以太坊智能合约开发完全指南 智能合约是区块链应用的核心,本文提供从入门到实战的完整开发指南。 Solidity基础 Hello World 数据类型 核心概念 事件和日志 修饰器 错误处理 常见模式 可升级合约 访问控制 暂停机制 ERC代币标准 ERC20代币 ERC721 NFT DeFi协议 去中心化交易所 借贷协议 安全最佳实践 重入攻击防护 整数溢出防护 开发工具链 Hardhat配置 测试 通过掌握Solidity和智能合约开发,可以构建去中心化应用,参与Web3生态系统建设。
智能合约是区块链应用的核心,本文提供从入门到实战的完整开发指南。
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract HelloWorld { string public message = "Hello, World!"; function setMessage(string memory newMessage) public { message = newMessage; } function getMessage() public view returns (string memory) { return message; } }
contract DataTypes { // 值类型 bool public isActive = true; int256 public balance = -100; uint256 public amount = 1000; address public owner = msg.sender; bytes32 public hash = keccak256("test"); // 引用类型 uint256[] public numbers; mapping(address => uint256) public balances; // 结构体 struct User { string name; uint256 age; } User public user; // 枚举 enum State { Active, Inactive, Pending } State public state; }
contract Events { event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); function transfer(address to, uint256 amount) public { emit Transfer(msg.sender, to, amount); } }
contract Modifiers { address public owner; constructor() { owner = msg.sender; } modifier onlyOwner() { require(msg.sender == owner, "Not owner"); _; // 继续执行函数 } modifier validAddress(address addr) { require(addr != address(0), "Invalid address"); _; } function criticalFunction() public onlyOwner validAddress(msg.sender) { // 只有owner才能调用 } }
contract ErrorHandling { error InsufficientBalance(uint256 requested, uint256 available); function withdraw(uint256 amount) public { uint256 balance = getBalance(); if (amount > balance) { revert InsufficientBalance(amount, balance); } payable(msg.sender).transfer(amount); } function getBalance() public view returns (uint256) { return address(this).balance; } }
// 代理合约 contract Proxy { address public implementation; address public admin; constructor(address _implementation) { implementation = _implementation; admin = msg.sender; } fallback() external payable { address impl = implementation; assembly { calldatacopy(0, 0, calldatasize()) let result := delegatecall(gas(), impl, 0, calldatasize(), 0, 0) returndatacopy(0, 0, returndatasize()) switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } function upgrade(address newImplementation) external { require(msg.sender == admin, "Only admin"); implementation = newImplementation; } } // 逻辑合约 contract LogicV1 { uint256 public value; function setValue(uint256 _value) external { value = _value; } } contract LogicV2 { uint256 public value; uint256 public extraValue; function setValue(uint256 _value) external { value = _value * 2; // 修改后的逻辑 } function setExtraValue(uint256 _extraValue) external { extraValue = _extraValue; } }
import "@openzeppelin/contracts/access/AccessControl.sol"; contract RoleBased is AccessControl { bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); bytes32 public constant USER_ROLE = keccak256("USER_ROLE"); constructor() { _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); _grantRole(ADMIN_ROLE, msg.sender); } function adminFunction() external onlyRole(ADMIN_ROLE) { // 只有admin可以调用 } function userFunction() external onlyRole(USER_ROLE) { // 有user role的都可以调用 } }
import "@openzeppelin/contracts/security/Pausable.sol"; contract PausableContract is Pausable { uint256 public value; function setValue(uint256 _value) external whenNotPaused { value = _value; } function pause() external onlyOwner { _pause(); } function unpause() external onlyOwner { _unpause(); } }
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract MyToken is ERC20 { constructor(uint256 initialSupply) ERC20("MyToken", "MTK") { _mint(msg.sender, initialSupply * 10**18); } function mint(address to, uint256 amount) public onlyOwner { _mint(to, amount * 10**18); } }
import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; contract MyNFT is ERC721, ERC721URIStorage { uint256 private _tokenId; constructor() ERC721("MyNFT", "MNFT") {} function mintNFT(address recipient, string memory tokenURI) public returns (uint256) { _tokenId++; _mint(recipient, _tokenId); _setTokenURI(_tokenId, tokenURI); return _tokenId; } function tokenURI(uint256 tokenId) public view override(ERC721, ERC721URIStorage) returns (string memory) { return super.tokenURI(tokenId); } }
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol"; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol"; contract SimpleDEX { IUniswapV2Factory public factory; constructor(address _factory) { factory = IUniswapV2Factory(_factory); } function createPool(address tokenA, address tokenB) external { factory.createPair(tokenA, tokenB); } function addLiquidity( address pair, uint256 amountA, uint256 amountB ) external { IERC20(tokenA).transferFrom(msg.sender, pair, amountA); IERC20(tokenB).transferFrom(msg.sender, pair, amountB); IUniswapV2Pair(pair).mint(msg.sender); } function swap( address pair, uint256 amountIn, uint256 amountOutMin, address[] calldata path ) external { IERC20(path[0]).transferFrom(msg.sender, pair, amountIn); IUniswapV2Pair(pair).swap( amountOutMin, 0, msg.sender, block.timestamp ); } }
contract LendingProtocol { mapping(address => uint256) public deposits; mapping(address => uint256) public borrows; uint256 public constant COLLATERAL_RATIO = 150; // 150% function deposit(uint256 amount) external { IERC20(usdc).transferFrom(msg.sender, address(this), amount); deposits[msg.sender] += amount; } function borrow(uint256 amount) external { uint256 collateral = deposits[msg.sender]; uint256 maxBorrow = (collateral * 100) / COLLATERAL_RATIO; require(amount <= maxBorrow, "Insufficient collateral"); borrows[msg.sender] += amount; IERC20(usdc).transfer(msg.sender, amount); } function liquidate(address borrower) external { uint256 collateral = deposits[borrower]; uint256 borrowAmount = borrows[borrower]; uint256 maxBorrow = (collateral * 100) / COLLATERAL_RATIO; require(borrowAmount > maxBorrow, "Not liquidatable"); // 清算逻辑 uint256 repayAmount = borrowAmount * 105 / 100; // 5% 清算奖励 IERC20(usdc).transferFrom(msg.sender, address(this), repayAmount); borrows[borrower] = 0; deposits[borrower] = 0; IERC20(usdc).transfer(msg.sender, collateral); } }
import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; contract SecureVault 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 balance"); // 检查-生效-交互模式 balances[msg.sender] -= amount; payable(msg.sender).transfer(amount); } }
import "@openzeppelin/contracts/utils/math/SafeMath.sol"; contract SafeMath { using SafeMath for uint256; function transfer(address to, uint256 amount) public { balances[msg.sender] = balances[msg.sender].sub(amount); balances[to] = balances[to].add(amount); } }
// hardhat.config.js require("@nomicfoundation/hardhat-toolbox"); require("@openzeppelin/hardhat-upgrades"); module.exports = { solidity: { version: "0.8.20", settings: { optimizer: { enabled: true, runs: 200 } } }, networks: { hardhat: { forking: { url: "https://eth-mainnet.alchemyapi.io/v2/YOUR-API-KEY" } }, sepolia: { url: "https://eth-sepolia.alchemyapi.io/v2/YOUR-API-KEY", accounts: [PRIVATE_KEY] } }, etherscan: { apiKey: ETHERSCAN_API_KEY } };
const { expect } = require("chai"); describe("Token Contract", function () { it("Should deploy with initial supply", async function () { const Token = await ethers.getContractFactory("MyToken"); const token = await Token.deploy(1000000); expect(await token.totalSupply()).to.equal(1000000 * 10**18); }); it("Should transfer tokens", async function () { const [owner, addr1] = await ethers.getSigners(); await token.transfer(addr1.address, 100); expect(await token.balanceOf(addr1.address)).to.equal(100); }); });
通过掌握Solidity和智能合约开发,可以构建去中心化应用,参与Web3生态系统建设。