asset database::match( const call_order_object& call, const force_settlement_object& settle, const price& match_price, asset max_settlement ) { try { FC_ASSERT(call.get_debt().asset_id == settle.balance.asset_id ); FC_ASSERT(call.debt > 0 && call.collateral > 0 && settle.balance.amount > 0); auto settle_for_sale = std::min(settle.balance, max_settlement); auto call_debt = call.get_debt(); asset call_receives = std::min(settle_for_sale, call_debt); asset call_pays = call_receives * match_price; asset settle_pays = call_receives; asset settle_receives = call_pays; /** * If the least collateralized call position lacks sufficient * collateral to cover at the match price then this indicates a black * swan event according to the price feed, but only the market * can trigger a black swan. So now we must cancel the forced settlement * object. */ GRAPHENE_ASSERT( call_pays < call.get_collateral(), black_swan_exception, "" ); assert( settle_pays == settle_for_sale || call_receives == call.get_debt() ); fill_order(call, call_pays, call_receives); fill_order(settle, settle_pays, settle_receives); return call_receives; } FC_CAPTURE_AND_RETHROW( (call)(settle)(match_price)(max_settlement) ) }
bool database::fill_order( const call_order_object& order, const asset& pays, const asset& receives ) { try { //idump((pays)(receives)(order)); FC_ASSERT( order.get_debt().asset_id == receives.asset_id ); FC_ASSERT( order.get_collateral().asset_id == pays.asset_id ); FC_ASSERT( order.get_collateral() >= pays ); optional<asset> collateral_freed; modify( order, [&]( call_order_object& o ){ o.debt -= receives.amount; o.collateral -= pays.amount; if( o.debt == 0 ) { collateral_freed = o.get_collateral(); o.collateral = 0; } }); const asset_object& mia = receives.asset_id(*this); assert( mia.is_market_issued() ); const asset_dynamic_data_object& mia_ddo = mia.dynamic_asset_data_id(*this); modify( mia_ddo, [&]( asset_dynamic_data_object& ao ){ //idump((receives)); ao.current_supply -= receives.amount; }); const account_object& borrower = order.borrower(*this); if( collateral_freed || pays.asset_id == asset_id_type() ) { const account_statistics_object& borrower_statistics = borrower.statistics(*this); if( collateral_freed ) adjust_balance(borrower.get_id(), *collateral_freed); modify( borrower_statistics, [&]( account_statistics_object& b ){ if( collateral_freed && collateral_freed->amount > 0 ) b.total_core_in_orders -= collateral_freed->amount; if( pays.asset_id == asset_id_type() ) b.total_core_in_orders -= pays.amount; assert( b.total_core_in_orders >= 0 ); }); } assert( pays.asset_id != receives.asset_id ); push_applied_operation( fill_order_operation{ order.id, order.borrower, pays, receives, asset(0, pays.asset_id) } ); if( collateral_freed ) remove( order ); return collateral_freed.valid(); } FC_CAPTURE_AND_RETHROW( (order)(pays)(receives) ) }
asset database::match( const call_order_object& call, const force_settlement_object& settle, const price& match_price, asset max_settlement ) { assert(call.get_debt().asset_id == settle.balance.asset_id ); assert(call.debt > 0 && call.collateral > 0 && settle.balance.amount > 0); auto settle_for_sale = std::min(settle.balance, max_settlement); auto call_debt = call.get_debt(); asset call_receives = std::min(settle_for_sale, call_debt), call_pays = call_receives * match_price, settle_pays = call_receives, settle_receives = call_pays; assert( settle_pays == settle_for_sale || call_receives == call.get_debt() ); fill_order(call, call_pays, call_receives); fill_order(settle, settle_pays, settle_receives); return call_receives; }