Solidity中SafeMath库废弃后如何实现日期乘法计算?
Solidity SafeMath废弃问题修复方案
你可以根据是否需要保留0.6.0编译版本,选择以下两种修复方案:
方案1:保留Solidity 0.6.0版本
该方案无需修改原有业务逻辑,仅修复失效的SafeMath导入即可正常编译:
- 替换原失效的SafeMath导入语句为适配0.6.0版本的正确引入路径
- 代码中所有
.add()/.mul()/.sub()语法保持不变 - 将代码中的HTML转义字符
>统一替换为>
0.6.0版本完整可编译代码:
pragma solidity 0.6.0; // 导入适配0.6.0版本的OpenZeppelin SafeMath import 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.2/contracts/math/SafeMath.sol'; contract Crowdfunding { using SafeMath for uint256; // 现有项目列表 Project[] private projects; // 新项目创建时触发的事件 event ProjectStarted( address contractAddress, address projectStarter, string projectTitle, string projectDesc, uint256 deadline, uint256 goalAmount ); /** @dev 创建新项目的方法 * @param title 项目标题 * @param description 项目简介 * @param durationInDays 众筹持续天数 * @param amountToRaise 众筹目标金额(单位wei) */ function startProject( string calldata title, string calldata description, uint durationInDays, uint amountToRaise ) external { uint raiseUntil = now.add(durationInDays.mul(1 days)); Project newProject = new Project(msg.sender, title, description, raiseUntil, amountToRaise); projects.push(newProject); emit ProjectStarted( address(newProject), msg.sender, title, description, raiseUntil, amountToRaise ); } /** @dev 获取所有项目合约地址 * @return 所有项目合约地址列表 */ function returnAllProjects() external view returns(Project[] memory){ return projects; } } contract Project { using SafeMath for uint256; // 项目状态枚举 enum State { Fundraising, Expired, Successful } // 状态变量 address payable public creator; uint public amountGoal; // 最低众筹目标,未达成则所有人可退款 uint public completeAt; uint256 public currentBalance; uint public raiseBy; string public title; string public description; State public state = State.Fundraising; // 初始化状态为募资中 mapping (address => uint) public contributions; // 收到捐款时触发的事件 event FundingReceived(address contributor, uint amount, uint currentTotal); // 项目方收到筹款时触发的事件 event CreatorPaid(address recipient); // 检查项目状态的修饰器 modifier inState(State _state) { require(state == _state); _; } // 检查调用方是否为项目发起人的修饰器 modifier isCreator() { require(msg.sender == creator); _; } constructor ( address payable projectStarter, string memory projectTitle, string memory projectDesc, uint fundRaisingDeadline, uint goalAmount ) public { creator = projectStarter; title = projectTitle; description = projectDesc; amountGoal = goalAmount; raiseBy = fundRaisingDeadline; currentBalance = 0; } /** @dev 为项目捐款的方法 */ function contribute() external inState(State.Fundraising) payable { require(msg.sender != creator); contributions[msg.sender] = contributions[msg.sender].add(msg.value); currentBalance = currentBalance.add(msg.value); emit FundingReceived(msg.sender, msg.value, currentBalance); checkIfFundingCompleteOrExpired(); } /** @dev 根据条件更新项目状态的方法 */ function checkIfFundingCompleteOrExpired() public { if (currentBalance >= amountGoal) { state = State.Successful; payOut(); } else if (now > raiseBy) { state = State.Expired; } completeAt = now; } /** @dev 给项目发起方打款的方法 */ function payOut() internal inState(State.Successful) returns (bool) { uint256 totalRaised = currentBalance; currentBalance = 0; if (creator.send(totalRaised)) { emit CreatorPaid(creator); return true; } else { currentBalance = totalRaised; state = State.Successful; } return false; } /** @dev 项目过期后捐款人申请退款的方法 */ function getRefund() public inState(State.Expired) returns (bool) { require(contributions[msg.sender] > 0); uint amountToRefund = contributions[msg.sender]; contributions[msg.sender] = 0; if (!msg.sender.send(amountToRefund)) { contributions[msg.sender] = amountToRefund; return false; } else { currentBalance = currentBalance.sub(amountToRefund); } return true; } /** @dev 获取项目具体信息的方法 * @return 返回项目所有基础信息 */ function getDetails() public view returns ( address payable projectStarter, string memory projectTitle, string memory projectDesc, uint256 deadline, State currentState, uint256 currentAmount, uint256 goalAmount ) { projectStarter = creator; projectTitle = title; projectDesc = description; deadline = raiseBy; currentState = state; currentAmount = currentBalance; goalAmount = amountGoal; } }
方案2:升级到Solidity 0.8+版本(推荐)
Solidity 0.8及以上版本默认内置整数溢出/下溢检查,无需引入第三方SafeMath库,代码更简洁,编译效率更高:
- 将编译版本调整为
pragma solidity ^0.8.0; - 删除所有SafeMath相关的导入和
using SafeMath for uint256;声明 - 所有SafeMath方法替换为原生运算符:
.add()→+、.mul()→*、.sub()→- - 将已弃用的
now关键字替换为等价的block.timestamp - 将代码中的HTML转义字符
>统一替换为>
你提到的报错代码行修改后为:
uint raiseUntil = block.timestamp + durationInDays * 1 days;
0.8+版本完整可编译代码:
pragma solidity ^0.8.0; contract Crowdfunding { // 现有项目列表 Project[] private projects; // 新项目创建时触发的事件 event ProjectStarted( address contractAddress, address projectStarter, string projectTitle, string projectDesc, uint256 deadline, uint256 goalAmount ); /** @dev 创建新项目的方法 * @param title 项目标题 * @param description 项目简介 * @param durationInDays 众筹持续天数 * @param amountToRaise 众筹目标金额(单位wei) */ function startProject( string calldata title, string calldata description, uint durationInDays, uint amountToRaise ) external { uint raiseUntil = block.timestamp + durationInDays * 1 days; Project newProject = new Project(msg.sender, title, description, raiseUntil, amountToRaise); projects.push(newProject); emit ProjectStarted( address(newProject), msg.sender, title, description, raiseUntil, amountToRaise ); } /** @dev 获取所有项目合约地址 * @return 所有项目合约地址列表 */ function returnAllProjects() external view returns(Project[] memory){ return projects; } } contract Project { // 项目状态枚举 enum State { Fundraising, Expired, Successful } // 状态变量 address payable public creator; uint public amountGoal; // 最低众筹目标,未达成则所有人可退款 uint public completeAt; uint256 public currentBalance; uint public raiseBy; string public title; string public description; State public state = State.Fundraising; // 初始化状态为募资中 mapping (address => uint) public contributions; // 收到捐款时触发的事件 event FundingReceived(address contributor, uint amount, uint currentTotal); // 项目方收到筹款时触发的事件 event CreatorPaid(address recipient); // 检查项目状态的修饰器 modifier inState(State _state) { require(state == _state); _; } // 检查调用方是否为项目发起人的修饰器 modifier isCreator() { require(msg.sender == creator); _; } constructor ( address payable projectStarter, string memory projectTitle, string memory projectDesc, uint fundRaisingDeadline, uint goalAmount ) { creator = projectStarter; title = projectTitle; description = projectDesc; amountGoal = goalAmount; raiseBy = fundRaisingDeadline; currentBalance = 0; } /** @dev 为项目捐款的方法 */ function contribute() external inState(State.Fundraising) payable { require(msg.sender != creator); contributions[msg.sender] += msg.value; currentBalance += msg.value; emit FundingReceived(msg.sender, msg.value, currentBalance); checkIfFundingCompleteOrExpired(); } /** @dev 根据条件更新项目状态的方法 */ function checkIfFundingCompleteOrExpired() public { if (currentBalance >= amountGoal) { state = State.Successful; payOut(); } else if (block.timestamp > raiseBy) { state = State.Expired; } completeAt = block.timestamp; } /** @dev 给项目发起方打款的方法 */ function payOut() internal inState(State.Successful) returns (bool) { uint256 totalRaised = currentBalance; currentBalance = 0; if (creator.send(totalRaised)) { emit CreatorPaid(creator); return true; } else { currentBalance = totalRaised; state = State.Successful; } return false; } /** @dev 项目过期后捐款人申请退款的方法 */ function getRefund() public inState(State.Expired) returns (bool) { require(contributions[msg.sender] > 0); uint amountToRefund = contributions[msg.sender]; contributions[msg.sender] = 0; if (!payable(msg.sender).send(amountToRefund)) { contributions[msg.sender] = amountToRefund; return false; } else { currentBalance -= amountToRefund; } return true; } /** @dev 获取项目具体信息的方法 * @return 返回项目所有基础信息 */ function getDetails() public view returns ( address payable projectStarter, string memory projectTitle, string memory projectDesc, uint256 deadline, State currentState, uint256 currentAmount, uint256 goalAmount ) { projectStarter = creator; projectTitle = title; projectDesc = description; deadline = raiseBy; currentState = state; currentAmount = currentBalance; goalAmount = amountGoal; } }
内容的提问来源于stack exchange,提问作者Juan Sepulveda
相关产品推荐
相关产品推荐

