国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

OpenZeppelin ERC20源碼分析

kumfo / 4201人閱讀

摘要:前提是擁有者必須要通過(guò)某些機(jī)制對(duì)這個(gè)請(qǐng)求進(jìn)行確認(rèn),比如通過(guò)進(jìn)行。事件,當(dāng)被調(diào)用時(shí),需要觸發(fā)該事件。允許從中轉(zhuǎn)出的數(shù)增加所有者允許花費(fèi)代幣的數(shù)量。已經(jīng)歸屬合約,其余歸還給所有者。計(jì)算已歸屬但尚未釋放的金額。源碼分析到這里就結(jié)束了。

ERC20:Ethereum Request for Comments 20,是一個(gè)基于以太坊代幣的接口標(biāo)準(zhǔn)(協(xié)議)。所有符合ERC-20標(biāo)準(zhǔn)的代幣都能立即兼容以太坊錢(qián)包,它能讓用戶(hù)和交易所,都能非常方便的管理多種代幣,轉(zhuǎn)賬、存儲(chǔ)、ICO等等。

OpenZeppelin的Token中實(shí)現(xiàn)了ERC20的一個(gè)安全的合約代碼,本篇主要來(lái)分析一下源碼,了解一下ERC20的實(shí)現(xiàn),由于代碼之間的調(diào)用可能略復(fù)雜,直接每個(gè)文件每個(gè)文件的來(lái)看會(huì)有點(diǎn)繞,我直接畫(huà)了一個(gè)繼承和調(diào)用關(guān)系的思維導(dǎo)圖,可以幫助更容易地看源碼。

ERC20Basic.sol
pragma solidity ^0.4.23;

contract ERC20Basic {
  function totalSupply() public view returns (uint256);
  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);
}

ERC20Basic合約主要定義了ERC20的基本接口,定義了必須要實(shí)現(xiàn)的方法:

totalSupply 返回總共發(fā)行量

balanceOf 查詢(xún)指定address的余額

transfer 發(fā)送指定數(shù)目的token到指定賬戶(hù),同時(shí)發(fā)送后需要觸發(fā)Transfer事件

Transfer事件,任何token發(fā)送發(fā)生時(shí),必須觸發(fā)該事件,即使是0額度。 當(dāng)一個(gè)token合約創(chuàng)建時(shí),應(yīng)該觸發(fā)一個(gè)Transfer事件,token的發(fā)送方是0x0,也就是說(shuō)憑空而來(lái)的token,簡(jiǎn)稱(chēng)空氣幣。

ERC20.sol
pragma solidity ^0.4.23;

import "./ERC20Basic.sol";

contract ERC20 is ERC20Basic {
  function allowance(address owner, address spender)
    public view returns (uint256);

  function transferFrom(address from, address to, uint256 value)
    public returns (bool);

  function approve(address spender, uint256 value) public returns (bool);
  event Approval(
    address indexed owner,
    address indexed spender,
    uint256 value
  );
}

ERC20合約繼承了ERC20Basic,另外定義了approve相關(guān)的方法:

allowance 獲取指定用戶(hù)的批準(zhǔn)額度,控制代幣的交易,如可交易賬號(hào)及資產(chǎn), 控制Token的流通

transferFrom 從一個(gè)地址向另外一個(gè)地址轉(zhuǎn)賬指定額度的token,這個(gè)方法可以理解為一個(gè)收款流程,允許合約來(lái)代表token持有者發(fā)送代幣。比如,合約可以幫助你向另外一個(gè)人發(fā)送token或者索要token。前提是token擁有者必須要通過(guò)某些機(jī)制對(duì)這個(gè)請(qǐng)求進(jìn)行確認(rèn),比如通過(guò)MetaMask進(jìn)行confirm。否則,執(zhí)行將失敗。 跟transfer一樣,即使發(fā)送0代幣,也要觸發(fā)Transfer事件。

approve 批準(zhǔn)額度,允許一個(gè)賬戶(hù)最多能從你的賬戶(hù)你取現(xiàn)指定額度。重復(fù)調(diào)用時(shí),以最后一次的額度為主。為了防止攻擊,最開(kāi)始這個(gè)額度必須設(shè)置為0。

