在上一篇文章《EOS开发入门》中,咱们为你们介绍了EOS的节点启动和合约部署和调用等入门知识。本次咱们来实现一个复杂的例子,能够为其取一个高大上的名字-悬赏任务管理系统。这能够是咱们身边的一个例子,在工做中咱们也许会碰到须要周围人帮助实现工做之外的问题,这每每须要靠交情来作到。咱们使用eos能够实现这样一个任务管理系统,任务发起人能够发布一个任务给某个赏金猎人,指定任务的赏金。在任务完成后,发起人将约定的赏金交给完成者。html
经过故事背景介绍,咱们能够察觉咱们须要支付赏金的部分,这个能够使用区块链的token来实现。另外还须要一个实现一个对任务的管理,token的实现能够直接使用eosio.token,任务的管理咱们须要实现3个action,建立任务,提交任务,验收任务。总结以下:ios
token合约:建立,发行,转帐git
task合约:建立,提交,验收github
任务须要包含的信息:json
struct [[eosio::table]] task { uint64_t taskID;//任务编号 name creator; //建立者 name worker;//执行者 asset bonus;//承诺奖励 uint8_t status = 0;//状态 string remark;//任务描述 string comment;//评价 uint64_t primary_key()const { return taskID; } };
/** * @file pdjtoken.hpp * @company http://pdjedu.com/ */ #pragma once #include <eosiolib/asset.hpp> #include <eosiolib/eosio.hpp> #include <string> namespace eosiosystem { class system_contract; } namespace eosio { using std::string; class [[eosio::contract("pdjtoken")]] pdjtoken : public contract { public: using contract::contract; pdjtoken(name receiver, name code, datastream<const char*> ds): contract(receiver, code, ds) {} [[eosio::action]] void create( name issuer, asset maximum_supply); [[eosio::action]] void issue( name to, asset quantity, string memo ); [[eosio::action]] void transfer( name from, name to, asset quantity, string memo ); private: inline asset get_supply( name token_contract_account, symbol_code sym_code )const; inline asset get_balance( name token_contract_account, name owner, symbol_code sym_code )const; private: struct [[eosio::table]] account { asset balance; uint64_t primary_key()const { return balance.symbol.code().raw(); } }; struct [[eosio::table]] currency_stats { asset supply; asset max_supply; name issuer; uint64_t primary_key()const { return supply.symbol.code().raw(); } }; typedef eosio::multi_index< "accounts"_n, account > accounts; typedef eosio::multi_index< "stat"_n, currency_stats > stats; void sub_balance( name owner, asset value ); void add_balance( name owner, asset value, name ram_payer ); }; asset pdjtoken::get_supply( name token_contract_account, symbol_code sym_code )const { stats statstable( token_contract_account, sym_code.raw() ); const auto& st = statstable.get( sym_code.raw() ); return st.supply; } asset pdjtoken::get_balance( name token_contract_account, name owner, symbol_code sym_code )const { accounts accountstable( token_contract_account, owner.value ); const auto& ac = accountstable.get( sym_code.raw() ); return ac.balance; } } /// namespace eosio
/** * @file pdjtoken.cpp * @copyright http://pdjedu.com/ */ #include "pdjtoken.hpp" namespace eosio { //建立 void pdjtoken::create( name issuer, asset maximum_supply ) { 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.code().raw() ); auto existing = statstable.find( sym.code().raw() ); 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; }); } //发行 void pdjtoken::issue( name to, asset quantity, string memo ) { auto sym = quantity.symbol; eosio_assert( sym.is_valid(), "invalid symbol name" ); eosio_assert( memo.size() <= 256, "memo has more than 256 bytes" ); stats statstable( _self, sym.code().raw() ); auto existing = statstable.find( sym.code().raw() ); eosio_assert( existing != statstable.end(), "token with symbol does not exist, create token before issue" ); 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, same_payer, [&]( auto& s ) { s.supply += quantity; }); add_balance( st.issuer, quantity, st.issuer ); if( to != st.issuer ) { SEND_INLINE_ACTION( *this, transfer, { {st.issuer, "active"_n} }, { st.issuer, to, quantity, memo } ); } } //转帐 void pdjtoken::transfer( name from, 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.code(); stats statstable( _self, sym.raw() ); const auto& st = statstable.get( sym.raw() ); 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" ); auto payer = has_auth( to ) ? to : from; sub_balance( from, quantity ); add_balance( to, quantity, payer ); } void pdjtoken::sub_balance( name owner, asset value ) { accounts from_acnts( _self, owner.value ); const auto& from = from_acnts.get( value.symbol.code().raw(), "no balance object found" ); eosio_assert( from.balance.amount >= value.amount, "overdrawn balance" ); from_acnts.modify( from, owner, [&]( auto& a ) { a.balance -= value; }); } void pdjtoken::add_balance( name owner, asset value, name ram_payer ) { accounts to_acnts( _self, owner.value ); auto to = to_acnts.find( value.symbol.code().raw() ); if( to == to_acnts.end() ) { to_acnts.emplace( ram_payer, [&]( auto& a ){ a.balance = value; }); } else { to_acnts.modify( to, same_payer, [&]( auto& a ) { a.balance += value; }); } } } /// namespace eosio EOSIO_DISPATCH( eosio::pdjtoken, (create)(issue)(transfer) )
/** * @file pdjtask.hpp * @company http://pdjedu.com/ */ #pragma once #include <eosiolib/asset.hpp> #include <eosiolib/eosio.hpp> #include <string> namespace eosiosystem { class system_contract; } namespace eosio { using std::string; class [[eosio::contract]] pdjtask : public contract { public: pdjtask(name receiver, name code, datastream<const char*> ds): contract(receiver, code, ds) {} //建立任务 [[eosio::action]] void createtk( name creator, name worker, asset taskBonus, string memo ); //提交任务 [[eosio::action]] void commit( uint64_t taskID, string memo ); //验收任务 [[eosio::action]] void confirm( uint64_t taskID, uint8_t ok = 1 ); private: struct [[eosio::table]] task { uint64_t taskID; name creator; name worker; asset bonus; uint8_t status = 0; string remark; string comment; uint64_t primary_key()const { return taskID; } }; typedef eosio::multi_index< "tasks"_n, task > tasks; private: /* void transfer( name from, name to, asset quantity, string memo ); */ void task_commit(name from, name to, asset bonus, string memo) { action act = action( permission_level{from,"active"_n}, "pdjtoken"_n, "transfer"_n, std::make_tuple(from, to, bonus, memo) ); act.send(); } }; } /// namespace eosio
/** * @file pdjtask.cpp * @company http://pdjedu.com/ */ #include "pdjtask.hpp" namespace eosio { //建立任务 void pdjtask::createtk( name creator, name worker, asset taskBonus, string memo ) { require_auth(creator); //require_auth(worker); auto sym = taskBonus.symbol; eosio_assert( sym.is_valid(), "invalid symbol name" ); tasks tk( _code, _code.value ); tk.emplace( creator, [&](auto &t){ t.creator = creator; t.worker = worker; t.taskID = tk.available_primary_key(); t.bonus = taskBonus; t.remark = memo; }); } //提交任务 void pdjtask::commit( uint64_t taskID, string memo ) { //提交任务者必须与任务分配者是一我的 print("hi,",name{_self}); //require_auth(worker); tasks tk( _code, _code.value ); auto tkobj = tk.find(taskID); eosio_assert( tkobj != tk.end(), "taskid not exists" ); require_auth(tkobj->worker ); //eosio_assert( tkobj->worker == worker, "worker not same" ); tk.modify(tkobj, tkobj->worker ,[&](auto &t){ t.status = 1; t.comment = memo; }); } //验收任务 void pdjtask::confirm( uint64_t taskID, uint8_t ok ) { //require_auth(creator); tasks tk( _code, _code.value ); auto tkobj = tk.find(taskID); eosio_assert( tkobj != tk.end(), "taskid not exists" ); uint8_t status = 2; print("confirm---",name{tkobj->creator}); require_auth(tkobj->creator); if ( !ok ) { // re do status = 0; } tk.modify(tkobj, tkobj->creator, [&](auto &t){ t.status = status; t.comment = "well done!"; }); if ( ok ){ //发币刺激 //transfer( creator, tkobj->worker, tkobj->bonus, "very good!" ); task_commit(tkobj->creator, tkobj->worker, tkobj->bonus, "very good!"); } } } /// namespace eosio EOSIO_DISPATCH( eosio::pdjtask, (createtk)(commit)(confirm) )
在合约编写完成后,咱们还须要编写一个页面来调用智能合约,这就须要用到eosjs。eosjs集成了EOSIO RPC API,用于与EOS区块链交互,查阅官方文档可获取更多详细信息。ide
monkeysun和laowang已经收到了任务奖励的token学习
$(function() { var userAccount; var userPrivateKey; $("#LoginWindow").modal(); $(".Login").on("click", function() { userAccount = $("#userAcc").val(); userPrivateKey = $("#PrivateKey").val(); config = { chainId: 'cf057bbfb72640471fd910bcb67639c22df9f92470936cddc1ade0e2f2e7dc4f', // 32 byte (64 char) hex string keyProvider: [userPrivateKey], // WIF string or array of keys.. //5J2ZC6ZbtoFnTsZofTnMaTQmZSkdx9DnM9QZbuYTvDS2AgQaGzX httpEndpoint: 'http://127.0.0.1:8888', expireInSeconds: 60, broadcast: true, verbose: false, // API activity sign: true } eos = Eos(config); eos.getAccount(userAccount).then(result => { console.log(result); alert("欢迎回来," + userAccount); $(".userName span:nth-child(2)").html("帐户:" + userAccount); getBalance(); }).catch(err => { console.log(err); alert("错误:帐户不存在!"); }); $(".close_win").click(); getTaskList(); }); //发布任务 $(".Createtk").on("click", function() { console.log("发布任务"); console.log(userPrivateKey); $("#ReleaseTask").modal(); getTaskList(); }); //确认发布任务 $(".ConfirmRelease").on("click", function() { var WorkerAcc = $("#GetWorker").val(); var TaskToken = $("#GetToken").val(); var TaskInfo = $("#GetTaskInfo").val(); console.log(WorkerAcc,TaskToken,TaskInfo); $(".close_win").click(); eos.transaction({ actions: [ { account: 'pdjtask', name: 'createtk', authorization: [{ actor: userAccount, permission: 'active' }], data: { creator: userAccount, worker: WorkerAcc, taskBonus: TaskToken, memo: TaskInfo } } ] }).then(result => { console.log(result); alert("发布成功!"); getTaskList(); }) .catch(error => {console.error(error);alert("发生错误!" + error)}); }); //领取任务 $(".Receive").on("click", function() { console.log("领取任务"); $("#ReceiveTask").modal(); getTaskList(); }); //确认领取 $(".ConfirmReceive").on("click", function() { var TaskID = $("#ReceiveTaskID").val(); console.log(TaskID); $(".close_win").click(); eos.transaction({ actions: [ { account: 'pdjtask', name: 'receivetk', authorization: [{ actor: userAccount, permission: 'active' }], data: { taskID: TaskID, worker: userAccount } } ] }).then(result => { console.log(result); alert("领取成功"); getTaskList(); }) .catch(error => {console.error(error);alert("发生错误!" + error)}); }); //提交任务 $(".Commit").on("click", function() { console.log("提交任务"); $("#SubmitTask").modal(); getTaskList(); }); //确认提交 $(".ConfirmSubmission").on("click", function() { var TaskID = $("#GetTaskID").val(); var TaskInfo = $("#TaskInformation").val(); console.log(TaskInfo); $(".close_win").click(); eos.transaction({ actions: [ { account: 'pdjtask', name: 'commit', authorization: [{ actor: userAccount, permission: 'active' }], data: { taskID: TaskID, memo: TaskInfo } } ] }).then(result => { console.log(result); alert("提交成功"); getTaskList(); }) .catch(error => {console.error(error);alert("发生错误!" + error)}); }); //验收任务 $(".Confirm").on("click", function() { console.log("验收任务"); $("#ConfirmTask").modal(); getTaskList(); }); //确认验收 $(".TaskConfirm").on("click", function() { var TaskID = $("#taskid").val(); var TaskStatus = $("#TaskStatus").val(); TaskStatus = parseInt(TaskStatus); console.log(TaskID,TaskStatus); $(".close_win").click(); eos.transaction({ actions: [ { account: 'pdjtask', name: 'confirm', authorization: [{ actor: userAccount, permission: 'active' }], data: { taskID: TaskID, ok: TaskStatus } } ] }).then(result => { console.log(result); alert("任务验收成功"); getTaskList(); getBalance(); }) .catch(error => {console.error(error);alert("发生错误!" + error)}); }); //查看余额 function getBalance(){ eos.getCurrencyBalance({ account: userAccount, code: 'pdjtoken', symbol: 'PTK' }) .then(result => { console.log(result); if(result.length == 0) $(".balance span:nth-child(2)").html("余额:0"); else $(".balance span:nth-child(2)").html("余额:" + result); }) .catch(error => console.error(error)); } //console.log(eos); //任务列表 function getTaskList(){ eos.getTableRows({ scope: 'pdjtask', code: 'pdjtask', table: 'tasks', json: true, lower_bound: 0, upper_bound: -1, limit: 20 }) .then(function(result){ console.log(result.rows); var tr; var tkStatus = ""; for(var i = 0; i < result.rows.length; i++){ if(result.rows[i].status == 0) tkStatus = "未领取"; else if(result.rows[i].status == 1) tkStatus = "已领取"; else if(result.rows[i].status == 2) tkStatus = "已提交"; else tkStatus = "已结束"; tr += '<tr>'; tr += '<td class="active">'+result.rows[i].taskID+'</td>'; tr += '<td class="success">'+result.rows[i].creator+'</td>'; tr += '<td class="warning">'+result.rows[i].worker+'</td>'; tr += '<td class="danger">'+result.rows[i].bonus+'</td>'; tr += '<td class="info">'+tkStatus+'</td>'; tr += '<td class="active">'+result.rows[i].remark+'</td>'; tr += '<td class="success">'+result.rows[i].comment+'</td>'; tr += '</tr>'; } //console.log(tr); $("#list").html(tr); }) .catch(error => console.error(error)); } });
本文只包含部分核心代码,点击这里可获取所有代码和文件。以上就是本次分享的内容,欢迎你们学习交流。区块链