EOS学习实战(三)教你如何发币!

学习区块链,最刺激的莫过于发币,第一篇文章里介绍了如何搭建EOS开发环境,第二篇文章我们已经介绍了如何部署调用合约,实际上隐含着对钱包和账号的操作!

这一篇我们重点介绍智能合约如何发币!既如何用(yekai)给(dinglinlin)发币。提示:本篇篇幅较长请耐新阅读。

另,为方便大家交流,需要EOS实战系列代码的小伙伴可以加QQ2082049536索要,希望跟大家一同进步。

使用eosio.token发币

我们先将eos官方给提供的eosio.token代码拷贝到开发目录。

yekaideMacBook-Pro:contracts yk$ cp -r ~/eoshome/eos/contracts/eosio.token/ eosio.token

yekaideMacBook-Pro:contracts yk$ ls

bak                eosio.token     

database          jing              tic_tac_toe

debug              moment 

yekaideMacBook-Pro:contracts yk$ cd eosio.token/

yekaideMacBook-Pro:eosio.token yk$ ls

CMakeLists.txt  eosio.token.abi eosio.token.cpp eosio.token.hpp

同样得到abi文件,hpp文件,cpp文件,缺少wast文件,通过eosiocpp可以生成!

yekaideMacBook-Pro:eosio.token yk$ eosiocpp -o eosio.token.wast eosio.token.cpp eosio.token.cpp:6:10: fatal error: 'eosio.token/eosio.token.hpp' file not found#include ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1 error generated.

上述有一个错误,我们需要修改cpp包含头文件的路径,在本目录下编译路径有点问题。 修改为 "eosio.token.hpp"。

/**

*  @file

*  @copyright defined in eos/LICENSE.txt

*/

#include "eosio.token.hpp"

namespace eosio {

void token::create( account_name issuer,

                    asset        maximum_supply,

                    uint8_t      issuer_can_freeze,

                    uint8_t      issuer_can_recall,

                    uint8_t      issuer_can_whitelist )

{

    require_auth( _self );

    auto sym = maximum_supply.symbol;

    eosio_assert( sym.is_valid(), "invalid symbol name" );

    eosio_assert( maximum_supply.is_valid(), "invalid supply");

    eosio_assert( maximum_supply.amount > 0, "max-supply must be positive");

    stats statstable( _self, sym.name() );

    auto existing = statstable.find( sym.name() );

    eosio_assert( existing == statstable.end(), "token with symbol already exists" );

    statstable.emplace( _self, [&]( auto& s ) {

      s.supply.symbol = maximum_supply.symbol;

      s.max_supply    = maximum_supply;

      s.issuer        = issuer;

      s.can_freeze    = issuer_can_freeze;

      s.can_recall    = issuer_can_recall;

      s.can_whitelist = issuer_can_whitelist;

    });

}

void token::issue( account_name to, asset quantity, string memo )

{

    print( "issue" );

    auto sym = quantity.symbol.name();

    stats statstable( _self, sym );

    const auto& st = statstable.get( sym );

    require_auth( st.issuer );

    eosio_assert( quantity.is_valid(), "invalid quantity" );

    eosio_assert( quantity.amount > 0, "must issue positive quantity" );

    eosio_assert( quantity <= st.max_supply - st.supply, "quantity exceeds available supply");

    statstable.modify( st, 0, [&]( auto& s ) {

      s.supply += quantity;

    });

    add_balance( st.issuer, quantity, st, st.issuer );

    if( to != st.issuer )

    {

      SEND_INLINE_ACTION( *this, transfer, {st.issuer,N(active)}, {st.issuer, to, quantity, memo} );

    }

}

void token::transfer( account_name from,

                      account_name to,

                      asset        quantity,

                      string      /*memo*/ )

{

    print( "transfer" );

    require_auth( from );

    auto sym = quantity.symbol.name();

    stats statstable( _self, sym );

    const auto& st = statstable.get( sym );

    require_recipient( from );

    require_recipient( to );

    eosio_assert( quantity.is_valid(), "invalid quantity" );

    eosio_assert( quantity.amount > 0, "must transfer positive quantity" );

    sub_balance( from, quantity, st );

    add_balance( to, quantity, st, from );

}

void token::sub_balance( account_name owner, asset value, const currency_stats& st ) {

  accounts from_acnts( _self, owner );

  const auto& from = from_acnts.get( value.symbol.name() );

  eosio_assert( from.balance.amount >= value.amount, "overdrawn balance" );

  if( has_auth( owner ) ) {

      eosio_assert( !st.can_freeze || !from.frozen, "account is frozen by issuer" );

      eosio_assert( !st.can_freeze || !st.is_frozen, "all transfers are frozen by issuer" );

      eosio_assert( !st.enforce_whitelist || from.whitelist, "account is not white listed" );

  } else if( has_auth( st.issuer ) ) {

      eosio_assert( st.can_recall, "issuer may not recall token" );

  } else {

      eosio_assert( false, "insufficient authority" );

  }

  from_acnts.modify( from, owner, [&]( auto& a ) {

      a.balance -= value;

  });

}

void token::add_balance( account_name owner, asset value, const currency_stats& st, account_name ram_payer )

{

  accounts to_acnts( _self, owner );

  auto to = to_acnts.find( value.symbol.name() );

  if( to == to_acnts.end() ) {

      eosio_assert( !st.enforce_whitelist, "can only transfer to white listed accounts" );

      to_acnts.emplace( ram_payer, [&]( auto& a ){

        a.balance = value;

      });

  } else {

      eosio_assert( !st.enforce_whitelist || to->whitelist, "receiver requires whitelist by issuer" );

      to_acnts.modify( to, 0, [&]( auto& a ) {

        a.balance += value;

      });

  }

}

} /// namespace eosio

