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

Fix issues related to global settlement introduced in PR #2721 #2727

Merged
merged 4 commits into from
Mar 13, 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
3 changes: 2 additions & 1 deletion libraries/chain/asset_evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1201,7 +1201,8 @@ static optional<asset> pay_collateral_fees( database& d,
{
const auto& head_time = d.head_block_time();
bool after_core_hardfork_2591 = HARDFORK_CORE_2591_PASSED( head_time ); // Tighter peg (fill settlement at MCOP)
if( after_core_hardfork_2591 && !bitasset.current_feed.settlement_price.is_null() )
if( after_core_hardfork_2591 && !bitasset.is_prediction_market
&& !bitasset.current_feed.settlement_price.is_null() )
{
price fill_price = bitasset.get_margin_call_order_price();
try
Expand Down
2 changes: 1 addition & 1 deletion libraries/chain/db_market.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ void database::globally_settle_asset_impl( const asset_object& mia,
const limit_order_object* limit_ptr = find_settled_debt_order( bitasset.asset_id );
if( limit_ptr )
{
collateral_gathered.amount += limit_ptr->for_sale;
collateral_gathered.amount += limit_ptr->settled_collateral_amount;
remove( *limit_ptr );
}

Expand Down
34 changes: 24 additions & 10 deletions tests/tests/bsrm_basic_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1364,11 +1364,21 @@ BOOST_AUTO_TEST_CASE( manual_gs_test )

using bsrm_type = bitasset_options::black_swan_response_type;

// Several passes for each BSRM type
for( uint8_t i = 0; i <= 3; ++i )
// Several passes, for each BSRM type, before and after core-2591 hf
for( uint8_t i = 0; i < 8; ++i )
{
idump( (i) );
uint8_t bsrm = i % 4;

idump( (i)(bsrm) );

if( 4 == i )
{
// Advance to core-2591 hard fork
generate_blocks(HARDFORK_CORE_2591_TIME);
generate_block();
}

set_expiration( db, trx );
ACTORS((sam)(feeder)(borrower)(borrower2));

auto init_amount = 10000000 * GRAPHENE_BLOCKCHAIN_PRECISION;
Expand All @@ -1387,7 +1397,7 @@ BOOST_AUTO_TEST_CASE( manual_gs_test )
acop.common_options.issuer_permissions = ASSET_ISSUER_PERMISSION_ENABLE_BITS_MASK;
acop.bitasset_opts = bitasset_options();
acop.bitasset_opts->minimum_feeds = 1;
acop.bitasset_opts->extensions.value.black_swan_response_method = i;
acop.bitasset_opts->extensions.value.black_swan_response_method = bsrm;
acop.bitasset_opts->extensions.value.margin_call_fee_ratio = 11;

trx.operations.clear();
Expand All @@ -1396,7 +1406,7 @@ BOOST_AUTO_TEST_CASE( manual_gs_test )
const asset_object& mpa = db.get<asset_object>(ptx.operation_results[0].get<object_id_type>());
asset_id_type mpa_id = mpa.get_id();

BOOST_CHECK( mpa.bitasset_data(db).get_black_swan_response_method() == static_cast<bsrm_type>(i) );
BOOST_CHECK( mpa.bitasset_data(db).get_black_swan_response_method() == static_cast<bsrm_type>(bsrm) );
BOOST_CHECK( !mpa_id(db).bitasset_data(db).has_individual_settlement() );
BOOST_CHECK( !mpa_id(db).bitasset_data(db).has_settlement() );
BOOST_CHECK( !db.find_settled_debt_order(mpa_id) );
Expand Down Expand Up @@ -1431,7 +1441,7 @@ BOOST_AUTO_TEST_CASE( manual_gs_test )
const auto& check_result = [&]
{
BOOST_CHECK( mpa_id(db).bitasset_data(db).median_feed.settlement_price == f.settlement_price );
switch( static_cast<bsrm_type>(i) )
switch( static_cast<bsrm_type>(bsrm) )
{
case bsrm_type::global_settlement:
BOOST_CHECK( mpa_id(db).bitasset_data(db).get_black_swan_response_method()
Expand Down Expand Up @@ -1505,11 +1515,15 @@ BOOST_AUTO_TEST_CASE( manual_gs_test )

check_result();

// publish a new feed (collateral price rises)
f.settlement_price = price( asset(1000,mpa_id), asset(15) );
publish_feed( mpa_id, feeder_id, f, feed_icr );

// globally settle
if( bsrm_type::no_settlement == static_cast<bsrm_type>(i) )
if( bsrm_type::no_settlement == static_cast<bsrm_type>(bsrm) )
force_global_settle( mpa_id(db), price( asset(1000,mpa_id), asset(18) ) );
else if( bsrm_type::individual_settlement_to_fund == static_cast<bsrm_type>(i)
|| bsrm_type::individual_settlement_to_order == static_cast<bsrm_type>(i) )
else if( bsrm_type::individual_settlement_to_fund == static_cast<bsrm_type>(bsrm)
|| bsrm_type::individual_settlement_to_order == static_cast<bsrm_type>(bsrm) )
force_global_settle( mpa_id(db), price( asset(1000,mpa_id), asset(22) ) );

// check
Expand All @@ -1526,7 +1540,7 @@ BOOST_AUTO_TEST_CASE( manual_gs_test )
BOOST_CHECK( mpa_id(db).bitasset_data(db).current_feed.settlement_price == f.settlement_price );
BOOST_CHECK( mpa_id(db).bitasset_data(db).median_feed.settlement_price == f.settlement_price );

switch( static_cast<bsrm_type>(i) )
switch( static_cast<bsrm_type>(bsrm) )
{
case bsrm_type::global_settlement:
break;
Expand Down
103 changes: 103 additions & 0 deletions tests/tests/settle_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2088,6 +2088,109 @@ BOOST_AUTO_TEST_CASE( collateral_fee_of_instant_settlement_test )

} FC_LOG_AND_RETHROW() }

/// Tests instant settlement:
/// * After hf core-2591, for prediction markets, forced-settlements are NOT filled at margin call order price (MCOP)
BOOST_AUTO_TEST_CASE( pm_instant_settlement_price_test )
{ try {

// Advance to a recent hard fork
generate_blocks(HARDFORK_CORE_2582_TIME);
generate_block();

// multiple passes,
// i == 0 : before hf core-2591
// i == 1 : after hf core-2591
for( int i = 0; i < 2; ++ i )
{
idump( (i) );

if( 1 == i )
{
// Advance to core-2591 hard fork
generate_blocks(HARDFORK_CORE_2591_TIME);
generate_block();
}

set_expiration( db, trx );

ACTORS((judge)(alice)(feeder));

const auto& pmark = create_prediction_market("PMARK", judge_id);
const auto& core = asset_id_type()(db);

asset_id_type pm_id = pmark.get_id();

int64_t init_balance(1000000);
transfer(committee_account, judge_id, asset(init_balance));
transfer(committee_account, alice_id, asset(init_balance));

BOOST_TEST_MESSAGE( "Open position with equal collateral" );
borrow( alice, pmark.amount(1000), asset(1000) );

BOOST_CHECK_EQUAL( get_balance( alice_id, pm_id ), 1000 );
BOOST_CHECK_EQUAL( get_balance( alice_id, asset_id_type() ), init_balance - 1000 );

// add a price feed publisher and publish a feed
update_feed_producers( pm_id, { feeder_id } );

price_feed f;
f.settlement_price = price( asset(100,pm_id), asset(1) );
f.core_exchange_rate = price( asset(100,pm_id), asset(1) );
f.maintenance_collateral_ratio = 1850;
f.maximum_short_squeeze_ratio = 1250;

uint16_t feed_icr = 1900;

publish_feed( pm_id, feeder_id, f, feed_icr );

BOOST_CHECK_EQUAL( get_balance( alice_id, pm_id ), 1000 );
BOOST_CHECK_EQUAL( get_balance( alice_id, asset_id_type() ), init_balance - 1000 );

BOOST_TEST_MESSAGE( "Globally settling" );
force_global_settle( pmark, pmark.amount(1) / core.amount(1) );

BOOST_CHECK_EQUAL( get_balance( alice_id, pm_id ), 1000 );
BOOST_CHECK_EQUAL( get_balance( alice_id, asset_id_type() ), init_balance - 1000 );

// alice settles
auto result = force_settle( alice, asset(300, pm_id) );
auto op_result = result.get<extendable_operation_result>().value;

BOOST_CHECK( !op_result.new_objects.valid() ); // force settlement order not created

BOOST_REQUIRE( op_result.paid.valid() && 1U == op_result.paid->size() );
BOOST_CHECK( *op_result.paid->begin() == asset( 300, pm_id ) );
BOOST_REQUIRE( op_result.received.valid() && 1U == op_result.received->size() );
BOOST_CHECK( *op_result.received->begin() == asset( 300 ) );
BOOST_REQUIRE( op_result.fees.valid() && 1U == op_result.fees->size() );
BOOST_CHECK( *op_result.fees->begin() == asset( 0 ) );

auto check_result = [&]
{
BOOST_CHECK( !pm_id(db).bitasset_data(db).has_individual_settlement() );
BOOST_CHECK( pm_id(db).bitasset_data(db).has_settlement() );
BOOST_CHECK_EQUAL( pm_id(db).bitasset_data(db).settlement_fund.value, 700 );

BOOST_CHECK_EQUAL( pm_id(db).dynamic_data(db).accumulated_collateral_fees.value, 0 );

BOOST_CHECK_EQUAL( get_balance( alice_id, pm_id ), 700 );
BOOST_CHECK_EQUAL( get_balance( alice_id, asset_id_type() ), init_balance - 700 );
};

check_result();

BOOST_TEST_MESSAGE( "Generate a block" );
generate_block();

check_result();

// reset
db.pop_block();

} // for i

} FC_LOG_AND_RETHROW() }

/**
* Test case to reproduce https://github.com/bitshares/bitshares-core/issues/1883.
* When there is only one fill_order object in the ticker rolling buffer, it should only be rolled out once.
Expand Down