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 ); }
/** * @pre producers must be sorted from lowest to highest * @pre if proxy is set then no producers can be voted for * @pre every listed producer or proxy must have been previously registered * @pre voter must authorize this action * @pre voter must have previously staked some EOS for voting */ void system_contract::voteproducer( const account_name voter, const account_name proxy, const std::vector<account_name>& producers ) { require_auth( voter ); //validate input if ( proxy ) { eosio_assert( producers.size() == 0, "cannot vote for producers and proxy at same time" ); require_recipient( proxy ); } else { eosio_assert( producers.size() <= 30, "attempt to vote for too many producers" ); for( size_t i = 1; i < producers.size(); ++i ) { eosio_assert( producers[i-1] < producers[i], "producer votes must be unique and sorted" ); } } voters_table voters_tbl( _self, _self ); auto voter_it = voters_tbl.find( voter ); eosio_assert( 0 <= voter_it->staked.amount, "negative stake" ); eosio_assert( voter_it != voters_tbl.end() && ( 0 < voter_it->staked.amount || ( voter_it->is_proxy && 0 < voter_it->proxied_votes ) ), "no stake to vote" ); if ( voter_it->is_proxy ) { eosio_assert( proxy == 0 , "account registered as a proxy is not allowed to use a proxy" ); } //find old producers, update old proxy if needed const std::vector<account_name>* old_producers = nullptr; if( voter_it->proxy ) { if ( voter_it->proxy == proxy ) { return; // nothing changed } auto old_proxy = voters_tbl.find( voter_it->proxy ); eosio_assert( old_proxy != voters_tbl.end(), "old proxy not found" ); //data corruption voters_tbl.modify( old_proxy, 0, [&](auto& a) { a.proxied_votes -= uint64_t(voter_it->staked.amount); } ); if ( old_proxy->is_proxy ) { //if proxy stopped being a proxy, the votes were already taken back from producers by on( const unregister_proxy& ) old_producers = &old_proxy->producers; } } else { old_producers = &voter_it->producers; } //find new producers, update new proxy if needed const std::vector<account_name>* new_producers = nullptr; if ( proxy ) { auto new_proxy = voters_tbl.find( proxy ); eosio_assert( new_proxy != voters_tbl.end() && new_proxy->is_proxy, "proxy not found" ); voters_tbl.modify( new_proxy, 0, [&](auto& a) { a.proxied_votes += uint64_t(voter_it->staked.amount); } ); new_producers = &new_proxy->producers; } else { new_producers = &producers; } producers_table producers_tbl( _self, _self ); uint128_t votes = uint64_t(voter_it->staked.amount); if ( voter_it->is_proxy ) { votes += voter_it->proxied_votes; } if ( old_producers ) { //old_producers == nullptr if proxy has stopped being a proxy and votes were taken back from the producers at that moment //revoke votes only from no longer elected std::vector<account_name> revoked( old_producers->size() ); auto end_it = std::set_difference( old_producers->begin(), old_producers->end(), new_producers->begin(), new_producers->end(), revoked.begin() ); for ( auto it = revoked.begin(); it != end_it; ++it ) { auto prod = producers_tbl.find( *it ); eosio_assert( prod != producers_tbl.end(), "never existed producer" ); //data corruption producers_tbl.modify( prod, 0, [&]( auto& pi ) { pi.total_votes -= votes; } ); } } //update newly elected std::vector<account_name> elected( new_producers->size() ); auto end_it = elected.begin(); if( old_producers ) { end_it = std::set_difference( new_producers->begin(), new_producers->end(), old_producers->begin(), old_producers->end(), elected.begin() ); } else { end_it = std::copy( new_producers->begin(), new_producers->end(), elected.begin() ); } for ( auto it = elected.begin(); it != end_it; ++it ) { auto prod = producers_tbl.find( *it ); eosio_assert( prod != producers_tbl.end(), "producer is not registered" ); if ( proxy == 0 ) { //direct voting, in case of proxy voting update total_votes even for inactive producers eosio_assert( prod->active(), "producer is not currently registered" ); } producers_tbl.modify( prod, 0, [&]( auto& pi ) { pi.total_votes += votes; } ); } // save new values to the account itself voters_tbl.modify( voter_it, 0, [&](voter_info& a) { a.proxy = proxy; a.last_update = now(); a.producers = producers; }); }