Example #1
0
asset database::calculate_market_fee( const asset_object& trade_asset, const asset& trade_amount )
{
   assert( trade_asset.id == trade_amount.asset_id );

   if( !trade_asset.charges_market_fees() )
      return trade_asset.amount(0);
   if( trade_asset.options.market_fee_percent == 0 )
      return trade_asset.amount(0);

   fc::uint128 a(trade_amount.amount.value);
   a *= trade_asset.options.market_fee_percent;
   a /= GRAPHENE_100_PERCENT;
   asset percent_fee = trade_asset.amount(a.to_uint64());

   if( percent_fee.amount > trade_asset.options.max_market_fee )
      percent_fee.amount = trade_asset.options.max_market_fee;

   return percent_fee;
}
Example #2
0
asset database::pay_market_fees( const asset_object& recv_asset, const asset& receives )
{
   auto issuer_fees = calculate_market_fee( recv_asset, receives );
   assert(issuer_fees <= receives );

   //Don't dirty undo state if not actually collecting any fees
   if( issuer_fees.amount > 0 )
   {
      const auto& recv_dyn_data = recv_asset.dynamic_asset_data_id(*this);
      modify( recv_dyn_data, [&]( asset_dynamic_data_object& obj ){
                   //idump((issuer_fees));
         obj.accumulated_fees += issuer_fees.amount;
      });
   }

   return issuer_fees;
}
Example #3
0
int64_t database_fixture::get_balance( const account_object& account, const asset_object& a )const
{
  return db.get_balance(account.get_id(), a.get_id()).amount.value;
}
Example #4
0
/**
 *  Starting with the least collateralized orders, fill them if their
 *  call price is above the max(lowest bid,call_limit).
 *
 *  This method will return true if it filled a short or limit
 *
 *  @param mia - the market issued asset that should be called.
 *  @param enable_black_swan - when adjusting collateral, triggering a black swan is invalid and will throw
 *                             if enable_black_swan is not set to true.
 *
 *  @return true if a margin call was executed.
 */
bool database::check_call_orders(const asset_object& mia, bool enable_black_swan)
{ try {
    if( !mia.is_market_issued() ) return false;

    if( check_for_blackswan( mia, enable_black_swan ) ) 
       return false;

    const asset_bitasset_data_object& bitasset = mia.bitasset_data(*this);
    if( bitasset.is_prediction_market ) return false;
    if( bitasset.current_feed.settlement_price.is_null() ) return false;

    const call_order_index& call_index = get_index_type<call_order_index>();
    const auto& call_price_index = call_index.indices().get<by_price>();

    const limit_order_index& limit_index = get_index_type<limit_order_index>();
    const auto& limit_price_index = limit_index.indices().get<by_price>();

    // looking for limit orders selling the most USD for the least CORE
    auto max_price = price::max( mia.id, bitasset.options.short_backing_asset );
    // stop when limit orders are selling too little USD for too much CORE
    auto min_price = bitasset.current_feed.max_short_squeeze_price();

    assert( max_price.base.asset_id == min_price.base.asset_id );
    // NOTE limit_price_index is sorted from greatest to least
    auto limit_itr = limit_price_index.lower_bound( max_price );
    auto limit_end = limit_price_index.upper_bound( min_price );

    if( limit_itr == limit_end )
       return false;

    auto call_min = price::min( bitasset.options.short_backing_asset, mia.id );
    auto call_max = price::max( bitasset.options.short_backing_asset, mia.id );
    auto call_itr = call_price_index.lower_bound( call_min );
    auto call_end = call_price_index.upper_bound( call_max );

    bool filled_limit = false;
    bool margin_called = false;

    while( !check_for_blackswan( mia, enable_black_swan ) && call_itr != call_end )
    {
       bool  filled_call      = false;
       price match_price;
       asset usd_for_sale;
       if( limit_itr != limit_end )
       {
          assert( limit_itr != limit_price_index.end() );
          match_price      = limit_itr->sell_price;
          usd_for_sale     = limit_itr->amount_for_sale();
       }
       else return margin_called;

       match_price.validate();

       // would be margin called, but there is no matching order #436
       bool feed_protected = ( bitasset.current_feed.settlement_price > ~call_itr->call_price );
       if( feed_protected && (head_block_time() > HARDFORK_436_TIME) )
          return margin_called;

       // would be margin called, but there is no matching order
       if( match_price > ~call_itr->call_price )
          return margin_called;

       if( feed_protected )
       {
          ilog( "Feed protected margin call executing (HARDFORK_436_TIME not here yet)" );
          idump( (*call_itr) );
          idump( (*limit_itr) );
       }

     //  idump((*call_itr));
     //  idump((*limit_itr));

     //  ilog( "match_price <= ~call_itr->call_price  performing a margin call" );

       margin_called = true;

       auto usd_to_buy   = call_itr->get_debt();

       if( usd_to_buy * match_price > call_itr->get_collateral() )
       {
          elog( "black swan detected" ); 
          edump((enable_black_swan));
          FC_ASSERT( enable_black_swan );
          globally_settle_asset(mia, bitasset.current_feed.settlement_price );
          return true;
       }

       asset call_pays, call_receives, order_pays, order_receives;
       if( usd_to_buy >= usd_for_sale )
       {  // fill order
          call_receives   = usd_for_sale;
          order_receives  = usd_for_sale * match_price;
          call_pays       = order_receives;
          order_pays      = usd_for_sale;

          filled_limit = true;
          filled_call           = (usd_to_buy == usd_for_sale);
       } else { // fill call
          call_receives  = usd_to_buy;
          order_receives = usd_to_buy * match_price;
          call_pays      = order_receives;
          order_pays     = usd_to_buy;

          filled_call    = true;
       }

       FC_ASSERT( filled_call || filled_limit );

       auto old_call_itr = call_itr;
       if( filled_call ) ++call_itr;
       fill_order(*old_call_itr, call_pays, call_receives);

       auto old_limit_itr = filled_limit ? limit_itr++ : limit_itr;
       fill_order(*old_limit_itr, order_pays, order_receives, true);

    } // whlie call_itr != call_end

    return margin_called;
} FC_CAPTURE_AND_RETHROW() }
Example #5
0
/**
 *  Starting with the least collateralized orders, fill them if their
 *  call price is above the max(lowest bid,call_limit).
 *
 *  This method will return true if it filled a short or limit
 *
 *  @param mia - the market issued asset that should be called.
 *  @param enable_black_swan - when adjusting collateral, triggering a black swan is invalid and will throw
 *                             if enable_black_swan is not set to true.
 *
 *  @return true if a margin call was executed.
 */