Approval事件,當(dāng)approve被調(diào)用時(shí),需要觸發(fā)該事件。

DetailedERC20.sol
pragma solidity ^0.4.23;

import "./ERC20.sol";

contract DetailedERC20 is ERC20 {
  string public name;
  string public symbol;
  uint8 public decimals;

  constructor(string _name, string _symbol, uint8 _decimals) public {
    name = _name;
    symbol = _symbol;
    decimals = _decimals;
  }
}

DetailedERC20 主要定義了token的展示信息:

name token的名稱(chēng),比如"XXXToken"

symbol token的符號(hào),比如"XXX"

decimals token精確的小數(shù)點(diǎn)位數(shù),比如18

BasicToken.sol
pragma solidity ^0.4.23;

import "./ERC20Basic.sol";
import "../../math/SafeMath.sol";


/**
 * @title 實(shí)現(xiàn)ERC20基本合約的接口 
 * @dev 基本的StandardToken,不包含allowances.
 */
contract BasicToken is ERC20Basic {
  using SafeMath for uint256;

  mapping(address => uint256) balances;

  uint256 totalSupply_;

  /**
  * @dev 返回存在的token總數(shù)
  */
  function totalSupply() public view returns (uint256) {
    return totalSupply_;
  }

  /**
  * @dev 給特定的address轉(zhuǎn)token
  * @param _to 要轉(zhuǎn)賬到的address
  * @param _value 要轉(zhuǎn)賬的金額
  */
  function transfer(address _to, uint256 _value) public returns (bool) {
    //做相關(guān)的合法驗(yàn)證
    require(_to != address(0));
    require(_value <= balances[msg.sender]);
    // msg.sender余額中減去額度,_to余額加上相應(yīng)額度
    balances[msg.sender] = balances[msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);
    //觸發(fā)Transfer事件
    emit Transfer(msg.sender, _to, _value);
    return true;
  }

  /**
  * @dev 獲取指定address的余額
  * @param _owner 查詢(xún)余額的address.
  * @return An uint256 representing the amount owned by the passed address.
  */
  function balanceOf(address _owner) public view returns (uint256) {
    return balances[_owner];
  }

}

通過(guò)SafeMath來(lái)做運(yùn)算很重要,在我們自己寫(xiě)合約的時(shí)候也盡量使用,可以避免一些計(jì)算過(guò)程的溢出等安全問(wèn)題。

StandardToken.sol
pragma solidity ^0.4.23;

import "./BasicToken.sol";
import "./ERC20.sol";

