Skip to content

Commit

Permalink
Merge pull request #23 from Cardinal-Cryptography/post-audit
Browse files Browse the repository at this point in the history
Post audit changes
  • Loading branch information
JanKuczma authored Jul 8, 2024
2 parents a9ae434 + 9c39965 commit 852dde8
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 90 deletions.
43 changes: 23 additions & 20 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.update_rate(current_time) | rate_changed;
}
if rate_changed {
Self::env().emit_event(RatesUpdated {
Expand All @@ -303,6 +311,8 @@ pub mod stable_pool {
/// 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
Expand Down Expand Up @@ -344,7 +354,9 @@ 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 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() {
let protocol_fee = self.pool.fees.protocol_trade_fee(fee)?;
Expand Down Expand Up @@ -394,13 +406,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 +465,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 +531,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 +723,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.update_rate_no_cache(current_time) | rate_changed;
}
if rate_changed {
Self::env().emit_event(RatesUpdated {
Expand Down Expand Up @@ -829,8 +834,6 @@ pub mod stable_pool {
self.pool.tokens.clone()
}

// This can output values lower than the actual balances of these tokens, which stems from roundings.
// However an invariant holds that each balance is at least the value returned by this function.
#[ink(message)]
fn reserves(&self) -> Vec<u128> {
self.pool.reserves.clone()
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

0 comments on commit 852dde8

Please sign in to comment.