> 技术文档 > solidity从入门到精通 第七章:高级特性与实战项目

solidity从入门到精通 第七章:高级特性与实战项目


第七章:高级特性与实战项目

从学徒到大师:高级Solidity之旅

欢迎来到我们Solidity之旅的最后一章,勇敢的区块链探险家!如果你一路跟随我们到这里,恭喜你——你已经从一个区块链新手成长为一个有能力构建智能合约的开发者。就像从\"你好,世界\"到\"我可以创建自己的数字经济\",这是一段令人印象深刻的旅程。

在本章中,我们将探索Solidity的高级特性,学习专业开发者使用的设计模式,并通过一个完整的实战项目将我们所学的知识整合起来。准备好迎接终极挑战了吗?让我们开始吧!

Solidity高级特性:解锁更强大的工具

1. 库(Libraries)

库是一种特殊类型的合约,主要用于代码重用。与普通合约不同,库不能有状态变量,不能继承或被继承,也不能接收以太币。

库的优势

  • 代码重用
  • 节省gas(库代码只部署一次)
  • 逻辑分离和模块化

创建和使用库

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;// 定义一个数学库library MathLib { function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } function average(uint256 a, uint256 b) internal pure returns (uint256) { // 防止溢出的安全平均值计算 return (a & b) + (a ^ b) / 2; }}// 使用库的合约contract MathUser { using MathLib for uint256; function testMax(uint256 a, uint256 b) public pure returns (uint256) { // 方法1:直接调用库函数 return MathLib.max(a, b); } function testMin(uint256 a, uint256 b) public pure returns (uint256) { // 方法2:使用附加到类型的库函数 return a.min(b); } function testAverage(uint256 a, uint256 b) public pure returns (uint256) { return a.average(b); }}

using A for B语法将库A的函数附加到类型B上,使其可以像方法一样调用。

2. 接口(Interfaces)

接口定义了合约应该实现的函数,但不提供实现。它们类似于其他编程语言中的抽象类或接口。

接口的特点

  • 不能包含状态变量
  • 不能包含构造函数
  • 不能继承除接口外的其他合约
  • 所有函数必须是external且不能有实现

定义和实现接口

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;// 定义代币接口interface IToken { function transfer(address to, uint256 amount) external returns (bool); function balanceOf(address account) external view returns (uint256);}// 实现接口的合约contract MyToken is IToken { mapping(address => uint256) private _balances; constructor() { _balances[msg.sender] = 1000000; } function transfer(address to, uint256 amount) external override returns (bool) { require(_balances[msg.sender] >= amount, \"Insufficient balance\"); _balances[msg.sender] -= amount; _balances[to] += amount; return true; } function balanceOf(address account) external view override returns (uint256) { return _balances[account]; }}// 使用接口的合约contract TokenUser { function transferTokens(address tokenContract, address to, uint256 amount) public { IToken token = IToken(tokenContract); require(token.transfer(to, amount), \"Transfer failed\"); } function checkBalance(address tokenContract, address account) public view returns (uint256) { return IToken(tokenContract).balanceOf(account); }}

接口使合约能够与其他合约交互,而无需知道它们的完整实现。这促进了模块化和可组合性,这是区块链生态系统的关键特性。

3. 继承与多态性

Solidity支持多重继承,允许合约从多个父合约继承功能。

继承的特点

  • 代码重用
  • 逻辑扩展
  • 多态性(通过虚函数)

