BitShares-Core  7.0.2
BitShares blockchain node software and command-line wallet software
market_evaluator.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
3  *
4  * The MIT License
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
27 
29 
32 #include <graphene/chain/hardfork.hpp>
34 
37 
38 namespace graphene { namespace chain {
40 { try {
41  const database& d = db();
42 
43  if( op.extensions.value.on_fill.valid() )
44  {
45  FC_ASSERT( HARDFORK_CORE_2535_PASSED( d.head_block_time() ) ,
46  "The on_fill extension is not allowed until the core-2535 hardfork");
47  FC_ASSERT( 1 == op.extensions.value.on_fill->size(),
48  "The on_fill action list must contain only one action until expanded in a future hardfork" );
49  const auto& take_profit_action = op.extensions.value.on_fill->front().get<create_take_profit_order_action>();
50  FC_ASSERT( d.find( take_profit_action.fee_asset_id ), "Fee asset does not exist" );
51  }
52 
54 
55  _seller = this->fee_paying_account;
56  _sell_asset = &op.amount_to_sell.asset_id(d);
57  _receive_asset = &op.min_to_receive.asset_id(d);
58 
59  if( _sell_asset->options.whitelist_markets.size() )
60  {
61  GRAPHENE_ASSERT( _sell_asset->options.whitelist_markets.find(_receive_asset->get_id())
62  != _sell_asset->options.whitelist_markets.end(),
63  limit_order_create_market_not_whitelisted,
64  "This market has not been whitelisted by the selling asset", );
65  }
66  if( _sell_asset->options.blacklist_markets.size() )
67  {
68  GRAPHENE_ASSERT( _sell_asset->options.blacklist_markets.find(_receive_asset->get_id())
69  == _sell_asset->options.blacklist_markets.end(),
70  limit_order_create_market_blacklisted,
71  "This market has been blacklisted by the selling asset", );
72  }
73 
74  GRAPHENE_ASSERT( is_authorized_asset( d, *_seller, *_sell_asset ),
75  limit_order_create_selling_asset_unauthorized,
76  "The account is not allowed to transact the selling asset", );
77 
78  GRAPHENE_ASSERT( is_authorized_asset( d, *_seller, *_receive_asset ),
79  limit_order_create_receiving_asset_unauthorized,
80  "The account is not allowed to transact the receiving asset", );
81 
82  GRAPHENE_ASSERT( d.get_balance( *_seller, *_sell_asset ) >= op.amount_to_sell,
83  limit_order_create_insufficient_balance,
84  "insufficient balance",
85  ("balance",d.get_balance(*_seller,*_sell_asset))("amount_to_sell",op.amount_to_sell) );
86 
87  return void_result();
88 } FC_CAPTURE_AND_RETHROW( (op) ) } // GCOVR_EXCL_LINE
89 
91 {
92  if( db().head_block_time() <= HARDFORK_CORE_604_TIME )
94  else if( fee_asset->get_id() != asset_id_type() )
95  {
98  });
99  }
100 }
101 
103 {
104  if( db().head_block_time() <= HARDFORK_445_TIME )
106  else
107  {
108  _deferred_fee = core_fee_paid;
109  if( db().head_block_time() > HARDFORK_CORE_604_TIME && fee_asset->get_id() != asset_id_type() )
110  _deferred_paid_fee = fee_from_account;
111  }
112 }
113 
115 { try {
116  if( op.amount_to_sell.asset_id == asset_id_type() )
117  {
118  db().modify( _seller->statistics(db()), [&op](account_statistics_object& bal) {
120  });
121  }
122 
124 
125  const auto& new_order_object = db().create<limit_order_object>([this,&op](limit_order_object& obj){
126  obj.seller = _seller->id;
127  obj.for_sale = op.amount_to_sell.amount;
128  obj.sell_price = op.get_price();
129  obj.expiration = op.expiration;
130  obj.deferred_fee = _deferred_fee;
131  obj.deferred_paid_fee = _deferred_paid_fee;
132  if( op.extensions.value.on_fill.valid() )
133  obj.on_fill = *op.extensions.value.on_fill;
134  });
135  object_id_type order_id = new_order_object.id; // save this because we may remove the object by filling it
136  bool filled;
137  if( db().get_dynamic_global_properties().next_maintenance_time <= HARDFORK_CORE_625_TIME )
138  filled = db().apply_order_before_hardfork_625( new_order_object );
139  else
140  filled = db().apply_order( new_order_object );
141 
142  GRAPHENE_ASSERT( !op.fill_or_kill || filled,
143  limit_order_create_kill_unfilled,
144  "Killing limit order ${op} due to unable to fill",
145  ("op",op) );
146 
147  return order_id;
148 } FC_CAPTURE_AND_RETHROW( (op) ) } // GCOVR_EXCL_LINE
149 
151 {
152  if( fee_asset->get_id() != asset_id_type() )
153  {
155  addo.fee_pool -= core_fee_paid;
156  });
157  }
158 }
159 
161 {
162  _deferred_fee = core_fee_paid;
163  if( fee_asset->get_id() != asset_id_type() )
164  _deferred_paid_fee = fee_from_account;
165 }
166 
168 { try {
169  const database& d = db();
170  FC_ASSERT( HARDFORK_CORE_1604_PASSED( d.head_block_time() ) , "Operation has not activated yet");
171 
172  if( o.on_fill.valid() )
173  {
174  // Note: Assuming that HF core-1604 and HF core-2535 will take place at the same time,
175  // no check for HF core-2535 here.
176  FC_ASSERT( o.on_fill->size() <= 1,
177  "The on_fill action list must contain zero or one action until expanded in a future hardfork" );
178  if( !o.on_fill->empty() )
179  {
180  const auto& take_profit_action = o.on_fill->front().get<create_take_profit_order_action>();
181  FC_ASSERT( d.find( take_profit_action.fee_asset_id ), "Fee asset does not exist" );
182  }
183  }
184 
185  _order = d.find( o.order );
186 
187  GRAPHENE_ASSERT( _order != nullptr,
188  limit_order_update_nonexist_order,
189  "Limit order ${oid} does not exist, cannot update",
190  ("oid", o.order) );
191 
192  // Check this is my order
193  GRAPHENE_ASSERT( o.seller == _order->seller,
194  limit_order_update_owner_mismatch,
195  "Limit order ${oid} is owned by someone else, cannot update",
196  ("oid", o.order) );
197 
198  // Check new price is compatible and appropriate
199  if (o.new_price) {
200  auto base_id = o.new_price->base.asset_id;
201  auto quote_id = o.new_price->quote.asset_id;
202  FC_ASSERT(base_id == _order->sell_price.base.asset_id && quote_id == _order->sell_price.quote.asset_id,
203  "Cannot update limit order with incompatible price");
204 
205  // Do not allow inappropriate price manipulation
206  auto max_amount_for_sale = std::max( _order->for_sale, _order->sell_price.base.amount );
207  if( o.delta_amount_to_sell )
208  max_amount_for_sale += o.delta_amount_to_sell->amount;
209  FC_ASSERT( o.new_price->base.amount <= max_amount_for_sale,
210  "The base amount in the new price cannot be greater than the estimated maximum amount for sale" );
211 
212  }
213 
214  // Check delta asset is compatible
215  if (o.delta_amount_to_sell) {
216  const auto& delta = *o.delta_amount_to_sell;
217  FC_ASSERT(delta.asset_id == _order->sell_price.base.asset_id,
218  "Cannot update limit order with incompatible asset");
219  if (delta.amount < 0)
220  FC_ASSERT(_order->for_sale > -delta.amount,
221  "Cannot deduct all or more from order than order contains");
222  // Note: if the delta amount is positive, account balance will be checked when calling adjust_balance()
223  }
224 
225  // Check dust
226  if (o.new_price || (o.delta_amount_to_sell && o.delta_amount_to_sell->amount < 0)) {
227  auto new_price = o.new_price? *o.new_price : _order->sell_price;
228  auto new_amount = _order->amount_for_sale();
229  if (o.delta_amount_to_sell)
230  new_amount += *o.delta_amount_to_sell;
231  auto new_amount_to_receive = new_amount * new_price;
232 
233  FC_ASSERT( new_amount_to_receive.amount > 0,
234  "Cannot update limit order: order becomes too small; cancel order instead" );
235  }
236 
237  // Check expiration is in the future
238  if (o.new_expiration)
239  FC_ASSERT( *o.new_expiration >= d.head_block_time(), "Cannot update limit order to expire in the past" );
240 
241  // Check asset authorization
242  // TODO refactor to fix duplicate code (see limit_order_create)
243  const auto sell_asset_id = _order->sell_asset_id();
244  const auto receive_asset_id = _order->receive_asset_id();
245  const auto& sell_asset = sell_asset_id(d);
246  const auto& receive_asset = receive_asset_id(d);
247  const auto& seller = *this->fee_paying_account;
248 
249  if( !sell_asset.options.whitelist_markets.empty() )
250  {
251  FC_ASSERT( sell_asset.options.whitelist_markets.find( receive_asset_id )
252  != sell_asset.options.whitelist_markets.end(),
253  "This market has not been whitelisted by the selling asset" );
254  }
255  if( !sell_asset.options.blacklist_markets.empty() )
256  {
257  FC_ASSERT( sell_asset.options.blacklist_markets.find( receive_asset_id )
258  == sell_asset.options.blacklist_markets.end(),
259  "This market has been blacklisted by the selling asset" );
260  }
261 
262  FC_ASSERT( is_authorized_asset( d, seller, sell_asset ),
263  "The account is not allowed to transact the selling asset" );
264 
265  FC_ASSERT( is_authorized_asset( d, seller, receive_asset ),
266  "The account is not allowed to transact the receiving asset" );
267 
268  return {};
269 } FC_CAPTURE_AND_RETHROW( (o) ) } // GCOVR_EXCL_LINE
270 
271 void limit_order_update_evaluator::process_deferred_fee()
272 {
273  // Attempt to deduct a possibly discounted order cancellation fee, and refund the remainder.
274  // Only deduct fee if there is any fee deferred.
275  // TODO fix duplicate code (see database::cancel_limit_order())
276  if( _order->deferred_fee <= 0 )
277  return;
278 
279  database& d = db();
280 
281  share_type deferred_fee = _order->deferred_fee;
282  asset deferred_paid_fee = _order->deferred_paid_fee;
283  const asset_dynamic_data_object* deferred_fee_asset_dyn_data = nullptr;
284  const auto& current_fees = d.current_fee_schedule();
285  asset core_cancel_fee = current_fees.calculate_fee( limit_order_cancel_operation() );
286  if( core_cancel_fee.amount > 0 )
287  {
288  // maybe-discounted cancel_fee calculation:
289  // limit_order_cancel_fee * limit_order_update_fee / limit_order_create_fee
290  asset core_create_fee = current_fees.calculate_fee( limit_order_create_operation() );
291  fc::uint128_t fee128( core_cancel_fee.amount.value );
292  if( core_create_fee.amount > 0 )
293  {
294  asset core_update_fee = current_fees.calculate_fee( limit_order_update_operation() );
295  fee128 *= core_update_fee.amount.value;
296  fee128 /= core_create_fee.amount.value;
297  }
298  // cap the fee
299  if( fee128 > static_cast<uint64_t>( deferred_fee.value ) )
300  fee128 = deferred_fee.value;
301  core_cancel_fee.amount = static_cast<int64_t>( fee128 );
302  }
303 
304  // if there is any CORE fee to deduct, redirect it to referral program
305  if( core_cancel_fee.amount > 0 )
306  {
307  if( !_seller_acc_stats )
308  _seller_acc_stats = &d.get_account_stats_by_owner( _order->seller );
309  d.modify( *_seller_acc_stats, [&core_cancel_fee, &d]( account_statistics_object& obj ) {
310  obj.pay_fee( core_cancel_fee.amount, d.get_global_properties().parameters.cashback_vesting_threshold );
311  } );
312  deferred_fee -= core_cancel_fee.amount;
313  // handle originally paid fee if any:
314  // to_deduct = round_up( paid_fee * core_cancel_fee / deferred_core_fee_before_deduct )
315  if( deferred_paid_fee.amount > 0 )
316  {
317  fc::uint128_t fee128( deferred_paid_fee.amount.value );
318  fee128 *= core_cancel_fee.amount.value;
319  // to round up
320  fee128 += _order->deferred_fee.value;
321  fee128 -= 1;
322  fee128 /= _order->deferred_fee.value;
323  share_type cancel_fee_amount = static_cast<int64_t>(fee128);
324  // cancel_fee should be positive, pay it to asset's accumulated_fees
325  deferred_fee_asset_dyn_data = &deferred_paid_fee.asset_id(d).dynamic_asset_data_id(d);
326  d.modify( *deferred_fee_asset_dyn_data, [&cancel_fee_amount](asset_dynamic_data_object& addo) {
327  addo.accumulated_fees += cancel_fee_amount;
328  });
329  // cancel_fee should be no more than deferred_paid_fee
330  deferred_paid_fee.amount -= cancel_fee_amount;
331  }
332  }
333 
334  // refund fee
335  if( 0 == _order->deferred_paid_fee.amount )
336  {
337  // be here, order.create_time <= HARDFORK_CORE_604_TIME, or fee paid in CORE, or no fee to refund.
338  // if order was created before hard fork 604,
339  // see it as fee paid in CORE, deferred_fee should be refunded to order owner but not fee pool
340  d.adjust_balance( _order->seller, deferred_fee );
341  }
342  else // need to refund fee in originally paid asset
343  {
344  d.adjust_balance( _order->seller, deferred_paid_fee );
345  // be here, must have: fee_asset != CORE
346  if( !deferred_fee_asset_dyn_data )
347  deferred_fee_asset_dyn_data = &deferred_paid_fee.asset_id(d).dynamic_asset_data_id(d);
348  d.modify( *deferred_fee_asset_dyn_data, [&deferred_fee](asset_dynamic_data_object& addo) {
349  addo.fee_pool += deferred_fee;
350  });
351  }
352 
353 }
354 
355 bool limit_order_update_evaluator::is_linked_tp_order_compatible(const limit_order_update_operation& o) const
356 {
357  if( !o.on_fill ) // there is no change to on_fill, so do nothing
358  return true;
359  bool is_compatible = true;
360  if( o.on_fill->empty() )
361  {
362  if( !_order->on_fill.empty() ) // This order's on_fill is being removed
363  {
364  // Two scenarios:
365  // 1. The linked order is generated by this order, now this order's on_fill is being removed, so unlink
366  // 2. This order is generated by the linked order, and "repeat" was true, now this order's on_fill is
367  // being removed, so it becomes incompatible with the linked order, so unlink
368  is_compatible = false;
369  }
370  // else there is no change, nothing to do here
371  }
372  else // o.on_fill is not empty
373  {
374  if( _order->on_fill.empty() )
375  {
376  // It means this order was generated by the linked order, and the linked order's "repeat" is false.
377  // We are adding on_fill to this order, so it becomes incompatible with the linked order, so unlink.
378  is_compatible = false;
379  }
380  else // Not empty
381  {
382  // Two scenarios:
383  // 1. Both order's "repeat" are true
384  // 2. This order's "repeat" was false, and the linked order was generated by this order
385  //
386  // Either way, if "spread_percent" or "repeat" in on_fill changed, unlink the linked take profit order.
387  const auto& old_take_profit_action = _order->get_take_profit_action();
388  const auto& new_take_profit_action = o.on_fill->front().get<create_take_profit_order_action>();
389  if( old_take_profit_action.spread_percent != new_take_profit_action.spread_percent
390  || old_take_profit_action.repeat != new_take_profit_action.repeat )
391  {
392  is_compatible = false;
393  }
394  } // whether order's on_fill is empty (both handled)
395  } // whether o.on_fill is empty (both handled)
396  return is_compatible;
397 };
398 
400 { try {
401  database& d = db();
402 
403  // Adjust account balance
404  if( o.delta_amount_to_sell )
405  {
407  if( o.delta_amount_to_sell->asset_id == asset_id_type() )
408  {
409  _seller_acc_stats = &d.get_account_stats_by_owner( o.seller );
410  d.modify( *_seller_acc_stats, [&o]( account_statistics_object& bal ) {
412  });
413  }
414  }
415 
416  // Process deferred fee in the order.
417  process_deferred_fee();
418 
419  // Process linked take profit order
420  bool unlink = false;
421  if( _order->take_profit_order_id.valid() )
422  {
423  // If price changed, unless it is triggered by on_fill of the linked take profit order,
424  // unlink the linked take profit order.
426  && o.new_price.valid() && *o.new_price != _order->sell_price )
427  {
428  unlink = true;
429  }
430  // If on_fill changed and the order became incompatible with the linked order, unlink
431  else
432  unlink = !is_linked_tp_order_compatible( o );
433 
434  // Now update database
435  if( unlink )
436  {
437  const auto& take_profit_order = (*_order->take_profit_order_id)(d);
438  d.modify( take_profit_order, []( limit_order_object& loo ) {
440  });
441  }
442  }
443 
444  // Update order
445  d.modify(*_order, [&o,this,unlink](limit_order_object& loo) {
446  if (o.new_price)
447  loo.sell_price = *o.new_price;
448  if (o.delta_amount_to_sell)
449  loo.for_sale += o.delta_amount_to_sell->amount;
450  if (o.new_expiration)
451  loo.expiration = *o.new_expiration;
452  loo.deferred_fee = _deferred_fee;
453  loo.deferred_paid_fee = _deferred_paid_fee;
454  if( o.on_fill )
455  loo.on_fill= *o.on_fill;
456  if( unlink )
458  });
459 
460  // Perform order matching if necessary
461  d.apply_order(*_order);
462 
463  return {};
464 } FC_CAPTURE_AND_RETHROW( (o) ) } // GCOVR_EXCL_LINE
465 
467 { try {
468  const database& d = db();
469 
470  _order = d.find( o.order );
471 
472  GRAPHENE_ASSERT( _order != nullptr,
473  limit_order_cancel_nonexist_order,
474  "Limit order ${oid} does not exist",
475  ("oid", o.order) );
476 
478  limit_order_cancel_owner_mismatch,
479  "Limit order ${oid} is owned by someone else",
480  ("oid", o.order) );
481 
482  return void_result();
483 } FC_CAPTURE_AND_RETHROW( (o) ) } // GCOVR_EXCL_LINE
484 
486 { try {
487  database& d = db();
488 
489  auto base_asset = _order->sell_price.base.asset_id;
490  auto quote_asset = _order->sell_price.quote.asset_id;
491  auto refunded = _order->amount_for_sale();
492 
493  d.cancel_limit_order( *_order, false ); // don't create a virtual op
494 
495  if( d.get_dynamic_global_properties().next_maintenance_time <= HARDFORK_CORE_606_TIME )
496  {
497  // Possible optimization:
498  // order can be called by canceling a limit order if the canceled order was at the top of the book.
499  // Do I need to check calls in both assets?
500  d.check_call_orders(base_asset(d));
501  d.check_call_orders(quote_asset(d));
502  }
503 
504  return refunded;
505 } FC_CAPTURE_AND_RETHROW( (o) ) } // GCOVR_EXCL_LINE
506 
508 { try {
509  const database& d = db();
510 
511  auto next_maintenance_time = d.get_dynamic_global_properties().next_maintenance_time;
512 
513  // Note: funding_account is the fee payer thus exists in the database
514  _debt_asset = &o.delta_debt.asset_id(d);
515  FC_ASSERT( _debt_asset->is_market_issued(), "Unable to cover ${sym} as it is not a collateralized asset.",
516  ("sym", _debt_asset->symbol) );
517 
518  FC_ASSERT( o.delta_debt.amount <= 0 || _debt_asset->can_create_new_supply(), "Can not create new supply" );
519 
520  _dynamic_data_obj = &_debt_asset->dynamic_asset_data_id(d);
521 
522  /***
523  * There are instances of assets exceeding max_supply before hf 1465, therefore this code must remain.
524  */
525  if (next_maintenance_time > HARDFORK_CORE_1465_TIME)
526  {
527  FC_ASSERT( _dynamic_data_obj->current_supply + o.delta_debt.amount <= _debt_asset->options.max_supply,
528  "Borrowing this quantity would exceed MAX_SUPPLY" );
529  }
530 
531  FC_ASSERT( _dynamic_data_obj->current_supply + o.delta_debt.amount >= 0,
532  "This transaction would bring current supply below zero.");
533 
534  _bitasset_data = &_debt_asset->bitasset_data(d);
535 
538  FC_ASSERT( !_bitasset_data->is_globally_settled(),
539  "Cannot update debt position when the asset has been globally settled" );
540 
542  "Collateral asset type should be same as backing asset of debt asset" );
543 
544  auto& call_idx = d.get_index_type<call_order_index>().indices().get<by_account>();
545  auto itr = call_idx.find( boost::make_tuple(o.funding_account, o.delta_debt.asset_id) );
546  if( itr != call_idx.end() ) // updating or closing debt position
547  {
548  call_ptr = &(*itr);
549  new_collateral = call_ptr->collateral + o.delta_collateral.amount;
550  new_debt = call_ptr->debt + o.delta_debt.amount;
551  if( new_debt == 0 )
552  {
553  FC_ASSERT( new_collateral == 0, "Should claim all collateral when closing debt position" );
554  _closing_order = true;
555  }
556  else
557  {
558  FC_ASSERT( new_collateral > 0 && new_debt > 0,
559  "Both collateral and debt should be positive after updated a debt position if not to close it" );
560  }
561  }
562  else // creating new debt position
563  {
564  FC_ASSERT( o.delta_collateral.amount > 0, "Delta collateral amount of new debt position should be positive" );
565  FC_ASSERT( o.delta_debt.amount > 0, "Delta debt amount of new debt position should be positive" );
566  }
567 
568  if( _bitasset_data->is_prediction_market )
570  "Debt amount and collateral amount should be same when updating debt position in a prediction "
571  "market" );
572  else if( _bitasset_data->current_feed.settlement_price.is_null()
573  && !( HARDFORK_CORE_2467_PASSED( next_maintenance_time ) && _closing_order ) )
574  FC_THROW_EXCEPTION(insufficient_feeds, "Cannot borrow asset with no price feed.");
575 
576  // Since hard fork core-973, check asset authorization limitations
577  if( HARDFORK_CORE_973_PASSED(d.head_block_time()) )
578  {
579  FC_ASSERT( is_authorized_asset( d, *fee_paying_account, *_debt_asset ),
580  "The account is not allowed to transact the debt asset" );
582  "The account is not allowed to transact the collateral asset" );
583  }
584 
585  // Note: there was code here checking whether the account has enough balance to increase delta collateral,
586  // which is now removed since the check is implicitly done later by `adjust_balance()` in `do_apply()`.
587 
588  return void_result();
589 } FC_CAPTURE_AND_RETHROW( (o) ) } // GCOVR_EXCL_LINE
590 
591 
593 { try {
594  database& d = db();
595 
596  if( o.delta_debt.amount != 0 )
597  {
599 
600  // Deduct the debt paid from the total supply of the debt asset.
601  d.modify(*_dynamic_data_obj, [&o](asset_dynamic_data_object& dynamic_asset) {
602  dynamic_asset.current_supply += o.delta_debt.amount;
603  });
604  }
605 
606  if( o.delta_collateral.amount != 0 )
607  {
609 
610  // Adjust the total core in orders accodingly
611  if( o.delta_collateral.asset_id == asset_id_type() )
612  {
614  stats.total_core_in_orders += o.delta_collateral.amount;
615  });
616  }
617  }
618 
619  if( _closing_order ) // closing the debt position
620  {
621  auto call_order_id = call_ptr->id;
622 
623  d.remove( *call_ptr );
624 
625  // Update current_feed if needed
626  const auto bsrm = _bitasset_data->get_black_swan_response_method();
627  if( bitasset_options::black_swan_response_type::no_settlement == bsrm )
628  {
629  auto old_feed_price = _bitasset_data->current_feed.settlement_price;
630  d.update_bitasset_current_feed( *_bitasset_data, true );
631  if( !_bitasset_data->current_feed.settlement_price.is_null()
632  && _bitasset_data->current_feed.settlement_price != old_feed_price )
633  {
634  d.check_call_orders( *_debt_asset, true, false, _bitasset_data );
635  }
636  }
637 
638  return call_order_id;
639  }
640 
641  const auto next_maint_time = d.get_dynamic_global_properties().next_maintenance_time;
642  bool before_core_hardfork_1270 = ( next_maint_time <= HARDFORK_CORE_1270_TIME ); // call price caching issue
643 
644  optional<price> old_collateralization;
645  optional<share_type> old_debt;
646 
647  if( !call_ptr ) // creating new debt position
648  {
649  call_ptr = &d.create<call_order_object>( [&o,this,before_core_hardfork_1270]( call_order_object& call ){
650  call.borrower = o.funding_account;
651  call.collateral = o.delta_collateral.amount;
652  call.debt = o.delta_debt.amount;
653  if( before_core_hardfork_1270 ) // before core-1270 hard fork, calculate call_price here and cache it
654  call.call_price = price::call_price( o.delta_debt, o.delta_collateral,
655  _bitasset_data->current_feed.maintenance_collateral_ratio );
656  else // after core-1270 hard fork, set call_price to 1
657  call.call_price = price( asset( 1, o.delta_collateral.asset_id ), asset( 1, o.delta_debt.asset_id ) );
658  call.target_collateral_ratio = o.extensions.value.target_collateral_ratio;
659  });
660  }
661  else // updating existing debt position
662  {
663  old_collateralization = call_ptr->collateralization();
664  old_debt = call_ptr->debt;
665 
666  d.modify( *call_ptr, [&o,this,before_core_hardfork_1270]( call_order_object& call ){
667  call.collateral = new_collateral;
668  call.debt = new_debt;
669  if( before_core_hardfork_1270 ) // don't update call_price after core-1270 hard fork
670  {
671  call.call_price = price::call_price( call.get_debt(), call.get_collateral(),
672  _bitasset_data->current_feed.maintenance_collateral_ratio );
673  }
674  call.target_collateral_ratio = o.extensions.value.target_collateral_ratio;
675  });
676  }
677 
678  object_id_type call_order_id = call_ptr->id;
679 
680  if( _bitasset_data->is_prediction_market )
681  return call_order_id;
682 
683  // then we must check for margin calls and other issues
684 
685  // After hf core-2481, we do not allow new position's CR to be <= ~max_short_squeeze_price, because
686  // * if there is no force settlement order, it would trigger a blackswan event instantly,
687  // * if there is a force settlement order, they will match at the call order's CR, but it is not fair for the
688  // force settlement order.
689  auto call_collateralization = call_ptr->collateralization();
690  bool increasing_cr = ( old_collateralization.valid() && call_ptr->debt <= *old_debt
691  && call_collateralization > *old_collateralization );
692  if( HARDFORK_CORE_2481_PASSED( next_maint_time ) )
693  {
694  // Note: if it is to increase CR and is not increasing debt amount, it is allowed,
695  // because it implies BSRM == no_settlement
696  FC_ASSERT( increasing_cr
697  || call_collateralization >= ~( _bitasset_data->median_feed.max_short_squeeze_price() ),
698  "Could not create a debt position which would trigger a blackswan event instantly, "
699  "unless it is to increase collateral ratio of an existing debt position and "
700  "is not increasing its debt amount" );
701  }
702  // Update current_feed if needed
703  const auto bsrm = _bitasset_data->get_black_swan_response_method();
704  if( bitasset_options::black_swan_response_type::no_settlement == bsrm )
705  d.update_bitasset_current_feed( *_bitasset_data, true );
706 
707  // check to see if the order needs to be margin called now, but don't allow black swans and require there to be
708  // limit orders available that could be used to fill the order.
709  // Note: due to https://github.com/bitshares/bitshares-core/issues/649, before core-343 hard fork,
710  // the first call order may be unable to be updated if the second one is undercollateralized.
711  // Note: check call orders, don't allow black swan, not for new limit order
712  bool called_some = d.check_call_orders( *_debt_asset, false, false, _bitasset_data );
713  call_ptr = d.find<call_order_object>(call_order_id);
714  if( called_some )
715  {
716  // before hard fork core-583: if we filled at least one call order, we are OK if we totally filled.
717  // after hard fork core-583: we want to allow increasing collateral
718  // Note: increasing collateral won't get the call order itself matched (instantly margin called)
719  // if there is at least a call order get matched but didn't cause a black swan event,
720  // current order must have got matched. in this case, it's OK if it's totally filled.
721  // after hard fork core-2467: when BSRM is no_settlement, it is possible that other call orders are matched
722  // in check_call_orders, also possible that increasing CR will get the call order itself matched
723  if( !HARDFORK_CORE_2467_PASSED( next_maint_time ) ) // before core-2467 hf
724  {
725  GRAPHENE_ASSERT( !call_ptr, call_order_update_unfilled_margin_call,
726  "Updating call order would trigger a margin call that cannot be fully filled" );
727  }
728  // after core-2467 hf
729  else
730  {
731  // if the call order is totally filled, it is OK,
732  // if it is increasing CR, it is always ok, no matter if it or another another call order is called,
733  // otherwise, the remaining call order's CR need to be > ICR
734  // TODO: perhaps it makes sense to allow more cases, e.g.
735  // - when a position has ICR > CR > MCR, allow the owner to sell some collateral to increase CR
736  // - allow owners to sell collateral at price < MSSP (need to update code elsewhere)
737  FC_ASSERT( !call_ptr || increasing_cr
738  || call_ptr->collateralization() > _bitasset_data->current_initial_collateralization,
739  "Could not create a debt position which would trigger a margin call instantly, "
740  "unless the debt position is fully filled, or it is to increase collateral ratio of "
741  "an existing debt position and is not increasing its debt amount, "
742  "or the remaining debt position's collateral ratio is above required "
743  "initial collateral ratio (ICR)" );
744  }
745  }
746  else
747  {
748  // we know no black swan event has occurred
749  FC_ASSERT( call_ptr, "no margin call was executed and yet the call object was deleted" );
750  // this HF must remain as-is, as the assert inside the "if" was triggered during push_proposal()
751  if( d.head_block_time() <= HARDFORK_CORE_583_TIME )
752  {
753  // We didn't fill any call orders. This may be because we
754  // aren't in margin call territory, or it may be because there
755  // were no matching orders. In the latter case, we throw.
757  // we know core-583 hard fork is before core-1270 hard fork, it's ok to use call_price here
758  ~call_ptr->call_price < _bitasset_data->current_feed.settlement_price,
759  call_order_update_unfilled_margin_call,
760  "Updating call order would trigger a margin call that cannot be fully filled",
761  // we know core-583 hard fork is before core-1270 hard fork, it's ok to use call_price here
762  ("a", ~call_ptr->call_price )("b", _bitasset_data->current_feed.settlement_price)
763  );
764  }
765  else // after hard fork core-583, always allow call order to be updated if collateral ratio
766  // is increased and debt is not increased
767  {
768  // We didn't fill any call orders. This may be because we
769  // aren't in margin call territory, or it may be because there
770  // were no matching orders. In the latter case,
771  // if collateral ratio is not increased or debt is increased, we throw.
772  // be here, we know no margin call was executed,
773  // so call_obj's collateral ratio should be set only by op
774  // ------
775  // Before BSIP77, CR of the new/updated position is required to be above MCR.
776  // After BSIP77, CR of the new/updated position is required to be above max(ICR,MCR).
777  // The `current_initial_collateralization` variable has been initialized according to the logic,
778  // so we directly use it here.
779  bool ok = increasing_cr;
780  if( !ok )
781  ok = before_core_hardfork_1270 ?
782  ( ~call_ptr->call_price < _bitasset_data->current_feed.settlement_price )
783  : ( call_collateralization > _bitasset_data->current_initial_collateralization );
784  FC_ASSERT( ok,
785  "Can only increase collateral ratio without increasing debt when the debt position's "
786  "collateral ratio is lower than or equal to required initial collateral ratio (ICR), "
787  "if not to trigger a margin call immediately",
788  ("old_debt", old_debt)
789  ("new_debt", call_ptr->debt)
790  ("old_collateralization", old_collateralization)
791  ("new_collateralization", call_collateralization)
792  );
793  }
794  }
795 
796  return call_order_id;
797 } FC_CAPTURE_AND_RETHROW( (o) ) } // GCOVR_EXCL_LINE
798 
800 { try {
801  const database& d = db();
802 
803  // TODO cleanup: remove the assertion and related test cases after hardfork
804  FC_ASSERT( d.head_block_time() > HARDFORK_CORE_216_TIME, "Not yet!" );
805 
806  // Note: bidder is the fee payer thus exists in the database
807  _debt_asset = &o.debt_covered.asset_id(d);
808  FC_ASSERT( _debt_asset->is_market_issued(), "Unable to cover ${sym} as it is not a collateralized asset.",
809  ("sym", _debt_asset->symbol) );
810 
812  // Note: due to old bugs, an asset can have the flag set before the hardfork, so we need the hardfork check here
813  // TODO review after hardfork to see if we can remove the check
814  if( HARDFORK_CORE_2281_PASSED( next_maint_time ) )
815  FC_ASSERT( _debt_asset->can_bid_collateral(), "Collateral bidding is disabled for this asset" );
816 
817  _bitasset_data = &_debt_asset->bitasset_data(d);
818 
819  FC_ASSERT( _bitasset_data->is_globally_settled(), "Cannot bid since the asset is not globally settled" );
820 
822 
823  FC_ASSERT( !_bitasset_data->is_prediction_market, "Cannot bid on a prediction market!" );
824 
826  const auto& index = bids.indices().get<by_account>();
827  const auto& bid = index.find( boost::make_tuple( o.debt_covered.asset_id, o.bidder ) );
828  if( bid != index.end() )
829  _bid = &(*bid);
830  else
831  FC_ASSERT( o.debt_covered.amount > 0, "Can't find bid to cancel?!");
832 
833  if( o.additional_collateral.amount > 0 )
834  {
835  auto collateral_balance = d.get_balance( o.bidder, _bitasset_data->options.short_backing_asset );
836  if( _bid && d.head_block_time() >= HARDFORK_CORE_1692_TIME ) // TODO: see if HF check can be removed after HF
837  {
839  FC_ASSERT( collateral_balance >= delta,
840  "Cannot increase bid from ${oc} to ${nc} collateral when payer only has ${b}",
842  ("b", collateral_balance.amount) );
843  } else
844  FC_ASSERT( collateral_balance >= o.additional_collateral,
845  "Cannot bid ${c} collateral when payer only has ${b}", ("c", o.additional_collateral.amount)
846  ("b", collateral_balance.amount) );
847  }
848 
849  // Since hard fork core-973, check asset authorization limitations
850  if( HARDFORK_CORE_973_PASSED(d.head_block_time()) )
851  {
852  FC_ASSERT( is_authorized_asset( d, *fee_paying_account, *_debt_asset ),
853  "The account is not allowed to transact the debt asset" );
855  "The account is not allowed to transact the collateral asset" );
856  }
857 
858  return void_result();
859 } FC_CAPTURE_AND_RETHROW( (o) ) } // GCOVR_EXCL_LINE
860 
861 
863 { try {
864  database& d = db();
865 
866  if( _bid )
867  d.cancel_bid( *_bid, false );
868 
869  if( o.debt_covered.amount == 0 ) return void_result();
870 
872 
874  bid.bidder = o.bidder;
875  bid.inv_swan_price = o.additional_collateral / o.debt_covered;
876  });
877 
878  // Note: CORE asset in collateral_bid_object is not counted in account_stats.total_core_in_orders
879 
880  return void_result();
881 } FC_CAPTURE_AND_RETHROW( (o) ) } // GCOVR_EXCL_LINE
882 
883 } } // graphene::chain
fc::optional::reset
void reset()
Definition: optional.hpp:224
graphene::chain::asset_dynamic_data_object::fee_pool
share_type fee_pool
in core asset
Definition: asset_object.hpp:65
graphene::protocol::bid_collateral_operation::bidder
account_id_type bidder
pays fee and additional collateral
Definition: market.hpp:247
FC_CAPTURE_AND_RETHROW
#define FC_CAPTURE_AND_RETHROW(...)
Definition: exception.hpp:479
graphene::protocol::limit_order_update_operation::new_price
optional< price > new_price
Definition: market.hpp:126
graphene::db::object::id
object_id_type id
Definition: object.hpp:69
is_authorized_asset.hpp
graphene::chain::limit_order_object::sell_price
price sell_price
The seller's asking price.
Definition: market_object.hpp:51
graphene::chain::limit_order_create_evaluator::convert_fee
void convert_fee() override
Definition: market_evaluator.cpp:90
graphene::chain::collateral_bid_object::get_additional_collateral
asset get_additional_collateral() const
Definition: market_object.hpp:210
graphene::chain::database
tracks the blockchain state in an extensible manner
Definition: database.hpp:70
graphene::protocol::call_order_update_operation::delta_debt
asset delta_debt
the amount of the debt to be paid off, may be negative to issue new debt
Definition: market.hpp:190
graphene::protocol::limit_order_create_operation::amount_to_sell
asset amount_to_sell
Definition: market.hpp:89
graphene::protocol::limit_order_update_operation::seller
account_id_type seller
Definition: market.hpp:124
graphene::chain::call_order_object::debt
share_type debt
call_price.quote.asset_id, access via get_debt
Definition: market_object.hpp:152
graphene::chain::database::apply_order_before_hardfork_625
bool apply_order_before_hardfork_625(const limit_order_object &new_order_object)
Process a new limit order through the markets.
Definition: db_market.cpp:672
graphene::chain::call_order_update_evaluator::do_evaluate
void_result do_evaluate(const call_order_update_operation &o)
Definition: market_evaluator.cpp:507
graphene::chain::database::head_block_time
time_point_sec head_block_time() const
Definition: db_getter.cpp:67
graphene::protocol::bid_collateral_operation
Definition: market.hpp:241
asset_object.hpp
graphene::chain::database::get_balance
asset get_balance(account_id_type owner, asset_id_type asset_id) const
Retrieve a particular account's balance in a given asset.
Definition: db_balance.cpp:35
graphene::protocol::price
The price struct stores asset prices in the BitShares system.
Definition: asset.hpp:108
graphene::chain::asset_bitasset_data_object::is_prediction_market
bool is_prediction_market
True if this asset implements a Prediction Market.
Definition: asset_object.hpp:291
graphene::chain::limit_order_update_evaluator::do_apply
void_result do_apply(const limit_order_update_operation &o)
Definition: market_evaluator.cpp:399
database.hpp
graphene::chain::dynamic_global_property_object::next_maintenance_time
time_point_sec next_maintenance_time
Definition: global_property_object.hpp:70
graphene::chain::asset_object::bitasset_data
const asset_bitasset_data_object & bitasset_data(const DB &db) const
Definition: asset_object.hpp:166
graphene::protocol::create_take_profit_order_action
Definition: market.hpp:33
graphene::chain::generic_evaluator::fee_asset
const asset_object * fee_asset
Definition: evaluator.hpp:118
graphene::chain::call_order_object::get_collateral
asset get_collateral() const
Definition: market_object.hpp:143
graphene::chain::global_property_object::parameters
chain_parameters parameters
Definition: global_property_object.hpp:44
graphene::chain::limit_order_object::on_fill
vector< limit_order_auto_action > on_fill
Automatic actions when the limit order is filled or partially filled.
Definition: market_object.hpp:58
graphene::chain::asset_dynamic_data_object::current_supply
share_type current_supply
The number of shares currently in existence.
Definition: asset_object.hpp:61
graphene::chain::call_order_object::collateralization
price collateralization() const
Definition: market_object.hpp:148
fee_schedule.hpp
graphene::chain::limit_order_update_evaluator::pay_fee
void pay_fee() override
Definition: market_evaluator.cpp:160
graphene::protocol::asset_options::whitelist_markets
flat_set< asset_id_type > whitelist_markets
Definition: asset_ops.hpp:84
graphene::db::object_database::create
const T & create(F &&constructor)
Definition: object_database.hpp:63
graphene::chain::database::adjust_balance
void adjust_balance(account_id_type account, asset delta)
Adjust a particular account's balance in a given asset by a delta.
Definition: db_balance.cpp:54
graphene::protocol::price_feed::settlement_price
price settlement_price
Definition: asset.hpp:180
graphene::protocol::limit_order_update_operation::on_fill
optional< vector< limit_order_auto_action > > on_fill
Automatic actions when the limit order is filled or partially filled.
Definition: market.hpp:130
graphene::chain::limit_order_object::sell_asset_id
asset_id_type sell_asset_id() const
Definition: market_object.hpp:79
graphene::chain::database::check_call_orders
bool check_call_orders(const asset_object &mia, bool enable_black_swan=true, bool for_new_limit_order=false, const asset_bitasset_data_object *bitasset_ptr=nullptr, bool mute_exceptions=false, bool skip_matching_settle_orders=false)
Definition: db_market.cpp:2079
graphene::chain::asset_object::symbol
string symbol
Ticker symbol for this asset, i.e. "USD".
Definition: asset_object.hpp:131
graphene::protocol::bid_collateral_operation::debt_covered
asset debt_covered
the amount of debt to take over
Definition: market.hpp:249
graphene::chain::call_order_object::get_debt
asset get_debt() const
Definition: market_object.hpp:144
graphene::protocol::asset_options::blacklist_markets
flat_set< asset_id_type > blacklist_markets
Definition: asset_ops.hpp:86
graphene::chain::call_order_object::collateral
share_type collateral
call_price.base.asset_id, access via get_collateral
Definition: market_object.hpp:151
graphene::protocol::call_order_update_operation::delta_collateral
asset delta_collateral
the amount of collateral to add to the margin position
Definition: market.hpp:189
graphene::chain::limit_order_object::seller
account_id_type seller
Who is selling.
Definition: market_object.hpp:49
graphene::protocol::bid_collateral_operation::additional_collateral
asset additional_collateral
the amount of collateral to bid for the debt
Definition: market.hpp:248
graphene::chain::asset_object::dynamic_asset_data_id
asset_dynamic_data_id_type dynamic_asset_data_id
Current supply, fee pool, and collected fees are stored in a separate object as they change frequentl...
Definition: asset_object.hpp:140
graphene::chain::limit_order_update_evaluator::convert_fee
void convert_fee() override
Definition: market_evaluator.cpp:150
graphene::chain::limit_order_update_evaluator::do_evaluate
void_result do_evaluate(const limit_order_update_operation &o)
Definition: market_evaluator.cpp:167
graphene::chain::generic_evaluator::pay_fee
virtual void pay_fee()
Definition: evaluator.cpp:91
graphene::chain::generic_evaluator::fee_from_account
asset fee_from_account
Definition: evaluator.hpp:114
graphene::chain::database::cancel_limit_order
void cancel_limit_order(const limit_order_object &order, bool create_virtual_op=true, bool skip_cancel_fee=false)
Definition: db_market.cpp:533
graphene::db::object_database::find
const T * find(const object_id_type &id) const
Definition: object_database.hpp:126
graphene::chain::call_order_object::target_collateral_ratio
optional< uint16_t > target_collateral_ratio
maximum CR to maintain when selling collateral on margin call
Definition: market_object.hpp:155
graphene::protocol::price_feed::max_short_squeeze_price
price max_short_squeeze_price() const
Definition: asset.cpp:300
graphene::chain::bid_collateral_evaluator::do_apply
void_result do_apply(const bid_collateral_operation &o) const
Definition: market_evaluator.cpp:862
graphene::chain::limit_order_object::for_sale
share_type for_sale
The amount for sale, asset id is sell_price.base.asset_id.
Definition: market_object.hpp:50
graphene::protocol::asset_options::max_supply
share_type max_supply
Definition: asset_ops.hpp:50
graphene::protocol::limit_order_create_operation::seller
account_id_type seller
Definition: market.hpp:88
graphene::chain::account_statistics_object
Definition: account_object.hpp:46
graphene::protocol::limit_order_update_operation::new_expiration
optional< time_point_sec > new_expiration
Definition: market.hpp:128
graphene::chain::limit_order_object::expiration
time_point_sec expiration
When this limit order will expire.
Definition: market_object.hpp:48
graphene::chain::transaction_evaluation_state::skip_limit_order_price_check
bool skip_limit_order_price_check
Definition: transaction_evaluation_state.hpp:51
graphene::chain::generic_evaluator::convert_fee
virtual void convert_fee()
Definition: evaluator.cpp:80
graphene::protocol::limit_order_create_operation::extensions
extensions_type extensions
Definition: market.hpp:100
graphene::protocol::price::call_price
static price call_price(const asset &debt, const asset &collateral, uint16_t collateral_ratio)
Definition: asset.cpp:216
graphene::protocol::call_order_update_operation
Definition: market.hpp:171
graphene::db::index::get
const object & get(object_id_type id) const
Definition: index.hpp:110
graphene::chain::database::current_fee_schedule
const fee_schedule & current_fee_schedule() const
Definition: db_getter.cpp:62
graphene::chain::database::update_bitasset_current_feed
void update_bitasset_current_feed(const asset_bitasset_data_object &bitasset, bool skip_median_update=false)
Definition: db_update.cpp:270
graphene::db::generic_index::indices
const index_type & indices() const
Definition: generic_index.hpp:115
fc::optional::valid
bool valid() const
Definition: optional.hpp:186
graphene::chain::database::cancel_bid
void cancel_bid(const collateral_bid_object &bid, bool create_virtual_op=true)
Definition: db_market.cpp:477
graphene::chain::asset_dynamic_data_object
tracks the asset information that changes frequently
Definition: asset_object.hpp:56
graphene::protocol::limit_order_update_operation
Definition: market.hpp:117
graphene::chain::database::apply_order
bool apply_order(const limit_order_object &new_order_object)
Definition: db_market.cpp:741
fc::time_point_sec
Definition: time.hpp:74
graphene::protocol::asset::asset_id
asset_id_type asset_id
Definition: asset.hpp:37
account_object.hpp
graphene::chain::asset_object::can_create_new_supply
bool can_create_new_supply() const
Definition: asset_object.hpp:101
graphene::chain::limit_order_object::receive_asset_id
asset_id_type receive_asset_id() const
Definition: market_object.hpp:80
graphene::protocol::price::is_null
bool is_null() const
Definition: asset.cpp:229
graphene::chain::generic_evaluator::fee_asset_dyn_data
const asset_dynamic_data_object * fee_asset_dyn_data
Definition: evaluator.hpp:119
graphene::chain::is_authorized_asset
bool is_authorized_asset(const database &d, const account_object &acct, const asset_object &asset_obj)
Definition: is_authorized_asset.hpp:43
graphene::chain::asset_bitasset_data_object::current_feed
price_feed_with_icr current_feed
This is the currently active price feed, calculated from median_feed and other parameters.
Definition: asset_object.hpp:272
graphene::chain::collateral_bid_object
bids of collateral for debt after a black swan
Definition: market_object.hpp:206
graphene::chain::asset_bitasset_data_object::median_feed
price_feed_with_icr median_feed
This is the median of values from the currently active feeds.
Definition: asset_object.hpp:270
graphene::chain::call_order_object::call_price
price call_price
Collateral / Debt.
Definition: market_object.hpp:153
graphene::protocol::limit_order_cancel_operation
Definition: market.hpp:145
graphene::chain::asset_object::can_bid_collateral
bool can_bid_collateral() const
Definition: asset_object.hpp:111
graphene::protocol::call_order_update_operation::extensions
extensions_type extensions
Definition: market.hpp:193
graphene::db::index::find
virtual const object * find(object_id_type id) const =0
graphene::protocol::limit_order_create_operation::expiration
time_point_sec expiration
Definition: market.hpp:94
graphene::protocol::limit_order_update_operation::order
limit_order_id_type order
Definition: market.hpp:125
graphene::chain::call_order_update_evaluator::do_apply
object_id_type do_apply(const call_order_update_operation &o)
Definition: market_evaluator.cpp:592
graphene::chain::bid_collateral_evaluator::do_evaluate
void_result do_evaluate(const bid_collateral_operation &o)
Definition: market_evaluator.cpp:799
graphene::protocol::limit_order_create_operation::min_to_receive
asset min_to_receive
Definition: market.hpp:90
graphene::protocol::share_type
safe< int64_t > share_type
Definition: types.hpp:309
graphene::chain::generic_evaluator::db
database & db() const
Definition: evaluator.cpp:39
graphene::chain::limit_order_cancel_evaluator::do_apply
asset do_apply(const limit_order_cancel_operation &o) const
Definition: market_evaluator.cpp:485
graphene::protocol::chain_parameters::cashback_vesting_threshold
share_type cashback_vesting_threshold
the maximum cashback that can be received without vesting
Definition: chain_parameters.hpp:70
graphene::chain::limit_order_create_evaluator::do_apply
object_id_type do_apply(const limit_order_create_operation &o) const
Definition: market_evaluator.cpp:114
FC_ASSERT
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
graphene::db::object_id_type
Definition: object_id.hpp:30
graphene::protocol::asset::amount
share_type amount
Definition: asset.hpp:36
graphene::chain::limit_order_object::get_take_profit_action
const create_take_profit_order_action & get_take_profit_action() const
Returns the configured automatic action that will create a take profit order when this limit order is...
Definition: market_object.hpp:64
graphene::chain::limit_order_create_evaluator::do_evaluate
void_result do_evaluate(const limit_order_create_operation &o)
Definition: market_evaluator.cpp:39
graphene::protocol::price_feed::maintenance_collateral_ratio
uint16_t maintenance_collateral_ratio
Definition: asset.hpp:186
market.hpp
graphene::chain::limit_order_object::amount_for_sale
asset amount_for_sale() const
Definition: market_object.hpp:77
graphene::chain::asset_bitasset_data_object::get_black_swan_response_method
bitasset_options::black_swan_response_type get_black_swan_response_method() const
Get the effective black swan response method of this bitasset.
Definition: asset_object.hpp:349
graphene::chain::account_statistics_object::total_core_in_orders
share_type total_core_in_orders
Definition: account_object.hpp:68
graphene::protocol::limit_order_cancel_operation::fee_paying_account
account_id_type fee_paying_account
Definition: market.hpp:152
graphene::chain::limit_order_cancel_evaluator::do_evaluate
void_result do_evaluate(const limit_order_cancel_operation &o)
Definition: market_evaluator.cpp:466
graphene::chain::call_order_object
tracks debt and call price information
Definition: market_object.hpp:140
graphene::chain::limit_order_create_evaluator::pay_fee
void pay_fee() override
Definition: market_evaluator.cpp:102
graphene::protocol::price::base
asset base
Definition: asset.hpp:113
graphene::chain::account_object::statistics
account_statistics_id_type statistics
Definition: account_object.hpp:229
graphene::protocol::limit_order_cancel_operation::order
limit_order_id_type order
Definition: market.hpp:150
graphene::protocol::limit_order_create_operation
instructs the blockchain to attempt to sell one asset for another
Definition: market.hpp:72
graphene::db::generic_index
Definition: generic_index.hpp:43
graphene::chain::database::get_account_stats_by_owner
const account_statistics_object & get_account_stats_by_owner(account_id_type owner) const
Definition: db_getter.cpp:142
graphene::db::abstract_object::get_id
object_id< SpaceID, TypeID > get_id() const
Definition: object.hpp:113
graphene::chain::database::get_global_properties
const global_property_object & get_global_properties() const
Definition: db_getter.cpp:47
fc::optional
provides stack-based nullable value similar to boost::optional
Definition: optional.hpp:20
graphene::protocol::limit_order_create_operation::get_price
price get_price() const
Definition: market.hpp:110
graphene::chain::generic_evaluator::fee_paying_account
const account_object * fee_paying_account
Definition: evaluator.hpp:116
graphene::chain::limit_order_object::take_profit_order_id
optional< limit_order_id_type > take_profit_order_id
ID of the take profit limit order linked to this limit order.
Definition: market_object.hpp:61
FC_THROW_EXCEPTION
#define FC_THROW_EXCEPTION(EXCEPTION, FORMAT,...)
Definition: exception.hpp:379
graphene::protocol::asset
Definition: asset.hpp:31
graphene::chain::asset_object::options
asset_options options
Definition: asset_object.hpp:137
market_object.hpp
graphene::chain::generic_evaluator::core_fee_paid
share_type core_fee_paid
Definition: evaluator.hpp:115
GRAPHENE_ASSERT
#define GRAPHENE_ASSERT(expr, exc_type, FORMAT,...)
Definition: exceptions.hpp:28
graphene::protocol::limit_order_create_operation::fill_or_kill
bool fill_or_kill
If this flag is set the entire order must be filled or the operation is rejected.
Definition: market.hpp:97
graphene::protocol::void_result
Definition: base.hpp:86
graphene::db::object_database::remove
void remove(const object &obj)
Definition: object_database.hpp:97
graphene::chain::asset_object::is_market_issued
bool is_market_issued() const
Definition: asset_object.hpp:84
graphene::db::object_database::get_index_type
const IndexType & get_index_type() const
Definition: object_database.hpp:77
graphene::chain::database::get_dynamic_global_properties
const dynamic_global_property_object & get_dynamic_global_properties() const
Definition: db_getter.cpp:57
fc::safe::value
T value
Definition: safe.hpp:28
graphene::protocol::limit_order_update_operation::delta_amount_to_sell
optional< asset > delta_amount_to_sell
Definition: market.hpp:127
graphene::chain::asset_bitasset_data_object::current_initial_collateralization
price current_initial_collateralization
Definition: asset_object.hpp:288
graphene::db::index
abstract base class for accessing objects indexed in various ways.
Definition: index.hpp:70
graphene::chain::limit_order_object
an offer to sell an amount of an asset at a specified exchange rate by a certain time
Definition: market_object.hpp:45
graphene::protocol::call_order_update_operation::funding_account
account_id_type funding_account
pays fee, collateral, and cover
Definition: market.hpp:188
graphene::protocol::bitasset_options::short_backing_asset
asset_id_type short_backing_asset
Definition: asset_ops.hpp:171
graphene::chain::limit_order_object::deferred_paid_fee
asset deferred_paid_fee
originally paid fee
Definition: market_object.hpp:54
graphene::chain::limit_order_object::deferred_fee
share_type deferred_fee
fee converted to CORE
Definition: market_object.hpp:53
graphene::protocol::price::quote
asset quote
Definition: asset.hpp:114
graphene
Definition: api.cpp:48
graphene::protocol::extension::value
T value
Definition: ext.hpp:40
exceptions.hpp
graphene::chain::asset_bitasset_data_object::options
bitasset_options options
The tunable options for BitAssets are stored in this field.
Definition: asset_object.hpp:263
market_evaluator.hpp
graphene::db::object_database::modify
void modify(const T &obj, const Lambda &m)
Definition: object_database.hpp:99
graphene::chain::generic_evaluator::trx_state
transaction_evaluation_state * trx_state
Definition: evaluator.hpp:120
graphene::chain::asset_bitasset_data_object::is_globally_settled
bool is_globally_settled() const
Definition: asset_object.hpp:299
fc::safe
Definition: safe.hpp:26