区块链智能合约编程三:可发行的代币实现

在前一章环境中,我为大家介绍了如何用solidity语言编写简单的代币。今天我为大家介绍用solidity语言去实现一种可发行的代币。

在此之前首先得了解想要发行代币,首先得遵循一个标准得协议,叫ERC20协议。

ERC20协议:可以简单地理解为一种代码规范。在以太坊官网 https://eips.ethereum.org/EIPS/eip-20 是这样介绍的:

Abstract(摘要)

The following standard allows for the implementation of a standard API for tokens within smart contracts. This standard provides basic functionality to transfer tokens, as well as allow tokens to be approved so they can be spent by another on-chain third party.

以下标准允许在智能合约中实施代币的标准API。 该标准提供了基本的功能去交易代币,并使代币被(公众)认可,以便它们可以由另一个链上第三方使用。

这个标准,也就是代码规范规定一个将要发行的代币要有以下内容

name 代币的名称。如比特币的名称bitcoin
symbol 代币的符号,通常用三个英文字母表示。如比特币的符号是BTC
decimals 小数点,也就是可交易的最小单位。如比特币是8位小数点0.00000001,意味着最小交易单位是0.00000001
totalSupply 总发行量。比特币的总发行量是2000万,当然我们发行的时候可以自定义代币发行量

balanceOf

这里表示的是对应账号的余额。

transfer()

转给其它账户的函数,最开始发行代币都是掌握在代币管理者账户手中的,在众筹的时候转给投资者。这个函数还被要求触发转账事件。
transferFrom() 一般转账函数,实现了投资者可以互相转账功能。

approve()

授权函数,这个函数授权一个账户去花费代币管理者的余额。再次调用会覆盖当前值。

allowance()

配合approve()使用,返回被授权的余额。
event transfer 交易函数事件。执行transfer()时需要触发该事件。

event approval

授权事件,执行approve()函数时需要触发该事件。

下面我为大家用solidity演示如何来实现ERC20标准代币:

首先我写一个标准的ERC20接口,等待具体的智能合约来实现。打开remix编辑器,新建一个ERC20.sol文件。

​
​

pragma solidity ^0.4.24;

/**
 * @title ERC20标准接口
 * 
 */
contract ERC20 {
  //返回发行总量  
  function totalSupply() public view returns (uint256);

  //返回账户余额
  function balanceOf(address _who) public view returns (uint256);

   //返回授权余额  
  function allowance(address _owner, address _spender)
    public view returns (uint256);

  //代币管理者转账函数
  function transfer(address _to, uint256 _value) public returns (bool);

  //授权函数
  function approve(address _spender, uint256 _value)
    public returns (bool);

  //一般转账函数
  function transferFrom(address _from, address _to, uint256 _value)
    public returns (bool);

  //代币管理者转账事件
  event Transfer(address indexed from,address indexed to,uint256 value);

  //授权事件
  event Approval(address indexed owner,address indexed spender,uint256 value);
}

​

​

下一步是写一个智能合约去实现这个接口,新建一个StandardToken.sol文件。

步骤如下:

一:声明solidity版本 pragma solidity ^0.4.24;

二:导入ERC20接口文件 import './ERC20'

三:让StandardToken继承ERC20并把ERC20定义的接口拷贝到StandardToken.sol,准备实现方法体

四:声明变量:

    string name;//代币名称
    string symbol;//代币符号
    uint256 totalSupply;//总发行量
    uint8 decimals;//代币小数点。
    mapping(address=>uint256) balanceOf;//账户余额
    mapping(address=>mapping(address=>uint256)) allowed;//这个是记录代币管理者授权指定账户的余额,双层map

五:实现ERC20函数体,代码如下

pragma solidity ^0.4.24;

import './ERC20.sol';

contract StandardToken is ERC20{
    string public name;//代币名称
    string public symbol;//代币符号
    uint256 public totalSupply;//总发行量
    uint8 public decimals;//代币小数点。
    mapping(address=>uint256) public balanceof;//账户余额
    mapping(address=>mapping(address=>uint256)) public allowed;//这个是记录代币管理者授权指定账户的余额,双层map
    
    //这个是StandardToken合约构造函数,目的就是给前面变量赋值
constructor(string _name,string _symbol,uint256 _totalSupply,uint8 _decimals) public{
        name=_name;
        symbol=_symbol;
        totalSupply=_totalSupply;
        balanceof[msg.sender]=totalSupply;
        decimals=_decimals;
    }
    
 //这个函数的目的是判断地址是否是合约地址,在以太坊中,合约是内部地址,账户是外部地址 
function isContract(address _address) public view  returns (bool) {
    uint size;
    //这里是获取地址的代码大小,合约地址肯定是大于0的,根据这个特性可以判断合约地址出来
    assembly {size := extcodesize(_address) }
    return size > 0;
  }  
 

//返回发行总量(这里稍微介绍下solidity语法,view关键字表明这个函数动作是只读数据,不写入数据) 
  function totalSupply() public view returns (uint256){
      return totalSupply;
  }

  //返回账户余额
  function balanceOf(address _who) public view returns (uint256){
      return balanceof[_who];
  }

   //返回授权余额  
  function allowance(address _owner, address _spender)
    public view returns (uint256){
        return allowed[_owner][_spender];
    }

  //代币管理者转账函数
  function transfer(address _to, uint256 _value) public returns (bool){
        require(!isContract(_to));//如果是合约地址,转账没有意义,因此不允许转到合约地址。
        require(balanceof[msg.sender]>=_value);//判断代币持有者余额要大于转账余额
        require(balanceof[_to]>=balanceof[_to]+_value);//溢出判断。
        balanceof[msg.sender]-=_value;//对代币持有者余额做减法
        balanceof[_to]+=_value;//目标地址做加法
        emit Transfer(msg.sender,_to,_value);//触发事件
        return true;
  }

  //授权函数
  function approve(address _spender, uint256 _value)
    public returns (bool){
        allowed[msg.sender][_spender]=_value;//记录授权额度
        emit Approval(msg.sender,_spender,_value);//触发事件
        return true;
    }

  //一般转账函数
  function transferFrom(address _from, address _to, uint256 _value)
    public returns (bool){
        //如果是合约地址,转账没有意义,因此不允许转到合约地址。
        require(!isContract(_from)&&!isContract(_to));
        //判断转账人是否有足够余额
        require(balanceof[_from]>=_value);
        //整数溢出判断
        require(balanceof[_to]>=balanceof[_to]+_value);
        balanceof[_from]-=_value;
        balanceof[_to]+=_value;
        return true;
    }
        

  //代币管理者转账事件
  event Transfer(address indexed from,address indexed to,uint256 value);

  //授权事件
  event Approval(address indexed owner,address indexed spender,uint256 value);
}

下面是部署JavaScript VM 部署细节:

ERC20代币就介绍到这里,下一章为大家介绍如何部署到以太坊测试网络中进行测试。如有不足之处欢迎指正 。

猜你喜欢

转载自blog.csdn.net/qq_42247900/article/details/81951296
今日推荐