/**
 * @title 標(biāo)準(zhǔn) ERC20 token
 *
 * @dev 實(shí)現(xiàn)基礎(chǔ)的標(biāo)準(zhǔn)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 從一個(gè)地址向另外一個(gè)地址轉(zhuǎn)token
   * @param _from 轉(zhuǎn)賬的from地址
   * @param _to address 轉(zhuǎn)賬的to地址
   * @param _value uint256 轉(zhuǎn)賬token數(shù)量
   */
  function transferFrom(
    address _from,
    address _to,
    uint256 _value
  )
    public
    returns (bool)
  {
    // 做合法性檢查
    require(_to != address(0));
    require(_value <= balances[_from]);
    require(_value <= allowed[_from][msg.sender]);
    //_from余額減去相應(yīng)的金額
    //_to余額加上相應(yīng)的金額
    //msg.sender可以從賬戶(hù)_from中轉(zhuǎn)出的數(shù)量減少_value
    balances[_from] = balances[_from].sub(_value);
    balances[_to] = balances[_to].add(_value);
    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
    // 觸發(fā)Transfer事件
    emit Transfer(_from, _to, _value);
    return true;
  }

  /**
   * @dev 批準(zhǔn)傳遞的address以代表msg.sender花費(fèi)指定數(shù)量的token
   *
   * Beware that changing an allowance with this method brings the risk that someone may use both the old
   * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
   * race condition is to first reduce the spender"s allowance to 0 and set the desired value afterwards:
   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
   * @param _spender 花費(fèi)資金的地址
   * @param _value 可以被花費(fèi)的token數(shù)量
   */
  function approve(address _spender, uint256 _value) public returns (bool) {
    //記錄msg.sender允許_spender動(dòng)用的token
    allowed[msg.sender][_spender] = _value;
    //觸發(fā)Approval事件
    emit Approval(msg.sender, _spender, _value);
    return true;
  }

  /**
   * @dev 函數(shù)檢查所有者允許的_spender花費(fèi)的token數(shù)量
   * @param _owner address 資金所有者地址.
   * @param _spender address 花費(fèi)資金的spender的地址.
   * @return A uint256 指定_spender仍可用token的數(shù)量。
   */
  function allowance(
    address _owner,
    address _spender
   )
    public
    view
    returns (uint256)
  {
    //允許_spender從_owner中轉(zhuǎn)出的token數(shù)
    return allowed[_owner][_spender];
  }

  /**
   * @dev 增加所有者允許_spender花費(fèi)代幣的數(shù)量。
   *
   * allowed[_spender] == 0時(shí)approve應(yīng)該被調(diào)用. 增加allowed值最好使用此函數(shù)避免2此調(diào)用(等待知道第一筆交易被挖出)
   * From MonolithDAO Token.sol
   * @param _spender 花費(fèi)資金的地址
   * @param _addedValue 用于增加允許動(dòng)用的token牌數(shù)量
   */
  function increaseApproval(
    address _spender,
    uint _addedValue
  )
    public
    returns (bool)
  {
    //在之前允許的數(shù)量上增加_addedValue
    allowed[msg.sender][_spender] = (
      allowed[msg.sender][_spender].add(_addedValue));
    //觸發(fā)Approval事件
    emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
    return true;
  }

  /**
   * @dev 減少所有者允許_spender花費(fèi)代幣的數(shù)量
   *
   * allowed[_spender] == 0時(shí)approve應(yīng)該被調(diào)用. 減少allowed值最好使用此函數(shù)避免2此調(diào)用(等待知道第一筆交易被挖出)
   * From MonolithDAO Token.sol
   * @param _spender  花費(fèi)資金的地址
   * @param _subtractedValue 用于減少允許動(dòng)用的token牌數(shù)量
   */
  function decreaseApproval(
    address _spender,
    uint _subtractedValue
  )
    public
    returns (bool)
  {
    uint oldValue = allowed[msg.sender][_spender];
    if (_subtractedValue > oldValue) {
    //減少的數(shù)量少于之前允許的數(shù)量,則清零
      allowed[msg.sender][_spender] = 0;
    } else {
    //減少對(duì)應(yīng)的_subtractedValue數(shù)量
      allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
    }
    //觸發(fā)Approval事件
    emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
    return true;
  }

}

上面合約定義的 mapping allowed,它用來(lái)記錄某個(gè)地址允許另外一個(gè)地址動(dòng)用多少token。假設(shè)錢(qián)包地址為B,有另外一個(gè)合約其合約地址為C,合約C會(huì)通過(guò)支付XXX Token來(lái)做一些事情,根據(jù)ERC20的定義,每個(gè)地址只能操作屬于自己的Token,則合約C無(wú)法直接使用B地址所擁有的Token,這時(shí)候allowed Mapping就派上用場(chǎng)了,它上面可以記錄一個(gè)允許操作值,像是「B 錢(qián)包地址允許 C 合約地址動(dòng)用屬于 B 錢(qián)包地址的 1000 XXX Token」,以 Mapping 的結(jié)構(gòu)來(lái)說(shuō)標(biāo)記為「B => C => 1000」

BurnableToken.sol
pragma solidity ^0.4.23;

import "./BasicToken.sol";

/**
 * @title 可銷(xiāo)毀 Token
 * @dev Token可以被不可逆轉(zhuǎn)地銷(xiāo)毀
 */