EOSIO_ABI( eosio::token, (create)(issue)(transfer) )

yekaideMacBook-Pro:eosio.token yk$

再次执行编译生成wast文件

yekaideMacBook-Pro:eosio.token yk$ eosiocpp -o eosio.token.wast eosio.token.cpp

终于可以发币了

有可能看到如图所示,这是由于nodes重启后,钱包需要解锁,此时上篇提到的钱包密码在此处就将有用武之地了!

yekaideMacBook-Pro:eosio.token yk$ cleos wallet unlock

输入钱包密码就会解锁成功了!再次发布合约!

yekaideMacBook-Pro:eosio.token yk$ cleos set contract yekai ../eosio.token/

Reading WAST/WASM from ../eosio.token/eosio.token.wast...

Assembling WASM...

Publishing contract...

executed transaction: 0cfdf14e4d5d7351b31ba88a029b9c96693fdaf9d9f7738738356cb01ad48dff  8320 bytes  2200576 cycles

#        eosio <= eosio::setcode              {"account":"yekai","vmtype":0,"vmversion":0,"code":"0061736d010000000181011560067f7e7f7f7f7f0060057f...

#        eosio <= eosio::setabi                {"account":"yekai","abi":{"types":[],"structs":[{"name":"transfer","base":"","fields":[{"name":"from...

看到上述结果代表成了!激动人心的时刻也开始了!

马上发币,手里有币,心里不慌

计划发布一个叶开币,持币的可以找我换飞刀!需要指定发行者issuer,指定最大发行量以及币符号(YKC),还有三个参数can_freeze,can_recall,can_whitelist分别代表是否可以冻结,是否可以回收,是否使用白名单。

yekaideMacBook-Pro:eosio.token yk$ cleos push action yekai create '{"issuer":"yekai", "maximum_supply": "1000000000.0000 YKC", "can_freeze": 1, "can_recall": 1, "can_whitelist": 1}' -p yekai@active

executed transaction: 60aba3068a0e3afebd81d23c3a5b954321eb1d29926a46199c7168590f3cf1fa  248 bytes  104448 cycles

#        yekai <= yekai::create                {"issuer":"yekai","maximum_supply":"1000000000.0000 YKC","can_freeze":1,"can_recall":1,"can_whitelis...

