以太坊开发(二十二)发布代币以及将合约代码上传至Etherscan

前言

这篇文章主要包含以下内容:

  1. 编写一个当前较主流的ERC20代币合约

  2. 将代币合约发布至以太坊主网

  3. 发布成功后,将合约代码上传至https://etherscan.io/

以及遇到的坑和如何解决。

1.代币合约

通过https://etherscan.io/查看一个名叫Welltrado的项目的代币合约
https://etherscan.io/address/0x9a0587eae7ef64b2b38a10442a44cfa43edd7d2a#code

关于代币合约的代码,其实很多文章已经有了。但是在我真正准备写一个代币合约时,我还是先去https://etherscan.io/上查看了一些主流代币的合约,发现他们的写法都与之前教程中的合约代码有一些不同:有增发上限,设置合约可暂停。当然最大的不同是加入了安全计算法SafeMath。最近经常爆出的一些代币合约漏洞,大多都是没有使用SafeMath导致的。

下面是本文使用的代币合约代码,没有加中文注释的方法解释,可以看以前的文章:

pragma solidity ^0.4.18;

/**
 * 使用安全计算法进行加减乘除运算
 * @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 a / b;
  }

  /**
  * @dev Subtracts 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;
  }
}

contract Ownable {
  address public owner;


  /**
   * @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.
   */
  function transferOwnership(address newOwner) public onlyOwner {
    if (newOwner != address(0)) {
      owner = newOwner;
    }
  }

}

/**
 * 合约管理员可以在紧急情况下暂停合约,停止转账行为
 * @title Pausable
 * @dev Base contract which allows children to implement an emergency stop mechanism.
 */
contract Pausable is Ownable {
  event Pause();
  event Unpause();

  bool public paused = false;


  /**
   * @dev Modifier to make a function callable only when the contract is not paused.
   */
  modifier whenNotPaused() {
    require(!paused);
    _;
  }

  /**
   * @dev Modifier to make a function callable only when the contract is paused.
   */
  modifier whenPaused() {
    require(paused);
    _;
  }

  /**
   * @dev called by the owner to pause, triggers stopped state
   */
  function pause() onlyOwner whenNotPaused public {
    paused = true;
    emit Pause();
  }

  /**
   * @dev called by the owner to unpause, returns to normal state
   */
  function unpause() onlyOwner whenPaused public {
    paused = false;
    emit Unpause();
  }

}

/**
 * @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);
  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 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);
  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);
}

/**
 * @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_;

  /**
  * @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]);

    balances[msg.sender] = balances[msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);
    emit Transfer(msg.sender, _to, _value);
    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];
  }

}

/**
 * @title Standard ERC20 token
 *
 * @dev Implementation of the basic standard token.
 * @dev https://github.com/ethereum/EIPs/issues/20
 */
contract StandardToken is ERC20, BasicToken {

  mapping (address => mapping (address => uint256)) internal allowed;


  /**
   * 方法调用者将from账户中的代币转入to账户中
   * @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));
    require(_value <= balances[_from]);
    require(_value <= allowed[_from][msg.sender]);

    balances[_from] = balances[_from].sub(_value);
    balances[_to] = balances[_to].add(_value);
    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
    emit Transfer(_from, _to, _value);
    return true;
  }

  /**
   * 方法调用者允许spender操作自己账户中value数量的代币
   * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
   *
   * 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 The address which will spend the funds.
   * @param _value The amount of tokens to be spent.
   */
  function approve(address _spender, uint256 _value) public returns (bool) {
    allowed[msg.sender][_spender] = _value;
    emit Approval(msg.sender, _spender, _value);
    return true;
  }

  /**
   * 查看spender还可以操作owner代币的数量是多少
   * @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];
  }

  /**
   * 调用者增加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);
    emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
    return true;
  }

  /**
   * 调用者减少spender可操作的代币数量
   * @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);
    }
    emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
    return true;
  }

}

/**
 * 一个可增发的代币。包含增发及结束增发的方法
 * @title Mintable token
 * @dev Simple ERC20 Token example, with mintable token creation
 * @dev Issue: * https://github.com/OpenZeppelin/zeppelin-solidity/issues/120
 */
contract MintableToken is StandardToken, Ownable {
  event Mint(address indexed to, uint256 amount);
  event MintFinished();

  bool public mintingFinished = false;


  modifier canMint() {
    require(!mintingFinished);
    _;
  }

  /**
   * @dev Function to mint tokens
   * @param _to The address that will receive the minted tokens.
   * @param _amount The amount of tokens to mint.
   * @return A boolean that indicates if the operation was successful.
   */
  function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {
    totalSupply_ = totalSupply_.add(_amount);
    balances[_to] = balances[_to].add(_amount);
    emit Mint(_to, _amount);
    emit Transfer(address(0), _to, _amount);
    return true;
  }

  /**
   * @dev Function to stop minting new tokens.
   * @return True if the operation was successful.
   */
  function finishMinting() onlyOwner canMint public returns (bool) {
    mintingFinished = true;
    emit MintFinished();
    return true;
  }
}

/**
 * 设置增发的上限
 * @title Capped token
 * @dev Mintable token with a token cap.
 */
contract CappedToken is MintableToken {

  uint256 public cap;

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

  /**
   * @dev Function to mint tokens
   * @param _to The address that will receive the minted tokens.
   * @param _amount The amount of tokens to mint.
   * @return A boolean that indicates if the operation was successful.
   */
  function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {
    require(totalSupply_.add(_amount) <= cap);

    return super.mint(_to, _amount);
  }

}

// 暂停合约会影响以下方法的调用
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);
  }

