#include "eosio.system.hpp" #include namespace eosiosystem { const int64_t min_daily_tokens = 100; const double continuous_rate = 0.04879; // 5% annual rate const double perblock_rate = 0.0025; // 0.25% const double standby_rate = 0.0075; // 0.75% const uint32_t blocks_per_year = 52*7*24*2*3600; // half seconds per year const uint32_t seconds_per_year = 52*7*24*3600; const uint32_t blocks_per_day = 2 * 24 * 3600; const uint32_t blocks_per_hour = 2 * 3600; const uint64_t useconds_per_day = 24 * 3600 * uint64_t(1000000); const uint64_t useconds_per_year = seconds_per_year*1000000ll; void system_contract::onblock( block_timestamp timestamp, account_name producer ) { using namespace eosio; require_auth(N(eosio)); /** until activated stake crosses this threshold no new rewards are paid */ if( _gstate.total_activated_stake < 150'000'000'0000 ) return; if( _gstate.last_pervote_bucket_fill == 0 ) /// start the presses _gstate.last_pervote_bucket_fill = current_time(); /** * At startup the initial producer may not be one that is registered / elected * and therefore there may be no producer object for them. */ auto prod = _producers.find(producer); if ( prod != _producers.end() ) { _gstate.total_unpaid_blocks++; _producers.modify( prod, 0, [&](auto& p ) { p.produced_blocks++; p.last_produced_block_time = timestamp; }); } /// only update block producers once every minute, block_timestamp is in half seconds if( timestamp - _gstate.last_producer_schedule_update > 120 ) { update_elected_producers( timestamp ); } } using namespace eosio; void system_contract::claimrewards( const account_name& owner ) { require_auth(owner); const auto& prod = _producers.get( owner ); eosio_assert( prod.active(), "producer does not have an active key" ); auto ct = current_time(); eosio_assert( ct - prod.last_claim_time > useconds_per_day, "already claimed rewards within past day" ); const asset token_supply = token( N(eosio.token)).get_supply(symbol_type(system_token_symbol).name() ); const auto usecs_since_last_fill = ct - _gstate.last_pervote_bucket_fill; if( usecs_since_last_fill > 0 ) { auto new_tokens = static_cast( (continuous_rate * double(token_supply.amount) * double(usecs_since_last_fill)) / double(useconds_per_year) ); auto to_producers = new_tokens / 5; auto to_savings = new_tokens - to_producers; auto to_per_block_pay = to_producers / 4; auto to_per_vote_pay = to_producers - to_per_block_pay; INLINE_ACTION_SENDER(eosio::token, issue)( N(eosio.token), {{N(eosio),N(active)}}, {N(eosio), asset(new_tokens), std::string("issue tokens for producer pay and savings")} ); _gstate.pervote_bucket += to_per_vote_pay; _gstate.perblock_bucket += to_per_block_pay; _gstate.savings += to_savings; _gstate.last_pervote_bucket_fill = ct; } int64_t producer_per_block_pay = (_gstate.perblock_bucket * prod.produced_blocks) / _gstate.total_unpaid_blocks; int64_t producer_per_vote_pay = int64_t((_gstate.pervote_bucket * prod.total_votes ) / _gstate.total_producer_vote_weight); int64_t total_pay = producer_per_block_pay + producer_per_vote_pay; eosio_assert( total_pay > 100'0000, "insufficient pay to claim, require at least 100.0000 EOS" ); _gstate.pervote_bucket -= producer_per_vote_pay; _gstate.perblock_bucket -= producer_per_block_pay; _gstate.total_unpaid_blocks -= prod.produced_blocks; _producers.modify( prod, 0, [&](auto& p) { p.last_claim_time = ct; p.produced_blocks = 0; }); if( total_pay > 0 ) { INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)}, { N(eosio), owner, asset(total_pay), std::string("producer pay") } ); } } } //namespace eosiosystem