Daniel Larimer 在他的博客介紹了EOS新的智能合約架構(EOS團隊的開發速度實在是太嚇人,根本追不上)。他給出了最簡單的一個新幣種的智能合約代碼,僅有49行就能完成一個新幣種的開發,一個新的“愛息歐”就誕生了讓。我們一步一步實現吧。
首先實現私有成員,建立一個 account 結構體,這個結構體裏保存的是所有持有我們這種代幣的人的賬戶和餘額。
private: //account 結構體 struct account { //EOS 賬戶名 account_name owner; //餘額 uint64_t balance; //主鍵 uint64_t primary_key()const { return owner; }
下一步 我們要利用 Boost 庫中的多索引列表,將上面聲明的結構體放入一個列表中,方便查詢和修改。
eosio::multi_index<N(accounts), account> _accounts;
接着,實現 add_balance() 函數,這個私有函數的目的是給特定的 EOS 賬戶增加特定的代幣。
void add_balance( account_name payer, account_name to, uint64_t q ) { //在列表中查詢,看要收幣的用戶是否已經在列表中。 auto toitr = _accounts.find( to ); //如果不在列表中,說明用戶從未持有過這種幣,要將用戶加入列表 if( toitr == _accounts.end() ) { //增加一個用戶 _accounts.emplace( payer, [&]( auto& a ) { a.owner = to; //因爲之前沒有這種幣,用戶名下的餘額爲要接收的數量 a.balance = q; }); //如果用戶在列表中,說明已經持有或持有過這種幣 } else { _accounts.modify( toitr, 0, [&]( auto& a ) { //直接將餘額增加要轉入的數量 a.balance += q; //判斷用戶餘額是否溢出(餘額增加了q,之後數量應該大於q) eosio_assert( a.balance >= q, "overflow detected" ); }); } }
之後就要實現公有方法了,首先是構造函數,別忘了初始化 _accounts 列表。
public: simpletoken( account_name self ) :contract(self),_accounts( _self, _self){}
實現公有的 transfer(轉賬)函數,將代幣從一個賬戶轉移到另一個賬戶。
void transfer( account_name from, account_name to, uint64_t quantity ) { //從付款方獲取權限 require_auth( from ); //從列表中搜索發幣方賬戶 const auto& fromacnt = _accounts.get( from ); //驗證付款方餘額,是否透支 eosio_assert( fromacnt.balance >= quantity, "overdrawn balance" ); //從付款方減去代幣 _accounts.modify( fromacnt, from, [&]( auto& a ){ a.balance -= quantity; } ); //收款方增加代幣(之前實現的私有函數) add_balance( from, to, quantity ); }
OK,是不是以爲大功告成了?還有最重要的 issue(發行)函數,要不從哪“印錢?”
void issue( account_name to, uint64_t quantity ) { //得到合約主人的權限 require_auth( _self ); //直接印錢 add_balance( _self, to, quantity );
最後一步,將我們的 transfer 和 issue 函數接口提供給 EOS 系統,通過一個宏就可以快速實現。
EOSIO_ABI( simpletoken, (transfer)(issue) )
這個宏是咋回事?我們看看 dispacher.hpp 文件中對這個宏的定義,其實是替開發者實現了 apply 函數,使得開發者可以專注於業務邏輯。
#define EOSIO_ABI( TYPE, MEMBERS ) \ extern "C" { \ void apply( uint64_t receiver, uint64_t code, uint64_t action ) { \ auto self = receiver; \ if( code == self ) { \ TYPE thiscontract( self ); \ switch( action ) { \ EOSIO_API( TYPE, MEMBERS ) \ } \ eosio_exit(0); \ } \ } \ } \
大功告成,看看全部的代碼吧,是不是49行就搞定了?不過 EOS 表示以後會有系統的標準代幣,連以上的具體邏輯都不用我們實現了,不過這段代碼對系統學習 EOS 智能合約架構還是很有意義的。
#include <eosiolib/eosio.hpp> class simpletoken : public eosio::contract { public: simpletoken( account_name self ) :contract(self),_accounts( _self, _self){} void transfer( account_name from, account_name to, uint64_t quantity ) { require_auth( from ); const auto& fromacnt = _accounts.get( from ); eosio_assert( fromacnt.balance >= quantity, "overdrawn balance" ); _accounts.modify( fromacnt, from, [&]( auto& a ){ a.balance -= quantity; } ); add_balance( from, to, quantity ); } void issue( account_name to, uint64_t quantity ) { require_auth( _self ); add_balance( _self, to, quantity ); } private: struct account { account_name owner; uint64_t balance; uint64_t primary_key()const { return owner; } }; eosio::multi_index<N(accounts), account> _accounts; void add_balance( account_name payer, account_name to, uint64_t q ) { auto toitr = _accounts.find( to ); if( toitr == _accounts.end() ) { _accounts.emplace( payer, [&]( auto& a ) { a.owner = to; a.balance = q; }); } else { _accounts.modify( toitr, 0, [&]( auto& a ) { a.balance += q; eosio_assert( a.balance >= q, "overflow detected" ); }); } } }; EOSIO_ABI( simpletoken, (transfer)(issue) )