Skip to content

Commit

Permalink
feat: swap fee
Browse files Browse the repository at this point in the history
  • Loading branch information
veeso committed Jan 25, 2024
1 parent d9ab6d1 commit 0d74f11
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 0 deletions.
1 change: 1 addition & 0 deletions integration-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ impl TestEnv {
cketh_minter_canister,
erc20_bridge_address: H160::from_hex_str("0x2CE04Fd64DB0372F6fb4B7a542f0F9196feE5663")
.unwrap(),
erc20_swap_fee: 178_180_000_000_000,
};
let init_arg = Encode!(&init_arg).unwrap();

Expand Down
2 changes: 2 additions & 0 deletions src/declarations/fly/fly.did.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export interface FlyInitData {
'ckbtc_canister' : Principal,
'erc20_bridge_address' : string,
'initial_balances' : Array<[Account, bigint]>,
'erc20_swap_fee' : bigint,
'swap_account' : Account,
'xrc_canister' : Principal,
'marketplace_canister' : Principal,
Expand Down Expand Up @@ -154,6 +155,7 @@ export interface _SERVICE {
'admin_set_cketh_ledger_canister' : ActorMethod<[Principal], undefined>,
'admin_set_cketh_minter_canister' : ActorMethod<[Principal], undefined>,
'admin_set_erc20_bridge_address' : ActorMethod<[string], undefined>,
'admin_set_erc20_swap_fee' : ActorMethod<[bigint], undefined>,
'admin_set_icp_ledger_canister' : ActorMethod<[Principal], undefined>,
'admin_set_role' : ActorMethod<[Principal, Role], undefined>,
'admin_set_swap_account' : ActorMethod<[Account], undefined>,
Expand Down
3 changes: 3 additions & 0 deletions src/declarations/fly/fly.did.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const idlFactory = ({ IDL }) => {
'ckbtc_canister' : IDL.Principal,
'erc20_bridge_address' : IDL.Text,
'initial_balances' : IDL.Vec(IDL.Tuple(Account, IDL.Nat)),
'erc20_swap_fee' : IDL.Nat64,
'swap_account' : Account,
'xrc_canister' : IDL.Principal,
'marketplace_canister' : IDL.Principal,
Expand Down Expand Up @@ -182,6 +183,7 @@ export const idlFactory = ({ IDL }) => {
'admin_set_cketh_ledger_canister' : IDL.Func([IDL.Principal], [], []),
'admin_set_cketh_minter_canister' : IDL.Func([IDL.Principal], [], []),
'admin_set_erc20_bridge_address' : IDL.Func([IDL.Text], [], []),
'admin_set_erc20_swap_fee' : IDL.Func([IDL.Nat64], [], []),
'admin_set_icp_ledger_canister' : IDL.Func([IDL.Principal], [], []),
'admin_set_role' : IDL.Func([IDL.Principal, Role], [], []),
'admin_set_swap_account' : IDL.Func([Account], [], []),
Expand Down Expand Up @@ -231,6 +233,7 @@ export const init = ({ IDL }) => {
'ckbtc_canister' : IDL.Principal,
'erc20_bridge_address' : IDL.Text,
'initial_balances' : IDL.Vec(IDL.Tuple(Account, IDL.Nat)),
'erc20_swap_fee' : IDL.Nat64,
'swap_account' : Account,
'xrc_canister' : IDL.Principal,
'marketplace_canister' : IDL.Principal,
Expand Down
2 changes: 2 additions & 0 deletions src/did/src/fly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ pub struct FlyInitData {
pub cketh_minter_canister: Principal,
/// The Ethereum address of the ERC20 bridge
pub erc20_bridge_address: H160,
/// Initial ERC20 swap fee
pub erc20_swap_fee: u64,
/// Total supply of $picofly tokens
pub total_supply: PicoFly,
/// Initial balances (wallet subaccount -> picofly)
Expand Down
2 changes: 2 additions & 0 deletions src/fly/fly.did
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ type FlyInitData = record {
ckbtc_canister : principal;
erc20_bridge_address : text;
initial_balances : vec record { Account; nat };
erc20_swap_fee : nat64;
swap_account : Account;
xrc_canister : principal;
marketplace_canister : principal;
Expand Down Expand Up @@ -141,6 +142,7 @@ service : (FlyInitData) -> {
admin_set_cketh_ledger_canister : (principal) -> ();
admin_set_cketh_minter_canister : (principal) -> ();
admin_set_erc20_bridge_address : (text) -> ();
admin_set_erc20_swap_fee : (nat64) -> ();
admin_set_icp_ledger_canister : (principal) -> ();
admin_set_role : (principal, Role) -> ();
admin_set_swap_account : (Account) -> ();
Expand Down
22 changes: 22 additions & 0 deletions src/fly/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
mod balance;
mod configuration;
mod erc20_bridge;
mod inspect;
mod liquidity_pool;
mod memory;
Expand All @@ -28,6 +29,7 @@ use icrc::icrc2::{self, Icrc2};

use self::balance::Balance;
use self::configuration::Configuration;
use self::erc20_bridge::Erc20Bridge;
pub use self::inspect::Inspect;
use self::liquidity_pool::LiquidityPool;
use self::pool::Pool;
Expand Down Expand Up @@ -55,6 +57,8 @@ impl FlyCanister {
Configuration::set_cketh_minter_canister(data.cketh_minter_canister);
// set ERC20 bridge address
Configuration::set_erc20_bridge_address(data.erc20_bridge_address);
// Set initial swap fee
Erc20Bridge::set_swap_fee(data.erc20_swap_fee).unwrap();
// init liquidity pool
LiquidityPool::init();
// set roles
Expand Down Expand Up @@ -244,6 +248,14 @@ impl FlyCanister {
}
Configuration::set_erc20_bridge_address(address);
}

/// Set ERC20 swap fee
pub fn admin_set_erc20_swap_fee(fee: u64) {
if !Inspect::inspect_is_admin(utils::caller()) {
ic_cdk::trap("Unauthorized");
}
Erc20Bridge::set_swap_fee(fee).unwrap()
}
}

impl Icrc1 for FlyCanister {
Expand Down Expand Up @@ -511,6 +523,7 @@ mod test {
use crate::utils::caller;

const ERC20_BRIDGE_ADDRESS: &str = "0x2CE04Fd64DB0372F6fb4B7a542f0F9196feE5663";
const ERC20_SWAP_FEE: u64 = 178_180_000_000_000;

#[tokio::test]
async fn test_should_init_canister() {
Expand Down Expand Up @@ -558,6 +571,7 @@ mod test {
Configuration::get_erc20_bridge_address(),
H160::from_hex_str(ERC20_BRIDGE_ADDRESS).unwrap()
);
assert_eq!(Erc20Bridge::get_swap_fee(), ERC20_SWAP_FEE);
}

#[tokio::test]
Expand Down Expand Up @@ -832,6 +846,13 @@ mod test {
assert_eq!(Configuration::get_erc20_bridge_address(), address);
}

#[test]
fn test_should_set_erc20_swap_fee() {
init_canister();
FlyCanister::admin_set_erc20_swap_fee(10);
assert_eq!(Erc20Bridge::get_swap_fee(), 10);
}

#[tokio::test]
async fn test_should_get_balance_of() {
init_canister();
Expand Down Expand Up @@ -1211,6 +1232,7 @@ mod test {
cketh_minter_canister: caller(),
cketh_ledger_canister: caller(),
erc20_bridge_address: H160::from_hex_str(ERC20_BRIDGE_ADDRESS).unwrap(),
erc20_swap_fee: ERC20_SWAP_FEE,
};
FlyCanister::init(data);
}
Expand Down
20 changes: 20 additions & 0 deletions src/fly/src/app/erc20_bridge.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
mod swap_fee;

use did::fly::FlyResult;

use self::swap_fee::SwapFee;

/// ERC20 Bridge
pub struct Erc20Bridge;

impl Erc20Bridge {
/// Returns the swap fee.
pub fn get_swap_fee() -> u64 {
SwapFee::get_swap_fee()
}

/// Sets the swap fee.
pub fn set_swap_fee(swap_fee: u64) -> FlyResult<()> {
SwapFee::set_swap_fee(swap_fee)
}
}
74 changes: 74 additions & 0 deletions src/fly/src/app/erc20_bridge/swap_fee.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use std::cell::RefCell;

use did::fly::{FlyError, FlyResult};
use ic_stable_structures::memory_manager::VirtualMemory;
use ic_stable_structures::{DefaultMemoryImpl, StableCell};

use crate::app::memory::{
ERC20_SWAP_FEE_LAST_UPDATE_MEMORY_ID, ERC20_SWAP_FEE_MEMORY_ID, MEMORY_MANAGER,
};
use crate::utils::time;

thread_local! {

static SWAP_FEE: RefCell<StableCell<u64, VirtualMemory<DefaultMemoryImpl>>> =
RefCell::new(
StableCell::new(
MEMORY_MANAGER.with(|mm| mm.get(ERC20_SWAP_FEE_MEMORY_ID)),
0_u64,
).unwrap()
);

static LAST_SWAP_FEE_UPDATE : RefCell<StableCell<u64, VirtualMemory<DefaultMemoryImpl>>> =
RefCell::new(
StableCell::new(
MEMORY_MANAGER.with(|mm| mm.get(ERC20_SWAP_FEE_LAST_UPDATE_MEMORY_ID)),
0_u64,
).unwrap()
);

}

/// Swap fee for ERC20 token swaps.
pub struct SwapFee;

impl SwapFee {
/// Returns the swap fee.
pub fn get_swap_fee() -> u64 {
SWAP_FEE.with(|sf| *sf.borrow().get())
}

/// Sets the swap fee and update last swap fee update.
pub fn set_swap_fee(swap_fee: u64) -> FlyResult<()> {
SWAP_FEE
.with_borrow_mut(|sf| sf.set(swap_fee))
.map_err(|_| FlyError::StorageError)?;

LAST_SWAP_FEE_UPDATE
.with_borrow_mut(|lsfu| lsfu.set(time()).map_err(|_| FlyError::StorageError))?;

Ok(())
}
}

#[cfg(test)]
mod test {

use pretty_assertions::{assert_eq, assert_ne};

use super::*;

#[test]
fn test_swap_fee() {
assert_eq!(SwapFee::get_swap_fee(), 0);
assert_eq!(LAST_SWAP_FEE_UPDATE.with(|lsfu| *lsfu.borrow().get()), 0);

SwapFee::set_swap_fee(100).unwrap();
assert_eq!(SwapFee::get_swap_fee(), 100);

SwapFee::set_swap_fee(200).unwrap();
assert_eq!(SwapFee::get_swap_fee(), 200);

assert_ne!(LAST_SWAP_FEE_UPDATE.with(|lsfu| *lsfu.borrow().get()), 0);
}
}
1 change: 1 addition & 0 deletions src/fly/src/app/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub const LIQUIDITY_POOL_CKBTC_ACCOUNT_MEMORY_ID: MemoryId = MemoryId::new(41);
pub const FLY_CANISTER_ETH_ADDRESS_MEMORY_ID: MemoryId = MemoryId::new(50);
pub const ERC20_SWAP_POOL_ACCOUNT_MEMORY_ID: MemoryId = MemoryId::new(51);
pub const ERC20_SWAP_FEE_MEMORY_ID: MemoryId = MemoryId::new(52);
pub const ERC20_SWAP_FEE_LAST_UPDATE_MEMORY_ID: MemoryId = MemoryId::new(53);

thread_local! {
/// Memory manager
Expand Down
6 changes: 6 additions & 0 deletions src/fly/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ pub fn admin_set_erc20_bridge_address(address: H160) {
FlyCanister::admin_set_erc20_bridge_address(address)
}

#[update]
#[candid_method(update)]
pub fn admin_set_erc20_swap_fee(fee: u64) {
FlyCanister::admin_set_erc20_swap_fee(fee)
}

#[query]
#[candid_method(query)]
pub fn get_transaction(id: u64) -> FlyResult<Transaction> {
Expand Down

0 comments on commit 0d74f11

Please sign in to comment.