Skip to content

Commit

Permalink
Merge pull request #200 from peerplays-network/feature/BLOCKBACK-166
Browse files Browse the repository at this point in the history
[BLOCKBACK-166] GPOS - dividend distribution for UIAs
  • Loading branch information
oxarbitrage authored Oct 26, 2019
2 parents 46dab25 + a8423f1 commit aef57f1
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 2 deletions.
4 changes: 2 additions & 2 deletions libraries/chain/db_maint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1108,8 +1108,8 @@ void schedule_pending_dividend_balances(database& db,
dlog("Crediting committee_account with ${amount}",
("amount", asset(full_shares_to_credit - shares_to_credit, payout_asset_type)));
db.adjust_balance(dividend_data.dividend_distribution_account,
-(full_shares_to_credit - shares_to_credit));
db.adjust_balance(account_id_type(0), full_shares_to_credit - shares_to_credit);
-asset(full_shares_to_credit - shares_to_credit, payout_asset_type));
db.adjust_balance(account_id_type(0), asset(full_shares_to_credit - shares_to_credit, payout_asset_type));
}

remaining_amount_to_distribute = credit_account(db,
Expand Down
170 changes: 170 additions & 0 deletions tests/tests/gpos_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,176 @@ BOOST_AUTO_TEST_CASE( dividends )
}
}

