当前位置: 首页 > news >正文

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

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

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

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

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

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

1. 库(Libraries)

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

库的优势

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

创建和使用库

// SPDX-License-Identifier: MIT
pragma 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: MIT
pragma 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: MIT
pragma 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;}// 覆盖并扩展transferOwnershipfunction transferOwnership(address newOwner) public override onlyOwner {super.transferOwnership(newOwner);// 额外逻辑,如记录事件}
}

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

4. 抽象合约和虚函数

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

// SPDX-License-Identifier: MIT
pragma 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: MIT
pragma 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: MIT
pragma 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: MIT
pragma 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 successcase 0 { revert(0, returndatasize()) }default { return(0, returndatasize()) }}}
}// 实现合约V1
contract 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: MIT
pragma 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: MIT
pragma 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: MIT
pragma 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: MIT
pragma 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 < endTime, "Campaign ended");contributions[msg.sender] += msg.value;totalRaised += msg.value;if (totalRaised >= 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: MIT
pragma 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-5string 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 < nextItemId, "Item does not exist");_;}modifier orderExists(uint256 orderId) {require(orderId > 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 < userOrders[user].length; i++) {uint256 orderId = userOrders[user][i];Order storage order = orders[orderId];address counterparty = (user == order.buyer) ? order.seller : order.buyer;if (userRatingCounts[user][counterparty] > 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 < nextOrderId; i++) {platformBalance -= userBalances[orders[i].seller];}require(platformBalance > 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`);
});
http://www.dtcms.com/a/364063.html

相关文章:

  • 机器视觉的平板电脑OCA全贴合应用
  • 修改⽂件之git
  • 企业微信AI在银行落地的3个实用场景:智能机器人、搜索、文档的具体用法
  • 了解名词ARM Linux的SOC
  • 枚举和泛型
  • 高性能接口实现方案
  • 刷题日记0902
  • 38.Ansible判断+实例
  • 硬件:51单片机
  • 【Unity Shader学习笔记】(一)计算机图形学
  • shell脚本案例
  • 【Unity Shader学习笔记】(二)图形显示系统
  • nmap扫描端口,netstat
  • 二叉树经典题目详解(下)
  • CH01-1.1 Exercise-Ordinary Differential Equation-by LiuChao
  • 猫猫狐狐的“你今天有点怪怪的”侦察日记
  • 标贝科技参编《数据标注产业发展研究报告(2025 年)》
  • ARM裸机开发(GPIO标准库开发)
  • Java搭建高效后端,Vue打造友好前端,联合构建电子采购管理系统,实现采购流程电子化、自动化,涵盖采购全周期管理,功能完备,附详细可运行源码
  • 提高卷积神经网络模型的一些应用
  • 复刻 Python 实现的小智语音客户端项目py-xiaozhi日记
  • AI助力开发:JetBrains官方DeepSeek插件Continue一站式上手!
  • 为什么研发文档的变更缺乏审批和追溯
  • 2025 大学生职业准备清单:从数据到财会,这些核心证书值得考
  • 毕业项目推荐:70-基于yolov8/yolov5/yolo11的苹果成熟度检测识别系统(Python+卷积神经网络)
  • Spring 循环依赖问题
  • 【代码随想录day 22】 力扣 40.组合总和II
  • 威科夫与强化学习状态
  • Spring Security 如何使用@PreAuthorize注解
  • srm信息系统数字化采购(程序代码部署程序包源码Java)