Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adjust chain inflation #84

Merged
merged 4 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions contracts/eosio.system/src/producer_pay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,24 @@ namespace eosiosystem {
const auto usecs_since_last_fill = (ct - _gstate.last_pervote_bucket_fill).count();

if( usecs_since_last_fill > 0 && _gstate.last_pervote_bucket_fill > time_point() ) {
auto new_tokens = static_cast<int64_t>( (continuous_rate * double(token_supply.amount) * double(usecs_since_last_fill)) / double(useconds_per_year) );
auto current_fees = eosio::token::get_balance(token_account, fees_account, core_symbol().code() );
auto distribute_tokens = static_cast<int64_t>( (continuous_rate * double(token_supply.amount) * double(usecs_since_last_fill)) / double(useconds_per_year) );
auto fees_to_use = std::min( distribute_tokens, current_fees.amount );
auto issue_tokens = distribute_tokens - fees_to_use;
// needs to be 2/5 Savings, 2/5 Voters, 1/5 producers
auto to_per_block_pay = new_tokens / 5;
auto to_per_block_pay = distribute_tokens / 5;
auto to_voters = 2 * to_per_block_pay;
auto to_savings = new_tokens - (to_voters + to_per_block_pay);
auto to_savings = distribute_tokens - (to_voters + to_per_block_pay);

{
token::issue_action issue_act{ token_account, { {get_self(), active_permission} } };
issue_act.send( get_self(), asset(new_tokens, core_symbol()), "issue tokens for producer pay and savings" );
if( issue_tokens > 0 ){
token::issue_action issue_act{ token_account, { {get_self(), active_permission} } };
issue_act.send( get_self(), asset(issue_tokens, core_symbol()), "issue tokens for producer pay and savings" );
}
if( fees_to_use > 0 ){
token::transfer_action transfer_act{ token_account, { {fees_account, active_permission} } };
transfer_act.send( fees_account, get_self(), asset(fees_to_use, core_symbol()), "collect tokenomic fees" );
}
}
{
token::transfer_action transfer_act{ token_account, { {get_self(), active_permission} } };
Expand All @@ -99,6 +108,16 @@ namespace eosiosystem {
_gstate.perblock_bucket += to_per_block_pay;
_gstate.voters_bucket += to_voters;
_gstate.last_pervote_bucket_fill = ct;

// burn remaining tokenomic fees
auto burn_fees = std::max(int64_t(0), (current_fees.amount - fees_to_use) );
if( burn_fees > 0 ){
token::transfer_action transfer_act{ token_account, { {fees_account, active_permission} } };
transfer_act.send( fees_account, get_self(), asset(burn_fees, core_symbol()), "burn tokenomic fees" );

token::retire_action retire_act{ token_account, { {get_self(), active_permission} } };
retire_act.send( asset(burn_fees, core_symbol()), "burn tokenomic fees" );
}
}
}

Expand Down
14 changes: 13 additions & 1 deletion tests/eosio.system_tester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class eosio_system_tester : public TESTER {
}
}

void remaining_setup() {
void remaining_setup(symbol core_symbol = symbol{CORE_SYM}) {
produce_blocks();

// Assumes previous setup steps were done with core token symbol set to CORE_SYM
Expand All @@ -93,6 +93,10 @@ class eosio_system_tester : public TESTER {
create_account_with_resources( "carol1111111"_n, config::system_account_name, core_sym::from_string("1.0000"), false );

BOOST_REQUIRE_EQUAL( core_sym::from_string("1000000000.0000"), get_balance("eosio") + get_balance("eosio.ramfee") + get_balance("eosio.stake") + get_balance("eosio.ram") );

// open ram for eosio.fees account
open( "eosio.fees"_n, core_symbol );
BOOST_REQUIRE_EQUAL( asset(0, core_symbol), get_balance( "eosio.fees", core_symbol ) );
}

enum class setup_level {
Expand Down Expand Up @@ -836,6 +840,14 @@ class eosio_system_tester : public TESTER {
);
}

void open( const name& owner, const symbol& symbolname, const name& manager = config::system_account_name) {
base_tester::push_action( "eosio.token"_n, "open"_n, manager, mutable_variant_object()
("owner", owner)
("symbol", symbolname )
("ram_payer", manager)
);
}

void transfer( const name& from, std::string_view to, const asset& amount, const name& manager = config::system_account_name ) {
transfer( from, name(to), amount, manager );
}
Expand Down
135 changes: 135 additions & 0 deletions tests/eosio.system_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2263,6 +2263,141 @@ BOOST_FIXTURE_TEST_CASE(producer_pay, eosio_system_tester, * boost::unit_test::t

} FC_LOG_AND_RETHROW()


BOOST_FIXTURE_TEST_CASE(adjust_chain_inflation, eosio_system_tester, * boost::unit_test::tolerance(1e-10)) try {

const double continuous_rate = 0.04879;
const double usecs_per_year = 52 * 7 * 24 * 3600 * 1000000ll;
const double secs_per_year = 52 * 7 * 24 * 3600;
const int64_t useconds_per_day = (int64_t)24 * 3600 * 1000'000ll;

const asset large_asset = core_sym::from_string("80.0000");
create_account_with_resources( "defproducera"_n, config::system_account_name, core_sym::from_string("1.0000"), false, large_asset, large_asset );
create_account_with_resources( "defproducerb"_n, config::system_account_name, core_sym::from_string("1.0000"), false, large_asset, large_asset );
create_account_with_resources( "defproducerc"_n, config::system_account_name, core_sym::from_string("1.0000"), false, large_asset, large_asset );

create_account_with_resources( "producvotera"_n, config::system_account_name, core_sym::from_string("1.0000"), false, large_asset, large_asset );
create_account_with_resources( "producvoterb"_n, config::system_account_name, core_sym::from_string("1.0000"), false, large_asset, large_asset );

BOOST_REQUIRE_EQUAL(success(), regproducer("defproducera"_n));
produce_block(fc::hours(24));
auto prod = get_producer_info( "defproducera"_n );
BOOST_REQUIRE_EQUAL("defproducera", prod["owner"].as_string());
BOOST_REQUIRE_EQUAL(0, prod["total_votes"].as_double());

transfer( config::system_account_name, "producvotera", core_sym::from_string("400000000.0000"), config::system_account_name);
BOOST_REQUIRE_EQUAL(success(), stake("producvotera", core_sym::from_string("100000000.0000"), core_sym::from_string("100000000.0000")));
BOOST_REQUIRE_EQUAL(success(), vote( "producvotera"_n, { "defproducera"_n }));

// Reduce Inflation Rate
// Simulates a scenario where the tokenomics can adjust the inflation rate.
{
produce_blocks(50);

const auto initial_global_state = get_global_state();
const uint64_t initial_claim_time = microseconds_since_epoch_of_iso_string( initial_global_state["last_pervote_bucket_fill"] );
const int64_t initial_pervote_bucket = initial_global_state["pervote_bucket"].as<int64_t>();
const int64_t initial_perblock_bucket = initial_global_state["perblock_bucket"].as<int64_t>();
const int64_t initial_savings = get_balance("eosio.saving"_n).get_amount();

prod = get_producer_info("defproducera");
const uint32_t unpaid_blocks = prod["unpaid_blocks"].as<uint32_t>();
BOOST_REQUIRE(1 < unpaid_blocks);


const asset initial_supply = get_token_supply();
const asset initial_balance = get_balance("defproducera"_n);
transfer(config::system_account_name, "eosio.fees", core_sym::from_string("1.0000"), config::system_account_name);
const asset init_account_fees = get_balance("eosio.fees"_n);
BOOST_TEST_MESSAGE("init_account_fees: " << init_account_fees.get_amount());

BOOST_REQUIRE_EQUAL(success(), push_action("defproducera"_n, "claimrewards"_n, mvo()("owner", "defproducera")));

const auto global_state = get_global_state();
const uint64_t claim_time = microseconds_since_epoch_of_iso_string( global_state["last_pervote_bucket_fill"] );
const int64_t pervote_bucket = global_state["pervote_bucket"].as<int64_t>();
const int64_t perblock_bucket = global_state["perblock_bucket"].as<int64_t>();
const int64_t savings = get_balance("eosio.saving"_n).get_amount();

prod = get_producer_info("defproducera");
const asset supply = get_token_supply();
const asset balance = get_balance("defproducera"_n);
const asset account_fees = get_balance("eosio.fees"_n);
BOOST_REQUIRE_EQUAL(0, account_fees.get_amount());

BOOST_REQUIRE_EQUAL(claim_time, microseconds_since_epoch_of_iso_string( prod["last_claim_time"] ));

auto usecs_between_fills = claim_time - initial_claim_time;
int32_t secs_between_fills = usecs_between_fills/1000000;
uint64_t distribute_tokens = (initial_supply.get_amount() * double(secs_between_fills) * continuous_rate) / secs_per_year;
BOOST_REQUIRE_EQUAL(0, initial_savings);
BOOST_REQUIRE_EQUAL(0, initial_perblock_bucket);
BOOST_REQUIRE_EQUAL(0, initial_pervote_bucket);

BOOST_REQUIRE_EQUAL(distribute_tokens - init_account_fees.get_amount(), supply.get_amount() - initial_supply.get_amount());
BOOST_REQUIRE_EQUAL(int64_t(distribute_tokens - (distribute_tokens / 5) * 3), savings - initial_savings);
BOOST_REQUIRE_EQUAL(int64_t(distribute_tokens / 5), balance.get_amount() - initial_balance.get_amount());

int64_t from_perblock_bucket = int64_t( initial_supply.get_amount() * double(secs_between_fills) * (continuous_rate / 5.) / secs_per_year ) ;
int64_t from_pervote_bucket = 0;


if (from_pervote_bucket >= 100 * 10000) {
BOOST_REQUIRE_EQUAL(from_perblock_bucket + from_pervote_bucket, balance.get_amount() - initial_balance.get_amount());
BOOST_REQUIRE_EQUAL(0, pervote_bucket);
} else {
BOOST_REQUIRE_EQUAL(from_perblock_bucket, balance.get_amount() - initial_balance.get_amount());
BOOST_REQUIRE_EQUAL(from_pervote_bucket, pervote_bucket);
}
}

// Wait 1 day
produce_block(fc::seconds(24 * 3600));

// No Inflation Rate Adjustment with Token Burn
// Evaluates the situation where the tokenomics covers inflation rate and tests the burning mechanism for remaining tokens.
{
produce_blocks(100);

const auto initial_global_state = get_global_state();
const uint64_t initial_claim_time = microseconds_since_epoch_of_iso_string( initial_global_state["last_pervote_bucket_fill"] );
const int64_t initial_pervote_bucket = initial_global_state["pervote_bucket"].as<int64_t>();
const int64_t initial_perblock_bucket = initial_global_state["perblock_bucket"].as<int64_t>();
const int64_t initial_savings = get_balance("eosio.saving"_n).get_amount();

prod = get_producer_info("defproducera");
const uint32_t unpaid_blocks = prod["unpaid_blocks"].as<uint32_t>();
BOOST_REQUIRE(1 < unpaid_blocks);

const asset initial_supply = get_token_supply();
transfer(config::system_account_name, "eosio.fees", core_sym::from_string("200000.0000"), config::system_account_name);
const asset init_account_fees = get_balance("eosio.fees"_n);

BOOST_REQUIRE_EQUAL(success(), push_action("defproducera"_n, "claimrewards"_n, mvo()("owner", "defproducera")));

const auto global_state = get_global_state();
const uint64_t claim_time = microseconds_since_epoch_of_iso_string( global_state["last_pervote_bucket_fill"] );
const int64_t pervote_bucket = global_state["pervote_bucket"].as<int64_t>();
const int64_t perblock_bucket = global_state["perblock_bucket"].as<int64_t>();
const int64_t savings = get_balance("eosio.saving"_n).get_amount();

prod = get_producer_info("defproducera");
const asset supply = get_token_supply();
const asset account_fees = get_balance("eosio.fees"_n);
BOOST_REQUIRE_EQUAL(account_fees.get_amount(), 0);

BOOST_REQUIRE_EQUAL(claim_time, microseconds_since_epoch_of_iso_string( prod["last_claim_time"] ));

auto usecs_between_fills = claim_time - initial_claim_time;
int32_t secs_between_fills = usecs_between_fills/1000000;
int64_t distribute_tokens = (initial_supply.get_amount() * double(usecs_between_fills) * continuous_rate) / usecs_per_year;

BOOST_REQUIRE_EQUAL(init_account_fees.get_amount() - distribute_tokens, initial_supply.get_amount() - supply.get_amount());
BOOST_REQUIRE_EQUAL(int64_t(distribute_tokens - (distribute_tokens / 5) * 3), savings - initial_savings);

}
} FC_LOG_AND_RETHROW()

BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::unit_test::tolerance(1e-10)) try {

auto within_one = [](int64_t a, int64_t b) -> bool { return std::abs( a - b ) <= 1; };
Expand Down