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

Post audit changes Part 1 #23

Merged
merged 12 commits into from
Jul 8, 2024
Merged
45 changes: 24 additions & 21 deletions amm/contracts/stable_pool/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
#![cfg_attr(not(feature = "std"), no_std, no_main)]
mod token_rate;

/// Stabelswap implementation based on the CurveFi stableswap model.
///
/// This pool contract supports PSP22 tokens which value increases at some
/// on-chain discoverable rate in terms of some other token, e.g. AZERO x sAZERO.
/// The rate oracle contract must implement [`RateProvider`](trait@traits::RateProvider).
///
/// IMPORTANT:
/// This stableswap implementation is NOT meant for yield-bearing assets which adjusts
/// its total supply to try and maintain a stable price a.k.a. rebasing tokens.
#[ink::contract]
pub mod stable_pool {
use crate::token_rate::TokenRate;
Expand Down Expand Up @@ -287,7 +295,7 @@ pub mod stable_pool {
let current_time = self.env().block_timestamp();
let mut rate_changed = false;
for rate in self.pool.token_rates.iter_mut() {
rate_changed = 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 @@ -300,9 +308,10 @@ pub mod stable_pool {
self.pool.fee_receiver
}

/// 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.
// 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 ro calling this function
fn get_scaled_rates(&self) -> Result<Vec<u128>, MathError> {
self.pool
.token_rates
Expand Down Expand Up @@ -344,7 +353,8 @@ pub mod stable_pool {
let token_out_id = self.token_id(token_out)?;
Ok((token_in_id, token_out_id))
}

/// Calculates lpt equivalent of the protocol fee and mints it to the `fee_to` if one is set.
/// NOTE: Rates should be updated prior ro calling this function
fn mint_protocol_fee(&mut self, fee: u128, token_id: usize) -> Result<(), StablePoolError> {
if let Some(fee_to) = self.fee_to() {
let protocol_fee = self.pool.fees.protocol_trade_fee(fee)?;
Expand Down Expand Up @@ -394,13 +404,6 @@ pub mod stable_pool {
Ok(())
}

/// This method is for internal use only
/// - calculates token_out amount
/// - calculates swap fee
/// - mints protocol fee
/// - updates reserves
/// It assumes that rates have been updated.
/// Returns (token_out_amount, swap_fee)
fn _swap_exact_in(
&mut self,
token_in: AccountId,
Expand Down Expand Up @@ -460,13 +463,6 @@ pub mod stable_pool {
Ok((token_out_amount, fee))
}

/// This method is for internal use only
/// - calculates token_in amount
/// - calculates swap fee
/// - mints protocol fee
/// - updates reserves
/// It assumes that rates have been updated.
/// Returns (token_in_amount, swap_fee)
fn _swap_exact_out(
&mut self,
token_in: AccountId,
Expand Down Expand Up @@ -533,6 +529,13 @@ pub mod stable_pool {
Ok((token_in_amount, fee))
}

/// Handles PSP22 token transfer,
///
/// If `amount` is `Some(amount)`, transfer this amount of `token_id`
/// from the caller to this contract.
///
/// If `amount` of `None`, calculate the difference between
/// this contract balance and recorded reserve of `token_id`.
fn _transfer_in(
&self,
token_id: usize,
Expand Down Expand Up @@ -718,7 +721,7 @@ pub mod stable_pool {
let current_time = self.env().block_timestamp();
let mut rate_changed = false;
for rate in self.pool.token_rates.iter_mut() {
rate_changed = rate_changed || rate.update_rate_no_cache(current_time);
rate_changed = rate_changed | rate.update_rate_no_cache(current_time);
}
if rate_changed {
Self::env().emit_event(RatesUpdated {
Expand Down
17 changes: 13 additions & 4 deletions amm/contracts/stable_pool/token_rate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,33 @@ impl TokenRate {
rate
}

// To make sure the rate is up-to-date, the caller should call `update_rate` before calling this method.
/// Returns cached rate.
///
/// NOTE: To make sure the rate is up-to-date, the caller should call `update_rate` before calling this method.
pub fn get_rate(&self) -> u128 {
match self {
Self::Constant(rate) => *rate,
Self::External(external) => external.get_rate(),
}
}

/// Update rate.
///
/// Returns `true` if the rate was expired and value of the new rate is different than the previous.
pub fn update_rate(&mut self, current_time: u64) -> bool {
match self {
Self::External(external) => external.update_rate(current_time),
_ => false,
Self::Constant(_) => false,
}
}

/// 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 {
match self {
Self::External(external) => external.update_rate_no_cache(current_time),
_ => false,
Self::Constant(_) => false,
}
}
}
Expand Down Expand Up @@ -102,8 +110,9 @@ impl ExternalTokenRate {
}

fn update(&mut self, current_time: u64) -> bool {
let old_rate = self.cached_token_rate;
self.cached_token_rate = Self::query_rate(self.token_rate_contract);
self.last_token_rate_update_ts = current_time;
true
old_rate != self.cached_token_rate
}
}
12 changes: 6 additions & 6 deletions amm/traits/stable_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ pub trait StablePoolView {
fn token_rates(&mut self) -> Vec<u128>;

/// Calculate swap amount of token_out
/// given token_in amount
/// given token_in amount.
/// Returns (amount_out, fee)
/// fee is applied to token_out
/// NOTE: fee is applied to token_out
#[ink(message)]
fn get_swap_amount_out(
&mut self,
Expand Down Expand Up @@ -96,7 +96,7 @@ pub trait StablePool {
/// for this contract.
/// Returns an error if the minted LP tokens amount is less
/// than `min_share_amount`.
/// Returns (minted_shares, fee_part)
/// Returns (minted_share_amount, fee_part)
#[ink(message)]
fn add_liquidity(
&mut self,
Expand All @@ -118,7 +118,7 @@ pub trait StablePool {

/// Burns LP tokens and withdraws underlying tokens in balanced amounts to `to` account.
/// Fails if any of the amounts received is less than in `min_amounts`.
/// Returns ([amounts_by_tokens], fee_part)
/// Returns (amounts_out, fee_part)
#[ink(message)]
fn remove_liquidity_by_shares(
&mut self,
Expand Down Expand Up @@ -150,6 +150,7 @@ pub trait StablePool {
/// for this contract.
/// Returns an error if to get token_out_amount of token_out it is required
/// to spend more than `max_token_in_amount` of token_in.
/// NOTE: Fee is applied to `token_out`.
/// Returns (token_in_amount, fee_amount)
#[ink(message)]
fn swap_exact_out(
Expand All @@ -162,9 +163,8 @@ pub trait StablePool {
) -> Result<(u128, u128), StablePoolError>;

/// Swaps excess reserve balance of `token_in` to `token_out`.
///
/// Swapped tokens are transferred to the `to` account.
/// Returns (amount_out, fees)
/// Returns (token_out_amount, fee_amount)
#[ink(message)]
fn swap_received(
&mut self,
Expand Down
1 change: 1 addition & 0 deletions helpers/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ pub enum MathError {
DivByZero(u8),
MulOverflow(u8),
SubUnderflow(u8),
Precision(u8),
}
Loading
Loading