contract BurnableToken is BasicToken {

  event Burn(address indexed burner, uint256 value);

  /**
   * @dev 銷(xiāo)毀指定數(shù)量的token.
   * @param _value 被銷(xiāo)毀的token數(shù)量.
   */
  function burn(uint256 _value) public {
    _burn(msg.sender, _value);
  }

  function _burn(address _who, uint256 _value) internal {
    require(_value <= balances[_who]);
    //不需要驗(yàn)證value <= totalSupply,因?yàn)檫@意味著發(fā)送者的余額大于總供應(yīng)量,這應(yīng)該是斷言失敗 
    balances[_who] = balances[_who].sub(_value);
    totalSupply_ = totalSupply_.sub(_value);
    emit Burn(_who, _value);
    emit Transfer(_who, address(0), _value);
  }
}

該合約比較簡(jiǎn)單,就是調(diào)用者可以銷(xiāo)毀一定數(shù)量的token,然后totalSupply減去對(duì)應(yīng)銷(xiāo)毀的數(shù)量

StandardBurnableToken.sol
pragma solidity ^0.4.23;

import "./BurnableToken.sol";
import "./StandardToken.sol";

/**
 * @title 標(biāo)準(zhǔn)可銷(xiāo)毀token
 * @dev 將burnFrom方法添加到ERC20實(shí)現(xiàn)中
 */
contract StandardBurnableToken is BurnableToken, StandardToken {

  /**
   * @dev 從目標(biāo)地址銷(xiāo)毀特定數(shù)量的token并減少允許量
   * @param _from address token所有者地址
   * @param _value uint256 被銷(xiāo)毀的token數(shù)量
   */
  function burnFrom(address _from, uint256 _value) public {
    require(_value <= allowed[_from][msg.sender]);
    // Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted,
    // 此方法需要觸發(fā)具有更新批準(zhǔn)的事件。
    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
    _burn(_from, _value);
  }
}
MintableToken.sol
pragma solidity ^0.4.23;

import "./StandardToken.sol";
import "../../ownership/Ownable.sol";


/**
 * @title 可增發(fā) token
 * @dev 簡(jiǎn)單的可增發(fā)的 ERC20 Token 示例
 * @dev Issue: * https://github.com/OpenZeppelin/openzeppelin-solidity/issues/120
 * Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
 */
contract MintableToken is StandardToken, Ownable {
  event Mint(address indexed to, uint256 amount);
  event MintFinished();
  //初始化增發(fā)狀態(tài)為false
  bool public mintingFinished = false;

  modifier canMint() {
    // 檢查沒(méi)有增發(fā)結(jié)束
    require(!mintingFinished);
    _;
  }

  modifier hasMintPermission() {
    //owner只能為msg.sender
    require(msg.sender == owner);
    _;
  }

  /**
   * @dev 增發(fā)token方法
   * @param _to 獲取增發(fā)token的地址_to.
   * @param _amount 增發(fā)的token數(shù)量.
   * @return A boolean that indicates if the operation was successful.
   */
  function mint(
    address _to,
    uint256 _amount
  )
    hasMintPermission
    canMint
    public
    returns (bool)
  {
    // 總發(fā)行量增加_amount數(shù)量的token
    totalSupply_ = totalSupply_.add(_amount);
    // 獲取增發(fā)的地址增加_amount數(shù)量的token
    balances[_to] = balances[_to].add(_amount);
    // 觸發(fā)增發(fā)事件
    emit Mint(_to, _amount);
    // 觸發(fā)Transfer事件
    emit Transfer(address(0), _to, _amount);
    return true;
  }

  /**
   * @dev 停止增發(fā)新token.
   * @return True if the operation was successful.
   */
  function finishMinting() onlyOwner canMint public returns (bool) {
    // 改變?cè)霭l(fā)狀態(tài)為已完成
    mintingFinished = true;
    // 觸發(fā)增發(fā)已完成事件
    emit MintFinished();
    return true;
  }
}

增發(fā)token的合約也很簡(jiǎn)單,就是通過(guò)增發(fā)一定量的token給對(duì)應(yīng)的address,并給總發(fā)行量增加對(duì)應(yīng)的增發(fā)token,可以通過(guò)調(diào)用finishMinting來(lái)完成增發(fā)。

