前言
这篇文章主要包含以下内容:
编写一个当前较主流的
ERC20
代币合约将代币合约发布至以太坊主网
发布成功后,将合约代码上传至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
,设置当前的provider
为MetaMask
,这时Account
一栏应该会显示之前导入的有以太币的账号地址。下方合约选择为CBC Token
。点击
Deploy
,MetaMask
会弹出确认页面要求你签署交易。这里说明一下gas limit
和gas price
。gas 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-solidity
在Setting
标签中默认为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);
}
}
- 在
Browser-solidity
编译成功代码后,先通过点击Details
获取到代码的BYTECODE
BYTECODE
60806040526040805190810160405280601081526020017f68747470733a2f2f6d73686b2e746f70000000000000000000000000000000008152506000908051906020019061004f9291906100c9565b5034801561005c57600080fd5b506040516020806106af8339810180604052810190808051906020019092919050505080600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505061016e565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061010a57805160ff1916838001178555610138565b82800160010185558215610138579182015b8281111561013757825182559160200191906001019061011c565b5b5090506101459190610149565b5090565b61016b91905b8082111561016757600081600090555060010161014f565b5090565b90565b6105328061017d6000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680635a3b7e421461005c57806370a08231146100ec578063a9059cbb14610143575b600080fd5b34801561006857600080fd5b50610071610190565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100b1578082015181840152602081019050610096565b50505050905090810190601f1680156100de5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156100f857600080fd5b5061012d600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061022e565b6040518082815260200191505060405180910390f35b34801561014f57600080fd5b5061018e600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610246565b005b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102265780601f106101fb57610100808354040283529160200191610226565b820191906000526020600020905b81548152906001019060200180831161020957829003601f168201915b505050505081565b60016020528060005260406000206000915090505481565b610251338383610255565b5050565b6000808373ffffffffffffffffffffffffffffffffffffffff161415151561027c57600080fd5b81600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156102ca57600080fd5b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020540111151561035857600080fd5b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401905081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555080600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020540114151561050057fe5b505050505600a165627a7a723058203b0a1ae0bd274f3a61fdae8f884579cdcfb672db4a2f6ec882f910389a3c6d310029
- 部署合约,获取
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有问题。