美文网首页Dapp开发以太坊- Ethereum
以太坊开发(二十二)发布代币以及将合约代码上传至Ethersca

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

作者: yuyangray | 来源:发表于2018-05-27 15:14 被阅读544次

    前言

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

    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有问题。

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

    相关文章

      网友评论

      • cnzhanhao:上图中的关于StandardToken 的地方没看明白,有相关介绍吗?

      本文标题:以太坊开发(二十二)发布代币以及将合约代码上传至Ethersca

      本文链接:https://www.haomeiwen.com/subject/opxmdftx.html