这样执行成功,我们就可以发币了

yekaideMacBook-Pro:eosio.token yk$ cleos push action yekai issue '{"to":"yekai","quantity":"1000.0000 YKC","memo":"issue first"}' -p yekai@active

executed transaction: fd0079f68e354e70a2c6af53d091531064681a256fbe807292bb11b20dcc408d  264 bytes  109568 cycles

#        yekai <= yekai::issue                {"to":"yekai","quantity":"1000.0000 YKC","memo":"issue first"}

>> issue

可以查看yekai当前的余额,两个yekai一个代表合约,一个代表范围,accounts代表表名,accounts在哪定义的?

yekaideMacBook-Pro:eosio.token yk$ cleos get table yekai yekai accounts

{

  "rows": [{

      "balance": "1000.0000 YKC",

      "frozen": 0,

      "whitelist": 1

    }

  ],

  "more": false

}

转账给dinglinlin,先创建一个账户dinglinlin

yekaideMacBook-Pro:eosio.token yk$ cleos create key

Private key: 5JibbdFPc4f5ZX9Qq8sWpX8yACNwAzex5ogHWxtTGVSYeUkvWJq

Public key: EOS5vn5Jj5oU1zP7rKDwbXsEjLbQnT8yvLF1PcyCEFKzoAX3xVz2J

yekaideMacBook-Pro:eosio.token yk$ cleos create account eosio dinglinlin EOS5vn5Jj5oU1zP7rKDwbXsEjLbQnT8yvLF1PcyCEFKzoAX3xVz2J EOS5vn5Jj5oU1zP7rKDwbXsEjLbQnT8yvLF1PcyCEFKzoAX3xVz2J

executed transaction: d710f137d34568981eb0bd65fbf4e7306cc813e47b067d06138af9eea15b352a  352 bytes  102400 cycles

#        eosio <= eosio::newaccount            {"creator":"eosio","name":"dinglinlin","owner":{"threshold":1,"keys":[{"key":"EOS5vn5Jj5oU1zP7rKDwbX...

yekaideMacBook-Pro:eosio.token yk$

yekaideMacBook-Pro:eosio.token yk$ cleos wallet import 5JibbdFPc4f5ZX9Qq8sWpX8yACNwAzex5ogHWxtTGVSYeUkvWJq

imported private key for: EOS5vn5Jj5oU1zP7rKDwbXsEjLbQnT8yvLF1PcyCEFKzoAX3xVz2J

转账给dinglinlin

yekaideMacBook-Pro:eosio.token yk$ cleos push action yekai transfer '{"from":"yekai","to":"dinglinlin","quantity":"20.0000 YKC","memo":"my first transfer"}' -p yekai@active

executed transaction: ae530eaab3c7b2dbecb73df0dc7d74c5861ff1d0cc50655f2f31d46004e4187d  272 bytes  112640 cycles

#        yekai <= yekai::transfer              {"from":"yekai","to":"dinglinlin","quantity":"20.0000 YKC","memo":"my first transfer"}

>> transfer

#    dinglinlin <= yekai::transfer              {"from":"yekai","to":"dinglinlin","quantity":"20.0000 YKC","memo":"my first transfer"}

再次查看余额,叶开和丁琳琳金额发生了变化!

yekaideMacBook-Pro:eosio.token yk$ cleos get table yekai dinglinlin accounts

{

  "rows": [{

      "balance": "20.0000 YKC",

      "frozen": 0,

      "whitelist": 1

    }

  ],

  "more": false

}

yekaideMacBook-Pro:eosio.token yk$ cleos get table yekai yekai accounts

{

  "rows": [{

      "balance": "980.0000 YKC",

      "frozen": 0,

      "whitelist": 1

    }

  ],

  "more": false

}

abi文件三要素

发币已然成功,然而少了点什么,我们再回过来介绍abi文件的内容。abi文件有三要素,当然不是阳光、空气和水!abi文件的三要素是struct,action,table。

yekaideMacBook-Pro:eosio.token yk$ cat eosio.token.abi

