From 0cb12741c61321005ea740f3e3e7140edb7f62f7 Mon Sep 17 00:00:00 2001 From: John Jones Date: Thu, 27 Dec 2018 15:55:16 -0500 Subject: [PATCH 1/9] check max_supply before borrowing MPAs --- libraries/chain/market_evaluator.cpp | 4 ++ tests/common/database_fixture.cpp | 2 +- tests/tests/operation_tests.cpp | 68 +++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/libraries/chain/market_evaluator.cpp b/libraries/chain/market_evaluator.cpp index 62dfc7c7b4..544aef320b 100644 --- a/libraries/chain/market_evaluator.cpp +++ b/libraries/chain/market_evaluator.cpp @@ -167,6 +167,10 @@ void_result call_order_update_evaluator::do_evaluate(const call_order_update_ope FC_ASSERT( _debt_asset->is_market_issued(), "Unable to cover ${sym} as it is not a collateralized asset.", ("sym", _debt_asset->symbol) ); + const auto& dyn_data = _debt_asset->dynamic_data(d); + FC_ASSERT( dyn_data.current_supply + o.delta_debt.amount <= _debt_asset->options.max_supply, + "Borrowing this quantity would exceed MAX_SUPPLY" ); + _bitasset_data = &_debt_asset->bitasset_data(d); /// if there is a settlement for this asset, then no further margin positions may be taken and diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 874e2f8241..b976e1c2af 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -451,7 +451,7 @@ const asset_object& database_fixture::create_bitasset( creator.issuer = issuer; creator.fee = asset(); creator.symbol = name; - creator.common_options.max_supply = GRAPHENE_MAX_SHARE_SUPPLY; + creator.common_options.max_supply = GRAPHENE_MAX_SHARE_SUPPLY / 2; creator.precision = precision; creator.common_options.market_fee_percent = market_fee_percent; if( issuer == GRAPHENE_WITNESS_ACCOUNT ) diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 398eb42b11..fd95424b17 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -592,7 +592,6 @@ BOOST_AUTO_TEST_CASE( call_order_update_validation_test ) op.extensions.value.target_collateral_ratio = 65535; op.validate(); // still valid - } // Tests that target_cr option can't be set before hard fork core-834 @@ -2004,6 +2003,73 @@ BOOST_AUTO_TEST_CASE( reserve_asset_test ) } } +BOOST_AUTO_TEST_CASE( call_order_update_evaluator_test ) +{ + try + { + ACTORS( (alice) (bob) ); + transfer(committee_account, alice_id, asset(1000000 * GRAPHENE_BLOCKCHAIN_PRECISION)); + + const auto& bitusd = create_bitasset( "USDBIT", alice_id ); + const auto& core = asset_id_type()(db); + + BOOST_TEST_MESSAGE( "Setting price feed to $100000 / 1" ); + update_feed_producers( bitusd, {alice_id} ); + price_feed current_feed; + current_feed.settlement_price = bitusd.amount( 100000 ) / core.amount(1); + publish_feed( bitusd, alice, current_feed ); + + { + BOOST_TEST_MESSAGE( "Attempting a call_order_update that exceeds max_supply" ); + call_order_update_operation op; + op.funding_account = alice_id; + op.delta_collateral = asset( 1000000 * GRAPHENE_BLOCKCHAIN_PRECISION ); + op.delta_debt = asset( bitusd.options.max_supply + 1, bitusd.id ); + transaction tx; + tx.operations.push_back( op ); + set_expiration( db, tx ); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, tx, database::skip_tapos_check | database::skip_transaction_signatures ), fc::exception ); + } + + { + BOOST_TEST_MESSAGE( "Creating 2 bitusd and transferring to bob (increases current supply)" ); + call_order_update_operation op; + op.funding_account = alice_id; + op.delta_collateral = asset( 100 * GRAPHENE_BLOCKCHAIN_PRECISION ); + op.delta_debt = asset( 2, bitusd.id ); + transaction tx; + tx.operations.push_back( op ); + set_expiration( db, tx ); + PUSH_TX( db, tx, database::skip_tapos_check | database::skip_transaction_signatures ); + transfer( alice, bob, asset( 2, bitusd.id ) ); + } + + { + BOOST_TEST_MESSAGE( "Again attempting a call_order_update_operation that is max_supply - 1 (should throw)" ); + call_order_update_operation op; + op.funding_account = alice_id; + op.delta_collateral = asset( 100000 * GRAPHENE_BLOCKCHAIN_PRECISION ); + op.delta_debt = asset( bitusd.options.max_supply - 1, bitusd.id ); + transaction tx; + tx.operations.push_back( op ); + set_expiration( db, tx ); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, tx, database::skip_tapos_check | database::skip_transaction_signatures ), fc::exception); + } + + { + BOOST_TEST_MESSAGE( "Again attempting a call_order_update_operation that equals max_supply (should work)" ); + call_order_update_operation op; + op.funding_account = alice_id; + op.delta_collateral = asset( 100000 * GRAPHENE_BLOCKCHAIN_PRECISION ); + op.delta_debt = asset( bitusd.options.max_supply - 2, bitusd.id ); + transaction tx; + tx.operations.push_back( op ); + set_expiration( db, tx ); + PUSH_TX( db, tx, database::skip_tapos_check | database::skip_transaction_signatures ); + } + } FC_LOG_AND_RETHROW() +} + /** * This test demonstrates how using the call_order_update_operation to * trigger a margin call is legal if there is a matching order. From e00383305331a33bb986014295907cbce1a83860 Mon Sep 17 00:00:00 2001 From: John Jones Date: Thu, 27 Dec 2018 16:01:15 -0500 Subject: [PATCH 2/9] Remove unnecessary variable --- libraries/chain/market_evaluator.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/chain/market_evaluator.cpp b/libraries/chain/market_evaluator.cpp index 544aef320b..d8999455f5 100644 --- a/libraries/chain/market_evaluator.cpp +++ b/libraries/chain/market_evaluator.cpp @@ -167,8 +167,7 @@ void_result call_order_update_evaluator::do_evaluate(const call_order_update_ope FC_ASSERT( _debt_asset->is_market_issued(), "Unable to cover ${sym} as it is not a collateralized asset.", ("sym", _debt_asset->symbol) ); - const auto& dyn_data = _debt_asset->dynamic_data(d); - FC_ASSERT( dyn_data.current_supply + o.delta_debt.amount <= _debt_asset->options.max_supply, + FC_ASSERT( _debt_asset->dynamic_data(d).current_supply + o.delta_debt.amount <= _debt_asset->options.max_supply, "Borrowing this quantity would exceed MAX_SUPPLY" ); _bitasset_data = &_debt_asset->bitasset_data(d); From d58e523b4e73ea502d9fb93a280ed8cf13ce9e8d Mon Sep 17 00:00:00 2001 From: John Jones Date: Mon, 31 Dec 2018 12:40:53 -0500 Subject: [PATCH 3/9] Add hardfork protection --- libraries/chain/hardfork.d/CORE_1465.hf | 4 ++++ libraries/chain/market_evaluator.cpp | 9 ++++++--- tests/tests/operation_tests.cpp | 4 ++++ 3 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 libraries/chain/hardfork.d/CORE_1465.hf diff --git a/libraries/chain/hardfork.d/CORE_1465.hf b/libraries/chain/hardfork.d/CORE_1465.hf new file mode 100644 index 0000000000..bdedbf8052 --- /dev/null +++ b/libraries/chain/hardfork.d/CORE_1465.hf @@ -0,0 +1,4 @@ +// bitshares-core issue #1465 check max_supply before processing call_order_update +#ifndef HARDFORK_CORE_1465_TIME +#define HARDFORK_CORE_1465_TIME (fc::time_point_sec( 1600000000 )) // 2020-09-13 12:26:40 +#endif diff --git a/libraries/chain/market_evaluator.cpp b/libraries/chain/market_evaluator.cpp index d8999455f5..d96a1d1668 100644 --- a/libraries/chain/market_evaluator.cpp +++ b/libraries/chain/market_evaluator.cpp @@ -157,8 +157,10 @@ void_result call_order_update_evaluator::do_evaluate(const call_order_update_ope { try { database& d = db(); + auto next_maintenance_time = d.get_dynamic_global_properties().next_maintenance_time; + // TODO: remove this check and the assertion after hf_834 - if( d.get_dynamic_global_properties().next_maintenance_time <= HARDFORK_CORE_834_TIME ) + if( next_maintenance_time <= HARDFORK_CORE_834_TIME ) FC_ASSERT( !o.extensions.value.target_collateral_ratio.valid(), "Can not set target_collateral_ratio in call_order_update_operation before hardfork 834." ); @@ -167,8 +169,9 @@ void_result call_order_update_evaluator::do_evaluate(const call_order_update_ope FC_ASSERT( _debt_asset->is_market_issued(), "Unable to cover ${sym} as it is not a collateralized asset.", ("sym", _debt_asset->symbol) ); - FC_ASSERT( _debt_asset->dynamic_data(d).current_supply + o.delta_debt.amount <= _debt_asset->options.max_supply, - "Borrowing this quantity would exceed MAX_SUPPLY" ); + FC_ASSERT( next_maintenance_time <= HARDFORK_CORE_1465_TIME + || _debt_asset->dynamic_data(d).current_supply + o.delta_debt.amount <= _debt_asset->options.max_supply, + "Borrowing this quantity would exceed MAX_SUPPLY" ); _bitasset_data = &_debt_asset->bitasset_data(d); diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index fd95424b17..e8206df1b6 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -2010,6 +2010,10 @@ BOOST_AUTO_TEST_CASE( call_order_update_evaluator_test ) ACTORS( (alice) (bob) ); transfer(committee_account, alice_id, asset(1000000 * GRAPHENE_BLOCKCHAIN_PRECISION)); + // advance past hardfork + generate_blocks( HARDFORK_CORE_1465_TIME ); + set_expiration( db, trx ); + const auto& bitusd = create_bitasset( "USDBIT", alice_id ); const auto& core = asset_id_type()(db); From 52b6c7ea8385be36e625a075dc1e2db857151bf5 Mon Sep 17 00:00:00 2001 From: John Jones Date: Thu, 3 Jan 2019 14:11:24 -0500 Subject: [PATCH 4/9] Add hard-fork maintenance logic. Test needed. --- libraries/chain/db_maint.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 4ee7cb2825..5090b50b14 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -919,6 +919,30 @@ void database::process_bitassets() } } +/**** + * @brief a one-time data process to correct max_supply + */ +void process_hf_1465( database& db ) +{ + const auto head_time = db.head_block_time(); + const auto head_num = db.head_block_num(); + wlog( "Processing hard fork core-1465 at block ${n}", ("n",head_num) ); + // for each market issued asset + const auto& asset_idx = db.get_index_type().indices().get(); + for( auto asset_itr = asset_idx.lower_bound(true); asset_itr != asset_idx.end(); ++asset_itr ) + { + const auto& current_asset = *asset_itr; + graphene::chain::share_type current_supply = current_asset.dynamic_data(db).current_supply; + graphene::chain::share_type max_supply = current_asset.options.max_supply; + if (current_supply > max_supply && max_supply != GRAPHENE_MAX_SHARE_SUPPLY) + { + db.modify( current_asset, [current_supply](asset_object& obj) { + obj.options.max_supply = graphene::chain::share_type(std::min(current_supply.value, GRAPHENE_MAX_SHARE_SUPPLY)); + }); + } + } +} + /****** * @brief one-time data process for hard fork core-868-890 * @@ -1225,6 +1249,10 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g && !to_update_and_match_call_orders ) process_hf_935( *this ); + // make sure current_supply is less than or equal to max_supply + if ( dgpo.next_maintenance_time <= HARDFORK_CORE_1465_TIME && next_maintenance_time > HARDFORK_CORE_1465_TIME ) + process_hf_1465(*this); + modify(dgpo, [next_maintenance_time](dynamic_global_property_object& d) { d.next_maintenance_time = next_maintenance_time; d.accounts_registered_this_interval = 0; From bc45e8b5d8ddd6e29f7999365c95c6f578eb4fe8 Mon Sep 17 00:00:00 2001 From: John Jones Date: Thu, 3 Jan 2019 14:32:25 -0500 Subject: [PATCH 5/9] Included pre-hardfork test --- tests/tests/operation_tests.cpp | 47 ++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index e8206df1b6..0d00dcbc35 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -2008,20 +2008,53 @@ BOOST_AUTO_TEST_CASE( call_order_update_evaluator_test ) try { ACTORS( (alice) (bob) ); - transfer(committee_account, alice_id, asset(1000000 * GRAPHENE_BLOCKCHAIN_PRECISION)); + transfer(committee_account, alice_id, asset(10000000 * GRAPHENE_BLOCKCHAIN_PRECISION)); + + const auto& core = asset_id_type()(db); + + // attempt to increase current supply beyond max_supply + const auto& bitjmj = create_bitasset( "JMJBIT", alice_id ); + share_type original_max_supply = bitjmj.options.max_supply; + + { + BOOST_TEST_MESSAGE( "Setting price feed to $100000 / 1" ); + update_feed_producers( bitjmj, {alice_id} ); + price_feed current_feed; + current_feed.settlement_price = bitjmj.amount( 100000 ) / core.amount(1); + publish_feed( bitjmj, alice, current_feed ); + } + + { + BOOST_TEST_MESSAGE( "Attempting a call_order_update that exceeds max_supply" ); + call_order_update_operation op; + op.funding_account = alice_id; + op.delta_collateral = asset( 1000000 * GRAPHENE_BLOCKCHAIN_PRECISION ); + op.delta_debt = asset( bitjmj.options.max_supply + 1, bitjmj.id ); + transaction tx; + tx.operations.push_back( op ); + set_expiration( db, tx ); + PUSH_TX( db, tx, database::skip_tapos_check | database::skip_transaction_signatures ); + generate_block(); + } // advance past hardfork generate_blocks( HARDFORK_CORE_1465_TIME ); set_expiration( db, trx ); + // bitjmj should have its problem corrected + auto newbitjmj = bitjmj.get_id()(db); + BOOST_REQUIRE_GT(newbitjmj.options.max_supply.value, original_max_supply.value); + + // now try with an asset after the hardfork const auto& bitusd = create_bitasset( "USDBIT", alice_id ); - const auto& core = asset_id_type()(db); - BOOST_TEST_MESSAGE( "Setting price feed to $100000 / 1" ); - update_feed_producers( bitusd, {alice_id} ); - price_feed current_feed; - current_feed.settlement_price = bitusd.amount( 100000 ) / core.amount(1); - publish_feed( bitusd, alice, current_feed ); + { + BOOST_TEST_MESSAGE( "Setting price feed to $100000 / 1" ); + update_feed_producers( bitusd, {alice_id} ); + price_feed current_feed; + current_feed.settlement_price = bitusd.amount( 100000 ) / core.amount(1); + publish_feed( bitusd, alice, current_feed ); + } { BOOST_TEST_MESSAGE( "Attempting a call_order_update that exceeds max_supply" ); From 5928010ff503e98cc6356334fce00b84b99fb4a8 Mon Sep 17 00:00:00 2001 From: John Jones Date: Mon, 7 Jan 2019 15:45:52 -0500 Subject: [PATCH 6/9] Added log message at hardfork, fixed test --- libraries/chain/db_maint.cpp | 4 ++++ tests/tests/operation_tests.cpp | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 5090b50b14..d0b6dc6426 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -936,6 +936,10 @@ void process_hf_1465( database& db ) graphene::chain::share_type max_supply = current_asset.options.max_supply; if (current_supply > max_supply && max_supply != GRAPHENE_MAX_SHARE_SUPPLY) { + wlog( "Adjusting max_supply of ${asset} because current_supply (${current_supply}) is greater than ${old}.", + ("asset", current_asset.symbol) + ("current_supply", current_supply.value) + ("old", max_supply)); db.modify( current_asset, [current_supply](asset_object& obj) { obj.options.max_supply = graphene::chain::share_type(std::min(current_supply.value, GRAPHENE_MAX_SHARE_SUPPLY)); }); diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 0d00dcbc35..fe5481cf15 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -2014,6 +2014,7 @@ BOOST_AUTO_TEST_CASE( call_order_update_evaluator_test ) // attempt to increase current supply beyond max_supply const auto& bitjmj = create_bitasset( "JMJBIT", alice_id ); + auto bitjmj_id = bitjmj.get_id(); share_type original_max_supply = bitjmj.options.max_supply; { @@ -2042,7 +2043,7 @@ BOOST_AUTO_TEST_CASE( call_order_update_evaluator_test ) set_expiration( db, trx ); // bitjmj should have its problem corrected - auto newbitjmj = bitjmj.get_id()(db); + auto newbitjmj = bitjmj_id(db); BOOST_REQUIRE_GT(newbitjmj.options.max_supply.value, original_max_supply.value); // now try with an asset after the hardfork From 6c5e48f94044c00b0a99159da49aaae5bfd783f9 Mon Sep 17 00:00:00 2001 From: John Jones Date: Tue, 8 Jan 2019 11:09:42 -0500 Subject: [PATCH 7/9] fix old reference in test --- tests/tests/operation_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index fe5481cf15..771074267a 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -2054,7 +2054,7 @@ BOOST_AUTO_TEST_CASE( call_order_update_evaluator_test ) update_feed_producers( bitusd, {alice_id} ); price_feed current_feed; current_feed.settlement_price = bitusd.amount( 100000 ) / core.amount(1); - publish_feed( bitusd, alice, current_feed ); + publish_feed( bitusd, alice_id(db), current_feed ); } { @@ -2079,7 +2079,7 @@ BOOST_AUTO_TEST_CASE( call_order_update_evaluator_test ) tx.operations.push_back( op ); set_expiration( db, tx ); PUSH_TX( db, tx, database::skip_tapos_check | database::skip_transaction_signatures ); - transfer( alice, bob, asset( 2, bitusd.id ) ); + transfer( alice_id(db), bob_id(db), asset( 2, bitusd.id ) ); } { From 097799bf7d3adddbcc33b873a0473351f7e06fb3 Mon Sep 17 00:00:00 2001 From: John Jones Date: Fri, 18 Jan 2019 16:41:35 -0500 Subject: [PATCH 8/9] Save a ptr to asset_dynamic_data_object --- libraries/chain/db_maint.cpp | 1 - .../chain/include/graphene/chain/market_evaluator.hpp | 1 + libraries/chain/market_evaluator.cpp | 7 +++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index d0b6dc6426..84e0b990bb 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -924,7 +924,6 @@ void database::process_bitassets() */ void process_hf_1465( database& db ) { - const auto head_time = db.head_block_time(); const auto head_num = db.head_block_num(); wlog( "Processing hard fork core-1465 at block ${n}", ("n",head_num) ); // for each market issued asset diff --git a/libraries/chain/include/graphene/chain/market_evaluator.hpp b/libraries/chain/include/graphene/chain/market_evaluator.hpp index 96a4ac07ed..af66323578 100644 --- a/libraries/chain/include/graphene/chain/market_evaluator.hpp +++ b/libraries/chain/include/graphene/chain/market_evaluator.hpp @@ -87,6 +87,7 @@ namespace graphene { namespace chain { const account_object* _paying_account = nullptr; const call_order_object* _order = nullptr; const asset_bitasset_data_object* _bitasset_data = nullptr; + const asset_dynamic_data_object* _dynamic_data_obj = nullptr; }; class bid_collateral_evaluator : public evaluator diff --git a/libraries/chain/market_evaluator.cpp b/libraries/chain/market_evaluator.cpp index d96a1d1668..d63d1be06e 100644 --- a/libraries/chain/market_evaluator.cpp +++ b/libraries/chain/market_evaluator.cpp @@ -188,6 +188,10 @@ void_result call_order_update_evaluator::do_evaluate(const call_order_update_ope else if( _bitasset_data->current_feed.settlement_price.is_null() ) FC_THROW_EXCEPTION(insufficient_feeds, "Cannot borrow asset with no price feed."); + _dynamic_data_obj = &_debt_asset->dynamic_asset_data_id(d); + FC_ASSERT( _dynamic_data_obj->current_supply + o.delta_debt.amount >= 0, + "This transaction would bring current supply below zero."); + // Note: there was code here checking whether the account has enough balance to increase delta collateral, // which is now removed since the check is implicitly done later by `adjust_balance()` in `do_apply()`. @@ -204,9 +208,8 @@ object_id_type call_order_update_evaluator::do_apply(const call_order_update_ope d.adjust_balance( o.funding_account, o.delta_debt ); // Deduct the debt paid from the total supply of the debt asset. - d.modify(_debt_asset->dynamic_asset_data_id(d), [&](asset_dynamic_data_object& dynamic_asset) { + d.modify(*_dynamic_data_obj, [&](asset_dynamic_data_object& dynamic_asset) { dynamic_asset.current_supply += o.delta_debt.amount; - FC_ASSERT(dynamic_asset.current_supply >= 0); }); } From ab4dfeb59cac1ea7d48511515e80a713006ad6a2 Mon Sep 17 00:00:00 2001 From: John Jones Date: Fri, 25 Jan 2019 15:48:24 -0500 Subject: [PATCH 9/9] use newly added member in all places --- libraries/chain/market_evaluator.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/chain/market_evaluator.cpp b/libraries/chain/market_evaluator.cpp index d63d1be06e..df3c6cb53e 100644 --- a/libraries/chain/market_evaluator.cpp +++ b/libraries/chain/market_evaluator.cpp @@ -169,10 +169,14 @@ void_result call_order_update_evaluator::do_evaluate(const call_order_update_ope FC_ASSERT( _debt_asset->is_market_issued(), "Unable to cover ${sym} as it is not a collateralized asset.", ("sym", _debt_asset->symbol) ); + _dynamic_data_obj = &_debt_asset->dynamic_asset_data_id(d); FC_ASSERT( next_maintenance_time <= HARDFORK_CORE_1465_TIME - || _debt_asset->dynamic_data(d).current_supply + o.delta_debt.amount <= _debt_asset->options.max_supply, + || _dynamic_data_obj->current_supply + o.delta_debt.amount <= _debt_asset->options.max_supply, "Borrowing this quantity would exceed MAX_SUPPLY" ); + FC_ASSERT( _dynamic_data_obj->current_supply + o.delta_debt.amount >= 0, + "This transaction would bring current supply below zero."); + _bitasset_data = &_debt_asset->bitasset_data(d); /// if there is a settlement for this asset, then no further margin positions may be taken and @@ -188,10 +192,6 @@ void_result call_order_update_evaluator::do_evaluate(const call_order_update_ope else if( _bitasset_data->current_feed.settlement_price.is_null() ) FC_THROW_EXCEPTION(insufficient_feeds, "Cannot borrow asset with no price feed."); - _dynamic_data_obj = &_debt_asset->dynamic_asset_data_id(d); - FC_ASSERT( _dynamic_data_obj->current_supply + o.delta_debt.amount >= 0, - "This transaction would bring current supply below zero."); - // Note: there was code here checking whether the account has enough balance to increase delta collateral, // which is now removed since the check is implicitly done later by `adjust_balance()` in `do_apply()`.