以太坊分析之 代币

以太坊介绍

       以太坊(Ethereum)是一个建立在区块链技术之上,去中心化应用平台。它允许任何人在平台中建立和使用通过区块链技术运行的去中心化应用。

 

 

以太坊代币

         以太坊代币(Ethereumtokens)是利用以太坊的智能合约编写的数字货币

         代币通常通过ICO进入公众视野。这些代币创建者会通过提供内置代币,来交换以太币、比特币或其他数字资产,比如EOS就是通过以太坊代币进行众筹。

         现在市场上最大的以太坊代币是 Augur’sREP Golem’sGNT

 

ERC20 

         ERC-20 标准是在201511月份推出的,使用这种规则的代币,表现出一种通用的和可预测的方式。通过标准化,这样代币之间的兑换和DAPP支持就会变得容易。

         为了充分兼容 ERC20,开发者需要将一组特定的函数(接口)集成到他们的智能合约中,以便在高层面能够执行以下操作:

·        获得代币总供应量

·        获得账户余额

·        转让代币

·        批准花费代币

         可以在https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md查看ERC20代币的标准API

ERC20 标准定义了一个兼容协议, 需要实现的函数. 具体如下.

contract ERC20Interface {

    //该方法用于获取发行的代币总数

    function totalSupply() public constant returns (uint);

    //该方法用于获取指定地址所拥有的代币数量

    function balanceOf(address tokenOwner) public constant returns (uint balance);

    //从方法用于查询_owner地址给_spender地址授权花费的额度

    function allowance(address tokenOwner, address spender) public constant returns (uint remaining);

    //该方法用于调用方发起转账

    function transfer(address to, uint tokens) public returns (bool success);

    //该方法是发起方授权_spender可以花费发起方_value个代币

    function approve(address spender, uint tokens) public returns (bool success);

    //从_from地址中转出_value个代币到_to地址中

    function transferFrom(address from, address to, uint tokens) public returns (bool success);

    //当transfer或transferFrom被调用时,触发转账的动作

    event Transfer(address indexed from, address indexed to, uint tokens);

    //表示相应的授权的请求被同意,可以正式授权

    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);

}

同时规定了三个必须定义的变量,分别是

//代币的名称

string public constant name = "Token Name";

//代币名称的缩写

string public constant symbol = "SYM";

//代币使用的小数点后几位

uint8 public constant decimals = 18;

        

         这些参数的目的是指定这个代币的一些特性。以人民币为例,人民币的名称(name)是RMB,美元的代号为¥,拿100去找零最小可以拿到零钱是一分,也就是0.0001元。因为1最小可分割到小数点4位(0.0001,因此最小交易单位(decimals)为4以下为人民币比特币以太币的对照表供参考:

name

symbol

decimals

RMB

¥

4

Bitcoin

BTC

8

Ethereum

ETH

18

 

 

当用户写的Token的智能合约符合以上这些函数的标准,则用户的Token被称之为标准的ERC20代币。 
ERC-20
代币能立刻兼容以太坊钱包以太坊官网给出了发行Token的案例https://ethereum.org/token

其中的ERC20代币代码:

pragma solidity ^0.4.16;

 

interfacetokenRecipient{ functionreceiveApproval(address _from, uint256 _value, address _token, bytes _extraData) external; }

 

contract TokenERC20 {

    // 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

     */

    functionTokenERC20(

        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

     */

    functiontransfer(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

     */

    functiontransferFrom(address _from, address _to, uint256 _value) publicreturns (bool success) {

        require(_value <= allowance[_from][msg.sender]);     // Check allowance

        allowance[_from][msg.sender] -= _value;

        _transfer(_from, _to, _value);

        returntrue;

    }

 

    /**

     * 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

     */

    functionapprove(address _spender, uint256 _value) public

        returns (bool success) {

        allowance[msg.sender][_spender] = _value;

        returntrue;

    }

 

    /**

     * 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

     */

    functionapproveAndCall(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);

            returntrue;

        }

    }

 

    /**

     * Destroy tokens

     *

     * Remove `_value` tokens from the system irreversibly

     *

     * @param _value the amount of money to burn

     */

    functionburn(uint256 _value) publicreturns (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);

        returntrue;

    }

 

    /**

     * 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

     */

    functionburnFrom(address _from, uint256 _value) publicreturns (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);

        returntrue;

    }

}

 

 

 

 

 

 

 

 

 

发行代币

         本文将truffle +ganache 来发行代币truffleganache开发环境的安装参考本系列的另一篇文章https://blog.csdn.net/wlhdo71920145/article/details/80476257

 

1.创建项目

$ mkdir my-token

$ cd my-token

$ truffle init

Downloading...

Unpacking...

Setting up...

Unbox successful. Sweet!

 

Commands:

 

  Compile:        truffle compile

  Migrate:        truffle migrate

  Test contracts: truffle test

 

2.安装zeppelin-solidity