BOOST_AUTO_TEST_CASE( gpos_basic_dividend_distribution_to_core_asset )
{

using namespace graphene;
ACTORS((alice)(bob)(carol)(dave));
try {

const auto& core = asset_id_type()(db);
BOOST_TEST_MESSAGE("Creating test asset");
{
asset_create_operation creator;
creator.issuer = account_id_type();
creator.fee = asset();
creator.symbol = "TESTB";
creator.common_options.max_supply = 100000000;
creator.precision = 2;
creator.common_options.market_fee_percent = GRAPHENE_MAX_MARKET_FEE_PERCENT/100; /*1%*/
creator.common_options.issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK;
creator.common_options.flags = charge_market_fee;
creator.common_options.core_exchange_rate = price({asset(2),asset(1,asset_id_type(1))});
trx.operations.push_back(std::move(creator));
set_expiration(db, trx);
PUSH_TX( db, trx, ~0 );
trx.operations.clear();
}

// pass hardfork
generate_blocks( HARDFORK_GPOS_TIME );
generate_block();

const auto& dividend_holder_asset_object = asset_id_type(0)(db);
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db);
const account_object& alice = get_account("alice");
const account_object& bob = get_account("bob");
const account_object& carol = get_account("carol");
const account_object& dave = get_account("dave");
const auto& test_asset_object = get_asset("TESTB");

auto issue_asset_to_account = [&](const asset_object& asset_to_issue, const account_object& destination_account, int64_t amount_to_issue)
{
asset_issue_operation op;
op.issuer = asset_to_issue.issuer;
op.asset_to_issue = asset(amount_to_issue, asset_to_issue.id);
op.issue_to_account = destination_account.id;
trx.operations.push_back( op );
set_expiration(db, trx);
PUSH_TX( db, trx, ~0 );
trx.operations.clear();
};

auto verify_pending_balance = [&](const account_object& holder_account_obj, const asset_object& payout_asset_obj, int64_t expected_balance) {
int64_t pending_balance = get_dividend_pending_payout_balance(dividend_holder_asset_object.id,
holder_account_obj.id,
payout_asset_obj.id);
BOOST_CHECK_EQUAL(pending_balance, expected_balance);
};

auto advance_to_next_payout_time = [&]() {
// Advance to the next upcoming payout time
BOOST_REQUIRE(dividend_data.options.next_payout_time);
fc::time_point_sec next_payout_scheduled_time = *dividend_data.options.next_payout_time;
idump((next_payout_scheduled_time));
// generate blocks up to the next scheduled time
generate_blocks(next_payout_scheduled_time);
// if the scheduled time fell on a maintenance interval, then we should have paid out.
// if not, we need to advance to the next maintenance interval to trigger the payout
if (dividend_data.options.next_payout_time)
{
// we know there was a next_payout_time set when we entered this, so if
// it has been cleared, we must have already processed payouts, no need to
// further advance time.
BOOST_REQUIRE(dividend_data.options.next_payout_time);
if (*dividend_data.options.next_payout_time == next_payout_scheduled_time)
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
generate_block(); // get the maintenance skip slots out of the way
}
idump((db.head_block_time()));
};

// the first test will be testing pending balances, so we need to hit a
// maintenance interval that isn't the payout interval. Payout is
// every 3 days, maintenance interval is every 1 day.
advance_to_next_payout_time();

// Set up the first test, issue alice, bob, and carol, and dave each 1/4 of the total
// supply of the core asset.
// Then deposit 400 TEST in the distribution account, and see that they
// each are credited 100 TEST.
transfer( committee_account(db), alice, asset( 250000000000000 ) );
transfer( committee_account(db), bob, asset( 250000000000000 ) );
transfer( committee_account(db), carol, asset( 250000000000000 ) );
transfer( committee_account(db), dave, asset( 250000000000000 ) );

// create vesting balance
// bob has not vested anything
create_vesting(alice_id, core.amount(25000000), vesting_balance_type::gpos);
create_vesting(carol_id, core.amount(25000000), vesting_balance_type::gpos);
create_vesting(dave_id, core.amount(25000000), vesting_balance_type::gpos);

// need to vote to get paid
// carol doesn't participate in voting
auto witness1 = witness_id_type(1)(db);
vote_for(alice_id, witness1.vote_id, alice_private_key);
vote_for(bob_id, witness1.vote_id, bob_private_key);
vote_for(dave_id, witness1.vote_id, dave_private_key);

// issuing 30000 TESTB to the dividend account
// alice and dave should receive 10000 TESTB as they have gpos vesting and
// participated in voting
// bob should not receive any TESTB as he doesn't have gpos vested
// carol should not receive any TESTB as she doesn't participated in voting
// remaining 10000 TESTB should be deposited in commitee_accoount.
BOOST_TEST_MESSAGE("Issuing 30000 TESTB to the dividend account");
issue_asset_to_account(test_asset_object, dividend_distribution_account, 30000);

generate_block();

BOOST_TEST_MESSAGE( "Generating blocks until next maintenance interval" );
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
generate_block(); // get the maintenance skip slots out of the way

verify_pending_balance(alice, test_asset_object, 10000);
verify_pending_balance(bob, test_asset_object, 0);
verify_pending_balance(carol, test_asset_object, 0);
verify_pending_balance(dave, test_asset_object, 10000);


advance_to_next_payout_time();

generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
generate_block(); // get the maintenance skip slots out of the way


auto verify_dividend_payout_operations = [&](const account_object& destination_account, const asset& expected_payout)
{
BOOST_TEST_MESSAGE("Verifying the virtual op was created");
const account_transaction_history_index& hist_idx = db.get_index_type<account_transaction_history_index>();
auto account_history_range = hist_idx.indices().get<by_seq>().equal_range(boost::make_tuple(destination_account.id));
BOOST_REQUIRE(account_history_range.first != account_history_range.second);
const operation_history_object& history_object = std::prev(account_history_range.second)->operation_id(db);
const asset_dividend_distribution_operation& distribution_operation = history_object.op.get<asset_dividend_distribution_operation>();
BOOST_CHECK(distribution_operation.account_id == destination_account.id);
BOOST_CHECK(std::find(distribution_operation.amounts.begin(), distribution_operation.amounts.end(), expected_payout)
!= distribution_operation.amounts.end());
};

BOOST_TEST_MESSAGE("Verifying the payouts");
BOOST_CHECK_EQUAL(get_balance(alice, test_asset_object), 10000);
verify_dividend_payout_operations(alice, asset(10000, test_asset_object.id));
verify_pending_balance(alice, test_asset_object, 0);

BOOST_CHECK_EQUAL(get_balance(bob, test_asset_object), 0);
verify_pending_balance(bob, test_asset_object, 0);

BOOST_CHECK_EQUAL(get_balance(carol, test_asset_object), 0);
verify_pending_balance(carol, test_asset_object, 0);

BOOST_CHECK_EQUAL(get_balance(dave, test_asset_object), 10000);
verify_dividend_payout_operations(dave, asset(10000, test_asset_object.id));
verify_pending_balance(dave, test_asset_object, 0);

BOOST_CHECK_EQUAL(get_balance(account_id_type(0)(db), test_asset_object), 10000);
} catch(fc::exception& e) {
edump((e.to_detail_string()));
throw;
}
}


BOOST_AUTO_TEST_CASE( voting )
{
ACTORS((alice)(bob));
Expand Down

0 comments on commit aef57f1

Please sign in to comment.