31 #include <graphene/chain/hardfork.hpp> 36 namespace graphene {
namespace chain {
43 FC_ASSERT( HARDFORK_LIQUIDITY_POOL_PASSED(block_time),
"Not allowed until the LP hardfork" );
50 "Only the asset owner can set an asset as the share asset of a liquidity pool" );
53 "Can not specify a market-issued asset as the share asset of a liquidity pool" );
56 "The share asset is already bound to another liquidity pool" );
59 "Current supply of the share asset needs to be zero" );
76 result.
new_objects.insert( new_liquidity_pool_object.id );
92 FC_ASSERT( _pool->balance_a == 0 && _pool->balance_b == 0,
"Can not delete a non-empty pool" );
126 FC_ASSERT( (_pool->balance_a == 0) == (_pool->balance_b == 0),
"Internal error" );
128 const asset_object& share_asset_obj = _pool->share_asset(d);
132 if( _pool->balance_a == 0 )
134 FC_ASSERT( share_asset_obj.
issuer == op.
account,
"The initial deposit can only be done by the pool owner" );
137 _share_asset_dyn_data = &share_asset_obj.
dynamic_data(d);
139 FC_ASSERT( (_pool->balance_a == 0) == (_share_asset_dyn_data->current_supply == 0),
"Internal error" );
142 "Can not create new supply for the share asset" );
145 "The account is unauthorized by the share asset" );
147 "The account is unauthorized by asset A" );
149 "The account is unauthorized by asset B" );
151 if( _pool->balance_a == 0 )
155 "For initial deposit, each amount of the two assets in the pool should not be greater than " 156 "the maximum supply of the share asset" );
159 _account_receives =
asset( share_amount, _pool->share_asset );
164 fc::uint128_t max128( max_new_supply.
value );
165 fc::uint128_t supply128( _share_asset_dyn_data->current_supply.value );
166 fc::uint128_t new_supply_if_a = supply128 * op.
amount_a.
amount.
value / _pool->balance_a.value;
167 fc::uint128_t new_supply_if_b = supply128 * op.
amount_b.
amount.
value / _pool->balance_b.value;
168 fc::uint128_t new_supply = std::min( { new_supply_if_a, new_supply_if_b, max128 } );
170 FC_ASSERT( new_supply > 0,
"Aborting due to zero outcome" );
172 fc::uint128_t a128 = ( new_supply * _pool->balance_a.value + supply128 - 1 ) / supply128;
174 _pool_receives_a =
asset( static_cast<int64_t>( a128 ), _pool->asset_a );
176 fc::uint128_t b128 = ( new_supply * _pool->balance_b.value + supply128 - 1 ) / supply128;
178 _pool_receives_b =
asset( static_cast<int64_t>( b128 ), _pool->asset_b );
180 _account_receives =
asset( static_cast<int64_t>( new_supply ), _pool->share_asset );
197 lpo.
balance_a += _pool_receives_a.amount;
198 lpo.
balance_b += _pool_receives_b.amount;
206 FC_ASSERT( _pool->balance_a > 0 && _pool->balance_b > 0,
"Internal error" );
207 FC_ASSERT( _share_asset_dyn_data->current_supply > 0,
"Internal error" );
209 result.
paid.emplace_back( _pool_receives_a );
210 result.
paid.emplace_back( _pool_receives_b );
211 result.
received.emplace_back( _account_receives );
224 FC_ASSERT( _pool->balance_a > 0 && _pool->balance_b > 0,
"The pool has not been initialized" );
226 const asset_object& share_asset_obj = _pool->share_asset(d);
229 "The account is unauthorized by the share asset" );
231 "The account is unauthorized by asset A" );
233 "The account is unauthorized by asset B" );
235 _share_asset_dyn_data = &share_asset_obj.
dynamic_data(d);
238 "Can not withdraw an amount that is more than the current supply" );
242 _pool_pays_a =
asset( _pool->balance_a, _pool->asset_a );
243 _pool_pays_b =
asset( _pool->balance_b, _pool->asset_b );
244 _fee_a =
asset( 0, _pool->asset_a );
245 _fee_b =
asset( 0, _pool->asset_b );
250 fc::uint128_t a128 = share128 * _pool->balance_a.value / _share_asset_dyn_data->current_supply.value;
251 FC_ASSERT( a128 < fc::uint128_t( _pool->balance_a.value ),
"Internal error" );
253 FC_ASSERT( fee_a <= a128,
"Withdrawal fee percent of the pool is too high" );
255 fc::uint128_t b128 = share128 * _pool->balance_b.value / _share_asset_dyn_data->current_supply.value;
256 FC_ASSERT( b128 < fc::uint128_t( _pool->balance_b.value ),
"Internal error" );
258 FC_ASSERT( fee_b <= b128,
"Withdrawal fee percent of the pool is too high" );
260 FC_ASSERT( a128 > 0 || b128 > 0,
"Aborting due to zero outcome" );
261 _pool_pays_a =
asset( static_cast<int64_t>( a128 ), _pool->asset_a );
262 _pool_pays_b =
asset( static_cast<int64_t>( b128 ), _pool->asset_b );
263 _fee_a =
asset( static_cast<int64_t>( fee_a ), _pool->asset_a );
264 _fee_b =
asset( static_cast<int64_t>( fee_b ), _pool->asset_b );
278 if( _pool_pays_a.amount > 0 )
280 if( _pool_pays_b.amount > 0 )
293 FC_ASSERT( (_pool->balance_a == 0) == (_pool->balance_b == 0),
"Internal error" );
294 FC_ASSERT( (_pool->balance_a == 0) == (_share_asset_dyn_data->current_supply == 0),
"Internal error" );
297 result.
received.emplace_back( _pool_pays_a );
298 result.
received.emplace_back( _pool_pays_b );
299 result.
fees.emplace_back( _fee_a );
300 result.
fees.emplace_back( _fee_b );
311 FC_ASSERT( _pool->balance_a > 0 && _pool->balance_b > 0,
"The pool has not been initialized" );
315 "Asset type mismatch" );
320 "The account is unauthorized by asset A" );
324 "The account is unauthorized by asset B" );
332 "The ${a}:${b} market has not been whitelisted by asset ${a}",
339 "The ${a}:${b} market has been blacklisted by asset ${a}",
346 "The ${a}:${b} market has not been whitelisted by asset ${b}",
353 "The ${a}:${b} market has been blacklisted by asset ${b}",
362 "Aborting since the maker market fee of the selling asset is too high" );
368 share_type new_balance_a = _pool->balance_a + _pool_receives.amount;
370 fc::uint128_t new_balance_b = ( _pool->virtual_value + new_balance_a.
value - 1 ) / new_balance_a.
value;
371 FC_ASSERT( new_balance_b <= _pool->balance_b,
"Internal error" );
372 delta = fc::uint128_t( _pool->balance_b.value ) - new_balance_b;
373 _pool_pays_asset = &asset_obj_b;
377 share_type new_balance_b = _pool->balance_b + _pool_receives.amount;
379 fc::uint128_t new_balance_a = ( _pool->virtual_value + new_balance_b.
value - 1 ) / new_balance_b.
value;
380 FC_ASSERT( new_balance_a <= _pool->balance_a,
"Internal error" );
381 delta = fc::uint128_t( _pool->balance_a.value ) - new_balance_a;
382 _pool_pays_asset = &asset_obj_a;
386 FC_ASSERT( pool_taker_fee <= delta,
"Taker fee percent of the pool is too high" );
391 FC_ASSERT( _taker_market_fee <= _pool_pays,
"Market fee should not be greater than the amount to receive" );
392 _account_receives = _pool_pays - _taker_market_fee;
395 liquidity_pool_exchange_unfillable_price,
396 "Unable to exchange at expected price" );
420 const auto old_virtual_value = _pool->virtual_value;
438 FC_ASSERT( _pool->balance_a > 0 && _pool->balance_b > 0,
"Internal error" );
439 FC_ASSERT( _pool->virtual_value >= old_virtual_value,
"Internal error" );
442 result.
received.emplace_back( _account_receives );
443 result.
fees.emplace_back( _maker_market_fee );
444 result.
fees.emplace_back( _taker_market_fee );
445 result.
fees.emplace_back( _pool_taker_fee );
flat_set< object_id_type > new_objects
asset share_amount
The amount of the share asset to use.
void modify(const T &obj, const Lambda &m)
liquidity_pool_id_type pool
ID of the liquidity pool.
generic_exchange_operation_result do_apply(const liquidity_pool_exchange_operation &op)
liquidity_pool_id_type pool
ID of the liquidity pool.
void adjust_balance(account_id_type account, asset delta)
Adjust a particular account's balance in a given asset by a delta.
Create a new liquidity pool.
bool is_authorized_asset(const database &d, const account_object &acct, const asset_object &asset_obj)
void_result do_evaluate(const liquidity_pool_withdraw_operation &op)
void_result do_evaluate(const liquidity_pool_exchange_operation &op)
time_point_sec head_block_time() const
uint16_t taker_fee_percent
Taker fee percent.
account_id_type account
The account who withdraws from the liquidity pool.
tracks the blockchain state in an extensible manner
void_result do_evaluate(const liquidity_pool_delete_operation &op)
asset min_to_receive
The minimum amount of the other asset type to receive.
uint16_t withdrawal_fee_percent
Withdrawal fee percent.
liquidity_pool_id_type pool
ID of the liquidity pool.
const account_object * fee_paying_account
const asset_dynamic_data_object & dynamic_data(const DB &db) const
flat_set< asset_id_type > blacklist_markets
account_id_type issuer
ID of the account which issued this asset.
optional< liquidity_pool_id_type > for_liquidity_pool
The ID of the liquidity pool if the asset is the share asset of a liquidity pool. ...
generic_exchange_operation_result do_apply(const liquidity_pool_withdraw_operation &op)
asset pay_market_fees(const account_object *seller, const asset_object &recv_asset, const asset &receives, const bool &is_maker, const optional< asset > &calculated_market_fees={})
asset_id_type asset_a
Type of the first asset in the pool.
account_id_type account
The account who exchanges with the liquidity pool.
flat_set< asset_id_type > whitelist_markets
#define GRAPHENE_100_PERCENT
liquidity_pool_id_type pool
ID of the liquidity pool.
Withdraw from a liquidity pool.
bool is_market_issued() const
string symbol
Ticker symbol for this asset, i.e. "USD".
asset_id_type share_asset
Type of the share asset aka the LP token.
void_result do_evaluate(const liquidity_pool_create_operation &op)
#define FC_CAPTURE_AND_RETHROW(...)
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
share_type balance_a
The balance of the first asset in the pool.
account_id_type account
The account who creates the liquidity pool.
Exchange with a liquidity pool.
asset amount_to_sell
The amount of one asset type to sell.
tracks the asset information that changes frequentlyBecause the asset_object is very large it doesn't...
const asset_object * _share_asset
account_id_type account
The account who deposits to the liquidity pool.
flat_set< object_id_type > removed_objects
tracks the parameters of an assetAll assets have a globally unique symbol name that controls how they...
asset calculate_market_fee(const asset_object &trade_asset, const asset &trade_amount, const bool &is_maker) const
Calculate the market fee that is to be taken.
bool can_create_new_supply() const
flat_set< object_id_type > updated_objects
void update_virtual_value()
share_type balance_b
The balance of the second asset in the pool.
void remove(const object &obj)
#define GRAPHENE_ASSERT(expr, exc_type, FORMAT,...)
bool is_liquidity_pool_share_asset() const
share_type current_supply
The number of shares currently in existence.
asset amount_b
The amount of the second asset to deposit.
account_id_type account
The account who owns the liquidity pool.
asset amount_a
The amount of the first asset to deposit.
Deposit to a liquidity pool.
const T & create(F &&constructor)
generic_exchange_operation_result do_apply(const liquidity_pool_deposit_operation &op)
void_result do_evaluate(const liquidity_pool_deposit_operation &op)
generic_operation_result do_apply(const liquidity_pool_delete_operation &op)
generic_operation_result do_apply(const liquidity_pool_create_operation &op)
asset_id_type asset_b
Type of the second asset in the pool.