Building with Solidity
Smart Contract Actions and Safety
This lesson covers common smart contract actions - minting tokens, spending/locking assets, transfers, and safety functions like access controls - along with read-only queries that let frontends display contract data without gas costs.
Common Contract Actions
Smart contracts let you define logic that runs automatically when triggered by a transaction.
Here are some of the most common:
Action Type | What It Does |
Minting | Creates new tokens or points for a user |
Spending | Moves tokens or reduces a balance |
Locking | Prevents access to something until a condition is met |
Sending | Transfers tokens or NFTs from one address to another |
In the Learn2Earn University contract, we’ve already talked about:
addStudent()spends as the user has use 1VET to activate this function.issueCertificate()mints and creates a certificate
Minting
Minting is the process of creating something new onchain, typically tokens, NFTs, or points. In a Focus2Earn contract, when a user completes a focus session, the contract “mints” focus points by increasing their onchain balance.
users[msg.sender].points += rewardAmount;
This line mints new points for the user. No one has to “send” them; they’re generated by the logic of the contract itself.
Spending
Spending refers to reducing a user’s onchain balance, often as part of a payment or burn mechanism. This might be used in a game contract to deduct energy points or in a marketplace contract to deduct tokens when buying an item.
Example:
This simple pattern enforces that users can only take certain actions if they have enough points, and then reduces their balance accordingly.
Locking
Smart contracts can lock access to functions or data until certain conditions are met. In the Focus2Earn contract, a cooldown period prevents users from earning rewards too frequently. This ensures fair use and prevents abuse.
This is a form of time-based locking. The function will only execute if enough time has passed since the user’s last action.
Sending
Contracts can send tokens or NFTs from one wallet to another. This is one of the most powerful features of smart contracts, enabling decentralized transfers with custom rules, like only sending a reward if a condition is met.
token.transfer(msg.sender, rewardAmount);
In this example, the contract sends tokens to a user, but it could be set to trigger only if the user completes a task, proves a behavior, or passes a verification step.
Optional Logic: Cooldowns and Timers
In your Focus2Earn contract, you introduced time-based logic to prevent abuse.
Example:
require(block.timestamp >= lastSessionTimestamp[msg.sender] + cooldown, "Please wait before next session");
This ensures users can’t spam reward claims, all enforced onchain.
Queries and Read Functions
Not all contract functions change state. Some simply return data. These are known as read-only functions, and they’re marked with the view or pure keyword.
view: reads onchain data but doesn’t change it.pure: doesn’t even read from storage — it only uses input parameters or internal calculations.
Example:
This allows a frontend to display a user's points without requiring a wallet signature.
They’re free to call from outside the blockchain. Frontends can use them to display contract data without requiring users to sign a transaction or pay gas.
Queries are essential for user-facing dApps. They let you:
Display account stats, balances, cooldown timers, etc.
Power leaderboards, dashboards, or activity logs
Keep your UI reactive and real-time without requiring blockchain writes
Safety Functions in Solidity
Safety functions are used to make your contract more robust and resistant to bugs, errors, or malicious misuse. They often enforce logical checks, error handling, and safe fallbacks.
Using require for Access Control and Validation
One of the most important tools in Solidity is the require statement. It ensures that specific conditions are met before continuing execution.
Example:
This ensures that only the contract owner can proceed with certain actions. If the condition is not met, the transaction reverts with a helpful error message. You’ve already applied this pattern to restrict addUser.
Example: Event + Modifier + Struct
Here’s a complete function using everything above:
It:
Checks that the caller is the owner
Stores a new
Userstruct on-chainEmits a public event
This pattern is the foundation of most secure smart contracts.
Join our Telegram