Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combine StablePool traits into one #30

Merged
merged 6 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 84 additions & 41 deletions amm/contracts/stable_pool/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ pub mod stable_pool {
use psp22::{PSP22Data, PSP22Error, PSP22Event, PSP22Metadata, PSP22};
use traits::{
MathError, Ownable2Step, Ownable2StepData, Ownable2StepResult, StablePool, StablePoolError,
StablePoolView,
};

#[ink(event)]
Expand Down Expand Up @@ -66,12 +65,12 @@ pub mod stable_pool {

#[ink(event)]
pub struct Sync {
reserves: Vec<u128>,
pub reserves: Vec<u128>,
}

#[ink(event)]
pub struct RatesUpdated {
rates: Vec<TokenRate>,
pub rates: Vec<TokenRate>,
}

#[ink(event)]
Expand Down Expand Up @@ -101,11 +100,13 @@ pub mod stable_pool {

#[ink(event)]
pub struct TransferOwnershipInitiated {
#[ink(topic)]
pub new_owner: AccountId,
}

#[ink(event)]
pub struct TransferOwnershipAccepted {
#[ink(topic)]
pub new_owner: AccountId,
}

Expand All @@ -120,14 +121,13 @@ pub mod stable_pool {

#[ink(event)]
pub struct AmpCoefChanged {
#[ink(topic)]
pub new_amp_coef: u128,
}

#[ink(event)]
pub struct FeeChanged {
trade_fee: u32,
protocol_fee: u32,
pub trade_fee: u32,
pub protocol_fee: u32,
}

#[ink::storage_item]
Expand Down Expand Up @@ -305,11 +305,18 @@ pub mod stable_pool {
self.pool.tokens[token_id].into()
}

/// Update cached rates if expired.
///
/// NOTE:
/// If the pool contains a token with rate oracle, this function makes
/// a cross-contract call to the `RateProvider` contract if the cached rate is expired.
/// This means that the gas cost of the contract methods that use this function may change,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'vary' instead of 'change'? Feels like a better fitting word 😛

/// depending on the state of the expiration timestamp of the cached rate.
fn update_rates(&mut self) {
let current_time = self.env().block_timestamp();
let mut rate_changed = false;
for rate in self.pool.token_rates.iter_mut() {
rate_changed = rate.update_rate(current_time) | rate_changed;
rate_changed |= rate.update_rate(current_time);
}
if rate_changed {
Self::env().emit_event(RatesUpdated {
Expand All @@ -318,18 +325,21 @@ pub mod stable_pool {
}
}

fn fee_to(&self) -> Option<AccountId> {
self.pool.fee_receiver
/// Get updated rates
fn get_updated_rates(&self) -> Vec<TokenRate> {
let current_time = self.env().block_timestamp();
let mut rates = self.pool.token_rates.clone();
rates.iter_mut().for_each(|rate| {
rate.update_rate(current_time);
});
rates
}

/// Scaled rates are rates multiplied by precision. They are assumed to fit in u128.
/// If TOKEN_TARGET_DECIMALS is 18 and RATE_DECIMALS is 12, then rates not exceeding ~340282366 should fit.
/// That's because if precision <= 10^18 and rate <= 10^12 * 340282366, then rate * precision < 2^128.
///
/// NOTE: Rates should be updated prior to calling this function
fn get_scaled_rates(&self) -> Result<Vec<u128>, MathError> {
self.pool
.token_rates
fn get_scaled_rates(&self, rates: &[TokenRate]) -> Result<Vec<u128>, MathError> {
rates
.iter()
.zip(self.pool.precisions.iter())
.map(|(rate, &precision)| {
Expand Down Expand Up @@ -364,10 +374,10 @@ pub mod stable_pool {
///
/// NOTE: Rates should be updated prior to calling this function
fn mint_protocol_fee(&mut self, fee: u128, token_id: usize) -> Result<(), StablePoolError> {
if let Some(fee_to) = self.fee_to() {
if let Some(fee_to) = self.fee_receiver() {
let protocol_fee = self.pool.fees.protocol_trade_fee(fee)?;
if protocol_fee > 0 {
let rates = self.get_scaled_rates()?;
let rates = self.get_scaled_rates(&self.pool.token_rates)?;
let mut protocol_deposit_amounts = vec![0u128; self.pool.tokens.len()];
protocol_deposit_amounts[token_id] = protocol_fee;
let mut reserves = self.pool.reserves.clone();
Expand Down Expand Up @@ -428,8 +438,8 @@ pub mod stable_pool {

// Make sure rates are up to date before we attempt any calculations
self.update_rates();
let rates = self.get_scaled_rates(&self.pool.token_rates)?;

let rates = self.get_scaled_rates()?;
// calc amount_out and fees
let (token_out_amount, fee) = math::rated_swap_to(
&rates,
Expand Down Expand Up @@ -489,8 +499,7 @@ pub mod stable_pool {

// Make sure rates are up to date before we attempt any calculations
self.update_rates();

let rates = self.get_scaled_rates()?;
let rates = self.get_scaled_rates(&self.pool.token_rates)?;

// calc amount_out and fees
let (token_in_amount, fee) = math::rated_swap_from(
Expand All @@ -506,7 +515,7 @@ pub mod stable_pool {
// Check if in token_in_amount is as constrained by the user
ensure!(
token_in_amount <= max_token_in_amount,
StablePoolError::TooLargeInputAmount
StablePoolError::InsufficientInputAmount
);
// update reserves
self.increase_reserve(token_in_id, token_in_amount)?;
Expand Down Expand Up @@ -577,8 +586,24 @@ pub mod stable_pool {
amounts: Vec<u128>,
to: AccountId,
) -> Result<(u128, u128), StablePoolError> {
ensure!(
amounts.len() == self.pool.tokens.len(),
StablePoolError::IncorrectAmountsCount
);

// Make sure rates are up to date before we attempt any calculations
self.update_rates();
let rates = self.get_scaled_rates(&self.pool.token_rates)?;

// calc lp tokens (shares_to_mint, fee)
let (shares, fee_part) = self.get_mint_liquidity_for_amounts(amounts.clone())?;
let (shares, fee_part) = math::rated_compute_lp_amount_for_deposit(
&rates,
&amounts,
&self.reserves(),
self.psp22.total_supply(),
Some(&self.pool.fees),
self.amp_coef(),
)?;

// Check min shares
ensure!(
Expand All @@ -601,7 +626,7 @@ pub mod stable_pool {
self.emit_events(events);

// mint protocol fee
if let Some(fee_to) = self.fee_to() {
if let Some(fee_to) = self.fee_receiver() {
let protocol_fee = self.pool.fees.protocol_trade_fee(fee_part)?;
if protocol_fee > 0 {
let events = self.psp22.mint(fee_to, protocol_fee)?;
Expand Down Expand Up @@ -683,9 +708,24 @@ pub mod stable_pool {
amounts: Vec<u128>,
to: AccountId,
) -> Result<(u128, u128), StablePoolError> {
ensure!(
amounts.len() == self.pool.tokens.len(),
StablePoolError::IncorrectAmountsCount
);

// Make sure rates are up to date before we attempt any calculations
self.update_rates();
let rates = self.get_scaled_rates(&self.pool.token_rates)?;

// calc comparable amounts
let (shares_to_burn, fee_part) =
self.get_burn_liquidity_for_amounts(amounts.clone())?;
let (shares_to_burn, fee_part) = math::rated_compute_lp_amount_for_withdraw(
&rates,
&amounts,
&self.reserves(),
self.psp22.total_supply(),
Some(&self.pool.fees),
self.amp_coef(),
)?;

// check max shares
ensure!(
Expand All @@ -696,7 +736,7 @@ pub mod stable_pool {
let events = self.psp22.burn(self.env().caller(), shares_to_burn)?;
self.emit_events(events);
// mint protocol fee
if let Some(fee_to) = self.fee_to() {
if let Some(fee_to) = self.fee_receiver() {
let protocol_fee = self.pool.fees.protocol_trade_fee(fee_part)?;
if protocol_fee > 0 {
let events = self.psp22.mint(fee_to, protocol_fee)?;
Expand Down Expand Up @@ -725,11 +765,11 @@ pub mod stable_pool {
}

#[ink(message)]
fn force_update_rate(&mut self) {
fn force_update_rates(&mut self) {
let current_time = self.env().block_timestamp();
let mut rate_changed = false;
for rate in self.pool.token_rates.iter_mut() {
rate_changed = rate.update_rate_no_cache(current_time) | rate_changed;
rate_changed |= rate.force_update_rate(current_time);
}
if rate_changed {
Self::env().emit_event(RatesUpdated {
Expand Down Expand Up @@ -820,9 +860,7 @@ pub mod stable_pool {
});
Ok(())
}
}

impl StablePoolView for StablePoolContract {
#[ink(message)]
fn tokens(&self) -> Vec<AccountId> {
self.pool.tokens.clone()
Expand All @@ -843,6 +881,11 @@ pub mod stable_pool {
(self.pool.fees.trade_fee, self.pool.fees.protocol_fee)
}

#[ink(message)]
fn fee_receiver(&self) -> Option<AccountId> {
self.pool.fee_receiver
}

#[ink(message)]
fn token_rates(&mut self) -> Vec<u128> {
self.update_rates();
Expand All @@ -855,14 +898,13 @@ pub mod stable_pool {

#[ink(message)]
fn get_swap_amount_out(
&mut self,
&self,
token_in: AccountId,
token_out: AccountId,
token_in_amount: u128,
) -> Result<(u128, u128), StablePoolError> {
let (token_in_id, token_out_id) = self.check_tokens(token_in, token_out)?;
self.update_rates();
let rates = self.get_scaled_rates()?;
let rates = self.get_scaled_rates(&self.get_updated_rates())?;
Ok(math::rated_swap_to(
&rates,
token_in_id,
Expand All @@ -876,14 +918,13 @@ pub mod stable_pool {

#[ink(message)]
fn get_swap_amount_in(
&mut self,
&self,
token_in: AccountId,
token_out: AccountId,
token_out_amount: u128,
) -> Result<(u128, u128), StablePoolError> {
let (token_in_id, token_out_id) = self.check_tokens(token_in, token_out)?;
self.update_rates();
let rates = self.get_scaled_rates()?;
let rates = self.get_scaled_rates(&self.get_updated_rates())?;
Ok(math::rated_swap_from(
&rates,
token_in_id,
Expand All @@ -897,15 +938,14 @@ pub mod stable_pool {

#[ink(message)]
fn get_mint_liquidity_for_amounts(
&mut self,
&self,
amounts: Vec<u128>,
) -> Result<(u128, u128), StablePoolError> {
ensure!(
amounts.len() == self.pool.tokens.len(),
StablePoolError::IncorrectAmountsCount
);
self.update_rates();
let rates = self.get_scaled_rates()?;
let rates = self.get_scaled_rates(&self.get_updated_rates())?;

Ok(math::rated_compute_lp_amount_for_deposit(
&rates,
Expand All @@ -931,15 +971,14 @@ pub mod stable_pool {

#[ink(message)]
fn get_burn_liquidity_for_amounts(
&mut self,
&self,
amounts: Vec<u128>,
) -> Result<(u128, u128), StablePoolError> {
self.update_rates();
ensure!(
amounts.len() == self.pool.tokens.len(),
StablePoolError::IncorrectAmountsCount
);
let rates = self.get_scaled_rates()?;
let rates = self.get_scaled_rates(&self.get_updated_rates())?;
math::rated_compute_lp_amount_for_withdraw(
&rates,
&amounts,
Expand All @@ -956,6 +995,10 @@ pub mod stable_pool {
&mut self,
liquidity: u128,
) -> Result<Vec<u128>, StablePoolError> {
ensure!(
liquidity <= self.psp22.total_supply(),
StablePoolError::InsufficientLiquidity
);
Ok(math::compute_amounts_given_lp(
liquidity,
&self.reserves(),
Expand Down
4 changes: 2 additions & 2 deletions amm/contracts/stable_pool/token_rate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl TokenRate {
token_rate_contract,
expiration_duration_ms,
));
_ = rate.update_rate_no_cache(current_time);
_ = rate.force_update_rate(current_time);
rate
}

Expand All @@ -60,7 +60,7 @@ impl TokenRate {
/// Update rate without expiry check.
///
/// Returns `true` if value of the new rate is different than the previous.
pub fn update_rate_no_cache(&mut self, current_time: u64) -> bool {
pub fn force_update_rate(&mut self, current_time: u64) -> bool {
match self {
Self::External(external) => external.update_rate_no_cache(current_time),
Self::Constant(_) => false,
Expand Down
1 change: 0 additions & 1 deletion amm/drink-tests/src/stable_swap_tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use primitive_types::U256;

pub use stable_pool_contract::StablePool as _;
pub use stable_pool_contract::StablePoolError;
pub use stable_pool_contract::StablePoolView as _;

use drink::{self, runtime::MinimalRuntime, session::Session, AccountId32};

Expand Down
2 changes: 1 addition & 1 deletion amm/drink-tests/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub fn upload_all(session: &mut Session<MinimalRuntime>) {

pub mod stable_swap {
use super::*;
use stable_pool_contract::{StablePool as _, StablePoolError, StablePoolView as _};
use stable_pool_contract::{StablePool as _, StablePoolError};

pub fn setup(
session: &mut Session<MinimalRuntime>,
Expand Down
2 changes: 1 addition & 1 deletion amm/traits/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ pub type Balance = <ink::env::DefaultEnvironment as ink::env::Environment>::Bala
pub use amm_helpers::math::MathError;
pub use ownable2step::{Ownable2Step, Ownable2StepData, Ownable2StepError, Ownable2StepResult};
pub use rate_provider::RateProvider;
pub use stable_pool::{StablePool, StablePoolError, StablePoolView};
pub use stable_pool::{StablePool, StablePoolError};
2 changes: 1 addition & 1 deletion amm/traits/ownable2step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub trait Ownable2Step {

/// The owner of the contract renounces the ownership.
/// To start the process, the owner has to initiate ownership transfer to this contract's address.
/// Can anly be caller by the current owner.
/// Can only be called by the current owner.
#[ink(message)]
fn renounce_ownership(&mut self) -> Ownable2StepResult<()>;

Expand Down
Loading
Loading