From c58d00baf906c5504bff4cf5b9a3dd16911daaf7 Mon Sep 17 00:00:00 2001 From: abitmore Date: Tue, 6 Feb 2018 21:11:54 +0000 Subject: [PATCH] Test case reproduces #338 #343 #453 #606 #625 #649 --- tests/tests/market_tests.cpp | 127 ++++++++++++++++++++++++++++++++--- 1 file changed, 117 insertions(+), 10 deletions(-) diff --git a/tests/tests/market_tests.cpp b/tests/tests/market_tests.cpp index 9f6cc81de0..6032202ef4 100644 --- a/tests/tests/market_tests.cpp +++ b/tests/tests/market_tests.cpp @@ -39,24 +39,28 @@ using namespace graphene::wallet; BOOST_FIXTURE_TEST_SUITE(market_tests, database_fixture) /*** - * Reproduce bitshares-core issue #338 + * Reproduce bitshares-core issue #338 #343 #453 #606 #625 #649 */ -BOOST_AUTO_TEST_CASE(issue_338) +BOOST_AUTO_TEST_CASE(issue_338_etc) { try { generate_blocks(HARDFORK_436_TIME); generate_block(); set_expiration( db, trx ); - ACTORS((buyer)(seller)(borrower)(feedproducer)); + ACTORS((buyer)(seller)(borrower)(borrower2)(borrower3)(feedproducer)); const auto& bitusd = create_bitasset("USDBIT", feedproducer_id); const auto& core = asset_id_type()(db); + asset_id_type usd_id = bitusd.id; + asset_id_type core_id = core.id; int64_t init_balance(1000000); transfer(committee_account, buyer_id, asset(init_balance)); transfer(committee_account, borrower_id, asset(init_balance)); + transfer(committee_account, borrower2_id, asset(init_balance)); + transfer(committee_account, borrower3_id, asset(init_balance)); update_feed_producers( bitusd, {feedproducer.id} ); price_feed current_feed; @@ -66,6 +70,13 @@ BOOST_AUTO_TEST_CASE(issue_338) publish_feed( bitusd, feedproducer, current_feed ); // start out with 300% collateral, call price is 15/1.75 CORE/USD = 60/7 const call_order_object& call = *borrow( borrower, bitusd.amount(1000), asset(15000)); + call_order_id_type call_id = call.id; + // create another position with 310% collateral, call price is 15.5/1.75 CORE/USD = 63/7 + const call_order_object& call2 = *borrow( borrower2, bitusd.amount(1000), asset(15500)); + call_order_id_type call2_id = call2.id; + // create yet another position with 320% collateral, call price is 16/1.75 CORE/USD = 64/7 + const call_order_object& call3 = *borrow( borrower3, bitusd.amount(1000), asset(16000)); + call_order_id_type call3_id = call3.id; transfer(borrower, seller, bitusd.amount(1000)); BOOST_CHECK_EQUAL( 1000, call.debt.value ); @@ -78,11 +89,11 @@ BOOST_AUTO_TEST_CASE(issue_338) publish_feed( bitusd, feedproducer, current_feed ); // settlement price = 1/10, mssp = 1/11 - // This order slightly below the call price will not be matched + // This order slightly below the call price will not be matched #606 limit_order_id_type sell_low = create_sell_order(seller, bitusd.amount(7), core.amount(59))->id; // This order above the MSSP will not be matched limit_order_id_type sell_high = create_sell_order(seller, bitusd.amount(7), core.amount(78))->id; - // This would match but is blocked by sell_low?! + // This would match but is blocked by sell_low?! #606 limit_order_id_type sell_med = create_sell_order(seller, bitusd.amount(7), core.amount(60))->id; cancel_limit_order( sell_med(db) ); @@ -90,14 +101,14 @@ BOOST_AUTO_TEST_CASE(issue_338) cancel_limit_order( sell_low(db) ); // current implementation: an incoming limit order will be filled at the - // requested price + // requested price #338 BOOST_CHECK( !create_sell_order(seller, bitusd.amount(7), core.amount(60)) ); BOOST_CHECK_EQUAL( 993, get_balance(seller, bitusd) ); BOOST_CHECK_EQUAL( 60, get_balance(seller, core) ); BOOST_CHECK_EQUAL( 993, call.debt.value ); BOOST_CHECK_EQUAL( 14940, call.collateral.value ); - auto buy_low = create_sell_order(buyer, asset(90), bitusd.amount(10))->id; + limit_order_id_type buy_low = create_sell_order(buyer, asset(90), bitusd.amount(10))->id; // margin call takes precedence BOOST_CHECK( !create_sell_order(seller, bitusd.amount(7), core.amount(60)) ); BOOST_CHECK_EQUAL( 986, get_balance(seller, bitusd) ); @@ -105,7 +116,7 @@ BOOST_AUTO_TEST_CASE(issue_338) BOOST_CHECK_EQUAL( 986, call.debt.value ); BOOST_CHECK_EQUAL( 14880, call.collateral.value ); - auto buy_med = create_sell_order(buyer, asset(105), bitusd.amount(10))->id; + limit_order_id_type buy_med = create_sell_order(buyer, asset(105), bitusd.amount(10))->id; // margin call takes precedence BOOST_CHECK( !create_sell_order(seller, bitusd.amount(7), core.amount(70)) ); BOOST_CHECK_EQUAL( 979, get_balance(seller, bitusd) ); @@ -113,13 +124,109 @@ BOOST_AUTO_TEST_CASE(issue_338) BOOST_CHECK_EQUAL( 979, call.debt.value ); BOOST_CHECK_EQUAL( 14810, call.collateral.value ); - auto buy_high = create_sell_order(buyer, asset(115), bitusd.amount(10))->id; - // margin call still has precedence (!)) + limit_order_id_type buy_high = create_sell_order(buyer, asset(115), bitusd.amount(10))->id; + // margin call still has precedence (!) #625 BOOST_CHECK( !create_sell_order(seller, bitusd.amount(7), core.amount(77)) ); BOOST_CHECK_EQUAL( 972, get_balance(seller, bitusd) ); BOOST_CHECK_EQUAL( 267, get_balance(seller, core) ); BOOST_CHECK_EQUAL( 972, call.debt.value ); BOOST_CHECK_EQUAL( 14733, call.collateral.value ); + + cancel_limit_order( buy_high(db) ); + cancel_limit_order( buy_med(db) ); + cancel_limit_order( buy_low(db) ); + + // call with more usd + BOOST_CHECK( !create_sell_order(seller, bitusd.amount(700), core.amount(7700)) ); + BOOST_CHECK_EQUAL( 272, get_balance(seller, bitusd) ); + BOOST_CHECK_EQUAL( 7967, get_balance(seller, core) ); + BOOST_CHECK_EQUAL( 272, call.debt.value ); + BOOST_CHECK_EQUAL( 7033, call.collateral.value ); + + // at this moment, collateralization of call is 7033 / 272 = 25.8 + // collateralization of call2 is 15500 / 1000 = 15.5 + // collateralization of call3 is 16000 / 1000 = 16 + + // call more, still matches with the first call order #343 + BOOST_CHECK( !create_sell_order(seller, bitusd.amount(10), core.amount(110)) ); + BOOST_CHECK_EQUAL( 262, get_balance(seller, bitusd) ); + BOOST_CHECK_EQUAL( 8077, get_balance(seller, core) ); + BOOST_CHECK_EQUAL( 262, call.debt.value ); + BOOST_CHECK_EQUAL( 6923, call.collateral.value ); + + // at this moment, collateralization of call is 6923 / 262 = 26.4 + // collateralization of call2 is 15500 / 1000 = 15.5 + // collateralization of call3 is 16000 / 1000 = 16 + + // force settle + force_settle( seller, bitusd.amount(10) ); + BOOST_CHECK_EQUAL( 252, get_balance(seller, bitusd) ); + BOOST_CHECK_EQUAL( 8077, get_balance(seller, core) ); + BOOST_CHECK_EQUAL( 262, call.debt.value ); + BOOST_CHECK_EQUAL( 6923, call.collateral.value ); + + // generate blocks to let the settle order execute + generate_blocks( HARDFORK_436_TIME + fc::days(2) ); + // call2 get settled #343 + BOOST_CHECK_EQUAL( 252, get_balance(seller_id, usd_id) ); + BOOST_CHECK_EQUAL( 8177, get_balance(seller_id, core_id) ); + BOOST_CHECK_EQUAL( 262, call_id(db).debt.value ); + BOOST_CHECK_EQUAL( 6923, call_id(db).collateral.value ); + BOOST_CHECK_EQUAL( 990, call2_id(db).debt.value ); + BOOST_CHECK_EQUAL( 15400, call2_id(db).collateral.value ); + + set_expiration( db, trx ); + update_feed_producers( usd_id(db), {feedproducer_id} ); + + // at this moment, collateralization of call is 8177 / 252 = 32.4 + // collateralization of call2 is 15400 / 990 = 15.5 + // collateralization of call3 is 16000 / 1000 = 16 + + // adjust price feed to get call2 into black swan territory, but not the first call order + current_feed.settlement_price = asset(1, usd_id) / asset(20, core_id); + publish_feed( usd_id(db), feedproducer_id(db), current_feed ); + // settlement price = 1/20, mssp = 1/22 + + // black swan event doesn't occur #649 + BOOST_CHECK( !usd_id(db).bitasset_data(db).has_settlement() ); + + // generate a block + generate_block(); + + set_expiration( db, trx ); + update_feed_producers( usd_id(db), {feedproducer_id} ); + + // adjust price feed back + current_feed.settlement_price = asset(1, usd_id) / asset(10, core_id); + publish_feed( usd_id(db), feedproducer_id(db), current_feed ); + // settlement price = 1/10, mssp = 1/11 + + transfer(borrower2_id, seller_id, asset(1000, usd_id)); + transfer(borrower3_id, seller_id, asset(1000, usd_id)); + + // Re-create sell_low, slightly below the call price, will not be matched, will expire soon + sell_low = create_sell_order(seller_id(db), asset(7, usd_id), asset(59), db.head_block_time() )->id; + // This would match but is blocked by sell_low, it has an amount same as call's debt which will be full filled later + sell_med = create_sell_order(seller_id(db), asset(262, usd_id), asset(2620))->id; // 1/10 + // Another big order above sell_med, blocked + limit_order_id_type sell_med2 = create_sell_order(seller_id(db), asset(1200, usd_id), asset(12120))->id; // 1/10.1 + // Another small order above sell_med2, blocked + limit_order_id_type sell_med3 = create_sell_order(seller_id(db), asset(120, usd_id), asset(1224))->id; // 1/10.2 + + // generate a block, sell_low will expire + generate_block(); + BOOST_CHECK( db.find( sell_low ) == nullptr ); + + // #453 multiple order matching issue occurs + BOOST_CHECK( db.find( sell_med ) == nullptr ); // sell_med get filled + BOOST_CHECK( db.find( sell_med2 ) != nullptr ); // sell_med2 is still there + BOOST_CHECK( db.find( sell_med3 ) == nullptr ); // sell_med3 get filled + BOOST_CHECK( db.find( call_id ) == nullptr ); // the first call order get filled + BOOST_CHECK( db.find( call2_id ) == nullptr ); // the second call order get filled + BOOST_CHECK( db.find( call3_id ) != nullptr ); // the third call order is still there + + } FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END()