继承示例

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;// 基础合约contract Ownable { address public owner; constructor() { owner = msg.sender; } modifier onlyOwner() { require(msg.sender == owner, \"Not the owner\"); _; } function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), \"New owner cannot be zero address\"); owner = newOwner; }}// 基础代币功能contract BasicToken { mapping(address => uint256) internal _balances; uint256 public totalSupply; event Transfer(address indexed from, address indexed to, uint256 value); constructor(uint256 initialSupply) { totalSupply = initialSupply; _balances[msg.sender] = initialSupply; } function balanceOf(address account) public view returns (uint256) { return _balances[account]; } function transfer(address to, uint256 amount) public virtual returns (bool) { require(_balances[msg.sender] >= amount, \"Insufficient balance\"); _balances[msg.sender] -= amount; _balances[to] += amount; emit Transfer(msg.sender, to, amount); return true; }}// 结合所有权和代币功能的合约contract ManagedToken is Ownable, BasicToken { bool public transfersEnabled; constructor(uint256 initialSupply) BasicToken(initialSupply) { transfersEnabled = true; } // 覆盖父合约的函数 function transfer(address to, uint256 amount) public override returns (bool) { require(transfersEnabled, \"Transfers are disabled\"); return super.transfer(to, amount); // 调用父合约的实现 } // 只有所有者可以禁用/启用转账 function setTransfersEnabled(bool enabled) public onlyOwner { transfersEnabled = enabled; } // 覆盖并扩展transferOwnership function transferOwnership(address newOwner) public override onlyOwner { super.transferOwnership(newOwner); // 额外逻辑,如记录事件 }}

在这个例子中,ManagedToken继承了OwnableBasicToken的功能,并添加了自己的逻辑。override关键字表明函数覆盖了父合约中的函数,而super关键字用于调用父合约的实现。

4. 抽象合约和虚函数

抽象合约包含至少一个未实现的函数(虚函数)。它们不能直接部署,必须被继承并实现所有虚函数。

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;// 抽象合约abstract contract BaseGame { address public owner; constructor() { owner = msg.sender; } // 虚函数 - 没有实现 function play() public virtual returns (bool); // 部分实现的函数 function isOwner() public view returns (bool) { return msg.sender == owner; }}// 实现抽象合约contract DiceGame is BaseGame { uint256 private nonce = 0; // 实现虚函数 function play() public override returns (bool) { nonce++; uint256 diceRoll = uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender, nonce))) % 6 + 1; return diceRoll > 3; // 4, 5, 6为胜利 }}

抽象合约和虚函数使你能够定义必须由子合约实现的接口,同时提供一些共享功能。

5. 事件和日志

事件是以太坊虚拟机(EVM)日志机制的抽象。它们允许合约将信息写入区块链日志,这些日志可以被外部应用程序高效地访问。

