text: /*
   * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
   *
   * 1. Any modified source or binaries are used only with the BitShares network.
   *
   * 2. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
   *
   * 3. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   */
  #pragma once
  #include <graphene/chain/protocol/config.hpp>
  #include <graphene/chain/protocol/types.hpp>
  
  namespace graphene { namespace chain {
  
     extern const int64_t scaled_precision_lut[];
  
     struct asset
     {
        asset( share_type a = 0, asset_id_type id = asset_id_type() )
        :amount(a),asset_id(id){}
  
        share_type    amount;
        asset_id_type asset_id;
  
        asset& operator += ( const asset& o )
        {
           FC_ASSERT( asset_id == o.asset_id );
           amount += o.amount;
           return *this;
        }
        asset& operator -= ( const asset& o )
        {
           FC_ASSERT( asset_id == o.asset_id );
           amount -= o.amount;
           return *this;
        }
        asset operator -()const { return asset( -amount, asset_id ); }
  
        friend bool operator == ( const asset& a, const asset& b )
        {
           return std::tie( a.asset_id, a.amount ) == std::tie( b.asset_id, b.amount );
        }
        friend bool operator < ( const asset& a, const asset& b )
        {
           FC_ASSERT( a.asset_id == b.asset_id );
           return a.amount < b.amount;
        }
        friend bool operator <= ( const asset& a, const asset& b )
        {
           return (a == b) || (a < b);
        }
  
        friend bool operator != ( const asset& a, const asset& b )
        {
           return !(a == b);
        }
        friend bool operator > ( const asset& a, const asset& b )
        {
           return !(a <= b);
        }
        friend bool operator >= ( const asset& a, const asset& b )
        {
           return !(a < b);
        }
  
        friend asset operator - ( const asset& a, const asset& b )
        {
           FC_ASSERT( a.asset_id == b.asset_id );
           return asset( a.amount - b.amount, a.asset_id );
        }
        friend asset operator + ( const asset& a, const asset& b )
        {
           FC_ASSERT( a.asset_id == b.asset_id );
           return asset( a.amount + b.amount, a.asset_id );
        }
  
        static share_type scaled_precision( uint8_t precision )
        {
           FC_ASSERT( precision < 19 );
           return scaled_precision_lut[ precision ];
        }
     };
  
     /**
      * @brief The price struct stores asset prices in the Graphene system.
      *
      * A price is defined as a ratio between two assets, and represents a possible exchange rate between those two
      * assets. prices are generally not stored in any simplified form, i.e. a price of (1000 CORE)/(20 USD) is perfectly
      * normal.
      *
      * The assets within a price are labeled base and quote. Throughout the Graphene code base, the convention used is
      * that the base asset is the asset being sold, and the quote asset is the asset being purchased, where the price is
      * represented as base/quote, so in the example price above the seller is looking to sell CORE asset and get USD in
      * return.
      */
     struct price
     {
        price(const asset& base = asset(), const asset quote = asset())
           : base(base),quote(quote){}
  
        asset base;
        asset quote;
  
        static price max(asset_id_type base, asset_id_type quote );
        static price min(asset_id_type base, asset_id_type quote );
  
        static price call_price(const asset& debt, const asset& collateral, uint16_t collateral_ratio);
  
        /// The unit price for an asset type A is defined to be a price such that for any asset m, m*A=m
        static price unit_price(asset_id_type a = asset_id_type()) { return price(asset(1, a), asset(1, a)); }
  
        price max()const { return price::max( base.asset_id, quote.asset_id ); }
        price min()const { return price::min( base.asset_id, quote.asset_id ); }
  
        double to_real()const { return double(base.amount.value)/double(quote.amount.value); }
  
        bool is_null()const;
        void validate()const;
     };
  
     price operator / ( const asset& base, const asset& quote );
     inline price operator~( const price& p ) { return price{p.quote,p.base}; }
  
     bool  operator <  ( const asset& a, const asset& b );
     bool  operator <= ( const asset& a, const asset& b );
     bool  operator <  ( const price& a, const price& b );
     bool  operator <= ( const price& a, const price& b );
     bool  operator >  ( const price& a, const price& b );
     bool  operator >= ( const price& a, const price& b );
     bool  operator == ( const price& a, const price& b );
     bool  operator != ( const price& a, const price& b );
     asset operator *  ( const asset& a, const price& b );
  
     /**
      *  @class price_feed
      *  @brief defines market parameters for margin positions
      */
     struct price_feed
     {
        /**
         *  Required maintenance collateral is defined
         *  as a fixed point number with a maximum value of 10.000
         *  and a minimum value of 1.000.  (denominated in GRAPHENE_COLLATERAL_RATIO_DENOM)
         *
         *  A black swan event occurs when value_of_collateral equals
         *  value_of_debt, to avoid a black swan a margin call is
         *  executed when value_of_debt * required_maintenance_collateral
         *  equals value_of_collateral using rate.
         *
         *  Default requirement is $1.75 of collateral per $1 of debt
         *
         *  BlackSwan ---> SQR ---> MCR ----> SP
         */
        ///@{
        /**
         * Forced settlements will evaluate using this price, defined as BITASSET / COLLATERAL
         */
        price settlement_price;
  
        /// Price at which automatically exchanging this asset for CORE from fee pool occurs (used for paying fees)
        price core_exchange_rate;
  
        /** Fixed point between 1.000 and 10.000, implied fixed point denominator is GRAPHENE_COLLATERAL_RATIO_DENOM */
        uint16_t maintenance_collateral_ratio = GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO;
  
        /** Fixed point between 1.000 and 10.000, implied fixed point denominator is GRAPHENE_COLLATERAL_RATIO_DENOM */
        uint16_t maximum_short_squeeze_ratio = GRAPHENE_DEFAULT_MAX_SHORT_SQUEEZE_RATIO;
  
        /**
         *  When updating a call order the following condition must be maintained:
         *
         *  debt * maintenance_price() < collateral
         *  debt * settlement_price    < debt * maintenance
         *  debt * maintenance_price() < debt * max_short_squeeze_price()
        price maintenance_price()const;
         */
  
        /** When selling collateral to pay off debt, the least amount of debt to receive should be
         *  min_usd = max_short_squeeze_price() * collateral
         *
         *  This is provided to ensure that a black swan cannot be trigged due to poor liquidity alone, it
         *  must be confirmed by having the max_short_squeeze_price() move below the black swan price.
         */
        price max_short_squeeze_price()const;
        ///@}
  
        friend bool operator == ( const price_feed& a, const price_feed& b )
        {
           return std::tie( a.settlement_price, a.maintenance_collateral_ratio, a.maximum_short_squeeze_ratio ) ==
                  std::tie( b.settlement_price, b.maintenance_collateral_ratio, b.maximum_short_squeeze_ratio );
        }
  
        void validate() const;
        bool is_for( asset_id_type asset_id ) const;
     };
  
  } }
  
  FC_REFLECT( graphene::chain::asset, (amount)(asset_id) )
  FC_REFLECT( graphene::chain::price, (base)(quote) )
  
  #define GRAPHENE_PRICE_FEED_FIELDS (settlement_price)(maintenance_collateral_ratio)(maximum_short_squeeze_ratio) \
     (core_exchange_rate)
  
  FC_REFLECT( graphene::chain::price_feed, GRAPHENE_PRICE_FEED_FIELDS )
  