void_result asset_global_settle_evaluator::do_evaluate(const asset_global_settle_evaluator::operation_type& op) { const database& d = db(); asset_to_settle = &op.asset_to_settle(d); FC_ASSERT(asset_to_settle->is_market_issued()); FC_ASSERT(asset_to_settle->can_global_settle()); FC_ASSERT(asset_to_settle->issuer == op.issuer ); FC_ASSERT(asset_to_settle->dynamic_data(d).current_supply > 0); const auto& idx = d.get_index_type<call_order_index>().indices().get<by_collateral>(); assert( !idx.empty() ); auto itr = idx.lower_bound(boost::make_tuple(price::min(asset_to_settle->bitasset_data(d).options.short_backing_asset, op.asset_to_settle))); assert( itr != idx.end() && itr->debt_type() == op.asset_to_settle ); const call_order_object& least_collateralized_short = *itr; FC_ASSERT(least_collateralized_short.get_debt() * op.settle_price <= least_collateralized_short.get_collateral(), "Cannot force settle at supplied price: least collateralized short lacks sufficient collateral to settle."); return void_result(); }
void database::clear_expired_orders() { detail::with_skip_flags( *this, get_node_properties().skip_flags | skip_authority_check, [&](){ transaction_evaluation_state cancel_context(this); //Cancel expired limit orders auto& limit_index = get_index_type<limit_order_index>().indices().get<by_expiration>(); while( !limit_index.empty() && limit_index.begin()->expiration <= head_block_time() ) { limit_order_cancel_operation canceler; const limit_order_object& order = *limit_index.begin(); canceler.fee_paying_account = order.seller; canceler.order = order.id; apply_operation(cancel_context, canceler); } }); //Process expired force settlement orders auto& settlement_index = get_index_type<force_settlement_index>().indices().get<by_expiration>(); if( !settlement_index.empty() ) { asset_id_type current_asset = settlement_index.begin()->settlement_asset_id(); asset max_settlement_volume; auto next_asset = [¤t_asset, &settlement_index] { auto bound = settlement_index.upper_bound(current_asset); if( bound == settlement_index.end() ) return false; current_asset = bound->settlement_asset_id(); return true; }; // At each iteration, we either consume the current order and remove it, or we move to the next asset for( auto itr = settlement_index.lower_bound(current_asset); itr != settlement_index.end(); itr = settlement_index.lower_bound(current_asset) ) { const force_settlement_object& order = *itr; auto order_id = order.id; current_asset = order.settlement_asset_id(); const asset_object& mia_object = get(current_asset); const asset_bitasset_data_object mia = mia_object.bitasset_data(*this); // Has this order not reached its settlement date? if( order.settlement_date > head_block_time() ) { if( next_asset() ) continue; break; } // Can we still settle in this asset? if( mia.current_feed.settlement_price.is_null() ) { ilog("Canceling a force settlement in ${asset} because settlement price is null", ("asset", mia_object.symbol)); cancel_order(order); continue; } if( max_settlement_volume.asset_id != current_asset ) max_settlement_volume = mia_object.amount(mia.max_force_settlement_volume(mia_object.dynamic_data(*this).current_supply)); if( mia.force_settled_volume >= max_settlement_volume.amount ) { /* ilog("Skipping force settlement in ${asset}; settled ${settled_volume} / ${max_volume}", ("asset", mia_object.symbol)("settlement_price_null",mia.current_feed.settlement_price.is_null()) ("settled_volume", mia.force_settled_volume)("max_volume", max_settlement_volume)); */ if( next_asset() ) continue; break; } auto& pays = order.balance; auto receives = (order.balance * mia.current_feed.settlement_price); receives.amount = (fc::uint128_t(receives.amount.value) * (GRAPHENE_100_PERCENT - mia.options.force_settlement_offset_percent) / GRAPHENE_100_PERCENT).to_uint64(); assert(receives <= order.balance * mia.current_feed.settlement_price); price settlement_price = pays / receives; auto& call_index = get_index_type<call_order_index>().indices().get<by_collateral>(); asset settled = mia_object.amount(mia.force_settled_volume); // Match against the least collateralized short until the settlement is finished or we reach max settlements while( settled < max_settlement_volume && find_object(order_id) ) { auto itr = call_index.lower_bound(boost::make_tuple(price::min(mia_object.bitasset_data(*this).options.short_backing_asset, mia_object.get_id()))); // There should always be a call order, since asset exists! assert(itr != call_index.end() && itr->debt_type() == mia_object.get_id()); asset max_settlement = max_settlement_volume - settled; settled += match(*itr, order, settlement_price, max_settlement); } modify(mia, [settled](asset_bitasset_data_object& b) { b.force_settled_volume = settled.amount; }); } } }