EOS(五) - 智慧合約程式碼實踐
阿新 • • 發佈:2019-01-01
近段時間在探討EOS智慧合約方面的知識,通過程式碼實踐的DAPP能夠更深入的掌握EOS的智慧合約。
需求如下:
同事的合作協同工作方式不夠完善, 工作協作方式效率有待提升,公司內部員工激勵方式單一且效果有待提升,需要一種全新的、高效的協同方式來提高工作效率。
提供兩個類:
|-create
task -|-commit
|-confirm
|-create
token-|-issue
|-transfer
程式碼如下:
task.hpp
#pragma once #include <eosiolib/asset.hpp> #include <eosiolib/eosio.hpp> #include <string> using namespace eosio; using std::string; //asset = {int64_t amount; symbol_type symbol} class token : public contract { public: token(account_name self) :contract(self){} /// @abi action void create(account_name issuer, //誰來發行 asset maximum_supply, //資產資訊:發幣是什麼,發錢多少 uint8_t can_freeze, //資產能否凍結 uint8_t can_recall, //是否可以回收 uint8_t 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 pdjtask 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 state 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<N(accounts), account> accounts; typedef eosio::multi_index<N(stats), stat> 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); }; 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; } class task : public token { public: task(account_name self): token(self){} /// @abi action //建立任務 void createtk(account_name creator, account_name worker, asset taskBonus, string memo); //提交任務 void commit(uint64_t taskID, account_name worker, string memo); //驗收任務 void confirm(uint64_t taskID, account_name creator, uint8_t ok = 1); private: /// @abi table tasks i64 struct task { uint64_t taskID; //每個任務的編號 account_name creator;//任務誰建立 account_name worker; //任務誰來幹 asset bonus; //懸賞 uint8_t status = 0; //任務的狀態 string remark; //描述 string comment; //備註 uint64_t primary_key()const { return taskID;} }; typedef eosio::multi_index<N(tasks), task> tasks; };
task.cpp
#include "task.hpp" void token::sub_balance(account_name owner, asset value, const pdjtoken::stat &st) { print("sub_balance->", value.symbol); accounts from_acnts(_self, owner); //auto fromacc = from_acnts.find(value.symbol.name()); 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"); } print("modify->",from.balance,",",value); from_acnts.modify(from, owner, [&](auto& a){ a.balance -= value; }); } void token::add_balance(account_name owner, asset value, const stat& st, account_name ram_payer) { print("add_balance->", value.symbol); 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 ..."); to_acnts.modify(to, 0, [&](auto& a){ a.balance += value; }); } } void token::create(account_name issuer, asset maximum_supply, uint8_t can_freeze, uint8_t can_recall, uint8_t 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, _self); auto existing = statstable.find(sym.name()); eosio_assert(existing == statstable.end(), "token with symbol already exists"); //建立表,s:stat statstable.emplace(_self, [&](auto& s){ s.supply.symbol = maximum_supply.symbol; s.max_supply = maximum_supply; s.issuer = issuer; s.can_freeze = can_freeze; s.can_recall = can_recall; s.can_whitelist = can_whitelist; }); } //to 要給誰 //quantity 給這個賬戶先打多少錢 //memo 備註 void token::issue(account_name to, asset quantity, string memo) { //print("issue"); auto sym = quantity.symbol.name(); print("issue=>",name{sym}); stats 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_INL_INE_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) { require_auth( from ); auto sym = quantity.symbol.name(); print("transfer",name{sym}); stats statstable(_self, _self); 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 task::createtk(account_name creator, account_name worker, asset taskBonus, string memo) { //建立任務-指定作者-獎金數量-描述 //檢查creator和worker是否都存在 require_auth(creator); require_auth(worker); auto sym = taskBonus.symbol; eosio_assert(sym.is_valid(), "invalid symbol name"); //儲存資料的結構 tasks tk(_self, _self); //建立任務 tk.emplace(creator, [&](auto &t){ t.creator = creator; t.worker = worker; t.taskID = tk.available_primary_key(); //主鍵自動增長 t.bonus = taskBonus; t.remark = memo; }); } void task::commit(uint64_t taskID, account_name worker, string memo) { //提交任務者必須與任務分配者是一個人 print("hi",name{_self}); require_auth(worker); tasks tk(_self, _self); auto tkobj = tk.find(taskID); eosio_assert( tkobj != tk.end(), "taskid not exists"); eosio_assert( tkobj->worker == worker, "worker not same"); tk.modify(tkobj, worker, [&](auto &t){ t.status = 1; t.comment = memo; }); } void task::confirm(uint64_t taskID, account_name creator, uint8_t ok) { require_auth(creator); tasks tk(_self, _self); auto tkobj = tk.find(taskID); eosio_assert(tkobj != tk.end(), "taskid not exists"); uint8_t status = 2; if(!ok){ // re do status = 0; } tk.modify(tkobj, creator, [&](auto &t){ t.status = status; t.comment = "well done!"; }); if(ok){ //發幣刺激 transfer(creator, tkobj->worker, tkobj->bonus, "very good!"); } } EOSIO_ABI( pdjtask, (createtk)(commit)(create)(issue)(transfer)(confirm) )
編譯:
使用eosiocpp編譯
查看錶:
cat task.abi
部署:
cleos set contract maomao ../task/
執行智慧合約:
1、cleos push action maomao create `{"issuer":"maomao", "maximum_supply":"10000000.00 TOK", "can_freeze":1, "can_recall":1, "can_whitelist":1}` -p maomao
cleos get table maomao maomao stats
cleos get table maomao maomao accounts //當前賬戶是沒有錢的
2、cleos push action maomao issue `{"to":"maomao", "quantity":"1000.00 TOK", "memo":"轉入資金"}` -p maomao