赞
踩
目录
编写这篇文章的目的是记录一下自己在开发代币合约中的过程,加深自己对合约功能的理解,在后续的学习过程中可以进行资料查阅,以及帮助有这方面开发要求或想学习的朋友进行更方便的入门。
区块链的本质是一个分布式记账系统,为保障其安全性使用了加密算法,同时具有数据公开透明、数据去中心化(及数据存在于任意节点上),从而数据安全可靠,防篡改、可追溯。数字代币是区块链的一个具体应用(区块链!=数字代币)。合约及为部署在某个链上的实现某些功能的应用程序,比较著名的是以太坊链。这里将使用以太坊链常用在线开发工具Remix - Ethereum IDE作为开发环境。
这里使用的是IBEP20接口作为开发功能性接口,这类似于各种开发语言中的继承,继承后即可使用改接口中上层中已经实现的功能,这种接口有很多如:ERC20、IBEP20等,主要区别为不同链需要实现不同的接口,这里的接口主要实现的功能为代币的相关操作。具体解释如下:
- interface IBEP20 {
- function totalSupply() external view returns (uint256);
-
- function balanceOf(address account) external view returns (uint256);
-
- function transfer(address recipient, uint256 amount) external returns (bool);
-
- function allowance(address owner, address spender) external view returns (uint256);
-
- function approve(address spender, uint256 amount) external returns (bool);
-
- function transferFrom(
- address sender,
- address recipient,
- uint256 amount
- ) external returns (bool);
-
- event Transfer(address indexed from, address indexed to, uint256 value);
-
- event Approval(address indexed owner, address indexed spender, uint256 value);
- }
- IBEP20 private tokenContract;
-
- struct LockInfo {
- uint256 amount;
- uint createTimestamp;
- uint256 unlockTimestamp;
- address owner;
- uint256 lockNo;
- }
- mapping(address=>LockInfo) private lockerBalance;
-
- event TokenLocked(address indexed account, uint256 amount, uint256 lockDuration);
-
- event TokenUnLocked(address indexed account, uint256 amount);
-
- uint256 private lockerPool=0;
-
- address[] private lockerAddresses;
-
- LockInfo[] private lockerHistoryList;
-
- uint8 constant _decimals = 9;
tokenContract:为关联的代币合约。(因为当前合约只做代币的锁仓功能,相当于依附另一个代币合约只实现功能)
LockInfo:结构体参数,用于存储用户锁定的代币数量(amount)、解锁时间(unlockTimestamp)、owner(拥有者)、创建时间(createTimestamp)、lockNo(锁定编号)
lockerBalance:Map键值对,这里存储owner和LockInfo,目的是在后续操作中可约快速使用地址查询到LockInfo信息(节省算力)
TokenLocked、TokenUnlocked:为自定义事件,用于在用户使用锁定和解锁功能后,提醒用户实现了相关操作。
lockerPool:这里定义为存储锁仓的代币数量。
lockerAddress[]:该列表用于所有存储代币的用户地址.
lockerHistoryList[]:改地址用于存储用户的锁仓历史列表。
(注:这里不使用lockerBalance进行遍历返回也是为了节省算力,更多的算力意味着用户需使用更多的手续费,这将影响用户使用)
_decimals:为小数点位数,这里保留9位小数。
constructor:构造参数,这里会在部署时传入代币地址,从而实现当前合约的初始化。
- function lockerToken(
- uint256 _amount,
- uint256 _lockDuration
- ) public {
- require(_lockDuration>0,"the lockDuration must be more than 0");
- require(!checkAddressLocked(msg.sender),"this address has locked,pls unlock");
- uint256 lockAmount=_amount*10**_decimals;
- require(tokenContract.balanceOf(msg.sender)>=lockAmount,"Token less amount");
- require(tokenContract.allowance(msg.sender,address(this))>=lockAmount, "Token allowance not");
- require(tokenContract.transferFrom(msg.sender,address(this),lockAmount), "Token transfer failed");
- uint256 unlockTimestamp = block.timestamp + _lockDuration;
- lockerBalance[msg.sender] = LockInfo({
- amount: lockAmount,
- createTimestamp: block.timestamp,
- unlockTimestamp: unlockTimestamp,
- owner:msg.sender,
- lockNo:lockerAddresses.length
- });
- lockerPool+=lockAmount;
- lockerAddresses.push(msg.sender);
- emit TokenLocked(msg.sender, _amount, _lockDuration);
- }
传入两个参数分别是锁定数量(_amount)和(_lockDuration)锁定时间。首先对锁定时间进行了检查,使锁定时间必须是>0的数,checkAddressLocked()检查用户是否被锁定,锁定的用户需先解锁才能再次锁定。对锁定数量进行精确度转换,使精确度符合链上精确度。对用户余额的检查,对用户授权的检查(锁定及用户需要当前合约转账,所以需要检查),然后使用transferFrom()请求者会向当前合约进行转移代币.unlockTimestamp为计算出来的过期时间(即当前时间+锁定时间),然后构建LockInfo结构体并放到lockerAddress中,锁仓池代币数量增加,将用户放入锁仓地址列表中。并发布代币锁定事件通知前端页面。
- function unLockerToken() public {
- LockInfo memory lockInfo = lockerBalance[msg.sender];
- require(lockInfo.unlockTimestamp <= block.timestamp, "Tokens still locked");
- require(tokenContract.approve(address(this),lockInfo.amount),"unlock approve failed");
- require(tokenContract.transfer(msg.sender, lockInfo.amount), "Token transfer failed");
- require(tokenContract.approve(address(this),0),"unlock approve 0 failed");
- lockerHistoryList.push(lockInfo);
- lockerPool-=lockInfo.amount;
- lockerAddresses[lockInfo.lockNo]=lockerAddresses[lockerAddresses.length-1];
- lockerAddresses.pop();
- delete lockerBalance[msg.sender];
- emit TokenUnLocked(msg.sender, lockInfo.amount);
- }
解锁会获取当前请求用户的锁定信息即lockInfo,然后判断当前时间是否大于解锁时间,通过后会授权当前合约可约执行转账的数量,然后使用transfer()进行转账,并解除当前合约授权(即使当前合约授权数量为0).将lockInfo添加到历史列表中,使锁仓池数量减去解锁数量,同时将锁仓的当前用户信息进行移除。delete删除锁仓用户的信息.同时发布用户解锁事件通知前端页面。
- function getLockerList() public view returns(LockInfo[] memory) {
- uint256 length = lockerAddresses.length;
- LockInfo[] memory lockInfos = new LockInfo[](length);
- for (uint256 i = 0; i < length; i++) {
- address addr = lockerAddresses[i];
- lockInfos[i] = lockerBalance[addr];
- }
-
- return lockInfos;
- }
这里首先获取锁定信息的长度,创建返回数据的数组并通过循环的方式获取锁仓信息并进行返回。
- function checkLockTimeExpired(address addr) public view returns (bool){
- if (checkAddressLocked(addr)){
- if(lockerBalance[addr].unlockTimestamp<=block.timestamp){
- return true;
- }
- }
- return false;
- }
- function getLockerHistoryList() public view returns(LockInfo[] memory){
- return lockerHistoryList;
- }
-
- function getUserLocker() public view returns(LockInfo memory){
- return lockerBalance[msg.sender];
- }
-
- function getLockerSize() public view returns(uint256){
- return lockerAddresses.length;
- }
-
- function getLockPool() public view returns(uint256){
- return lockerPool;
- }
-
- function getTimestamp() public view returns(uint256){
- return block.timestamp;
- }
除了主要功能的锁定、解锁、锁仓列表方法外,这边还编写了如获取锁仓代币数量、检查锁仓时间是否过期、获取锁仓人数、历史列表等方法,因其实现比较简单,这边就不进行记录了。
BabyBonkLocker | Address 0x285387e8286e351047464750127142ed322a0a7f | BscScan
这边后面会开放界面代码,请关注更新!!!!
录屏_选择区域_20240225093939
- /**
- *Submitted for verification at BscScan.com on 2024-02-01
- */
-
- // SPDX-License-Identifier: MIT
- pragma solidity ^0.8.22;
-
- interface IBEP20 {
- function totalSupply() external view returns (uint256);
-
- function balanceOf(address account) external view returns (uint256);
-
- function transfer(address recipient, uint256 amount) external returns (bool);
-
- function allowance(address owner, address spender) external view returns (uint256);
-
- function approve(address spender, uint256 amount) external returns (bool);
-
- function transferFrom(
- address sender,
- address recipient,
- uint256 amount
- ) external returns (bool);
-
- event Transfer(address indexed from, address indexed to, uint256 value);
-
- event Approval(address indexed owner, address indexed spender, uint256 value);
- }
- abstract contract Context {
- function _msgSender() internal view virtual returns (address) {
- return msg.sender;
- }
-
- function _msgData() internal view virtual returns (bytes calldata) {
- this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
- return msg.data;
- }
- }
-
- abstract contract Ownable is Context {
- address private _owner;
-
- event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
-
- constructor() {
- _setOwner(_msgSender());
- }
-
- function owner() public view virtual returns (address) {
- return _owner;
- }
-
- modifier onlyOwner() {
- require(owner() == _msgSender(), "Ownable: caller is not the owner");
- _;
- }
-
- function renounceOwnership() public virtual onlyOwner {
- _setOwner(address(0));
- }
-
- function transferOwnership(address newOwner) public virtual onlyOwner {
- require(newOwner != address(0), "Ownable: new owner is the zero address");
- _setOwner(newOwner);
- }
-
- function _setOwner(address newOwner) private {
- address oldOwner = _owner;
- _owner = newOwner;
- emit OwnershipTransferred(oldOwner, newOwner);
- }
- }
- contract BabyBonkLocker is Context, Ownable{
-
- IBEP20 private tokenContract;
-
- struct LockInfo {
- uint256 amount;
- uint createTimestamp;
- uint256 unlockTimestamp;
- address owner;
- uint256 lockNo;
- }
- mapping(address=>LockInfo) private lockerBalance;
-
- event TokenLocked(address indexed account, uint256 amount, uint256 lockDuration);
-
- event TokenUnLocked(address indexed account, uint256 amount);
-
- uint256 private lockerPool=0;
-
- address[] private lockerAddresses;
-
- LockInfo[] private lockerHistoryList;
-
- uint8 constant _decimals = 9;
-
-
- constructor(
- address payable _token
- ){
- tokenContract=IBEP20(_token);
- }
- function lockerToken(
- uint256 _amount,
- uint256 _lockDuration
- ) public {
- require(_lockDuration>0,"the lockDuration must be more than 0");
- require(!checkAddressLocked(msg.sender),"this address has locked,pls unlock");
- uint256 lockAmount=_amount*10**_decimals;
- require(tokenContract.balanceOf(msg.sender)>=lockAmount,"Token less amount");
- require(tokenContract.allowance(msg.sender,address(this))>=lockAmount, "Token allowance not");
- require(tokenContract.transferFrom(msg.sender,address(this),lockAmount), "Token transfer failed");
- uint256 unlockTimestamp = block.timestamp + _lockDuration;
- lockerBalance[msg.sender] = LockInfo({
- amount: lockAmount,
- createTimestamp: block.timestamp,
- unlockTimestamp: unlockTimestamp,
- owner:msg.sender,
- lockNo:lockerAddresses.length
- });
- lockerPool+=lockAmount;
- lockerAddresses.push(msg.sender);
- emit TokenLocked(msg.sender, _amount, _lockDuration);
- }
-
- function unLockerToken() public {
- LockInfo memory lockInfo = lockerBalance[msg.sender];
- require(lockInfo.unlockTimestamp <= block.timestamp, "Tokens still locked");
- require(tokenContract.approve(address(this),lockInfo.amount),"unlock approve failed");
- require(tokenContract.transfer(msg.sender, lockInfo.amount), "Token transfer failed");
- require(tokenContract.approve(address(this),0),"unlock approve 0 failed");
- lockerHistoryList.push(lockInfo);
- lockerPool-=lockInfo.amount;
- lockerAddresses[lockInfo.lockNo]=lockerAddresses[lockerAddresses.length-1];
- lockerAddresses.pop();
- delete lockerBalance[msg.sender];
- emit TokenUnLocked(msg.sender, lockInfo.amount);
- }
- function checkAddressLocked(address addr) public view returns (bool) {
- return lockerBalance[addr].unlockTimestamp !=0;
- }
-
- function getLockerList() public view returns(LockInfo[] memory) {
- uint256 length = lockerAddresses.length;
- LockInfo[] memory lockInfos = new LockInfo[](length);
- for (uint256 i = 0; i < length; i++) {
- address addr = lockerAddresses[i];
- lockInfos[i] = lockerBalance[addr];
- }
-
- return lockInfos;
- }
- function checkLockTimeExpired(address addr) public view returns (bool){
- if (checkAddressLocked(addr)){
- if(lockerBalance[addr].unlockTimestamp<=block.timestamp){
- return true;
- }
- }
- return false;
- }
- function getLockerHistoryList() public view returns(LockInfo[] memory){
- return lockerHistoryList;
- }
-
- function getUserLocker() public view returns(LockInfo memory){
- return lockerBalance[msg.sender];
- }
-
- function getLockerSize() public view returns(uint256){
- return lockerAddresses.length;
- }
-
- function getLockPool() public view returns(uint256){
- return lockerPool;
- }
-
- function getTimestamp() public view returns(uint256){
- return block.timestamp;
- }
-
- }
注:单纯的兴趣爱好和学习过程,其中不涉及任何其它的如投资理财方面的建议。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。