1、流程圖
2寄猩、ERC20代碼詳解
? ? 1)、基本合約提供總發(fā)行量骑疆,余額田篇,交易轉(zhuǎn)賬函數(shù)以及轉(zhuǎn)賬事件
2)、SafeMath加減乘除library 庫
library SafeMath {
? /**
? * @dev Multiplies two numbers, throws on overflow.
? */
? function mul(uint256 a, uint256 b) internal pure returns (uint256) {
? ? if (a == 0) {
? ? ? return 0;
? ? }
? ? uint256 c = a * b;
? ? assert(c / a == b);
? ? return c;
? }
? /**
? * @dev Integer division of two numbers, truncating the quotient.
? */
? function div(uint256 a, uint256 b) internal pure returns (uint256) {
? ? // assert(b > 0); // Solidity automatically throws when dividing by 0
? ? uint256 c = a / b;
? ? // assert(a == b * c + a % b); // There is no case in which this doesn't hold
? ? return c;
? }
? /**
? * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
? */
? function sub(uint256 a, uint256 b) internal pure returns (uint256) {
? ? assert(b <= a);
? ? return a - b;
? }
? /**
? * @dev Adds two numbers, throws on overflow.
? */
? function add(uint256 a, uint256 b) internal pure returns (uint256) {
? ? uint256 c = a + b;
? ? assert(c >= a);
? ? return c;
? }
}
?3)箍铭、ERC20合約提供允許轉(zhuǎn)賬金額查詢泊柬,從A賬戶到B賬戶的交易,授權(quán)A-》B的轉(zhuǎn)賬以及授權(quán)事件
4)坡疼、實(shí)現(xiàn)ERC20Basic合約的function
5)彬呻、實(shí)現(xiàn)ERC20, BasicToken合約
3、鎖倉解鎖代碼:
1)柄瑰、創(chuàng)建創(chuàng)世塊
2)闸氮、定義管理員,為了對(duì)代幣進(jìn)行管理教沾,首先需要給合約添加一個(gè)管理者蒲跨。
3)、鎖倉解鎖合約核心代碼授翻,由于注釋完備或悲,所以就不敘述。
/**
? * @dev 鎖倉解鎖合約
? */
contract LibraTokenVault is Ownable {
? ? using SafeMath for uint256;
? ? /**
? ? * @dev 創(chuàng)建三個(gè)賬戶地址堪唐,將解鎖后的余額預(yù)分配到三個(gè)地址
? ? * 每個(gè)地址根據(jù)不同的解鎖時(shí)間巡语,在調(diào)用合約后將對(duì)應(yīng)的余額按照一定規(guī)則轉(zhuǎn)移到相應(yīng)的地址
? ? */
? ? address public teamReserveWallet = 0x373c69fDedE072A3F5ab1843a0e5fE0102Cc6793;
? ? address public firstReserveWallet = 0x99C83f62DBE1a488f9C9d370DA8e86EC55224eB4;
? ? address public secondReserveWallet = 0x90DfF11810dA6227d348C86C59257C1C0033D307;
? ? /** 三個(gè)賬戶地址對(duì)應(yīng)的鎖倉金額 */
? ? uint256 public teamReserveAllocation = 2 * (10 ** 8) * (10 ** 18);
? ? uint256 public firstReserveAllocation = 15 * (10 ** 7) * (10 ** 18);
? ? uint256 public secondReserveAllocation = 15 * (10 ** 7) * (10 ** 18);
? ? // 總鎖倉的金額
? ? uint256 public totalAllocation = 5 * (10 ** 8) * (10 ** 18);
? ? /** 三個(gè)賬戶地址對(duì)應(yīng)的鎖倉時(shí)間 */
? ? uint256 public teamTimeLock = 2 * 365 days;
? ? /** 分多少次解鎖到對(duì)應(yīng)的地址 */
? ? uint256 public teamVestingStages = 8;
? ? uint256 public firstReserveTimeLock = 2 * 365 days;
? ? uint256 public secondReserveTimeLock = 3 * 365 days;
? ? /** Reserve allocations */
? ? mapping(address => uint256) public allocations;? // 每個(gè)地址對(duì)應(yīng)鎖倉金額的映射表
? ? /** When timeLocks are over (UNIX Timestamp)? */?
? ? mapping(address => uint256) public timeLocks;? // 每個(gè)地址對(duì)應(yīng)鎖倉時(shí)間的映射表
? ? /** How many tokens each reserve wallet has claimed */
? ? mapping(address => uint256) public claimed;? // 每個(gè)地址對(duì)應(yīng)鎖倉后已經(jīng)解鎖的金額的映射表
? ? /** When this vault was locked (UNIX Timestamp)*/
? ? uint256 public lockedAt = 0;
? ? LibraToken public token;
? ? /** Allocated reserve tokens */
? ? event Allocated(address wallet, uint256 value);
? ? /** Distributed reserved tokens */
? ? event Distributed(address wallet, uint256 value);
? ? /** Tokens have been locked */
? ? event Locked(uint256 lockTime);
? ? //Any of the three reserve wallets
? ? modifier onlyReserveWallets {? // 合約調(diào)用者的鎖倉余額大于0才能查詢鎖倉余額
? ? ? ? require(allocations[msg.sender] > 0);
? ? ? ? _;
? ? }
? ? //Only Libra team reserve wallet
? ? modifier onlyTeamReserve {? // 合約調(diào)用者的地址為teamReserveWallet
? ? ? ? require(msg.sender == teamReserveWallet);
? ? ? ? require(allocations[msg.sender] > 0);
? ? ? ? _;
? ? }
? ? //Only first and second token reserve wallets
? ? modifier onlyTokenReserve { // 合約調(diào)用者的地址為firstReserveWallet或者secondReserveWallet
? ? ? ? require(msg.sender == firstReserveWallet || msg.sender == secondReserveWallet);
? ? ? ? require(allocations[msg.sender] > 0);
? ? ? ? _;
? ? }
? ? //Has not been locked yet
? ? modifier notLocked {? // 未鎖定
? ? ? ? require(lockedAt == 0);
? ? ? ? _;
? ? }
? ? modifier locked { // 鎖定
? ? ? ? require(lockedAt > 0);
? ? ? ? _;
? ? }
? ? //Token allocations have not been set
? ? modifier notAllocated {? // 沒有為每個(gè)地址分配對(duì)應(yīng)的鎖倉金額時(shí)
? ? ? ? require(allocations[teamReserveWallet] == 0);
? ? ? ? require(allocations[firstReserveWallet] == 0);
? ? ? ? require(allocations[secondReserveWallet] == 0);
? ? ? ? _;
? ? }
? ? function LibraTokenVault(ERC20 _token) public {? // 構(gòu)造LibraToken模式的合約
? ? ? ? owner = msg.sender;? // msg.sender 是指直接調(diào)用當(dāng)前合約的調(diào)用方地址
? ? ? ? token = LibraToken(_token);
? ? }
? ? /* 當(dāng)合約調(diào)用者是ower時(shí)才可執(zhí)行鎖倉功能,鎖倉為解鎖對(duì)應(yīng)的地址分配對(duì)應(yīng)金額
? ? * 調(diào)用分配事件
? ? * 分配成功后淮菠,執(zhí)行鎖操作
? ? */
? ? function allocate() public notLocked notAllocated onlyOwner {?
? ? ? ? //Makes sure Token Contract has the exact number of tokens
? ? ? ? require(token.balanceOf(address(this)) == totalAllocation);? // 合約調(diào)用方要求鎖的金額與預(yù)定義分配的金額是否相等
? ? ? ? allocations[teamReserveWallet] = teamReserveAllocation;
? ? ? ? allocations[firstReserveWallet] = firstReserveAllocation;
? ? ? ? allocations[secondReserveWallet] = secondReserveAllocation;
? ? ? ? Allocated(teamReserveWallet, teamReserveAllocation);
? ? ? ? Allocated(firstReserveWallet, firstReserveAllocation);
? ? ? ? Allocated(secondReserveWallet, secondReserveAllocation);
? ? ? ? lock();
? ? }
? ? /* internal:內(nèi)部函數(shù)男公,并且只有owner才擁有才權(quán)限
? ? * 從調(diào)用該合約的lock方法起,算出每一個(gè)地址對(duì)應(yīng)的解鎖時(shí)間
? ? * 執(zhí)行鎖事件
? ? */
? ? function lock() internal notLocked onlyOwner {
? ? ? ? lockedAt = block.timestamp; // 區(qū)塊當(dāng)前時(shí)間
? ? ? ? timeLocks[teamReserveWallet] = lockedAt.add(teamTimeLock);
? ? ? ? timeLocks[firstReserveWallet] = lockedAt.add(firstReserveTimeLock);
? ? ? ? timeLocks[secondReserveWallet] = lockedAt.add(secondReserveTimeLock);
? ? ? ? Locked(lockedAt);
? ? }
? ? //In the case locking failed, then allow the owner to reclaim the tokens on the contract.
? ? //Recover Tokens in case incorrect amount was sent to contract.
? ? // 失敗回滾
? ? function recoverFailedLock() external notLocked notAllocated onlyOwner {
? ? ? ? // Transfer all tokens on this contract back to the owner
? ? ? ? require(token.transfer(owner, token.balanceOf(address(this))));
? ? }
? ? // Total number of tokens currently in the vault
? ? // 查詢當(dāng)前合約所持有的金額
? ? function getTotalBalance() public view returns (uint256 tokensCurrentlyInVault) {
? ? ? ? return token.balanceOf(address(this));
? ? }
? ? // Number of tokens that are still locked
? ? // 根據(jù)鎖住的地址查詢對(duì)應(yīng)鎖住的金額
? ? function getLockedBalance() public view onlyReserveWallets returns (uint256 tokensLocked) {
? ? ? ? return allocations[msg.sender].sub(claimed[msg.sender]);? // 某一個(gè)地址對(duì)應(yīng)的分配金額-該地址已經(jīng)解鎖的金額
? ? }
? ? //Claim tokens for first/second reserve wallets
? ? /* 解鎖函數(shù)合陵,擁有firstReserveWallet或者secondReserveWallet地址的用戶才具有此權(quán)限枢赔,并且此地址已經(jīng)被鎖住澄阳,當(dāng)前時(shí)間大于該地址的解鎖時(shí)間
? ? * 從調(diào)用該合約的lock方法起,算出每一個(gè)地址對(duì)應(yīng)的解鎖時(shí)間
? ? * 執(zhí)行鎖事件
? ? */
? ? function claimTokenReserve() onlyTokenReserve locked public {
? ? ? ? address reserveWallet = msg.sender;
? ? ? ? // Can't claim before Lock ends
? ? ? ? require(block.timestamp > timeLocks[reserveWallet]); // 當(dāng)前時(shí)間大于第一個(gè)或者第二個(gè)解鎖時(shí)間
? ? ? ? // Must Only claim once
? ? ? ? require(claimed[reserveWallet] == 0);? // 已解鎖發(fā)放出額度為0
? ? ? ? uint256 amount = allocations[reserveWallet]; // 當(dāng)前賬號(hào)分配量
? ? ? ? claimed[reserveWallet] = amount;? // 一次性解鎖發(fā)放
? ? ? ? require(token.transfer(reserveWallet, amount)); // 解鎖到對(duì)應(yīng)的地址
? ? ? ? Distributed(reserveWallet, amount);
? ? }
? ? //Claim tokens for Libra team reserve wallet
? ? /* 解鎖函數(shù)踏拜,擁有teamReserveWallet地址的用戶才具有此權(quán)限碎赢,并且此地址已經(jīng)被鎖住,當(dāng)前時(shí)間大于該地址的解鎖時(shí)間
? ? * 從調(diào)用該合約的lock方法起速梗,算出每一個(gè)地址對(duì)應(yīng)的解鎖時(shí)間,每三個(gè)月發(fā)放一次
? ? * 執(zhí)行鎖事件
? ? */
? ? function claimTeamReserve() onlyTeamReserve locked public {
? ? ? ? uint256 vestingStage = teamVestingStage();?
? ? ? ? //Amount of tokens the team should have at this vesting stage
? ? ? ? uint256 totalUnlocked = vestingStage.mul(allocations[teamReserveWallet]).div(teamVestingStages); // 總的解鎖量
? ? ? ? require(totalUnlocked <= allocations[teamReserveWallet]);
? ? ? ? //Previously claimed tokens must be less than what is unlocked
? ? ? ? require(claimed[teamReserveWallet] < totalUnlocked); // 解鎖已經(jīng)發(fā)放量<總的解鎖量
? ? ? ? uint256 payment = totalUnlocked.sub(claimed[teamReserveWallet]); // 本次解鎖發(fā)放量 = 總的解鎖量 - 解鎖已經(jīng)發(fā)放量
? ? ? ? claimed[teamReserveWallet] = totalUnlocked; // 解鎖已經(jīng)發(fā)放量 = 總的解鎖量
? ? ? ? require(token.transfer(teamReserveWallet, payment)); // 發(fā)放
? ? ? ? Distributed(teamReserveWallet, payment);
? ? }
? ? //Current Vesting stage for Libra team
? ? function teamVestingStage() public view onlyTeamReserve returns(uint256){
? ? ? ? // Every 3 months
? ? ? ? uint256 vestingMonths = teamTimeLock.div(teamVestingStages); // 解鎖每個(gè)的時(shí)間=鎖定時(shí)間/解鎖次數(shù)
? ? ? ? uint256 stage = (block.timestamp.sub(lockedAt)).div(vestingMonths); // 已經(jīng)解鎖的次數(shù) =(當(dāng)前時(shí)間-鎖定時(shí)間)/每個(gè)解鎖時(shí)間
? ? ? ? //Ensures team vesting stage doesn't go past teamVestingStages
? ? ? ? if(stage > teamVestingStages){ // 已經(jīng)解鎖的次數(shù)大于解鎖次數(shù)
? ? ? ? ? ? stage = teamVestingStages;
? ? ? ? }
? ? ? ? return stage;
? ? }
}
4肮塞、全部代碼
pragma solidity ^0.4.18;
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/179
*/
contract ERC20Basic {
? function totalSupply() public view returns (uint256);? // totalSupply - 總發(fā)行量
? function balanceOf(address who) public view returns (uint256);? // 余額
? function transfer(address to, uint256 value) public returns (bool);? // 交易
? event Transfer(address indexed from, address indexed to, uint256 value);? // 交易事件
}
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
? /**
? * @dev Multiplies two numbers, throws on overflow.
? */
? function mul(uint256 a, uint256 b) internal pure returns (uint256) {
? ? if (a == 0) {
? ? ? return 0;
? ? }
? ? uint256 c = a * b;
? ? assert(c / a == b);
? ? return c;
? }
? /**
? * @dev Integer division of two numbers, truncating the quotient.
? */
? function div(uint256 a, uint256 b) internal pure returns (uint256) {
? ? // assert(b > 0); // Solidity automatically throws when dividing by 0
? ? uint256 c = a / b;
? ? // assert(a == b * c + a % b); // There is no case in which this doesn't hold
? ? return c;
? }
? /**
? * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
? */
? function sub(uint256 a, uint256 b) internal pure returns (uint256) {
? ? assert(b <= a);
? ? return a - b;
? }
? /**
? * @dev Adds two numbers, throws on overflow.
? */
? function add(uint256 a, uint256 b) internal pure returns (uint256) {
? ? uint256 c = a + b;
? ? assert(c >= a);
? ? return c;
? }
}
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
? function allowance(address owner, address spender) public view returns (uint256);? // 獲取被授權(quán)令牌余額,獲取 _owner 地址授權(quán)給 _spender 地址可以轉(zhuǎn)移的令牌的余額
? function transferFrom(address from, address to, uint256 value) public returns (bool);? // A賬戶-》B賬戶的轉(zhuǎn)賬
? function approve(address spender, uint256 value) public returns (bool);? // 授權(quán),允許 _spender 地址從你的賬戶中轉(zhuǎn)移 _value 個(gè)令牌到任何地方
? event Approval(address indexed owner, address indexed spender, uint256 value);? // 授權(quán)事件
}
/**
* @title Basic token
* @dev Basic version of StandardToken, with no allowances.
*/
contract BasicToken is ERC20Basic {
? using SafeMath for uint256;
? mapping(address => uint256) balances; // 余額
? uint256 totalSupply_;? // 發(fā)行總量
? /**
? * @dev total number of tokens in existence
? */
? function totalSupply() public view returns (uint256) {
? ? return totalSupply_;
? }
? /**
? * @dev transfer token for a specified address
? * @param _to The address to transfer to.
? * @param _value The amount to be transferred.
? */
? function transfer(address _to, uint256 _value) public returns (bool) {
? ? require(_to != address(0));? // 無效地址
? ? require(_value <= balances[msg.sender]);? // 轉(zhuǎn)賬賬戶余額大于轉(zhuǎn)賬數(shù)目
? ? // SafeMath.sub will throw if there is not enough balance.
? ? balances[msg.sender] = balances[msg.sender].sub(_value);? // 轉(zhuǎn)賬賬戶余額=賬戶余額-轉(zhuǎn)賬金額
? ? balances[_to] = balances[_to].add(_value); // 接收賬戶的余額=原先賬戶余額+賬金額
? ? Transfer(msg.sender, _to, _value);? // 轉(zhuǎn)賬
? ? return true;
? }
? /**
? * @dev Gets the balance of the specified address.
? * @param _owner The address to query the the balance of.
? * @return An uint256 representing the amount owned by the passed address.
? */
? function balanceOf(address _owner) public view returns (uint256 balance) {
? ? return balances[_owner];? // 查詢合約調(diào)用者的余額
? }
}
/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* @dev https://github.com/ethereum/EIPs/issues/20
* @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract StandardToken is ERC20, BasicToken {
? mapping (address => mapping (address => uint256)) internal allowed;
? /**
? * @dev Transfer tokens from one address to another
? * @param _from address The address which you want to send tokens from
? * @param _to address The address which you want to transfer to
? * @param _value uint256 the amount of tokens to be transferred
? */
? function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
? ? require(_to != address(0)); // 到達(dá)B賬戶的地址不能為無效地址
? ? require(_value <= balances[_from]);? // 轉(zhuǎn)賬賬戶余額大于轉(zhuǎn)賬金額
? ? require(_value <= allowed[_from][msg.sender]);? // 允許_from地址轉(zhuǎn)賬給 _to地址
? ? balances[_from] = balances[_from].sub(_value);?
? ? balances[_to] = balances[_to].add(_value);
? ? allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);? // 允許轉(zhuǎn)賬的余額
? ? Transfer(_from, _to, _value);
? ? return true;
? }
? /**
? ? * 設(shè)置帳戶允許支付的最大金額
? ? *
? ? * 一般在智能合約的時(shí)候镀琉,避免支付過多峦嗤,造成風(fēng)險(xiǎn)
? ? *
? ? * @param _spender 帳戶地址
? ? * @param _value 金額
? ? */
? function approve(address _spender, uint256 _value) public returns (bool) {
? ? allowed[msg.sender][_spender] = _value;
? ? Approval(msg.sender, _spender, _value);
? ? return true;
? }
? /**
? * @dev Function to check the amount of tokens that an owner allowed to a spender.
? * @param _owner address The address which owns the funds.
? * @param _spender address The address which will spend the funds.
? * @return A uint256 specifying the amount of tokens still available for the spender.
? */
? function allowance(address _owner, address _spender) public view returns (uint256) {
? ? return allowed[_owner][_spender];
? }
? /**
? * @dev Increase the amount of tokens that an owner allowed to a spender.
? *
? * approve should be called when allowed[_spender] == 0. To increment
? * allowed value is better to use this function to avoid 2 calls (and wait until
? * the first transaction is mined)
? * From MonolithDAO Token.sol
? * @param _spender The address which will spend the funds.
? * @param _addedValue The amount of tokens to increase the allowance by.
? ? 增加允許支付的最大額度
? */
? function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
? ? allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
? ? Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
? ? return true;
? }
? /**
? * @dev Decrease the amount of tokens that an owner allowed to a spender.
? *
? * approve should be called when allowed[_spender] == 0. To decrement
? * allowed value is better to use this function to avoid 2 calls (and wait until
? * the first transaction is mined)
? * From MonolithDAO Token.sol
? * @param _spender The address which will spend the funds.
? * @param _subtractedValue The amount of tokens to decrease the allowance by.
? ? ? 減少允許支付的最大額度
? */
? function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
? ? uint oldValue = allowed[msg.sender][_spender];
? ? if (_subtractedValue > oldValue) {
? ? ? allowed[msg.sender][_spender] = 0;
? ? } else {
? ? ? allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
? ? }
? ? Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
? ? return true;
? }
}
/**
* @title SimpleToken
* @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator.
* Note they can later distribute these tokens as they wish using `transfer` and other
* `StandardToken` functions.? 初始化合約,并且把初始的所有代幣都給這合約的創(chuàng)建者
*/
contract LibraToken is StandardToken {
? ? string public constant name = "LibraToken"; // solium-disable-line uppercase
? ? string public constant symbol = "LBA"; // solium-disable-line uppercase
? ? uint8 public constant decimals = 18; // solium-disable-line uppercase
? ? uint256 public constant INITIAL_SUPPLY = (10 ** 9) * (10 ** uint256(decimals));
? ? /**
? ? * @dev Constructor that gives msg.sender all of existing tokens.
? ? */
? ? function LibraToken() public {
? ? ? ? totalSupply_ = INITIAL_SUPPLY;
? ? ? ? balances[msg.sender] = INITIAL_SUPPLY;
? ? ? ? Transfer(0x0, msg.sender, INITIAL_SUPPLY);
? ? }
}
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".? 為了對(duì)代幣進(jìn)行管理屋摔,首先需要給合約添加一個(gè)管理者
*/
contract Ownable {
? address public owner;
? event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
? /**
? * @dev The Ownable constructor sets the original `owner` of the contract to the sender
? * account.
? */
? function Ownable() public {
? ? owner = msg.sender;
? }
? /**
? * @dev Throws if called by any account other than the owner.
? */
? modifier onlyOwner() {
? ? require(msg.sender == owner);
? ? _;
? }
? /**
? * @dev Allows the current owner to transfer control of the contract to a newOwner.
? * @param newOwner The address to transfer ownership to.? 指派一個(gè)新的管理員
? */
? function transferOwnership(address newOwner) public onlyOwner {
? ? require(newOwner != address(0));
? ? OwnershipTransferred(owner, newOwner);
? ? owner = newOwner;
? }
}
/**
? * @dev 鎖倉解鎖合約
? */
contract LibraTokenVault is Ownable {
? ? using SafeMath for uint256;
? ? /**
? ? * @dev 創(chuàng)建三個(gè)賬戶地址,將解鎖后的余額預(yù)分配到三個(gè)地址
? ? */
? ? address public teamReserveWallet = 0x373c69fDedE072A3F5ab1843a0e5fE0102Cc6793;
? ? address public firstReserveWallet = 0x99C83f62DBE1a488f9C9d370DA8e86EC55224eB4;
? ? address public secondReserveWallet = 0x90DfF11810dA6227d348C86C59257C1C0033D307;
? ? /** 三個(gè)賬戶地址對(duì)應(yīng)的鎖倉金額 */
? ? uint256 public teamReserveAllocation = 2 * (10 ** 8) * (10 ** 18);
? ? uint256 public firstReserveAllocation = 15 * (10 ** 7) * (10 ** 18);
? ? uint256 public secondReserveAllocation = 15 * (10 ** 7) * (10 ** 18);
? ? // 總鎖倉的金額
? ? uint256 public totalAllocation = 5 * (10 ** 8) * (10 ** 18);
? ? /** 三個(gè)賬戶地址對(duì)應(yīng)的鎖倉時(shí)間 */
? ? uint256 public teamTimeLock = 2 * 365 days;
? ? uint256 public teamVestingStages = 8;
? ? uint256 public firstReserveTimeLock = 2 * 365 days;
? ? uint256 public secondReserveTimeLock = 3 * 365 days;
? ? /** Reserve allocations */
? ? mapping(address => uint256) public allocations;? // 每個(gè)地址對(duì)應(yīng)鎖倉金額的映射表
? ? /** When timeLocks are over (UNIX Timestamp)? */?
? ? mapping(address => uint256) public timeLocks;? // 每個(gè)地址對(duì)應(yīng)鎖倉時(shí)間的映射表
? ? /** How many tokens each reserve wallet has claimed */
? ? mapping(address => uint256) public claimed;? // 每個(gè)地址對(duì)應(yīng)鎖倉后已經(jīng)解鎖的金額的映射表
? ? /** When this vault was locked (UNIX Timestamp)*/
? ? uint256 public lockedAt = 0;
? ? LibraToken public token;
? ? /** Allocated reserve tokens */
? ? event Allocated(address wallet, uint256 value);
? ? /** Distributed reserved tokens */
? ? event Distributed(address wallet, uint256 value);
? ? /** Tokens have been locked */
? ? event Locked(uint256 lockTime);
? ? //Any of the three reserve wallets
? ? modifier onlyReserveWallets {? // 合約調(diào)用者的鎖倉余額大于0才能查詢鎖倉余額
? ? ? ? require(allocations[msg.sender] > 0);
? ? ? ? _;
? ? }
? ? //Only Libra team reserve wallet
? ? modifier onlyTeamReserve {? // 合約調(diào)用者的地址為teamReserveWallet
? ? ? ? require(msg.sender == teamReserveWallet);
? ? ? ? require(allocations[msg.sender] > 0);
? ? ? ? _;
? ? }
? ? //Only first and second token reserve wallets
? ? modifier onlyTokenReserve { // 合約調(diào)用者的地址為firstReserveWallet或者secondReserveWallet
? ? ? ? require(msg.sender == firstReserveWallet || msg.sender == secondReserveWallet);
? ? ? ? require(allocations[msg.sender] > 0);
? ? ? ? _;
? ? }
? ? //Has not been locked yet
? ? modifier notLocked {? // 未鎖定
? ? ? ? require(lockedAt == 0);
? ? ? ? _;
? ? }
? ? modifier locked { // 鎖定
? ? ? ? require(lockedAt > 0);
? ? ? ? _;
? ? }
? ? //Token allocations have not been set
? ? modifier notAllocated {? // 沒有為每個(gè)地址分配對(duì)應(yīng)的鎖倉金額時(shí)
? ? ? ? require(allocations[teamReserveWallet] == 0);
? ? ? ? require(allocations[firstReserveWallet] == 0);
? ? ? ? require(allocations[secondReserveWallet] == 0);
? ? ? ? _;
? ? }
? ? function LibraTokenVault(ERC20 _token) public {? // 構(gòu)造LibraToken模式的合約
? ? ? ? owner = msg.sender;? // msg.sender 是指直接調(diào)用當(dāng)前合約的調(diào)用方地址
? ? ? ? token = LibraToken(_token);
? ? }
? ? function allocate() public notLocked notAllocated onlyOwner {?
? ? ? ? //Makes sure Token Contract has the exact number of tokens
? ? ? ? require(token.balanceOf(address(this)) == totalAllocation);?
? ? ? ? allocations[teamReserveWallet] = teamReserveAllocation;
? ? ? ? allocations[firstReserveWallet] = firstReserveAllocation;
? ? ? ? allocations[secondReserveWallet] = secondReserveAllocation;
? ? ? ? Allocated(teamReserveWallet, teamReserveAllocation);
? ? ? ? Allocated(firstReserveWallet, firstReserveAllocation);
? ? ? ? Allocated(secondReserveWallet, secondReserveAllocation);
? ? ? ? lock();
? ? }
? ? function lock() internal notLocked onlyOwner {
? ? ? ? lockedAt = block.timestamp; // 區(qū)塊當(dāng)前時(shí)間
? ? ? ? timeLocks[teamReserveWallet] = lockedAt.add(teamTimeLock);
? ? ? ? timeLocks[firstReserveWallet] = lockedAt.add(firstReserveTimeLock);
? ? ? ? timeLocks[secondReserveWallet] = lockedAt.add(secondReserveTimeLock);
? ? ? ? Locked(lockedAt);
? ? }
? ? function recoverFailedLock() external notLocked notAllocated onlyOwner {
? ? ? ? // Transfer all tokens on this contract back to the owner
? ? ? ? require(token.transfer(owner, token.balanceOf(address(this))));
? ? }
? ? // Total number of tokens currently in the vault
? ? // 查詢當(dāng)前合約所持有的金額
? ? function getTotalBalance() public view returns (uint256 tokensCurrentlyInVault) {
? ? ? ? return token.balanceOf(address(this));
? ? }
? ? // Number of tokens that are still locked
? ? function getLockedBalance() public view onlyReserveWallets returns (uint256 tokensLocked) {
? ? ? ? return allocations[msg.sender].sub(claimed[msg.sender]);?
? ? }
? ? //Claim tokens for first/second reserve wallets
? ? function claimTokenReserve() onlyTokenReserve locked public {
? ? ? ? address reserveWallet = msg.sender;
? ? ? ? // Can't claim before Lock ends
? ? ? ? require(block.timestamp > timeLocks[reserveWallet]);?
? ? ? ? // Must Only claim once
? ? ? ? require(claimed[reserveWallet] == 0);??
? ? ? ? uint256 amount = allocations[reserveWallet];
? ? ? ? claimed[reserveWallet] = amount;? // 一次性解鎖發(fā)放
? ? ? ? require(token.transfer(reserveWallet, amount));
? ? ? ? Distributed(reserveWallet, amount);
? ? }
? ? //Claim tokens for Libra team reserve wallet
? ? function claimTeamReserve() onlyTeamReserve locked public {
? ? ? ? uint256 vestingStage = teamVestingStage();?
? ? ? ? //Amount of tokens the team should have at this vesting stage
? ? ? ? uint256 totalUnlocked = vestingStage.mul(allocations[teamReserveWallet]).div(teamVestingStages); // 總的解鎖量
? ? ? ? require(totalUnlocked <= allocations[teamReserveWallet]);
? ? ? ? //Previously claimed tokens must be less than what is unlocked
? ? ? ? require(claimed[teamReserveWallet] < totalUnlocked);?
? ? ? ? uint256 payment = totalUnlocked.sub(claimed[teamReserveWallet]);?
? ? ? ? claimed[teamReserveWallet] = totalUnlocked;
? ? ? ? require(token.transfer(teamReserveWallet, payment));?
? ? ? ? Distributed(teamReserveWallet, payment);
? ? }
? ? //Current Vesting stage for Libra team
? ? function teamVestingStage() public view onlyTeamReserve returns(uint256){
? ? ? ? // Every 3 months
? ? ? ? uint256 vestingMonths = teamTimeLock.div(teamVestingStages);?
? ? ? ? uint256 stage = (block.timestamp.sub(lockedAt)).div(vestingMonths);?
? ? ? ? //Ensures team vesting stage doesn't go past teamVestingStages
? ? ? ? return stage;
? ? }
}