事件的高级用法

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract AdvancedEvents { // 定义事件,最多可以有3个indexed参数 event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); event ComplexEvent( address indexed primary, address indexed secondary, uint256 indexed code, string details, bytes data ); function transfer(address to, uint256 amount) public { // 业务逻辑... // 触发事件 emit Transfer(msg.sender, to, amount); } function approve(address spender, uint256 amount) public { // 业务逻辑... // 触发事件 emit Approval(msg.sender, spender, amount); } function complexOperation( address secondary, uint256 code, string memory details, bytes memory data ) public { // 业务逻辑... // 触发复杂事件 emit ComplexEvent(msg.sender, secondary, code, details, data); }}

indexed参数作为主题存储,允许高效过滤和搜索。非索引参数存储在日志的数据部分。

6. 汇编和底层操作

Solidity允许使用内联汇编访问以太坊虚拟机的底层功能。这提供了更多的控制,但也增加了复杂性和风险。

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract AssemblyExample { function addAssembly(uint256 a, uint256 b) public pure returns (uint256 c) { assembly { // 直接在EVM中执行加法 c := add(a, b) // 如果结果小于a,说明发生了溢出 if lt(c, a) { revert(0, 0) } } } function getBlockHash(uint256 blockNumber) public view returns (bytes32 hash) { assembly { // 使用blockhash操作码 hash := blockhash(blockNumber) } } function callWithExactGas(address target, uint256 gasAmount, bytes memory data) public returns (bool success) { assembly { // 获取data的长度和指针 let len := mload(data) let ptr := add(data, 0x20) // 使用指定的gas调用目标合约 success := call(gasAmount, target, 0, ptr, len, 0, 0) } }}

内联汇编应谨慎使用,通常只在需要优化gas或访问Solidity不直接暴露的EVM功能时使用。

智能合约设计模式:构建更好的DApps

设计模式是解决常见问题的可重用解决方案。以下是Solidity中一些流行的设计模式:

1. 代理模式(Proxy Pattern)

代理模式允许合约逻辑升级,同时保持状态和地址不变。

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;// 存储合约(保持不变)contract Storage { address public implementation; address public admin; mapping(bytes32 => uint256) private values; constructor() { admin = msg.sender; } function setValue(bytes32 key, uint256 value) external { require(msg.sender == address(this), \"Only implementation can set values\"); values[key] = value; } function getValue(bytes32 key) external view returns (uint256) { return values[key]; } function setImplementation(address newImplementation) external { require(msg.sender == admin, \"Only admin can upgrade\"); implementation = newImplementation; } // 将所有调用委托给实现合约 fallback() external payable { address impl = implementation; require(impl != address(0), \"Implementation not set\"); assembly { // 复制调用数据 calldatacopy(0, 0, calldatasize()) // 调用实现合约 let success := delegatecall(gas(), impl, 0, calldatasize(), 0, 0) // 复制返回数据 returndatacopy(0, 0, returndatasize()) // 根据调用结果返回或回滚 switch success case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } }}// 实现合约V1contract ImplementationV1 { function setValue(bytes32 key, uint256 value) external { Storage(address(this)).setValue(key, value); } function getValue(bytes32 key) external view returns (uint256) { return Storage(address(this)).getValue(key); } function version() external pure returns (string memory) { return \"V1\"; }}// 实现合约V2(升级版)contract ImplementationV2 { function setValue(bytes32 key, uint256 value) external { Storage(address(this)).setValue(key, value); } function getValue(bytes32 key) external view returns (uint256) { return Storage(address(this)).getValue(key); } function version() external pure returns (string memory) { return \"V2\"; } // 新功能 function doubleValue(bytes32 key) external { uint256 value = Storage(address(this)).getValue(key); Storage(address(this)).setValue(key, value * 2); }}

使用代理模式,你可以升级合约逻辑而不改变用户交互的地址,也不丢失状态数据。

2. 工厂模式(Factory Pattern)

工厂模式用于创建合约的多个实例,常用于创建标准化但可定制的合约。

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;// 产品合约contract Vault { address public owner; address public factory; string public name; constructor(address _owner, string memory _name) { owner = _owner; factory = msg.sender; name = _name; } modifier onlyOwner() { require(msg.sender == owner, \"Not the owner\"); _; } function deposit() external payable { // 存款逻辑 } function withdraw(uint256 amount) external onlyOwner { require(address(this).balance >= amount, \"Insufficient balance\"); payable(owner).transfer(amount); }}// 工厂合约contract VaultFactory { mapping(address => address[]) public userVaults; address[] public allVaults; event VaultCreated(address indexed owner, address vault, string name); function createVault(string memory name) external returns (address) { Vault newVault = new Vault(msg.sender, name); userVaults[msg.sender].push(address(newVault)); allVaults.push(address(newVault)); emit VaultCreated(msg.sender, address(newVault), name); return address(newVault); } function getUserVaults(address user) external view returns (address[] memory) { return userVaults[user]; } function getVaultCount() external view returns (uint256) { return allVaults.length; }}

工厂模式使创建多个相似合约变得简单,同时提供了一个中央注册表来跟踪所有实例。

3. 检查-效果-交互模式(Checks-Effects-Interactions Pattern)

这种模式通过按特定顺序组织代码来防止重入攻击:

  1. 检查所有前提条件
  2. 修改合约状态
  3. 与其他合约交互
// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract SecureBank { mapping(address => uint256) private balances; function deposit() external payable { balances[msg.sender] += msg.value; } // 不安全的提款函数 function unsafeWithdraw(uint256 amount) external { require(balances[msg.sender] >= amount, \"Insufficient balance\"); // 危险:在更新状态前与外部合约交互 (bool success, ) = msg.sender.call{value: amount}(\"\"); require(success, \"Transfer failed\"); balances[msg.sender] -= amount; // 如果发生重入攻击,这行可能永远不会执行 } // 安全的提款函数(检查-效果-交互) function safeWithdraw(uint256 amount) external { // 1. 检查 require(balances[msg.sender] >= amount, \"Insufficient balance\"); // 2. 效果(状态更新) balances[msg.sender] -= amount; // 3. 交互 (bool success, ) = msg.sender.call{value: amount}(\"\"); require(success, \"Transfer failed\"); } function getBalance() external view returns (uint256) { return balances[msg.sender]; }}

这种模式是智能合约安全的基础,应该在所有涉及外部调用的函数中使用。

4. 提款模式(Pull Payment Pattern)

提款模式将发送资金的责任从合约转移到接收者,避免了许多与直接发送以太币相关的问题。

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract PullPayment { mapping(address => uint256) private payments; event FundsSent(address indexed recipient, uint256 amount); event FundsWithdrawn(address indexed recipient, uint256 amount); // 记录应付款项,但不立即发送 function sendPayment(address recipient, uint256 amount) public payable { require(msg.value == amount, \"Must send exact amount\"); payments[recipient] += amount; emit FundsSent(recipient, amount); } // 接收者自己提取资金 function withdrawPayment() public { uint256 amount = payments[msg.sender]; require(amount > 0, \"No funds to withdraw\"); // 检查-效果-交互模式 payments[msg.sender] = 0; (bool success, ) = msg.sender.call{value: amount}(\"\"); require(success, \"Transfer failed\"); emit FundsWithdrawn(msg.sender, amount); } function getPayment(address recipient) public view returns (uint256) { return payments[recipient]; }}

提款模式避免了发送以太币时可能出现的失败,并将gas成本转移给了接收者。

5. 状态机模式(State Machine Pattern)

状态机模式用于管理合约的不同状态和状态之间的转换。

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract Crowdfunding { enum State { Fundraising, Successful, Failed, Closed } State public state; address public creator; uint256 public goal; uint256 public endTime; mapping(address => uint256) public contributions; uint256 public totalRaised; modifier inState(State _state) { require(state == _state, \"Invalid state\"); _; } constructor(uint256 _goal, uint256 durationDays) { creator = msg.sender; goal = _goal; endTime = block.timestamp + (durationDays * 1 days); state = State.Fundraising; } function contribute() public payable inState(State.Fundraising) { require(block.timestamp = goal) { state = State.Successful; } } function checkStatus() public { if (state == State.Fundraising && block.timestamp >= endTime) { if (totalRaised >= goal) { state = State.Successful; } else { state = State.Failed; } } } function claimFunds() public inState(State.Successful) { require(msg.sender == creator, \"Only creator can claim\"); state = State.Closed; payable(creator).transfer(address(this).balance); } function refund() public inState(State.Failed) { require(contributions[msg.sender] > 0, \"No contribution to refund\"); uint256 amount = contributions[msg.sender]; contributions[msg.sender] = 0; payable(msg.sender).transfer(amount); }}

状态机模式使复杂的业务流程更容易管理,并确保操作只在适当的状态下执行。

实战项目:去中心化市场

让我们将所学的知识应用到一个实际项目中——一个去中心化的二手商品市场。这个项目将展示多种Solidity特性和设计模式。

项目概述

我们将创建一个去中心化市场,允许用户:

  • 列出商品销售
  • 购买其他用户的商品
  • 管理订单状态
  • 提交和查看评价
  • 提取收益

这个项目将使用多种我们学过的设计模式和安全实践,包括:

  • 检查-效果-交互模式
  • 提款模式
  • 访问控制
  • 事件记录
  • 安全转账

合约结构

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;import \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";import \"@openzeppelin/contracts/access/Ownable.sol\";/** * @title DecentralizedMarketplace * @dev 一个去中心化的二手商品市场,允许用户列出、购买和评价商品 */contract DecentralizedMarketplace is ReentrancyGuard, Ownable { // 商品结构 struct Item { uint256 id; address seller; string title; string description; uint256 price; bool available; uint256 createdAt; } // 订单结构 struct Order { uint256 id; uint256 itemId; address buyer; address seller; uint256 price; OrderStatus status; uint256 createdAt; } // 评价结构 struct Review { address reviewer; address reviewee; uint256 orderId; uint8 rating; // 1-5 string comment; uint256 createdAt; } // 订单状态枚举 enum OrderStatus { Created, Shipped, Received, Cancelled, Disputed, Resolved } // 状态变量 uint256 private nextItemId = 1; uint256 private nextOrderId = 1; uint256 public platformFeePercent = 2; // 2% mapping(uint256 => Item) public items; mapping(uint256 => Order) public orders; mapping(address => uint256[]) public userItems; mapping(address => uint256[]) public userOrders; mapping(address => uint256) public userBalances; mapping(uint256 => Review[]) public orderReviews; mapping(address => mapping(address => uint256)) public userRatings; // 用户评分总和 mapping(address => mapping(address => uint256)) public userRatingCounts; // 用户评分计数 // 事件 event ItemListed(uint256 indexed itemId, address indexed seller, string title, uint256 price); event ItemUpdated(uint256 indexed itemId, string title, uint256 price, bool available); event ItemPurchased(uint256 indexed orderId, uint256 indexed itemId, address indexed buyer, uint256 price); event OrderStatusChanged(uint256 indexed orderId, OrderStatus status); event ReviewSubmitted(uint256 indexed orderId, address indexed reviewer, address indexed reviewee, uint8 rating); event FundsWithdrawn(address indexed user, uint256 amount); // 修饰符 modifier onlyItemOwner(uint256 itemId) { require(items[itemId].seller == msg.sender, \"Not the item owner\"); _; } modifier itemExists(uint256 itemId) { require(itemId > 0 && itemId  0 && orderId < nextOrderId, \"Order does not exist\"); _; } modifier onlyOrderParticipant(uint256 orderId) { require( orders[orderId].buyer == msg.sender || orders[orderId].seller == msg.sender, \"Not a participant in this order\" ); _; }

这是我们市场合约的基本结构,包括数据结构、状态变量、事件和修饰符。接下来,我们将实现核心功能。

商品管理功能

 /** * @dev 列出新商品 */ function listItem(string memory title, string memory description, uint256 price) external returns (uint256) { require(bytes(title).length > 0, \"Title cannot be empty\"); require(price > 0, \"Price must be greater than zero\"); uint256 itemId = nextItemId++; items[itemId] = Item({ id: itemId, seller: msg.sender, title: title, description: description, price: price, available: true, createdAt: block.timestamp }); userItems[msg.sender].push(itemId); emit ItemListed(itemId, msg.sender, title, price); return itemId; } /** * @dev 更新商品信息 */ function updateItem(uint256 itemId, string memory title, string memory description, uint256 price, bool available) external itemExists(itemId) onlyItemOwner(itemId) { require(bytes(title).length > 0, \"Title cannot be empty\"); require(price > 0, \"Price must be greater than zero\"); Item storage item = items[itemId]; item.title = title; item.description = description; item.price = price; item.available = available; emit ItemUpdated(itemId, title, price, available); } /** * @dev 获取商品详情 */ function getItem(uint256 itemId) external view itemExists(itemId) returns ( uint256 id, address seller, string memory title, string memory description, uint256 price, bool available, uint256 createdAt ) { Item storage item = items[itemId]; return ( item.id, item.seller, item.title, item.description, item.price, item.available, item.createdAt ); } /** * @dev 获取用户的所有商品 */ function getUserItems(address user) external view returns (uint256[] memory) { return userItems[user]; }

订单和购买功能

 /** * @dev 购买商品 */ function purchaseItem(uint256 itemId) external payable nonReentrant itemExists(itemId) { Item storage item = items[itemId]; require(item.available, \"Item is not available\"); require(item.seller != msg.sender, \"Cannot buy your own item\"); require(msg.value >= item.price, \"Insufficient payment\"); // 创建订单 uint256 orderId = nextOrderId++; orders[orderId] = Order({ id: orderId, itemId: itemId, buyer: msg.sender, seller: item.seller, price: item.price, status: OrderStatus.Created, createdAt: block.timestamp }); // 更新商品状态 item.available = false; // 记录订单 userOrders[msg.sender].push(orderId); userOrders[item.seller].push(orderId); // 计算平台费用 uint256 platformFee = (item.price * platformFeePercent) / 100; uint256 sellerAmount = item.price - platformFee; // 更新卖家余额(使用提款模式) userBalances[item.seller] += sellerAmount; // 退还多余的以太币 if (msg.value > item.price) { payable(msg.sender).transfer(msg.value - item.price); } emit ItemPurchased(orderId, itemId, msg.sender, item.price); } /** * @dev 更新订单状态 */ function updateOrderStatus(uint256 orderId, OrderStatus newStatus) external orderExists(orderId) onlyOrderParticipant(orderId) { Order storage order = orders[orderId]; // 验证状态转换的有效性 if (newStatus == OrderStatus.Shipped) { require(msg.sender == order.seller, \"Only seller can mark as shipped\"); require(order.status == OrderStatus.Created, \"Invalid status transition\"); } else if (newStatus == OrderStatus.Received) { require(msg.sender == order.buyer, \"Only buyer can mark as received\"); require(order.status == OrderStatus.Shipped, \"Item must be shipped first\"); } else if (newStatus == OrderStatus.Disputed) { require(order.status != OrderStatus.Disputed, \"Already disputed\"); require(order.status != OrderStatus.Resolved, \"Already resolved\"); } else if (newStatus == OrderStatus.Cancelled) { require( order.status == OrderStatus.Created ||  (order.status == OrderStatus.Shipped && msg.sender == order.seller), \"Cannot cancel at this stage\" ); // 如果卖家取消,退还买家资金 if (msg.sender == order.seller) { userBalances[order.buyer] += order.price; userBalances[order.seller] -= order.price; } } order.status = newStatus; emit OrderStatusChanged(orderId, newStatus); } /** * @dev 获取订单详情 */ function getOrder(uint256 orderId) external view orderExists(orderId) returns ( uint256 id, uint256 itemId, address buyer, address seller, uint256 price, OrderStatus status, uint256 createdAt ) { Order storage order = orders[orderId]; return ( order.id, order.itemId, order.buyer, order.seller, order.price, order.status, order.createdAt ); } /** * @dev 获取用户的所有订单 */ function getUserOrders(address user) external view returns (uint256[] memory) { return userOrders[user]; }

这些函数实现了商品列表和订单管理的核心功能。接下来,我们将添加评价系统和资金管理功能。

评价系统

 /** * @dev 提交评价 */ function submitReview(uint256 orderId, address reviewee, uint8 rating, string memory comment) external orderExists(orderId) onlyOrderParticipant(orderId) { Order storage order = orders[orderId]; // 验证评价参数 require(rating >= 1 && rating <= 5, \"Rating must be between 1 and 5\"); require( (msg.sender == order.buyer && reviewee == order.seller) || (msg.sender == order.seller && reviewee == order.buyer), \"Invalid reviewer or reviewee\" ); require(order.status == OrderStatus.Received || order.status == OrderStatus.Resolved, \"Order must be completed before review\" ); // 创建评价 Review memory review = Review({ reviewer: msg.sender, reviewee: reviewee, orderId: orderId, rating: rating, comment: comment, createdAt: block.timestamp }); // 存储评价 orderReviews[orderId].push(review); // 更新用户评分 userRatings[reviewee][msg.sender] = rating; userRatingCounts[reviewee][msg.sender] = 1; emit ReviewSubmitted(orderId, msg.sender, reviewee, rating); } /** * @dev 获取订单的所有评价 */ function getOrderReviews(uint256 orderId) external view orderExists(orderId) returns (Review[] memory) { return orderReviews[orderId]; } /** * @dev 计算用户的平均评分 */ function getUserAverageRating(address user) external view returns (uint256) { uint256 totalRating = 0; uint256 count = 0; for (uint256 i = 0; i  0) { totalRating += userRatings[user][counterparty]; count += userRatingCounts[user][counterparty]; } } if (count == 0) return 0; return totalRating / count; }

资金管理功能

 /** * @dev 提取余额 */ function withdrawFunds() external nonReentrant { uint256 amount = userBalances[msg.sender]; require(amount > 0, \"No funds to withdraw\"); // 检查-效果-交互模式 userBalances[msg.sender] = 0; (bool success, ) = payable(msg.sender).call{value: amount}(\"\"); require(success, \"Transfer failed\"); emit FundsWithdrawn(msg.sender, amount); } /** * @dev 获取用户余额 */ function getBalance() external view returns (uint256) { return userBalances[msg.sender]; } /** * @dev 平台提取费用 */ function withdrawPlatformFees() external onlyOwner nonReentrant { uint256 platformBalance = address(this).balance; for (uint256 i = 1; i  0, \"No platform fees to withdraw\"); (bool success, ) = payable(owner()).call{value: platformBalance}(\"\"); require(success, \"Transfer failed\"); } /** * @dev 更新平台费率 */ function updatePlatformFee(uint256 newFeePercent) external onlyOwner { require(newFeePercent <= 10, \"Fee too high\"); // 最高10% platformFeePercent = newFeePercent; } /** * @dev 解决争议 */ function resolveDispute(uint256 orderId, address winner) external onlyOwner orderExists(orderId) { Order storage order = orders[orderId]; require(order.status == OrderStatus.Disputed, \"Order not disputed\"); require( winner == order.buyer || winner == order.seller, \"Winner must be buyer or seller\" ); // 如果买家胜诉,退还资金 if (winner == order.buyer) { userBalances[order.buyer] += order.price; userBalances[order.seller] -= order.price; } order.status = OrderStatus.Resolved; emit OrderStatusChanged(orderId, OrderStatus.Resolved); }}

这些函数实现了评价系统和资金管理的功能,包括提交评价、计算用户评分、提取资金和解决争议等。

项目总结

我们的去中心化市场合约现在已经完成,它包含了以下功能:

  1. 商品管理:用户可以列出、更新和查询商品
  2. 订单处理:用户可以购买商品并管理订单状态
  3. 评价系统:用户可以对交易对手进行评价
  4. 资金管理:安全的资金处理和提款机制
  5. 争议解决:平台可以介入解决买卖双方的争议

这个项目展示了多种Solidity高级特性和设计模式:

  • 继承:从OpenZeppelin合约继承安全功能
  • 修饰符:用于访问控制和验证
  • 枚举:用于订单状态管理
  • 结构体:组织复杂数据
  • 事件:记录重要操作
  • 检查-效果-交互模式:防止重入攻击
  • 提款模式:安全的资金处理
  • 状态机模式:管理订单状态转换

前端集成

要将这个智能合约与前端应用程序集成,你可以使用Web3.js或ethers.js库。以下是使用ethers.js的简单示例:

// 连接到合约const provider = new ethers.providers.Web3Provider(window.ethereum);const signer = provider.getSigner();const marketplaceContract = new ethers.Contract(contractAddress, contractABI, signer);// 列出商品async function listItem(title, description, price) { try { const tx = await marketplaceContract.listItem(title, description, ethers.utils.parseEther(price)); await tx.wait(); console.log(\"Item listed successfully!\"); } catch (error) { console.error(\"Error listing item:\", error); }}// 购买商品async function purchaseItem(itemId, price) { try { const tx = await marketplaceContract.purchaseItem(itemId, { value: ethers.utils.parseEther(price) }); await tx.wait(); console.log(\"Item purchased successfully!\"); } catch (error) { console.error(\"Error purchasing item:\", error); }}// 监听事件marketplaceContract.on(\"ItemListed\", (itemId, seller, title, price, event) => { console.log(`New item listed: ${title} by ${seller} for ${ethers.utils.formatEther(price)} ETH`);});