Skip to content

Commit 2c1df09

Browse files
committed
Merge branch 'main' of https://github.com/emarc99/spotnet into fix-685
2 parents d0b114b + a004b5f commit 2c1df09

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+2446
-966
lines changed

margin/.tool-versions

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
scarb 2.9.4
2-
starknet-foundry 0.38.0
2+
starknet-foundry 0.37.0

margin/Scarb.lock

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,17 @@ name = "alexandria_math"
66
version = "0.2.1"
77
source = "git+https://github.com/keep-starknet-strange/alexandria.git#74cafd429eef374730f2c6fed9a74753103c6fdb"
88

9+
[[package]]
10+
name = "ekubo"
11+
version = "0.1.0"
12+
source = "git+https://github.com/ekuboprotocol/abis?rev=edb6de8#edb6de8c9baf515f1053bbab3d86825d54a63bc3"
13+
914
[[package]]
1015
name = "margin"
1116
version = "0.1.0"
1217
dependencies = [
1318
"alexandria_math",
19+
"ekubo",
1420
"openzeppelin_token",
1521
"snforge_std",
1622
]

margin/Scarb.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ edition = "2023_11"
99
starknet = "2.9.4"
1010
openzeppelin_token = "1.0.0"
1111
alexandria_math = { git = "https://github.com/keep-starknet-strange/alexandria.git" }
12+
ekubo = { git = "https://github.com/ekuboprotocol/abis", rev = "edb6de8" }
1213

1314

1415
[dev-dependencies]

margin/src/interface.cairo

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,29 @@
11
use starknet::ContractAddress;
2-
use crate::types::{TokenAmount, PositionParameters};
2+
use crate::types::{TokenAmount, PositionParameters, EkuboSlippageLimits};
3+
use ekubo::types::keys::PoolKey;
34

45
#[starknet::interface]
56
pub trait IMargin<TContractState> {
67
fn deposit(ref self: TContractState, token: ContractAddress, amount: TokenAmount);
78
fn withdraw(ref self: TContractState, token: ContractAddress, amount: TokenAmount);
89

910
// TODO: Add Ekubo data for swap
10-
fn open_margin_position(ref self: TContractState, position_parameters: PositionParameters);
11-
fn close_position(ref self: TContractState);
11+
fn open_margin_position(
12+
ref self: TContractState,
13+
position_parameters: PositionParameters,
14+
pool_key: PoolKey,
15+
ekubo_limits: EkuboSlippageLimits,
16+
);
17+
fn close_position(
18+
ref self: TContractState, pool_key: PoolKey, ekubo_limits: EkuboSlippageLimits,
19+
);
1220

13-
fn liquidate(ref self: TContractState, user: ContractAddress);
21+
fn liquidate(
22+
ref self: TContractState,
23+
user: ContractAddress,
24+
pool_key: PoolKey,
25+
ekubo_limits: EkuboSlippageLimits,
26+
);
1427
}
1528

1629
#[starknet::interface]

margin/src/margin.cairo

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,16 @@ pub mod Margin {
77
storage::{StoragePointerReadAccess, StoragePointerWriteAccess, StoragePathEntry, Map},
88
ContractAddress, get_contract_address, get_caller_address,
99
};
10-
use margin::{interface::IMargin, types::{Position, TokenAmount, PositionParameters}};
10+
use margin::{
11+
interface::IMargin,
12+
types::{Position, TokenAmount, PositionParameters, SwapData, EkuboSlippageLimits},
13+
};
1114
use openzeppelin_token::erc20::interface::{IERC20Dispatcher};
15+
use ekubo::{
16+
interfaces::core::{ICoreDispatcher, ILocker, ICoreDispatcherTrait},
17+
types::{keys::PoolKey, delta::Delta},
18+
components::shared_locker::{consume_callback_data, handle_delta, call_core_with_callback},
19+
};
1220

