基于以太坊发布属于自己的数字货币(代币)完整版

基于以太坊发布属于自己的数字货币(代币)完整版

参考资料来源于网络以及各种摸索,其中各种坑

本文单纯从技术角度详细介绍如何基于以太坊ERC20创建代币的流程(此案例是部署的eth主网,非测试案例)

写在前面

 

本文所讲的代币是使用以太坊智能合约创建,阅读本文前,你应该对以太坊、智能合约有所了解,如果你还不了解,建议你先看以太坊是什么

代币Token

如果不那么追求精确的定义,代币就是数字货币,比特币、以太币就是一个代币。
利用以太坊的智能合约可以轻松编写出属于自己的代币,代币可以代表任何可以交易的东西,如:积分、财产、证书等等。

因此不管是出于商业,还是学习很多人想创建一个自己的代币,先贴一个图看看创建的代币是什么样子。

以我自己发布的BliBli币 Bcoin为例

访问地址  https://etherscan.io/token/0x73c8da697fe5e145f6269c4c852e59a7328f9371




 今天我们就来详细讲一讲怎样创建一个这样的代币。

ERC20 Token

ERC20和代币一同出现, ERC20是以太坊定义的一个代币标准是一种发行代币合约必须要遵守的协议,该协议规定了几个参数——发行货币的名称,简称,发行量,要支持的函数等,只有支持了该协议才会被以太坊所认同。

erc20标准代码如下

// https://github.com/ethereum/EIPs/issues/20
  contract ERC20 {
      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);
    }

totalSupply:  代表的是代币发行总量    totalSupply():该方法可以返回代币的总数量

name:  发行代币的名称                       dicimals:  发行代币以后,代币交易的最小单位

balanceOf(): 该方法返回的是输入钱包地址后,该钱包的代币余额

tansferFrom() :从一个地址向另一个地址发送余额

approve(): 允许_spender从你的账户转出_value余额

allowance(): 允许_spender从你的账户转出_value的余额,调用多次会覆盖可用量。某些DEX功能需要此功能

event Transfer():  token转移完成后出发

event Approval():  approve(address _spender, uint256 _value)调用后触发


编写代币合约:


pragma solidity ^0.4.12;

contract IMigrationContract {
    function migrate(address addr, uint256 nas) returns (bool success);
}

/* 灵感来自于NAS  coin*/
contract SafeMath {


    function safeAdd(uint256 x, uint256 y) internal returns(uint256) {
        uint256 z = x + y;
        assert((z >= x) && (z >= y));
        return z;
    }

    function safeSubtract(uint256 x, uint256 y) internal returns(uint256) {
        assert(x >= y);
        uint256 z = x - y;
        return z;
    }

    function safeMult(uint256 x, uint256 y) internal returns(uint256) {
        uint256 z = x * y;
        assert((x == 0)||(z/x == y));
        return z;
    }

}

contract Token {
    uint256 public totalSupply;
    function balanceOf(address _owner) constant returns (uint256 balance);
    function transfer(address _to, uint256 _value) returns (bool success);
    function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
    function approve(address _spender, uint256 _value) returns (bool success);
    function allowance(address _owner, address _spender) constant returns (uint256 remaining);
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}


/*  ERC 20 token */
contract StandardToken is Token {

    function transfer(address _to, uint256 _value) returns (bool success) {
        if (balances[msg.sender] >= _value && _value > 0) {
            balances[msg.sender] -= _value;
            balances[_to] += _value;
            Transfer(msg.sender, _to, _value);
            return true;
        } else {
            return false;
        }
    }

    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
        if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) {
            balances[_to] += _value;
            balances[_from] -= _value;
            allowed[_from][msg.sender] -= _value;
            Transfer(_from, _to, _value);
            return true;
        } else {
            return false;
        }
    }

    function balanceOf(address _owner) constant returns (uint256 balance) {
        return balances[_owner];
    }

    function approve(address _spender, uint256 _value) returns (bool success) {
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);
        return true;
    }

    function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
        return allowed[_owner][_spender];
    }

    mapping (address => uint256) balances;
    mapping (address => mapping (address => uint256)) allowed;
}