CappedToken.sol
pragma solidity ^0.4.23;

import "./MintableToken.sol";

/**
 * @title 上限 token
 * @dev 設(shè)置一個(gè)頂?shù)目稍霭l(fā)token.
 */
contract CappedToken is MintableToken {

  uint256 public cap;

  constructor(uint256 _cap) public {
    require(_cap > 0);
    cap = _cap;
  }

  /**
   * @dev 增發(fā)token
   * @param _to 獲取增發(fā)token的地址_to.
   * @param _amount 增發(fā)token數(shù)量.
   * @return A boolean that indicates if the operation was successful.
   */
  function mint(
    address _to,
    uint256 _amount
  )
    public
    returns (bool)
  {
    // 驗(yàn)證總發(fā)行量+增發(fā)量小于所設(shè)置的上限
    require(totalSupply_.add(_amount) <= cap);
    // 調(diào)用父合約的增發(fā)方法
    return super.mint(_to, _amount);
  }

}

CappedToken 也很簡(jiǎn)單,就是在可增發(fā)合約上加了一個(gè)"cap",來(lái)限制增發(fā)的上限

RBACMintableToken.sol
pragma solidity ^0.4.23;

import "./MintableToken.sol";
import "../../ownership/rbac/RBAC.sol";

/**
 * @title RBACMintableToken
 * @author Vittorio Minacori (@vittominacori)
 * @dev Mintable Token, with RBAC minter permissions
 */
contract RBACMintableToken is MintableToken, RBAC {
  /**
   * 指定一個(gè)增發(fā)者的常量名.
   */
  string public constant ROLE_MINTER = "minter";

  /**
   * @dev 重寫(xiě)Mintable token合約的 modifier,增加角色有關(guān)的邏輯 
   */
  modifier hasMintPermission() {
    // 調(diào)用RBAC合約中的角色檢查
    checkRole(msg.sender, ROLE_MINTER);
    _;
  }

  /**
   * @dev 將一個(gè)地址添加為可增發(fā)者角色
   * @param minter address
   */
  function addMinter(address minter) onlyOwner public {
    addRole(minter, ROLE_MINTER);
  }

  /**
   * @dev 將一個(gè)地址移除可增發(fā)者角色
   * @param minter address
   */
  function removeMinter(address minter) onlyOwner public {
    removeRole(minter, ROLE_MINTER);
  }
}

RBACMintableToken 合約將增發(fā)操作中添加了RBAC邏輯,就是角色權(quán)限管理的邏輯,將一個(gè)地址這是為增發(fā)者角色,也可以移除一個(gè)地址的增發(fā)者角色,只有擁有"minter"角色的address才有權(quán)限增發(fā)token

SafeERC20.sol
pragma solidity ^0.4.23;

import "./ERC20Basic.sol";
import "./ERC20.sol";

/**
 * @title SafeERC20
 * @dev 圍繞ERC20操作發(fā)生故障的包裝程序.
 * 可以在合約中通過(guò)這樣使用這個(gè)庫(kù) `using SafeERC20 for ERC20;` 來(lái)使用安全的操作`token.safeTransfer(...)`
 */
library SafeERC20 {
  function safeTransfer(ERC20Basic token, address to, uint256 value) internal {
    require(token.transfer(to, value));
  }

  function safeTransferFrom(
    ERC20 token,
    address from,
    address to,
    uint256 value
  )
    internal
  {
    require(token.transferFrom(from, to, value));
  }

  function safeApprove(ERC20 token, address spender, uint256 value) internal {
    require(token.approve(spender, value));
  }
}

SafeERC20 是一個(gè)ERC20的安全操作庫(kù),在下面的TokenTimelock鎖定期后釋放token的合約中我們可以看到用法

TokenTimelock.sol
pragma solidity ^0.4.23;

import "./SafeERC20.sol";

/**
 * @title TokenTimelock 鎖定期釋放token
 * @dev TokenTimelock 是一個(gè)令token持有人合同,將允許一個(gè)受益人在給定的發(fā)布時(shí)間之后提取token
 */
