快速实现一个约定代币归属条款的智能合约之线性释放

  • 木西
  • 发布于 1天前
  • 阅读 30

前言本文实现一个线性释放合约,主要用来解决以下问题:防止市场抛售压力、激励团队和投资者、稳定市场和建立信任线性释放定义:一种常见的代币或股权分配机制,通常用于激励团队成员、早期投资者或顾问在一定时间内持续为项目做出贡献。线性释放机制确保代币或股权在预定的时间内逐步解锁,而不是一次性发放。

前言

本文实现一个线性释放合约,主要用来解决以下问题: 防止市场抛售压力、激励团队和投资者、稳定市场和建立信任

线性释放

定义:一种常见的代币或股权分配机制,通常用于激励团队成员、早期投资者或顾问在一定时间内持续为项目做出贡献。线性释放机制确保代币或股权在预定的时间内逐步解锁,而不是一次性发放。这种机制有助于保持团队的稳定性和长期承诺,同时也为项目提供了一种激励机制,确保关键人员在项目的关键阶段持续参与

特点
  1. 逐步解锁:代币或股权在预定的时间内逐步解锁,通常以固定的时间间隔(如每月或每季度)释放一定比例。
  2. 激励长期参与:通过逐步解锁,激励团队成员和投资者在项目的关键阶段持续参与,确保他们对项目的长期成功有共同的利益。
  3. 减少短期套现风险:避免一次性发放代币或股权后,团队成员或投资者立即套现,从而减少对项目的短期负面影响。
  4. 灵活的释放计划:可以根据项目的具体需求和目标,定制不同的释放计划,包括释放的总时间、释放的频率和每次释放的比例
    场景
  5. 团队激励:确保团队成员在项目的关键阶段持续参与,激励他们为项目的长期成功做出贡献。
  6. 早期投资者:激励早期投资者在项目的关键阶段持续支持项目,确保他们对项目的长期成功有共同的利益。
  7. 顾问和合作伙伴:激励顾问和合作伙伴在项目的关键阶段提供持续的支持和资源,确保他们对项目的长期成功有共同的利益。

    合约开发

    
    // 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;
    }
}

}

编译指令

npx hardhat compile

# 合约测试
**说明**:测试释放方法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`)

    })
})

})

测试指令

npx hardhat test ./test/xxx.js

# 合约部署

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"];

部署指令

npx hardhat deploy


# 总结
以上就是线性释放合约开发、测试、部署全流程以及合约的使用场景的介绍,`注意`:在调用释放方法`release`时链接受益人账号,`参数`:代币的合约地址;
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
木西
木西
江湖只有他的大名,没有他的介绍。