Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
26 changes: 26 additions & 0 deletions ref-exchange/src/fees.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use near_sdk::{env, AccountId};

/// Maintain information about fees.
pub struct SwapFees {
/// Basis points of the fee for exchange.
pub exchange_fee: u32,
/// Basis points of the fee for referrer.
pub referral_fee: u32,
pub exchange_id: AccountId,
pub referral_id: Option<AccountId>,
}

impl SwapFees {
pub fn new(exchange_fee: u32) -> Self {
SwapFees {
exchange_fee,
exchange_id: env::current_account_id(),
referral_fee: 0,
referral_id: None,
}
}

pub fn zero() -> Self {
Self::new(0)
}
}
73 changes: 51 additions & 22 deletions ref-exchange/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,31 @@ use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::collections::{LookupMap, UnorderedSet, Vector};
use near_sdk::json_types::{ValidAccountId, U128};
use near_sdk::{
assert_one_yocto, env, log, near_bindgen, AccountId, Balance, PanicOnDefault, Promise,
PromiseResult, StorageUsage, BorshStorageKey
assert_one_yocto, env, log, near_bindgen, AccountId, Balance, BorshStorageKey, PanicOnDefault,
Promise, PromiseResult, StorageUsage,
};

use crate::account_deposit::{VAccount, Account};
use crate::account_deposit::{Account, VAccount};
pub use crate::action::SwapAction;
use crate::action::{Action, ActionResult};
use crate::errors::*;
use crate::fees::SwapFees;
use crate::pool::Pool;
use crate::simple_pool::SimplePool;
use crate::stable_swap::StableSwapPool;
use crate::utils::check_token_duplicates;
pub use crate::views::PoolInfo;

mod account_deposit;
mod action;
mod errors;
mod fees;
mod legacy;
mod multi_fungible_token;
mod owner;
mod pool;
mod simple_pool;
mod stable_swap;
mod storage_impl;
mod token_receiver;
mod utils;
Expand Down Expand Up @@ -88,7 +92,23 @@ impl Contract {
)))
}

/// [AUDIT_03_reject(NOPE action is allowed by design)]
#[payable]
pub fn add_stable_swap_pool(
&mut self,
tokens: Vec<ValidAccountId>,
fee: u32,
amp_factor: u64,
) -> u64 {
check_token_duplicates(&tokens);
self.internal_add_pool(Pool::StableSwapPool(StableSwapPool::new(
self.pools.len() as u32,
tokens,
amp_factor as u128,
fee + self.exchange_fee + self.referral_fee,
)))
}

