BitShares-Core  7.0.2
BitShares blockchain node software and command-line wallet software
util.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 Abit More, 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  */
24 
25 #include <boost/multiprecision/cpp_int.hpp>
26 
27 #include <graphene/app/util.hpp>
30 
31 namespace graphene { namespace app {
32 
33 using boost::multiprecision::uint256_t;
34 
35 static fc::uint128_t to_capped_128( const uint256_t& t )
36 {
37  if( t >= std::numeric_limits<fc::uint128_t>::max() )
38  return std::numeric_limits<fc::uint128_t>::max();
39  return static_cast<fc::uint128_t>(t);
40 }
41 
42 std::string uint128_amount_to_string( const fc::uint128_t& amount, const uint8_t precision )
43 { try {
44  std::string s = fc::variant( amount, 2 ).as_string();
45  if( precision == 0 || amount == fc::uint128_t() )
46  return s;
47 
48  std::stringstream ss;
49  uint8_t pos = s.find_last_not_of( '0' ); // should be >= 0
50  uint8_t len = s.size();
51  if( len > precision )
52  {
53  uint8_t left_len = len - precision;
54  ss << s.substr( 0, left_len );
55  if( pos >= left_len )
56  ss << '.' << s.substr( left_len, pos - left_len + 1 );
57  }
58  else
59  {
60  ss << "0.";
61  for( uint8_t i = precision - len; i > 0; --i )
62  ss << '0';
63  ss << s.substr( 0, pos + 1 );
64  }
65  return ss.str();
66 } FC_CAPTURE_AND_RETHROW( (amount)(precision) ) }
67 
68 std::string price_to_string( const graphene::protocol::price& _price,
69  const uint8_t base_precision,
70  const uint8_t quote_precision )
71 { try {
72  if( _price.base.amount == 0 )
73  return "0";
74  FC_ASSERT( _price.base.amount >= 0 );
75  FC_ASSERT( _price.quote.amount >= 0 );
76  FC_ASSERT( base_precision <= 19 );
77  FC_ASSERT( quote_precision <= 19 );
78  graphene::protocol::price new_price = _price;
79  if( new_price.quote.amount == 0 )
80  {
81  new_price.base.amount = std::numeric_limits<int64_t>::max();
82  new_price.quote.amount = 1;
83  }
84 
85  // times (10**19) so won't overflow but have good accuracy
86  fc::uint128_t price128 = fc::uint128_t( new_price.base.amount.value ) * uint64_t(10000000000000000000ULL)
87  / new_price.quote.amount.value;
88 
89  return uint128_amount_to_string( price128, 19 + base_precision - quote_precision );
90 } FC_CAPTURE_AND_RETHROW( (_price)(base_precision)(quote_precision) ) }
91 
92 std::string price_to_string( const graphene::protocol::price& _price,
93  const graphene::chain::asset_object& _base,
94  const graphene::chain::asset_object& _quote )
95 { try {
96  if( _price.base.asset_id == _base.id && _price.quote.asset_id == _quote.id )
97  return price_to_string( _price, _base.precision, _quote.precision );
98  else if( _price.base.asset_id == _quote.id && _price.quote.asset_id == _base.id )
99  return price_to_string( ~_price, _base.precision, _quote.precision );
100  else
101  FC_ASSERT( !"bad parameters" );
102 } FC_CAPTURE_AND_RETHROW( (_price)(_base)(_quote) ) }
103 
105  const graphene::protocol::price& new_price )
106 { try {
107  FC_ASSERT( old_price.base.asset_id == new_price.base.asset_id );
108  FC_ASSERT( old_price.quote.asset_id == new_price.quote.asset_id );
109  FC_ASSERT( old_price.base.amount >= 0 );
110  FC_ASSERT( old_price.quote.amount >= 0 );
111  FC_ASSERT( new_price.base.amount >= 0 );
112  FC_ASSERT( new_price.quote.amount >= 0 );
113  graphene::protocol::price old_price1 = old_price;
114  if( old_price.base.amount == 0 )
115  {
116  old_price1.base.amount = 1;
117  old_price1.quote.amount = std::numeric_limits<int64_t>::max();
118  }
119  else if( old_price.quote.amount == 0 )
120  {
121  old_price1.base.amount = std::numeric_limits<int64_t>::max();
122  old_price1.quote.amount = 1;
123  }
124  graphene::protocol::price new_price1 = new_price;
125  if( new_price.base.amount == 0 )
126  {
127  new_price1.base.amount = 1;
128  new_price1.quote.amount = std::numeric_limits<int64_t>::max();
129  }
130  else if( new_price.quote.amount == 0 )
131  {
132  new_price1.base.amount = std::numeric_limits<int64_t>::max();
133  new_price1.quote.amount = 1;
134  }
135 
136  // change = new/old - 1 = (new_base/new_quote)/(old_base/old_quote) - 1
137  // = (new_base * old_quote) / (new_quote * old_base) - 1
138  // = (new_base * old_quote - new_quote * old_base) / (new_quote * old_base)
139  uint256_t new256 = uint256_t( new_price1.base.amount.value ) * old_price1.quote.amount.value;
140  uint256_t old256 = uint256_t( old_price1.base.amount.value ) * new_price1.quote.amount.value;
141  bool non_negative = (new256 >= old256);
142  uint256_t diff256;
143  if( non_negative )
144  diff256 = new256 - old256;
145  else
146  diff256 = old256 - new256;
147  diff256 = diff256 * 10000 / old256;
148  std::string diff_str = uint128_amount_to_string( to_capped_128(diff256), 2 ); // at most 2 decimal digits
149  if( non_negative || diff_str == "0" )
150  return diff_str;
151  else
152  return "-" + diff_str;
153 } FC_CAPTURE_AND_RETHROW( (old_price)(new_price) ) }
154 
155 } } // graphene::app
FC_CAPTURE_AND_RETHROW
#define FC_CAPTURE_AND_RETHROW(...)
Definition: exception.hpp:479
graphene::db::object::id
object_id_type id
Definition: object.hpp:69
asset_object.hpp
graphene::protocol::price
The price struct stores asset prices in the BitShares system.
Definition: asset.hpp:108
graphene::chain::asset_object
tracks the parameters of an asset
Definition: asset_object.hpp:75
fc::variant::as_string
std::string as_string() const
Definition: variant.cpp:469
graphene::chain::asset_object::precision
uint8_t precision
Maximum number of digits after the decimal point (must be <= 12)
Definition: asset_object.hpp:133
graphene::protocol::asset::asset_id
asset_id_type asset_id
Definition: asset.hpp:37
graphene::app::price_diff_percent_string
std::string price_diff_percent_string(const graphene::protocol::price &old_price, const graphene::protocol::price &new_price)
Definition: util.cpp:104
FC_ASSERT
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
fc::variant
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object's.
Definition: variant.hpp:198
graphene::protocol::asset::amount
share_type amount
Definition: asset.hpp:36
graphene::app::price_to_string
std::string price_to_string(const graphene::protocol::price &_price, const uint8_t base_precision, const uint8_t quote_precision)
Definition: util.cpp:68
graphene::protocol::price::base
asset base
Definition: asset.hpp:113
graphene::app::uint128_amount_to_string
std::string uint128_amount_to_string(const fc::uint128_t &amount, const uint8_t precision)
Definition: util.cpp:42
fc::safe::value
T value
Definition: safe.hpp:28
asset.hpp
graphene::protocol::price::quote
asset quote
Definition: asset.hpp:114
graphene
Definition: api.cpp:48
util.hpp