bool database::check_call_orders(const asset_object& mia, bool enable_black_swan)
{ try {
    if( !mia.is_market_issued() ) return false;
    const asset_bitasset_data_object& bitasset = mia.bitasset_data(*this);
    if( bitasset.is_prediction_market ) return false;
    if( bitasset.current_feed.settlement_price.is_null() ) return false;

    const call_order_index& call_index = get_index_type<call_order_index>();
    const auto& call_price_index = call_index.indices().get<by_price>();

    const limit_order_index& limit_index = get_index_type<limit_order_index>();
    const auto& limit_price_index = limit_index.indices().get<by_price>();

    // looking for limit orders selling the most USD for the least CORE
    auto max_price = price::max( mia.id, bitasset.options.short_backing_asset );
    // stop when limit orders are selling too little USD for too much CORE
    auto min_price = bitasset.current_feed.max_short_squeeze_price();

    assert( max_price.base.asset_id == min_price.base.asset_id );
    // NOTE limit_price_index is sorted from greatest to least
    auto limit_itr = limit_price_index.lower_bound( max_price );
    auto limit_end = limit_price_index.upper_bound( min_price );

    if( limit_itr == limit_end ) {
       return false;
    }

    auto call_itr = call_price_index.lower_bound( price::min( bitasset.options.short_backing_asset, mia.id ) );
    auto call_end = call_price_index.upper_bound( price::max( bitasset.options.short_backing_asset, mia.id ) );

    bool filled_limit = false;

    while( call_itr != call_end )
    {
       bool  filled_call      = false;
       price match_price;
       asset usd_for_sale;
       if( limit_itr != limit_end )
       {
          assert( limit_itr != limit_price_index.end() );
          match_price      = limit_itr->sell_price;
          usd_for_sale     = limit_itr->amount_for_sale();
       }
       else return filled_limit;

       match_price.validate();

       if( match_price > ~call_itr->call_price )
       {
          return filled_limit;
       }

       auto usd_to_buy   = call_itr->get_debt();

       if( usd_to_buy * match_price > call_itr->get_collateral() )
       {
          FC_ASSERT( enable_black_swan );
          //globally_settle_asset(mia, call_itr->get_debt() / call_itr->get_collateral());
          globally_settle_asset(mia, bitasset.current_feed.settlement_price );// call_itr->get_debt() / call_itr->get_collateral());
          return true;
       }

       asset call_pays, call_receives, order_pays, order_receives;
       if( usd_to_buy >= usd_for_sale )
       {  // fill order
          call_receives   = usd_for_sale;
          order_receives  = usd_for_sale * match_price;
          call_pays       = order_receives;
          order_pays      = usd_for_sale;

          filled_limit = true;
          filled_call           = (usd_to_buy == usd_for_sale);
       } else { // fill call
          call_receives  = usd_to_buy;
          order_receives = usd_to_buy * match_price;
          call_pays      = order_receives;
          order_pays     = usd_to_buy;

          filled_call    = true;
       }

       auto old_call_itr = call_itr;
       if( filled_call ) ++call_itr;
       fill_order(*old_call_itr, call_pays, call_receives);

       auto old_limit_itr = filled_limit ? limit_itr++ : limit_itr;
       fill_order(*old_limit_itr, order_pays, order_receives);
    } // whlie call_itr != call_end

    return filled_limit;
} FC_CAPTURE_AND_RETHROW() }