From 73321cad4393cb20350efdd6971292da71d0a394 Mon Sep 17 00:00:00 2001 From: Alexey Frolov Date: Mon, 8 Jul 2019 17:31:10 +0300 Subject: [PATCH 1/8] Added settle orders to market fee sharing program --- libraries/chain/db_market.cpp | 6 +- libraries/chain/hardfork.d/CORE_1780.hf | 4 + tests/tests/market_fee_sharing_tests.cpp | 1 - tests/tests/settle_tests.cpp | 189 +++++++++++++++++++++++ 4 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 libraries/chain/hardfork.d/CORE_1780.hf diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index c009d0b830..e309aec4b2 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -932,7 +932,11 @@ bool database::fill_settle_order( const force_settlement_object& settle, const a { try { bool filled = false; - auto issuer_fees = pay_market_fees(get(receives.asset_id), receives); + const account_object& owner = settle.owner(*this); + + auto issuer_fees = ( head_block_time() < HARDFORK_CORE_1780_TIME ) ? + pay_market_fees(get(receives.asset_id), receives) : + pay_market_fees(owner, get(receives.asset_id), receives); if( pays < settle.balance ) { diff --git a/libraries/chain/hardfork.d/CORE_1780.hf b/libraries/chain/hardfork.d/CORE_1780.hf new file mode 100644 index 0000000000..8e1358b15b --- /dev/null +++ b/libraries/chain/hardfork.d/CORE_1780.hf @@ -0,0 +1,4 @@ +// Market fees of settle orders aren't shared to referral program +#ifndef HARDFORK_CORE_1780_TIME +#define HARDFORK_CORE_1780_TIME (fc::time_point_sec( 1600000000 ) ) // September 13, 2020 3:26:40 PM (GMT) +#endif diff --git a/tests/tests/market_fee_sharing_tests.cpp b/tests/tests/market_fee_sharing_tests.cpp index 2ba95b2c5b..a267a3b9b5 100644 --- a/tests/tests/market_fee_sharing_tests.cpp +++ b/tests/tests/market_fee_sharing_tests.cpp @@ -426,7 +426,6 @@ BOOST_AUTO_TEST_CASE(create_actors) price price(asset(1, asset_id_type(1)), asset(1)); uint16_t market_fee_percent = 20 * GRAPHENE_1_PERCENT; - auto obj = jill_id(db); const asset_object jillcoin = create_user_issued_asset( "JCOIN", jill, charge_market_fee, price, 2, market_fee_percent ); const account_object alice = create_account("alice", izzyregistrar, izzyreferrer, 50/*0.5%*/); diff --git a/tests/tests/settle_tests.cpp b/tests/tests/settle_tests.cpp index f64719e613..1249c03eb9 100644 --- a/tests/tests/settle_tests.cpp +++ b/tests/tests/settle_tests.cpp @@ -1501,4 +1501,193 @@ BOOST_AUTO_TEST_CASE( global_settle_rounding_test_after_hf_184 ) } FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE( create_bitassets ) +{ + try { + generate_blocks( HARDFORK_1268_TIME ); + generate_blocks( db.get_dynamic_global_properties().next_maintenance_time ); + set_expiration( db, trx ); + + ACTORS((paul)(rachelregistrar)(rachelreferrer)); + + upgrade_to_lifetime_member(rachelregistrar); + upgrade_to_lifetime_member(rachelreferrer); + + constexpr auto market_fee_percent = 50 * GRAPHENE_1_PERCENT; + constexpr auto biteur_reward_percent = 90 * GRAPHENE_1_PERCENT; + constexpr auto referrer_reward_percent = 10 * GRAPHENE_1_PERCENT; + + const auto& biteur = create_bitasset( "EURBIT", paul_id, market_fee_percent, charge_market_fee, 2 ); + asset_id_type biteur_id = biteur.id; + + const auto& bitusd = create_bitasset( "USDBIT", paul_id, market_fee_percent, charge_market_fee, 2, biteur_id ); + + const account_object rachel = create_account( "rachel", rachelregistrar, rachelreferrer, referrer_reward_percent ); + + transfer( committee_account, rachelregistrar_id, asset( 10000000 ) ); + transfer( committee_account, rachelreferrer_id, asset( 10000000 ) ); + transfer( committee_account, rachel.get_id(), asset( 10000000) ); + transfer( committee_account, paul_id, asset( 10000000000 ) ); + + asset_update_operation op; + op.issuer = biteur.issuer; + op.asset_to_update = biteur_id; + op.new_options.issuer_permissions = charge_market_fee; + op.new_options.extensions.value.reward_percent = biteur_reward_percent; + op.new_options.flags = bitusd.options.flags | charge_market_fee; + op.new_options.core_exchange_rate = price( asset(20,biteur_id), asset(1,asset_id_type()) ); + op.new_options.market_fee_percent = market_fee_percent; + trx.operations.push_back(op); + sign(trx, paul_private_key); + PUSH_TX(db, trx); + generate_block(); + trx.clear(); + } FC_LOG_AND_RETHROW() +} + +BOOST_AUTO_TEST_CASE( market_fee_of_settle_order_before_hardfork_1780 ) +{ + try { + INVOKE(create_bitassets); + + GET_ACTOR(paul); + GET_ACTOR(rachelregistrar); + GET_ACTOR(rachelreferrer); + + const asset_object &biteur = get_asset( "EURBIT" ); + asset_id_type biteur_id = biteur.id; + const asset_object &bitusd = get_asset( "USDBIT" ); + asset_id_type bitusd_id = bitusd.id; + + const auto& core = asset_id_type()(db); + + const account_object& rachel = get_account( "rachel" ); + + {// add a feed to asset bitusd + update_feed_producers( bitusd, {paul_id} ); + price_feed feed; + feed.settlement_price = price( bitusd.amount(100), biteur.amount(5) ); + feed.core_exchange_rate = price( bitusd.amount(100), asset(1) ); + feed.maintenance_collateral_ratio = 175 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + feed.maximum_short_squeeze_ratio = 110 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + publish_feed( bitusd_id, paul_id, feed ); + } + + {// add a feed to asset biteur + update_feed_producers( biteur, {paul_id} ); + price_feed feed; + feed.settlement_price = price( biteur.amount(100), core.amount(5) ); + feed.maintenance_collateral_ratio = 175 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + feed.maximum_short_squeeze_ratio = 110 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + publish_feed( biteur_id, paul_id, feed ); + } + + enable_fees(); + + // paul gets some bitusd and biteur + borrow( paul_id, biteur.amount(20000), core.amount(2000) ); + borrow( paul_id, bitusd.amount(10000), biteur.amount(1000) ); + + // and transfer some bitusd to rachel + constexpr auto rachel_bitusd_count = 1000; + transfer( paul_id, rachel.get_id(), asset(rachel_bitusd_count, bitusd_id) ); + + force_settle( rachel, bitusd.amount(rachel_bitusd_count) ); + generate_block(); + generate_blocks( db.head_block_time() + fc::hours(24) ); + + // 1 biteur = 20 bitusd see publish_feed + const auto biteur_expected_result = rachel_bitusd_count/20; + BOOST_CHECK_EQUAL( get_balance(rachel, biteur), biteur_expected_result/2/*market fee percent = 50%*/ ); + BOOST_CHECK_EQUAL( get_balance(rachel, bitusd), 0 ); + + const auto rachelregistrar_reward = get_market_fee_reward( rachelregistrar, biteur ); + const auto rachelreferrer_reward = get_market_fee_reward( rachelreferrer, biteur ); + + BOOST_CHECK_EQUAL( rachelregistrar_reward, 0 ); + BOOST_CHECK_EQUAL( rachelreferrer_reward, 0 ); + + } FC_LOG_AND_RETHROW() +} + +BOOST_AUTO_TEST_CASE( market_fee_of_settle_order_after_hardfork_1780 ) +{ + try { + INVOKE(create_bitassets); + + GET_ACTOR(paul); + GET_ACTOR(rachelregistrar); + GET_ACTOR(rachelreferrer); + + const asset_object &biteur = get_asset( "EURBIT" ); + asset_id_type biteur_id = biteur.id; + const asset_object &bitusd = get_asset( "USDBIT" ); + asset_id_type bitusd_id = bitusd.id; + + const auto& core = asset_id_type()(db); + + const account_object& rachel = get_account( "rachel" ); + + generate_blocks( HARDFORK_CORE_1780_TIME ); + + {// add a feed to asset bitusd + update_feed_producers( bitusd, {paul_id} ); + price_feed feed; + feed.settlement_price = price( bitusd.amount(100), biteur.amount(5) ); + feed.core_exchange_rate = price( bitusd.amount(100), asset(1) ); + feed.maintenance_collateral_ratio = 175 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + feed.maximum_short_squeeze_ratio = 110 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + publish_feed( bitusd_id, paul_id, feed ); + } + + {// add a feed to asset biteur + update_feed_producers( biteur, {paul_id} ); + price_feed feed; + feed.settlement_price = price( biteur.amount(100), core.amount(5) ); + feed.maintenance_collateral_ratio = 175 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + feed.maximum_short_squeeze_ratio = 110 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + publish_feed( biteur_id, paul_id, feed ); + } + + enable_fees(); + + // paul gets some bitusd and biteur + borrow( paul_id, biteur.amount(20000), core.amount(2000) ); + borrow( paul_id, bitusd.amount(10000), biteur.amount(1000) ); + + // and transfer some bitusd to rachel + constexpr auto rachel_bitusd_count = 1000; + transfer( paul_id, rachel.get_id(), asset(rachel_bitusd_count, bitusd_id) ); + + force_settle( rachel, bitusd.amount(rachel_bitusd_count) ); + generate_block(); + generate_blocks( db.head_block_time() + fc::hours(24) ); + + // 1 biteur = 20 bitusd see publish_feed + const auto biteur_expected_result = rachel_bitusd_count/20; + BOOST_CHECK_EQUAL( get_balance(rachel, biteur), biteur_expected_result/2/*market fee percent = 50%*/ ); + BOOST_CHECK_EQUAL( get_balance(rachel, bitusd), 0 ); + + const auto rachelregistrar_reward = get_market_fee_reward( rachelregistrar, biteur ); + const auto rachelreferrer_reward = get_market_fee_reward( rachelreferrer, biteur ); + + BOOST_CHECK_GT( rachelregistrar_reward, 0 ); + BOOST_CHECK_GT( rachelreferrer_reward, 0 ); + + auto calculate_percent = [](const share_type& value, uint16_t percent) + { + auto a(value.value); + a *= percent; + a /= GRAPHENE_100_PERCENT; + return a; + }; + + const auto biteur_market_fee = calculate_percent( biteur_expected_result, 50 * GRAPHENE_1_PERCENT ); + const auto biteur_reward = calculate_percent( biteur_market_fee, 90*GRAPHENE_1_PERCENT ); + BOOST_CHECK_EQUAL( biteur_reward, rachelregistrar_reward + rachelreferrer_reward ); + + } FC_LOG_AND_RETHROW() +} + + BOOST_AUTO_TEST_SUITE_END() From c2b28e9917e9d4e11aef7e754f98ea0e283cc3a5 Mon Sep 17 00:00:00 2001 From: Alexey Frolov Date: Thu, 11 Jul 2019 16:46:36 +0300 Subject: [PATCH 2/8] optimize access to graphene database --- libraries/chain/db_market.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index e309aec4b2..53f6d97c8d 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -932,11 +932,9 @@ bool database::fill_settle_order( const force_settlement_object& settle, const a { try { bool filled = false; - const account_object& owner = settle.owner(*this); - auto issuer_fees = ( head_block_time() < HARDFORK_CORE_1780_TIME ) ? pay_market_fees(get(receives.asset_id), receives) : - pay_market_fees(owner, get(receives.asset_id), receives); + pay_market_fees(settle.owner(*this), get(receives.asset_id), receives); if( pays < settle.balance ) { From 734887385cefa8cbec43aaaa8f03ab40b51611a8 Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 9 Apr 2020 14:07:56 +0000 Subject: [PATCH 3/8] Fix test cases --- tests/tests/settle_tests.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/tests/settle_tests.cpp b/tests/tests/settle_tests.cpp index 961378b169..2681bf3ea3 100644 --- a/tests/tests/settle_tests.cpp +++ b/tests/tests/settle_tests.cpp @@ -1505,6 +1505,10 @@ BOOST_AUTO_TEST_CASE( create_bitassets ) { try { + generate_blocks( HARDFORK_480_TIME ); // avoid being affected by the price feed bug + generate_block(); + set_expiration( db, trx ); + ACTORS((paul)(rachelregistrar)(rachelreferrer)); upgrade_to_lifetime_member(rachelregistrar); From ab3f9b82b279a9bf080744720bdda70654e935fd Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 9 Apr 2020 14:33:58 +0000 Subject: [PATCH 4/8] Update coding style --- libraries/chain/db_market.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index d217f6ae88..dcd2be96f5 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -924,7 +924,7 @@ bool database::fill_settle_order( const force_settlement_object& settle, const a if( head_block_time() >= HARDFORK_CORE_1780_TIME ) settle_owner_ptr = &settle.owner(*this); - auto issuer_fees = pay_market_fees( settle_owner_ptr, get(receives.asset_id), receives); + auto issuer_fees = pay_market_fees( settle_owner_ptr, get(receives.asset_id), receives ); if( pays < settle.balance ) { From c32a4e6072ab38e4d1a62c5a611c9bc74deadd4a Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 9 Apr 2020 14:51:07 +0000 Subject: [PATCH 5/8] Add market fee sharing for instant settlements Pay market fee and share it with the referral program when settling an amount of a globally settled asset after the core-1780 hard fork, for issue https://github.com/bitshares/bitshares-core/issues/1780 --- libraries/chain/asset_evaluator.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index 926ae1146c..f8df7203af 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -708,10 +708,10 @@ void_result asset_settle_evaluator::do_evaluate(const asset_settle_evaluator::op if( bitasset.is_prediction_market ) FC_ASSERT( bitasset.has_settlement(), "global settlement must occur before force settling a prediction market" ); else if( bitasset.current_feed.settlement_price.is_null() - && ( d.head_block_time() <= HARDFORK_CORE_216_TIME + && ( d.head_block_time() <= HARDFORK_CORE_216_TIME // TODO check whether the HF check can be removed || !bitasset.has_settlement() ) ) FC_THROW_EXCEPTION(insufficient_feeds, "Cannot force settle with no price feed."); - FC_ASSERT(d.get_balance(d.get(op.account), *asset_to_settle) >= op.amount); + FC_ASSERT( d.get_balance( op.account, op.amount.asset_id ) >= op.amount, "Insufficient balance" ); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } @@ -735,8 +735,7 @@ operation_result asset_settle_evaluator::do_apply(const asset_settle_evaluator:: { if( d.get_dynamic_global_properties().next_maintenance_time > HARDFORK_CORE_184_TIME ) FC_THROW( "Settle amount is too small to receive anything due to rounding" ); - else // TODO remove this warning after hard fork core-184 - wlog( "Something for nothing issue (#184, variant F) occurred at block #${block}", ("block",d.head_block_num()) ); + // else do nothing. Before the hf, something for nothing issue (#184, variant F) could occur } asset pays = op.amount; @@ -755,7 +754,14 @@ operation_result asset_settle_evaluator::do_apply(const asset_settle_evaluator:: obj.settlement_fund -= settled_amount.amount; }); - d.adjust_balance( op.account, settled_amount ); + if( d.head_block_time() >= HARDFORK_CORE_1780_TIME ) + { + auto issuer_fees = d.pay_market_fees( fee_paying_account, settled_amount.asset_id(d), settled_amount ); + settled_amount -= issuer_fees; + } + + if( settled_amount.amount > 0 ) + d.adjust_balance( op.account, settled_amount ); } d.modify( mia_dyn, [&]( asset_dynamic_data_object& obj ){ From 140f0224d114085bc09dda5f50279d2ef6ecd3a7 Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 9 Apr 2020 17:01:33 +0000 Subject: [PATCH 6/8] Update test cases * Add new test cases for instant settlement market fee sharing * Update old test cases to test more data --- tests/tests/settle_tests.cpp | 208 ++++++++++++++++++++++++++++++----- 1 file changed, 182 insertions(+), 26 deletions(-) diff --git a/tests/tests/settle_tests.cpp b/tests/tests/settle_tests.cpp index 2681bf3ea3..eb9331138d 100644 --- a/tests/tests/settle_tests.cpp +++ b/tests/tests/settle_tests.cpp @@ -1598,16 +1598,69 @@ BOOST_AUTO_TEST_CASE( market_fee_of_settle_order_before_hardfork_1780 ) generate_blocks( db.head_block_time() + fc::hours(24) ); set_expiration( db, trx ); - // 1 biteur = 20 bitusd see publish_feed - const auto biteur_expected_result = rachel_bitusd_count/20; - BOOST_CHECK_EQUAL( get_balance(rachel, biteur), biteur_expected_result/2/*market fee percent = 50%*/ ); - BOOST_CHECK_EQUAL( get_balance(rachel, bitusd), 0 ); + // Check results + int64_t biteur_balance = 0; + int64_t biteur_accumulated_fee = 0; + int64_t bitusd_accumulated_fee = 0; + { + // 1 biteur = 20 bitusd see publish_feed + const auto biteur_expected_result = rachel_bitusd_count/20; + const auto biteur_market_fee = biteur_expected_result / 2; // market fee percent = 50% + biteur_balance += biteur_expected_result - biteur_market_fee; + + BOOST_CHECK_EQUAL( get_balance(rachel, biteur), biteur_balance ); + BOOST_CHECK_EQUAL( get_balance(rachel, bitusd), 0 ); + + const auto rachelregistrar_reward = get_market_fee_reward( rachelregistrar, biteur ); + const auto rachelreferrer_reward = get_market_fee_reward( rachelreferrer, biteur ); + + BOOST_CHECK_EQUAL( rachelregistrar_reward, 0 ); + BOOST_CHECK_EQUAL( rachelreferrer_reward, 0 ); + + // market fee + biteur_accumulated_fee += biteur_market_fee; + bitusd_accumulated_fee += 0; // usd market fee percent 50%, but call orders don't pay + BOOST_CHECK_EQUAL( biteur.dynamic_data(db).accumulated_fees.value, biteur_accumulated_fee); + BOOST_CHECK_EQUAL( bitusd.dynamic_data(db).accumulated_fees.value, bitusd_accumulated_fee ); + } + + // Update the feed to asset bitusd to trigger a global settlement + { + price_feed feed; + feed.settlement_price = price( bitusd.amount(10), biteur.amount(5) ); + feed.core_exchange_rate = price( bitusd.amount(100), asset(1) ); + feed.maintenance_collateral_ratio = 175 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + feed.maximum_short_squeeze_ratio = 110 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + publish_feed( bitusd_id, paul_id, feed ); + } + + // Transfer more bitusd to rachel + transfer( paul_id, rachel_id, asset(rachel_bitusd_count, bitusd_id) ); + // Instant settlement + force_settle( rachel, bitusd.amount(rachel_bitusd_count) ); + + // Check results + { + // 950 biteur = 9000 bitusd in settlement fund + const auto biteur_expected_result = rachel_bitusd_count * 950 / 9000; + const auto biteur_market_fee = 0; // market fee percent = 50%, but doesn't pay before hf + biteur_balance += biteur_expected_result - biteur_market_fee; + + BOOST_CHECK_EQUAL( get_balance(rachel, biteur), biteur_balance ); + BOOST_CHECK_EQUAL( get_balance(rachel, bitusd), 0 ); + + const auto rachelregistrar_reward = get_market_fee_reward( rachelregistrar, biteur ); + const auto rachelreferrer_reward = get_market_fee_reward( rachelreferrer, biteur ); - const auto rachelregistrar_reward = get_market_fee_reward( rachelregistrar, biteur ); - const auto rachelreferrer_reward = get_market_fee_reward( rachelreferrer, biteur ); + BOOST_CHECK_EQUAL( rachelregistrar_reward, 0 ); + BOOST_CHECK_EQUAL( rachelreferrer_reward, 0 ); - BOOST_CHECK_EQUAL( rachelregistrar_reward, 0 ); - BOOST_CHECK_EQUAL( rachelreferrer_reward, 0 ); + // No market fee for instant settlement before hf + biteur_accumulated_fee += 0; + bitusd_accumulated_fee += 0; + BOOST_CHECK_EQUAL( biteur.dynamic_data(db).accumulated_fees.value, biteur_accumulated_fee); + BOOST_CHECK_EQUAL( bitusd.dynamic_data(db).accumulated_fees.value, bitusd_accumulated_fee ); + } } FC_LOG_AND_RETHROW() } @@ -1666,28 +1719,131 @@ BOOST_AUTO_TEST_CASE( market_fee_of_settle_order_after_hardfork_1780 ) generate_blocks( db.head_block_time() + fc::hours(24) ); set_expiration( db, trx ); - // 1 biteur = 20 bitusd see publish_feed - const auto biteur_expected_result = rachel_bitusd_count/20; - BOOST_CHECK_EQUAL( get_balance(rachel_id, biteur_id), biteur_expected_result/2/*market fee percent = 50%*/ ); - BOOST_CHECK_EQUAL( get_balance(rachel_id, bitusd_id), 0 ); + // Check results + int64_t biteur_balance = 0; + int64_t biteur_accumulated_fee = 0; + int64_t bitusd_accumulated_fee = 0; + { + // 1 biteur = 20 bitusd see publish_feed + const auto biteur_expected_result = rachel_bitusd_count/20; + const auto biteur_market_fee = biteur_expected_result / 2; // market fee percent = 50% + biteur_balance += biteur_expected_result - biteur_market_fee; + + BOOST_CHECK_EQUAL( get_balance(rachel, biteur), biteur_balance ); + BOOST_CHECK_EQUAL( get_balance(rachel, bitusd), 0 ); - const auto rachelregistrar_reward = get_market_fee_reward( rachelregistrar_id(db), biteur_id(db) ); - const auto rachelreferrer_reward = get_market_fee_reward( rachelreferrer_id(db), biteur_id(db) ); + const auto rachelregistrar_reward = get_market_fee_reward( rachelregistrar, biteur ); + const auto rachelreferrer_reward = get_market_fee_reward( rachelreferrer, biteur ); - BOOST_CHECK_GT( rachelregistrar_reward, 0 ); - BOOST_CHECK_GT( rachelreferrer_reward, 0 ); + const auto biteur_reward = biteur_market_fee * 9 / 10; // 90% + const auto referrer_reward = biteur_reward / 10; // 10% + const auto registrar_reward = biteur_reward - referrer_reward; - auto calculate_percent = [](const share_type& value, uint16_t percent) + BOOST_CHECK_EQUAL( rachelregistrar_reward, registrar_reward ); + BOOST_CHECK_EQUAL( rachelreferrer_reward, referrer_reward ); + + // market fee + biteur_accumulated_fee += biteur_market_fee - biteur_reward; + bitusd_accumulated_fee += 0; // usd market fee percent 50%, but call orders don't pay + BOOST_CHECK_EQUAL( biteur.dynamic_data(db).accumulated_fees.value, biteur_accumulated_fee); + BOOST_CHECK_EQUAL( bitusd.dynamic_data(db).accumulated_fees.value, bitusd_accumulated_fee ); + + } + + } FC_LOG_AND_RETHROW() +} + +BOOST_AUTO_TEST_CASE( market_fee_of_instant_settle_order_after_hardfork_1780 ) +{ + try { + INVOKE(create_bitassets); + + generate_blocks( HARDFORK_CORE_1780_TIME ); + set_expiration( db, trx ); + + GET_ACTOR(paul); + GET_ACTOR(rachel); + GET_ACTOR(rachelregistrar); + GET_ACTOR(rachelreferrer); + + const asset_object &biteur = get_asset( "EURBIT" ); + asset_id_type biteur_id = biteur.id; + const asset_object &bitusd = get_asset( "USDBIT" ); + asset_id_type bitusd_id = bitusd.id; + + const auto& core = asset_id_type()(db); + + {// add a feed to asset bitusd + update_feed_producers( bitusd, {paul_id} ); + price_feed feed; + feed.settlement_price = price( bitusd.amount(100), biteur.amount(5) ); + feed.core_exchange_rate = price( bitusd.amount(100), asset(1) ); + feed.maintenance_collateral_ratio = 175 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + feed.maximum_short_squeeze_ratio = 110 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + publish_feed( bitusd_id, paul_id, feed ); + } + + {// add a feed to asset biteur + update_feed_producers( biteur, {paul_id} ); + price_feed feed; + feed.settlement_price = price( biteur.amount(100), core.amount(5) ); + feed.maintenance_collateral_ratio = 175 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + feed.maximum_short_squeeze_ratio = 110 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + publish_feed( biteur_id, paul_id, feed ); + } + + enable_fees(); + + // paul gets some bitusd and biteur + borrow( paul_id, biteur.amount(20000), core.amount(2000) ); + borrow( paul_id, bitusd.amount(10000), biteur.amount(1000) ); + + // Update the feed to asset bitusd to trigger a global settlement { - auto a(value.value); - a *= percent; - a /= GRAPHENE_100_PERCENT; - return a; - }; - - const auto biteur_market_fee = calculate_percent( biteur_expected_result, 50 * GRAPHENE_1_PERCENT ); - const auto biteur_reward = calculate_percent( biteur_market_fee, 90*GRAPHENE_1_PERCENT ); - BOOST_CHECK_EQUAL( biteur_reward, rachelregistrar_reward + rachelreferrer_reward ); + price_feed feed; + feed.settlement_price = price( bitusd.amount(10), biteur.amount(5) ); + feed.core_exchange_rate = price( bitusd.amount(100), asset(1) ); + feed.maintenance_collateral_ratio = 175 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + feed.maximum_short_squeeze_ratio = 110 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + publish_feed( bitusd_id, paul_id, feed ); + } + + // Transfer some bitusd to rachel + constexpr auto rachel_bitusd_count = 1000; + transfer( paul_id, rachel_id, asset(rachel_bitusd_count, bitusd_id) ); + // Instant settlement + force_settle( rachel, bitusd.amount(rachel_bitusd_count) ); // instant settlement + + // Check results + int64_t biteur_balance = 0; + int64_t biteur_accumulated_fee = 0; + int64_t bitusd_accumulated_fee = 0; + { + // 1000 biteur = 10000 bitusd in settlement fund + const auto biteur_expected_result = rachel_bitusd_count/10; + const auto biteur_market_fee = biteur_expected_result / 2; // market fee percent = 50% + biteur_balance += biteur_expected_result - biteur_market_fee; + + BOOST_CHECK_EQUAL( get_balance(rachel, biteur), biteur_balance ); + BOOST_CHECK_EQUAL( get_balance(rachel, bitusd), 0 ); + + const auto rachelregistrar_reward = get_market_fee_reward( rachelregistrar, biteur ); + const auto rachelreferrer_reward = get_market_fee_reward( rachelreferrer, biteur ); + + const auto biteur_reward = biteur_market_fee * 9 / 10; // 90% + const auto referrer_reward = biteur_reward / 10; // 10% + const auto registrar_reward = biteur_reward - referrer_reward; + + BOOST_CHECK_EQUAL( rachelregistrar_reward, registrar_reward ); + BOOST_CHECK_EQUAL( rachelreferrer_reward, referrer_reward ); + + // market fee + biteur_accumulated_fee += biteur_market_fee - biteur_reward; + bitusd_accumulated_fee += 0; // usd market fee percent 50%, but call orders don't pay + BOOST_CHECK_EQUAL( biteur.dynamic_data(db).accumulated_fees.value, biteur_accumulated_fee); + BOOST_CHECK_EQUAL( bitusd.dynamic_data(db).accumulated_fees.value, bitusd_accumulated_fee ); + + } } FC_LOG_AND_RETHROW() } From 88727de9d39f185eec83fd753d166d5f489fbec8 Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 9 Apr 2020 17:15:00 +0000 Subject: [PATCH 7/8] Wrap long lines --- tests/tests/market_fee_sharing_tests.cpp | 3 ++- tests/tests/settle_tests.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/tests/market_fee_sharing_tests.cpp b/tests/tests/market_fee_sharing_tests.cpp index 1fa634acb6..ad0b533863 100644 --- a/tests/tests/market_fee_sharing_tests.cpp +++ b/tests/tests/market_fee_sharing_tests.cpp @@ -436,7 +436,8 @@ BOOST_AUTO_TEST_CASE(create_actors) price price(asset(1, asset_id_type(1)), asset(1)); uint16_t market_fee_percent = 20 * GRAPHENE_1_PERCENT; - const asset_object jillcoin = create_user_issued_asset( "JCOIN", jill, charge_market_fee, price, 2, market_fee_percent ); + const asset_object jillcoin = create_user_issued_asset( "JCOIN", jill, charge_market_fee, + price, 2, market_fee_percent ); const account_object alice = create_account("alice", izzyregistrar, izzyreferrer, 50/*0.5%*/); const account_object bob = create_account("bob", izzyregistrar, izzyreferrer, 50/*0.5%*/); diff --git a/tests/tests/settle_tests.cpp b/tests/tests/settle_tests.cpp index eb9331138d..51e4c24036 100644 --- a/tests/tests/settle_tests.cpp +++ b/tests/tests/settle_tests.cpp @@ -1523,7 +1523,8 @@ BOOST_AUTO_TEST_CASE( create_bitassets ) const auto& bitusd = create_bitasset( "USDBIT", paul_id, market_fee_percent, charge_market_fee, 2, biteur_id ); - const account_object rachel = create_account( "rachel", rachelregistrar, rachelreferrer, referrer_reward_percent ); + const account_object rachel = create_account( "rachel", rachelregistrar, rachelreferrer, + referrer_reward_percent ); transfer( committee_account, rachelregistrar_id, asset( 10000000 ) ); transfer( committee_account, rachelreferrer_id, asset( 10000000 ) ); From c54302fef6285c50a778a958aff28d4aba043c23 Mon Sep 17 00:00:00 2001 From: abitmore Date: Fri, 10 Apr 2020 13:39:37 +0000 Subject: [PATCH 8/8] Update comments --- libraries/chain/asset_evaluator.cpp | 5 +++++ libraries/chain/db_market.cpp | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index f8df7203af..5e6460a089 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -754,6 +754,11 @@ operation_result asset_settle_evaluator::do_apply(const asset_settle_evaluator:: obj.settlement_fund -= settled_amount.amount; }); + // The account who settles pays market fees to the issuer of the collateral asset after HF core-1780 + // + // TODO Check whether the HF check can be removed after the HF. + // Note: even if logically it can be removed, perhaps the removal will lead to a small + // performance loss. Needs testing. if( d.head_block_time() >= HARDFORK_CORE_1780_TIME ) { auto issuer_fees = d.pay_market_fees( fee_paying_account, settled_amount.asset_id(d), settled_amount ); diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index dcd2be96f5..18ad895fbb 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -919,8 +919,9 @@ bool database::fill_settle_order( const force_settlement_object& settle, const a const account_object* settle_owner_ptr = nullptr; // The owner of the settle order pays market fees to the issuer of the collateral asset after HF core-1780 // - // TODO It's possible that the HF check can be removed after the HF for cleaner code and a potential small - // performance gain, however the cleanup could also lead to a small performance loss. Needs testing. + // TODO Check whether the HF check can be removed after the HF. + // Note: even if logically it can be removed, perhaps the removal will lead to a small performance + // loss. Needs testing. if( head_block_time() >= HARDFORK_CORE_1780_TIME ) settle_owner_ptr = &settle.owner(*this);