如何在ERC-20合约中实现按时间规则分批铸造代币
ERC20 按时间规则分批铸币实现方案
核心实现逻辑
- 在合约中预定义释放时间节点和对应每个节点的释放额度,需要将日期转换为Unix时间戳,你给出的示例中三个时间点对应的UTC零点时间戳分别为
1630454400(2021-09-01)、1661990400(2022-09-01)、1693526400(2023-09-01) - 定义状态变量记录每个节点的铸造状态,避免重复铸造
- 封装铸币方法,调用时先校验当前区块时间是否达到对应节点的释放要求,再校验该节点额度是否未被铸造,校验通过后调用ERC20标准的
_mint方法将代币转入指定的接收地址(通常为项目金库、多签地址)
完整合约代码示例
推荐基于OpenZeppelin的标准ERC20库实现,无需重复造轮子:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract TimeVestedMintERC20 is ERC20 { // 接收铸造代币的固定金库地址 address public immutable treasury; // 释放节点结构体 struct VestingSchedule { uint256 releaseTime; // 释放时间戳 uint256 amount; // 对应释放额度,单位为wei bool isMinted; // 该节点是否已完成铸造 } // 释放节点列表 VestingSchedule[] public vestingSchedules; constructor(address _treasury) ERC20("Test Token", "TT") { treasury = _treasury; // 初始化你要求的三个释放节点 vestingSchedules.push(VestingSchedule({ releaseTime: 1630454400, amount: 1_000_000 * 10 ** decimals(), isMinted: false })); vestingSchedules.push(VestingSchedule({ releaseTime: 1661990400, amount: 1_000_000 * 10 ** decimals(), isMinted: false })); vestingSchedules.push(VestingSchedule({ releaseTime: 1693526400, amount: 1_000_000 * 10 ** decimals(), isMinted: false })); } // 铸造符合释放条件的代币,任何人可调用,资金只会进入预设金库无风险 function mintVestedTokens() external { for (uint256 i = 0; i < vestingSchedules.length; i++) { VestingSchedule storage schedule = vestingSchedules[i]; if (block.timestamp >= schedule.releaseTime && !schedule.isMinted) { schedule.isMinted = true; _mint(treasury, schedule.amount); } } } // 辅助方法:查询当前可铸造的总额度 function getAvailableMintAmount() external view returns (uint256) { uint256 available = 0; for (uint256 i = 0; i < vestingSchedules.length; i++) { VestingSchedule storage schedule = vestingSchedules[i]; if (block.timestamp >= schedule.releaseTime && !schedule.isMinted) { available += schedule.amount; } } return available; } }
注意事项
- 时间戳统一使用UTC时区的数值,避免时区偏差导致释放时间不符合预期,转换前建议用Unix时间戳工具校验数值正确性
- 计算释放额度时不要忘记乘以
10 ** decimals(),否则实际铸造的代币数量会比预期少10的18次方倍(ERC20默认精度为18位) - 接收代币的地址建议使用多签钱包或金库合约,避免单地址私钥泄露造成资产损失
- 若希望仅指定地址可调用铸币方法,可引入OpenZeppelin的
Ownable扩展,给mintVestedTokens方法添加onlyOwner修饰符即可 - 以太坊区块时间戳存在±几十秒的误差,不要对释放时间做秒级精度的要求,属于底层特性无法避免
内容的提问来源于stack exchange,提问作者Umair Janjua
相关产品推荐
相关产品推荐