// 批量转账
function batchTransfer(address[] _receivers, uint256 _value) public whenNotPaused returns (bool) {
    uint receiverCount = _receivers.length;
    uint256 amount = _value.mul(uint256(receiverCount));
    /* require(receiverCount > 0 && receiverCount <= 20); */
    require(receiverCount > 0);
    require(_value > 0 && balances[msg.sender] >= amount);

    balances[msg.sender] = balances[msg.sender].sub(amount);
    for (uint i = 0; i < receiverCount; i++) {
        balances[_receivers[i]] = balances[_receivers[i]].add(_value);
        Transfer(msg.sender, _receivers[i], _value);
    }
    return true;
  }
}

/**
 * 调用者销毁手中的代币,代币总量也会相应减少,此方法是不可逆的
 * @title Burnable Token
 * @dev Token that can be irreversibly burned (destroyed).
 */
contract BurnableToken is BasicToken {

  event Burn(address indexed burner, uint256 value);

  /**
   * @dev Burns a specific amount of tokens.
   * @param _value The amount of token to be burned.
   */
  function burn(uint256 _value) public {
    require(_value <= balances[msg.sender]);
    // no need to require value <= totalSupply, since that would imply the
    // sender's balance is greater than the totalSupply, which *should* be an assertion failure

    address burner = msg.sender;
    balances[burner] = balances[burner].sub(_value);
    totalSupply_ = totalSupply_.sub(_value);
    emit Burn(burner, _value);
    emit Transfer(burner, address(0), _value);
  }
}

contract CBCToken is CappedToken, PausableToken, BurnableToken {

    string public constant name = "CarBoxCoin";
    string public constant symbol = "CBC";
    uint8 public constant decimals = 18;

    uint256 private constant TOKEN_CAP = 300000000 * (10 ** uint256(decimals));
    uint256 private constant TOKEN_INITIAL = 200000000 * (10 ** uint256(decimals));

    function CBCToken() public CappedToken(TOKEN_CAP) {
      totalSupply_ = TOKEN_INITIAL;

      balances[msg.sender] = TOKEN_INITIAL;
      emit Transfer(address(0), msg.sender, TOKEN_INITIAL);

      paused = true;
  }
}

上面的可增发,增发上限,可销毁等方法根据实际需要选择性继承,不过可暂停的方法建议保留,以应对紧急情况。

2.发布代币合约到以太坊主网

之前的文章中,我们使用以太坊的官方客户端Mist,连接本地的私有链进行代币的发布。如果要将代币发布到以太坊主网中,Mist也需要连接以太坊主链。这时Mist必须同步主网的全部区块数据,不仅耗时久,而且占用硬盘。这里我们使用Browser-solidity + MetaMask进行合约发布。

  • 首先使用Chrome或者FireFox浏览器,并且安装好MetaMask插件,然后导入一个有以太币的账号。这部分内容可以查看以前的文章。

  • 打开https://remix.ethereum.org/,将代码复制进去。编译成功后选择CBC Token。切换至Run标签,Environment选择 injected Web3,设置当前的providerMetaMask,这时Account一栏应该会显示之前导入的有以太币的账号地址。下方合约选择为CBC Token

  • 点击DeployMetaMask会弹出确认页面要求你签署交易。这里说明一下gas limitgas pricegas limit是根据代码内容大小计算的,一般不用去改它,gas price是一个你愿意支付的价格,价格越高,被确认的速度越快。可以通过这个网站https://ethgasstation.info/,查看不同gas price被确认的时间,根据需要进行选择。