/// [AUDIT_03_reject(NOPE action is allowed by design)]
/// [AUDIT_04]
/// Executes generic set of actions.
/// If referrer provided, pays referral_fee to it.
Expand Down Expand Up @@ -157,7 +177,16 @@ impl Contract {
let mut amounts: Vec<u128> = amounts.into_iter().map(|amount| amount.into()).collect();
let mut pool = self.pools.get(pool_id).expect("ERR_NO_POOL");
// Add amounts given to liquidity first. It will return the balanced amounts.
pool.add_liquidity(&sender_id, &mut amounts);
pool.add_liquidity(
&sender_id,
&mut amounts,
SwapFees {
exchange_fee: self.exchange_fee,
exchange_id: self.owner_id.clone(),
referral_fee: 0,
referral_id: None,
},
);
if let Some(min_amounts) = min_amounts {
// Check that all amounts are above request min amounts in case of front running that changes the exchange rate.
for (amount, min_amount) in amounts.iter().zip(min_amounts.iter()) {
Expand Down Expand Up @@ -189,6 +218,12 @@ impl Contract {
.into_iter()
.map(|amount| amount.into())
.collect(),
SwapFees {
exchange_fee: self.exchange_fee,
exchange_id: self.owner_id.clone(),
referral_fee: 0,
referral_id: None,
},
);
self.pools.replace(pool_id, &pool);
let tokens = pool.tokens();
Expand All @@ -207,7 +242,6 @@ impl Contract {

/// Internal methods implementation.
impl Contract {

/// Check how much storage taken costs and refund the left over back.
fn internal_check_storage(&self, prev_storage: StorageUsage) {
let storage_cost = env::storage_usage()
Expand Down Expand Up @@ -297,8 +331,12 @@ impl Contract {
amount_in,
token_out,
min_amount_out,
&self.owner_id,
referral_id,
SwapFees {
exchange_fee: self.exchange_fee,
exchange_id: self.owner_id.clone(),
referral_fee: self.referral_fee,
referral_id: referral_id.clone(),
},
);
self.pools.replace(pool_id, &pool);
amount_out
Expand Down Expand Up @@ -745,7 +783,7 @@ mod tests {
// account(0) -- swap contract
// account(1) -- token0 contract
// account(2) -- token1 contract
// account(3) -- user account
// account(3) -- user account
// account(4) -- another user account
let (mut context, mut contract) = setup_contract();
deposit_tokens(
Expand All @@ -768,20 +806,14 @@ mod tests {
contract.mft_balance_of(":0".to_string(), accounts(3)).0,
to_yocto("1")
);
assert_eq!(
contract.mft_total_supply(":0".to_string()).0,
to_yocto("1")
);
assert_eq!(contract.mft_total_supply(":0".to_string()).0, to_yocto("1"));
testing_env!(context.attached_deposit(1).build());
contract.add_liquidity(id, vec![U128(to_yocto("50")), U128(to_yocto("50"))], None);
assert_eq!(
contract.mft_balance_of(":0".to_string(), accounts(3)).0,
to_yocto("2")
);
assert_eq!(
contract.mft_total_supply(":0".to_string()).0,
to_yocto("2")
);
assert_eq!(contract.mft_total_supply(":0".to_string()).0, to_yocto("2"));

// register another user
testing_env!(context
Expand All @@ -803,10 +835,7 @@ mod tests {
contract.mft_balance_of(":0".to_string(), accounts(4)).0,
to_yocto("1")
);
assert_eq!(
contract.mft_total_supply(":0".to_string()).0,
to_yocto("2")
);
assert_eq!(contract.mft_total_supply(":0".to_string()).0, to_yocto("2"));
// remove lpt for account 3
testing_env!(context
.predecessor_account_id(accounts(3))
Expand Down Expand Up @@ -859,7 +888,7 @@ mod tests {
// account(0) -- swap contract
// account(1) -- token0 contract
// account(2) -- token1 contract
// account(3) -- user account
// account(3) -- user account
let (mut context, mut contract) = setup_contract();
deposit_tokens(
&mut context,
Expand Down
29 changes: 29 additions & 0 deletions ref-exchange/src/owner.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Implement all the relevant logic for owner of this contract.

use near_sdk::json_types::WrappedTimestamp;

use crate::*;

#[near_bindgen]
Expand Down Expand Up @@ -49,6 +51,33 @@ impl Contract {
"ERR_NOT_ALLOWED"
);
}

pub fn stable_swap_ramp_amp(
&mut self,
pool_id: u64,
future_amp_factor: u64,
future_amp_time: WrappedTimestamp,
) {
self.assert_owner();
let mut pool = self.pools.get(pool_id).expect("ERR_NO_POOL");
match &mut pool {
Pool::StableSwapPool(pool) => {
pool.ramp_amplification(future_amp_factor as u128, future_amp_time.0)
}
_ => env::panic(b"ERR_NOT_STABLE_POOL"),
}
self.pools.replace(pool_id, &pool);
}

pub fn stable_swap_stop_ramp_amp(&mut self, pool_id: u64) {
let mut pool = self.pools.get(pool_id).expect("ERR_NO_POOL");
match &mut pool {
Pool::StableSwapPool(pool) => pool.stop_ramp_amplification(),
_ => env::panic(b"ERR_NOT_STABLE_POOL"),
}
self.assert_owner();
self.pools.replace(pool_id, &pool);
}
}

#[cfg(target_arch = "wasm32")]
Expand Down
42 changes: 31 additions & 11 deletions ref-exchange/src/pool.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,47 @@
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::{AccountId, Balance};

use crate::fees::SwapFees;
use crate::simple_pool::SimplePool;
use crate::stable_swap::StableSwapPool;
use crate::utils::SwapVolume;

/// Generic Pool, providing wrapper around different implementations of swap pools.
/// Allows to add new types of pools just by adding extra item in the enum without needing to migrate the storage.
#[derive(BorshSerialize, BorshDeserialize)]
pub enum Pool {
SimplePool(SimplePool),
StableSwapPool(StableSwapPool),
}

impl Pool {
/// Returns pool kind.
pub fn kind(&self) -> String {
match self {
Pool::SimplePool(_) => "SIMPLE_POOL".to_string(),
Pool::StableSwapPool(_) => "STABLE_SWAP".to_string(),
}
}

/// Returns which tokens are in the underlying pool.
pub fn tokens(&self) -> &[AccountId] {
match self {
Pool::SimplePool(pool) => pool.tokens(),
Pool::StableSwapPool(pool) => pool.tokens(),
}
}

/// Adds liquidity into underlying pool.
/// Updates amounts to amount kept in the pool.
pub fn add_liquidity(&mut self, sender_id: &AccountId, amounts: &mut Vec<Balance>) -> Balance {
pub fn add_liquidity(
&mut self,
sender_id: &AccountId,
amounts: &mut Vec<Balance>,
fees: SwapFees,
) -> Balance {
match self {
Pool::SimplePool(pool) => pool.add_liquidity(sender_id, amounts),
Pool::StableSwapPool(pool) => pool.add_liquidity(sender_id, amounts, &fees),
}
}

Expand All @@ -40,9 +51,13 @@ impl Pool {
sender_id: &AccountId,
shares: Balance,
min_amounts: Vec<Balance>,
fees: SwapFees,
) -> Vec<Balance> {
match self {
Pool::SimplePool(pool) => pool.remove_liquidity(sender_id, shares, min_amounts),
Pool::StableSwapPool(pool) => {
pool.remove_liquidity(sender_id, shares, min_amounts, &fees)
}
}
}

Expand All @@ -55,20 +70,24 @@ impl Pool {
) -> Balance {
match self {
Pool::SimplePool(pool) => pool.get_return(token_in, amount_in, token_out),
_ => 0
// Pool::StableSwapPool(pool) => pool.get_return(token_in, amount_in, token_out),
}
}

/// Returns given pool's total fee.
pub fn get_fee(&self) -> u32 {
match self {
Pool::SimplePool(pool) => pool.get_fee(),
Pool::StableSwapPool(pool) => pool.get_fee(),
}
}

/// Returns volumes of the given pool.
pub fn get_volumes(&self) -> Vec<SwapVolume> {
match self {
Pool::SimplePool(pool) => pool.get_volumes(),
Pool::StableSwapPool(pool) => pool.get_volumes(),
}
}

Expand All @@ -79,42 +98,43 @@ impl Pool {
amount_in: Balance,
token_out: &AccountId,
min_amount_out: Balance,
exchange_id: &AccountId,
referral_id: &Option<AccountId>,
fees: SwapFees,
) -> Balance {
match self {
Pool::SimplePool(pool) => pool.swap(
token_in,
amount_in,
token_out,
min_amount_out,
exchange_id,
referral_id,
),
Pool::SimplePool(pool) => {
pool.swap(token_in, amount_in, token_out, min_amount_out, fees)
}
Pool::StableSwapPool(pool) => {
pool.swap(token_in, amount_in, token_out, min_amount_out, &fees)
}
}
}

pub fn share_total_balance(&self) -> Balance {
match self {
Pool::SimplePool(pool) => pool.share_total_balance(),
Pool::StableSwapPool(pool) => pool.share_total_balance(),
}
}

pub fn share_balances(&self, account_id: &AccountId) -> Balance {
match self {
Pool::SimplePool(pool) => pool.share_balance_of(account_id),
Pool::StableSwapPool(pool) => pool.share_balance_of(account_id),
}
}

pub fn share_transfer(&mut self, sender_id: &AccountId, receiver_id: &AccountId, amount: u128) {
match self {
Pool::SimplePool(pool) => pool.share_transfer(sender_id, receiver_id, amount),
Pool::StableSwapPool(pool) => pool.share_transfer(sender_id, receiver_id, amount),
}
}

pub fn share_register(&mut self, account_id: &AccountId) {
match self {
Pool::SimplePool(pool) => pool.share_register(account_id),
Pool::StableSwapPool(pool) => pool.share_register(account_id),
}
}
}
Loading