diff --git a/pallets/xyk/rpc/src/lib.rs b/pallets/xyk/rpc/src/lib.rs index e89f6235cbc5e..1596512f0414b 100644 --- a/pallets/xyk/rpc/src/lib.rs +++ b/pallets/xyk/rpc/src/lib.rs @@ -33,6 +33,24 @@ pub trait XykApi, ) -> Result; + #[rpc(name = "xyk_calculate_sell_price_id")] + fn calculate_sell_price_id( + &self, + sold_token_id: TokenId, + bought_token_id: TokenId, + sell_amount: Balance, + at: Option, + ) -> Result; + + #[rpc(name = "xyk_calculate_buy_price_id")] + fn calculate_buy_price_id( + &self, + sold_token_id: TokenId, + bought_token_id: TokenId, + buy_amount: Balance, + at: Option, + ) -> Result; + #[rpc(name = "xyk_get_burn_amount")] fn get_burn_amount( &self, @@ -111,6 +129,48 @@ where }) } + fn calculate_sell_price_id( + &self, + sold_token_id: TokenId, + bought_token_id: TokenId, + sell_amount: Balance, + at: Option<::Hash>, + ) -> Result> { + let api = self.client.runtime_api(); + let at = BlockId::::hash(at.unwrap_or_else(|| + // If the block hash is not supplied assume the best block. + self.client.info().best_hash)); + + let runtime_api_result = + api.calculate_sell_price_id(&at, sold_token_id, bought_token_id, sell_amount); + runtime_api_result.map_err(|e| RpcError { + code: ErrorCode::ServerError(1), + message: "Unable to serve the request".into(), + data: Some(format!("{:?}", e).into()), + }) + } + + fn calculate_buy_price_id( + &self, + sold_token_id: TokenId, + bought_token_id: TokenId, + buy_amount: Balance, + at: Option<::Hash>, + ) -> Result> { + let api = self.client.runtime_api(); + let at = BlockId::::hash(at.unwrap_or_else(|| + // If the block hash is not supplied assume the best block. + self.client.info().best_hash)); + + let runtime_api_result = + api.calculate_buy_price_id(&at, sold_token_id, bought_token_id, buy_amount); + runtime_api_result.map_err(|e| RpcError { + code: ErrorCode::ServerError(1), + message: "Unable to serve the request".into(), + data: Some(format!("{:?}", e).into()), + }) + } + fn get_burn_amount( &self, first_asset_id: TokenId, diff --git a/pallets/xyk/runtime-api/src/lib.rs b/pallets/xyk/runtime-api/src/lib.rs index c5cd57bf26da8..2e06217209f8d 100644 --- a/pallets/xyk/runtime-api/src/lib.rs +++ b/pallets/xyk/runtime-api/src/lib.rs @@ -79,10 +79,20 @@ sp_api::decl_runtime_apis! { sell_amount: Balance ) -> RpcResult; fn calculate_buy_price( - input_reserve: Balance, + input_reserve: Balance, output_reserve: Balance, buy_amount: Balance ) -> RpcResult; + fn calculate_sell_price_id( + sold_token_id: TokenId, + bought_token_id: TokenId, + sell_amount: Balance + ) -> RpcResult; + fn calculate_buy_price_id( + sold_token_id: TokenId, + bought_token_id: TokenId, + buy_amount: Balance + ) -> RpcResult; fn get_burn_amount( first_asset_id: TokenId, second_asset_id: TokenId, diff --git a/pallets/xyk/src/lib.rs b/pallets/xyk/src/lib.rs index 68aafc55dc042..1c272b2348f84 100644 --- a/pallets/xyk/src/lib.rs +++ b/pallets/xyk/src/lib.rs @@ -371,6 +371,7 @@ decl_module! { ) -> DispatchResult { let sender = ensure_signed(origin)?; + >::sell_asset(sender, sold_asset_id.into(), bought_asset_id.into(), sold_asset_amount.into(), min_amount_out.into()) } @@ -437,6 +438,7 @@ impl Module { let result = numerator .checked_div(denominator) .ok_or_else(|| DispatchError::from(Error::::DivisionByZero))?; + Ok(result.saturated_into::().saturated_into::()) } @@ -463,16 +465,19 @@ impl Module { input_reserve: Balance, output_reserve: Balance, buy_amount: Balance, - ) -> Balance { + ) -> Result { let input_reserve_saturated: U256 = input_reserve.saturated_into::().into(); let output_reserve_saturated: U256 = output_reserve.saturated_into::().into(); let buy_amount_saturated: U256 = buy_amount.saturated_into::().into(); let numerator: U256 = input_reserve_saturated * buy_amount_saturated * 1000; let denominator: U256 = (output_reserve_saturated - buy_amount_saturated) * 997; - let result: U256 = numerator / denominator + 1; + let result = numerator + .checked_div(denominator) + .ok_or_else(|| DispatchError::from(Error::::DivisionByZero))? + + 1; - result.saturated_into::().saturated_into::() + Ok(result.saturated_into::().saturated_into::()) } pub fn get_liquidity_asset( @@ -488,6 +493,28 @@ impl Module { } } + pub fn calculate_sell_price_id( + sold_token_id: TokenId, + bought_token_id: TokenId, + sell_amount: Balance, + ) -> Result { + let input_reserve = Pools::get((sold_token_id, bought_token_id)); + let output_reserve = Pools::get((bought_token_id, sold_token_id)); + + Self::calculate_sell_price(input_reserve, output_reserve, sell_amount) + } + + pub fn calculate_buy_price_id( + sold_token_id: TokenId, + bought_token_id: TokenId, + buy_amount: Balance, + ) -> Result { + let input_reserve = Pools::get((sold_token_id, bought_token_id)); + let output_reserve = Pools::get((bought_token_id, sold_token_id)); + + Self::calculate_buy_price(input_reserve, output_reserve, buy_amount) + } + // Calculate first and second token amounts depending on liquidity amount to burn pub fn get_burn_amount( first_asset_id: TokenId, @@ -926,7 +953,7 @@ impl XykFunctionsTrait for Module { // Calculate amount to be paid from bought amount let sold_asset_amount = - Module::::calculate_buy_price(input_reserve, output_reserve, bought_asset_amount); + Module::::calculate_buy_price(input_reserve, output_reserve, bought_asset_amount)?; // Ensure user has enought tokens to sell ensure!( diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 8d641268c0a9d..50a68a77bde9f 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -774,7 +774,27 @@ impl_runtime_apis! { buy_amount: Balance ) -> RpcResult { RpcResult { - price: Xyk::calculate_buy_price(input_reserve, output_reserve, buy_amount) + price: Xyk::calculate_buy_price(input_reserve, output_reserve, buy_amount).unwrap_or_default() + } + } + + fn calculate_sell_price_id( + sold_token_id: TokenId, + bought_token_id: TokenId, + sell_amount: Balance + ) -> RpcResult { + RpcResult { + price: Xyk::calculate_sell_price_id(sold_token_id, bought_token_id, sell_amount).unwrap_or_default() + } + } + + fn calculate_buy_price_id( + sold_token_id: TokenId, + bought_token_id: TokenId, + buy_amount: Balance + ) -> RpcResult { + RpcResult { + price: Xyk::calculate_buy_price_id(sold_token_id, bought_token_id, buy_amount).unwrap_or_default() } }