contract BliBliToken is StandardToken, SafeMath {

    // metadata
    string  public constant name = "BliBli";
    string  public constant symbol = "BCoin";
    uint256 public constant decimals = 18;
    string  public version = "1.0";

    // contracts
    address public ethFundDeposit;          // ETH存放地址
    address public newContractAddr;         // token更新地址

    // crowdsale parameters
    bool    public isFunding;                // 状态切换到true
    uint256 public fundingStartBlock;
    uint256 public fundingStopBlock;

    uint256 public currentSupply;           // 正在售卖中的tokens数量
    uint256 public tokenRaised = 0;         // 总的售卖数量token
    uint256 public tokenMigrated = 0;     // 总的已经交易的 token
    uint256 public tokenExchangeRate = 625;             // 625 BILIBILI 兑换 1 ETH

    // events
    event AllocateToken(address indexed _to, uint256 _value);   // 分配的私有交易token;
    event IssueToken(address indexed _to, uint256 _value);      // 公开发行售卖的token;
    event IncreaseSupply(uint256 _value);
    event DecreaseSupply(uint256 _value);
    event Migrate(address indexed _to, uint256 _value);

    // 转换
    function formatDecimals(uint256 _value) internal returns (uint256 ) {
        return _value * 10 ** decimals;
    }

    // constructor
    function BliBliToken(
        address _ethFundDeposit,
        uint256 _currentSupply)
    {
        ethFundDeposit = _ethFundDeposit;

        isFunding = false;                           //通过控制预CrowdS ale状态
        fundingStartBlock = 0;
        fundingStopBlock = 0;

        currentSupply = formatDecimals(_currentSupply);
        totalSupply = formatDecimals(10000000);
        balances[msg.sender] = totalSupply;
        if(currentSupply > totalSupply) throw;
    }

    modifier isOwner()  { require(msg.sender == ethFundDeposit); _; }

    ///  设置token汇率
    function setTokenExchangeRate(uint256 _tokenExchangeRate) isOwner external {
        if (_tokenExchangeRate == 0) throw;
        if (_tokenExchangeRate == tokenExchangeRate) throw;

        tokenExchangeRate = _tokenExchangeRate;
    }

    /// @dev 超发token处理
    function increaseSupply (uint256 _value) isOwner external {
        uint256 value = formatDecimals(_value);
        if (value + currentSupply > totalSupply) throw;
        currentSupply = safeAdd(currentSupply, value);
        IncreaseSupply(value);
    }

    /// @dev 被盗token处理
    function decreaseSupply (uint256 _value) isOwner external {
        uint256 value = formatDecimals(_value);
        if (value + tokenRaised > currentSupply) throw;

        currentSupply = safeSubtract(currentSupply, value);
        DecreaseSupply(value);
    }

    ///  启动区块检测 异常的处理
    function startFunding (uint256 _fundingStartBlock, uint256 _fundingStopBlock) isOwner external {
        if (isFunding) throw;
        if (_fundingStartBlock >= _fundingStopBlock) throw;
        if (block.number >= _fundingStartBlock) throw;

        fundingStartBlock = _fundingStartBlock;
        fundingStopBlock = _fundingStopBlock;
        isFunding = true;
    }

    ///  关闭区块异常处理
    function stopFunding() isOwner external {
        if (!isFunding) throw;
        isFunding = false;
    }

    /// 开发了一个新的合同来接收token(或者更新token)
    function setMigrateContract(address _newContractAddr) isOwner external {
        if (_newContractAddr == newContractAddr) throw;
        newContractAddr = _newContractAddr;
    }

    /// 设置新的所有者地址
    function changeOwner(address _newFundDeposit) isOwner() external {
        if (_newFundDeposit == address(0x0)) throw;
        ethFundDeposit = _newFundDeposit;
    }

    ///转移token到新的合约
    function migrate() external {
        if(isFunding) throw;
        if(newContractAddr == address(0x0)) throw;

        uint256 tokens = balances[msg.sender];
        if (tokens == 0) throw;

        balances[msg.sender] = 0;
        tokenMigrated = safeAdd(tokenMigrated, tokens);

        IMigrationContract newContract = IMigrationContract(newContractAddr);
        if (!newContract.migrate(msg.sender, tokens)) throw;

        Migrate(msg.sender, tokens);               // log it
    }

    /// 转账ETH 到BILIBILI团队
    function transferETH() isOwner external {
        if (this.balance == 0) throw;
        if (!ethFundDeposit.send(this.balance)) throw;
    }

    ///  将BILIBILI token分配到预处理地址。
    function allocateToken (address _addr, uint256 _eth) isOwner external {
        if (_eth == 0) throw;
        if (_addr == address(0x0)) throw;

        uint256 tokens = safeMult(formatDecimals(_eth), tokenExchangeRate);
        if (tokens + tokenRaised > currentSupply) throw;

        tokenRaised = safeAdd(tokenRaised, tokens);
        balances[_addr] += tokens;

        AllocateToken(_addr, tokens);  // 记录token日志
    }

    /// 购买token
    function () payable {
        if (!isFunding) throw;
        if (msg.value == 0) throw;

        if (block.number < fundingStartBlock) throw;
        if (block.number > fundingStopBlock) throw;

        uint256 tokens = safeMult(msg.value, tokenExchangeRate);
        if (tokens + tokenRaised > currentSupply) throw;

        tokenRaised = safeAdd(tokenRaised, tokens);
        balances[msg.sender] += tokens;

        IssueToken(msg.sender, tokens);  //记录日志
    }
}

