Skip to content

Commit

Permalink
Merge pull request #2727 from bitshares/pr-2591-fix-gs
Browse files Browse the repository at this point in the history
Fix issues related to global settlement introduced in PR #2721
  • Loading branch information
abitmore authored Mar 13, 2023
2 parents a6dcc1a + 338de92 commit 0b2dd8e
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 12 deletions.
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

0 comments on commit 0b2dd8e

Please sign in to comment.