Refactor: Move limit order execution to database
This logic was previously located in limit_order_create_evaluator, but other code may need it in the future, so it should be made available at the database level.
This commit is contained in:
parent
8b010b1f99
commit
dad1ca3bee
8 changed files with 118 additions and 125 deletions
|
|
@ -54,7 +54,11 @@ void_result asset_create_evaluator::do_evaluate( const asset_create_operation& o
|
|||
const asset_object& backing_backing = backing_bitasset_data.options.short_backing_asset(d);
|
||||
FC_ASSERT( !backing_backing.is_market_issued(),
|
||||
"May not create a bitasset backed by a bitasset backed by a bitasset." );
|
||||
}
|
||||
FC_ASSERT( op.issuer != GRAPHENE_COMMITTEE_ACCOUNT || backing_backing.get_id() == asset_id_type(),
|
||||
"May not create a blockchain-controlled market asset which is not backed by CORE.");
|
||||
} else
|
||||
FC_ASSERT( op.issuer != GRAPHENE_COMMITTEE_ACCOUNT || backing.get_id() == asset_id_type(),
|
||||
"May not create a blockchain-controlled market asset which is not backed by CORE.");
|
||||
FC_ASSERT( op.bitasset_options->feed_lifetime_sec > chain_parameters.block_interval &&
|
||||
op.bitasset_options->force_settlement_delay_sec > chain_parameters.block_interval );
|
||||
}
|
||||
|
|
@ -192,13 +196,28 @@ void_result asset_update_evaluator::do_evaluate(const asset_update_operation& o)
|
|||
{ try {
|
||||
database& d = db();
|
||||
|
||||
if( o.new_issuer ) FC_ASSERT(d.find_object(*o.new_issuer));
|
||||
|
||||
const asset_object& a = o.asset_to_update(d);
|
||||
auto a_copy = a;
|
||||
a_copy.options = o.new_options;
|
||||
a_copy.validate();
|
||||
|
||||
if( o.new_issuer )
|
||||
{
|
||||
FC_ASSERT(d.find_object(*o.new_issuer));
|
||||
if( a.is_market_issued() && *o.new_issuer == GRAPHENE_COMMITTEE_ACCOUNT )
|
||||
{
|
||||
const asset_object& backing = a.bitasset_data(d).options.short_backing_asset(d);
|
||||
if( backing.is_market_issued() )
|
||||
{
|
||||
const asset_object& backing_backing = backing.bitasset_data(d).options.short_backing_asset(d);
|
||||
FC_ASSERT( backing_backing.get_id() == asset_id_type(),
|
||||
"May not create a blockchain-controlled market asset which is not backed by CORE.");
|
||||
} else
|
||||
FC_ASSERT( backing.get_id() == asset_id_type(),
|
||||
"May not create a blockchain-controlled market asset which is not backed by CORE.");
|
||||
}
|
||||
}
|
||||
|
||||
//There must be no bits set in o.permissions which are unset in a.issuer_permissions.
|
||||
FC_ASSERT(!(o.new_options.issuer_permissions & ~a.options.issuer_permissions),
|
||||
"Cannot reinstate previously revoked issuer permissions on an asset.");
|
||||
|
|
@ -257,6 +276,19 @@ void_result asset_update_bitasset_evaluator::do_evaluate(const asset_update_bita
|
|||
{
|
||||
FC_ASSERT(a.dynamic_asset_data_id(d).current_supply == 0);
|
||||
FC_ASSERT(d.find_object(o.new_options.short_backing_asset));
|
||||
|
||||
if( a.issuer == GRAPHENE_COMMITTEE_ACCOUNT )
|
||||
{
|
||||
const asset_object& backing = a.bitasset_data(d).options.short_backing_asset(d);
|
||||
if( backing.is_market_issued() )
|
||||
{
|
||||
const asset_object& backing_backing = backing.bitasset_data(d).options.short_backing_asset(d);
|
||||
FC_ASSERT( backing_backing.get_id() == asset_id_type(),
|
||||
"May not create a blockchain-controlled market asset which is not backed by CORE.");
|
||||
} else
|
||||
FC_ASSERT( backing.get_id() == asset_id_type(),
|
||||
"May not create a blockchain-controlled market asset which is not backed by CORE.");
|
||||
}
|
||||
}
|
||||
|
||||
bitasset_to_update = &b;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/limit_order_object.hpp>
|
||||
|
||||
#include <fc/uint128.hpp>
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,49 @@ void database::cancel_order( const limit_order_object& order, bool create_virtua
|
|||
// TODO: create a virtual cancel operation
|
||||
}
|
||||
|
||||
remove( order );
|
||||
remove(order);
|
||||
}
|
||||
|
||||
bool database::apply_order(const limit_order_object& new_order_object, bool allow_black_swan)
|
||||
{
|
||||
auto order_id = new_order_object.id;
|
||||
const asset_object& sell_asset = get(new_order_object.amount_for_sale().asset_id);
|
||||
const asset_object& receive_asset = get(new_order_object.amount_to_receive().asset_id);
|
||||
|
||||
// Possible optimization: We only need to check calls if both are true:
|
||||
// - The new order is at the front of the book
|
||||
// - The new order is below the call limit price
|
||||
bool called_some = check_call_orders(sell_asset, allow_black_swan);
|
||||
called_some |= check_call_orders(receive_asset, allow_black_swan);
|
||||
if( called_some && !find_object(order_id) ) // then we were filled by call order
|
||||
return true;
|
||||
|
||||
const auto& limit_price_idx = get_index_type<limit_order_index>().indices().get<by_price>();
|
||||
|
||||
// TODO: it should be possible to simply check the NEXT/PREV iterator after new_order_object to
|
||||
// determine whether or not this order has "changed the book" in a way that requires us to
|
||||
// check orders. For now I just lookup the lower bound and check for equality... this is log(n) vs
|
||||
// constant time check. Potential optimization.
|
||||
|
||||
auto max_price = ~new_order_object.sell_price;
|
||||
auto limit_itr = limit_price_idx.lower_bound(max_price.max());
|
||||
auto limit_end = limit_price_idx.upper_bound(max_price);
|
||||
|
||||
bool finished = false;
|
||||
while( !finished && limit_itr != limit_end )
|
||||
{
|
||||
auto old_limit_itr = limit_itr;
|
||||
++limit_itr;
|
||||
// match returns 2 when only the old order was fully filled. In this case, we keep matching; otherwise, we stop.
|
||||
finished = (match(new_order_object, *old_limit_itr, old_limit_itr->sell_price) != 2);
|
||||
}
|
||||
|
||||
//Possible optimization: only check calls if the new order completely filled some old order
|
||||
//Do I need to check both assets?
|
||||
check_call_orders(sell_asset, allow_black_swan);
|
||||
check_call_orders(receive_asset, allow_black_swan);
|
||||
|
||||
return find_object(order_id) == nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -306,7 +348,7 @@ bool database::fill_order(const force_settlement_object& settle, const asset& pa
|
|||
|
||||
/**
|
||||
* Starting with the least collateralized orders, fill them if their
|
||||
* call price is above the max(lowest bid,call_limit).
|
||||
* call price is above the max(lowest bid,call_limit).
|
||||
*
|
||||
* This method will return true if it filled a short or limit
|
||||
*
|
||||
|
|
@ -316,7 +358,7 @@ bool database::fill_order(const force_settlement_object& settle, const asset& pa
|
|||
*
|
||||
* @return true if a margin call was executed.
|
||||
*/
|
||||
bool database::check_call_orders( const asset_object& mia, bool enable_black_swan )
|
||||
bool database::check_call_orders(const asset_object& mia, bool enable_black_swan)
|
||||
{ try {
|
||||
if( !mia.is_market_issued() ) return false;
|
||||
const asset_bitasset_data_object& bitasset = mia.bitasset_data(*this);
|
||||
|
|
@ -333,42 +375,13 @@ bool database::check_call_orders( const asset_object& mia, bool enable_black_swa
|
|||
auto max_price = price::max( mia.id, bitasset.options.short_backing_asset );
|
||||
// stop when limit orders are selling too little USD for too much CORE
|
||||
auto min_price = bitasset.current_feed.max_short_squeeze_price();
|
||||
/*
|
||||
// edump((bitasset.current_feed));
|
||||
edump((min_price.to_real())(min_price));
|
||||
edump((max_price.to_real())(max_price));
|
||||
//auto min_price = price::min( mia.id, bitasset.options.short_backing_asset );
|
||||
idump((bitasset.current_feed.settlement_price)(bitasset.current_feed.settlement_price.to_real()));
|
||||
{
|
||||
for( const auto& order : limit_price_index )
|
||||
wdump((order)(order.sell_price.to_real()));
|
||||
|
||||
for( const auto& call : call_price_index )
|
||||
idump((call)(call.call_price.to_real()));
|
||||
|
||||
// limit pirce index is sorted from highest price to lowest price.
|
||||
//auto limit_itr = limit_price_index.lower_bound( price::max( mia.id, bitasset.options.short_backing_asset ) );
|
||||
wdump((max_price)(max_price.to_real()));
|
||||
wdump((min_price)(min_price.to_real()));
|
||||
}
|
||||
*/
|
||||
|
||||
assert( max_price.base.asset_id == min_price.base.asset_id );
|
||||
// wlog( "from ${a} Debt/Col to ${b} Debt/Col ", ("a", max_price.to_real())("b",min_price.to_real()) );
|
||||
// NOTE limit_price_index is sorted from greatest to least
|
||||
auto limit_itr = limit_price_index.lower_bound( max_price );
|
||||
auto limit_end = limit_price_index.upper_bound( min_price );
|
||||
auto limit_end = limit_price_index.upper_bound( min_price );
|
||||
|
||||
/*
|
||||
if( limit_itr != limit_price_index.end() )
|
||||
wdump((*limit_itr)(limit_itr->sell_price.to_real()));
|
||||
if( limit_end != limit_price_index.end() )
|
||||
wdump((*limit_end)(limit_end->sell_price.to_real()));
|
||||
*/
|
||||
|
||||
if( limit_itr == limit_end )
|
||||
{
|
||||
// wlog( "no orders available to fill margin calls" );
|
||||
if( limit_itr == limit_end ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -389,32 +402,26 @@ bool database::check_call_orders( const asset_object& mia, bool enable_black_swa
|
|||
usd_for_sale = limit_itr->amount_for_sale();
|
||||
}
|
||||
else return filled_limit;
|
||||
// wdump((match_price));
|
||||
// edump((usd_for_sale));
|
||||
|
||||
match_price.validate();
|
||||
|
||||
// wdump((match_price)(~call_itr->call_price) );
|
||||
if( match_price > ~call_itr->call_price )
|
||||
{
|
||||
return filled_limit;
|
||||
}
|
||||
|
||||
auto usd_to_buy = call_itr->get_debt();
|
||||
// edump((usd_to_buy));
|
||||
|
||||
if( usd_to_buy * match_price > call_itr->get_collateral() )
|
||||
{
|
||||
FC_ASSERT( enable_black_swan );
|
||||
//elog( "black swan, we do not have enough collateral to cover at this price" );
|
||||
globally_settle_asset( mia, call_itr->get_debt() / call_itr->get_collateral() );
|
||||
globally_settle_asset(mia, call_itr->get_debt() / call_itr->get_collateral());
|
||||
return true;
|
||||
}
|
||||
|
||||
asset call_pays, call_receives, order_pays, order_receives;
|
||||
if( usd_to_buy >= usd_for_sale )
|
||||
{ // fill order
|
||||
//ilog( "filling all of limit order" );
|
||||
call_receives = usd_for_sale;
|
||||
order_receives = usd_for_sale * match_price;
|
||||
call_pays = order_receives;
|
||||
|
|
@ -422,9 +429,7 @@ bool database::check_call_orders( const asset_object& mia, bool enable_black_swa
|
|||
|
||||
filled_limit = true;
|
||||
filled_call = (usd_to_buy == usd_for_sale);
|
||||
}
|
||||
else // fill call
|
||||
{
|
||||
} else { // fill call
|
||||
call_receives = usd_to_buy;
|
||||
order_receives = usd_to_buy * match_price;
|
||||
call_pays = order_receives;
|
||||
|
|
@ -435,10 +440,10 @@ bool database::check_call_orders( const asset_object& mia, bool enable_black_swa
|
|||
|
||||
auto old_call_itr = call_itr;
|
||||
if( filled_call ) ++call_itr;
|
||||
fill_order( *old_call_itr, call_pays, call_receives );
|
||||
fill_order(*old_call_itr, call_pays, call_receives);
|
||||
|
||||
auto old_limit_itr = filled_limit ? limit_itr++ : limit_itr;
|
||||
fill_order( *old_limit_itr, order_pays, order_receives );
|
||||
fill_order(*old_limit_itr, order_pays, order_receives);
|
||||
} // whlie call_itr != call_end
|
||||
|
||||
return filled_limit;
|
||||
|
|
@ -454,16 +459,6 @@ void database::pay_order( const account_object& receiver, const asset& receives,
|
|||
adjust_balance(receiver.get_id(), receives);
|
||||
}
|
||||
|
||||
/**
|
||||
* For Market Issued assets Managed by Delegates, any fees collected in the MIA need
|
||||
* to be sold and converted into CORE by accepting the best offer on the table.
|
||||
*/
|
||||
bool database::convert_fees( const asset_object& mia )
|
||||
{
|
||||
if( mia.issuer != account_id_type() ) return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
asset database::calculate_market_fee( const asset_object& trade_asset, const asset& trade_amount )
|
||||
{
|
||||
assert( trade_asset.id == trade_amount.asset_id );
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
namespace graphene { namespace chain {
|
||||
class account_object;
|
||||
class database;
|
||||
using namespace graphene::db;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@
|
|||
|
||||
/**
|
||||
* These ratios are fixed point numbers with a denominator of GRAPHENE_COLLATERAL_RATIO_DENOM, the
|
||||
* minimum maitenance collateral is therefore 1.001x and the default
|
||||
* maintenance ratio is 1.75x
|
||||
* minimum maitenance collateral is therefore 1.001x and the default
|
||||
* maintenance ratio is 1.75x
|
||||
*/
|
||||
///@{
|
||||
#define GRAPHENE_COLLATERAL_RATIO_DENOM 1000
|
||||
|
|
@ -92,6 +92,7 @@
|
|||
#define GRAPHENE_DEFAULT_BURN_PERCENT_OF_FEE (20*GRAPHENE_1_PERCENT)
|
||||
#define GRAPHENE_WITNESS_PAY_PERCENT_PRECISION (1000000000)
|
||||
#define GRAPHENE_DEFAULT_MAX_ASSERT_OPCODE 1
|
||||
#define GRAPHENE_DEFAULT_FEE_LIQUIDATION_THRESHOLD GRAPHENE_BLOCKCHAIN_PRECISION * 100;
|
||||
#define GRAPHENE_GENESIS_TIMESTAMP (1431700000) /// Should be divisible by GRAPHENE_DEFAULT_BLOCK_INTERVAL
|
||||
|
||||
#define GRAPHENE_MAX_WORKER_NAME_LENGTH 63
|
||||
|
|
|
|||
|
|
@ -348,6 +348,16 @@ namespace graphene { namespace chain {
|
|||
void cancel_order(const force_settlement_object& order, bool create_virtual_op = true);
|
||||
void cancel_order(const limit_order_object& order, bool create_virtual_op = true);
|
||||
|
||||
/**
|
||||
* @brief Process a new limit order through the markets
|
||||
* @param order The new order to process
|
||||
* @return true if order was completely filled; false otherwise
|
||||
*
|
||||
* This function takes a new limit order, and runs the markets attempting to match it with existing orders
|
||||
* already on the books.
|
||||
*/
|
||||
bool apply_order(const limit_order_object& new_order_object, bool allow_black_swan = true);
|
||||
|
||||
/**
|
||||
* Matches the two orders,
|
||||
*
|
||||
|
|
@ -381,7 +391,6 @@ namespace graphene { namespace chain {
|
|||
// helpers to fill_order
|
||||
void pay_order( const account_object& receiver, const asset& receives, const asset& pays );
|
||||
|
||||
bool convert_fees( const asset_object& mia );
|
||||
asset calculate_market_fee(const asset_object& recv_asset, const asset& trade_amount);
|
||||
asset pay_market_fees( const asset_object& recv_asset, const asset& receives );
|
||||
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ namespace graphene { namespace chain {
|
|||
uint64_t account_len5_fee = 5*UINT64_C(1000000000); ///< about $100
|
||||
uint64_t account_len4_fee = 5*UINT64_C(2000000000); ///< about $200
|
||||
uint64_t account_len3_fee = 5*3000000000; ///< about $300
|
||||
uint64_t account_len2_fee = 5*4000000000; ///< about $400
|
||||
uint64_t account_len2_fee = 5*4000000000; ///< about $400
|
||||
uint32_t asset_create_fee = 5ll*500000000; ///< about $35 for LTM, the cost to register the cheapest asset
|
||||
uint32_t asset_update_fee = 150000; ///< the cost to modify a registered asset
|
||||
uint32_t asset_issue_fee = 700000; ///< the cost to print a UIA and send it to an account
|
||||
|
|
@ -456,6 +456,7 @@ namespace graphene { namespace chain {
|
|||
share_type witness_pay_per_block = GRAPHENE_DEFAULT_WITNESS_PAY_PER_BLOCK; ///< CORE to be allocated to witnesses (per block)
|
||||
share_type worker_budget_per_day = GRAPHENE_DEFAULT_WORKER_BUDGET_PER_DAY; ///< CORE to be allocated to workers (per day)
|
||||
uint16_t max_predicate_opcode = GRAPHENE_DEFAULT_MAX_ASSERT_OPCODE; ///< predicate_opcode must be less than this number
|
||||
share_type fee_liquidation_threshold = GRAPHENE_DEFAULT_FEE_LIQUIDATION_THRESHOLD; ///< value in CORE at which accumulated fees in blockchain-issued market assets should be liquidated
|
||||
|
||||
void validate()const
|
||||
{
|
||||
|
|
@ -614,6 +615,7 @@ FC_REFLECT( graphene::chain::chain_parameters,
|
|||
(witness_pay_per_block)
|
||||
(worker_budget_per_day)
|
||||
(max_predicate_opcode)
|
||||
(fee_liquidation_threshold)
|
||||
)
|
||||
|
||||
FC_REFLECT_TYPENAME( graphene::chain::share_type )
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
#include <fc/uint128.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
void_result limit_order_create_evaluator::do_evaluate( const limit_order_create_operation& op )
|
||||
void_result limit_order_create_evaluator::do_evaluate(const limit_order_create_operation& op)
|
||||
{ try {
|
||||
database& d = db();
|
||||
|
||||
|
|
@ -32,9 +32,9 @@ void_result limit_order_create_evaluator::do_evaluate( const limit_order_create_
|
|||
_receive_asset = &op.min_to_receive.asset_id(d);
|
||||
|
||||
if( _sell_asset->options.whitelist_markets.size() )
|
||||
FC_ASSERT( _sell_asset->options.whitelist_markets.find( _receive_asset->id ) != _sell_asset->options.whitelist_markets.end() );
|
||||
FC_ASSERT( _sell_asset->options.whitelist_markets.find(_receive_asset->id) != _sell_asset->options.whitelist_markets.end() );
|
||||
if( _sell_asset->options.blacklist_markets.size() )
|
||||
FC_ASSERT( _sell_asset->options.blacklist_markets.find( _receive_asset->id ) == _sell_asset->options.blacklist_markets.end() );
|
||||
FC_ASSERT( _sell_asset->options.blacklist_markets.find(_receive_asset->id) == _sell_asset->options.blacklist_markets.end() );
|
||||
|
||||
if( _sell_asset->enforce_white_list() ) FC_ASSERT( _seller->is_authorized_asset( *_sell_asset ) );
|
||||
if( _receive_asset->enforce_white_list() ) FC_ASSERT( _seller->is_authorized_asset( *_receive_asset ) );
|
||||
|
|
@ -45,10 +45,10 @@ void_result limit_order_create_evaluator::do_evaluate( const limit_order_create_
|
|||
return void_result();
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
||||
object_id_type limit_order_create_evaluator::do_apply( const limit_order_create_operation& op )
|
||||
object_id_type limit_order_create_evaluator::do_apply(const limit_order_create_operation& op)
|
||||
{ try {
|
||||
const auto& seller_stats = _seller->statistics(db());
|
||||
db().modify( seller_stats, [&]( account_statistics_object& bal ){
|
||||
db().modify(seller_stats, [&](account_statistics_object& bal) {
|
||||
if( op.amount_to_sell.asset_id == asset_id_type() )
|
||||
{
|
||||
bal.total_core_in_orders += op.amount_to_sell.amount;
|
||||
|
|
@ -57,70 +57,21 @@ object_id_type limit_order_create_evaluator::do_apply( const limit_order_create_
|
|||
|
||||
db().adjust_balance(op.seller, -op.amount_to_sell);
|
||||
|
||||
const auto& new_order_object = db().create<limit_order_object>( [&]( limit_order_object& obj ){
|
||||
const auto& new_order_object = db().create<limit_order_object>([&](limit_order_object& obj){
|
||||
obj.seller = _seller->id;
|
||||
obj.for_sale = op.amount_to_sell.amount;
|
||||
obj.sell_price = op.get_price();
|
||||
obj.expiration = op.expiration;
|
||||
});
|
||||
limit_order_id_type result = new_order_object.id; // save this because we may remove the object by filling it
|
||||
limit_order_id_type order_id = new_order_object.id; // save this because we may remove the object by filling it
|
||||
bool filled = db().apply_order(new_order_object);
|
||||
|
||||
// Possible optimization: We only need to check calls if both are true:
|
||||
// - The new order is at the front of the book
|
||||
// - The new order is below the call limit price
|
||||
bool called_some = db().check_call_orders(*_sell_asset);
|
||||
called_some |= db().check_call_orders(*_receive_asset);
|
||||
if( called_some && !db().find(result) ) // then we were filled by call order
|
||||
return result;
|
||||
FC_ASSERT( !op.fill_or_kill || filled );
|
||||
|
||||
const auto& limit_order_idx = db().get_index_type<limit_order_index>();
|
||||
const auto& limit_price_idx = limit_order_idx.indices().get<by_price>();
|
||||
|
||||
// TODO: it should be possible to simply check the NEXT/PREV iterator after new_order_object to
|
||||
// determine whether or not this order has "changed the book" in a way that requires us to
|
||||
// check orders. For now I just lookup the lower bound and check for equality... this is log(n) vs
|
||||
// constant time check. Potential optimization.
|
||||
|
||||
auto max_price = ~op.get_price(); //op.min_to_receive / op.amount_to_sell;
|
||||
auto limit_itr = limit_price_idx.lower_bound( max_price.max() );
|
||||
auto limit_end = limit_price_idx.upper_bound( max_price );
|
||||
|
||||
for( auto tmp = limit_itr; tmp != limit_end; ++tmp )
|
||||
{
|
||||
assert( tmp != limit_price_idx.end() );
|
||||
}
|
||||
|
||||
bool filled = false;
|
||||
//if( new_order_object.amount_to_receive().asset_id(db()).is_market_issued() )
|
||||
if( _receive_asset->is_market_issued() )
|
||||
{ // then we may also match against shorts
|
||||
if( _receive_asset->bitasset_data(db()).options.short_backing_asset == asset_id_type() )
|
||||
{
|
||||
bool converted_some = db().convert_fees( *_receive_asset );
|
||||
// just incase the new order was completely filled from fees
|
||||
if( converted_some && !db().find(result) ) // then we were filled by call order
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
while( !filled && limit_itr != limit_end )
|
||||
{
|
||||
auto old_limit_itr = limit_itr;
|
||||
++limit_itr;
|
||||
filled = (db().match( new_order_object, *old_limit_itr, old_limit_itr->sell_price ) != 2 );
|
||||
}
|
||||
|
||||
//Possible optimization: only check calls if the new order completely filled some old order
|
||||
//Do I need to check both assets?
|
||||
db().check_call_orders(*_sell_asset);
|
||||
db().check_call_orders(*_receive_asset);
|
||||
|
||||
FC_ASSERT( !op.fill_or_kill || db().find_object(result) == nullptr );
|
||||
|
||||
return result;
|
||||
return order_id;
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
||||
void_result limit_order_cancel_evaluator::do_evaluate( const limit_order_cancel_operation& o )
|
||||
void_result limit_order_cancel_evaluator::do_evaluate(const limit_order_cancel_operation& o)
|
||||
{ try {
|
||||
database& d = db();
|
||||
|
||||
|
|
@ -130,7 +81,7 @@ void_result limit_order_cancel_evaluator::do_evaluate( const limit_order_cancel_
|
|||
return void_result();
|
||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||
|
||||
asset limit_order_cancel_evaluator::do_apply( const limit_order_cancel_operation& o )
|
||||
asset limit_order_cancel_evaluator::do_apply(const limit_order_cancel_operation& o)
|
||||
{ try {
|
||||
database& d = db();
|
||||
|
||||
|
|
@ -138,7 +89,7 @@ asset limit_order_cancel_evaluator::do_apply( const limit_order_cancel_operation
|
|||
auto quote_asset = _order->sell_price.quote.asset_id;
|
||||
auto refunded = _order->amount_for_sale();
|
||||
|
||||
db().cancel_order( *_order, false /* don't create a virtual op*/ );
|
||||
db().cancel_order(*_order, false /* don't create a virtual op*/);
|
||||
|
||||
// Possible optimization: order can be called by canceling a limit order iff the canceled order was at the top of the book.
|
||||
// Do I need to check calls in both assets?
|
||||
|
|
|
|||
Loading…
Reference in a new issue