以上的代币合约,是参考以太坊已经ICO过,并且产生价值的代币合约参考而来,完整比且功能强大,此合约创建的代币,具有“交易”,“转账”,“异常检测”,“更改代币持有人”,“设置汇率”,“被盗处理”,“超发代币”等功能。

(解释下:在以太坊的世界中,硬通货就是ETH-以太币,相当于现实世界中的黄金,我们发布的代币,就相当于各国发行的需要 与黄金挂钩兑换比率的货币,国家对货币拥有控制权,只要合约功能进行扩展,创造代币的人也会对代币拥有控制权。)

(对于挖矿的误解:不少小哥哥小姐姐认为挖矿就是挖币,其实挖矿是挖区块,区块是干嘛的,是用来打包交易的,是存储数据的,代币是不用挖的,当你挖到了区块,代币是给你的奖励,在发行量一定的情况下,代币会越来越少,所以挖到区块的奖励会变少。那奖励少了为什么还要挖矿呢,因为你的任何一笔交易都需要记录,一个区块的大小也就几M,存储不了那么多交易信息,所以要持续挖区块来记录你的交易,同时交易的手续费,会奖励给挖出区块的人。)


部署合约:

    

部署合约有多种方式      1 geth 编译代码 ---部署合约

                                     2 用ethereum wallet钱包部署合约

                                    3 最简单直观的部署合约方式:  MetaMaskRemix Solidity IDE 部署合约

   我们按照 MetaMaskRemix Solidity IDE 来进行部署合约。

 1 创建钱包帐号MetaMask是钱包的一种,在chrome浏览器中,安装MetaMask插件即可,安装完成后,右上角会出现一个“狐狸头”的标志,点击该标志,打开钱包,第一步,创建账户,(创建账户只需要输入面密码即可,名称创建后可以随便改,该账户就是一个hash值,如何给自己创建的账户冲以太币,可以上https://otcbtc.com/sign_up网站,按照操作买以太币,然后转账到自己创建的账户)创建成功后,记住密码还有产生的几个随机单词(一定要记录下来)。如下:


   2:打开 Remix Solidity IDE 访问地址: http://remix.ethereum.org/#optimize=false&version=soljson-v0.4.21+commit.dfe3193c.js   界面如下 



3:  拷贝“编写代币合约”后边的代码到Remix Solidity IDE中按照如下编译


4: create 发布  如下

 

 

5 create后,产生hash值,拷贝hash值,在钱包中添加token






OK,如上所示,第一个属于你的真正意义上的去中心化数字货币就诞生了。正式网络和测试网络部署方法一样,不需要买eth就是了。

如果是测试网络,如何获得ETH?   进入 https://gitter.im/kovan-testnet/faucet  下方直接发送你的账户地址(hash值)即可,一般五分钟到账,会得到五个测试网络用的ETH币。



6(如果部署的是eth主网,非测试网,执行该步骤,测试网络可以不理会)

发布了代币以后,如果以后进行ico,那么需要发布源码公开。步骤如下

   ①  拷贝部署成功的合约地址(hash),到  https://etherscan.io/   右上角搜索hash

   ②  按照如下图进行verify AND publish

           打开如下页面第一步



         打开如下页面第二部




 

          打开如下页面第三部


 

 



 


  ok  现在的代币就比较完整了,差ico了



代币转账:

   1  metamask钱包转账:  如下


   输入地址和代币数量





2  网页钱包转账:  如下  https://www.myetherwallet.com/#send-transaction

    登录账户:



  转账交易




     qq群交流

 

 

 

猜你喜欢

转载自blog.csdn.net/java_hhhh/article/details/79771752