美文网首页
Solidity代币:IOC 、Token、ERC20

Solidity代币:IOC 、Token、ERC20

作者: 黄靠谱 | 来源:发表于2019-01-16 17:59 被阅读8次

    概述

    1. ERC20是一个标准,规范所有的代币,按照相同的接口开发业务,初始发行总量、符号、名称、支持几位小数点、转账、预算授权等功能
    2. Token也就是虚拟代币的名称,需要手写一个Token的合约,该合约必须满足ERC20规范,token是在以太坊平台上的运行的虚拟货币,不同于以太币。以太币除了也具有交易的功能,还肩负着支付gas的功能
    3. IOC就是通过筹集以太币来获取初始化的 token的一个过程,需要编写一个Crowdsale 合约来执行IOC的首次募集以太币

    IOC过程:用户在众筹期间,往指定的众筹合约账户转账以太币,从而获得token,众筹成功后,用户可以使用自己的token。众筹失败的话,用户可以取回自己的转账款

    核心代码:众筹合约(IOC合约)、代币Token的管理合约

    标准的一套合约(IOC合约和Token合约

    • Crowdsale继承token合约,在Crowdsale初始化的时候,填充两个合约的初始化变量
    • Crowdsale合约里面有一个匿名函数,所有在募集期的转账都会触发,该函数会同时在IOC合约 balance记录转账金额 和Token合约的 balanceOf 记录获取的代币数量
    • 众筹成功后,Crowdsale的owner可以提取募集到的IOC的以太币,同时Token合约正式上线,用户可以自由的交易自己手上的token了
    pragma solidity 0.4.20;
    
     contract token {
    
         string public standard = 'yuyangray';
         string public name; //代币名称
         string public symbol; //代币符号比如'$'
         uint8 public decimals = 2;  
    
         uint256 public totalSupply; //代币总量
         mapping (address => uint256) public balanceOf;
    
         event Transfer(address indexed from, address indexed to, uint256 value);  //转帐通知事件
    
    
         /* 初始化合约,并且把初始的所有代币都给这合约的创建者
          * @param _owned 合约的管理者
          * @param tokenName 代币名称
          * @param tokenSymbol 代币符号
          */
         function token(address _owned, string tokenName, string tokenSymbol) public {
             //合约的管理者获得的代币总量
             balanceOf[_owned] = totalSupply;
    
             name = tokenName;
             symbol = tokenSymbol;
    
         }
    
         /**
          * 转帐,具体可以根据自己的需求来实现
          * @param  _to address 接受代币的地址
          * @param  _value uint256 接受代币的数量
          */
         function transfer(address _to, uint256 _value) public {
           //从发送者减掉发送额
           balanceOf[msg.sender] -= _value;
    
           //给接收者加上相同的量
           balanceOf[_to] += _value;
    
           //通知任何监听该交易的客户端
           Transfer(msg.sender, _to, _value);
         }
    
         /**
          * 增加代币,并将代币发送给捐赠新用户
          * @param  _to address 接受代币的地址
          * @param  _amount uint256 接受代币的数量
          */
         function issue(address _to, uint256 _amount) public {
             totalSupply = totalSupply + _amount;
             balanceOf[_to] += _amount;
    
             //通知任何监听该交易的客户端
             Transfer(this, _to, _amount);
         }
      }
    
    /**
     * 众筹合约
     */
    contract Crowdsale is token {
        address public beneficiary = msg.sender; //受益人地址,测试时为合约创建者
        uint public fundingGoal;  //众筹目标,单位是ether
        uint public amountRaised; //已筹集金额数量, 单位是ether
        uint public deadline; //截止时间
        uint public price;  //代币价格
        bool public fundingGoalReached = false;  //达成众筹目标
        bool public crowdsaleClosed = false; //众筹关闭
    
    
        mapping(address => uint256) public balance; //保存众筹地址及对应的以太币数量
    
        // 受益人将众筹金额转走的通知
        event GoalReached(address _beneficiary, uint _amountRaised);
    
        // 用来记录众筹资金变动的通知,_isContribution表示是否是捐赠,因为有可能是捐赠者退出或发起者转移众筹资金
        event FundTransfer(address _backer, uint _amount, bool _isContribution);
    
        /**
         * 初始化构造函数
         *
         * @param fundingGoalInEthers 众筹以太币总量
         * @param durationInMinutes 众筹截止,单位是分钟
         * @param tokenName 代币名称
         * @param tokenSymbol 代币符号
         */
        function Crowdsale(
            uint fundingGoalInEthers,
            uint durationInMinutes,
            string tokenName,
            string tokenSymbol
        ) token(this, tokenName, tokenSymbol) public {
            fundingGoal = fundingGoalInEthers * 1 ether;
            deadline = now + durationInMinutes * 1 minutes;
            price = 500 finney; //1个以太币可以买 2 个代币
        }
    
    
        /**
         * 默认函数
         *
         * 默认函数,可以向合约直接打款
         */
        function () payable public {
    
            //判断是否关闭众筹
            require(!crowdsaleClosed);
            uint amount = msg.value;
    
            //捐款人的金额累加
            balance[msg.sender] += amount;
    
            //捐款总额累加
            amountRaised += amount;
    
            //转帐操作,转多少代币给捐款人
            issue(msg.sender, amount / price * 10 ** uint256(decimals));
            FundTransfer(msg.sender, amount, true);
        }
    
        /**
         * 判断是否已经过了众筹截止限期
         */
        modifier afterDeadline() { if (now >= deadline) _; }
    
        /**
         * 检测众筹目标是否已经达到
         */
        function checkGoalReached() afterDeadline public {
            if (amountRaised >= fundingGoal){
                //达成众筹目标
                fundingGoalReached = true;
                GoalReached(beneficiary, amountRaised);
            }
    
            //关闭众筹
            crowdsaleClosed = true;
        }
    
    
        /**
         * 收回资金
         *
         * 检查是否达到了目标或时间限制,如果有,并且达到了资金目标,
         * 将全部金额发送给受益人。如果没有达到目标,每个贡献者都可以退出
         * 他们贡献的金额
         * 注:这里代码应该是限制了众筹时间结束且众筹目标没有达成的情况下才允许退出。如果去掉限制条件afterDeadline,应该是可以允许众筹时间还未到且众筹目标没有达成的情况下退出
         */
        function safeWithdrawal() afterDeadline public {
    
            //如果没有达成众筹目标
            if (!fundingGoalReached) {
                //获取合约调用者已捐款余额
                uint amount = balance[msg.sender];
    
                if (amount > 0) {
                    //返回合约发起者所有余额
                    msg.sender.transfer(amount);
                    FundTransfer(msg.sender, amount, false);
                    balance[msg.sender] = 0;
                }
            }
    
            //如果达成众筹目标,并且合约调用者是受益人
            if (fundingGoalReached && beneficiary == msg.sender) {
    
                //将所有捐款从合约中给受益人
                beneficiary.transfer(amountRaised);
    
                FundTransfer(beneficiary, amount, false);
            }
        }
    }
    
    

    Token合约的简单Demo

    继承了EIP20Interface.sol合约,获得了转账和授权的事件代码

    pragma solidity ^0.4.21;
    
    import "./EIP20Interface.sol";
    
    
    contract EIP20 is EIP20Interface {
    
        uint256 constant private MAX_UINT256 = 2**256 - 1;
    
        //记录每个账户的代币余额,创建人的账户初始值为 _initialAmount
        mapping (address => uint256) public balances;
        //账户授权保存
        mapping (address => mapping (address => uint256)) public allowed;
        string public name;                   //fancy name: eg Simon Bucks
        uint8 public decimals;                //How many decimals to show.
        string public symbol;                 //An identifier: eg SBX
    
        function EIP20(
            uint256 _initialAmount,
            string _tokenName,
            uint8 _decimalUnits,
            string _tokenSymbol
        ) public {
            balances[msg.sender] = _initialAmount;               // Give the creator all initial tokens
            totalSupply = _initialAmount;                        // Update total supply
            name = _tokenName;                                   // Set the name for display purposes
            decimals = _decimalUnits;                            // Amount of decimals for display purposes
            symbol = _tokenSymbol;                               // Set the symbol for display purposes
        }
    
        function transfer(address _to, uint256 _value) public returns (bool success) {
            require(balances[msg.sender] >= _value);
            balances[msg.sender] -= _value;
            balances[_to] += _value;
            emit Transfer(msg.sender, _to, _value); //solhint-disable-line indent, no-unused-vars
            return true;
        }
    
        function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
            uint256 allowance = allowed[_from][msg.sender];
            require(balances[_from] >= _value && allowance >= _value);
            balances[_to] += _value;
            balances[_from] -= _value;
            if (allowance < MAX_UINT256) {
                allowed[_from][msg.sender] -= _value;
            }
            emit Transfer(_from, _to, _value); //solhint-disable-line indent, no-unused-vars
            return true;
        }
    
        function balanceOf(address _owner) public view returns (uint256 balance) {
            return balances[_owner];
        }
    
        function approve(address _spender, uint256 _value) public returns (bool success) {
            allowed[msg.sender][_spender] = _value;
            emit Approval(msg.sender, _spender, _value); //solhint-disable-line indent, no-unused-vars
            return true;
        }
    
        function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
            return allowed[_owner][_spender];
        }
    }
    

    参考

    一套完整的IOC合约演示
    https://www.jianshu.com/p/84cf2f12daed

    ERC20官方文档
    https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md

    一个标准的符合ERC20规范的代币合约 Demo
    https://github.com/ConsenSys/Tokens/blob/fdf687c69d998266a95f15216b1955a4965a0a6d/contracts/eip20/EIP20.sol

    查看目前所有的代币的最新情况(报价、代码)
    https://etherscan.io/tokens

    市值最高的代币(BNB) 价值分析,市值大约7.7亿$
    http://www.sohu.com/a/216907154_99957669

    BNB的合约源码
    https://etherscan.io/address/0xB8c77482e45F1F44dE1745F52C74426C631bDD52#code

    相关文章

      网友评论

          本文标题:Solidity代币:IOC 、Token、ERC20

          本文链接:https://www.haomeiwen.com/subject/zmtvdqtx.html