前言本文实现一个线性释放合约,主要用来解决以下问题:防止市场抛售压力、激励团队和投资者、稳定市场和建立信任线性释放定义:一种常见的代币或股权分配机制,通常用于激励团队成员、早期投资者或顾问在一定时间内持续为项目做出贡献。线性释放机制确保代币或股权在预定的时间内逐步解锁,而不是一次性发放。
本文实现一个线性释放合约,主要用来解决以下问题: 防止市场抛售压力、激励团队和投资者、稳定市场和建立信任
线性释放
定义:一种常见的代币或股权分配机制,通常用于激励团队成员、早期投资者或顾问在一定时间内持续为项目做出贡献。线性释放机制确保代币或股权在预定的时间内逐步解锁,而不是一次性发放。这种机制有助于保持团队的稳定性和长期承诺,同时也为项目提供了一种激励机制,确保关键人员在项目的关键阶段持续参与
特点
- 逐步解锁:代币或股权在预定的时间内逐步解锁,通常以固定的时间间隔(如每月或每季度)释放一定比例。
- 激励长期参与:通过逐步解锁,激励团队成员和投资者在项目的关键阶段持续参与,确保他们对项目的长期成功有共同的利益。
- 减少短期套现风险:避免一次性发放代币或股权后,团队成员或投资者立即套现,从而减少对项目的短期负面影响。
- 灵活的释放计划:可以根据项目的具体需求和目标,定制不同的释放计划,包括释放的总时间、释放的频率和每次释放的比例
场景
- 团队激励:确保团队成员在项目的关键阶段持续参与,激励他们为项目的长期成功做出贡献。
- 早期投资者:激励早期投资者在项目的关键阶段持续支持项目,确保他们对项目的长期成功有共同的利益。
- 顾问和合作伙伴:激励顾问和合作伙伴在项目的关键阶段提供持续的支持和资源,确保他们对项目的长期成功有共同的利益。
合约开发
// SPDX-License-Identifier: MIT // wtf.academy pragma solidity ^0.8.22; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "hardhat/console.sol"; /** * @title ERC20代币线性释放 * @dev 这个合约会将ERC20代币线性释放给给受益人`_beneficiary`。 * 释放的代币可以是一种,也可以是多种。释放周期由起始时间`_start`和时长`_duration`定义。 * 所有转到这个合约上的代币都会遵循同样的线性释放周期,并且需要受益人调用`release()`函数提取。 * 合约是从OpenZeppelin的VestingWallet简化而来。 */ contract LinearRelease { // 事件 event ERC20Released(address indexed token, uint256 amount); // 提币事件
// 状态变量
mapping(address => uint256) public erc20Released; // 代币地址->释放数量的映射,记录受益人已领取的代币数量
address public immutable beneficiary; // 受益人地址
uint256 public immutable start; // 归属期起始时间戳
uint256 public immutable duration; // 归属期 (秒)
/**
* @dev 初始化受益人地址,释放周期(秒), 起始时间戳(当前区块链时间戳)
*/
constructor(
address beneficiaryAddress,
uint256 durationSeconds
) {
require(beneficiaryAddress != address(0), "VestingWallet: beneficiary is zero address");
beneficiary = beneficiaryAddress;
start = block.timestamp;
duration = durationSeconds;
}
/**
* @dev 受益人提取已释放的代币。
* 调用vestedAmount()函数计算可提取的代币数量,然后transfer给受益人。
* 释放 {ERC20Released} 事件.
*/
function release(address token) public {
// 调用vestedAmount()函数计算可提取的代币数量
uint256 releasable = vestedAmount(token, uint256(block.timestamp)) - erc20Released[token];
// 更新已释放代币数量
erc20Released[token] += releasable;
// 转代币给受益人
emit ERC20Released(token, releasable);
IERC20(token).transfer(beneficiary, releasable);
}
/**
* @dev 根据线性释放公式,计算已经释放的数量。开发者可以通过修改这个函数,自定义释放方式。
* @param token: 代币地址
* @param timestamp: 查询的时间戳
*/
function vestedAmount(address token, uint256 timestamp) public view returns (uint256) {
// 合约里总共收到了多少代币(当前余额 + 已经提取)
uint256 totalAllocation = IERC20(token).balanceOf(address(this)) + erc20Released[token];
// 根据线性释放公式,计算已经释放的数量
if (timestamp < start) {
return 0;
} else if (timestamp > start + duration) {
return totalAllocation;
} else {
return (totalAllocation * (timestamp - start)) / duration;
}
}
}
# 合约测试
**说明**:测试释放方法release,1.保证链接的时受益人的账号地址,2.传递参数:代币的合约地址
const {ethers,getNamedAccounts,deployments} = require("hardhat"); const { assert,expect } = require("chai"); describe("LinearRelease",function(){ let LinearRelease;//合约 let MyToken;//代币合约 let firstAccount//第一个账户 let secondAccount//第二个账户 let addr1; let addr2; beforeEach(async function(){ await deployments.fixture(["token","LinearRelease"]); [addr1,addr2]=await ethers.getSigners(); firstAccount=(await getNamedAccounts()).firstAccount; secondAccount=(await getNamedAccounts()).secondAccount; //代币 const TokenDeployment = await ethers.getContract("MyToken");//获取合约 MyToken = await ethers.getContractAt("MyToken",TokenDeployment.address);//已经部署的合约交互 //线性释放
const LinearReleaseDeployment = await deployments.get("LinearRelease");
LinearRelease = await ethers.getContractAt("LinearRelease",LinearReleaseDeployment.address);//已经部署的合约交互
});
describe("LinearRelease测试",function(){
it("测试",async function(){
// 获取当前区块时间
const currentTime = await ethers.provider.getBlock("latest").then(block => block.timestamp);
console.log("获取当前区块时间",currentTime)
// 预定执行时间:当前时间 + 100s
const executeTime = currentTime + 100;
console.log("预定执行时间",executeTime)
//获取token账号余额
console.log(await MyToken.balanceOf(firstAccount))
//把代币发给线性释放合约
await MyToken.mint(firstAccount,ethers.utils.parseEther("200"));
console.log(await MyToken.balanceOf(addr1.address))
await MyToken.transfer(LinearRelease.address,ethers.utils.parseEther("1200"));
console.log("线性合约余额",await MyToken.balanceOf(LinearRelease.address))
console.log("代币账号余额",await MyToken.balanceOf(firstAccount))
let beneficiary=await LinearRelease.beneficiary()
console.log("收益人地址",beneficiary)
console.log("开始时间",await LinearRelease.start())
let time=await LinearRelease.duration()
console.log("时长秒",time)
//模拟10s后修改 动态设置时间来模拟
let simulateTime=10;
await ethers.provider.send("evm_increaseTime", [simulateTime]);
await ethers.provider.send("evm_mine", []);
//线性释放 参数说明 保证收益人账号正确链接,release传的参数 锁定代币合约地址
await LinearRelease.connect(addr1).release(MyToken.address);
let balance=await MyToken.balanceOf(addr1.address)
console.log("线性合约释放的代币,受益人的代币额度",`${ethers.utils.formatEther(balance)} ETH`)
})
})
})
# 合约部署
module.exports = async function ({getNamedAccounts,deployments}) {
const firstAccount= (await getNamedAccounts()).firstAccount;
const secondAccount= (await getNamedAccounts()).secondAccount;
const {deploy,log}=deployments;
const LinearRelease=await deploy("LinearRelease",{
from:firstAccount,
args: [firstAccount,100],//参数
log: true,
})
console.log('LinearRelease合约地址',LinearRelease.address)
}
module.exports.tags = ["all", "LinearRelease"];
# 总结
以上就是线性释放合约开发、测试、部署全流程以及合约的使用场景的介绍,`注意`:在调用释放方法`release`时链接受益人账号,`参数`:代币的合约地址;
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!