contract TokenTimelock {
  //這里用到了上面的SafeERC20
  using SafeERC20 for ERC20Basic;

  // ERC20 basic token contract being held
  ERC20Basic public token;

  // token被釋放后的受益人address
  address public beneficiary;

  // token可以被釋放的時(shí)間戳
  uint256 public releaseTime;
  // 對(duì)token,受益人address和釋放時(shí)間初始化
  constructor(
    ERC20Basic _token,
    address _beneficiary,
    uint256 _releaseTime
  )
    public
  {
    require(_releaseTime > block.timestamp);
    token = _token;
    beneficiary = _beneficiary;
    releaseTime = _releaseTime;
  }

  /**
   * @notice 將時(shí)間限制內(nèi)的token轉(zhuǎn)移給受益人.
   */
  function release() public {
    require(block.timestamp >= releaseTime);

    uint256 amount = token.balanceOf(this);
    require(amount > 0);

    token.safeTransfer(beneficiary, amount);
  }
}

TokenTimelock 合約通過(guò)初始化受益人以及釋放的時(shí)間和鎖定的token,通過(guò)release來(lái)將鎖定期過(guò)后釋放的token轉(zhuǎn)給受益人

TokenVesting.sol
pragma solidity ^0.4.23;

import "./ERC20Basic.sol";
import "./SafeERC20.sol";
import "../../ownership/Ownable.sol";
import "../../math/SafeMath.sol";

/**
 * @title TokenVesting 定期釋放token
 * @dev token持有人合同可以逐漸釋放token余額典型的歸屬方案,有斷崖時(shí)間和歸屬期, 可選擇可撤銷(xiāo)的所有者。
 */
contract TokenVesting is Ownable {
  using SafeMath for uint256;
  using SafeERC20 for ERC20Basic;

  event Released(uint256 amount);
  event Revoked();

  // 釋放后的token收益人
  address public beneficiary;

  uint256 public cliff; //斷崖表示「鎖倉(cāng)4年,1年之后一次性解凍25%」中的一年
  uint256 public start;//起始時(shí)間
  uint256 public duration;//持續(xù)鎖倉(cāng)時(shí)間

  bool public revocable;

  mapping (address => uint256) public released;
  mapping (address => bool) public revoked;

  /**
   * @dev 創(chuàng)建一份歸屬權(quán)合同,將任何ERC20 token的余額歸屬給_beneficiary,逐漸以線性方式,直到_start + _duration 所有的余額都將歸屬。
   * @param _beneficiary 授予轉(zhuǎn)讓token的受益人的地址
   * @param _cliff 持續(xù)時(shí)間以秒為單位,代幣將開(kāi)始?xì)w屬
   * @param _start 歸屬開(kāi)始的時(shí)間(如Unix時(shí)間)
   * @param _duration 持續(xù)時(shí)間以token的歸屬期限為單位
   * @param _revocable 歸屬是否可撤銷(xiāo)
   */
  constructor(
    address _beneficiary,
    uint256 _start,
    uint256 _cliff,
    uint256 _duration,
    bool _revocable
  )
    public
  {
    require(_beneficiary != address(0));
    require(_cliff <= _duration);

    beneficiary = _beneficiary;
    revocable = _revocable;
    duration = _duration;
    cliff = _start.add(_cliff);
    start = _start;
  }

  /**
   * @notice 將歸屬代幣轉(zhuǎn)讓給受益人.
   * @param token ERC20 token which is being vested
   */
  function release(ERC20Basic token) public {
    uint256 unreleased = releasableAmount(token);

    require(unreleased > 0);

    released[token] = released[token].add(unreleased);

    token.safeTransfer(beneficiary, unreleased);

    emit Released(unreleased);
  }

  /**
   * @notice允許所有者撤銷(xiāo)歸屬。 token已經(jīng)歸屬合約,其余歸還給所有者。  
   * @param token ERC20 token which is being vested
   */
  function revoke(ERC20Basic token) public onlyOwner {
    require(revocable);
    require(!revoked[token]);

    uint256 balance = token.balanceOf(this);

    uint256 unreleased = releasableAmount(token);
    uint256 refund = balance.sub(unreleased);

    revoked[token] = true;

    token.safeTransfer(owner, refund);

    emit Revoked();
  }

  /**
   * @dev 計(jì)算已歸屬但尚未釋放的金額。
   * @param token ERC20 token which is being vested
   */
  function releasableAmount(ERC20Basic token) public view returns (uint256) {
    return vestedAmount(token).sub(released[token]);
  }

  /**
   * @dev 計(jì)算已歸屬的金額.
   * @param token ERC20 token which is being vested
   */
  function vestedAmount(ERC20Basic token) public view returns (uint256) {
    uint256 currentBalance = token.balanceOf(this);
    uint256 totalBalance = currentBalance.add(released[token]);

    if (block.timestamp < cliff) {
      return 0;
    } else if (block.timestamp >= start.add(duration) || revoked[token]) {
      return totalBalance;
    } else {
      return totalBalance.mul(block.timestamp.sub(start)).div(duration);
    }
  }
}

