Skip to content

Commit

Permalink
Merge pull request #17 from Starkdefi/feat/fee-tier
Browse files Browse the repository at this point in the history
feat: add fee tiers
  • Loading branch information
iddriss authored Nov 30, 2023
2 parents 56185c5 + 3d49660 commit 98199af
Show file tree
Hide file tree
Showing 15 changed files with 392 additions and 212 deletions.
11 changes: 4 additions & 7 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 All @@ -26,7 +24,6 @@ keystore = "./accounts/testnet_deployer_key.json"
url = "https://starknet-goerli.infura.io/v3/${INFURA_PROJECT_ID}"

[tool.sncast.mainnet]
name="mainnet"
account = "./accounts/mainnet_deployer.json"
keystore = "./accounts/mainnet_deployer_key.json"
url = "https://starknet-mainnet.infura.io/v3/${INFURA_PROJECT_ID}"
account = "mainnet"
accounts-file = "./accounts/mainnet_deployer.json"
url = "https://starknet-mainnet.infura.io/v3/${INFURA_PROJECT_ID}"
66 changes: 39 additions & 27 deletions src/dex/v1/factory/factory.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,32 @@ 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;
use starknet::syscalls::deploy_syscall;
use starknet::replace_class_syscall;
use starkDefi::utils::{ContractAddressPartialOrd};
use starkDefi::utils::upgradeable::{Upgradeable, IUpgradeable};
use starkDefi::utils::upgradable::{Upgradable, IUpgradable};


#[event]
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,16 +312,12 @@ 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);
assert(pair_info.is_valid, 'invalid pair');
if pair_info.is_stable {
pair_info.custom_fee = fee;
} else {
pair_info.custom_fee = fee;
}
pair_info.custom_fee = fee;
self.valid_pairs.write(pair, pair_info);
self.emit(SetPairFee { pair, stable: pair_info.is_stable, fee });
}
Expand Down Expand Up @@ -385,11 +397,11 @@ mod StarkDFactory {

/// @notice upgradable at moment, a future implementation will drop this
#[external(v0)]
impl UpgradableImpl of IUpgradeable<ContractState> {
impl UpgradableImpl of IUpgradable<ContractState> {
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
Modifiers::assert_only_handler(@self);
let mut state = Upgradeable::unsafe_new_contract_state();
Upgradeable::InternalImpl::_upgrade(ref state, new_class_hash);
let mut state = Upgradable::unsafe_new_contract_state();
Upgradable::InternalImpl::_upgrade(ref state, new_class_hash);
}
}

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
Loading

0 comments on commit 98199af

Please sign in to comment.