学习区块链,最刺激的莫过于发币,第一篇文章里介绍了如何搭建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