Examples
Solidity contract examples: ERC-20, ERC-721, simple voting, payable function, time-locked withdraw.
Web3 — Solidity examples
EXAMPLE
// ===== 1. ERC-20 (OpenZeppelin) =====
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyToken is ERC20, Ownable {
constructor(address initialOwner) ERC20("MyToken", "MYT") Ownable(initialOwner) {}
function mint(address to, uint256 amount) external onlyOwner {
_mint(to, amount);
}
}
// ===== 2. ERC-721 (NFTs) =====
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract MyNFT is ERC721, Ownable {
uint256 private _nextId;
constructor(address initialOwner) ERC721("MyNFT", "MNFT") Ownable(initialOwner) {}
function mint(address to) external onlyOwner returns (uint256) {
uint256 id = ++_nextId;
_safeMint(to, id);
return id;
}
}
// ===== 3. Simple voting =====
contract Voting {
mapping(bytes32 => uint256) public votes;
mapping(address => bool) public hasVoted;
event Voted(address indexed voter, bytes32 indexed choice);
function vote(bytes32 choice) external {
require(!hasVoted[msg.sender], "already voted");
hasVoted[msg.sender] = true;
votes[choice]++;
emit Voted(msg.sender, choice);
}
}
// ===== 4. Payable function =====
contract Tipping {
address payable public owner;
event Tipped(address indexed from, uint256 amount, string message);
constructor() { owner = payable(msg.sender); }
function tip(string calldata message) external payable {
require(msg.value > 0, "no tip");
emit Tipped(msg.sender, msg.value, message);
}
function withdraw() external {
require(msg.sender == owner, "not owner");
owner.transfer(address(this).balance);
}
}
// ===== 5. Time-locked withdraw =====
contract Timelock {
address public owner;
uint256 public releaseTime;
constructor(uint256 _releaseTime) payable {
require(_releaseTime > block.timestamp, "release in past");
owner = msg.sender;
releaseTime = _releaseTime;
}
function withdraw() external {
require(msg.sender == owner, "not owner");
require(block.timestamp >= releaseTime, "locked");
payable(owner).transfer(address(this).balance);
}
}
// ===== 6. Reentrancy-safe withdraw =====
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
contract Vault is ReentrancyGuard {
mapping(address => uint256) public balances;
function deposit() external payable {
balances[msg.sender] += msg.value;
}
function withdraw(uint256 amount) external nonReentrant {
require(balances[msg.sender] >= amount, "insufficient");
balances[msg.sender] -= amount; // Effects BEFORE Interactions
(bool ok, ) = payable(msg.sender).call{ value: amount }("");
require(ok, "transfer failed");
}
}
// ===== Deploy via Hardhat =====
// scripts/deploy.js
const hre = require('hardhat');
async function main() {
const [deployer] = await hre.ethers.getSigners();
const Token = await hre.ethers.getContractFactory('MyToken');
const token = await Token.deploy(deployer.address);
await token.waitForDeployment();
console.log('deployed at', await token.getAddress());
}
main().catch((e) => { console.error(e); process.exit(1); });
// hardhat run scripts/deploy.js --network sepolia
// ===== Patterns =====
// - OpenZeppelin contracts as audited base
// - Checks-Effects-Interactions
// - ReentrancyGuard on functions calling external untrusted code
// - emit events on every state change
// - Use SafeERC20 for token interactions
// ===== Pitfalls =====
// - block.timestamp not perfectly accurate (miner manipulable by ~15 sec)
// - tx.origin instead of msg.sender (phishing risk)
// - Unbounded loops -> gas DoS
// - Missing access control on critical functions
Why it matters
Five real Solidity contract patterns: ERC-20, ERC-721, voting, payable + withdraw, timelock, reentrancy-safe vault. Build on OpenZeppelin contracts, use CEI + ReentrancyGuard, emit events, deploy via Hardhat. The same shapes power most production DeFi + NFT projects.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…