├── .gitignore ├── README.md ├── more.moment ├── more.moment.cpp ├── README.md ├── more.moment.abi └── more.moment.hpp └── more.voting ├── more.voting.hpp ├── README.md ├── more.voting.abi └── more.voting.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | cmake-build-debug/ 3 | CMakeLists.txt 4 | *.wast -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EOS Contract Demo 2 | - `more.moment` simple post demo (contain db operations) 3 | - `more.voting` simple voting demo -------------------------------------------------------------------------------- /more.moment/more.moment.cpp: -------------------------------------------------------------------------------- 1 | #include "more.moment.hpp" 2 | 3 | uint64_t moment::id = 2; 4 | 5 | void moment::post(account_name creator, string content) { 6 | require_auth(creator); 7 | 8 | mshares mshare_table(_self, _self); 9 | 10 | config conf; 11 | get_config(conf); 12 | 13 | uint64_t id = conf.id++; 14 | 15 | mshare_table.emplace( creator, [&]( auto& mshare ) { 16 | mshare.id = id; 17 | mshare.content = content; 18 | mshare.author = creator; 19 | mshare.ptime = now(); 20 | mshare.itime = now(); 21 | }); 22 | 23 | store_config(conf); 24 | 25 | } 26 | 27 | void moment::remove(uint64_t id) { 28 | mshares mshare_table(_self, _self); 29 | auto it = mshare_table.find( id ); 30 | eosio_assert( it != mshare_table.end(), "moment with the id not found" ); 31 | 32 | require_auth(it->author); 33 | 34 | mshare_table.erase( it ); 35 | } -------------------------------------------------------------------------------- /more.moment/README.md: -------------------------------------------------------------------------------- 1 | # moment contract 2 | ## build and deploy 3 | ```shell 4 | $ eosiocpp -o contracts/more.moment/more.moment.wast contracts/more.moment/more.moment.cpp 5 | $ cleos set contract more.moment contracts/more.moment -p more.moment 6 | ``` 7 | ## run 8 | ### Post 9 | ```shell 10 | $ cleos push action more.moment post '{"creator":"more","content":"it's a nice day"}' -p more 11 | ``` 12 | ### View the table 13 | ```shell 14 | $ cleos get table more.moment more.moment mshare 15 | { 16 | "rows": [{ 17 | "id": 1232, 18 | "content": "it's a nice day", 19 | "author": "more", 20 | "ptime": "2018-04-16T09:15:29", 21 | "itime": "2018-04-16T09:15:29" 22 | },{ 23 | "id": 1233, 24 | "content": "生命在于运动", 25 | "author": "morea", 26 | "ptime": "2018-04-16T09:15:46", 27 | "itime": "2018-04-16T09:15:46" 28 | } 29 | ], 30 | "more": false 31 | } 32 | ``` 33 | ### Remove 34 | ```shell 35 | $ cleos push action more.moment remove '[1232]' -p more 36 | ``` -------------------------------------------------------------------------------- /more.moment/more.moment.abi: -------------------------------------------------------------------------------- 1 | { 2 | "____comment": "This file was generated by eosio-abigen. DO NOT EDIT - 2018-04-16T09:30:11", 3 | "types": [], 4 | "structs": [{ 5 | "name": "mshare", 6 | "base": "", 7 | "fields": [{ 8 | "name": "id", 9 | "type": "uint64" 10 | },{ 11 | "name": "content", 12 | "type": "string" 13 | },{ 14 | "name": "author", 15 | "type": "account_name" 16 | },{ 17 | "name": "ptime", 18 | "type": "time" 19 | },{ 20 | "name": "itime", 21 | "type": "time" 22 | } 23 | ] 24 | },{ 25 | "name": "post", 26 | "base": "", 27 | "fields": [{ 28 | "name": "creator", 29 | "type": "account_name" 30 | },{ 31 | "name": "content", 32 | "type": "string" 33 | } 34 | ] 35 | },{ 36 | "name": "remove", 37 | "base": "", 38 | "fields": [{ 39 | "name": "id", 40 | "type": "uint64" 41 | } 42 | ] 43 | } 44 | ], 45 | "actions": [{ 46 | "name": "post", 47 | "type": "post", 48 | "ricardian_contract": "" 49 | },{ 50 | "name": "remove", 51 | "type": "remove", 52 | "ricardian_contract": "" 53 | } 54 | ], 55 | "tables": [{ 56 | "name": "mshare", 57 | "index_type": "i64", 58 | "key_names": [ 59 | "id" 60 | ], 61 | "key_types": [ 62 | "uint64" 63 | ], 64 | "type": "mshare" 65 | } 66 | ], 67 | "clauses": [] 68 | } -------------------------------------------------------------------------------- /more.moment/more.moment.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace eosio; 4 | using namespace std; 5 | 6 | class moment : public contract { 7 | using contract::contract; 8 | public: 9 | moment( account_name self ) : 10 | contract( self ) {} 11 | 12 | void post( account_name creator, string content ); 13 | 14 | void remove( uint64_t id ); 15 | 16 | private: 17 | static uint64_t id; 18 | 19 | struct config { 20 | config() {} 21 | constexpr static uint64_t key = N(config); 22 | uint64_t id = 1232; 23 | }; 24 | 25 | void store_config(const config &conf) { 26 | auto it = db_find_i64( _self, _self, N(config), config::key ); 27 | if ( it != -1 ) { 28 | db_update_i64( it, _self, (const char *)&conf, sizeof(config) ); 29 | } else { 30 | db_store_i64( _self, N(config), _self, config::key, (const char *)&conf, sizeof(config) ); 31 | } 32 | } 33 | 34 | bool get_config( config &conf ) { 35 | auto it = db_find_i64( _self, _self, N(config), config::key ); 36 | if ( it != -1 ) { 37 | auto size = db_get_i64( it, (char*)&conf, sizeof(config) ); 38 | eosio_assert( size == sizeof(config), "Wrong record size" ); 39 | return true; 40 | } 41 | return false; 42 | } 43 | 44 | // @abi table 45 | struct mshare { 46 | uint64_t id; 47 | string content; 48 | account_name author; 49 | time ptime; 50 | time itime; 51 | 52 | uint64_t primary_key() const { return id; } 53 | }; 54 | 55 | typedef multi_index mshares; 56 | }; 57 | 58 | EOSIO_ABI(moment, (post)(remove)) -------------------------------------------------------------------------------- /more.voting/more.voting.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace eosio; 5 | using namespace std; 6 | 7 | typedef uint8_t vcount; 8 | 9 | struct proposal_content { 10 | 11 | proposal_content() {} 12 | 13 | name pname; 14 | string description; 15 | 16 | friend bool operator == ( const proposal_content& a, const proposal_content& b ) { 17 | return a.pname == b.pname; 18 | } 19 | 20 | EOSLIB_SERIALIZE( proposal_content, (pname)(description)) 21 | }; 22 | 23 | struct proposal : public proposal_content { 24 | 25 | proposal() {} 26 | 27 | proposal( account_name aname, proposal_content content ) { 28 | proposer = aname; 29 | pname = content.pname; 30 | description = content.description; 31 | } 32 | 33 | account_name proposer; 34 | vcount votes = 0; 35 | 36 | EOSLIB_SERIALIZE_DERIVED( proposal, proposal_content, (proposer)(votes)) 37 | }; 38 | 39 | struct proposal_finder { 40 | name pname; 41 | proposal_finder(name n) : pname(n) {} 42 | bool operator() (const proposal& p) { return p.pname == pname; } 43 | }; 44 | 45 | bool proposal_compare( const proposal& p1, const proposal& p2 ) { 46 | return p1.votes > p2.votes; 47 | } 48 | 49 | class voting : public contract { 50 | using contract::contract; 51 | public: 52 | voting( account_name self ) : 53 | contract( self ){} 54 | 55 | // @abi action 56 | void create( account_name creator, name vname, time expiration, vector proposals ); 57 | 58 | // @abi action 59 | void propose( account_name proposer, account_name creator, name vname, proposal_content content ); 60 | 61 | // @abi action 62 | void unpropose( account_name creator, name vname, name pname ); 63 | 64 | // @abi action 65 | void vote( account_name voter, account_name creator, name vname, name pname ); 66 | 67 | // @abi reveal 68 | void reveal( account_name creator, name vname ); 69 | 70 | // @abi action 71 | void cancel( account_name creator, name vname ); 72 | 73 | private: 74 | // @abi table 75 | struct vrecord { 76 | name vname; 77 | time expiration; 78 | vector proposals; 79 | vector voters; 80 | 81 | name primary_key() const { return vname; } 82 | }; 83 | 84 | typedef multi_index vrecords; 85 | }; 86 | 87 | EOSIO_ABI( voting, (create)(propose)(unpropose)(vote)(reveal)(cancel) ) -------------------------------------------------------------------------------- /more.voting/README.md: -------------------------------------------------------------------------------- 1 | # voting contract 2 | ## build and deploy 3 | ```shell 4 | $ eosiocpp -o contracts/more.voting/more.voting.wast contracts/more.voting/more.voting.cpp 5 | $ cleos set contract more.voting contracts/more.voting -p more.voting 6 | ``` 7 | ## run 8 | ### Create a voting 9 | 10 | Edit file `create.json` 11 | 12 | ```json 13 | { 14 | "creator": "more", 15 | "vname": "voting", 16 | "proposals": [{ 17 | "pname": "first", 18 | "description": "the first proposal" 19 | }, { 20 | "pname": "second", 21 | "description": "the second proposal" 22 | }], 23 | "expiration": "2018-04-13T10:08:30" 24 | } 25 | ``` 26 | 27 | Run the command 28 | 29 | ```shell 30 | $ cleos push action more.voting create "$(cat create.json)" -p more 31 | ``` 32 | Then query the `vrecord` table to view the added voting 33 | 34 | ```shell 35 | $ cleos get table more.voting more vrecord 36 | { 37 | "rows": [{ 38 | "vname": "voting", 39 | "expiration": "2018-04-13T10:08:30", 40 | "proposals": [{ 41 | "pname": "first", 42 | "description": "the first proposal", 43 | "proposer": "more", 44 | "votes": 0 45 | },{ 46 | "pname": "second", 47 | "description": "the second proposal", 48 | "proposer": "more", 49 | "votes": 0 50 | } 51 | ] 52 | } 53 | ], 54 | "more": false 55 | } 56 | ``` 57 | 58 | ### Add a proposal 59 | 60 | Edit file `propose.json` 61 | 62 | ```json 63 | { 64 | "proposer": "moreb", 65 | "creator": "more", 66 | "vname": "voting", 67 | "content": { 68 | "pname": "selectb", 69 | "description": "moreb test proposal" 70 | } 71 | } 72 | ``` 73 | 74 | Run the command 75 | 76 | ```shell 77 | $ cleos push action more.voting propose "$(cat propose.json)" -p moreb 78 | ``` 79 | 80 | Re-query `vrecord` table for user `more` to view the added proposal 81 | 82 | ```shell 83 | $ cleos get table more.voting more vrecord 84 | { 85 | "rows": [{ 86 | "vname": "voting", 87 | "expiration": "2018-04-13T10:08:30", 88 | "proposals": [{ 89 | "pname": "first", 90 | "description": "the first proposal", 91 | "proposer": "more", 92 | "votes": 0 93 | },{ 94 | "pname": "second", 95 | "description": "the second proposal", 96 | "proposer": "more", 97 | "votes": 0 98 | },{ 99 | "pname": "selectb", 100 | "description": "moreb test proposal", 101 | "proposer": "moreb", 102 | "votes": 0 103 | } 104 | ] 105 | } 106 | ], 107 | "more": false 108 | } 109 | ``` 110 | 111 | ### Undo a proposal 112 | 113 | Edit file `unpropose.json` 114 | 115 | ```json 116 | { 117 | "creator": "more", 118 | "vname": "voting", 119 | "pname": "selectb" 120 | } 121 | ``` 122 | 123 | Run the command 124 | 125 | ```shell 126 | $ cleos push action more.voting unpropose "$(cat unpropose.json)" -p moreb 127 | ``` 128 | 129 | ### Vote for proposal 130 | 131 | Edit file `vote.json` 132 | 133 | ```json 134 | { 135 | "voter": "morea", 136 | "creator": "more", 137 | "vname": "voting", 138 | "pname": "first" 139 | } 140 | ``` 141 | 142 | Run the command 143 | 144 | ```shell 145 | $ cleos push action more.voting vote "$(cat vote.json)" -p morea 146 | ``` 147 | 148 | ### Reveal voting results 149 | 150 | Run the command 151 | 152 | ```shell 153 | $ cleos push action more.voting reveal '{"creator":"more","vname":"voting"}' -p more 154 | ``` 155 | 156 | ### Cancel a voting 157 | 158 | Run the command 159 | 160 | ```shell 161 | $ cleos push action more.voting cancel '{"creator":"more","vname":"voting"}' -p more 162 | ``` 163 | 164 | -------------------------------------------------------------------------------- /more.voting/more.voting.abi: -------------------------------------------------------------------------------- 1 | { 2 | "____comment": "This file was generated by eosio-abigen. DO NOT EDIT - 2018-04-16T06:17:59", 3 | "types": [{ 4 | "new_type_name": "vcount", 5 | "type": "uint8" 6 | } 7 | ], 8 | "structs": [{ 9 | "name": "proposal_content", 10 | "base": "", 11 | "fields": [{ 12 | "name": "pname", 13 | "type": "name" 14 | },{ 15 | "name": "description", 16 | "type": "string" 17 | } 18 | ] 19 | },{ 20 | "name": "proposal", 21 | "base": "proposal_content", 22 | "fields": [{ 23 | "name": "proposer", 24 | "type": "account_name" 25 | },{ 26 | "name": "votes", 27 | "type": "vcount" 28 | } 29 | ] 30 | },{ 31 | "name": "vrecord", 32 | "base": "", 33 | "fields": [{ 34 | "name": "vname", 35 | "type": "name" 36 | },{ 37 | "name": "expiration", 38 | "type": "time" 39 | },{ 40 | "name": "proposals", 41 | "type": "proposal[]" 42 | },{ 43 | "name": "voters", 44 | "type": "account_name[]" 45 | } 46 | ] 47 | },{ 48 | "name": "create", 49 | "base": "", 50 | "fields": [{ 51 | "name": "creator", 52 | "type": "account_name" 53 | },{ 54 | "name": "vname", 55 | "type": "name" 56 | },{ 57 | "name": "expiration", 58 | "type": "time" 59 | },{ 60 | "name": "proposals", 61 | "type": "proposal_content[]" 62 | } 63 | ] 64 | },{ 65 | "name": "propose", 66 | "base": "", 67 | "fields": [{ 68 | "name": "proposer", 69 | "type": "account_name" 70 | },{ 71 | "name": "creator", 72 | "type": "account_name" 73 | },{ 74 | "name": "vname", 75 | "type": "name" 76 | },{ 77 | "name": "content", 78 | "type": "proposal_content" 79 | } 80 | ] 81 | },{ 82 | "name": "unpropose", 83 | "base": "", 84 | "fields": [{ 85 | "name": "creator", 86 | "type": "account_name" 87 | },{ 88 | "name": "vname", 89 | "type": "name" 90 | },{ 91 | "name": "pname", 92 | "type": "name" 93 | } 94 | ] 95 | },{ 96 | "name": "vote", 97 | "base": "", 98 | "fields": [{ 99 | "name": "voter", 100 | "type": "account_name" 101 | },{ 102 | "name": "creator", 103 | "type": "account_name" 104 | },{ 105 | "name": "vname", 106 | "type": "name" 107 | },{ 108 | "name": "pname", 109 | "type": "name" 110 | } 111 | ] 112 | },{ 113 | "name": "reveal", 114 | "base": "", 115 | "fields": [{ 116 | "name": "creator", 117 | "type": "account_name" 118 | },{ 119 | "name": "vname", 120 | "type": "name" 121 | } 122 | ] 123 | },{ 124 | "name": "cancel", 125 | "base": "", 126 | "fields": [{ 127 | "name": "creator", 128 | "type": "account_name" 129 | },{ 130 | "name": "vname", 131 | "type": "name" 132 | } 133 | ] 134 | } 135 | ], 136 | "actions": [{ 137 | "name": "create", 138 | "type": "create", 139 | "ricardian_contract": "" 140 | },{ 141 | "name": "propose", 142 | "type": "propose", 143 | "ricardian_contract": "" 144 | },{ 145 | "name": "unpropose", 146 | "type": "unpropose", 147 | "ricardian_contract": "" 148 | },{ 149 | "name": "vote", 150 | "type": "vote", 151 | "ricardian_contract": "" 152 | },{ 153 | "name": "reveal", 154 | "type": "reveal", 155 | "ricardian_contract": "" 156 | },{ 157 | "name": "cancel", 158 | "type": "cancel", 159 | "ricardian_contract": "" 160 | } 161 | ], 162 | "tables": [{ 163 | "name": "vrecord", 164 | "index_type": "i64", 165 | "key_names": [ 166 | "vname" 167 | ], 168 | "key_types": [ 169 | "name" 170 | ], 171 | "type": "vrecord" 172 | } 173 | ], 174 | "clauses": [] 175 | } -------------------------------------------------------------------------------- /more.voting/more.voting.cpp: -------------------------------------------------------------------------------- 1 | #include "more.voting.hpp" 2 | 3 | void voting::create(account_name creator, name vname, time expiration, vector proposals) { 4 | require_auth( creator ); 5 | 6 | eosio_assert( expiration > now(), "expiration cannot be earlier than current" ); 7 | 8 | vrecords record_table(_self, creator); 9 | eosio_assert( record_table.find( vname ) == record_table.end(), "voting with the same name exists" ); 10 | 11 | vector i_proposals; 12 | 13 | for (auto prop_itr = proposals.begin(); prop_itr != proposals.end() ; ++prop_itr) { 14 | proposal i_proposal = proposal(creator, *prop_itr); 15 | i_proposals.push_back(i_proposal); 16 | } 17 | 18 | record_table.emplace(creator, [&]( auto& row ) { 19 | row.vname = vname; 20 | row.expiration = expiration; 21 | row.proposals = move(i_proposals); 22 | }); 23 | } 24 | 25 | void voting::propose( account_name proposer, account_name creator, name vname, proposal_content content ) { 26 | require_auth( proposer ); 27 | 28 | vrecords record_table(_self, creator); 29 | auto record_itr = record_table.find( vname ); 30 | eosio_assert( record_itr != record_table.end(), "voting with the name not found" ); 31 | 32 | eosio_assert( record_itr->expiration < now(), "voting has expired" ); 33 | 34 | proposal i_proposal = proposal(proposer, content); 35 | 36 | auto prop_itr = std::find( record_itr->proposals.begin(), record_itr->proposals.end(), i_proposal ); 37 | eosio_assert( prop_itr == record_itr->proposals.end(), "proposal with the same name exists" ); 38 | 39 | record_table.modify( record_itr, proposer, [&]( auto& row ) { 40 | row.proposals.push_back( i_proposal ); 41 | }); 42 | 43 | } 44 | 45 | void voting::unpropose( account_name creator, name vname, name pname ) { 46 | 47 | vrecords record_table(_self, creator); 48 | auto record_itr = record_table.find( vname ); 49 | eosio_assert( record_itr != record_table.end(), "voting with the name not found" ); 50 | 51 | eosio_assert( record_itr->expiration < now(), "voting has expired" ); 52 | 53 | auto prop_itr = std::find_if( record_itr->proposals.begin(), record_itr->proposals.end(), proposal_finder(pname) ); 54 | eosio_assert( prop_itr != record_itr->proposals.end(), "proposal with the name not found" ); 55 | 56 | account_name proposer = prop_itr->proposer; 57 | 58 | require_auth(proposer); 59 | 60 | record_table.modify( record_itr, proposer, [&]( auto& row ) { 61 | row.proposals.erase( prop_itr ); 62 | }); 63 | 64 | } 65 | 66 | void voting::vote( account_name voter, account_name creator, name vname, name pname ) { 67 | require_auth(voter); 68 | 69 | vrecords record_table(_self, creator); 70 | auto record_itr = record_table.find( vname ); 71 | eosio_assert( record_itr != record_table.end(), "voting with the name not found" ); 72 | 73 | eosio_assert( record_itr->expiration > now(), "voting has expired" ); 74 | 75 | auto voters_itr = std::find( record_itr->voters.begin(), record_itr->voters.end(), voter ); 76 | eosio_assert( voters_itr == record_itr->voters.end(), "the voter have already voted" ); 77 | 78 | auto prop_itr = std::find_if( record_itr->proposals.begin(), record_itr->proposals.end(), proposal_finder(pname) ); 79 | eosio_assert( prop_itr != record_itr->proposals.end(), "proposal with the name not found" ); 80 | 81 | record_table.modify( record_itr, voter, [&]( auto& row ) { 82 | row.voters.push_back( voter ); 83 | auto p_itr = std::find_if( row.proposals.begin(), row.proposals.end(), proposal_finder(pname) ); 84 | p_itr->votes++; 85 | }); 86 | 87 | } 88 | 89 | void voting::reveal( account_name creator, name vname ) { 90 | require_auth(creator); 91 | 92 | vrecords record_table(_self, creator); 93 | auto record_itr = record_table.find( vname ); 94 | eosio_assert( record_itr != record_table.end(), "voting with the name not found" ); 95 | 96 | record_table.modify( record_itr, creator, [&]( auto& row ) { 97 | std::sort( row.proposals.begin(), row.proposals.end(), proposal_compare ); 98 | }); 99 | 100 | } 101 | 102 | void voting::cancel( account_name creator, name vname ) { 103 | require_auth(creator); 104 | 105 | vrecords record_table(_self, creator); 106 | auto iterator = record_table.find( vname ); 107 | eosio_assert( iterator != record_table.end(), "voting with the name not found" ); 108 | 109 | record_table.erase( iterator ); 110 | } 111 | --------------------------------------------------------------------------------