一、EOS token合约
此合约允许创建许多不同的token,这些token全部在同一合同上运行,但可能由不同的用户管理。
1.1 创建账户
$ cleos create account eosio eosio.token
1.2 部署合约
$ cleos set contract eosio.token build/contracts/eosio.token -p eosio.token@active
Reading WAST...
Assembling WASM...
Publishing contract...
executed transaction: 52
1.3 创建token
(1)创建过程
/**
*共有函数,即为action
*/
void token::create( account_name issuer,
asset maximum_supply )
{
//首先经过认证授权 cleos push action 须有-p参数
require_auth( _self );
//sym:最大资产的token,symbol represents a token and contains precision and name: "4,EOS"
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 in eosio.token.hpp:typedef eosio::multi_index<N(stat), currency_stats> stats;
*建立一个 stats 类型的数据表,用来与数据库交互(存储当前代币状态信息)
*/
stats statstable( _self, sym.name() );
//在表中搜索相同名称的代币
auto existing = statstable.find( sym.name() );
//校验,是否已经存在相同名称的代币
eosio_assert( existing == statstable.end(), "token with symbol already exists" );
//使用 emplace 方法,[在数据表中增加一项](https://developers.eos.io/eosio-cpp/reference#emplace)
statstable.emplace( _self, [&]( auto& s ) {
s.supply.symbol = maximum_supply.symbol;
s.max_supply = maximum_supply;
s.issuer = issuer;
});
}
(2)调用方法
$ cleos push action eosio.token create '[ "eosio", "1000000000.0000 SYS"]' \
-p eosio.token@active
1.4 发行token
(1)发行过程
void token::issue( account_name to, asset quantity, string memo )
{
//获取代币(token)
auto sym = quantity.symbol;
eosio_assert( sym.is_valid(), "invalid symbol name" );
eosio_assert( memo.size() <= 256, "memo has more than 256 bytes" );
//获取代币token名称
auto sym_name = sym.name();
//建立一个 milti_index 数据表,用来与数据库交互
stats statstable( _self, sym_name );
//在数据表中搜索代币 currency_stats 结构体,返回迭代器 exsting
auto existing = statstable.find( sym_name );
eosio_assert( existing != statstable.end(), "token with symbol does not exist, create token before issue" );
//取出地址内的数据赋值给st(引用 alias)
const auto& st = *existing;
//需要经过授权
require_auth( st.issuer );
eosio_assert( quantity.is_valid(), "invalid quantity" );
eosio_assert( quantity.amount > 0, "must issue positive quantity" );
eosio_assert( quantity.symbol == st.supply.symbol, "symbol precision mismatch" );
eosio_assert( quantity.amount <= st.max_supply.amount - st.supply.amount, "quantity exceeds available supply");
statstable.modify( st, 0, [&]( auto& s ) {
s.supply += quantity;
});
//给发布者增加资产
add_balance( st.issuer, quantity, st.issuer );
//判断代币接受方是否是发币者
if( to != st.issuer ) {
SEND_INLINE_ACTION( *this, transfer, {st.issuer,N(active)}, {st.issuer, to, quantity, memo} );
}
}
/**
*issue中调用的私有函数add_balance
*/
void token::add_balance( account_name owner, asset value, account_name ram_payer )
{
//创建数据表
accounts to_acnts( _self, owner );
auto to = to_acnts.find( value.symbol.name() );
//没有则插入
if( to == to_acnts.end() ) {
to_acnts.emplace( ram_payer, [&]( auto& a ){
a.balance = value;
});
} else {
//找到增加余额
to_acnts.modify( to, 0, [&]( auto& a ) {
a.balance += value;
});
}
}
(2)调用发行
$ cleos push action eosio.token issue '[ "user", "100.0000 SYS", "memo" ]' \
-p eosio@active
executed transaction: 822a607a9196112831ecc2dc14ffb1722634f1749f3ac18b73ffacd41160b019 268 bytes 1000 cycles
# eosio.token <= eosio.token::issue {"to":"user","quantity":"100.0000 SYS","memo":"memo"}
>> issue
# eosio.token <= eosio.token::transfer {"from":"eosio","to":"user","quantity":"100.0000 SYS","memo":"memo"}
>> transfer
# eosio <= eosio.token::transfer {"from":"eosio","to":"user","quantity":"100.0000 SYS","memo":"memo"}
# user <= eosio.token::transfer {"from":"eosio","to":"user","quantity":"100.0000 SYS","memo":"memo"}
1.5 交易token
(1)交易过程
/**
*公有函数,action可以调用
*/
void token::transfer( account_name from,
account_name to,
asset quantity,
string memo )
{
eosio_assert( from != to, "cannot transfer to self" );
//授权
require_auth( from );
eosio_assert( is_account( to ), "to account does not exist");
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" );
eosio_assert( quantity.symbol == st.supply.symbol, "symbol precision mismatch" );
eosio_assert( memo.size() <= 256, "memo has more than 256 bytes" );
sub_balance( from, quantity );
add_balance( to, quantity, from );
}
/**
*私有函数:减少余额
*/
void token::sub_balance( account_name owner, asset value ) {
accounts from_acnts( _self, owner );
//没有找到或余额大于总数,报错
const auto& from = from_acnts.get( value.symbol.name(), "no balance object found" );
eosio_assert( from.balance.amount >= value.amount, "overdrawn balance" );
//余额等于总数,删除这个账户;余额小于总数,则余额减去转账数
if( from.balance.amount == value.amount ) {
from_acnts.erase( from );
} else {
from_acnts.modify( from, owner, [&]( auto& a ) {
a.balance -= value;
});
}
}
(2)调用交易
$ cleos push action eosio.token transfer \
'[ "user", "tester", "25.0000 SYS", "m" ]' -p user@active
executed transaction: 06d0a99652c11637230d08a207520bf38066b8817ef7cafaab2f0344aafd7018 268 bytes 1000 cycles
# eosio.token <= eosio.token::transfer {"from":"user","to":"tester","quantity":"25.0000 SYS","memo":"m"}
>> transfer
# user <= eosio.token::transfer {"from":"user","to":"tester","quantity":"25.0000 SYS","memo":"m"}
# tester <= eosio.token::transfer {"from":"user","to":"tester","quantity":"25.0000 SYS","memo":"m"}