这张图中可以看出:

  • 支付6gwei,可以在30分钟内得到确认

  • 支付10gwei,可以在10分钟内得到确认

  • 支付12gwei,可以在2分钟内得到确认

部署后就可以在页面中得到代币合约地址,这时候我们需要复制这个地址去https://etherscan.io/进行查询,确认合约是否成功创建。根据支付的gas price,合约可能会很快创建成功,也可能会处于pending状态。

页面中显示最终部署合约花费了0.022以太币,按当前币值,等于12.82美元,约等于82人民币。

3.上传合约代码到https://etherscan.io/

3.1 为什么要上传代币合约代码?

  • 公开代币合约代码,有助于增加透明度和信任度

  • https://etherscan.io/上传代码后,人们可以通过网页查看代码当前状态,以及查询代码余额

你们感受下
https://etherscan.io/address/0x7fccf800568747b178c6cbbe4bf3d147df75ac61#readContract

3.2 如何上传代码?

在代币合约页面点击下图中的验证按钮(这里我随便找了一个没有验证过代码的代币合约)

来到下面的页面

https://etherscan.io/verifyContract?a=0x16342dbadb1c62165cc17af95f90cf34a8dea98e

3.3 必填项说明

  • Contract Address合约地址。不可更改

  • Contract Name合约名称。这里不是随便起一个,而是填写刚才在Browser-solidity部署时选择的合约名称,本例中是CBC Token

  • Compiler编译器版本。注意这个的编译器版本不是编写代码使用的版本。上面我们的代码中,编译器版本是pragma solidity ^0.4.18,一直无法验证通过。后来怀疑是不是这里应该选择部署代码时的编译器版本?而当时Browser-soliditySetting标签中默认为0.4.24。于是这里更换为0.4.24,果然成功了。

  • Optimization优化。如果以上问题解决了还是验证失败,可以尝试选择不优化。

  • Enter the Solidity Contract Code below粘贴合约源代码。这里可以选择将代码保存到GithubGist,然后根据id获取。也可以直接粘贴。

3.4 选填项说明

Constructor Arguments ABI-encoded (For contracts that accept constructor parameters)构造函数参数的ABI-encoded。如果你的合约在部署时不需要给构造函数传参,那这里可以不填。如果有传参,那么这段ABI-encoded的获取方式为:

这里随便找了一个简单的需要传参的代币合约来演示

pragma solidity ^0.4.20;

/**
 * @title 基础版的代币合约
 */
contract token {
    
    /* 公共变量 */
    string public standard = "https://mshk.top";
    
    /*记录所有余额的映射*/
    mapping (address => uint256) public balanceOf;
    
    /* 初始化合约,并且把初始的所有代币都给这合约的创建者
     * @param initialSupply 代币的总数
     */
    function token (uint256 initialSupply) public {
        balanceOf[msg.sender] = initialSupply;
    }
    
    /**
     * 私有方法从一个帐户发送给另一个帐户代币
     * @param  from address 发送代币的地址
     * @param  to address 接受代币的地址
     * @param  value uint256 接受代币的数量
     */
    function _transfer (address from, address to, uint256 value) internal {
        
        //避免转帐的地址是0x0
        require(to != 0x0);
        
        //检查发送者是否拥有足够余额
        require(balanceOf[from] >= value);
        
        //检查是否溢出
        require(balanceOf[to] + value > balanceOf[to]);
        
        //保存数据用于后面的判断
        uint previousBalances = balanceOf[from] + balanceOf[to];
        
        //从发送者减掉发送额
        balanceOf[from] -= value;
        
        //给接收者加上相同的量
        balanceOf[to] += value;
        
        //判断买、卖双方的数据是否和转换前一致
        assert(balanceOf[from] + balanceOf[to] == previousBalances);
    }
    
    /**
     * 从主帐户合约调用者发送给别人代币
     * @param  to address 接受代币的地址
     * @param  value uint256 接受代币的数量
     */
    function transfer (address to, uint256 value) public {
        _transfer(msg.sender, to, value);
    }
}
  1. Browser-solidity编译成功代码后,先通过点击Details获取到代码的BYTECODE

