From 57b5506aa1ec703c20bc044a4e5980097e7024c6 Mon Sep 17 00:00:00 2001 From: Iddriss Raaj Date: Sun, 22 Oct 2023 04:52:08 +0000 Subject: [PATCH] add fee tier --- Scarb.toml | 4 +- src/dex/v1/factory/factory.cairo | 52 ++++-- src/dex/v1/factory/interface.cairo | 40 +++-- src/dex/v1/pair/Pair.cairo | 11 +- src/dex/v1/pair/interface.cairo | 3 + src/dex/v1/router/interface.cairo | 3 + src/dex/v1/router/router.cairo | 50 ++++-- src/tests/factory/test_factory.cairo | 37 ++-- src/tests/pair/test_pair_shared.cairo | 47 ++--- src/tests/pair/test_stable_pair.cairo | 20 ++- src/tests/pair/test_volatile_pair.cairo | 19 +- src/tests/router/test_router.cairo | 227 ++++++++++++++++-------- 12 files changed, 336 insertions(+), 177 deletions(-) diff --git a/Scarb.toml b/Scarb.toml index 071762f..2ced998 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -1,6 +1,6 @@ [package] name = "starkDefi" -version = "1.0.0" +version = "1.1.0" [[target.starknet-contract]] allowed-libfuncs-list.name = "experimental" @@ -11,8 +11,6 @@ casm = true starknet = ">=2.1.1" # snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.4.1" } - - [tool.snforge] exit_first = true diff --git a/src/dex/v1/factory/factory.cairo b/src/dex/v1/factory/factory.cairo index a4414c3..e35a1e0 100644 --- a/src/dex/v1/factory/factory.cairo +++ b/src/dex/v1/factory/factory.cairo @@ -16,8 +16,8 @@ struct Config { /// @dev Structure for holding fee information #[derive(Copy, Drop, Serde, starknet::Store)] struct Fees { - stable: u256, - volatile: u256, + stable: u8, + volatile: u8, } /// @dev Structure for validating a pair @@ -25,15 +25,16 @@ struct Fees { struct ValidPair { is_valid: bool, is_stable: bool, - custom_fee: u256, + custom_fee: u8, } -const MAX_FEE: u256 = 100; // 1% +const MAX_FEE: u8 = 100; // 1% #[starknet::contract] mod StarkDFactory { use starkDefi::dex::v1::factory::interface::IStarkDFactory; use array::ArrayTrait; + use traits::Into; use super::{Config, Fees, ValidPair, MAX_FEE, ContractAddress, ClassHash}; use starknet::{get_caller_address, contract_address_to_felt252}; use zeroable::Zeroable; @@ -69,7 +70,7 @@ mod StarkDFactory { pair: ContractAddress, #[key] stable: bool, - fee: u256, + fee: u8, } #[derive(Drop, starknet::Event)] @@ -88,7 +89,7 @@ mod StarkDFactory { fees: Fees, paused: bool, protocol_fee_on: bool, - _pair: LegacyMap::<(ContractAddress, ContractAddress, bool), ContractAddress>, + _pair: LegacyMap::<(ContractAddress, ContractAddress, bool, u8), ContractAddress>, _all_pairs: LegacyMap::, valid_pairs: LegacyMap::, _all_pairs_length: u32, @@ -139,16 +140,20 @@ mod StarkDFactory { /// @notice Get pair contract address given tokenA, tokenB and a bool representing stable or volatile /// @returns address of the pair fn get_pair( - self: @ContractState, tokenA: ContractAddress, tokenB: ContractAddress, stable: bool + self: @ContractState, + tokenA: ContractAddress, + tokenB: ContractAddress, + stable: bool, + fee: u8 ) -> ContractAddress { let (token0, token1) = self.sort_tokens(tokenA, tokenB); - let pair = self._pair.read((token0, token1, stable)); + let pair = self._pair.read((token0, token1, stable, fee)); pair } /// @notice Get global fees - /// @returns stable u256 and volatile u256 fees - fn get_fees(self: @ContractState) -> (u256, u256) { + /// @returns stable u8 and volatile u8 fees + fn get_fees(self: @ContractState) -> (u8, u8) { let fees = self.fees.read(); (fees.stable, fees.volatile) } @@ -161,7 +166,7 @@ mod StarkDFactory { /// @notice Get fee for a pair /// @returns fee - fn get_fee(self: @ContractState, pair: ContractAddress) -> u256 { + fn get_fee(self: @ContractState, pair: ContractAddress) -> u8 { let pair_info = self.valid_pairs.read(pair); assert(pair_info.is_valid, 'invalid pair'); let is_stable = pair_info.is_stable; @@ -215,15 +220,20 @@ mod StarkDFactory { /// @param tokenB ContractAddress of tokenB /// @return pair ContractAddress of the new pair fn create_pair( - ref self: ContractState, tokenA: ContractAddress, tokenB: ContractAddress, stable: bool + ref self: ContractState, + tokenA: ContractAddress, + tokenB: ContractAddress, + stable: bool, + fee: u8 ) -> ContractAddress { assert(tokenA.is_non_zero() && tokenB.is_non_zero(), 'invalid token address'); assert(tokenA != tokenB, 'identical addresses'); + assert(fee.into() <= MAX_FEE, 'fee too high'); let config = self.config.read(); let vault_class_hash = config.vault_class_hash; - let found_pair = self.get_pair(tokenA, tokenB, stable); + let found_pair = self.get_pair(tokenA, tokenB, stable, fee); assert(found_pair.is_zero(), 'pair exists'); let (token0, token1) = self.sort_tokens(tokenA, tokenB); @@ -232,9 +242,15 @@ mod StarkDFactory { Serde::serialize(@token0, ref pair_constructor_calldata); Serde::serialize(@token1, ref pair_constructor_calldata); Serde::serialize(@stable, ref pair_constructor_calldata); + Serde::serialize(@fee, ref pair_constructor_calldata); Serde::serialize(@vault_class_hash, ref pair_constructor_calldata); - let token0_felt252 = contract_address_to_felt252(token0); + let token0_felt252 = contract_address_to_felt252(token0) + + if (fee > 0) { + fee.into() + } else { + 0 + }; let token1_stable_felt252 = contract_address_to_felt252(token1) + if stable { 1 @@ -249,12 +265,12 @@ mod StarkDFactory { ) .unwrap_syscall(); // deploy_syscall never panics - self._pair.write((token0, token1, stable), pair); + self._pair.write((token0, token1, stable, fee), pair); let pair_count = self._all_pairs_length.read(); self._all_pairs.write(pair_count, pair); self .valid_pairs - .write(pair, ValidPair { is_valid: true, is_stable: stable, custom_fee: 0 }); + .write(pair, ValidPair { is_valid: true, is_stable: stable, custom_fee: fee }); self._all_pairs_length.write(pair_count + 1); self @@ -280,7 +296,7 @@ mod StarkDFactory { /// @notice Set universal fee /// @param fee u256, must be less than MAX_FEE /// @param stable bool - fn set_fee(ref self: ContractState, fee: u256, stable: bool) { + fn set_fee(ref self: ContractState, fee: u8, stable: bool) { Modifiers::assert_only_handler(@self); assert(fee <= MAX_FEE && fee > 0, 'invalid fee'); let mut fees = self.fees.read(); @@ -296,7 +312,7 @@ mod StarkDFactory { /// @param pair ContractAddress of pair /// @param fee u256, must be less than MAX_FEE /// @param stable bool - fn set_custom_pair_fee(ref self: ContractState, pair: ContractAddress, fee: u256) { + fn set_custom_pair_fee(ref self: ContractState, pair: ContractAddress, fee: u8) { Modifiers::assert_only_handler(@self); assert(fee <= MAX_FEE, 'fee too high'); let mut pair_info = self.valid_pairs.read(pair); diff --git a/src/dex/v1/factory/interface.cairo b/src/dex/v1/factory/interface.cairo index e17bf43..4c50491 100644 --- a/src/dex/v1/factory/interface.cairo +++ b/src/dex/v1/factory/interface.cairo @@ -6,23 +6,31 @@ trait IStarkDFactory { fn fee_handler(self: @TContractState) -> ContractAddress; fn get_pair( - self: @TContractState, tokenA: ContractAddress, tokenB: ContractAddress, stable: bool + self: @TContractState, + tokenA: ContractAddress, + tokenB: ContractAddress, + stable: bool, + fee: u8 ) -> ContractAddress; - fn get_fees(self: @TContractState) -> (u256, u256); + fn get_fees(self: @TContractState) -> (u8, u8); fn protocol_fee_on(self: @TContractState) -> bool; - fn get_fee(self: @TContractState, pair: ContractAddress) -> u256; + fn get_fee(self: @TContractState, pair: ContractAddress) -> u8; fn valid_pair(self: @TContractState, pair: ContractAddress) -> bool; fn all_pairs(self: @TContractState) -> (u32, Array::); fn all_pairs_length(self: @TContractState) -> u32; fn class_hash_for_pair_contract(self: @TContractState) -> ClassHash; fn create_pair( - ref self: TContractState, tokenA: ContractAddress, tokenB: ContractAddress, stable: bool + ref self: TContractState, + tokenA: ContractAddress, + tokenB: ContractAddress, + stable: bool, + fee: u8 ) -> ContractAddress; fn set_fee_to(ref self: TContractState, fee_to: ContractAddress); - fn set_fee(ref self: TContractState, fee: u256, stable: bool); - fn set_custom_pair_fee(ref self: TContractState, pair: ContractAddress, fee: u256); + fn set_fee(ref self: TContractState, fee: u8, stable: bool); + fn set_custom_pair_fee(ref self: TContractState, pair: ContractAddress, fee: u8); fn set_fee_handler(ref self: TContractState, handler_address: ContractAddress); } @@ -32,23 +40,31 @@ trait IStarkDFactoryABI { fn fee_handler(self: @TContractState) -> ContractAddress; fn get_pair( - self: @TContractState, tokenA: ContractAddress, tokenB: ContractAddress, stable: bool + self: @TContractState, + tokenA: ContractAddress, + tokenB: ContractAddress, + stable: bool, + fee: u8 ) -> ContractAddress; - fn get_fees(self: @TContractState) -> (u256, u256); + fn get_fees(self: @TContractState) -> (u8, u8); fn protocol_fee_on(self: @TContractState) -> bool; - fn get_fee(self: @TContractState, pair: ContractAddress) -> u256; + fn get_fee(self: @TContractState, pair: ContractAddress) -> u8; fn valid_pair(self: @TContractState, pair: ContractAddress) -> bool; fn all_pairs(self: @TContractState) -> (u32, Array::); fn all_pairs_length(self: @TContractState) -> u32; fn class_hash_for_pair_contract(self: @TContractState) -> ClassHash; fn create_pair( - ref self: TContractState, tokenA: ContractAddress, tokenB: ContractAddress, stable: bool + ref self: TContractState, + tokenA: ContractAddress, + tokenB: ContractAddress, + stable: bool, + fee: u8 ) -> ContractAddress; fn set_fee_to(ref self: TContractState, fee_to: ContractAddress); - fn set_fee(ref self: TContractState, fee: u256, stable: bool); - fn set_custom_pair_fee(ref self: TContractState, pair: ContractAddress, fee: u256); + fn set_fee(ref self: TContractState, fee: u8, stable: bool); + fn set_custom_pair_fee(ref self: TContractState, pair: ContractAddress, fee: u8); fn set_fee_handler(ref self: TContractState, handler_address: ContractAddress); fn set_pair_contract_class(ref self: TContractState, class_hash_pair_contract: ClassHash); fn set_vault_contract_class(ref self: TContractState, vault_class_hash: ClassHash); diff --git a/src/dex/v1/pair/Pair.cairo b/src/dex/v1/pair/Pair.cairo index edea618..be46f15 100644 --- a/src/dex/v1/pair/Pair.cairo +++ b/src/dex/v1/pair/Pair.cairo @@ -11,6 +11,7 @@ struct Config { factory: ContractAddress, vault: ContractAddress, stable: bool, + fee_tier: u8, decimal0: u256, decimal1: u256, } @@ -137,6 +138,7 @@ mod StarkDPair { tokenA: ContractAddress, tokenB: ContractAddress, stable: bool, + fee_tier: u8, vault_class_hash: ClassHash ) { assert(tokenA.is_non_zero() && tokenB.is_non_zero(), 'invalid address'); @@ -161,6 +163,7 @@ mod StarkDPair { factory: factory, vault: vault, stable: stable, + fee_tier: fee_tier, decimal0: u256 { low: pow(10, decimal0), high: 0 }, decimal1: u256 { @@ -218,6 +221,10 @@ mod StarkDPair { self.config.read().token1 } + fn fee_tier(self: @ContractState) -> u8 { + self.config.read().fee_tier + } + /// @notice Returns the address of the fee vault. /// @return the address of the fee vault. @@ -543,7 +550,7 @@ mod StarkDPair { assert(reserve0 > 0 && reserve1 > 0, 'insufficient liquidity'); let pool_fee = IStarkDFactoryABIDispatcher { contract_address: self.factory() - }.get_fee(get_contract_address()); + }.get_fee(get_contract_address()).into(); let _amount_in = amountIn - ((amountIn * pool_fee) / FEE_DENOMINATOR); @@ -682,7 +689,7 @@ mod StarkDPair { let pair = get_contract_address(); let factory = IStarkDFactoryABIDispatcher { contract_address: self.factory() }; - let swap_fee = factory.get_fee(pair); + let swap_fee = factory.get_fee(pair).into(); let protocol_fee_on = factory.protocol_fee_on(); if (amount0In > 0) { diff --git a/src/dex/v1/pair/interface.cairo b/src/dex/v1/pair/interface.cairo index 082aa84..1172f2c 100644 --- a/src/dex/v1/pair/interface.cairo +++ b/src/dex/v1/pair/interface.cairo @@ -50,6 +50,7 @@ trait IStarkDPair { fn factory(self: @TContractState) -> ContractAddress; fn token0(self: @TContractState) -> ContractAddress; fn token1(self: @TContractState) -> ContractAddress; + fn fee_tier(self: @TContractState) -> u8; fn fee_vault(self: @TContractState) -> ContractAddress; fn snapshot(self: @TContractState) -> Snapshot; fn get_reserves(self: @TContractState) -> (u256, u256, u64); @@ -117,6 +118,7 @@ trait IStarkDPairABI { fn factory(self: @TContractState) -> ContractAddress; fn token0(self: @TContractState) -> ContractAddress; fn token1(self: @TContractState) -> ContractAddress; + fn fee_tier(self: @TContractState) -> u8; fn fee_vault(self: @TContractState) -> ContractAddress; fn snapshot(self: @TContractState) -> Snapshot; fn get_reserves(self: @TContractState) -> (u256, u256, u64); @@ -165,6 +167,7 @@ trait IStarkDPairCamelABI { fn factory(self: @TContractState) -> ContractAddress; fn token0(self: @TContractState) -> ContractAddress; fn token1(self: @TContractState) -> ContractAddress; + fn fee_tier(self: @TContractState) -> u8; fn feeVault(self: @TContractState) -> ContractAddress; fn snapshot(self: @TContractState) -> Snapshot; fn getReserves(self: @TContractState) -> (u256, u256, u64); diff --git a/src/dex/v1/router/interface.cairo b/src/dex/v1/router/interface.cairo index 20d433d..0bf81ab 100644 --- a/src/dex/v1/router/interface.cairo +++ b/src/dex/v1/router/interface.cairo @@ -5,6 +5,7 @@ struct SwapPath { tokenIn: ContractAddress, tokenOut: ContractAddress, stable: bool, + feeTier: u8, } #[starknet::interface] @@ -23,6 +24,7 @@ trait IStarkDRouter { tokenA: ContractAddress, tokenB: ContractAddress, stable: bool, + feeTier: u8, amountADesired: u256, amountBDesired: u256, amountAMin: u256, @@ -35,6 +37,7 @@ trait IStarkDRouter { tokenA: ContractAddress, tokenB: ContractAddress, stable: bool, + feeTier: u8, liquidity: u256, amountAMin: u256, amountBMin: u256, diff --git a/src/dex/v1/router/router.cairo b/src/dex/v1/router/router.cairo index 7a5b0aa..4e0b678 100644 --- a/src/dex/v1/router/router.cairo +++ b/src/dex/v1/router/router.cairo @@ -95,6 +95,7 @@ mod StarkDRouter { tokenA: ContractAddress, tokenB: ContractAddress, stable: bool, + feeTier: u8, amountADesired: u256, amountBDesired: u256, amountAMin: u256, @@ -109,12 +110,13 @@ mod StarkDRouter { tokenA, tokenB, stable, + feeTier, amountADesired, amountBDesired, amountAMin, amountBMin ); - let pair = InternalFunctions::_pair_for(factory, tokenA, tokenB, stable); + let pair = InternalFunctions::_pair_for(factory, tokenA, tokenB, stable, feeTier); let sender = get_caller_address(); InternalFunctions::_transfer_token_from(tokenA, sender, pair, amountA); @@ -140,6 +142,7 @@ mod StarkDRouter { tokenA: ContractAddress, tokenB: ContractAddress, stable: bool, + feeTier: u8, liquidity: u256, amountAMin: u256, amountBMin: u256, @@ -149,7 +152,7 @@ mod StarkDRouter { Modifiers::_ensure(deadline); let factory = self._factory.read(); - let pair = InternalFunctions::_pair_for(factory, tokenA, tokenB, stable); + let pair = InternalFunctions::_pair_for(factory, tokenA, tokenB, stable, feeTier); let sender = get_caller_address(); InternalFunctions::_transfer_token_from(pair, sender, pair, liquidity); @@ -195,7 +198,7 @@ mod StarkDRouter { let _route = _path.pop_front().unwrap(); let pair = InternalFunctions::_pair_for( - factory, _route.tokenIn, _route.tokenOut, _route.stable + factory, _route.tokenIn, _route.tokenOut, _route.stable, _route.feeTier ); let sender = get_caller_address(); @@ -224,7 +227,7 @@ mod StarkDRouter { let _route = _path.pop_front().unwrap(); let factory = self._factory.read(); let pair = InternalFunctions::_pair_for( - factory, _route.tokenIn, _route.tokenOut, _route.stable + factory, _route.tokenIn, _route.tokenOut, _route.stable, _route.feeTier ); let sender = get_caller_address(); @@ -307,6 +310,7 @@ mod StarkDRouter { tokenA: ContractAddress, tokenB: ContractAddress, stable: bool, + feeTier: u8, amountADesired: u256, amountBDesired: u256, amountAMin: u256, @@ -315,14 +319,14 @@ mod StarkDRouter { let factory = self._factory.read(); let factoryDispatcher = IStarkDFactoryABIDispatcher { contract_address: factory }; - let pair = factoryDispatcher.get_pair(tokenA, tokenB, stable); + let pair = factoryDispatcher.get_pair(tokenA, tokenB, stable, feeTier); if (pair == contract_address_const::<0>()) { - factoryDispatcher.create_pair(tokenA, tokenB, stable); + factoryDispatcher.create_pair(tokenA, tokenB, stable, feeTier); } let (reserveA, reserveB) = InternalFunctions::_get_reserves( - factory, tokenA, tokenB, stable + factory, tokenA, tokenB, stable, feeTier ); if (reserveA == 0 && reserveB == 0) { @@ -385,7 +389,7 @@ mod StarkDRouter { let _next: SwapPath = *path[index + 1]; InternalFunctions::_pair_for( - factory, _next.tokenIn, _next.tokenOut, _next.stable + factory, _next.tokenIn, _next.tokenOut, _next.stable, _next.feeTier ) } else { _to @@ -393,7 +397,11 @@ mod StarkDRouter { IStarkDPairDispatcher { contract_address: InternalFunctions::_pair_for( - factory, *route.tokenIn, *route.tokenOut, *route.stable + factory, + *route.tokenIn, + *route.tokenOut, + *route.stable, + *route.feeTier ) }.swap(amount0Out, amount1Out, to, ArrayTrait::::new()); @@ -428,13 +436,13 @@ mod StarkDRouter { *route.tokenIn, *route.tokenOut ); let pair = InternalFunctions::_pair_for( - factory, *route.tokenIn, *route.tokenOut, *route.stable + factory, *route.tokenIn, *route.tokenOut, *route.stable, *route.feeTier ); let pairDispatcher = IStarkDPairDispatcher { contract_address: pair }; let (reserveA, _) = InternalFunctions::_get_reserves( - factory, *route.tokenIn, *route.tokenOut, *route.stable + factory, *route.tokenIn, *route.tokenOut, *route.stable, *route.feeTier ); let balance_tokenIn = InternalFunctions::_balance_of(*route.tokenIn, pair); @@ -451,7 +459,7 @@ mod StarkDRouter { let to = if index < path.len() - 1 { let _next: SwapPath = *path[index + 1]; InternalFunctions::_pair_for( - factory, _next.tokenIn, _next.tokenOut, _next.stable + factory, _next.tokenIn, _next.tokenOut, _next.stable, _next.feeTier ) } else { _to @@ -470,19 +478,27 @@ mod StarkDRouter { } fn _pair_for( - factory: ContractAddress, tokenA: ContractAddress, tokenB: ContractAddress, stable: bool + factory: ContractAddress, + tokenA: ContractAddress, + tokenB: ContractAddress, + stable: bool, + feeTier: u8 ) -> ContractAddress { let (token0, token1) = InternalFunctions::_sort_tokens(tokenA, tokenB); IStarkDFactoryABIDispatcher { contract_address: factory - }.get_pair(token0, token1, stable) + }.get_pair(token0, token1, stable, feeTier) } fn _get_reserves( - factory: ContractAddress, tokenA: ContractAddress, tokenB: ContractAddress, stable: bool + factory: ContractAddress, + tokenA: ContractAddress, + tokenB: ContractAddress, + stable: bool, + feeTier: u8 ) -> (u256, u256) { let (token0, _) = InternalFunctions::_sort_tokens(tokenA, tokenB); - let pair = InternalFunctions::_pair_for(factory, tokenA, tokenB, stable); + let pair = InternalFunctions::_pair_for(factory, tokenA, tokenB, stable, feeTier); let (reserve0, reserve1, _) = IStarkDPairDispatcher { contract_address: pair }.get_reserves(); @@ -516,7 +532,7 @@ mod StarkDRouter { match _path.pop_front() { Option::Some(route) => { let pair = InternalFunctions::_pair_for( - factory, *route.tokenIn, *route.tokenOut, *route.stable + factory, *route.tokenIn, *route.tokenOut, *route.stable, *route.feeTier ); let factoryDispatcher = IStarkDFactoryABIDispatcher { contract_address: factory diff --git a/src/tests/factory/test_factory.cairo b/src/tests/factory/test_factory.cairo index e9271aa..07eff65 100644 --- a/src/tests/factory/test_factory.cairo +++ b/src/tests/factory/test_factory.cairo @@ -145,8 +145,8 @@ fn test_all_pairs_length() { fn test_get_pair() { let mut state = setup(); let (token0, token1) = deploy_tokens(); - let pair = StarkDFactoryImpl::create_pair(ref state, token0, token1, false); - let got_pair = StarkDFactoryImpl::get_pair(@state, token0, token1, false); + let pair = StarkDFactoryImpl::create_pair(ref state, token0, token1, false, 0); + let got_pair = StarkDFactoryImpl::get_pair(@state, token0, token1, false, 0); assert(got_pair == pair, 'got_pair eq `pair`'); } @@ -155,7 +155,7 @@ fn test_get_pair() { #[should_panic(expected: ('StarkDefi: PAIR_NOT_FOUND',))] fn test_get_pair_not_found() { let mut state = setup(); - let pair = StarkDFactoryImpl::get_pair(@state, ADDRESS_ONE(), ADDRESS_TWO(), false); + let pair = StarkDFactoryImpl::get_pair(@state, ADDRESS_ONE(), ADDRESS_TWO(), false, 0); assert(pair != ADDRESS_ZERO(), 'StarkDefi: PAIR_NOT_FOUND'); } @@ -176,7 +176,7 @@ fn test_all_pairs() { fn test_create_pair() { let mut state = setup(); let (token0, token1) = deploy_tokens(); - let pair = StarkDFactoryImpl::create_pair(ref state, token0, token1, false); + let pair = StarkDFactoryImpl::create_pair(ref state, token0, token1, false, 0); assert_event_pair_created(@state, token0, token1, pair, 1); assert(pair != ADDRESS_ZERO(), 'pair neq 0'); @@ -186,7 +186,7 @@ fn test_create_pair() { assert(pairs.len() == 1, 'pairs len eq 1'); assert(*pairs.at(0) == pair, 'pairs[0] eq `pair`'); - let got_pair = StarkDFactoryImpl::get_pair(@state, token0, token1, false); + let got_pair = StarkDFactoryImpl::get_pair(@state, token0, token1, false, 0); assert(got_pair == pair, 'got_pair eq `pair`'); } @@ -196,7 +196,7 @@ fn test_deployed_create_pair() { let factory = deploy_factory(ADDRESS_ZERO()); let (token0, token1) = deploy_tokens(); - let pair = factory.create_pair(token0, token1, true); + let pair = factory.create_pair(token0, token1, true, 0); let event = testing::pop_log::(factory.contract_address).unwrap(); @@ -210,9 +210,9 @@ fn test_deployed_create_pair() { fn test_create_pair_twice() { let mut state = setup(); let (token0, token1) = deploy_tokens(); - let pair1 = StarkDFactoryImpl::create_pair(ref state, token0, token1, false); + let pair1 = StarkDFactoryImpl::create_pair(ref state, token0, token1, false, 0); drop_event(ADDRESS_ZERO()); - let pair2 = StarkDFactoryImpl::create_pair(ref state, token0, token1, true); + let pair2 = StarkDFactoryImpl::create_pair(ref state, token0, token1, true, 0); assert_event_pair_created(@state, token0, token1, pair2, 2); assert(pair1 != ADDRESS_ZERO(), 'pair1 neq 0'); @@ -223,9 +223,9 @@ fn test_create_pair_twice() { assert(pairs.len() == 2, 'pairs len eq 2'); assert(*pairs.at(0) == pair1, 'pairs[0] eq `pair1`'); - let got_pair1 = StarkDFactoryImpl::get_pair(@state, token0, token1, false); + let got_pair1 = StarkDFactoryImpl::get_pair(@state, token0, token1, false, 0); assert(got_pair1 == pair1, 'got_pair eq `pair1`'); - let got_pair2 = StarkDFactoryImpl::get_pair(@state, token0, token1, true); + let got_pair2 = StarkDFactoryImpl::get_pair(@state, token0, token1, true, 0); assert(got_pair2 == pair2, 'got_pair eq `pair1`'); } @@ -234,7 +234,7 @@ fn test_create_pair_twice() { #[should_panic(expected: ('invalid token address',))] fn test_create_pair_invalid_token() { let mut state = setup(); - StarkDFactoryImpl::create_pair(ref state, ADDRESS_ZERO(), ADDRESS_TWO(), false); + StarkDFactoryImpl::create_pair(ref state, ADDRESS_ZERO(), ADDRESS_TWO(), false, 0); } #[test] @@ -242,7 +242,7 @@ fn test_create_pair_invalid_token() { #[should_panic(expected: ('identical addresses',))] fn test_create_pair_identical_token() { let mut state = setup(); - StarkDFactoryImpl::create_pair(ref state, ADDRESS_ONE(), ADDRESS_ONE(), false); + StarkDFactoryImpl::create_pair(ref state, ADDRESS_ONE(), ADDRESS_ONE(), false, 0); } #[test] @@ -251,8 +251,8 @@ fn test_create_pair_identical_token() { fn test_create_pair_pair_exists() { let mut state = setup(); let (token0, token1) = deploy_tokens(); - StarkDFactoryImpl::create_pair(ref state, token0, token1, true); - StarkDFactoryImpl::create_pair(ref state, token0, token1, true); + StarkDFactoryImpl::create_pair(ref state, token0, token1, true, 0); + StarkDFactoryImpl::create_pair(ref state, token0, token1, true, 0); } @@ -295,7 +295,6 @@ fn test_set_fees() { // stable StarkDFactoryImpl::set_fee(ref state, 10, true); assert(StarkDFactoryImpl::get_fees(@state) == (10, 35), 'get_fees eq (10, 35)'); - } #[test] @@ -333,8 +332,8 @@ fn test_set_fees_max() { fn test_set_custom_pair_fee() { let mut state = setup(); let (token0, token1) = deploy_tokens(); - let vPair = StarkDFactoryImpl::create_pair(ref state, token0, token1, false); - let sPair = StarkDFactoryImpl::create_pair(ref state, token0, token1, true); + let vPair = StarkDFactoryImpl::create_pair(ref state, token0, token1, false, 0); + let sPair = StarkDFactoryImpl::create_pair(ref state, token0, token1, true, 0); // get default fees let vFees = StarkDFactoryImpl::get_fee(@state, vPair); @@ -357,7 +356,7 @@ fn test_set_custom_pair_fee() { fn test_set_custom_pair_fee_not_allowed() { let mut state = setup(); let (token0, token1) = deploy_tokens(); - let vPair = StarkDFactoryImpl::create_pair(ref state, token0, token1, false); + let vPair = StarkDFactoryImpl::create_pair(ref state, token0, token1, false, 0); testing::set_caller_address(ADDRESS_ONE()); StarkDFactoryImpl::set_custom_pair_fee(ref state, vPair, 50); } @@ -368,7 +367,7 @@ fn test_set_custom_pair_fee_not_allowed() { fn test_set_custom_pair_fee_too_high() { let mut state = setup(); let (token0, token1) = deploy_tokens(); - let vPair = StarkDFactoryImpl::create_pair(ref state, token0, token1, false); + let vPair = StarkDFactoryImpl::create_pair(ref state, token0, token1, false, 0); testing::set_caller_address(FEE_TO_SETTER()); StarkDFactoryImpl::set_custom_pair_fee(ref state, vPair, 101); } diff --git a/src/tests/pair/test_pair_shared.cairo b/src/tests/pair/test_pair_shared.cairo index 50c2164..36bd702 100644 --- a/src/tests/pair/test_pair_shared.cairo +++ b/src/tests/pair/test_pair_shared.cairo @@ -38,13 +38,14 @@ use debug::PrintTrait; // Setup // -fn deploy_pair(stable: bool) -> (IStarkDPairABIDispatcher, AccountABIDispatcher) { +fn deploy_pair(stable: bool, feeTier: u8) -> (IStarkDPairABIDispatcher, AccountABIDispatcher) { let account = setup_account(); let factory = deploy_factory(account.contract_address); let token0 = deploy_erc20('Token0', 'TK0', with_decimals(10000), account.contract_address); let token1 = deploy_erc20('Token1', 'TK1', with_decimals(10000), account.contract_address); - let pair = factory.create_pair(token0.contract_address, token1.contract_address, stable); + let pair = factory + .create_pair(token0.contract_address, token1.contract_address, stable, feeTier); (IStarkDPairABIDispatcher { contract_address: pair }, account) } @@ -53,7 +54,7 @@ fn STATE() -> StarkDPair::ContractState { StarkDPair::contract_state_for_testing() } -fn setup(stable: bool) -> StarkDPair::ContractState { +fn setup(stable: bool, feeTier: u8) -> StarkDPair::ContractState { let mut state = STATE(); testing::set_caller_address(constants::FACTORY()); @@ -63,6 +64,7 @@ fn setup(stable: bool) -> StarkDPair::ContractState { constants::TOKEN_0(), constants::TOKEN_1(), stable, + feeTier, constants::PAIR_FEES_CLASS_HASH() ); drop_event(constants::ADDRESS_ZERO()); @@ -87,6 +89,7 @@ fn test_pair_constructor() { token0.contract_address, token1.contract_address, false, + 0, constants::PAIR_FEES_CLASS_HASH() ); @@ -104,7 +107,7 @@ fn test_pair_constructor() { #[test] #[available_gas(20000000)] fn test_deployed_pair() { - let (pairDispatcher, accountDispatcher) = deploy_pair(false); + let (pairDispatcher, accountDispatcher) = deploy_pair(false, 0); assert(pairDispatcher.token0() == constants::ADDRESS_THREE(), 'Token0 eq ADDRESS_THREE'); assert(pairDispatcher.token1() == constants::ADDRESS_FOUR(), 'Token1 eq ADDRESS_FOUR'); @@ -148,9 +151,9 @@ fn transfer_erc20(token: ContractAddress, to: ContractAddress, amount: u256) -> } fn add_initial_liquidity( - ignore_decimals: bool, token0_amount: u256, token1_amount: u256, stable: bool + ignore_decimals: bool, token0_amount: u256, token1_amount: u256, stable: bool, feeTier: u8 ) -> (IStarkDPairABIDispatcher, AccountABIDispatcher) { - let (pairDispatcher, accountDispatcher) = deploy_pair(stable); + let (pairDispatcher, accountDispatcher) = deploy_pair(stable, feeTier); let token0Dispatcher = token_at(pairDispatcher.token0()); let token1Dispatcher = token_at(pairDispatcher.token1()); @@ -250,7 +253,7 @@ fn add_more_liquidity( #[test] #[available_gas(20000000)] fn test_mint() { - let (pairDispatcher, accountDispatcher) = deploy_pair(false); + let (pairDispatcher, accountDispatcher) = deploy_pair(false, 0); let token0Dispatcher = token_at(pairDispatcher.token0()); let token1Dispatcher = token_at(pairDispatcher.token1()); @@ -300,7 +303,7 @@ fn test_mint() { #[available_gas(20000000)] #[should_panic(expected: ('u128_sub Overflow', 'ENTRYPOINT_FAILED'))] fn test_mint_no_zero_tokens() { - let (pairDispatcher, accountDispatcher) = deploy_pair(false); + let (pairDispatcher, accountDispatcher) = deploy_pair(false, 0); // mint pairDispatcher.mint(accountDispatcher.contract_address); } @@ -312,7 +315,7 @@ fn test_mint_no_zero_tokens() { )] fn test_mint_not_enough_tokens() { let stable = false; - let (pairDispatcher, accountDispatcher) = add_initial_liquidity(true, 1000, 1000, stable); + let (pairDispatcher, accountDispatcher) = add_initial_liquidity(true, 1000, 1000, stable, 0); } // @@ -373,7 +376,7 @@ fn swap( fn test_swap_insufficient_liquidity() { let stable = true; let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 2500, 2500, stable + false, 2500, 2500, stable, 0 ); // swap let amount = with_decimals(5000); @@ -386,7 +389,7 @@ fn test_swap_insufficient_liquidity() { fn test_vPair_swap_insufficient_output_amount() { let stable = false; let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 5000, 3000, stable + false, 5000, 3000, stable, 0 ); // swap swap(ref pairDispatcher, ref accountDispatcher, with_decimals(50), 0, 0, false); @@ -398,7 +401,7 @@ fn test_vPair_swap_insufficient_output_amount() { fn test_swap_invalid_to() { let stable = true; let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 5000, 5000, stable + false, 5000, 5000, stable, 0 ); // swap swap(ref pairDispatcher, ref accountDispatcher, 50, 81, 0, true); @@ -410,7 +413,7 @@ fn test_swap_invalid_to() { fn test_swap_insufficient_input_amount() { let stable = false; let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 5000, 3000, stable + false, 5000, 3000, stable, 0 ); // swap swap(ref pairDispatcher, ref accountDispatcher, 0, 81, 0, false); @@ -464,7 +467,7 @@ fn remove_liqudity( fn test_burn() { let stable = false; let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 5000, 3000, stable + false, 5000, 3000, stable, 0 ); let token0Dispatcher = token_at(pairDispatcher.token0()); let token1Dispatcher = token_at(pairDispatcher.token1()); @@ -505,7 +508,7 @@ fn test_burn() { fn test_burn_remove_all_liquidity() { let stable = false; let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 5000, 3000, stable + false, 5000, 3000, stable, 0 ); let token0Dispatcher = token_at(pairDispatcher.token0()); let token1Dispatcher = token_at(pairDispatcher.token1()); @@ -536,7 +539,7 @@ fn test_burn_remove_all_liquidity() { fn test_burn_insufficient_liquidity() { let stable = false; let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 5000, 3000, stable + false, 5000, 3000, stable, 0 ); // remove liquidity remove_liqudity(ref pairDispatcher, ref accountDispatcher, 0, false); @@ -549,7 +552,7 @@ fn test_burn_insufficient_liquidity() { #[test] #[available_gas(20000000)] fn test_skim() { - let (pairDispatcher, accountDispatcher) = add_initial_liquidity(false, 5000, 3000, false); + let (pairDispatcher, accountDispatcher) = add_initial_liquidity(false, 5000, 3000, false, 0); let token0Dispatcher = token_at(pairDispatcher.token0()); // transfer token0 to pair @@ -585,7 +588,7 @@ fn test_skim() { #[test] #[available_gas(20000000)] fn test_sync() { - let (pairDispatcher, accountDispatcher) = add_initial_liquidity(false, 5000, 3000, false); + let (pairDispatcher, accountDispatcher) = add_initial_liquidity(false, 5000, 3000, false, 0); let token0Dispatcher = token_at(pairDispatcher.token0()); // transfer token0 to pair @@ -620,8 +623,9 @@ fn test_sync() { #[available_gas(50000000)] fn test_fees_collected_on_swap() { let stable = false; + let feeTier = 0; let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 5000, 3000, stable + false, 5000, 3000, stable, feeTier ); let fee_vault = pairDispatcher.fee_vault(); let token0Dispatcher = token_at(pairDispatcher.token0()); @@ -676,8 +680,9 @@ fn test_fees_collected_on_swap() { #[available_gas(100000000)] fn test_claim_fees() { let stable = false; + let feeTier = 1; let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 5000, 3000, stable + false, 5000, 3000, stable, feeTier ); let fee_vault = pairDispatcher.fee_vault(); let token0Dispatcher = token_at(pairDispatcher.token0()); @@ -736,7 +741,7 @@ fn test_claim_fees() { #[available_gas(20000000)] #[should_panic(expected: ('insufficient input amount', 'ENTRYPOINT_FAILED'))] fn test_get_amount_out_insufficient_in() { - let (pairDispatcher, accountDispatcher) = add_initial_liquidity(false, 5000, 4103, false); + let (pairDispatcher, accountDispatcher) = add_initial_liquidity(false, 5000, 4103, false, 0); pairDispatcher.get_amount_out(pairDispatcher.token0(), 0); } diff --git a/src/tests/pair/test_stable_pair.cairo b/src/tests/pair/test_stable_pair.cairo index 033c980..571631c 100644 --- a/src/tests/pair/test_stable_pair.cairo +++ b/src/tests/pair/test_stable_pair.cairo @@ -33,6 +33,7 @@ fn test_sPair_constructor() { token0.contract_address, token1.contract_address, true, + 0, constants::PAIR_FEES_CLASS_HASH() ); assert(StarkDPairImpl::name(@state) == 'sStarkDefi Pair', 'Name eq sStarkDefi Pair'); @@ -46,7 +47,7 @@ fn test_sPair_constructor() { #[test] #[available_gas(4000000)] fn test_deployed_sPair() { - let (pairDispatcher, _) = deploy_pair(true); + let (pairDispatcher, _) = deploy_pair(true, 0); assert(pairDispatcher.name() == 'sStarkDefi Pair', 'Name eq sStarkDefi Pair'); assert(pairDispatcher.symbol() == 'sSTARKD-P', 'Symbol eq sSTARKD-P'); } @@ -54,7 +55,7 @@ fn test_deployed_sPair() { #[test] #[available_gas(20000000)] fn test_sPair_mint() { - let (pairDispatcher, accountDispatcher) = deploy_pair(true); + let (pairDispatcher, accountDispatcher) = deploy_pair(true, 0); let token0Dispatcher = token_at(pairDispatcher.token0()); let token1Dispatcher = token_at(pairDispatcher.token1()); @@ -93,7 +94,7 @@ fn test_sPair_mint() { #[available_gas(20000000)] #[should_panic(expected: ('unequal amounts', 'ENTRYPOINT_FAILED'))] fn test_sPair_mint_unmatched() { - let (pairDispatcher, accountDispatcher) = deploy_pair(true); + let (pairDispatcher, accountDispatcher) = deploy_pair(true, 0); let token0Dispatcher = token_at(pairDispatcher.token0()); let token1Dispatcher = token_at(pairDispatcher.token1()); @@ -126,9 +127,10 @@ fn test_sPair_mint_unmatched() { #[available_gas(200000000)] fn test_sPair_mint_more_lp() { let stable = true; + let feeTier = 0; let _5000 = with_decimals(5000); let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 5000, 5000, stable + false, 5000, 5000, stable, feeTier ); let token0Dispatcher = token_at(pairDispatcher.token0()); let token1Dispatcher = token_at(pairDispatcher.token1()); @@ -159,8 +161,9 @@ fn test_sPair_mint_more_lp() { #[available_gas(20000000)] fn test_sPair_swap_token0_for_token1() { let stable = true; + let feeTier = 0; let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 5000, 5000, stable + false, 5000, 5000, stable, feeTier ); let token0Dispatcher = token_at(pairDispatcher.token0()); let token1Dispatcher = token_at(pairDispatcher.token1()); @@ -198,8 +201,9 @@ fn test_sPair_swap_token0_for_token1() { #[available_gas(40000000)] fn test_sPair_swap_token1_for_token0() { let stable = true; + let feeTier = 0; let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 5000, 5000, stable + false, 5000, 5000, stable, feeTier ); let token0Dispatcher = token_at(pairDispatcher.token0()); let token1Dispatcher = token_at(pairDispatcher.token1()); @@ -226,7 +230,7 @@ fn test_sPair_swap_token1_for_token0() { #[test] #[available_gas(200000000)] fn test_sPair_get_amount_out() { - let (pairDispatcher, accountDispatcher) = add_initial_liquidity(false, 10000, 10000, true); + let (pairDispatcher, accountDispatcher) = add_initial_liquidity(false, 10000, 10000, true, 0); let amountIn = with_decimals(1); let tokenIn = pairDispatcher.token0(); @@ -245,7 +249,7 @@ fn test_sPair_get_amount_out() { fn test_sPair_swap_invariant_k() { let stable = true; let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 5000, 5000, stable + false, 5000, 5000, stable, 0 ); // swap swap(ref pairDispatcher, ref accountDispatcher, 50, 51, 0, false); diff --git a/src/tests/pair/test_volatile_pair.cairo b/src/tests/pair/test_volatile_pair.cairo index cd37277..3336aab 100644 --- a/src/tests/pair/test_volatile_pair.cairo +++ b/src/tests/pair/test_volatile_pair.cairo @@ -32,6 +32,7 @@ fn test_vPair_constructor() { token0.contract_address, token1.contract_address, false, + 0, constants::PAIR_FEES_CLASS_HASH() ); assert(StarkDPairImpl::name(@state) == 'vStarkDefi Pair', 'Name eq vStarkDefi Pair'); @@ -45,7 +46,7 @@ fn test_vPair_constructor() { #[test] #[available_gas(4000000)] fn test_deployed_vPair() { - let (pairDispatcher, _) = deploy_pair(false); + let (pairDispatcher, _) = deploy_pair(false, 0); assert(pairDispatcher.name() == 'vStarkDefi Pair', 'Name eq vStarkDefi Pair'); assert(pairDispatcher.symbol() == 'vSTARKD-P', 'Symbol eq vSTARKD-P'); } @@ -53,7 +54,7 @@ fn test_deployed_vPair() { #[test] #[available_gas(20000000)] fn test_vPair_mint() { - let (pairDispatcher, accountDispatcher) = deploy_pair(false); + let (pairDispatcher, accountDispatcher) = deploy_pair(false, 0); let token0Dispatcher = token_at(pairDispatcher.token0()); let token1Dispatcher = token_at(pairDispatcher.token1()); @@ -91,8 +92,9 @@ fn test_vPair_mint() { #[available_gas(40000000)] fn test_vPair_mint_more_lp() { let stable = false; + let feeTier = 0; let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 5000, 3000, stable + false, 5000, 3000, stable, feeTier ); let token0Dispatcher = token_at(pairDispatcher.token0()); let token1Dispatcher = token_at(pairDispatcher.token1()); @@ -124,8 +126,9 @@ fn test_vPair_mint_more_lp() { #[available_gas(20000000)] fn test_vPair_swap_token0_for_token1() { let stable = false; + let feeTier = 0; let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 5000, 3000, stable + false, 5000, 3000, stable, feeTier ); let token0Dispatcher = token_at(pairDispatcher.token0()); let token1Dispatcher = token_at(pairDispatcher.token1()); @@ -163,8 +166,9 @@ fn test_vPair_swap_token0_for_token1() { #[available_gas(20000000)] fn test_vPair_swap_token1_for_token0() { let stable = false; + let feeTier = 0; let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 5000, 3000, stable + false, 5000, 3000, stable, feeTier ); let token0Dispatcher = token_at(pairDispatcher.token0()); let token1Dispatcher = token_at(pairDispatcher.token1()); @@ -193,8 +197,9 @@ fn test_vPair_swap_token1_for_token0() { #[should_panic(expected: ('invariant K', 'ENTRYPOINT_FAILED', 'ENTRYPOINT_FAILED'))] fn test_vPair_swap_invariant_k() { let stable = false; + let feeTier = 0; let (mut pairDispatcher, mut accountDispatcher) = add_initial_liquidity( - false, 5000, 3000, stable + false, 5000, 3000, stable, feeTier ); // swap swap(ref pairDispatcher, ref accountDispatcher, 50, 100, 0, false); @@ -203,7 +208,7 @@ fn test_vPair_swap_invariant_k() { #[test] #[available_gas(200000000)] fn test_vPair_get_amount_out() { - let (pairDispatcher, accountDispatcher) = add_initial_liquidity(false, 5000, 4103, false); + let (pairDispatcher, accountDispatcher) = add_initial_liquidity(false, 5000, 4103, false, 0); let amountIn = with_decimals(100); let tokenIn = pairDispatcher.token0(); diff --git a/src/tests/router/test_router.cairo b/src/tests/router/test_router.cairo index 82e5803..dd2c7fc 100644 --- a/src/tests/router/test_router.cairo +++ b/src/tests/router/test_router.cairo @@ -154,6 +154,7 @@ fn add_liquidity( tokenA: ContractAddress, tokenB: ContractAddress, stable: bool, + feeTier: u8, amountADesired: u128, amountBDesired: u128, slipTolerance: u256, @@ -169,6 +170,7 @@ fn add_liquidity( Serde::serialize(@tokenA, ref calldata); Serde::serialize(@tokenB, ref calldata); Serde::serialize(@stable, ref calldata); + Serde::serialize(@feeTier, ref calldata); Serde::serialize(@amountA, ref calldata); Serde::serialize(@amountB, ref calldata); Serde::serialize(@amountAMin, ref calldata); @@ -194,7 +196,7 @@ fn add_liquidity( } fn create_pair( - stable: bool + stable: bool, feeTier: u8 ) -> ( IStarkDRouterDispatcher, AccountABIDispatcher, @@ -206,13 +208,14 @@ fn create_pair( let factory = IStarkDFactoryABIDispatcher { contract_address: router.factory() }; let (token0, token1, _, _) = deploy_tokens(); - let pair = factory.create_pair(token0.contract_address, token1.contract_address, stable); + let pair = factory + .create_pair(token0.contract_address, token1.contract_address, stable, feeTier); (router, account, IStarkDPairDispatcher { contract_address: pair }, token0, token1) } fn add_initial_liquidity( - stable: bool + stable: bool, feeTier: u8 ) -> ( IStarkDRouterDispatcher, AccountABIDispatcher, @@ -237,6 +240,7 @@ fn add_initial_liquidity( token0.contract_address, token1.contract_address, stable, + feeTier, amount0Desired, amount1Desired, slipTolerance, @@ -247,7 +251,7 @@ fn add_initial_liquidity( } fn add_multiple_liquidity( - stable: bool + stable: bool, feeTier: u8 ) -> ( IStarkDRouterDispatcher, AccountABIDispatcher, @@ -275,6 +279,7 @@ fn add_multiple_liquidity( Serde::serialize(@token0.contract_address, ref t0t1_calldata); Serde::serialize(@token1.contract_address, ref t0t1_calldata); Serde::serialize(@stable, ref t0t1_calldata); + Serde::serialize(@feeTier, ref t0t1_calldata); Serde::serialize(@amount0Desired, ref t0t1_calldata); Serde::serialize(@amount1Desired, ref t0t1_calldata); Serde::serialize(@minAmount, ref t0t1_calldata); @@ -298,6 +303,7 @@ fn add_multiple_liquidity( Serde::serialize(@token0.contract_address, ref t0t2_calldata); Serde::serialize(@token2.contract_address, ref t0t2_calldata); Serde::serialize(@stable, ref t0t2_calldata); + Serde::serialize(@feeTier, ref t0t2_calldata); Serde::serialize(@amount0, ref t0t2_calldata); Serde::serialize(@amount1, ref t0t2_calldata); Serde::serialize(@minAmount, ref t0t2_calldata); @@ -321,6 +327,7 @@ fn add_multiple_liquidity( Serde::serialize(@token0.contract_address, ref t0t3_calldata); Serde::serialize(@token3.contract_address, ref t0t3_calldata); Serde::serialize(@stable, ref t0t3_calldata); + Serde::serialize(@feeTier, ref t0t3_calldata); Serde::serialize(@amount0, ref t0t3_calldata); Serde::serialize(@amount1, ref t0t3_calldata); Serde::serialize(@minAmount, ref t0t3_calldata); @@ -344,6 +351,7 @@ fn add_multiple_liquidity( Serde::serialize(@token1.contract_address, ref t1t2_calldata); Serde::serialize(@token2.contract_address, ref t1t2_calldata); Serde::serialize(@stable, ref t1t2_calldata); + Serde::serialize(@feeTier, ref t1t2_calldata); Serde::serialize(@amount0, ref t1t2_calldata); Serde::serialize(@amount1, ref t1t2_calldata); Serde::serialize(@minAmount, ref t1t2_calldata); @@ -367,6 +375,7 @@ fn add_multiple_liquidity( Serde::serialize(@token1.contract_address, ref t1t3_calldata); Serde::serialize(@token3.contract_address, ref t1t3_calldata); Serde::serialize(@stable, ref t1t3_calldata); + Serde::serialize(@feeTier, ref t1t3_calldata); Serde::serialize(@amount0, ref t1t3_calldata); Serde::serialize(@amount1, ref t1t3_calldata); Serde::serialize(@minAmount, ref t1t3_calldata); @@ -390,6 +399,7 @@ fn add_multiple_liquidity( Serde::serialize(@token2.contract_address, ref t2t3_calldata); Serde::serialize(@token3.contract_address, ref t2t3_calldata); Serde::serialize(@stable, ref t2t3_calldata); + Serde::serialize(@feeTier, ref t2t3_calldata); Serde::serialize(@amount0, ref t2t3_calldata); Serde::serialize(@amount1Desired, ref t2t3_calldata); Serde::serialize(@minAmount, ref t2t3_calldata); @@ -430,6 +440,7 @@ fn test_router_add_new_liquidity() { token0.contract_address, token1.contract_address, false, + 0, amount0Desired, amount1Desired, slipTolerance, @@ -445,7 +456,7 @@ fn test_router_add_new_liquidity() { #[test] #[available_gas(20000000)] fn test_router_add_more_liquidity() { - let (router, account, factoryDispatcher, token0, token1) = add_initial_liquidity(false); + let (router, account, factoryDispatcher, token0, token1) = add_initial_liquidity(false, 0); let amount0Desired = 100_000_000; let amount1Desired = 100_000_000; @@ -459,6 +470,7 @@ fn test_router_add_more_liquidity() { token0.contract_address, token1.contract_address, false, + 0, amount0Desired - 80_222_789, amount1Desired - 80_222_789, slipTolerance, @@ -472,7 +484,7 @@ fn test_router_add_more_liquidity() { #[available_gas(40000000)] #[should_panic(expected: ('INSUFFICIENT_B_AMOUNT', 'ENTRYPOINT_FAILED', 'ENTRYPOINT_FAILED'))] fn test_router_add_liquidity_insufficient_b() { - let (router, account, _, token0, token1) = add_initial_liquidity(false); + let (router, account, _, token0, token1) = add_initial_liquidity(false, 0); let amount0Desired = 100_000_000; let amount1Desired = 100_000_000; @@ -485,6 +497,7 @@ fn test_router_add_liquidity_insufficient_b() { token0.contract_address, token1.contract_address, false, + 0, amount0Desired, amount1Desired, slipTolerance, @@ -498,6 +511,7 @@ fn test_router_add_liquidity_insufficient_b() { token0.contract_address, token1.contract_address, false, + 0, amount0Desired - 80_222_789, amount1Desired - 40_222_789, slipTolerance, @@ -509,7 +523,7 @@ fn test_router_add_liquidity_insufficient_b() { #[available_gas(40000000)] #[should_panic(expected: ('INSUFFICIENT_A_AMOUNT', 'ENTRYPOINT_FAILED', 'ENTRYPOINT_FAILED'))] fn test_router_add_liquidity_insufficient_a() { - let (router, account, _, token0, token1) = add_initial_liquidity(false); + let (router, account, _, token0, token1) = add_initial_liquidity(false, 0); let amount0Desired = 100_000_000; let amount1Desired = 100_000_000; @@ -522,6 +536,7 @@ fn test_router_add_liquidity_insufficient_a() { token0.contract_address, token1.contract_address, false, + 0, amount0Desired, amount1Desired, slipTolerance, @@ -535,6 +550,7 @@ fn test_router_add_liquidity_insufficient_a() { token0.contract_address, token1.contract_address, false, + 0, amount0Desired - 40_222_789, amount1Desired - 80_222_789, slipTolerance, @@ -552,13 +568,14 @@ fn remove_liquidity( tokenA: ContractAddress, tokenB: ContractAddress, stable: bool, + feeTier: u8, liquidity: u256, amountAMin: u256, amountBMin: u256, deadline: u64 ) -> (u256, u256) { let factoryDispatcher = IStarkDFactoryABIDispatcher { contract_address: router.factory() }; - let lp_token_address = factoryDispatcher.get_pair(tokenA, tokenB, stable); + let lp_token_address = factoryDispatcher.get_pair(tokenA, tokenB, stable, feeTier); let mut calls = array![]; @@ -577,6 +594,7 @@ fn remove_liquidity( Serde::serialize(@tokenA, ref remove_calldata); Serde::serialize(@tokenB, ref remove_calldata); Serde::serialize(@stable, ref remove_calldata); + Serde::serialize(@feeTier, ref remove_calldata); Serde::serialize(@liquidity, ref remove_calldata); Serde::serialize(@amountAMin, ref remove_calldata); Serde::serialize(@amountBMin, ref remove_calldata); @@ -604,11 +622,14 @@ fn remove_liquidity( #[available_gas(40000000)] fn test_router_remove_all_liquidity() { let stable = false; - let (router, account, factoryDispatcher, token0, token1) = add_initial_liquidity(stable); + let feeTier = 0; + let (router, account, factoryDispatcher, token0, token1) = add_initial_liquidity( + stable, feeTier + ); let pairDispatcher = IStarkDPairDispatcher { contract_address: factoryDispatcher - .get_pair(token0.contract_address, token1.contract_address, stable) + .get_pair(token0.contract_address, token1.contract_address, stable, feeTier) }; let lp_balance = pairDispatcher.balance_of(account.contract_address); @@ -618,6 +639,7 @@ fn test_router_remove_all_liquidity() { token0.contract_address, token1.contract_address, stable, + feeTier, lp_balance, 0, 0, @@ -635,11 +657,14 @@ fn test_router_remove_all_liquidity() { #[available_gas(40000000)] fn test_router_remove_liqudity_some() { let stable = false; - let (router, account, factoryDispatcher, token0, token1) = add_initial_liquidity(stable); + let feeTier = 0; + let (router, account, factoryDispatcher, token0, token1) = add_initial_liquidity( + stable, feeTier + ); let pairDispatcher = IStarkDPairDispatcher { contract_address: factoryDispatcher - .get_pair(token0.contract_address, token1.contract_address, stable) + .get_pair(token0.contract_address, token1.contract_address, stable, feeTier) }; let lp_balance = pairDispatcher.balance_of(account.contract_address); @@ -649,6 +674,7 @@ fn test_router_remove_liqudity_some() { token0.contract_address, token1.contract_address, stable, + feeTier, lp_balance / 2, 0, 0, @@ -670,7 +696,10 @@ fn test_router_remove_liqudity_some() { #[should_panic(expected: ('insufficient A amount', 'ENTRYPOINT_FAILED', 'ENTRYPOINT_FAILED'))] fn test_router_remove_liqudity_less_A() { let stable = false; - let (router, account, factoryDispatcher, token0, token1) = add_initial_liquidity(stable); + let feeTier = 0; + let (router, account, factoryDispatcher, token0, token1) = add_initial_liquidity( + stable, feeTier + ); remove_liquidity( router, @@ -678,6 +707,7 @@ fn test_router_remove_liqudity_less_A() { token0.contract_address, token1.contract_address, stable, + feeTier, with_decimals(99_000_000), with_decimals(100_000_000), 0, @@ -690,7 +720,10 @@ fn test_router_remove_liqudity_less_A() { #[should_panic(expected: ('insufficient B amount', 'ENTRYPOINT_FAILED', 'ENTRYPOINT_FAILED'))] fn test_router_remove_liqudity_less_B() { let stable = false; - let (router, account, factoryDispatcher, token0, token1) = add_initial_liquidity(stable); + let feeTier = 0; + let (router, account, factoryDispatcher, token0, token1) = add_initial_liquidity( + stable, feeTier + ); remove_liquidity( router, @@ -698,6 +731,7 @@ fn test_router_remove_liqudity_less_B() { token0.contract_address, token1.contract_address, stable, + feeTier, with_decimals(99_000_000), 0, with_decimals(100_000_000), @@ -713,11 +747,14 @@ fn test_router_remove_liqudity_less_B() { #[available_gas(20000000)] fn test_router_quote() { let stable = false; - let (router, account, factoryDispatcher, token0, token1) = add_initial_liquidity(stable); + let feeTier = 0; + let (router, account, factoryDispatcher, token0, token1) = add_initial_liquidity( + stable, feeTier + ); let pairDispatcher = IStarkDPairDispatcher { contract_address: factoryDispatcher - .get_pair(token0.contract_address, token1.contract_address, stable) + .get_pair(token0.contract_address, token1.contract_address, stable, feeTier) }; let (res0, res1, _) = pairDispatcher.get_reserves(); @@ -733,7 +770,8 @@ fn test_router_quote() { #[should_panic(expected: ('insufficient amount', 'ENTRYPOINT_FAILED'))] fn test_router_quote_insufficient_amount() { let stable = false; - let (router, _, _, _, _) = add_initial_liquidity(stable); + let feeTier = 0; + let (router, _, _, _, _) = add_initial_liquidity(stable, feeTier); router.quote(0, 1, 1); } @@ -743,7 +781,8 @@ fn test_router_quote_insufficient_amount() { #[should_panic(expected: ('insufficient liquidity', 'ENTRYPOINT_FAILED'))] fn test_router_quote_insufficient_liquidity() { let stable = false; - let (router, _, _, _, _) = add_initial_liquidity(stable); + let feeTier = 0; + let (router, _, _, _, _) = add_initial_liquidity(stable, feeTier); router.quote(1, 0, 1); } @@ -752,11 +791,14 @@ fn test_router_quote_insufficient_liquidity() { #[available_gas(20000000)] fn test_router_get_amount_out() { let stable = false; - let (router, account, factoryDispatcher, token0, token1) = add_initial_liquidity(stable); + let feeTier = 0; + let (router, account, factoryDispatcher, token0, token1) = add_initial_liquidity( + stable, feeTier + ); let pairDispatcher = IStarkDPairDispatcher { contract_address: factoryDispatcher - .get_pair(token0.contract_address, token1.contract_address, stable) + .get_pair(token0.contract_address, token1.contract_address, stable, feeTier) }; let (resIn, resOut, _) = pairDispatcher.get_reserves(); @@ -772,11 +814,12 @@ fn test_router_get_amount_out() { #[should_panic(expected: ('insufficient input amount', 'ENTRYPOINT_FAILED'))] fn test_router_get_amount_out_insufficient_amount() { let stable = false; - let (router, _, factoryDispatcher, token0, token1) = add_initial_liquidity(stable); + let feeTier = 0; + let (router, _, factoryDispatcher, token0, token1) = add_initial_liquidity(stable, feeTier); let pairDispatcher = IStarkDPairDispatcher { contract_address: factoryDispatcher - .get_pair(token0.contract_address, token1.contract_address, stable) + .get_pair(token0.contract_address, token1.contract_address, stable, feeTier) }; pairDispatcher.get_amount_out(token0.contract_address, 0); @@ -787,7 +830,8 @@ fn test_router_get_amount_out_insufficient_amount() { #[should_panic(expected: ('insufficient liquidity', 'ENTRYPOINT_FAILED'))] fn test_router_get_amount_out_insufficient_liquidity() { let stable = false; - let (router, _, pairDispatcher, token0, token1) = create_pair(stable); + let feeTier = 0; + let (router, _, pairDispatcher, token0, token1) = create_pair(stable, feeTier); let amountIn = with_decimals(100_000); pairDispatcher.get_amount_out(token0.contract_address, amountIn); @@ -797,13 +841,20 @@ fn test_router_get_amount_out_insufficient_liquidity() { #[available_gas(200000000)] fn test_router_get_amounts_out() { let stable = false; - let (router, _, _, token0, token1, token2, token3) = add_multiple_liquidity(stable); + let feeTier = 0; + let (router, _, _, token0, token1, token2, token3) = add_multiple_liquidity(stable, feeTier); let amountIn = with_decimals(1_000); let path: Array:: = array![ - SwapPath { tokenIn: token0.contract_address, tokenOut: token3.contract_address, stable }, - SwapPath { tokenIn: token3.contract_address, tokenOut: token2.contract_address, stable }, - SwapPath { tokenIn: token2.contract_address, tokenOut: token1.contract_address, stable } + SwapPath { + tokenIn: token0.contract_address, tokenOut: token3.contract_address, stable, feeTier + }, + SwapPath { + tokenIn: token3.contract_address, tokenOut: token2.contract_address, stable, feeTier + }, + SwapPath { + tokenIn: token2.contract_address, tokenOut: token1.contract_address, stable, feeTier + } ]; let amounts = router.get_amounts_out(amountIn, path); @@ -822,7 +873,8 @@ fn test_router_get_amounts_out() { #[should_panic(expected: ('invalid path', 'ENTRYPOINT_FAILED'))] fn test_router_get_amounts_out_invalid_path() { let stable = false; - let (router, _, _, token0, _, _, _) = add_multiple_liquidity(stable); + let feeTier = 0; + let (router, _, _, token0, _, _, _) = add_multiple_liquidity(stable, feeTier); let amountIn = with_decimals(1_000); let path: Array:: = array![]; @@ -899,14 +951,23 @@ fn swap_exact_tokens_for_tokens_supporting_fees_on_transfer_tokens( #[available_gas(200000000)] fn test_router_swap_exact_tokens_for_tokens() { let stable = false; - let (router, account, _, token0, token1, token2, token3) = add_multiple_liquidity(stable); + let feeTier = 100; + let (router, account, _, token0, token1, token2, token3) = add_multiple_liquidity( + stable, feeTier + ); let slipTolerance = 100; // 1% let amountIn: u256 = with_decimals(10_000); let path: Array:: = array![ - SwapPath { tokenIn: token0.contract_address, tokenOut: token3.contract_address, stable }, - SwapPath { tokenIn: token3.contract_address, tokenOut: token2.contract_address, stable }, - SwapPath { tokenIn: token2.contract_address, tokenOut: token1.contract_address, stable } + SwapPath { + tokenIn: token0.contract_address, tokenOut: token3.contract_address, stable, feeTier + }, + SwapPath { + tokenIn: token3.contract_address, tokenOut: token2.contract_address, stable, feeTier + }, + SwapPath { + tokenIn: token2.contract_address, tokenOut: token1.contract_address, stable, feeTier + } ]; let token0_balance_before = token0.balance_of(account.contract_address); @@ -924,27 +985,31 @@ fn test_router_swap_exact_tokens_for_tokens() { let token1_balance_after = token1.balance_of(account.contract_address); assert( - token0_balance_before - token0_balance_after == with_decimals(10_000), - 'balances 0 checks' + token0_balance_before - token0_balance_after == with_decimals(10_000), 'balances 0 checks' ); assert( - token1_balance_after - token1_balance_before == *swap_amounts.at(3), - 'balances 1 checks' + token1_balance_after - token1_balance_before == *swap_amounts.at(3), 'balances 1 checks' ); - } #[test] #[available_gas(200000000)] fn test_router_swap_exact_tokens_for_tokens_3() { let stable = false; - let (router, account, _, token0, token1, token2, token3) = add_multiple_liquidity(stable); + let feeTier = 0; + let (router, account, _, token0, token1, token2, token3) = add_multiple_liquidity( + stable, feeTier + ); let slipTolerance = 50; // 0.5% let amountIn: u256 = with_decimals(1_000); let path: Array:: = array![ - SwapPath { tokenIn: token0.contract_address, tokenOut: token3.contract_address, stable }, - SwapPath { tokenIn: token3.contract_address, tokenOut: token1.contract_address, stable } + SwapPath { + tokenIn: token0.contract_address, tokenOut: token3.contract_address, stable, feeTier + }, + SwapPath { + tokenIn: token3.contract_address, tokenOut: token1.contract_address, stable, feeTier + } ]; let balance0_before = token0.balance_of(account.contract_address); @@ -961,26 +1026,25 @@ fn test_router_swap_exact_tokens_for_tokens_3() { let balance0_after = token0.balance_of(account.contract_address); let balance1_after = token1.balance_of(account.contract_address); - assert( - balance0_before - balance0_after == with_decimals(1_000), - 'balances 0 checks' - ); - assert( - balance1_after - balance1_before == *swap_amounts.at(2), - 'balances 1 checks' - ); + assert(balance0_before - balance0_after == with_decimals(1_000), 'balances 0 checks'); + assert(balance1_after - balance1_before == *swap_amounts.at(2), 'balances 1 checks'); } #[test] #[available_gas(200000000)] fn test_router_swap_exact_tokens_for_tokens_2() { let stable = false; - let (router, account, _, token0, token1, token2, token3) = add_multiple_liquidity(stable); + let feeTier = 0; + let (router, account, _, token0, token1, token2, token3) = add_multiple_liquidity( + stable, feeTier + ); let slipTolerance = 50; // 0.5% let amountIn: u256 = with_decimals(1_000); let path: Array:: = array![ - SwapPath { tokenIn: token2.contract_address, tokenOut: token0.contract_address, stable } + SwapPath { + tokenIn: token2.contract_address, tokenOut: token0.contract_address, stable, feeTier + } ]; let balance2_before = token2.balance_of(account.contract_address); @@ -998,26 +1062,25 @@ fn test_router_swap_exact_tokens_for_tokens_2() { let balance2_after = token2.balance_of(account.contract_address); let balance0_after = token0.balance_of(account.contract_address); - assert( - balance2_before - balance2_after == with_decimals(1_000), - 'balances 2 checks' - ); - assert( - balance0_after - balance0_before == *swap_amounts.at(1), - 'balances 0 checks' - ); + assert(balance2_before - balance2_after == with_decimals(1_000), 'balances 2 checks'); + assert(balance0_after - balance0_before == *swap_amounts.at(1), 'balances 0 checks'); } #[test] #[available_gas(200000000)] fn test_router_swap_exact_tokens_for_tokens_multiple() { let stable = false; - let (router, account, _, token0, token1, token2, token3) = add_multiple_liquidity(stable); + let feeTier = 0; + let (router, account, _, token0, token1, token2, token3) = add_multiple_liquidity( + stable, feeTier + ); let slipTolerance = 50; // 0.5% let amountIn: u256 = with_decimals(1_000); let path: Array:: = array![ - SwapPath { tokenIn: token2.contract_address, tokenOut: token0.contract_address, stable } + SwapPath { + tokenIn: token2.contract_address, tokenOut: token0.contract_address, stable, feeTier + } ]; let amounts = router.get_amounts_out(amountIn, path.clone()); @@ -1067,13 +1130,20 @@ fn test_router_swap_exact_tokens_for_tokens_multiple() { #[should_panic(expected: ('invalid path', 'ENTRYPOINT_FAILED', 'ENTRYPOINT_FAILED'))] fn test_router_swap_exact_tokens_for_tokens_invalid_path_progression() { let stable = false; - let (router, account, _, token0, token1, token2, token3) = add_multiple_liquidity(stable); + let feeTier = 0; + let (router, account, _, token0, token1, token2, token3) = add_multiple_liquidity( + stable, feeTier + ); let slipTolerance = 50; // 0.5% let amountIn: u256 = with_decimals(1_000); let path: Array:: = array![ - SwapPath { tokenIn: token0.contract_address, tokenOut: token3.contract_address, stable }, - SwapPath { tokenIn: token0.contract_address, tokenOut: token1.contract_address, stable } + SwapPath { + tokenIn: token0.contract_address, tokenOut: token3.contract_address, stable, feeTier + }, + SwapPath { + tokenIn: token0.contract_address, tokenOut: token1.contract_address, stable, feeTier + } ]; let amounts = router.get_amounts_out(amountIn, path.clone()); @@ -1088,12 +1158,17 @@ fn test_router_swap_exact_tokens_for_tokens_invalid_path_progression() { #[available_gas(200000000)] fn test_router_swap_exact_tokens_for_tokens_supporting_fees_on_transfer_tokens_multiple() { let stable = false; - let (router, account, _, token0, token1, token2, token3) = add_multiple_liquidity(stable); + let feeTier = 0; + let (router, account, _, token0, token1, token2, token3) = add_multiple_liquidity( + stable, feeTier + ); let slipTolerance = 50; // 0.5% let amountIn: u256 = with_decimals(1_000); let path: Array:: = array![ - SwapPath { tokenIn: token2.contract_address, tokenOut: token0.contract_address, stable } + SwapPath { + tokenIn: token2.contract_address, tokenOut: token0.contract_address, stable, feeTier + } ]; let amounts = router.get_amounts_out(amountIn, path.clone()); @@ -1141,13 +1216,20 @@ fn test_router_swap_exact_tokens_for_tokens_supporting_fees_on_transfer_tokens_m #[should_panic(expected: ('invalid path', 'ENTRYPOINT_FAILED', 'ENTRYPOINT_FAILED'))] fn test_router_swap_exact_tokens_for_tokens_supporting_fees_on_transfer_tokens_invalid_path_progression() { let stable = false; - let (router, account, _, token0, token1, token2, token3) = add_multiple_liquidity(stable); + let feeTier = 0; + let (router, account, _, token0, token1, token2, token3) = add_multiple_liquidity( + stable, feeTier + ); let slipTolerance = 50; // 0.5% let amountIn: u256 = with_decimals(1_000); let path: Array:: = array![ - SwapPath { tokenIn: token0.contract_address, tokenOut: token3.contract_address, stable }, - SwapPath { tokenIn: token0.contract_address, tokenOut: token1.contract_address, stable } + SwapPath { + tokenIn: token0.contract_address, tokenOut: token3.contract_address, stable, feeTier + }, + SwapPath { + tokenIn: token0.contract_address, tokenOut: token1.contract_address, stable, feeTier + } ]; let amounts = router.get_amounts_out(amountIn, path.clone()); @@ -1163,11 +1245,16 @@ fn test_router_swap_exact_tokens_for_tokens_supporting_fees_on_transfer_tokens_i #[should_panic(expected: ('insufficient output amount', 'ENTRYPOINT_FAILED', 'ENTRYPOINT_FAILED'))] fn test_router_swap_exact_tokens_for_tokens_invalid() { let stable = false; - let (router, account, _, token0, token1, token2, token3) = add_multiple_liquidity(stable); + let feeTier = 0; + let (router, account, _, token0, token1, token2, token3) = add_multiple_liquidity( + stable, feeTier + ); let amountIn: u256 = with_decimals(1_000); let path: Array:: = array![ - SwapPath { tokenIn: token2.contract_address, tokenOut: token0.contract_address, stable } + SwapPath { + tokenIn: token2.contract_address, tokenOut: token0.contract_address, stable, feeTier + } ]; let amounts = router.get_amounts_out(amountIn, path.clone());