{

  "types": [],

  "structs": [{

      "name": "transfer",

      "base": "",

      "fields": [

        {"name":"from", "type":"account_name"},

        {"name":"to", "type":"account_name"},

        {"name":"quantity", "type":"asset"},

        {"name":"memo", "type":"string"}

      ]

    },{

    "name": "create",

    "base": "",

    "fields": [

        {"name":"issuer", "type":"account_name"},

        {"name":"maximum_supply", "type":"asset"},

        {"name":"can_freeze", "type":"uint8"},

        {"name":"can_recall", "type":"uint8"},

        {"name":"can_whitelist", "type":"uint8"}

    ]

  },{

    "name": "issue",

    "base": "",

    "fields": [

        {"name":"to", "type":"account_name"},

        {"name":"quantity", "type":"asset"},

        {"name":"memo", "type":"string"}

    ]

  },{

      "name": "account",

      "base": "",

      "fields": [

        {"name":"balance", "type":"asset"},

        {"name":"frozen", "type":"uint8"},

        {"name":"whitelist", "type":"uint8"}

      ]

    },{

      "name": "currency_stats",

      "base": "",

      "fields": [

        {"name":"supply", "type":"asset"},

        {"name":"max_supply", "type":"asset"},

        {"name":"issuer", "type":"account_name"},

        {"name":"can_freeze", "type":"uint8"},

        {"name":"can_recall", "type":"uint8"},

        {"name":"can_whitelist", "type":"uint8"},

        {"name":"is_frozen", "type":"uint8"},

        {"name":"enforce_whitelist", "type":"uint8"}

      ]

    }

  ],

  "actions": [{

      "name": "transfer",

      "type": "transfer",

      "ricardian_contract": ""

    },{

      "name": "issue",

      "type": "issue",

      "ricardian_contract": ""

    }, {

      "name": "create",

      "type": "create",

      "ricardian_contract": ""

    }

  ],

  "tables": [{

      "name": "accounts",

      "type": "account",

      "index_type": "i64",

      "key_names" : ["currency"],

      "key_types" : ["uint64"]

    },{

      "name": "stat",

      "type": "currency_stats",

      "index_type": "i64",

      "key_names" : ["currency"],

      "key_types" : ["uint64"]

    }

  ],

  "ricardian_clauses": []

}

struct 结构

struct不会碰到太多问题,就是我们定义的结构体

action 动作

action是abi文件的灵魂,eos是以action驱动,当然锝得得action。

table

table其实是非必须的,比如hello的例子中就没有table,table做什么用呢?既然是table,就可以当成数据库的table,那么什么用处也就清晰了!本例使用table存储每个用户的持币余额!说到这里,也就能理解之前的操作为什么用accounts这个表了!

修改示例代码重新得到abi

很遗憾的是官方给的示例代码是无法通过eosiocpp生成官方版的abi文件的,咱们做一下跳坑练习!

yekaideMacBook-Pro:eosio.token yk$ eosiocpp -g eosio.token.abi eosio.token.cpp

yekaideMacBook-Pro:eosio.token yk$ cat eosio.token.abi

{

  "____comment": "This file was generated by eosio-abigen. DO NOT EDIT - 2018-05-11T06:32:03",

  "types": [],

  "structs": [],

  "actions": [],

  "tables": [],

  "ricardian_clauses": []

}

很郁闷的发现abi的文件空空如也,整个人都不好了!接下来就看动手能力了,我们先将hpp和cpp源码改造一下,将namespace的使用方式去掉,经过证明,我们需要使用全局空间,不能再次定义eosio这个命名空间!

代码改造如下(第一次修改)

eosio.token.hpp

/**

* @file

* @copyright defined in eos/LICENSE.txt

*/

#pragma once

