Skip to content

Commit ddd26f8

Browse files
committed
Add tests for GS after core-2481 hard fork
1 parent 2500b8b commit ddd26f8

File tree

1 file changed

+120
-0
lines changed

1 file changed

+120
-0
lines changed

tests/tests/market_tests.cpp

+120
Original file line numberDiff line numberDiff line change
@@ -1304,6 +1304,126 @@ BOOST_AUTO_TEST_CASE(mcfr_blackswan_test)
13041304

13051305
} FC_LOG_AND_RETHROW() }
13061306

1307+
/***
1308+
* Tests a scenario after the core-2481 hard fork that GS may occur when there is no sufficient collateral
1309+
* to pay margin call fee, but GS won't occur if no need to pay margin call fee. The amount gathered to the
1310+
* global settlement fund will be different than the case before the hard fork.
1311+
*/
1312+
BOOST_AUTO_TEST_CASE(mcfr_blackswan_test_after_hf_core_2481)
1313+
{ try {
1314+
// Proceeds to the core-2481 hard fork time
1315+
auto mi = db.get_global_properties().parameters.maintenance_interval;
1316+
generate_blocks(HARDFORK_CORE_2481_TIME - mi);
1317+
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
1318+
set_expiration( db, trx );
1319+
1320+
ACTORS((seller)(borrower)(borrower2)(borrower3)(feedproducer));
1321+
1322+
const auto& bitusd = create_bitasset("USDBIT", feedproducer_id);
1323+
const auto& core = asset_id_type()(db);
1324+
asset_id_type usd_id = bitusd.id;
1325+
1326+
int64_t init_balance(1000000);
1327+
1328+
transfer(committee_account, borrower_id, asset(init_balance));
1329+
transfer(committee_account, borrower2_id, asset(init_balance));
1330+
transfer(committee_account, borrower3_id, asset(init_balance));
1331+
1332+
{
1333+
// set margin call fee ratio
1334+
asset_update_bitasset_operation uop;
1335+
uop.issuer = usd_id(db).issuer;
1336+
uop.asset_to_update = usd_id;
1337+
uop.new_options = usd_id(db).bitasset_data(db).options;
1338+
uop.new_options.extensions.value.margin_call_fee_ratio = 80;
1339+
1340+
trx.clear();
1341+
trx.operations.push_back(uop);
1342+
PUSH_TX(db, trx, ~0);
1343+
}
1344+
1345+
update_feed_producers( bitusd, {feedproducer.id} );
1346+
1347+
price_feed current_feed;
1348+
current_feed.maintenance_collateral_ratio = 1750;
1349+
current_feed.maximum_short_squeeze_ratio = 1100;
1350+
current_feed.settlement_price = bitusd.amount( 1 ) / core.amount(5);
1351+
publish_feed( bitusd, feedproducer, current_feed );
1352+
1353+
// start out with 300% collateral, call price is 15/1.75 CORE/USD = 60/7
1354+
const call_order_object& call = *borrow( borrower, bitusd.amount(1000), asset(15000));
1355+
call_order_id_type call_id = call.id;
1356+
// create another position with 400% collateral, call price is 20/1.75 CORE/USD = 80/7
1357+
const call_order_object& call2 = *borrow( borrower2, bitusd.amount(1000), asset(20000));
1358+
call_order_id_type call2_id = call2.id;
1359+
// create yet another position with 800% collateral, call price is 40/1.75 CORE/USD = 160/7
1360+
const call_order_object& call3 = *borrow( borrower3, bitusd.amount(1000), asset(40000));
1361+
call_order_id_type call3_id = call3.id;
1362+
transfer(borrower, seller, bitusd.amount(1000));
1363+
transfer(borrower2, seller, bitusd.amount(1000));
1364+
transfer(borrower3, seller, bitusd.amount(1000));
1365+
1366+
BOOST_CHECK_EQUAL( 1000, call.debt.value );
1367+
BOOST_CHECK_EQUAL( 15000, call.collateral.value );
1368+
BOOST_CHECK_EQUAL( 1000, call2.debt.value );
1369+
BOOST_CHECK_EQUAL( 20000, call2.collateral.value );
1370+
BOOST_CHECK_EQUAL( 1000, call3.debt.value );
1371+
BOOST_CHECK_EQUAL( 40000, call3.collateral.value );
1372+
BOOST_CHECK_EQUAL( 3000, get_balance(seller, bitusd) );
1373+
BOOST_CHECK_EQUAL( 0, get_balance(seller, core) );
1374+
1375+
// No margin call at this moment
1376+
1377+
// This order is sufficient to close the first debt position and no GS if margin call fee ratio is 0
1378+
limit_order_id_type sell_mid = create_sell_order(seller, bitusd.amount(1000), core.amount(14900))->id;
1379+
1380+
BOOST_CHECK_EQUAL( 1000, sell_mid(db).for_sale.value );
1381+
1382+
BOOST_CHECK_EQUAL( 1000, call_id(db).debt.value );
1383+
BOOST_CHECK_EQUAL( 15000, call_id(db).collateral.value );
1384+
BOOST_CHECK_EQUAL( 1000, call2_id(db).debt.value );
1385+
BOOST_CHECK_EQUAL( 20000, call2_id(db).collateral.value );
1386+
BOOST_CHECK_EQUAL( 1000, call3_id(db).debt.value );
1387+
BOOST_CHECK_EQUAL( 40000, call3_id(db).collateral.value );
1388+
BOOST_CHECK_EQUAL( 2000, get_balance(seller, bitusd) );
1389+
BOOST_CHECK_EQUAL( 0, get_balance(seller, core) );
1390+
1391+
// adjust price feed to get call_order into black swan territory
1392+
BOOST_MESSAGE( "Trying to trigger GS" );
1393+
current_feed.settlement_price = bitusd.amount( 1 ) / core.amount(18);
1394+
publish_feed( bitusd, feedproducer, current_feed );
1395+
// settlement price = 1/18, mssp = 10/198
1396+
1397+
// GS occurs even when there is a good sell order
1398+
BOOST_CHECK( usd_id(db).bitasset_data(db).has_settlement() );
1399+
BOOST_CHECK( !db.find<call_order_object>( call_id ) );
1400+
BOOST_CHECK( !db.find<call_order_object>( call2_id ) );
1401+
BOOST_CHECK( !db.find<call_order_object>( call3_id ) );
1402+
1403+
// after the core-2481 hard fork, GS price is not 1/18.
1404+
// * the first call order would pay all collateral.
1405+
// due to margin call fee, not all collateral enters global settlement fund, but
1406+
// fund_receives = round_up(15000 / 1.1) = 13637
1407+
// fees = 15000 - 13637 = 1363
1408+
// * the second call order was in margin call territory too, so it would pay a premium and margin call fee.
1409+
// fund_receives = 13637
1410+
// fees = 15000 - 13637 = 1363
1411+
// the rest ( 20000 - 15000 = 5000 ) returns to borrower2
1412+
// * the third call order was not in margin call territory, so no premium or margin call fee.
1413+
// fund_receives = round_up(15000 / 1.1) = 13637
1414+
// GS price is 1/18, but the first call order has only 15000 thus capped
1415+
BOOST_CHECK_EQUAL( 13637 * 3, usd_id(db).bitasset_data(db).settlement_fund.value );
1416+
BOOST_CHECK_EQUAL( 1363 * 2, usd_id(db).dynamic_asset_data_id(db).accumulated_collateral_fees.value );
1417+
1418+
// the sell order does not change
1419+
BOOST_CHECK_EQUAL( 1000, sell_mid(db).for_sale.value );
1420+
1421+
// generate a block to include operations above
1422+
BOOST_MESSAGE( "Generating a new block" );
1423+
generate_block();
1424+
1425+
} FC_LOG_AND_RETHROW() }
1426+
13071427
/***
13081428
* Tests a scenario about rounding errors related to margin call fee
13091429
*/

0 commit comments

Comments
 (0)