OpenZeppelin是一套能够给我们方便提供编写加密合约的函数库,同时里面也提供了兼容ERC20的智能合约。

$ cd my-token

$ npm install zeppelin-solidity

安装成功后可以在项目目录node_modules下查询到。

3.创建代币合约

在contracts/目录下建立一个合约文件 myToken.sol

pragma solidity ^0.4.4;
import "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";
 
contract myToken is StandardToken {
  string public name = "MyToken"; //代币名称
  string public symbol = "MYT"; //代币简称
  uint8 public decimals = 4;
  uint256 public INITIAL_SUPPLY = 1000000; //发行总量
  function myToken () {
    balances[msg.sender] = INITIAL_SUPPLY;
  }
}

4.编译&部署代币合约

启动Ganache

ganache-cli -p 60545

修改配置文件truffle.jstruffle-config.js:

module.exports = {

  // See   // for more about customizing your Truffle configuration!

  networks: {

    development: {

      host: "127.0.0.1",

      port: 60545,

      network_id: "*" // Match any network id

    }

  }

};

创建文件migrations/2_deploy_contracts.js

const myToken = artifacts.require("./myToken.sol")

module.exports = function(deployer) {

    deployer.deploy(myToken);

};

编译部署

$ truffle compile

$ truffle migrate --network development

5.发行代币

启动控制台执行合约来代币

$ truffle console --network development

truffle(development)> var myTokenInstance

undefined

truffle(development)>myToken.deployed().then(function(instance){myTokenInstance = instance})

undefined

truffle(development)> myTokenInstance.balanceOf(web3.eth.accounts[0])

{ [String: '1000000'] s: 1, e: 6, c: [ 1000000 ] }

可以看到自己的代币创建完成,总量1000000,已经分配置给主账户,因为他是合约部署的账户

 

6.通过钱包查看代币

查询代币的合约地址

truffle(development)> myTokenInstance.address

'0x23138de749202c7a2febc2a11c14b3e8a44d3e32'

 

现在通过钱包MetaMask来查询代币,首先配置MetaMask连接到Ganache的测试网络:

 

然后导入账户,Ganache启动的时候会生成账户和PrivateKey,获取第一个账户的PrivateKey:

Ganache CLI v6.1.0 (ganache-core: 2.1.0)

Available Accounts

==================

(0) 0x4e46cb4e659ab6529a76050047b46a9550f40b73

(1) 0x3deb41052edefae8c405e316d05e1ae1fd8a440d

(2) 0x7d1d633567d8513ef4289bf377cc499cb11fb6d1

(3) 0x1842efd93fcc83bd89ff99d1620f0294fd56c896

(4) 0x23f63b6e88b9dcb4f20ca98fa5e64d52c62245cb

(5) 0xd0d0f981b90e5738dfcb8d92f9739a0543ff4ec6

(6) 0xe32c2ed2d28a25d1e6054ef507eeba6fe91e520e

(7) 0x462a0aac15c6f23995ca38a836df808f6a857b7c

(8) 0x18ebb0c8d9979f82d220efff1e9766faf2f1b396

(9) 0xd46dc33270a069e6d53eb1436a6add923150c05d

Private Keys

==================

(0) 51ba9be2099116ce70163a01854584af8c20e292d6ac05fc507ea74d05db3128

(1) c8555c81fff7ded0a1de56ce584fad72385937da15e15bb7fc83df3d58ea765d

(2) 4143654a28bdef6d5926143002cdbab6a15552895ddf5595b82d17158b217677

(3) 2a10cc50ca4a3a25928f59d50bbe18c964b1ab41203a0c8e2b77b639bbf52099

(4) a059395f63d63d22d4cd86428df6ff39d78996947439b87da41a12b44a8f8233

(5) eba6aef32844ff0099a463cb3d8d1ca84e5716c94285bbb8cbb609742fe96d63

(6) 9404a5a0e7a084129355dfbe9f0cefa7abd69c1e6da3863ac2790727487a6214

(7) 2c7aa55cb1a71ef1632140de575c264d3ae370c5c9a846f47558083e19b20457

(8) daf0936b531e338fe75081d9ae688c7ebf1f9971f3d82ca53384c96f54c2643e

(9) ba9d0dcfed2e1dfb9be37aad1aa67b00f8cd5051ba2d0c32c8a52dbe89099d37

 

MetaMask界面导入账户:

 

 点击add token 添加token,输入合约地址:

Token添加成功后就可以查询到我们的代币了:


参考

  • https://ethfans.org/toya/articles/464
  • https://www.jianshu.com/p/a3a59c651cc2
  • https://blog.csdn.net/a32521500/article/details/79217517
  • https://blog.csdn.net/weixin_41806245/article/details/80297406

作者简介

吴龙辉,《Kubernetes实战》作者,活跃于技术开源社区,贡献代码和撰写技术文档。 
邮箱: [email protected]

猜你喜欢

转载自blog.csdn.net/wlhdo71920145/article/details/80584485
今日推荐