@@ -1304,6 +1304,126 @@ BOOST_AUTO_TEST_CASE(mcfr_blackswan_test)
1304
1304
1305
1305
} FC_LOG_AND_RETHROW () }
1306
1306
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
+
1307
1427
/* **
1308
1428
* Tests a scenario about rounding errors related to margin call fee
1309
1429
*/
0 commit comments