1321
#[derive(starknet::Event, Drop)]
1422
struct Deposit {
@@ -34,11 +42,26 @@ pub mod Margin {
3442

3543
#[storage]
3644
struct Storage {
45+
ekubo_core: ICoreDispatcher,
3746
treasury_balances: Map<(ContractAddress, ContractAddress), TokenAmount>,
3847
pools: Map<ContractAddress, TokenAmount>,
3948
positions: Map<ContractAddress, Position>,
4049
}
4150

51+
#[constructor]
52+
fn constructor(ref self: ContractState, ekubo_core: ICoreDispatcher) {
53+
self.ekubo_core.write(ekubo_core);
54+
}
55+
56+
57+
#[generate_trait]
58+
pub impl InternalImpl of InternalTrait {
59+
fn swap(ref self: ContractState, swap_data: SwapData) -> Delta {
60+
call_core_with_callback(self.ekubo_core.read(), @swap_data)
61+
}
62+
}
63+
64+
4265
#[abi(embed_v0)]
4366
impl Margin of IMargin<ContractState> {
4467
/// Deposits specified amount of ERC20 tokens into the contract's treasury
@@ -79,9 +102,37 @@ pub mod Margin {
79102
self.emit(Withdraw { withdrawer, token, amount });
80103
}
81104

82-
// TODO: Add Ekubo data for swap
83-
fn open_margin_position(ref self: ContractState, position_parameters: PositionParameters) {}
84-
fn close_position(ref self: ContractState) {}
85-
fn liquidate(ref self: ContractState, user: ContractAddress) {}
105+
fn open_margin_position(
106+
ref self: ContractState,
107+
position_parameters: PositionParameters,
108+
pool_key: PoolKey,
109+
ekubo_limits: EkuboSlippageLimits,
110+
) {}
111+
fn close_position(
112+
ref self: ContractState, pool_key: PoolKey, ekubo_limits: EkuboSlippageLimits,
113+
) {}
114+
fn liquidate(
115+
ref self: ContractState,
116+
user: ContractAddress,
117+
pool_key: PoolKey,
118+
ekubo_limits: EkuboSlippageLimits,
119+
) {}
120+
}
121+
122+
123+
#[abi(embed_v0)]
124+
impl Locker of ILocker<ContractState> {
125+
fn locked(ref self: ContractState, id: u32, data: Span<felt252>) -> Span<felt252> {
126+
let core = self.ekubo_core.read();
127+
let SwapData { pool_key, params, caller } = consume_callback_data(core, data);
128+
let delta = core.swap(pool_key, params);
129+
130+
handle_delta(core, pool_key.token0, delta.amount0, caller);
131+
handle_delta(core, pool_key.token1, delta.amount1, caller);
132+
133+
let mut arr: Array<felt252> = ArrayTrait::new();
134+
Serde::serialize(@delta, ref arr);
135+
arr.span()
136+
}
86137
}
87138
}

margin/src/types.cairo

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use starknet::ContractAddress;
2+
use ekubo::{interfaces::core::SwapParameters, types::keys::PoolKey};
23

34
pub type TokenAmount = u256;
45
pub type Timestamp = u128;
@@ -10,12 +11,25 @@ pub struct PositionParameters {
1011
pub amount: TokenAmount,
1112
}
1213

13-
#[derive(Serde, starknet::Store)]
14+
#[derive(Serde, starknet::Store, Drop)]
1415
pub struct Position {
1516
pub initial_token: ContractAddress,
16-
pub traded_token: ContractAddress,
17+
pub debt_token: ContractAddress,
1718
pub traded_amount: TokenAmount,
1819
pub debt: TokenAmount,
1920
pub is_open: bool,
2021
pub open_time: Timestamp,
2122
}
23+
24+
#[derive(Copy, Serde, Drop)]
25+
pub struct SwapData {
26+
pub params: SwapParameters,
27+
pub pool_key: PoolKey,
28+
pub caller: ContractAddress,
29+
}
30+
31+
#[derive(Copy, Drop, Serde)]
32+
pub struct EkuboSlippageLimits {
33+
pub lower: u256,
34+
pub upper: u256,
35+
}

margin/tests/constants.cairo

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
pub const DEPOSIT_MOCK_USER: felt252 =
2+
0x0038925b0bcf4dce081042ca26a96300d9e181b910328db54a6c89e5451503f5;
3+
pub const DEPOSIT_MOCK_USER_2: felt252 = 0x1234;
4+
pub const HYPOTHETICAL_OWNER_ADDR: felt252 =
5+
0x059a943ca214c10234b9a3b61c558ac20c005127d183b86a99a8f3c60a08b4ff;
6+
7+
pub mod tokens {
8+
pub const ETH: felt252 = 0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7;
9+
pub const USDC: felt252 = 0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8;
10+
}
11+
12+
pub mod pool_key {
13+
pub const FEE: u128 = 170141183460469235273462165868118016;
14+
pub const TICK_SPACING: u128 = 1000;
15+
pub const EXTENSION: felt252 = 0;
16+
}
17+
18+
pub mod contracts {
19+
pub const EKUBO_CORE_MAINNET: felt252 =
20+
0x00000005dd3d2f4429af886cd1a3b08289dbcea99a294197e9eb43b0e0325b4b;
21+
pub const EKUBO_CORE_SEPOLIA: felt252 =
22+
0x0444a09d96389aa7148f1aada508e30b71299ffe650d9c97fdaae38cb9a23384;
23+
}

margin/tests/lib.cairo

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ mod utils;
55
mod mocks {
66
mod erc20_mock;
77
}
8+
9+
mod constants;

margin/tests/test_deposit.cairo

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ use snforge_std::cheatcodes::execution_info::caller_address::{
44
start_cheat_caller_address, stop_cheat_caller_address,
55
};
66
use margin::interface::{IMarginDispatcherTrait};
7-
use super::utils::{
8-
setup_test_suite, deploy_erc20_mock, setup_user, get_treasury_balance, get_pool_value,
7+
use super::{
8+
utils::{
9+
setup_test_suite, deploy_erc20_mock, setup_user, get_treasury_balance, get_pool_value,
10+
},
11+
constants::{
12+
DEPOSIT_MOCK_USER, DEPOSIT_MOCK_USER_2, HYPOTHETICAL_OWNER_ADDR,
13+
},
914
};
1015

11-
const DEPOSIT_MOCK_USER: felt252 =
12-
0x0038925b0bcf4dce081042ca26a96300d9e181b910328db54a6c89e5451503f5;
13-
const DEPOSIT_MOCK_USER_2: felt252 = 0x1234;
14-
const HYPOTHETICAL_OWNER_ADDR: felt252 =
15-
0x059a943ca214c10234b9a3b61c558ac20c005127d183b86a99a8f3c60a08b4ff;
1616

1717
#[test]
1818
#[should_panic(expected: 'Amount is zero')]

margin/tests/utils.cairo

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use snforge_std::cheatcodes::execution_info::caller_address::{
77
use snforge_std::{declare, ContractClassTrait, DeclareResultTrait};
88
use alexandria_math::fast_power::fast_power;
99
use margin::types::TokenAmount;
10+
use super::constants::contracts::EKUBO_CORE_SEPOLIA;
1011

1112
#[derive(Drop)]
1213
pub struct MarginTestSuite {
@@ -63,7 +64,7 @@ pub fn deploy_erc20_mock_2() -> ContractAddress {
6364
pub fn setup_test_suite(owner: ContractAddress, token_address: ContractAddress) -> MarginTestSuite {
6465
let contract = declare("Margin").unwrap().contract_class();
6566

66-
let (margin_contract, _) = contract.deploy(@array![]).unwrap();
67+
let (margin_contract, _) = contract.deploy(@array![EKUBO_CORE_SEPOLIA]).unwrap();
6768

6869
MarginTestSuite {
6970
margin: IMarginDispatcher { contract_address: margin_contract },

0 commit comments

Comments
 (0)