Skip to content

Commit

Permalink
add fee tier
Browse files Browse the repository at this point in the history
  • Loading branch information
iddriss committed Oct 22, 2023
1 parent 56185c5 commit 57b5506
Show file tree
Hide file tree
Showing 12 changed files with 336 additions and 177 deletions.
4 changes: 1 addition & 3 deletions Scarb.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "starkDefi"
version = "1.0.0"
version = "1.1.0"

[[target.starknet-contract]]
allowed-libfuncs-list.name = "experimental"
Expand All @@ -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

Expand Down
52 changes: 34 additions & 18 deletions src/dex/v1/factory/factory.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,25 @@ 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
#[derive(Copy, Drop, Serde, starknet::Store)]
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;
Expand Down Expand Up @@ -69,7 +70,7 @@ mod StarkDFactory {
pair: ContractAddress,
#[key]
stable: bool,
fee: u256,
fee: u8,
}

#[derive(Drop, starknet::Event)]
Expand All @@ -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::<u32, ContractAddress>,
valid_pairs: LegacyMap::<ContractAddress, ValidPair>,
_all_pairs_length: u32,
Expand Down Expand Up @@ -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)
}
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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();
Expand All @@ -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);
Expand Down
40 changes: 28 additions & 12 deletions src/dex/v1/factory/interface.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,31 @@ trait IStarkDFactory<TContractState> {
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::<ContractAddress>);
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);
}

Expand All @@ -32,23 +40,31 @@ trait IStarkDFactoryABI<TContractState> {
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::<ContractAddress>);
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);
Expand Down
11 changes: 9 additions & 2 deletions src/dex/v1/pair/Pair.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ struct Config {
factory: ContractAddress,
vault: ContractAddress,
stable: bool,
fee_tier: u8,
decimal0: u256,
decimal1: u256,
}
Expand Down Expand Up @@ -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');
Expand All @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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) {
Expand Down
3 changes: 3 additions & 0 deletions src/dex/v1/pair/interface.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ trait IStarkDPair<TContractState> {
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);
Expand Down Expand Up @@ -117,6 +118,7 @@ trait IStarkDPairABI<TContractState> {
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);
Expand Down Expand Up @@ -165,6 +167,7 @@ trait IStarkDPairCamelABI<TContractState> {
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);
Expand Down
3 changes: 3 additions & 0 deletions src/dex/v1/router/interface.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ struct SwapPath {
tokenIn: ContractAddress,
tokenOut: ContractAddress,
stable: bool,
feeTier: u8,
}

#[starknet::interface]
Expand All @@ -23,6 +24,7 @@ trait IStarkDRouter<TContractState> {
tokenA: ContractAddress,
tokenB: ContractAddress,
stable: bool,
feeTier: u8,
amountADesired: u256,
amountBDesired: u256,
amountAMin: u256,
Expand All @@ -35,6 +37,7 @@ trait IStarkDRouter<TContractState> {
tokenA: ContractAddress,
tokenB: ContractAddress,
stable: bool,
feeTier: u8,
liquidity: u256,
amountAMin: u256,
amountBMin: u256,
Expand Down
Loading

0 comments on commit 57b5506

Please sign in to comment.