TokenVesting也是鎖倉(cāng)的一種方式,主要解決的是有斷崖時(shí)間和持續(xù)鎖倉(cāng)時(shí)間的鎖倉(cāng)場(chǎng)景

PausableToken.sol
pragma solidity ^0.4.23;

import "./StandardToken.sol";
import "../../lifecycle/Pausable.sol";


/**
 * @title Pausable token
 * @dev StandardToken modified with pausable transfers.
 **/
contract PausableToken is StandardToken, Pausable {

  function transfer(
    address _to,
    uint256 _value
  )
    public
    whenNotPaused
    returns (bool)
  {
    return super.transfer(_to, _value);
  }

  function transferFrom(
    address _from,
    address _to,
    uint256 _value
  )
    public
    whenNotPaused
    returns (bool)
  {
    return super.transferFrom(_from, _to, _value);
  }

  function approve(
    address _spender,
    uint256 _value
  )
    public
    whenNotPaused
    returns (bool)
  {
    return super.approve(_spender, _value);
  }

  function increaseApproval(
    address _spender,
    uint _addedValue
  )
    public
    whenNotPaused
    returns (bool success)
  {
    return super.increaseApproval(_spender, _addedValue);
  }

  function decreaseApproval(
    address _spender,
    uint _subtractedValue
  )
    public
    whenNotPaused
    returns (bool success)
  {
    return super.decreaseApproval(_spender, _subtractedValue);
  }
}

PausableToken繼承了StandardToken,但是在方法中都添加了whenNotPaused函數(shù)修改器,whenNotPaused繼承自Pausable合約,Pausable有個(gè)paused來(lái)標(biāo)記暫停的狀態(tài),從而控制合約的是否暫停。

OpenZeppelin ERC20源碼分析到這里就結(jié)束了。

轉(zhuǎn)載請(qǐng)注明: 轉(zhuǎn)載自Ryan是菜鳥(niǎo) | LNMP技術(shù)棧筆記

如果覺(jué)得本篇文章對(duì)您十分有益,何不 打賞一下

本文鏈接地址: OpenZeppelin ERC20源碼分析

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/24147.html