#include#include#includenamespace eosiosystem { class system_contract;}using namespace eosio ; using std::string; class token : public contract { public: token( account_name self ):contract(self){} /// @abi action void create( account_name issuer, asset maximum_supply, uint8_t issuer_can_freeze, uint8_t issuer_can_recall, uint8_t issuer_can_whitelist ); void issue( account_name to, asset quantity, string memo ); void transfer( account_name from, account_name to, asset quantity, string memo ); private: friend eosiosystem::system_contract; inline asset get_supply( symbol_name sym )const; inline asset get_balance( account_name owner, symbol_name sym )const; private: struct account { asset balance; bool frozen = false; bool whitelist = true; uint64_t primary_key()const { return balance.symbol.name(); } }; struct currency_stats { asset supply; asset max_supply; account_name issuer; bool can_freeze = true; bool can_recall = true; bool can_whitelist = true; bool is_frozen = false; bool enforce_whitelist = false; uint64_t primary_key()const { return supply.symbol.name(); } }; typedef eosio::multi_indexaccounts; typedef eosio::multi_index stats;

        void sub_balance( account_name owner, asset value, const currency_stats& st );

        void add_balance( account_name owner, asset value, const currency_stats& st,

                          account_name ram_payer );

      public:

        struct transfer_args {

            account_name  from;

            account_name  to;

            asset        quantity;

            string        memo;

        };

  };

  asset token::get_supply( symbol_name sym )const

  {

      stats statstable( _self, sym );

      const auto& st = statstable.get( sym );

      return st.supply;

  }

  asset token::get_balance( account_name owner, symbol_name sym )const

  {

      accounts accountstable( _self, owner );

      const auto& ac = accountstable.get( sym );

      return ac.balance;

  }

eosio.token.cpp

/**

*  @file

*  @copyright defined in eos/LICENSE.txt

*/

#include "eosio.token.hpp"

void token::create( account_name issuer,

                    asset        maximum_supply,

                    uint8_t      issuer_can_freeze,

                    uint8_t      issuer_can_recall,

                    uint8_t      issuer_can_whitelist )

{

    require_auth( _self );

    auto sym = maximum_supply.symbol;

    eosio_assert( sym.is_valid(), "invalid symbol name" );

    eosio_assert( maximum_supply.is_valid(), "invalid supply");

    eosio_assert( maximum_supply.amount > 0, "max-supply must be positive");

    stats statstable( _self, sym.name() );

    auto existing = statstable.find( sym.name() );

    eosio_assert( existing == statstable.end(), "token with symbol already exists" );

    statstable.emplace( _self, [&]( auto& s ) {

      s.supply.symbol = maximum_supply.symbol;

      s.max_supply    = maximum_supply;

      s.issuer        = issuer;

      s.can_freeze    = issuer_can_freeze;

      s.can_recall    = issuer_can_recall;

      s.can_whitelist = issuer_can_whitelist;

    });

}

void token::issue( account_name to, asset quantity, string memo )

{

    print( "issue" );

    auto sym = quantity.symbol.name();

    stats statstable( _self, sym );

    const auto& st = statstable.get( sym );

    require_auth( st.issuer );

    eosio_assert( quantity.is_valid(), "invalid quantity" );

    eosio_assert( quantity.amount > 0, "must issue positive quantity" );

    eosio_assert( quantity <= st.max_supply - st.supply, "quantity exceeds available supply");

    statstable.modify( st, 0, [&]( auto& s ) {

      s.supply += quantity;

    });

    add_balance( st.issuer, quantity, st, st.issuer );

    if( to != st.issuer )

    {

      SEND_INLINE_ACTION( *this, transfer, {st.issuer,N(active)}, {st.issuer, to, quantity, memo} );

    }

}

void token::transfer( account_name from,

                      account_name to,

                      asset        quantity,

                      string      /*memo*/ )

{

    print( "transfer" );

    require_auth( from );

    auto sym = quantity.symbol.name();

    stats statstable( _self, sym );

    const auto& st = statstable.get( sym );

    require_recipient( from );

    require_recipient( to );

    eosio_assert( quantity.is_valid(), "invalid quantity" );

    eosio_assert( quantity.amount > 0, "must transfer positive quantity" );

    sub_balance( from, quantity, st );

    add_balance( to, quantity, st, from );

}

