operation_tests2.cpp: Implement force_settlement_test
This commit is contained in:
parent
cb2031a1e4
commit
5f12f3f445
3 changed files with 187 additions and 122 deletions
|
|
@ -740,7 +740,7 @@ void database_fixture::force_global_settle( const asset_object& what, const pric
|
|||
verify_asset_supplies(db);
|
||||
} FC_CAPTURE_AND_RETHROW( (what)(p) ) }
|
||||
|
||||
void database_fixture::force_settle( const account_object& who, asset what )
|
||||
operation_result database_fixture::force_settle( const account_object& who, asset what )
|
||||
{ try {
|
||||
trx.set_expiration(db.head_block_time() + fc::minutes(1));
|
||||
trx.operations.clear();
|
||||
|
|
@ -750,9 +750,11 @@ void database_fixture::force_settle( const account_object& who, asset what )
|
|||
trx.operations.push_back(sop);
|
||||
for( auto& op : trx.operations ) db.current_fee_schedule().set_fee(op);
|
||||
trx.validate();
|
||||
db.push_transaction(trx, ~0);
|
||||
processed_transaction ptx = db.push_transaction(trx, ~0);
|
||||
const operation_result& op_result = ptx.operation_results.front();
|
||||
trx.operations.clear();
|
||||
verify_asset_supplies(db);
|
||||
return op_result;
|
||||
} FC_CAPTURE_AND_RETHROW( (who)(what) ) }
|
||||
|
||||
const call_order_object* database_fixture::borrow(const account_object& who, asset what, asset collateral)
|
||||
|
|
|
|||
|
|
@ -190,9 +190,9 @@ struct database_fixture {
|
|||
);
|
||||
|
||||
void force_global_settle(const asset_object& what, const price& p);
|
||||
void force_settle(account_id_type who, asset what)
|
||||
{ force_settle(who(db), what); }
|
||||
void force_settle(const account_object& who, asset what);
|
||||
operation_result force_settle(account_id_type who, asset what)
|
||||
{ return force_settle(who(db), what); }
|
||||
operation_result force_settle(const account_object& who, asset what);
|
||||
void update_feed_producers(asset_id_type mia, flat_set<account_id_type> producers)
|
||||
{ update_feed_producers(mia(db), producers); }
|
||||
void update_feed_producers(const asset_object& mia, flat_set<account_id_type> producers);
|
||||
|
|
|
|||
|
|
@ -820,128 +820,191 @@ BOOST_AUTO_TEST_CASE( burn_worker_test )
|
|||
BOOST_CHECK_EQUAL( get_balance(GRAPHENE_NULL_ACCOUNT, asset_id_type()), 2000 );
|
||||
}FC_LOG_AND_RETHROW()}
|
||||
|
||||
BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES( unimp_force_settlement_unavailable, 1 )
|
||||
BOOST_AUTO_TEST_CASE( unimp_force_settlement_unavailable )
|
||||
BOOST_AUTO_TEST_CASE( force_settle_test )
|
||||
{
|
||||
BOOST_FAIL( "TODO - Reimplement this" );
|
||||
/*
|
||||
try {
|
||||
auto private_key = init_account_priv_key;
|
||||
auto private_key = generate_private_key("committee");
|
||||
>>>>>>> short_refactor
|
||||
account_id_type nathan_id = create_account("nathan").get_id();
|
||||
account_id_type shorter1_id = create_account("shorter1").get_id();
|
||||
account_id_type shorter2_id = create_account("shorter2").get_id();
|
||||
account_id_type shorter3_id = create_account("shorter3").get_id();
|
||||
transfer(account_id_type()(db), nathan_id(db), asset(100000000));
|
||||
transfer(account_id_type()(db), shorter1_id(db), asset(100000000));
|
||||
transfer(account_id_type()(db), shorter2_id(db), asset(100000000));
|
||||
transfer(account_id_type()(db), shorter3_id(db), asset(100000000));
|
||||
asset_id_type bit_usd = create_bitasset("BITUSD", GRAPHENE_TEMP_ACCOUNT, 0, disable_force_settle).get_id();
|
||||
FC_ASSERT( bit_usd(db).is_market_issued() );
|
||||
try
|
||||
{
|
||||
asset_update_bitasset_operation op;
|
||||
op.asset_to_update = bit_usd;
|
||||
op.issuer = bit_usd(db).issuer;
|
||||
op.new_options = bit_usd(db).bitasset_data(db).options;
|
||||
op.new_options.maximum_force_settlement_volume = 9000;
|
||||
trx.clear();
|
||||
trx.operations.push_back(op);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.clear();
|
||||
ACTORS( (nathan)(shorter1)(shorter2)(shorter3)(shorter4)(shorter5) );
|
||||
|
||||
int64_t initial_balance = 100000000;
|
||||
|
||||
transfer(account_id_type()(db), shorter1_id(db), asset(initial_balance));
|
||||
transfer(account_id_type()(db), shorter2_id(db), asset(initial_balance));
|
||||
transfer(account_id_type()(db), shorter3_id(db), asset(initial_balance));
|
||||
transfer(account_id_type()(db), shorter4_id(db), asset(initial_balance));
|
||||
transfer(account_id_type()(db), shorter5_id(db), asset(initial_balance));
|
||||
|
||||
asset_id_type bitusd_id = create_bitasset(
|
||||
"BITUSD",
|
||||
nathan_id,
|
||||
100,
|
||||
disable_force_settle
|
||||
).id;
|
||||
|
||||
asset_id_type core_id = asset_id_type();
|
||||
|
||||
auto update_bitasset_options = [&]( asset_id_type asset_id,
|
||||
std::function< void(bitasset_options&) > update_function )
|
||||
{
|
||||
const asset_object& _asset = asset_id(db);
|
||||
asset_update_bitasset_operation op;
|
||||
op.asset_to_update = asset_id;
|
||||
op.issuer = _asset.issuer;
|
||||
op.new_options = (*_asset.bitasset_data_id)(db).options;
|
||||
update_function( op.new_options );
|
||||
signed_transaction tx;
|
||||
tx.operations.push_back( op );
|
||||
tx.set_expiration( db.head_block_time() + fc::minutes(5) );
|
||||
PUSH_TX( db, tx, ~0 );
|
||||
} ;
|
||||
|
||||
auto update_asset_options = [&]( asset_id_type asset_id,
|
||||
std::function< void(asset_options&) > update_function )
|
||||
{
|
||||
const asset_object& _asset = asset_id(db);
|
||||
asset_update_operation op;
|
||||
op.asset_to_update = asset_id;
|
||||
op.issuer = _asset.issuer;
|
||||
op.new_options = _asset.options;
|
||||
update_function( op.new_options );
|
||||
signed_transaction tx;
|
||||
tx.operations.push_back( op );
|
||||
tx.set_expiration( db.head_block_time() + fc::minutes(5) );
|
||||
PUSH_TX( db, tx, ~0 );
|
||||
} ;
|
||||
|
||||
BOOST_TEST_MESSAGE( "Update maximum_force_settlement_volume = 9000" );
|
||||
|
||||
BOOST_CHECK( bitusd_id(db).is_market_issued() );
|
||||
update_bitasset_options( bitusd_id, [&]( bitasset_options& new_options )
|
||||
{ new_options.maximum_force_settlement_volume = 9000; } );
|
||||
|
||||
BOOST_TEST_MESSAGE( "Publish price feed" );
|
||||
|
||||
update_feed_producers( bitusd_id, { nathan_id } );
|
||||
{
|
||||
price_feed feed;
|
||||
feed.settlement_price = price( asset( 1, bitusd_id ), asset( 1, core_id ) );
|
||||
publish_feed( bitusd_id, nathan_id, feed );
|
||||
}
|
||||
|
||||
BOOST_TEST_MESSAGE( "First short batch" );
|
||||
|
||||
call_order_id_type call1_id = borrow( shorter1_id, asset(1000, bitusd_id), asset(2*1000, core_id) )->id; // 2.0000
|
||||
call_order_id_type call2_id = borrow( shorter2_id, asset(2000, bitusd_id), asset(2*1999, core_id) )->id; // 1.9990
|
||||
call_order_id_type call3_id = borrow( shorter3_id, asset(3000, bitusd_id), asset(2*2890, core_id) )->id; // 1.9267
|
||||
call_order_id_type call4_id = borrow( shorter4_id, asset(4000, bitusd_id), asset(2*3950, core_id) )->id; // 1.9750
|
||||
call_order_id_type call5_id = borrow( shorter5_id, asset(5000, bitusd_id), asset(2*4900, core_id) )->id; // 1.9600
|
||||
|
||||
transfer( shorter1_id, nathan_id, asset(1000, bitusd_id) );
|
||||
transfer( shorter2_id, nathan_id, asset(2000, bitusd_id) );
|
||||
transfer( shorter3_id, nathan_id, asset(3000, bitusd_id) );
|
||||
transfer( shorter4_id, nathan_id, asset(4000, bitusd_id) );
|
||||
transfer( shorter5_id, nathan_id, asset(5000, bitusd_id) );
|
||||
|
||||
BOOST_CHECK_EQUAL( get_balance(nathan_id, bitusd_id), 15000);
|
||||
BOOST_CHECK_EQUAL( get_balance(nathan_id, core_id), 0);
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter1_id, core_id), initial_balance-2000 );
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter2_id, core_id), initial_balance-3998 );
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter3_id, core_id), initial_balance-5780 );
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter4_id, core_id), initial_balance-7900 );
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter5_id, core_id), initial_balance-9800 );
|
||||
|
||||
BOOST_TEST_MESSAGE( "Update force_settlement_delay_sec = 100, force_settlement_offset_percent = 1%" );
|
||||
|
||||
update_bitasset_options( bitusd_id, [&]( bitasset_options& new_options )
|
||||
{ new_options.force_settlement_delay_sec = 100;
|
||||
new_options.force_settlement_offset_percent = GRAPHENE_1_PERCENT; } );
|
||||
|
||||
// Force settlement is disabled; check that it fails
|
||||
GRAPHENE_REQUIRE_THROW( force_settle( nathan_id, asset( 50, bitusd_id ) ), fc::exception );
|
||||
|
||||
update_asset_options( bitusd_id, [&]( asset_options& new_options )
|
||||
{ new_options.flags &= ~disable_force_settle; } );
|
||||
|
||||
// Can't settle more BitUSD than you own
|
||||
GRAPHENE_REQUIRE_THROW( force_settle( nathan_id, asset( 999999, bitusd_id ) ), fc::exception );
|
||||
|
||||
// settle3 should be least collateralized order according to index
|
||||
BOOST_CHECK( db.get_index_type<call_order_index>().indices().get<by_collateral>().begin()->id == call3_id );
|
||||
BOOST_CHECK_EQUAL( call3_id(db).debt.value, 3000 );
|
||||
|
||||
BOOST_TEST_MESSAGE( "Verify partial settlement of call" );
|
||||
// Partially settle a call
|
||||
force_settlement_id_type settle_id = force_settle( nathan_id, asset( 50, bitusd_id ) ).get< object_id_type >();
|
||||
|
||||
// Call does not take effect immediately
|
||||
BOOST_CHECK_EQUAL( get_balance(nathan_id, bitusd_id), 14950);
|
||||
BOOST_CHECK_EQUAL( settle_id(db).balance.amount.value, 50);
|
||||
BOOST_CHECK_EQUAL( call3_id(db).debt.value, 3000 );
|
||||
BOOST_CHECK_EQUAL( call3_id(db).collateral.value, 5780 );
|
||||
BOOST_CHECK( settle_id(db).owner == nathan_id );
|
||||
|
||||
// Wait for settlement to take effect
|
||||
generate_blocks(settle_id(db).settlement_date);
|
||||
BOOST_CHECK(db.find(settle_id) == nullptr);
|
||||
BOOST_CHECK_EQUAL( get_balance(nathan_id, bitusd_id), 14950);
|
||||
BOOST_CHECK_EQUAL( get_balance(nathan_id, core_id), 49 ); // 1% force_settlement_offset_percent (rounded unfavorably)
|
||||
BOOST_CHECK_EQUAL( call3_id(db).debt.value, 2950 );
|
||||
BOOST_CHECK_EQUAL( call3_id(db).collateral.value, 5731 ); // 5731 == 5780-49
|
||||
|
||||
BOOST_CHECK( db.get_index_type<call_order_index>().indices().get<by_collateral>().begin()->id == call3_id );
|
||||
|
||||
BOOST_TEST_MESSAGE( "Verify pending settlement is cancelled when asset's force_settle is disabled" );
|
||||
// Ensure pending settlement is cancelled when force settle is disabled
|
||||
settle_id = force_settle( nathan_id, asset( 50, bitusd_id ) ).get< object_id_type >();
|
||||
|
||||
BOOST_CHECK( !db.get_index_type<force_settlement_index>().indices().empty() );
|
||||
update_asset_options( bitusd_id, [&]( asset_options& new_options )
|
||||
{ new_options.flags |= disable_force_settle; } );
|
||||
BOOST_CHECK( db.get_index_type<force_settlement_index>().indices().empty() );
|
||||
update_asset_options( bitusd_id, [&]( asset_options& new_options )
|
||||
{ new_options.flags &= ~disable_force_settle; } );
|
||||
|
||||
BOOST_TEST_MESSAGE( "Perform iterative settlement" );
|
||||
settle_id = force_settle( nathan_id, asset( 12500, bitusd_id ) ).get< object_id_type >();
|
||||
|
||||
// c3 2950 : 5731 1.9427 fully settled
|
||||
// c5 5000 : 9800 1.9600 fully settled
|
||||
// c4 4000 : 7900 1.9750 fully settled
|
||||
// c2 2000 : 3998 1.9990 550 settled
|
||||
// c1 1000 : 2000 2.0000
|
||||
|
||||
generate_blocks( settle_id(db).settlement_date );
|
||||
|
||||
int64_t call1_payout = 0;
|
||||
int64_t call2_payout = 550*99/100;
|
||||
int64_t call3_payout = 49 + 2950*99/100;
|
||||
int64_t call4_payout = 4000*99/100;
|
||||
int64_t call5_payout = 5000*99/100;
|
||||
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter1_id, core_id), initial_balance-2*1000 ); // full collat still tied up
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter2_id, core_id), initial_balance-2*1999 ); // full collat still tied up
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter3_id, core_id), initial_balance-call3_payout ); // initial balance minus transfer to Nathan (as BitUSD)
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter4_id, core_id), initial_balance-call4_payout ); // initial balance minus transfer to Nathan (as BitUSD)
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter5_id, core_id), initial_balance-call5_payout ); // initial balance minus transfer to Nathan (as BitUSD)
|
||||
|
||||
BOOST_CHECK_EQUAL( get_balance(nathan_id, core_id),
|
||||
call1_payout + call2_payout + call3_payout + call4_payout + call5_payout );
|
||||
|
||||
BOOST_CHECK( db.find(call3_id) == nullptr );
|
||||
BOOST_CHECK( db.find(call4_id) == nullptr );
|
||||
BOOST_CHECK( db.find(call5_id) == nullptr );
|
||||
|
||||
BOOST_REQUIRE( db.find(call1_id) != nullptr );
|
||||
BOOST_REQUIRE( db.find(call2_id) != nullptr );
|
||||
|
||||
BOOST_CHECK_EQUAL( call1_id(db).debt.value, 1000 );
|
||||
BOOST_CHECK_EQUAL( call1_id(db).collateral.value, 2000 );
|
||||
|
||||
BOOST_CHECK_EQUAL( call2_id(db).debt.value, 2000-550 );
|
||||
BOOST_CHECK_EQUAL( call2_id(db).collateral.value, 3998-call2_payout );
|
||||
}
|
||||
generate_block();
|
||||
|
||||
create_short(shorter1_id(db), asset(1000, bit_usd), asset(1000));
|
||||
create_sell_order(nathan_id(db), asset(1000), asset(1000, bit_usd));
|
||||
create_short(shorter2_id(db), asset(2000, bit_usd), asset(1999));
|
||||
create_sell_order(nathan_id(db), asset(1999), asset(2000, bit_usd));
|
||||
create_short(shorter3_id(db), asset(3000, bit_usd), asset(2990));
|
||||
create_sell_order(nathan_id(db), asset(2990), asset(3000, bit_usd));
|
||||
BOOST_CHECK_EQUAL(get_balance(nathan_id, bit_usd), 6000);
|
||||
|
||||
transfer(nathan_id(db), account_id_type()(db), db.get_balance(nathan_id, asset_id_type()));
|
||||
|
||||
catch(fc::exception& e)
|
||||
{
|
||||
asset_update_bitasset_operation uop;
|
||||
uop.issuer = bit_usd(db).issuer;
|
||||
uop.asset_to_update = bit_usd;
|
||||
uop.new_options = bit_usd(db).bitasset_data(db).options;
|
||||
uop.new_options.force_settlement_delay_sec = 100;
|
||||
uop.new_options.force_settlement_offset_percent = 100;
|
||||
trx.operations.push_back(uop);
|
||||
} {
|
||||
asset_update_feed_producers_operation uop;
|
||||
uop.asset_to_update = bit_usd;
|
||||
uop.issuer = bit_usd(db).issuer;
|
||||
uop.new_feed_producers = {nathan_id};
|
||||
trx.operations.push_back(uop);
|
||||
} {
|
||||
asset_publish_feed_operation pop;
|
||||
pop.asset_id = bit_usd;
|
||||
pop.publisher = nathan_id;
|
||||
price_feed feed;
|
||||
feed.settlement_price = price(asset(1),asset(1, bit_usd));
|
||||
feed.call_limit = price::min(0, bit_usd);
|
||||
pop.feed = feed;
|
||||
trx.operations.push_back(pop);
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
trx.sign(key_id_type(),private_key);
|
||||
PUSH_TX( db, trx );
|
||||
trx.clear();
|
||||
|
||||
asset_settle_operation sop;
|
||||
sop.account = nathan_id;
|
||||
sop.amount = asset(50, bit_usd);
|
||||
trx.operations = {sop};
|
||||
//Force settlement is disabled; check that it fails
|
||||
GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, ~0 ), fc::exception);
|
||||
{
|
||||
//Enable force settlement
|
||||
asset_update_operation op;
|
||||
op.issuer = bit_usd(db).issuer;
|
||||
op.asset_to_update = bit_usd;
|
||||
op.new_options = bit_usd(db).options;
|
||||
op.new_options.flags &= ~disable_force_settle;
|
||||
trx.operations = {op};
|
||||
trx.sign(key_id_type(), private_key);
|
||||
PUSH_TX( db, trx );
|
||||
trx.operations = {sop};
|
||||
}
|
||||
REQUIRE_THROW_WITH_VALUE(sop, amount, asset(999999, bit_usd));
|
||||
trx.operations.back() = sop;
|
||||
trx.sign(key_id_type(),private_key);
|
||||
|
||||
//Partially settle a call
|
||||
force_settlement_id_type settle_id = PUSH_TX( db, trx ).operation_results.front().get<object_id_type>();
|
||||
trx.clear();
|
||||
call_order_id_type call_id = db.get_index_type<call_order_index>().indices().get<by_collateral>().begin()->id;
|
||||
BOOST_CHECK_EQUAL(settle_id(db).balance.amount.value, 50);
|
||||
BOOST_CHECK_EQUAL(call_id(db).debt.value, 3000);
|
||||
BOOST_CHECK(settle_id(db).owner == nathan_id);
|
||||
|
||||
generate_blocks(settle_id(db).settlement_date);
|
||||
BOOST_CHECK(db.find(settle_id) == nullptr);
|
||||
BOOST_CHECK_EQUAL(get_balance(nathan_id, asset_id_type()), 49);
|
||||
BOOST_CHECK_EQUAL(call_id(db).debt.value, 2950);
|
||||
|
||||
{
|
||||
//Disable force settlement
|
||||
asset_update_operation op;
|
||||
op.issuer = bit_usd(db).issuer;
|
||||
op.asset_to_update = bit_usd;
|
||||
op.new_options = bit_usd(db).options;
|
||||
op.new_options.flags |= disable_force_settle;
|
||||
trx.operations.push_back(op);
|
||||
trx.set_reference_block(db.head_block_id()); trx.set_expiration( db.head_block_time() + fc::seconds( 3 * db.get_global_properties().parameters.block_interval ) );
|
||||
trx.sign(key_id_type(), private_key);
|
||||
PUSH_TX( db, trx );
|
||||
//Check that force settlements were all canceled
|
||||
BOOST_CHECK(db.get_index_type<force_settlement_index>().indices().empty());
|
||||
BOOST_CHECK_EQUAL(get_balance(nathan_id, bit_usd), bit_usd(db).dynamic_data(db).current_supply.value);
|
||||
}
|
||||
} FC_LOG_AND_RETHROW()
|
||||
*/
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( assert_op_test )
|
||||
|
|
|
|||
Loading…
Reference in a new issue