代币锁定系统
代币锁定系统用于实现代币的时间锁定和条件解锁,常用于团队代币、投资者代币的锁定管理。本教程将介绍如何实现一个安全的代币锁定系统。
功能特性
- 时间锁定机制
- 分批解锁支持
- 多受益人管理
- 锁定条件设置
- 紧急操作机制
合约实现
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
/**
* @title TokenLock
* @dev 代币锁定合约实现
*/
contract TokenLock is Ownable, ReentrancyGuard {
using Counters for Counters.Counter;
// 锁定信息结构
struct LockInfo {
address token; // 代币地址
address beneficiary; // 受益人地址
uint256 totalAmount; // 总锁定量
uint256 releasedAmount; // 已释放量
uint256 startTime; // 开始时间
uint256 endTime; // 结束时间
uint256[] releasePoints; // 释放时间点
uint256[] releaseRatios; // 释放比例
bool revocable; // 是否可撤销
bool revoked; // 是否已撤销
}
// 锁定ID计数器
Counters.Counter private lockIdCounter;
// 锁定信息映射
mapping(uint256 => LockInfo) public locks;
// 用户锁定ID映射 user => lockIds
mapping(address => uint256[]) public userLocks;
// 事件
event LockCreated(uint256 indexed lockId, address indexed token, address indexed beneficiary);
event TokensReleased(uint256 indexed lockId, uint256 amount);
event LockRevoked(uint256 indexed lockId);
event BeneficiaryUpdated(uint256 indexed lockId, address indexed oldBeneficiary, address indexed newBeneficiary);
/**
* @dev 创建新的锁定
*/
function createLock(
address _token,
address _beneficiary,
uint256 _totalAmount,
uint256 _startTime,
uint256 _endTime,
uint256[] calldata _releasePoints,
uint256[] calldata _releaseRatios,
bool _revocable
) external returns (uint256) {
require(_token != address(0), "Invalid token address");
require(_beneficiary != address(0), "Invalid beneficiary address");
require(_totalAmount > 0, "Invalid amount");
require(_startTime < _endTime, "Invalid time range");
require(
_releasePoints.length == _releaseRatios.length,
"Points and ratios length mismatch"
);
require(
_releasePoints.length > 0,
"No release points specified"
);
// 验证释放时间点和比例
uint256 totalRatio = 0;
for (uint256 i = 0; i < _releasePoints.length; i++) {
require(
_releasePoints[i] >= _startTime && _releasePoints[i] <= _endTime,
"Invalid release point"
);
if (i > 0) {
require(
_releasePoints[i] > _releasePoints[i-1],
"Release points must be in order"
);
}
totalRatio += _releaseRatios[i];
}
require(totalRatio == 100, "Total ratio must be 100");
// 转入代币
IERC20(_token).transferFrom(msg.sender, address(this), _totalAmount);
// 创建锁定信息
uint256 lockId = lockIdCounter.current();
lockIdCounter.increment();
locks[lockId] = LockInfo({
token: _token,
beneficiary: _beneficiary,
totalAmount: _totalAmount,
releasedAmount: 0,
startTime: _startTime,
endTime: _endTime,
releasePoints: _releasePoints,
releaseRatios: _releaseRatios,
revocable: _revocable,
revoked: false
});
userLocks[_beneficiary].push(lockId);
emit LockCreated(lockId, _token, _beneficiary);
return lockId;
}
/**
* @dev 释放代币
*/
function release(uint256 _lockId) external nonReentrant {
LockInfo storage lock = locks[_lockId];
require(!lock.revoked, "Lock revoked");
require(
msg.sender == lock.beneficiary,
"Only beneficiary can release"
);
uint256 releasableAmount = getReleasableAmount(_lockId);
require(releasableAmount > 0, "No tokens to release");
lock.releasedAmount += releasableAmount;
IERC20(lock.token).transfer(lock.beneficiary, releasableAmount);
emit TokensReleased(_lockId, releasableAmount);
}
/**
* @dev 计算可释放金额
*/
function getReleasableAmount(uint256 _lockId) public view returns (uint256) {
LockInfo storage lock = locks[_lockId];
if (lock.revoked || block.timestamp < lock.startTime) {
return 0;
}
uint256 currentReleaseRatio = 0;
for (uint256 i = 0; i < lock.releasePoints.length; i++) {
if (block.timestamp >= lock.releasePoints[i]) {
currentReleaseRatio = 0;
for (uint256 j = 0; j <= i; j++) {
currentReleaseRatio += lock.releaseRatios[j];
}
}
}
uint256 releasableAmount = (lock.totalAmount * currentReleaseRatio) / 100;
return releasableAmount - lock.releasedAmount;
}
/**
* @dev 撤销锁定(仅管理员)
*/
function revoke(uint256 _lockId) external onlyOwner {
LockInfo storage lock = locks[_lockId];
require(lock.revocable, "Lock not revocable");
require(!lock.revoked, "Lock already revoked");
lock.revoked = true;
uint256 remainingAmount = lock.totalAmount - lock.releasedAmount;
if (remainingAmount > 0) {
IERC20(lock.token).transfer(owner(), remainingAmount);
}
emit LockRevoked(_lockId);
}
/**
* @dev 更新受益人
*/
function updateBeneficiary(uint256 _lockId, address _newBeneficiary) external {
require(_newBeneficiary != address(0), "Invalid beneficiary address");
LockInfo storage lock = locks[_lockId];
require(
msg.sender == lock.beneficiary,
"Only current beneficiary can update"
);
address oldBeneficiary = lock.beneficiary;
lock.beneficiary = _newBeneficiary;
// 更新用户锁定映射
uint256[] storage oldUserLockIds = userLocks[oldBeneficiary];
for (uint256 i = 0; i < oldUserLockIds.length; i++) {
if (oldUserLockIds[i] == _lockId) {
oldUserLockIds[i] = oldUserLockIds[oldUserLockIds.length - 1];
oldUserLockIds.pop();
break;
}
}
userLocks[_newBeneficiary].push(_lockId);
emit BeneficiaryUpdated(_lockId, oldBeneficiary, _newBeneficiary);
}
/**
* @dev 获取用户的所有锁定ID
*/
function getUserLocks(address _user) external view returns (uint256[] memory) {
return userLocks[_user];
}
/**
* @dev 获取锁定详情
*/
function getLockInfo(uint256 _lockId)
external
view
returns (
address token,
address beneficiary,
uint256 totalAmount,
uint256 releasedAmount,
uint256 startTime,
uint256 endTime,
uint256[] memory releasePoints,
uint256[] memory releaseRatios,
bool revocable,
bool revoked
)
{
LockInfo storage lock = locks[_lockId];
return (
lock.token,
lock.beneficiary,
lock.totalAmount,
lock.releasedAmount,
lock.startTime,
lock.endTime,
lock.releasePoints,
lock.releaseRatios,
lock.revocable,
lock.revoked
);
}
/**
* @dev 获取总锁定数量
*/
function getTotalLocks() external view returns (uint256) {
return lockIdCounter.current();
}
/**
* @dev 批量释放代币
*/
function batchRelease(uint256[] calldata _lockIds) external nonReentrant {
for (uint256 i = 0; i < _lockIds.length; i++) {
uint256 lockId = _lockIds[i];
LockInfo storage lock = locks[lockId];
require(!lock.revoked, "Lock revoked");
require(
msg.sender == lock.beneficiary,
"Only beneficiary can release"
);
uint256 releasableAmount = getReleasableAmount(lockId);
if (releasableAmount > 0) {
lock.releasedAmount += releasableAmount;
IERC20(lock.token).transfer(lock.beneficiary, releasableAmount);
emit TokensReleased(lockId, releasableAmount);
}
}
}
/**
* @dev 紧急提取(仅管理员)
*/
function emergencyWithdraw(
address _token,
address _to,
uint256 _amount
) external onlyOwner {
require(_token != address(0), "Invalid token address");
require(_to != address(0), "Invalid recipient address");
require(_amount > 0, "Invalid amount");
IERC20(_token).transfer(_to, _amount);
}
/**
* @dev 检查锁定状态
*/
function checkLockStatus(uint256 _lockId)
external
view
returns (
bool isActive,
bool isRevoked,
bool canRelease,
uint256 releasableAmount,
uint256 remainingAmount
)
{
LockInfo storage lock = locks[_lockId];
isActive = block.timestamp >= lock.startTime && block.timestamp <= lock.endTime;
isRevoked = lock.revoked;
releasableAmount = getReleasableAmount(_lockId);
canRelease = releasableAmount > 0;
remainingAmount = lock.totalAmount - lock.releasedAmount;
return (isActive, isRevoked, canRelease, releasableAmount, remainingAmount);
}
}
关键概念
锁定机制
锁定系统支持:
- 时间锁定
- 分批释放
- 条件解锁
- 可撤销设置
释放计算
释放机制包括:
- 时间点验证
- 比例计算
- 已释放追踪
- 余额检查
权限管理
权限控制:
- 受益人操作
- 管理员功能
- 撤销权限
- 受益人转移
安全考虑
时间控制
- 时间点验证
- 顺序检查
- 状态更新
金额验证
- 余额检查
- 比例验证
- 释放计算
权限管理
- 角色验证
- 操作限制
- 状态保护
紧急处理
- 撤销机制
- 余额返还
- 状态恢复
最佳实践
锁定设计
- 合理的时间安排
- 适当的释放比例
- 灵活的条件设置
数据管理
- 状态追踪
- 记录完整
- 查询便利
用户体验
- 操作简单
- 状态透明
- 提示清晰
异常处理
- 错误检查
- 状态回滚
- 日志记录
扩展功能
- 多代币支持
- 条件触发
- 投票权委托
- 分红权益
- 转让限制
应用场景
团队代币
- 长期激励
- 权益绑定
- 退出机制
投资锁定
- 投资承诺
- 风险控制
- 利益对齐
项目治理
- 权益锁定
- 投票权管理
- 社区建设
总结
代币锁定系统是项目代币管理的重要工具。通过本教程,你可以:
- 实现灵活的锁定机制
- 确保资金安全
- 优化用户体验
- 支持项目治理
常见问题解答(FAQ)
1. 基本概念
Q: 什么是代币锁定? A: 代币锁定是一种智能合约机制,主要特点包括:
- 时间锁定控制
- 分批释放管理
- 条件触发解锁
- 多方权益保护
- 紧急操作支持
Q: 代币锁定有哪些应用场景? A: 主要应用包括:
- 团队代币管理
- 投资者代币锁定
- 项目激励计划
- 生态基金管理
- 流动性管理
2. 功能相关
Q: 如何设计锁定计划? A: 设计要点:
solidity
function createLockPlan(
uint256 amount,
uint256 duration,
uint256[] memory milestones
) public pure returns (uint256[] memory) {
// 1. 计算释放点
uint256[] memory releases = new uint256[](milestones.length);
// 2. 设置里程碑
for (uint256 i = 0; i < milestones.length; i++) {
releases[i] = amount * milestones[i] / 100;
}
return releases;
}
Q: 如何管理多个锁定计划? A: 管理策略:
- 批量创建
- 统一管理
- 状态追踪
- 自动执行
- 异常处理
3. 安全相关
Q: 锁定系统有什么风险? A: 主要风险包括:
- 合约漏洞风险
- 权限管理风险
- 时间控制风险
- 紧急操作风险
- 代币安全风险
Q: 如何保护锁定资产? A: 安全措施包括:
- 多重签名
- 时间锁定
- 权限分级
- 紧急暂停
- 审计验证
4. 优化相关
Q: 如何优化锁定机制? A: 优化策略:
- 批量处理
- Gas优化
- 存储优化
- 逻辑简化
- 接口标准化
Q: 如何提高系统效率? A: 改进方案:
- 事件监听
- 状态缓存
- 批量操作
- 智能调度
- 自动化处理
5. 实现细节
Q: 如何实现分批释放? A: 实现机制:
solidity
function calculateRelease(
uint256 lockId,
uint256 timestamp
) internal view returns (uint256) {
// 1. 获取锁定信息
LockInfo storage lock = locks[lockId];
// 2. 计算可释放金额
uint256 releasable = 0;
for (uint256 i = 0; i < lock.releasePoints.length; i++) {
if (timestamp >= lock.releasePoints[i]) {
releasable += lock.amounts[i];
}
}
return releasable;
}
Q: 如何处理紧急情况? A: 处理机制:
- 紧急暂停
- 权限转移
- 强制解锁
- 状态回滚
- 资金保护
6. 最佳实践
Q: 锁定系统开发建议? A: 开发建议:
- 完整测试
- 安全审计
- 权限管理
- 文档完善
- 监控预警
Q: 如何提高系统可靠性? A: 改进方案:
- 故障检测
- 自动恢复
- 状态验证
- 日志记录
- 备份机制
7. 错误处理
Q: 常见错误及解决方案? A: 错误类型:
"Lock not found"
: 检查ID"Not released yet"
: 等待时间"Already released"
: 验证状态"Invalid amount"
: 检查数量"Not authorized"
: 确认权限
Q: 如何处理异常情况? A: 处理机制:
- 状态回滚
- 错误记录
- 通知机制
- 手动干预
- 补偿机制
8. 升级维护
Q: 如何升级锁定系统? A: 升级策略:
- 代理合约
- 数据迁移
- 兼容处理
- 测试验证
- 平滑过渡
Q: 如何监控系统状态? A: 监控方案:
- 锁定状态
- 释放进度
- 异常检测
- 资金流向
- 操作日志
9. 与其他系统集成
Q: 如何与治理系统集成? A: 集成方案:
- 权重计算
- 投票限制
- 提案控制
- 执行延迟
- 状态同步
Q: 如何实现跨链锁定? A: 实现策略:
- 跨链消息
- 状态同步
- 资产映射
- 安全验证
- 异常处理