Skip to content

Commit

Permalink
Router v2 stable liquidity (#118)
Browse files Browse the repository at this point in the history
Allow adding liquidity to StablePools via Router.
  • Loading branch information
JanKuczma authored Sep 26, 2024
2 parents 58583b8 + 3222cff commit a09a8b2
Show file tree
Hide file tree
Showing 7 changed files with 711 additions and 43 deletions.
111 changes: 90 additions & 21 deletions amm/contracts/router_v2/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub struct CallerIsNotOwner;
#[ink::contract]
pub mod router_v2 {
use crate::{
pool::{Pair, Pool},
pool::{Pair, Pool, StablePool},
utils::*,
};
use amm_helpers::ensure;
Expand Down Expand Up @@ -50,7 +50,7 @@ pub mod router_v2 {
/// Returns Pool for `pool_id` if it exists.
/// Adds the Pool to the cache.
#[inline]
fn get_pool(&mut self, pool_id: AccountId) -> Result<Pool, RouterV2Error> {
fn get_and_cache_pool(&mut self, pool_id: AccountId) -> Result<Pool, RouterV2Error> {
match self.cached_pools.get(pool_id) {
Some(pool) => Ok(pool),
None => {
Expand All @@ -60,13 +60,24 @@ pub mod router_v2 {
}
}
}

/// Returns StablePool for `pool_id`.
/// Adds the StablePool to the cache.
#[inline]
fn get_and_cache_stable_pool(&mut self, pool_id: AccountId) -> Result<StablePool, RouterV2Error> {
match self.get_and_cache_pool(pool_id)? {
Pool::StablePool(pool) => Ok(pool),
Pool::Pair(_) => Err(RouterV2Error::InvalidPoolAddress),
}
}

/// Returns Pair for `pool_id`.
/// If `pool_id` is `None`, it creates a new Pair for
/// `(token_0, token_1)` tokens if the Pair does not
/// exist in the pair Factory.
/// Adds the Pair to the cache.
#[inline]
fn get_pair(
fn get_and_cache_pair(
&mut self,
pool_id: Option<AccountId>,
token_0: AccountId,
Expand All @@ -76,9 +87,9 @@ pub mod router_v2 {
Some(pool_id) => pool_id,
None => self.pair_factory_ref().create_pair(token_0, token_1)?,
};
match self.get_pool(pool_id)? {
match self.get_and_cache_pool(pool_id)? {
Pool::Pair(pair) => Ok(pair),
Pool::StablePool(_) => Err(RouterV2Error::PairNotFound),
Pool::StablePool(_) => Err(RouterV2Error::InvalidPoolAddress),
}
}

Expand All @@ -91,15 +102,15 @@ pub mod router_v2 {
) -> Result<(), RouterV2Error> {
let n_pools = path.len();
for i in 0..n_pools - 1 {
self.get_pool(path[i].pool_id)?.swap(
self.get_and_cache_pool(path[i].pool_id)?.swap(
path[i].token_in,
path[i + 1].token_in,
amounts[i + 1],
path[i + 1].pool_id,
)?;
}
// If last pool in the path, transfer tokens to the `to` recipient.
self.get_pool(path[n_pools - 1].pool_id)?.swap(
self.get_and_cache_pool(path[n_pools - 1].pool_id)?.swap(
path[n_pools - 1].token_in,
token_out,
amounts[n_pools],
Expand All @@ -120,13 +131,13 @@ pub mod router_v2 {
let n_pools = path.len();
let mut amounts = vec![0; n_pools + 1];
amounts[n_pools] = amount_out;
amounts[n_pools - 1] = self.get_pool(path[n_pools - 1].pool_id)?.get_amount_in(
amounts[n_pools - 1] = self.get_and_cache_pool(path[n_pools - 1].pool_id)?.get_amount_in(
path[n_pools - 1].token_in,
token_out,
amount_out,
)?;
for i in (0..n_pools - 1).rev() {
amounts[i] = self.get_pool(path[i].pool_id)?.get_amount_in(
amounts[i] = self.get_and_cache_pool(path[i].pool_id)?.get_amount_in(
path[i].token_in,
path[i + 1].token_in,
amounts[i + 1],
Expand All @@ -149,13 +160,13 @@ pub mod router_v2 {
let mut amounts = vec![0; n_pools + 1];
amounts[0] = amount_in;
for i in 0..n_pools - 1 {
amounts[i + 1] = self.get_pool(path[i].pool_id)?.get_amount_out(
amounts[i + 1] = self.get_and_cache_pool(path[i].pool_id)?.get_amount_out(
path[i].token_in,
path[i + 1].token_in,
amounts[i],
)?;
}
amounts[n_pools] = self.get_pool(path[n_pools - 1].pool_id)?.get_amount_out(
amounts[n_pools] = self.get_and_cache_pool(path[n_pools - 1].pool_id)?.get_amount_out(
path[n_pools - 1].token_in,
token_out,
amounts[n_pools - 1],
Expand Down Expand Up @@ -284,9 +295,7 @@ pub mod router_v2 {
self.swap(&amounts, &path, wnative, self.env().account_id())?;
let native_out = amounts[amounts.len() - 1];
withdraw(wnative, native_out)?;
self.env()
.transfer(to, native_out)
.map_err(|_| RouterV2Error::TransferError)?;
transfer_native(to, native_out)?;
Ok(amounts)
}

Expand Down Expand Up @@ -315,9 +324,7 @@ pub mod router_v2 {
)?;
self.swap(&amounts, &path, wnative, self.env().account_id())?;
withdraw(wnative, native_out)?;
self.env()
.transfer(to, native_out)
.map_err(|_| RouterV2Error::TransferError)?;
transfer_native(to, native_out)?;
Ok(amounts)
}

Expand Down Expand Up @@ -386,7 +393,7 @@ pub mod router_v2 {
to: AccountId,
deadline: u64,
) -> Result<(u128, u128, u128), RouterV2Error> {
let pair = self.get_pair(pair, token_0, token_1)?;
let pair = self.get_and_cache_pair(pair, token_0, token_1)?;
pair.add_liquidity(
token_0,
token_1,
Expand All @@ -411,7 +418,7 @@ pub mod router_v2 {
deadline: u64,
) -> Result<(u128, Balance, u128), RouterV2Error> {
let wnative = self.wnative;
let pair = self.get_pair(pair, token, wnative)?;
let pair = self.get_and_cache_pair(pair, token, wnative)?;
pair.add_liquidity_native(
token,
wnative,
Expand All @@ -435,7 +442,7 @@ pub mod router_v2 {
to: AccountId,
deadline: u64,
) -> Result<(u128, u128), RouterV2Error> {
let pair = self.get_pair(Some(pair), token_0, token_1)?;
let pair = self.get_and_cache_pair(Some(pair), token_0, token_1)?;
pair.remove_liquidity(
token_0,
token_1,
Expand All @@ -459,7 +466,7 @@ pub mod router_v2 {
deadline: u64,
) -> Result<(u128, Balance), RouterV2Error> {
let wnative = self.wnative;
let pair = self.get_pair(Some(pair), token, wnative)?;
let pair = self.get_and_cache_pair(Some(pair), token, wnative)?;
pair.remove_liquidity_native(
token,
wnative,
Expand All @@ -470,6 +477,68 @@ pub mod router_v2 {
deadline,
)
}

// ----------- STABLE POOL LIQUIDITY METHODS ----------- //

#[ink(message, payable)]
fn add_stable_pool_liquidity(
&mut self,
pool: AccountId,
min_share_amount: u128,
amounts: Vec<u128>,
to: AccountId,
deadline: u64,
native: bool,
) -> Result<(u128, u128), RouterV2Error> {
let wnative = if native { Some(self.wnative) } else { None };
self.get_and_cache_stable_pool(pool)?.add_liquidity(
min_share_amount,
amounts,
to,
deadline,
wnative,
)
}

#[ink(message)]
fn remove_stable_pool_liquidity(
&mut self,
pool: AccountId,
max_share_amount: u128,
amounts: Vec<u128>,
to: AccountId,
deadline: u64,
native: bool,
) -> Result<(u128, u128), RouterV2Error> {
let wnative = if native { Some(self.wnative) } else { None };
self.get_and_cache_stable_pool(pool)?.remove_liquidity(
max_share_amount,
amounts,
to,
deadline,
wnative,
)
}

#[ink(message)]
fn remove_stable_pool_liquidity_by_share(
&mut self,
pool: AccountId,
share_amount: u128,
min_amounts: Vec<u128>,
to: AccountId,
deadline: u64,
native: bool,
) -> Result<Vec<u128>, RouterV2Error> {
let wnative = if native { Some(self.wnative) } else { None };
self.get_and_cache_stable_pool(pool)?.remove_liquidity_by_share(
share_amount,
min_amounts,
to,
deadline,
wnative,
)
}
}

#[cfg(test)]
Expand Down
9 changes: 5 additions & 4 deletions amm/contracts/router_v2/pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use amm_helpers::{ensure, math::casted_mul};
use ink::{
codegen::TraitCallBuilder,
contract_ref,
env::{account_id, caller, transfer, transferred_value, DefaultEnvironment as Env},
env::{account_id, caller, transferred_value, DefaultEnvironment as Env},
primitives::AccountId,
};
use traits::{Balance, MathError, Pair as PairTrait, RouterV2Error};
Expand Down Expand Up @@ -63,6 +63,8 @@ impl Pair {

/// Makes a cross-contract call to fetch the Pair reserves.
/// Returns reserves `(reserve_0, reserve_1)` in order of `token_0` and `token_1`
/// NOTE: before calling this method ensure that `token_0` and `token_1` belong to
/// this `Pair` pool
fn get_reserves(&self, token_0: &AccountId, token_1: &AccountId) -> (u128, u128) {
let (reserve_0, reserve_1, _) = self.contract_ref().get_reserves();
if token_0 < token_1 {
Expand Down Expand Up @@ -185,8 +187,7 @@ impl Pair {
let liquidity = self.contract_ref().mint(to)?;

if received_value > amount_native {
transfer::<Env>(caller, received_value - amount_native)
.map_err(|_| RouterV2Error::TransferError)?;
transfer_native(caller, received_value - amount_native)?;
}

Ok((amount_0, amount_native, liquidity))
Expand Down Expand Up @@ -240,7 +241,7 @@ impl Pair {
)?;
psp22_transfer(token, to, amount_token)?;
withdraw(wnative, amount_native)?;
transfer::<Env>(to, amount_native).map_err(|_| RouterV2Error::TransferError)?;
transfer_native(to, amount_native)?;
Ok((amount_token, amount_native))
}

Expand Down
Loading

0 comments on commit a09a8b2

Please sign in to comment.