-
Notifications
You must be signed in to change notification settings - Fork 111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tests and contract rework for audit #69
Conversation
Dashboard-API-fixing
dashboard backendUrl update
Added plug to dashboard in case of missing API data
…and made draft tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is decided through which Ekubo pools you'll be routing? (Did you look into that?)
src/deposit.cairo
Outdated
/// * `debt_token`: ContractAddress - Address of the token used as borrowing. | ||
/// * `pool_key`: PoolKey - Ekubo type for obtaining info about the pool and swapping | ||
/// tokens. | ||
/// * `supply_price`: felt252 - Price of `supply` token in terms of `debt` token in Ekubo |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it exactly just price? How is that expressed? It must be a fraction or fixed point number right; what kind is it? (edit: later found in docs)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And – can you give an example where supply_price is > 2**128? (I don't think it can reach that high?)
This format is used in Ekubo? (I don't think so)
I don't think it makes sense to have the price be in relation to one "full" (human-readable) unit; then you need to fiddle with decimals.
So 2 questions:
- Why do you need the price? (Future slippage calculation?)
- Don't you get the price from Ekubo after executing a swap?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Why aren't you using the same format as Ekubo (since that's where you interact with the price) for storing the price? (You will then be able to truly get rid of decimals:) (I understand the Ekubo math is very hard and it might very well be a good reason)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Calculation of how much can I borrow from zkLend, we will borrow 80%(I will try and test lower value) of allowed amount so precise median price from the oracles as used in zkLend is not required I suppose.
- It's not given exactly on swap. However I can get pool price from Ekubo as sqrt_ratio and then convert to the normal price. I am concerned about price of base token in terms of quote token(so ETH amount for USDC in ETH/USDC) and I wanted to calculate it on backend with normal decimals, but I should be able to handle it to depend on external params less.
- Ekubo using prices as ticks or sqrt_ratio and zkLend as normal amounts, so there is a need for conversions unfortunately.
src/deposit.cairo
Outdated
let SQRT_LIMIT_REPAY = if supply_token == pool_key.token0 { | ||
18446748437148339061 | ||
} else { | ||
(6277100250585753475930931601400621808602321654880405518632, 18446748437148339061) | ||
6277100250585753475930931601400621808602321654880405518632 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is essentially the max slippage no? Is it correct to hardcode it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I will calculate 3-5% slippage from current sqrt_ratio
src/deposit.cairo
Outdated
assert( | ||
amount * usdc_price / deposit_token_decimals.into() >= 1000000, | ||
'Loop amount is too small' | ||
); // User needs to have at least 1 USDC, so rounded down amount is OK. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are only using usdc_price to calculate whether the loan amount is at least 1 USDC.
- Why is this limitation in place?
- This does not actually check anything because the caller can spoof the usdc_price. (!!)
- If this is really necessary (and I don't think it is), you can adjust the usdc_price format such that you don't need to fetch decimals! (Basically embed the decimals there and pass only the ratio)
- usdc_price is actually not really price of USDC, is it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added it because sometimes for small amounts depositing and borrowing is failing because of number of iterations(or steps made by program). I can remove it but sometimes transaction will fail with unclear message(same will be if user or our frontend inputs wrong price). I had some doubts when adding this because of the same reason, so I will remove it and try to locate the reason and location of fail, it's number of iterations I would consider limiting it instead(number of deposits and borrowings in a loop).
) { | ||
assert(get_caller_address() == self.owner.read(), 'Caller is not an owner'); | ||
// TODO: Add borrow factor | ||
let user_acount = get_tx_info().unbox().account_contract_address; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not get_caller_address() ? (Maybe it was removed in a new Cairo version that I'm not yet aware of?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was made because of testing troubles. In a contract, when swapping we are getting callback from Ekubo. When using normal cheat_caller_address, it cheats all input calls to the contract, and code fails with 'Caller is not the core' error from Ekubo core contract, so I cheat the account that initiated transaction instead(practically it should be the caller themself). However I agree this functionality is an unusual and unpredicted, so I should include it in the docs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think okay to just add an explainer comment like this to the code. Interesting!
is_token1: !is_token1_repay_swap, | ||
sqrt_ratio_limit: SQRT_LIMIT_WITHDRAW, | ||
skip_ahead: 0 | ||
debt = zk_market.get_user_debt_for_token(contract_address, debt_token).into(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you previously called repay_all (line 311), this will be zero, no? Either remove or assert that it's zero in that case.
feat: function claim_rewards for claiming DeFi Spring rewards
docs/spotnet.md
Outdated
* `supply_price`: TokenPrice - Price of `supply` token in terms of `debt` token in Ekubo pool(so for ex. 2400000000 USDC for ETH). | ||
* `debt_price`: TokenPrice - Price of `debt` token in terms of `supply` token in Ekubo pool(for ex. 410000000000000 ETH for USDC). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this really the price in Ekubo pool?
src/deposit.cairo
Outdated
let amount_base_token = token_price * borrow_capacity; | ||
let amount_quote_token = amount_base_token.into() / decimals_difference.into(); | ||
((amount_quote_token - total_borrowed.into()) / 100_u256 * borrow_const).try_into().unwrap() | ||
let borrow_const = 60; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This depends on the asset, no? It can change as zkLend changes its risk parameters I think?
But maybe the only thing this will cause is that it will loop more times than necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zkLend risk parameters are borrow and collateral factors and we are getting them from their contract. This one is how much of available amount we are borrowing(approximately 60% now), while causing looping more times, lower value will increase health factor. I can add it to the constructor so we'll be able to change it dynamically without changing the code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why should that matter? Why can't we be borrowing 99 %? The health factor is decided by the leverage at the end only.
src/deposit.cairo
Outdated
let curr_contract_address = get_contract_address(); | ||
assert( | ||
token_dispatcher.allowance(user_acount, curr_contract_address) >= amount, | ||
'Approved amount incuficient' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
src/deposit.cairo
Outdated
let mut deposited = amount; | ||
let mut total_borrowed = 0; | ||
let mut accumulated = 0; | ||
let (mut total_borrowed, mut accumulated, mut deposited) = (0, 0, amount); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would just keep this on three separate lines
src/types.cairo
Outdated
use starknet::ContractAddress; | ||
|
||
pub type TokenPrice = u256; | ||
pub type TokenPrice = u128; | ||
pub type TokenAmount = u256; | ||
pub type Decimals = u64; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't actually store Decimals in this data type, you store 10**x where x is the decimal count, which is unclear
src/deposit.cairo
Outdated
proof: Span<felt252>, | ||
airdrop_addr: ContractAddress | ||
) { | ||
assert(self.is_position_open.read(), 'Open position not exists'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if the position was closed in the meantime? Why do we need this check?
src/deposit.cairo
Outdated
airdrop_addr: ContractAddress | ||
) { | ||
assert(self.is_position_open.read(), 'Open position not exists'); | ||
assert(proof.len() != 0, 'Proof Span cannot be empty'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate the defensiveness, but this is not necessary; it will fail when calling claim() anyway
No description provided.