相關(guān)文章

  • OpenZeppelin ERC721源碼分析

    摘要:它和我寫(xiě)的上一篇源碼分析介紹的有所不同,最小的單位為無(wú)法再分割,代表獨(dú)一無(wú)二的,針對(duì)不可置換的的智能合約標(biāo)準(zhǔn)接口。源碼分析到這里就結(jié)束了。 ERC721 官方簡(jiǎn)介是:A standard interface for non-fungible tokens, also known as deeds.也叫非同質(zhì)代幣,或者不可置換代幣(NFTs)。提到ERC721,一個(gè)好理解的例子就是Cry...

    ctriptech 評(píng)論0 收藏0
  • 以太坊開(kāi)發(fā)實(shí)戰(zhàn)學(xué)習(xí)-ERC721標(biāo)準(zhǔn)(七)

    摘要:從這節(jié)開(kāi)始,我們將學(xué)習(xí)代幣標(biāo)準(zhǔn)以及加密收集資產(chǎn)等知識(shí)。聲明一個(gè)繼承的新合約,命名為。注意目前是一個(gè)草稿,還沒(méi)有正式商定的實(shí)現(xiàn)。所以把這一個(gè)可能的實(shí)現(xiàn)當(dāng)作考慮,但不要把它作為代幣的官方標(biāo)準(zhǔn)。 從這節(jié)開(kāi)始,我們將學(xué)習(xí)代幣, ERC721標(biāo)準(zhǔn), 以及加密收集資產(chǎn)等知識(shí)。 一、代幣 代幣 讓我們來(lái)聊聊以太坊上的代幣。 如果你對(duì)以太坊的世界有一些了解,你很可能聽(tīng)過(guò)人們聊到代幣——尤其是 ERC2...

    android_c 評(píng)論0 收藏0
  • 以太坊開(kāi)發(fā)實(shí)戰(zhàn)學(xué)習(xí)-合約安全(八)

    摘要:合約安全增強(qiáng)溢出和下溢我們將來(lái)學(xué)習(xí)你在編寫(xiě)智能合約的時(shí)候需要注意的一個(gè)主要的安全特性防止溢出和下溢。實(shí)戰(zhàn)演練給加上一些標(biāo)簽把這里變成標(biāo)準(zhǔn)的注釋把一個(gè)管理轉(zhuǎn)移僵尸所有權(quán)的合約符合對(duì)標(biāo)準(zhǔn)草案的實(shí)現(xiàn) 通過(guò)上一節(jié)的學(xué)習(xí),我們完成了 ERC721 的實(shí)現(xiàn)。并不是很復(fù)雜,對(duì)吧?很多類(lèi)似的以太坊概念,當(dāng)你只聽(tīng)人們談?wù)撍鼈兊臅r(shí)候,會(huì)覺(jué)得很復(fù)雜。所以最簡(jiǎn)單的理解方式就是你自己來(lái)實(shí)現(xiàn)它。 一、預(yù)防溢出 不...

    UsherChen 評(píng)論0 收藏0
  • 區(qū)塊鏈開(kāi)發(fā)中使用的最流行的編程語(yǔ)言

    摘要:我們目前正處于一個(gè)新興的區(qū)塊鏈開(kāi)發(fā)行業(yè)中。,一種在以太坊開(kāi)發(fā)人員中流行的新的簡(jiǎn)單編程語(yǔ)言,因?yàn)樗怯糜陂_(kāi)發(fā)以太坊智能合約的語(yǔ)言。它是全球至少萬(wàn)開(kāi)發(fā)人員使用的世界上最流行的編程語(yǔ)言之一。以太坊,主要是針對(duì)工程師使用進(jìn)行區(qū)塊鏈以太坊開(kāi)發(fā)的詳解。 我們目前正處于一個(gè)新興的區(qū)塊鏈開(kāi)發(fā)行業(yè)中。區(qū)塊鏈技術(shù)處于初期階段,然而這種顛覆性技術(shù)已經(jīng)成功地風(fēng)靡全球,并且最近經(jīng)歷了一場(chǎng)與眾不同的繁榮。由于許多...

    2shou 評(píng)論0 收藏0
  • ERC20重要補(bǔ)充之a(chǎn)pproveAndCall

    摘要:假設(shè)某一天,星巴克突然宣布為了擁抱區(qū)塊鏈技術(shù),不再接受法幣買(mǎi)咖啡了,大家以后可以用以太幣或者星巴克自己發(fā)行的星星幣來(lái)買(mǎi)咖啡。用星星幣買(mǎi)咖啡星巴克自己發(fā)行了,取名,遵循協(xié)議。 什么是ERC20 ERC20是以太坊上為token提供的一種協(xié)議,也可以理解成一種token的共同標(biāo)準(zhǔn)。遵循ERC20協(xié)議的token都可以兼容以太坊錢(qián)包,讓用戶(hù)在錢(qián)包中可以查看token余額以及操作token轉(zhuǎn)賬...

    nanchen2251 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<