BitShares-Core  4.0.0
BitShares blockchain implementation and command-line interface software
asset_evaluator.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-2018 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  */
30 #include <graphene/chain/hardfork.hpp>
32 
33 #include <functional>
34 
35 namespace graphene { namespace chain {
36 namespace detail {
37 
38  // TODO review and remove code below and links to it after hf_1774
39  void check_asset_options_hf_1774(const fc::time_point_sec& block_time, const asset_options& options)
40  {
41  if( block_time < HARDFORK_1774_TIME )
42  {
45  "Asset extension reward percent must be less than 100% till HARDFORK_1774_TIME!");
46  }
47  }
48 
49  void check_bitasset_options_hf_bsip74( const fc::time_point_sec& block_time, const bitasset_options& options)
50  {
51  // HF_REMOVABLE: Following hardfork check should be removable after hardfork date passes:
52  FC_ASSERT( block_time >= HARDFORK_CORE_BSIP74_TIME
53  || !options.extensions.value.margin_call_fee_ratio.valid(),
54  "A BitAsset's MCFR cannot be set before Hardfork BSIP74" );
55  }
56 
57  // TODO review and remove code below and links to it after HARDFORK_BSIP_81_TIME
58  void check_asset_options_hf_bsip81(const fc::time_point_sec& block_time, const asset_options& options)
59  {
60  if (block_time < HARDFORK_BSIP_81_TIME) {
61  // Taker fees should not be set until activation of BSIP81
63  "Taker fee percent should not be defined before HARDFORK_BSIP_81_TIME");
64  }
65  }
66 
67  // TODO review and remove code below and links to it after HARDFORK_BSIP_48_75_TIME
68  void check_asset_options_hf_bsip_48_75(const fc::time_point_sec& block_time, const asset_options& options)
69  {
70  if ( !HARDFORK_BSIP_48_75_PASSED( block_time ) )
71  {
72  // new issuer permissions should not be set until activation of BSIP_48_75
73  FC_ASSERT( !(options.issuer_permissions & ~ASSET_ISSUER_PERMISSION_ENABLE_BITS_MASK),
74  "New asset issuer permission bits should not be set before HARDFORK_BSIP_48_75_TIME" );
75  // Note: no check for flags here because we didn't check in the past
76  }
77  }
78 
79  // TODO review and remove code below and links to it after HARDFORK_BSIP_48_75_TIME
81  {
82  if ( !HARDFORK_BSIP_48_75_PASSED( block_time ) )
83  {
84  // new params should not be set until activation of BSIP_48_75
85  FC_ASSERT( !options.extensions.value.maintenance_collateral_ratio.valid(),
86  "Maintenance collateral ratio should not be defined by asset owner "
87  "before HARDFORK_BSIP_48_75_TIME" );
88  FC_ASSERT( !options.extensions.value.maximum_short_squeeze_ratio.valid(),
89  "Maximum short squeeze ratio should not be defined by asset owner "
90  "before HARDFORK_BSIP_48_75_TIME" );
91  }
92  }
93 
94  // TODO review and remove code below and links to it after HARDFORK_BSIP_48_75_TIME
96  const asset_update_operation::ext& extensions )
97  {
98  if ( !HARDFORK_BSIP_48_75_PASSED( block_time ) )
99  {
100  // new extensions should not be set until activation of BSIP_48_75
101  FC_ASSERT( !extensions.new_precision.valid(),
102  "new_precision should not be set before HARDFORK_BSIP_48_75_TIME" );
103  FC_ASSERT( !extensions.skip_core_exchange_rate.valid(),
104  "skip_core_exchange_rate should not be set before HARDFORK_BSIP_48_75_TIME" );
105  }
106  }
107 
108  // TODO review and remove code below and links to it after HARDFORK_BSIP_77_TIME
110  const asset_publish_feed_operation::ext& extensions )
111  {
112  if ( !HARDFORK_BSIP_77_PASSED( block_time ) )
113  {
114  // new extensions should not be set until activation of BSIP_77
116  "Initial collateral ratio should not be defined before HARDFORK_BSIP_77_TIME" );
117  }
118  }
119 
120  // TODO review and remove code below and links to it after HARDFORK_BSIP_77_TIME
122  {
123  if ( !HARDFORK_BSIP_77_PASSED( block_time ) ) {
124  // ICR should not be set until activation of BSIP77
125  FC_ASSERT(!options.extensions.value.initial_collateral_ratio.valid(),
126  "Initial collateral ratio should not be defined before HARDFORK_BSIP_77_TIME");
127  }
128  }
129 
131  {
132  // HF_REMOVABLE: Following hardfork check should be removable after hardfork date passes:
133  FC_ASSERT( !options.extensions.value.force_settle_fee_percent.valid()
134  || block_time >= HARDFORK_CORE_BSIP87_TIME,
135  "A BitAsset's FSFP cannot be set before Hardfork BSIP87" );
136  }
137 
139  const asset_claim_fees_operation& op)
140  {
141  // HF_REMOVABLE: Following hardfork check should be removable after hardfork date passes:
142  FC_ASSERT( !op.extensions.value.claim_from_asset_id.valid() ||
143  block_time >= HARDFORK_CORE_BSIP_87_74_COLLATFEE_TIME,
144  "Collateral-denominated fees are not yet active and therefore cannot be claimed." );
145  }
146 
147 } // graphene::chain::detail
148 
150 { try {
151 
152  const database& d = db();
153  const time_point_sec now = d.head_block_time();
154 
155  // Hardfork Checks:
159  if( op.bitasset_opts ) {
161  detail::check_bitasset_options_hf_bsip74( now, *op.bitasset_opts ); // HF_REMOVABLE
162  detail::check_bitasset_options_hf_bsip77( now, *op.bitasset_opts ); // HF_REMOVABLE
163  detail::check_bitasset_options_hf_bsip87( now, *op.bitasset_opts ); // HF_REMOVABLE
164  }
165 
166  // TODO move as many validations as possible to validate() if not triggered before hardfork
167  if( HARDFORK_BSIP_48_75_PASSED( now ) )
168  {
170  }
171 
175 
176  // Check that all authorities do exist
177  for( auto id : op.common_options.whitelist_authorities )
178  d.get_object(id);
179  for( auto id : op.common_options.blacklist_authorities )
180  d.get_object(id);
181 
182  auto& asset_indx = d.get_index_type<asset_index>().indices().get<by_symbol>();
183  auto asset_symbol_itr = asset_indx.find( op.symbol );
184  FC_ASSERT( asset_symbol_itr == asset_indx.end() );
185 
186  // This must remain due to "BOND.CNY" being allowed before this HF
187  if( now > HARDFORK_385_TIME )
188  {
189  auto dotpos = op.symbol.rfind( '.' );
190  if( dotpos != std::string::npos )
191  {
192  auto prefix = op.symbol.substr( 0, dotpos );
193  auto asset_symbol_itr = asset_indx.find( prefix );
194  FC_ASSERT( asset_symbol_itr != asset_indx.end(),
195  "Asset ${s} may only be created by issuer of asset ${p}, but asset ${p} has not been created",
196  ("s",op.symbol)("p",prefix) );
197  FC_ASSERT( asset_symbol_itr->issuer == op.issuer, "Asset ${s} may only be created by issuer of ${p}, ${i}",
198  ("s",op.symbol)("p",prefix)("i", op.issuer(d).name) );
199  }
200  }
201 
202  if( op.bitasset_opts )
203  {
204  const asset_object& backing = op.bitasset_opts->short_backing_asset(d);
205  if( backing.is_market_issued() )
206  {
207  const asset_bitasset_data_object& backing_bitasset_data = backing.bitasset_data(d);
208  const asset_object& backing_backing = backing_bitasset_data.options.short_backing_asset(d);
209  FC_ASSERT( !backing_backing.is_market_issued(),
210  "May not create a bitasset backed by a bitasset backed by a bitasset." );
211  FC_ASSERT( op.issuer != GRAPHENE_COMMITTEE_ACCOUNT || backing_backing.get_id() == asset_id_type(),
212  "May not create a blockchain-controlled market asset which is not backed by CORE.");
213  } else
214  FC_ASSERT( op.issuer != GRAPHENE_COMMITTEE_ACCOUNT || backing.get_id() == asset_id_type(),
215  "May not create a blockchain-controlled market asset which is not backed by CORE.");
216  FC_ASSERT( op.bitasset_opts->feed_lifetime_sec > chain_parameters.block_interval &&
217  op.bitasset_opts->force_settlement_delay_sec > chain_parameters.block_interval );
218  }
219 
220  if( op.is_prediction_market )
221  {
222  FC_ASSERT( op.bitasset_opts );
223  FC_ASSERT( op.precision == op.bitasset_opts->short_backing_asset(d).precision );
224  }
225 
226  return void_result();
227 } FC_CAPTURE_AND_RETHROW( (op) ) }
228 
230 {
231  fee_is_odd = core_fee_paid.value & 1;
232  core_fee_paid -= core_fee_paid.value/2;
234 }
235 
237 { try {
238  database& d = db();
239 
240  bool hf_429 = fee_is_odd && d.head_block_time() > HARDFORK_CORE_429_TIME;
241 
242  const asset_dynamic_data_object& dyn_asset =
244  a.current_supply = 0;
245  a.fee_pool = core_fee_paid - (hf_429 ? 1 : 0);
246  });
247 
248  if( fee_is_odd && !hf_429 )
249  {
251  dd.current_supply++;
252  });
253  }
254 
255  asset_bitasset_data_id_type bit_asset_id;
256 
257  auto next_asset_id = d.get_index_type<asset_index>().get_next_id();
258 
259  if( op.bitasset_opts.valid() )
260  bit_asset_id = d.create<asset_bitasset_data_object>( [&op,next_asset_id]( asset_bitasset_data_object& a ) {
261  a.options = *op.bitasset_opts;
263  a.asset_id = next_asset_id;
264  }).id;
265 
266  const asset_object& new_asset =
267  d.create<asset_object>( [&op,next_asset_id,&dyn_asset,bit_asset_id]( asset_object& a ) {
268  a.issuer = op.issuer;
269  a.symbol = op.symbol;
270  a.precision = op.precision;
271  a.options = op.common_options;
272  if( a.options.core_exchange_rate.base.asset_id.instance.value == 0 )
273  a.options.core_exchange_rate.quote.asset_id = next_asset_id;
274  else
275  a.options.core_exchange_rate.base.asset_id = next_asset_id;
276  a.dynamic_asset_data_id = dyn_asset.id;
277  if( op.bitasset_opts.valid() )
278  a.bitasset_data_id = bit_asset_id;
279  });
280  FC_ASSERT( new_asset.id == next_asset_id, "Unexpected object database error, object id mismatch" );
281 
282  return new_asset.id;
283 } FC_CAPTURE_AND_RETHROW( (op) ) }
284 
286 { try {
287  const database& d = db();
288 
289  const asset_object& a = o.asset_to_issue.asset_id(d);
290  FC_ASSERT( o.issuer == a.issuer );
291  FC_ASSERT( !a.is_market_issued(), "Cannot manually issue a market-issued asset." );
292 
293  FC_ASSERT( a.can_create_new_supply(), "Can not create new supply" );
294 
295  to_account = &o.issue_to_account(d);
296  FC_ASSERT( is_authorized_asset( d, *to_account, a ) );
297 
298  asset_dyn_data = &a.dynamic_asset_data_id(d);
299  FC_ASSERT( (asset_dyn_data->current_supply + o.asset_to_issue.amount) <= a.options.max_supply );
300 
301  return void_result();
302 } FC_CAPTURE_AND_RETHROW( (o) ) }
303 
305 { try {
306  db().adjust_balance( o.issue_to_account, o.asset_to_issue );
307 
308  db().modify( *asset_dyn_data, [&o]( asset_dynamic_data_object& data ){
310  });
311 
312  return void_result();
313 } FC_CAPTURE_AND_RETHROW( (o) ) }
314 
316 { try {
317  const database& d = db();
318 
319  const asset_object& a = o.amount_to_reserve.asset_id(d);
321  !a.is_market_issued(),
322  asset_reserve_invalid_on_mia,
323  "Cannot reserve ${sym} because it is a market-issued asset",
324  ("sym", a.symbol)
325  );
326 
327  from_account = &o.payer(d);
328  FC_ASSERT( is_authorized_asset( d, *from_account, a ) );
329 
330  asset_dyn_data = &a.dynamic_asset_data_id(d);
331  FC_ASSERT( (asset_dyn_data->current_supply - o.amount_to_reserve.amount) >= 0 );
332 
333  return void_result();
334 } FC_CAPTURE_AND_RETHROW( (o) ) }
335 
337 { try {
338  db().adjust_balance( o.payer, -o.amount_to_reserve );
339 
340  db().modify( *asset_dyn_data, [&o]( asset_dynamic_data_object& data ){
342  });
343 
344  return void_result();
345 } FC_CAPTURE_AND_RETHROW( (o) ) }
346 
348 { try {
349  database& d = db();
350 
351  const asset_object& a = o.asset_id(d);
352 
353  asset_dyn_data = &a.dynamic_asset_data_id(d);
354 
355  return void_result();
356 } FC_CAPTURE_AND_RETHROW( (o) ) }
357 
359 { try {
360  db().adjust_balance(o.from_account, -o.amount);
361 
362  db().modify( *asset_dyn_data, [&o]( asset_dynamic_data_object& data ) {
363  data.fee_pool += o.amount;
364  });
365 
366  return void_result();
367 } FC_CAPTURE_AND_RETHROW( (o) ) }
368 
369 static void validate_new_issuer( const database& d, const asset_object& a, account_id_type new_issuer )
370 { try {
371  FC_ASSERT(d.find_object(new_issuer));
372  if( a.is_market_issued() && new_issuer == GRAPHENE_COMMITTEE_ACCOUNT )
373  {
374  const asset_object& backing = a.bitasset_data(d).options.short_backing_asset(d);
375  if( backing.is_market_issued() )
376  {
377  const asset_object& backing_backing = backing.bitasset_data(d).options.short_backing_asset(d);
378  FC_ASSERT( backing_backing.get_id() == asset_id_type(),
379  "May not create a blockchain-controlled market asset which is not backed by CORE.");
380  } else
381  FC_ASSERT( backing.get_id() == asset_id_type(),
382  "May not create a blockchain-controlled market asset which is not backed by CORE.");
383  }
384 } FC_CAPTURE_AND_RETHROW( (a)(new_issuer) ) }
385 
387 { try {
388  const database& d = db();
389  const time_point_sec now = d.head_block_time();
390 
391  // Hardfork Checks:
396 
397  bool hf_bsip_48_75_passed = ( HARDFORK_BSIP_48_75_PASSED( now ) );
398 
399  const asset_object& a = o.asset_to_update(d);
400  auto a_copy = a;
401  a_copy.options = o.new_options;
402  a_copy.validate();
403 
404  if( o.new_issuer )
405  {
406  FC_ASSERT( now < HARDFORK_CORE_199_TIME,
407  "Since Hardfork #199, updating issuer requires the use of asset_update_issuer_operation.");
408  validate_new_issuer( d, a, *o.new_issuer );
409  }
410 
411  uint16_t enabled_issuer_permissions_mask = a.options.get_enabled_issuer_permissions_mask();
412  if( hf_bsip_48_75_passed && a.is_market_issued() )
413  {
414  bitasset_data = &a.bitasset_data(d);
415  if( bitasset_data->is_prediction_market )
416  {
417  // Note: if the global_settle permission was unset, it should be corrected
418  FC_ASSERT( a_copy.can_global_settle(),
419  "The global_settle permission should be enabled for prediction markets" );
420  enabled_issuer_permissions_mask |= global_settle;
421  }
422  }
423 
424  const auto& dyn_data = a.dynamic_asset_data_id(d);
425  if( dyn_data.current_supply != 0 )
426  {
427  // new issuer_permissions must be subset of old issuer permissions
428  FC_ASSERT(!(o.new_options.get_enabled_issuer_permissions_mask() & ~enabled_issuer_permissions_mask),
429  "Cannot reinstate previously revoked issuer permissions on an asset if current supply is non-zero.");
430  // precision can not be changed
431  FC_ASSERT( !o.extensions.value.new_precision.valid(),
432  "Cannot update precision if current supply is non-zero" );
433 
434  if( hf_bsip_48_75_passed ) // TODO review after hard fork, probably can assert unconditionally
435  {
436  FC_ASSERT( dyn_data.current_supply <= o.new_options.max_supply,
437  "Max supply should not be smaller than current supply" );
438  }
439  }
440 
441  // TODO move as many validations as possible to validate() if not triggered before hardfork
442  if( hf_bsip_48_75_passed )
443  {
445  }
446 
447  // changed flags must be subset of old issuer permissions
448  if( hf_bsip_48_75_passed )
449  {
450  // Note: if an invalid bit was set, it can be unset regardless of the permissions
451  uint16_t check_bits = ( a.is_market_issued() ? VALID_FLAGS_MASK : UIA_VALID_FLAGS_MASK );
452 
453  FC_ASSERT( !((o.new_options.flags ^ a.options.flags) & check_bits & ~enabled_issuer_permissions_mask),
454  "Flag change is forbidden by issuer permissions" );
455  }
456  else
457  {
459  "Flag change is forbidden by issuer permissions" );
460  }
461 
462  asset_to_update = &a;
463  FC_ASSERT( o.issuer == a.issuer,
464  "Incorrect issuer for asset! (${o.issuer} != ${a.issuer})",
465  ("o.issuer", o.issuer)("a.issuer", a.issuer) );
466 
468  "Can not update max supply" );
469 
470  if( o.extensions.value.new_precision.valid() )
471  {
472  FC_ASSERT( *o.extensions.value.new_precision != a.precision,
473  "Specified a new precision but it does not change" );
474 
475  if( a.is_market_issued() )
476  {
477  if( !bitasset_data )
478  bitasset_data = &asset_to_update->bitasset_data(d);
479  FC_ASSERT( !bitasset_data->is_prediction_market, "Can not update precision of a prediction market" );
480  }
481 
482  // If any other asset is backed by this asset, this asset's precision can't be updated
484  .indices().get<by_short_backing_asset>();
485  auto itr = idx.lower_bound( o.asset_to_update );
486  bool backing_another_asset = ( itr != idx.end() && itr->options.short_backing_asset == o.asset_to_update );
487  FC_ASSERT( !backing_another_asset,
488  "Asset ${a} is backed by this asset, can not update precision",
489  ("a",itr->asset_id) );
490  }
491 
493 
495  for( auto id : o.new_options.whitelist_authorities )
496  d.get_object(id);
498  for( auto id : o.new_options.blacklist_authorities )
499  d.get_object(id);
500 
501  return void_result();
502 } FC_CAPTURE_AND_RETHROW((o)) }
503 
505 { try {
506  database& d = db();
507 
508  // If we are now disabling force settlements, cancel all open force settlement orders
509  if( (o.new_options.flags & disable_force_settle) && asset_to_update->can_force_settle() )
510  {
511  const auto& idx = d.get_index_type<force_settlement_index>().indices().get<by_expiration>();
512  // Funky iteration code because we're removing objects as we go. We have to re-initialize itr every loop instead
513  // of simply incrementing it.
514  for( auto itr = idx.lower_bound(o.asset_to_update);
515  itr != idx.end() && itr->settlement_asset_id() == o.asset_to_update;
516  itr = idx.lower_bound(o.asset_to_update) )
517  d.cancel_settle_order(*itr);
518  }
519 
520  // For market-issued assets, if core exchange rate changed, update flag in bitasset data
521  if( !o.extensions.value.skip_core_exchange_rate.valid() && asset_to_update->is_market_issued()
522  && asset_to_update->options.core_exchange_rate != o.new_options.core_exchange_rate )
523  {
524  const auto& bitasset = ( bitasset_data ? *bitasset_data : asset_to_update->bitasset_data(d) );
525  if( !bitasset.asset_cer_updated )
526  {
527  d.modify( bitasset, [](asset_bitasset_data_object& b)
528  {
529  b.asset_cer_updated = true;
530  });
531  }
532  }
533 
534  d.modify(*asset_to_update, [&o](asset_object& a) {
535  if( o.new_issuer )
536  a.issuer = *o.new_issuer;
537  if( o.extensions.value.new_precision.valid() )
538  a.precision = *o.extensions.value.new_precision;
539  if( o.extensions.value.skip_core_exchange_rate.valid() )
540  {
541  const auto old_cer = a.options.core_exchange_rate;
542  a.options = o.new_options;
543  a.options.core_exchange_rate = old_cer;
544  }
545  else
546  a.options = o.new_options;
547  });
548 
549  return void_result();
550 } FC_CAPTURE_AND_RETHROW( (o) ) }
551 
553 { try {
554  database& d = db();
555 
556  const asset_object& a = o.asset_to_update(d);
557 
558  validate_new_issuer( d, a, o.new_issuer );
559 
560  asset_to_update = &a;
561  FC_ASSERT( o.issuer == a.issuer,
562  "Incorrect issuer for asset! (${o.issuer} != ${a.issuer})",
563  ("o.issuer", o.issuer)("a.issuer", a.issuer) );
564 
565  return void_result();
566 } FC_CAPTURE_AND_RETHROW((o)) }
567 
569 { try {
570  database& d = db();
571  d.modify(*asset_to_update, [&](asset_object& a) {
572  a.issuer = o.new_issuer;
573  });
574 
575  return void_result();
576 } FC_CAPTURE_AND_RETHROW( (o) ) }
577 
578 /****************
579  * Loop through assets, looking for ones that are backed by the asset being changed. When found,
580  * perform checks to verify validity
581  *
582  * @param d the database
583  * @param op the bitasset update operation being performed
584  * @param new_backing_asset
585  * @param true if after hf 922/931 (if nothing triggers, this and the logic that depends on it
586  * should be removed).
587  */
589  const asset_object& new_backing_asset)
590 {
591  // no need to do these checks if the new backing asset is CORE
592  if ( new_backing_asset.get_id() == asset_id_type() )
593  return;
594 
595  // loop through all assets that have this asset as a backing asset
597  .indices()
598  .get<by_short_backing_asset>();
599  auto backed_range = idx.equal_range(op.asset_to_update);
600  std::for_each( backed_range.first, backed_range.second,
601  [&new_backing_asset, &d, &op](const asset_bitasset_data_object& bitasset_data)
602  {
603  const auto& child = bitasset_data.asset_id(d);
604  FC_ASSERT( child.get_id() != op.new_options.short_backing_asset,
605  "A BitAsset would be invalidated by changing this backing asset ('A' backed by 'B' backed by 'A')." );
606 
607  FC_ASSERT( child.issuer != GRAPHENE_COMMITTEE_ACCOUNT,
608  "A blockchain-controlled market asset would be invalidated by changing this backing asset." );
609 
610  FC_ASSERT( !new_backing_asset.is_market_issued(),
611  "A non-blockchain controlled BitAsset would be invalidated by changing this backing asset.");
612  } ); // end of lambda and std::for_each()
613 } // check_children_of_bitasset
614 
616 { try {
617  const database& d = db();
618  const time_point_sec now = d.head_block_time();
619 
620  // Hardfork Checks:
622  detail::check_bitasset_options_hf_bsip74( now, op.new_options ); // HF_REMOVABLE
623  detail::check_bitasset_options_hf_bsip77( now, op.new_options ); // HF_REMOVABLE
624  detail::check_bitasset_options_hf_bsip87( now, op.new_options ); // HF_REMOVABLE
625 
626  const asset_object& asset_obj = op.asset_to_update(d);
627 
628  FC_ASSERT( asset_obj.is_market_issued(), "Cannot update BitAsset-specific settings on a non-BitAsset." );
629 
630  FC_ASSERT( op.issuer == asset_obj.issuer, "Only asset issuer can update bitasset_data of the asset." );
631 
632  const asset_bitasset_data_object& current_bitasset_data = asset_obj.bitasset_data(d);
633 
634  FC_ASSERT( !current_bitasset_data.has_settlement(),
635  "Cannot update a bitasset after a global settlement has executed" );
636 
637  // TODO simplify code below when made sure operator==(optional,optional) works
638  if( !asset_obj.can_owner_update_mcr() )
639  {
640  // check if MCR will change
641  const auto& old_mcr = current_bitasset_data.options.extensions.value.maintenance_collateral_ratio;
642  const auto& new_mcr = op.new_options.extensions.value.maintenance_collateral_ratio;
643  bool mcr_changed = ( ( old_mcr.valid() != new_mcr.valid() )
644  || ( old_mcr.valid() && *old_mcr != *new_mcr ) );
645  FC_ASSERT( !mcr_changed, "No permission to update MCR" );
646  }
647  if( !asset_obj.can_owner_update_icr() )
648  {
649  // check if ICR will change
650  const auto& old_icr = current_bitasset_data.options.extensions.value.initial_collateral_ratio;
651  const auto& new_icr = op.new_options.extensions.value.initial_collateral_ratio;
652  bool icr_changed = ( ( old_icr.valid() != new_icr.valid() )
653  || ( old_icr.valid() && *old_icr != *new_icr ) );
654  FC_ASSERT( !icr_changed, "No permission to update ICR" );
655  }
656  if( !asset_obj.can_owner_update_mssr() )
657  {
658  // check if MSSR will change
659  const auto& old_mssr = current_bitasset_data.options.extensions.value.maximum_short_squeeze_ratio;
660  const auto& new_mssr = op.new_options.extensions.value.maximum_short_squeeze_ratio;
661  bool mssr_changed = ( ( old_mssr.valid() != new_mssr.valid() )
662  || ( old_mssr.valid() && *old_mssr != *new_mssr ) );
663  FC_ASSERT( !mssr_changed, "No permission to update MSSR" );
664  }
665 
666  // hf 922_931 is a consensus/logic change. This hf cannot be removed.
667  bool after_hf_core_922_931 = ( d.get_dynamic_global_properties().next_maintenance_time
668  > HARDFORK_CORE_922_931_TIME );
669 
670  // Are we changing the backing asset?
671  if( op.new_options.short_backing_asset != current_bitasset_data.options.short_backing_asset )
672  {
673  const asset_dynamic_data_object& dyn = asset_obj.dynamic_asset_data_id(d);
674  FC_ASSERT( dyn.current_supply == 0,
675  "Cannot update a bitasset if there is already a current supply." );
676 
678  "Must claim collateral-denominated fees before changing backing asset." );
679 
680  const asset_object& new_backing_asset = op.new_options.short_backing_asset(d); // check if the asset exists
681 
682  if( after_hf_core_922_931 )
683  {
684  FC_ASSERT( op.new_options.short_backing_asset != asset_obj.get_id(),
685  "Cannot update an asset to be backed by itself." );
686 
687  if( current_bitasset_data.is_prediction_market )
688  {
689  FC_ASSERT( asset_obj.precision == new_backing_asset.precision,
690  "The precision of the asset and backing asset must be equal." );
691  }
692 
693  if( asset_obj.issuer == GRAPHENE_COMMITTEE_ACCOUNT )
694  {
695  if( new_backing_asset.is_market_issued() )
696  {
697  FC_ASSERT( new_backing_asset.bitasset_data(d).options.short_backing_asset == asset_id_type(),
698  "May not modify a blockchain-controlled market asset to be backed by an asset which is not "
699  "backed by CORE." );
700 
701  check_children_of_bitasset( d, op, new_backing_asset );
702  }
703  else
704  {
705  FC_ASSERT( new_backing_asset.get_id() == asset_id_type(),
706  "May not modify a blockchain-controlled market asset to be backed by an asset which is not "
707  "market issued asset nor CORE." );
708  }
709  }
710  else
711  {
712  // not a committee issued asset
713 
714  // If we're changing to a backing_asset that is not CORE, we need to look at any
715  // asset ( "CHILD" ) that has this one as a backing asset. If CHILD is committee-owned,
716  // the change is not allowed. If CHILD is user-owned, then this asset's backing
717  // asset must be either CORE or a UIA.
718  if ( new_backing_asset.get_id() != asset_id_type() ) // not backed by CORE
719  {
720  check_children_of_bitasset( d, op, new_backing_asset );
721  }
722 
723  }
724 
725  // Check if the new backing asset is itself backed by something. It must be CORE or a UIA
726  if ( new_backing_asset.is_market_issued() )
727  {
728  asset_id_type backing_backing_asset_id = new_backing_asset.bitasset_data(d).options.short_backing_asset;
729  FC_ASSERT( (backing_backing_asset_id == asset_id_type() || !backing_backing_asset_id(d).is_market_issued()),
730  "A BitAsset cannot be backed by a BitAsset that itself is backed by a BitAsset.");
731  }
732  }
733  }
734 
736  if( after_hf_core_922_931 )
737  {
739  "Feed lifetime must exceed block interval." );
741  "Force settlement delay must exceed block interval." );
742  }
743 
744  bitasset_to_update = &current_bitasset_data;
745  asset_to_update = &asset_obj;
746 
747  return void_result();
748 } FC_CAPTURE_AND_RETHROW( (op) ) }
749 
750 /*******
751  * @brief Apply requested changes to bitasset options
752  *
753  * This applies the requested changes to the bitasset object. It also cleans up the
754  * releated feeds, and checks conditions that might necessitate a call to check_call_orders.
755  * Called from asset_update_bitasset_evaluator::do_apply().
756  *
757  * @param op the requested operation
758  * @param db the database
759  * @param bdo the actual database object
760  * @param asset_to_update the asset_object related to this bitasset_data_object
761  *
762  * @returns true if we should check call orders, such as if if the feed price is changed, or some
763  * cases after hf core-868-890, or if the margin_call_fee_ratio has changed, which affects the
764  * matching price of margin call orders.
765  */
766 static bool update_bitasset_object_options(
768  asset_bitasset_data_object& bdo, const asset_object& asset_to_update )
769 {
771  bool after_hf_core_868_890 = ( next_maint_time > HARDFORK_CORE_868_890_TIME );
772 
773  // If the minimum number of feeds to calculate a median has changed, we need to recalculate the median
774  bool should_update_feeds = false;
776  should_update_feeds = true;
777 
778  // after hardfork core-868-890, we also should call update_median_feeds if the feed_lifetime_sec changed
779  if( after_hf_core_868_890
781  {
782  should_update_feeds = true;
783  }
784 
785  // feeds must be reset if the backing asset is changed after hardfork core-868-890
786  bool backing_asset_changed = false;
787  bool is_witness_or_committee_fed = false;
788  if( after_hf_core_868_890
790  {
791  backing_asset_changed = true;
792  should_update_feeds = true;
793  if( asset_to_update.options.flags & ( witness_fed_asset | committee_fed_asset ) )
794  is_witness_or_committee_fed = true;
795  }
796 
797  // TODO simplify code below when made sure operator==(optional,optional) works
798  // check if ICR will change
799  if( !should_update_feeds )
800  {
801  const auto& old_icr = bdo.options.extensions.value.initial_collateral_ratio;
802  const auto& new_icr = op.new_options.extensions.value.initial_collateral_ratio;
803  bool icr_changed = ( ( old_icr.valid() != new_icr.valid() )
804  || ( old_icr.valid() && *old_icr != *new_icr ) );
805  should_update_feeds = icr_changed;
806  }
807  // check if MCR will change
808  if( !should_update_feeds )
809  {
810  const auto& old_mcr = bdo.options.extensions.value.maintenance_collateral_ratio;
811  const auto& new_mcr = op.new_options.extensions.value.maintenance_collateral_ratio;
812  bool mcr_changed = ( ( old_mcr.valid() != new_mcr.valid() )
813  || ( old_mcr.valid() && *old_mcr != *new_mcr ) );
814  should_update_feeds = mcr_changed;
815  }
816  // check if MSSR will change
817  if( !should_update_feeds )
818  {
819  const auto& old_mssr = bdo.options.extensions.value.maximum_short_squeeze_ratio;
820  const auto& new_mssr = op.new_options.extensions.value.maximum_short_squeeze_ratio;
821  bool mssr_changed = ( ( old_mssr.valid() != new_mssr.valid() )
822  || ( old_mssr.valid() && *old_mssr != *new_mssr ) );
823  should_update_feeds = mssr_changed;
824  }
825 
826  // check if MCFR will change
827  const auto& old_mcfr = bdo.options.extensions.value.margin_call_fee_ratio;
828  const auto& new_mcfr = op.new_options.extensions.value.margin_call_fee_ratio;
829  const bool mcfr_changed = ( ( old_mcfr.valid() != new_mcfr.valid() )
830  || ( old_mcfr.valid() && *old_mcfr != *new_mcfr ) );
831 
832  // Apply changes to bitasset options
833  bdo.options = op.new_options;
834 
835  // are we modifying the underlying? If so, reset the feeds
836  if( backing_asset_changed )
837  {
838  if( is_witness_or_committee_fed )
839  {
840  bdo.feeds.clear();
841  }
842  else
843  {
844  // for non-witness-feeding and non-committee-feeding assets, modify all feeds
845  // published by producers to nothing, since we can't simply remove them. For more information:
846  // https://github.com/bitshares/bitshares-core/pull/832#issuecomment-384112633
847  for( auto& current_feed : bdo.feeds )
848  {
849  current_feed.second.second.settlement_price = price();
850  }
851  }
852  }
853 
854  bool feed_actually_changed = false;
855  if( should_update_feeds )
856  {
857  const auto old_feed = bdo.current_feed;
858  bdo.update_median_feeds( db.head_block_time(), next_maint_time );
859 
860  // We need to call check_call_orders if the settlement price changes after hardfork core-868-890
861  feed_actually_changed = ( after_hf_core_868_890 && !old_feed.margin_call_params_equal( bdo.current_feed ) );
862  }
863 
864  // Conditions under which a call to check_call_orders is needed in response to the updates applied here:
865  const bool retval = feed_actually_changed || mcfr_changed;
866 
867  return retval;
868 }
869 
871 {
872  try
873  {
874  auto& db_conn = db();
875  const auto& asset_being_updated = (*asset_to_update);
876  bool to_check_call_orders = false;
877 
878  db_conn.modify( *bitasset_to_update,
879  [&op, &asset_being_updated, &to_check_call_orders, &db_conn]( asset_bitasset_data_object& bdo )
880  {
881  to_check_call_orders = update_bitasset_object_options( op, db_conn, bdo, asset_being_updated );
882  });
883 
884  if( to_check_call_orders )
885  // Process margin calls, allow black swan, not for a new limit order
886  db_conn.check_call_orders( asset_being_updated, true, false, bitasset_to_update );
887 
888  return void_result();
889 
890  } FC_CAPTURE_AND_RETHROW( (op) )
891 }
892 
894 { try {
895  database& d = db();
896 
898  "Cannot specify more feed producers than maximum allowed" );
899 
900  const asset_object& a = o.asset_to_update(d);
901 
902  FC_ASSERT(a.is_market_issued(), "Cannot update feed producers on a non-BitAsset.");
903  FC_ASSERT(!(a.options.flags & committee_fed_asset), "Cannot set feed producers on a committee-fed asset.");
904  FC_ASSERT(!(a.options.flags & witness_fed_asset), "Cannot set feed producers on a witness-fed asset.");
905 
906  FC_ASSERT( a.issuer == o.issuer, "Only asset issuer can update feed producers of an asset" );
907 
908  asset_to_update = &a;
909 
910  // Make sure all producers exist. Check these after asset because account lookup is more expensive
911  for( auto id : o.new_feed_producers )
912  d.get_object(id);
913 
914  return void_result();
915 } FC_CAPTURE_AND_RETHROW( (o) ) }
916 
918 { try {
919  database& d = db();
920  const auto head_time = d.head_block_time();
921  const auto next_maint_time = d.get_dynamic_global_properties().next_maintenance_time;
922  const asset_bitasset_data_object& bitasset_to_update = asset_to_update->bitasset_data(d);
923  d.modify( bitasset_to_update, [&o,head_time,next_maint_time](asset_bitasset_data_object& a) {
924  //This is tricky because I have a set of publishers coming in, but a map of publisher to feed is stored.
925  //I need to update the map such that the keys match the new publishers, but not munge the old price feeds from
926  //publishers who are being kept.
927 
928  // TODO possible performance optimization:
929  // Since both the map and the set are ordered by account already, we can iterate through them only once
930  // and avoid lookups while iterating by maintaining two iterators at same time.
931  // However, this operation is not used much, and both the set and the map are small,
932  // so likely we won't gain much with the optimization.
933 
934  //First, remove any old publishers who are no longer publishers
935  for( auto itr = a.feeds.begin(); itr != a.feeds.end(); )
936  {
937  if( !o.new_feed_producers.count(itr->first) )
938  itr = a.feeds.erase(itr);
939  else
940  ++itr;
941  }
942  //Now, add any new publishers
943  for( const account_id_type acc : o.new_feed_producers )
944  {
945  a.feeds[acc];
946  }
947  a.update_median_feeds( head_time, next_maint_time );
948  });
949  // Process margin calls, allow black swan, not for a new limit order
950  d.check_call_orders( *asset_to_update, true, false, &bitasset_to_update );
951 
952  return void_result();
953 } FC_CAPTURE_AND_RETHROW( (o) ) }
954 
956 { try {
957  const database& d = db();
958  asset_to_settle = &op.asset_to_settle(d);
959  FC_ASSERT( asset_to_settle->is_market_issued(), "Can only globally settle market-issued assets" );
960  FC_ASSERT( asset_to_settle->can_global_settle(), "The global_settle permission of this asset is disabled" );
961  FC_ASSERT( asset_to_settle->issuer == op.issuer, "Only asset issuer can globally settle an asset" );
962  FC_ASSERT( asset_to_settle->dynamic_data(d).current_supply > 0, "Can not globally settle an asset with zero supply" );
963 
964  const asset_bitasset_data_object& _bitasset_data = asset_to_settle->bitasset_data(d);
965  // if there is a settlement for this asset, then no further global settle may be taken
966  FC_ASSERT( !_bitasset_data.has_settlement(), "This asset has settlement, cannot global settle again" );
967 
968  const auto& idx = d.get_index_type<call_order_index>().indices().get<by_collateral>();
969  FC_ASSERT( !idx.empty(), "Internal error: no debt position found" );
970  auto itr = idx.lower_bound( price::min( _bitasset_data.options.short_backing_asset, op.asset_to_settle ) );
971  FC_ASSERT( itr != idx.end() && itr->debt_type() == op.asset_to_settle, "Internal error: no debt position found" );
972  const call_order_object& least_collateralized_short = *itr;
973  FC_ASSERT(least_collateralized_short.get_debt() * op.settle_price <= least_collateralized_short.get_collateral(),
974  "Cannot force settle at supplied price: least collateralized short lacks sufficient collateral to settle.");
975 
976  return void_result();
977 } FC_CAPTURE_AND_RETHROW( (op) ) }
978 
980 { try {
981  database& d = db();
982  d.globally_settle_asset( *asset_to_settle, op.settle_price );
983  return void_result();
984 } FC_CAPTURE_AND_RETHROW( (op) ) }
985 
987 { try {
988  const database& d = db();
989  asset_to_settle = &op.amount.asset_id(d);
990  FC_ASSERT(asset_to_settle->is_market_issued());
991  const auto& bitasset = asset_to_settle->bitasset_data(d);
992  FC_ASSERT(asset_to_settle->can_force_settle() || bitasset.has_settlement() );
993  if( bitasset.is_prediction_market )
994  FC_ASSERT( bitasset.has_settlement(), "global settlement must occur before force settling a prediction market" );
995  else if( bitasset.current_feed.settlement_price.is_null()
996  && ( d.head_block_time() <= HARDFORK_CORE_216_TIME // TODO check whether the HF check can be removed
997  || !bitasset.has_settlement() ) )
998  FC_THROW_EXCEPTION(insufficient_feeds, "Cannot force settle with no price feed.");
999  FC_ASSERT( d.get_balance( op.account, op.amount.asset_id ) >= op.amount, "Insufficient balance" );
1000 
1001  return void_result();
1002 } FC_CAPTURE_AND_RETHROW( (op) ) }
1003 
1005 { try {
1006  database& d = db();
1007 
1008  const auto& bitasset = asset_to_settle->bitasset_data(d);
1009  if( bitasset.has_settlement() )
1010  {
1011  const auto& mia_dyn = asset_to_settle->dynamic_asset_data_id(d);
1012 
1013  auto settled_amount = op.amount * bitasset.settlement_price; // round down, in favor of global settlement fund
1014  if( op.amount.amount == mia_dyn.current_supply )
1015  settled_amount.amount = bitasset.settlement_fund; // avoid rounding problems
1016  else
1017  FC_ASSERT( settled_amount.amount <= bitasset.settlement_fund ); // should be strictly < except for PM with zero outcome
1018 
1019  if( settled_amount.amount == 0 && !bitasset.is_prediction_market )
1020  {
1021  if( d.get_dynamic_global_properties().next_maintenance_time > HARDFORK_CORE_184_TIME )
1022  FC_THROW( "Settle amount is too small to receive anything due to rounding" );
1023  // else do nothing. Before the hf, something for nothing issue (#184, variant F) could occur
1024  }
1025 
1026  asset pays = op.amount;
1027  if( op.amount.amount != mia_dyn.current_supply
1028  && settled_amount.amount != 0
1029  && d.get_dynamic_global_properties().next_maintenance_time > HARDFORK_CORE_342_TIME )
1030  {
1031  pays = settled_amount.multiply_and_round_up( bitasset.settlement_price );
1032  }
1033 
1034  d.adjust_balance( op.account, -pays );
1035 
1036  if( settled_amount.amount > 0 )
1037  {
1038  d.modify( bitasset, [&]( asset_bitasset_data_object& obj ){
1039  obj.settlement_fund -= settled_amount.amount;
1040  });
1041 
1042  // The account who settles pays market fees to the issuer of the collateral asset after HF core-1780
1043  //
1044  // TODO Check whether the HF check can be removed after the HF.
1045  // Note: even if logically it can be removed, perhaps the removal will lead to a small
1046  // performance loss. Needs testing.
1047  if( d.head_block_time() >= HARDFORK_CORE_1780_TIME )
1048  {
1049  auto issuer_fees = d.pay_market_fees( fee_paying_account, settled_amount.asset_id(d),
1050  settled_amount, false );
1051  settled_amount -= issuer_fees;
1052  }
1053 
1054  if( settled_amount.amount > 0 )
1055  d.adjust_balance( op.account, settled_amount );
1056  }
1057 
1058  d.modify( mia_dyn, [&]( asset_dynamic_data_object& obj ){
1059  obj.current_supply -= pays.amount;
1060  });
1061 
1062  return settled_amount;
1063  }
1064  else
1065  {
1066  d.adjust_balance( op.account, -op.amount );
1068  s.owner = op.account;
1069  s.balance = op.amount;
1070  s.settlement_date = d.head_block_time() + asset_to_settle->bitasset_data(d).options.force_settlement_delay_sec;
1071  }).id;
1072  }
1073 } FC_CAPTURE_AND_RETHROW( (op) ) }
1074 
1076 { try {
1077  const database& d = db();
1078  const time_point_sec now = d.head_block_time();
1079 
1080  // TODO remove check after hard fork
1082 
1083  const asset_object& base = o.asset_id(d);
1084  //Verify that this feed is for a market-issued asset and that asset is backed by the base
1085  FC_ASSERT( base.is_market_issued(), "Can only publish price feeds for market-issued assets" );
1086 
1087  const asset_bitasset_data_object& bitasset = base.bitasset_data(d);
1088  if( bitasset.is_prediction_market || now <= HARDFORK_CORE_216_TIME )
1089  {
1090  FC_ASSERT( !bitasset.has_settlement(), "No further feeds may be published after a settlement event" );
1091  }
1092 
1093  // the settlement price must be quoted in terms of the backing asset
1094  FC_ASSERT( o.feed.settlement_price.quote.asset_id == bitasset.options.short_backing_asset,
1095  "Quote asset type in settlement price should be same as backing asset of this asset" );
1096 
1097  if( now > HARDFORK_480_TIME )
1098  {
1099  if( !o.feed.core_exchange_rate.is_null() )
1100  {
1101  FC_ASSERT( o.feed.core_exchange_rate.quote.asset_id == asset_id_type(),
1102  "Quote asset in core exchange rate should be CORE asset" );
1103  }
1104  }
1105  else
1106  {
1108  {
1109  // Old buggy code, but we have to live with it
1111  }
1112  }
1113 
1114  //Verify that the publisher is authoritative to publish a feed
1115  if( base.options.flags & witness_fed_asset )
1116  {
1117  FC_ASSERT( d.get(GRAPHENE_WITNESS_ACCOUNT).active.account_auths.count(o.publisher),
1118  "Only active witnesses are allowed to publish price feeds for this asset" );
1119  }
1120  else if( base.options.flags & committee_fed_asset )
1121  {
1122  FC_ASSERT( d.get(GRAPHENE_COMMITTEE_ACCOUNT).active.account_auths.count(o.publisher),
1123  "Only active committee members are allowed to publish price feeds for this asset" );
1124  }
1125  else
1126  {
1127  FC_ASSERT( bitasset.feeds.count(o.publisher),
1128  "The account is not in the set of allowed price feed producers of this asset" );
1129  }
1130 
1131  asset_ptr = &base;
1132  bitasset_ptr = &bitasset;
1133 
1134  return void_result();
1135 } FC_CAPTURE_AND_RETHROW((o)) }
1136 
1138 { try {
1139 
1140  database& d = db();
1141  const auto head_time = d.head_block_time();
1142  const auto next_maint_time = d.get_dynamic_global_properties().next_maintenance_time;
1143 
1144  const asset_object& base = *asset_ptr;
1145  const asset_bitasset_data_object& bad = *bitasset_ptr;
1146 
1147  auto old_feed = bad.current_feed;
1148  // Store medians for this asset
1149  d.modify( bad , [&o,head_time,next_maint_time](asset_bitasset_data_object& a) {
1150  a.feeds[o.publisher] = make_pair( head_time, price_feed_with_icr( o.feed,
1151  o.extensions.value.initial_collateral_ratio ) );
1152  a.update_median_feeds( head_time, next_maint_time );
1153  });
1154 
1155  if( !old_feed.margin_call_params_equal(bad.current_feed) )
1156  {
1157  // Check whether need to revive the asset and proceed if need
1158  if( bad.has_settlement() // has globally settled, implies head_block_time > HARDFORK_CORE_216_TIME
1159  && !bad.current_feed.settlement_price.is_null() ) // has a valid feed
1160  {
1161  bool should_revive = false;
1162  const auto& mia_dyn = base.dynamic_asset_data_id(d);
1163  if( mia_dyn.current_supply == 0 ) // if current supply is zero, revive the asset
1164  should_revive = true;
1165  else // if current supply is not zero, when collateral ratio of settlement fund is greater than MCR, revive the asset
1166  {
1167  if( next_maint_time <= HARDFORK_CORE_1270_TIME )
1168  {
1169  // before core-1270 hard fork, calculate call_price and compare to median feed
1170  if( ~price::call_price( asset(mia_dyn.current_supply, o.asset_id),
1173  should_revive = true;
1174  }
1175  else
1176  {
1177  // after core-1270 hard fork, calculate collateralization and compare to maintenance_collateralization
1179  asset( mia_dyn.current_supply, o.asset_id ) ) > bad.current_maintenance_collateralization )
1180  should_revive = true;
1181  }
1182  }
1183  if( should_revive )
1184  d.revive_bitasset(base);
1185  }
1186  // Process margin calls, allow black swan, not for a new limit order
1187  d.check_call_orders( base, true, false, bitasset_ptr );
1188  }
1189 
1190  return void_result();
1191 } FC_CAPTURE_AND_RETHROW((o)) }
1192 
1193 
1194 /***
1195  * @brief evaluator for asset_claim_fees operation
1196  *
1197  * Checks that we are able to claim fees denominated in asset Y (the amount_to_claim asset),
1198  * from some container asset X which is presumed to have accumulated the fees we wish to claim.
1199  * The container asset is either explicitly named in the extensions, or else assumed as the same
1200  * asset as the amount_to_claim asset. Evaluation fails if either (a) operation issuer is not
1201  * the same as the container_asset issuer, or (b) container_asset has no fee bucket for
1202  * amount_to_claim asset, or (c) accumulated fees are insufficient to cover amount claimed.
1203  */
1205 { try {
1206  const database& d = db();
1207 
1209 
1210  container_asset = o.extensions.value.claim_from_asset_id.valid() ?
1211  &(*o.extensions.value.claim_from_asset_id)(d) : &o.amount_to_claim.asset_id(d);
1212 
1213  FC_ASSERT( container_asset->issuer == o.issuer, "Asset fees may only be claimed by the issuer" );
1214  FC_ASSERT( container_asset->can_accumulate_fee(d,o.amount_to_claim),
1215  "Asset ${a} (${id}) is not backed by asset (${fid}) and does not hold it as fees.",
1216  ("a",container_asset->symbol)("id",container_asset->id)("fid",o.amount_to_claim.asset_id) );
1217 
1218  container_ddo = &container_asset->dynamic_asset_data_id(d);
1219 
1220  if (container_asset->get_id() == o.amount_to_claim.asset_id) {
1221  FC_ASSERT( o.amount_to_claim.amount <= container_ddo->accumulated_fees,
1222  "Attempt to claim more fees than have accumulated within asset ${a} (${id}). "
1223  "Asset DDO: ${ddo}. Fee claim: ${claim}.", ("a",container_asset->symbol)
1224  ("id",container_asset->id)("ddo",*container_ddo)("claim",o.amount_to_claim) );
1225  } else {
1226  FC_ASSERT( o.amount_to_claim.amount <= container_ddo->accumulated_collateral_fees,
1227  "Attempt to claim more backing-asset fees than have accumulated within asset ${a} (${id}) "
1228  "backed by (${fid}). Asset DDO: ${ddo}. Fee claim: ${claim}.", ("a",container_asset->symbol)
1229  ("id",container_asset->id)("fid",o.amount_to_claim.asset_id)("ddo",*container_ddo)
1230  ("claim",o.amount_to_claim) );
1231  }
1232 
1233  return void_result();
1234 } FC_CAPTURE_AND_RETHROW( (o) ) }
1235 
1236 
1237 /***
1238  * @brief apply asset_claim_fees operation
1239  */
1241 { try {
1242  database& d = db();
1243 
1244  if ( container_asset->get_id() == o.amount_to_claim.asset_id ) {
1245  d.modify( *container_ddo, [&o]( asset_dynamic_data_object& _addo ) {
1247  });
1248  } else {
1249  d.modify( *container_ddo, [&o]( asset_dynamic_data_object& _addo ) {
1251  });
1252  }
1253 
1255 
1256  return void_result();
1257 } FC_CAPTURE_AND_RETHROW( (o) ) }
1258 
1259 
1261 { try {
1262  FC_ASSERT( o.asset_id(db()).issuer == o.issuer, "Asset fee pool may only be claimed by the issuer" );
1263 
1264  return void_result();
1265 } FC_CAPTURE_AND_RETHROW( (o) ) }
1266 
1268 { try {
1269  database& d = db();
1270 
1271  const asset_object& a = o.asset_id(d);
1273  FC_ASSERT( o.amount_to_claim.amount <= addo.fee_pool, "Attempt to claim more fees than is available", ("addo",addo) );
1274 
1275  d.modify( addo, [&o]( asset_dynamic_data_object& _addo ) {
1276  _addo.fee_pool -= o.amount_to_claim.amount;
1277  });
1278 
1280 
1281  return void_result();
1282 } FC_CAPTURE_AND_RETHROW( (o) ) }
1283 
1284 
1285 } } // graphene::chain
uint8_t maximum_asset_feed_publishers
the maximum number of feed publishers for a given asset
asset_id_type asset_id
asset for which the feed is published
Definition: asset_ops.hpp:427
account_id_type issuer
must match issuer of asset from which we claim fees
Definition: asset_ops.hpp:499
uint32_t force_settlement_delay_sec
This is the delay between the time a long requests settlement and the chain evaluates the settlement...
Definition: asset_ops.hpp:130
asset_id_type asset_id
The asset this object belong to.
void modify(const T &obj, const Lambda &m)
Update the set of feed-producing accounts for a BitAssetBitAssets have price feeds selected by taking...
Definition: asset_ops.hpp:384
flat_set< account_id_type > blacklist_authorities
Definition: asset_ops.hpp:81
void check_asset_options_hf_bsip81(const fc::time_point_sec &block_time, const asset_options &options)
void adjust_balance(account_id_type account, asset delta)
Adjust a particular account&#39;s balance in a given asset by a delta.
Definition: db_balance.cpp:54
void check_bitasset_options_hf_bsip74(const fc::time_point_sec &block_time, const bitasset_options &options)
contains properties that only apply to bitassets (market issued assets)
void check_bitasset_options_hf_bsip87(const fc::time_point_sec &block_time, const bitasset_options &options)
bool is_authorized_asset(const database &d, const account_object &acct, const asset_object &asset_obj)
extension< additional_options_type > extensions
Definition: asset_ops.hpp:502
const object * find_object(object_id_type id) const
tracks the blockchain state in an extensible manner
Definition: database.hpp:70
void_result do_evaluate(const asset_update_issuer_operation &o)
asset amount
Amount of asset to force settle. This must be a market-issued asset.
Definition: asset_ops.hpp:242
Definition: api.cpp:56
The asset_options struct contains options available on all assets in the network. ...
Definition: asset_ops.hpp:47
used to transfer accumulated fees back to the issuer&#39;s balance.
Definition: asset_ops.hpp:482
asset pay_market_fees(const account_object *seller, const asset_object &recv_asset, const asset &receives, const bool &is_maker)
Definition: db_market.cpp:1376
void check_bitasset_options_hf_bsip_48_75(const fc::time_point_sec &block_time, const bitasset_options &options)
tracks debt and call price information
asset get_balance(account_id_type owner, asset_id_type asset_id) const
Retrieve a particular account&#39;s balance in a given asset.
Definition: db_balance.cpp:35
bool is_prediction_market
For BitAssets, set this to true if the asset implements a Prediction Market; false otherwise...
Definition: asset_ops.hpp:181
void globally_settle_asset(const asset_object &bitasset, const price &settle_price)
Market Helpers
Definition: db_market.cpp:57
Schedules a market-issued asset for automatic settlementHolders of market-issued assests may request ...
Definition: asset_ops.hpp:226
const dynamic_global_property_object & get_dynamic_global_properties() const
Definition: db_getter.cpp:54
bool valid() const
Definition: optional.hpp:186
void_result do_evaluate(const asset_update_bitasset_operation &o)
void_result do_apply(const asset_publish_feed_operation &o)
#define FC_THROW(...)
Definition: exception.hpp:366
defines market parameters for margin positions, extended with an initial_collateral_ratio field ...
void check_asset_publish_feed_extensions_hf_bsip77(const fc::time_point_sec &block_time, const asset_publish_feed_operation::ext &extensions)
object_id_type do_apply(const asset_create_operation &o)
uint8_t maximum_asset_whitelist_authorities
maximum number of accounts which an asset may list as authorities for its whitelist OR blacklist ...
account_id_type issuer
ID of the account which issued this asset.
void_result do_evaluate(const asset_reserve_operation &o)
Publish price feeds for market-issued assetsPrice feed providers use this operation to publish their ...
Definition: asset_ops.hpp:415
fc::optional< uint16_t > initial_collateral_ratio
After BSIP77, price feed producers can feed ICR too.
Definition: asset_ops.hpp:420
uint8_t precision
Number of digits to the right of decimal point, must be less than or equal to 12. ...
Definition: asset_ops.hpp:169
bool is_null() const
Definition: asset.cpp:225
share_type accumulated_collateral_fees
accumulated collateral-denominated fees (for bitassets)
const global_property_object & get_global_properties() const
Definition: db_getter.cpp:44
void_result do_apply(const asset_update_issuer_operation &o)
const T & get(object_id_type id) const
price min() const
Definition: asset.hpp:131
void_result do_evaluate(const asset_issue_operation &o)
void cancel_settle_order(const force_settlement_object &order, bool create_virtual_op=true)
Definition: db_market.cpp:223
string symbol
The ticker symbol of this asset.
Definition: asset_ops.hpp:167
void update_median_feeds(time_point_sec current_time, time_point_sec next_maintenance_time)
bool is_prediction_market
True if this asset implements a Prediction Market.
fc::optional< uint16_t > reward_percent
Definition: asset_ops.hpp:33
used to take an asset out of circulation, returning to the issuer
Definition: asset_ops.hpp:466
void_result do_apply(const asset_claim_pool_operation &o)
object_id_type id
Definition: object.hpp:73
uint16_t maintenance_collateral_ratio
Definition: asset.hpp:190
The price struct stores asset prices in the BitShares system.
Definition: asset.hpp:114
#define GRAPHENE_100_PERCENT
Definition: config.hpp:102
operation_result do_apply(const operation_type &op)
uint16_t get_enabled_issuer_permissions_mask() const
Definition: asset_ops.cpp:319
void_result do_apply(const asset_claim_fees_operation &o)
time_point_sec head_block_time() const
Definition: db_getter.cpp:64
uint8_t minimum_feeds
Minimum number of unexpired feeds required to extract a median feed from.
Definition: asset_ops.hpp:128
#define GRAPHENE_COMMITTEE_ACCOUNT
Definition: config.hpp:125
uint16_t issuer_permissions
The flags which the issuer has permission to update. See asset_issuer_permission_flags.
Definition: asset_ops.hpp:61
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...
string symbol
Ticker symbol for this asset, i.e. "USD".
tracks bitassets scheduled for force settlement at some point in the future.
#define FC_CAPTURE_AND_RETHROW(...)
Definition: exception.hpp:478
Update options specific to BitAssetsBitAssets have some options which are not relevant to other asset...
Definition: asset_ops.hpp:353
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
account_id_type account
Account requesting the force settlement. This account pays the fee.
Definition: asset_ops.hpp:240
void_result do_apply(const asset_update_operation &o)
tracks the asset information that changes frequentlyBecause the asset_object is very large it doesn&#39;t...
uint32_t feed_lifetime_sec
Time before a price feed expires.
Definition: asset_ops.hpp:126
account_id_type issuer
Must be asset_to_issue->asset_id->issuer.
Definition: asset_ops.hpp:446
#define FC_THROW_EXCEPTION(EXCEPTION, FORMAT,...)
Definition: exception.hpp:378
Update options common to all assetsThere are a number of options which all assets in the network use...
Definition: asset_ops.hpp:307
void_result do_evaluate(const asset_claim_pool_operation &o)
void_result do_evaluate(const operation_type &op)
account_id_type issuer
This account must sign and pay the fee for this operation. Later, this account may update the asset...
Definition: asset_ops.hpp:165
Transfers BTS from the fee pool of a specified asset back to the issuer&#39;s balance.
Definition: asset_ops.hpp:554
void_result do_evaluate(const asset_update_operation &o)
void_result do_evaluate(const operation_type &op)
void_result do_evaluate(const asset_create_operation &o)
void check_asset_update_extensions_hf_bsip_48_75(const fc::time_point_sec &block_time, const asset_update_operation::ext &extensions)
void check_asset_claim_fees_hardfork_87_74_collatfee(const fc::time_point_sec &block_time, const asset_claim_fees_operation &op)
share_type accumulated_fees
fees accumulate to be paid out over time
const asset_dynamic_data_object & get_core_dynamic_data() const
Definition: db_getter.cpp:39
void check_bitasset_options_hf_bsip77(const fc::time_point_sec &block_time, const bitasset_options &options)
tracks the parameters of an assetAll assets have a globally unique symbol name that controls how they...
uint8_t precision
Maximum number of digits after the decimal point (must be <= 12)
void check_asset_options_hf_bsip_48_75(const fc::time_point_sec &block_time, const asset_options &options)
the bitasset is to be fed by witnesses
Definition: types.hpp:147
const object & get(object_id_type id) const
Definition: index.hpp:111
asset_id_type asset_id
Definition: asset.hpp:39
void_result do_apply(const asset_issue_operation &o)
allow the bitasset owner to force a global settling, permission only
Definition: types.hpp:145
optional< bitasset_options > bitasset_opts
Definition: asset_ops.hpp:179
bitasset_options options
The tunable options for BitAssets are stored in this field.
void validate_flags(bool is_market_issued) const
Definition: asset_ops.cpp:301
void_result do_evaluate(const asset_claim_fees_operation &o)
asset amount_to_claim
fee.asset_id must != asset_id
Definition: asset_ops.hpp:563
void_result do_apply(const asset_reserve_operation &o)
fc::optional< uint16_t > taker_fee_percent
Definition: asset_ops.hpp:36
asset_id_type get_id() const
uint16_t flags
The currently active flags on this permission. See asset_issuer_permission_flags. ...
Definition: asset_ops.hpp:63
void_result do_apply(const asset_update_bitasset_operation &o)
flat_set< account_id_type > whitelist_authorities
Definition: asset_ops.hpp:76
void revive_bitasset(const asset_object &bitasset)
Definition: db_market.cpp:129
void_result do_evaluate(const asset_publish_feed_operation &o)
#define GRAPHENE_ASSERT(expr, exc_type, FORMAT,...)
Definition: exceptions.hpp:28
void_result do_apply(const operation_type &op)
Update issuer of an assetAn issuer has general administrative power of an asset and in some cases als...
Definition: asset_ops.hpp:518
void check_children_of_bitasset(const database &d, const asset_update_bitasset_operation &op, const asset_object &new_backing_asset)
void_result do_evaluate(const operation_type &o)
share_type current_supply
The number of shares currently in existence.
flat_map< account_id_type, pair< time_point_sec, price_feed_with_icr > > feeds
void check_asset_options_hf_1774(const fc::time_point_sec &block_time, const asset_options &options)
void_result do_evaluate(const asset_fund_fee_pool_operation &op)
void for_each(T &&t, const account_object &a, seq< Is... >)
Definition: database.hpp:700
bool asset_cer_updated
Track whether core_exchange_rate in corresponding asset_object has updated.
additional_asset_options_t extensions
Definition: asset_ops.hpp:93
static price call_price(const asset &debt, const asset &collateral, uint16_t collateral_ratio)
Definition: asset.cpp:212
const asset_bitasset_data_object & bitasset_data(const DB &db) const
const T & create(F &&constructor)
share_type settlement_fund
Amount of collateral which is available for force settlement.
uint8_t block_interval
interval in seconds between blocks
account_id_type issuer
must equal asset_to_settle->issuer
Definition: asset_ops.hpp:204
The bitasset_options struct contains configurable options available only to BitAssets.
Definition: asset_ops.hpp:109
const object & get_object(object_id_type id) const
const IndexType & get_index_type() const
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)
Definition: db_market.cpp:1100
allows global settling of bitassets (black swan or prediction markets)
Definition: asset_ops.hpp:199
#define GRAPHENE_WITNESS_ACCOUNT
Represents the current witnesses.
Definition: config.hpp:127
optional< account_id_type > new_issuer
If the asset is to be given a new issuer, specify his ID here.
Definition: asset_ops.hpp:331
void_result do_apply(const asset_fund_fee_pool_operation &op)
asset multiply_and_round_up(const price &p) const
Multiply and round up.
Definition: asset.cpp:78
price core_exchange_rate
Price at which automatically exchanging this asset for CORE from fee pool occurs (used for paying fee...
Definition: asset.hpp:187