文章内容主要来自于 https://www.ethereum.org/token。 笔者没有过英语4级,翻译的不好请见谅 ^_^
我们将创建一个数字令牌(digital token)。以太坊生态系统中的token可以代表任何可替换可交易的物品:硬币,金币,游戏内物品等。任何token都以标准方式实现一些基本功能。这意味着您的token可以兼容以太坊钱包和其他任何使用形同标准的contract。
我们所说的代币,绝大多数都是token。
先看一下代币的样子:
进入网站:https://etherscan.io/。随便找一个代币,点进去查看:
接下来看一下ERC20标准。以下是ERC20标准的接口声明:
// https://github.com/ethereum/EIPs/issues/20
contract ERC20 {
string public constant name = "Token Name";//token的名字、代币名称
string public constant symbol = "SYM"; // token的简写/代币符号
uint8 public constant decimals = 18; // 代币小数点位数,代币的最小单位, 18表示我们可以拥有 .0000000000000000001单位个代币。 官方推荐18。不要轻易改变
function totalSupply() constant returns (uint totalSupply);//发行代币总量。
function balanceOf(address _owner) constant returns (uint balance);//查看对应账号的代币余额。
function transfer(address _to, uint _value) returns (bool success);//实现代币交易,用于给用户发送代币(从我们的账户里)。
function transferFrom(address _from, address _to, uint _value) returns (bool success);//实现代币用户之间的交易。
function approve(address _spender, uint _value) returns (bool success);//允许用户可花费的代币数。
function allowance(address _owner, address _spender) constant returns (uint remaining);//控制代币的交易,如可交易账号及资产。
event Transfer(address indexed _from, address indexed _to, uint _value);
event Approval(address indexed _owner, address indexed _spender, uint _value);
}
直接上代码:
pragma solidity ^0.4.16;
interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) external; }
contract LBL {
// Public variables of the token
string public name;
string public symbol;
uint8 public decimals = 18;
// 18 decimals is the strongly suggested default, avoid changing it
uint256 public totalSupply;
// This creates an array with all balances
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
// This generates a public event on the blockchain that will notify clients
event Transfer(address indexed from, address indexed to, uint256 value);
// This notifies clients about the amount burnt
event Burn(address indexed from, uint256 value);
/** * Constructor function * * Initializes contract with initial supply tokens to the creator of the contract */
function LBL (
uint256 initialSupply,
string tokenName,
string tokenSymbol
) public {
totalSupply = initialSupply * 10 ** uint256(decimals); // Update total supply with the decimal amount
balanceOf[msg.sender] = totalSupply; // Give the creator all initial tokens
name = tokenName; // Set the name for display purposes
symbol = tokenSymbol; // Set the symbol for display purposes
}
/** * Internal transfer, only can be called by this contract */
function _transfer(address _from, address _to, uint _value) internal {
// Prevent transfer to 0x0 address. Use burn() instead
require(_to != 0x0);
// Check if the sender has enough
require(balanceOf[_from] >= _value);
// Check for overflows
require(balanceOf[_to] + _value >= balanceOf[_to]);
// Save this for an assertion in the future
uint previousBalances = balanceOf[_from] + balanceOf[_to];
// Subtract from the sender
balanceOf[_from] -= _value;
// Add the same to the recipient
balanceOf[_to] += _value;
emit Transfer(_from, _to, _value);
// Asserts are used to use static analysis to find bugs in your code. They should never fail
assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
}
/** * Transfer tokens * * Send `_value` tokens to `_to` from your account * * @param _to The address of the recipient * @param _value the amount to send */
function transfer(address _to, uint256 _value) public {
_transfer(msg.sender, _to, _value);
}
/** * Transfer tokens from other address * * Send `_value` tokens to `_to` on behalf of `_from` * * @param _from The address of the sender * @param _to The address of the recipient * @param _value the amount to send */
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(_value <= allowance[_from][msg.sender]); // Check allowance
allowance[_from][msg.sender] -= _value;
_transfer(_from, _to, _value);
return true;
}
/** * Set allowance for other address * * Allows `_spender` to spend no more than `_value` tokens on your behalf * * @param _spender The address authorized to spend * @param _value the max amount they can spend */
function approve(address _spender, uint256 _value) public
returns (bool success) {
allowance[msg.sender][_spender] = _value;
return true;
}
/** * Set allowance for other address and notify * * Allows `_spender` to spend no more than `_value` tokens on your behalf, and then ping the contract about it * * @param _spender The address authorized to spend * @param _value the max amount they can spend * @param _extraData some extra information to send to the approved contract */
function approveAndCall(address _spender, uint256 _value, bytes _extraData)
public
returns (bool success) {
tokenRecipient spender = tokenRecipient(_spender);
if (approve(_spender, _value)) {
spender.receiveApproval(msg.sender, _value, this, _extraData);
return true;
}
}
/** * Destroy tokens * * Remove `_value` tokens from the system irreversibly * * @param _value the amount of money to burn */
function burn(uint256 _value) public returns (bool success) {
require(balanceOf[msg.sender] >= _value); // Check if the sender has enough
balanceOf[msg.sender] -= _value; // Subtract from the sender
totalSupply -= _value; // Updates totalSupply
emit Burn(msg.sender, _value);
return true;
}
/** * Destroy tokens from other account * * Remove `_value` tokens from the system irreversibly on behalf of `_from`. * * @param _from the address of the sender * @param _value the amount of money to burn */
function burnFrom(address _from, uint256 _value) public returns (bool success) {
require(balanceOf[_from] >= _value); // Check if the targeted balance is enough
require(_value <= allowance[_from][msg.sender]); // Check allowance
balanceOf[_from] -= _value; // Subtract from the targeted balance
allowance[_from][msg.sender] -= _value; // Subtract from the sender's allowance
totalSupply -= _value; // Update totalSupply
emit Burn(_from, _value);
return true;
}
}
将上述代码贴到Remix 中(https://ethereum.github.io/browser-solidity):
上图中create按钮填入你想要的发行量,名称及代号,就可以创建合约了。
这时MetaMask会弹出一个交易确认框,点SUBMIT。待合约部署交易确认之后,复制合约地址。
如果你没有余额,需要先充值,才能发布成功。复制上述合约地址,牢记,否则合约就白部署了。你的以太币也浪费了。
上面部署好了以后,不方便查看和交易,下面我们将通过MetaMask和myetherwallet两个钱包来实现我们代笔的交易。
参见 以太坊轻钱包MetaMask详细图文教程。 读者请自行安装部署
安装好了以后,打开Metamask界面,切换到TOKENS,点添加合约,出现如下对话框:
填入刚刚复制的地址,点ADD,这时你就可以看到你创建的代币了,如图:
到此为止,我们已经完成了代币的发放部署。可以在Etherscan上查询到我们刚刚部署的代币了
可以在以太坊浏览器上查看到我的代币 https://etherscan.io/address/0xFFCABB58bE7de3579bE5c423451896eb89bF18Ff:
由于MetaMask插件没有提供代币交易功能,以太坊钱包又受限于网速等原因特别不好用。所以我们选择myetherwallet。