void token::sub_balance( account_name owner, asset value, const currency_stats& st ) {

  accounts from_acnts( _self, owner );

  const auto& from = from_acnts.get( value.symbol.name() );

  eosio_assert( from.balance.amount >= value.amount, "overdrawn balance" );

  if( has_auth( owner ) ) {

      eosio_assert( !st.can_freeze || !from.frozen, "account is frozen by issuer" );

      eosio_assert( !st.can_freeze || !st.is_frozen, "all transfers are frozen by issuer" );

      eosio_assert( !st.enforce_whitelist || from.whitelist, "account is not white listed" );

  } else if( has_auth( st.issuer ) ) {

      eosio_assert( st.can_recall, "issuer may not recall token" );

  } else {

      eosio_assert( false, "insufficient authority" );

  }

  from_acnts.modify( from, owner, [&]( auto& a ) {

      a.balance -= value;

  });

}

void token::add_balance( account_name owner, asset value, const currency_stats& st, account_name ram_payer )

{

  accounts to_acnts( _self, owner );

  auto to = to_acnts.find( value.symbol.name() );

  if( to == to_acnts.end() ) {

      eosio_assert( !st.enforce_whitelist, "can only transfer to white listed accounts" );

      to_acnts.emplace( ram_payer, [&]( auto& a ){

        a.balance = value;

      });

  } else {

      eosio_assert( !st.enforce_whitelist || to->whitelist, "receiver requires whitelist by issuer" );

      to_acnts.modify( to, 0, [&]( auto& a ) {

        a.balance += value;

      });

  }

}

EOSIO_ABI( token, (create)(issue)(transfer) )

这次abi文件有变化了,但是好像还缺少点什么!

{

  "____comment": "This file was generated by eosio-abigen. DO NOT EDIT - 2018-05-11T06:41:35",

  "types": [],

  "structs": [{

      "name": "create",

      "base": "",

      "fields": [{

          "name": "issuer",

          "type": "account_name"

        },{

          "name": "maximum_supply",

          "type": "asset"

        },{

          "name": "issuer_can_freeze",

          "type": "uint8"

        },{

          "name": "issuer_can_recall",

          "type": "uint8"

        },{

          "name": "issuer_can_whitelist",

          "type": "uint8"

        }

      ]

    },{

      "name": "issue",

      "base": "",

      "fields": [{

          "name": "to",

          "type": "account_name"

        },{

          "name": "quantity",

          "type": "asset"

        },{

          "name": "memo",

          "type": "string"

        }

      ]

    },{

      "name": "transfer",

      "base": "",

      "fields": [{

          "name": "from",

          "type": "account_name"

        },{

          "name": "to",

          "type": "account_name"

        },{

          "name": "quantity",

          "type": "asset"

        },{

          "name": "memo",

          "type": "string"

        }

      ]

    }

  ],

  "actions": [{

      "name": "create",

      "type": "create",

      "ricardian_contract": ""

    },{

      "name": "issue",

      "type": "issue",

      "ricardian_contract": ""

    },{

      "name": "transfer",

      "type": "transfer",

      "ricardian_contract": ""

    }

  ],

  "tables": [],

  "ricardian_clauses": []

}

上面看似abi文件没有问题了,但实际上tables部分,也就是abi的三要素少了一个tables,这样数据是存储不下来的,发币会有问题!

关键点,添加注释

再次编译,结果更多的错误!不要慌!

abi_generation_exception: Unable to generate abi

false: types can only be: vector, struct, class or a built-in type. (bool)

    {"type":"bool"}

    thread-0  abi_generator.cpp:606 add_type

    {}

    thread-0  abi_generator.cpp:290 handle_decl

在eos的智能合约里,导出的table数据中不可以有bool类型,其实提示的已经较为明显了,另外就是加那行注释是有实际作用的,eosiocpp会做正则匹配,然后才会导出table信息到abi。

/**

*  @file

*  @copyright defined in eos/LICENSE.txt

*/

#pragma once

#include

#include

#include

namespace eosiosystem {