BYTECODE

60806040526040805190810160405280601081526020017f68747470733a2f2f6d73686b2e746f70000000000000000000000000000000008152506000908051906020019061004f9291906100c9565b5034801561005c57600080fd5b506040516020806106af8339810180604052810190808051906020019092919050505080600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505061016e565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061010a57805160ff1916838001178555610138565b82800160010185558215610138579182015b8281111561013757825182559160200191906001019061011c565b5b5090506101459190610149565b5090565b61016b91905b8082111561016757600081600090555060010161014f565b5090565b90565b6105328061017d6000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680635a3b7e421461005c57806370a08231146100ec578063a9059cbb14610143575b600080fd5b34801561006857600080fd5b50610071610190565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100b1578082015181840152602081019050610096565b50505050905090810190601f1680156100de5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156100f857600080fd5b5061012d600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061022e565b6040518082815260200191505060405180910390f35b34801561014f57600080fd5b5061018e600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610246565b005b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102265780601f106101fb57610100808354040283529160200191610226565b820191906000526020600020905b81548152906001019060200180831161020957829003601f168201915b505050505081565b60016020528060005260406000206000915090505481565b610251338383610255565b5050565b6000808373ffffffffffffffffffffffffffffffffffffffff161415151561027c57600080fd5b81600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156102ca57600080fd5b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020540111151561035857600080fd5b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401905081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555080600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020540114151561050057fe5b505050505600a165627a7a723058203b0a1ae0bd274f3a61fdae8f884579cdcfb672db4a2f6ec882f910389a3c6d310029
  1. 部署合约,获取input

input creation byte code

0x60806040526040805190810160405280601081526020017f68747470733a2f2f6d73686b2e746f70000000000000000000000000000000008152506000908051906020019061004f9291906100c9565b5034801561005c57600080fd5b506040516020806106af8339810180604052810190808051906020019092919050505080600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505061016e565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061010a57805160ff1916838001178555610138565b82800160010185558215610138579182015b8281111561013757825182559160200191906001019061011c565b5b5090506101459190610149565b5090565b61016b91905b8082111561016757600081600090555060010161014f565b5090565b90565b6105328061017d6000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680635a3b7e421461005c57806370a08231146100ec578063a9059cbb14610143575b600080fd5b34801561006857600080fd5b50610071610190565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100b1578082015181840152602081019050610096565b50505050905090810190601f1680156100de5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156100f857600080fd5b5061012d600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061022e565b6040518082815260200191505060405180910390f35b34801561014f57600080fd5b5061018e600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610246565b005b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102265780601f106101fb57610100808354040283529160200191610226565b820191906000526020600020905b81548152906001019060200180831161020957829003601f168201915b505050505081565b60016020528060005260406000206000915090505481565b610251338383610255565b5050565b6000808373ffffffffffffffffffffffffffffffffffffffff161415151561027c57600080fd5b81600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156102ca57600080fd5b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020540111151561035857600080fd5b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401905081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555080600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020540114151561050057fe5b505050505600a165627a7a723058203b0a1ae0bd274f3a61fdae8f884579cdcfb672db4a2f6ec882f910389a3c6d3100290000000000000000000000000000000000000000000000056bc75e2d63100000

两个bytecode对比会发现,部署合约时的code比编译合约时的code尾部多了一串code

00000000000000000000000000000000000000000000056bc75e2d63100000

56bc75e2d63100000作为16进制进行转换

结果为十进制100000000000000000000,正好是我部署合约是填写的参数的数字。00000000000000000000000000000000000000000000056bc75e2d63100000这串数字也就是要填入此处的内容。

Contract Library Address (For contracts that use libraries, supports up to 5 libraries)依赖合约的地址,最多可以填写5个。因为我依赖的SafeMath都写在代码里了,所以这里不用填写。

3.5 进行验证

点击验证按钮进行提交。如果有错误,页面会给出相应提示,按提示修改就好。我之前一直显示:发生了未知错误,后来又好了,估计是那几天Etherscan有问题。

原创内容,转载请注明出处,谢谢

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容