  class system_contract;

}

using namespace eosio ;

  using std::string;

  class token : public contract {

      public:

        token( account_name self ):contract(self){}

        /// @abi action

        void create( account_name issuer,

                      asset        maximum_supply,

                      uint8_t      issuer_can_freeze,

                      uint8_t      issuer_can_recall,

                      uint8_t      issuer_can_whitelist );

        void issue( account_name to, asset quantity, string memo );

        void transfer( account_name from,

                        account_name to,

                        asset        quantity,

                        string      memo );

      private:

        friend eosiosystem::system_contract;

        inline asset get_supply( symbol_name sym )const;


        inline asset get_balance( account_name owner, symbol_name sym )const;

      private:

        /// @abi table accounts i64

        struct account {

            asset    balance;

            uint8_t frozen    = 0;

            uint8_t    whitelist = 1;

            uint64_t primary_key()const { return balance.symbol.name(); }

        };

        /// @abi table stats i64

        struct stat {

            asset          supply;

            asset          max_supply;

            account_name  issuer;

            uint8_t          can_freeze        = 1;

            uint8_t          can_recall        = 1;

            uint8_t          can_whitelist      = 1;

            uint8_t          is_frozen          = 0;

            uint8_t          enforce_whitelist  = 0;

            uint64_t primary_key()const { return supply.symbol.name(); }

        };

        typedef eosio::multi_index accounts;

        typedef eosio::multi_index stats;

        void sub_balance( account_name owner, asset value, const stat& st );

        void add_balance( account_name owner, asset value, const stat& st,

                          account_name ram_payer );

      public:

        struct transfer_args {

            account_name  from;

            account_name  to;

            asset        quantity;

            string        memo;

        };

  };

  asset token::get_supply( symbol_name sym )const

  {

      stats statstable( _self, sym );

      const auto& st = statstable.get( sym );

      return st.supply;

  }

  asset token::get_balance( account_name owner, symbol_name sym )const

  {

      accounts accountstable( _self, owner );

      const auto& ac = accountstable.get( sym );

      return ac.balance;

  }

注意一下修改变化,account和stat结构体前都加了注释,另外导出时对table的name长度有限制,所以去掉了currency_和后面的s,当然相应的函数调用部分都要调整。 别忘了同步修改cpp文件对应的函数接口部分,这样基本可以大公告成了!

再次发币

先部署合约

cleos set contract yekai ../eosio.token

给linlin妹子再来点币

yk$ cleos push action yekai transfer '{"from":"yekai","to":"dinglinlin","quantity":"66.0000 YKC","memo":"my sencond transfer"}' -p yekai@active

executed transaction: 08f6f04ee43e51423e84379080e1788461fc6b36bdbbf58c3a1fe518e2140e90  280 bytes  112640 cycles

#        yekai <= yekai::transfer              {"from":"yekai","to":"dinglinlin","quantity":"66.0000 YKC","memo":"my sencond transfer"}

>> transfer

#    dinglinlin <= yekai::transfer              {"from":"yekai","to":"dinglinlin","quantity":"66.0000 YKC","memo":"my sencond transfer"}

再次分别查看余额

yekaideMacBook-Pro:eosio.token yk$ cleos get table yekai yekai accounts

{

  "rows": [{

      "balance": "914.0000 YKC",

      "frozen": 0,

      "whitelist": 1

    }

  ],

  "more": false

}

yekaideMacBook-Pro:eosio.token yk$ cleos get table yekai dinglinlin accounts

{

  "rows": [{

      "balance": "86.0000 YKC",

      "frozen": 0,

      "whitelist": 1

    }

  ],

  "more": false

}

总结

本篇主要介绍如何发币,如何编译智能合约代码,以及智能合约编写时碰到的问题,把遇到的坑总结如下:

/// @abi 有特殊作用

类型必须使用内建类型,或者结构体,类,vector等

table结构体长度是有限制的,不能太长,这也需要注意

table指定主键有时也需要自己指定,例如:/// @abi table tablename i64


推荐阅读更多精彩内容