-
Notifications
You must be signed in to change notification settings - Fork 1
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
fix: addressing sandwich attack fix in the deposit function #14
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,9 +4,6 @@ use anchor_spl::token::{self, Mint, Token, TokenAccount, Approve}; | |
use whirlpool::{ | ||
self, | ||
state::{Whirlpool, TickArray, Position}, | ||
math::sqrt_price_from_tick_index, | ||
math::{mul_u256, U256Muldiv}, | ||
manager::liquidity_manager::calculate_liquidity_token_deltas, | ||
cpi::accounts::ModifyLiquidity, | ||
cpi::accounts::UpdateFeesAndRewards, | ||
cpi::accounts::CollectFees | ||
|
@@ -121,9 +118,11 @@ pub mod liquidity_lockbox { | |
/// Deposits an NFT position under the Lockbox management and gets bridged tokens minted in return. | ||
/// | ||
/// ### Parameters | ||
/// - `liquidity_amount` - Requested liquidity amount. | ||
/// - `token_max_a` - Max amount of SOL token to be added for liquidity. | ||
/// - `token_max_b` - Max amount of OLAS token to be added for liquidity. | ||
pub fn deposit(ctx: Context<DepositPositionForLiquidity>, | ||
liquidity_amount: u64, | ||
token_max_a: u64, | ||
token_max_b: u64, | ||
) -> Result<()> { | ||
|
@@ -185,35 +184,10 @@ pub mod liquidity_lockbox { | |
return Err(ErrorCode::OutOfRange.into()); | ||
} | ||
|
||
let sqrt_price_current_x64 = ctx.accounts.whirlpool.sqrt_price; | ||
let sqrt_price_upper_x64 = sqrt_price_from_tick_index(ctx.accounts.position.tick_upper_index); | ||
|
||
// get_liquidity_from_token_a is imported from whirlpools-sdk (getLiquidityFromTokenA) | ||
let liquidity_amount = get_liquidity_from_token_a(token_max_a as u128, sqrt_price_current_x64, sqrt_price_upper_x64)?; | ||
|
||
let (delta_a, delta_b) = calculate_liquidity_token_deltas( | ||
tick_index_current, | ||
sqrt_price_current_x64, | ||
&ctx.accounts.position, | ||
liquidity_amount as i128 | ||
)?; | ||
|
||
// block too much deposit | ||
if delta_a > token_max_a || delta_b > token_max_b { | ||
return Err(ErrorCode::DeltaAmountOverflow.into()); | ||
} | ||
|
||
// Check that the liquidity is within uint64 bounds | ||
if liquidity_amount > std::u64::MAX as u128 { | ||
return Err(ErrorCode::LiquidityOverflow.into()); | ||
} | ||
|
||
let position_liquidity = liquidity_amount as u64; | ||
|
||
Comment on lines
-188
to
-212
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is obsolete as the liquidity amount is already provided. |
||
// Total liquidity update with the check | ||
ctx.accounts.lockbox.total_liquidity = ctx.accounts.lockbox | ||
.total_liquidity | ||
.checked_add(position_liquidity) | ||
.checked_add(liquidity_amount) | ||
.unwrap_or_else(|| panic!("Liquidity overflow")); | ||
|
||
// Approve SOL tokens for the lockbox | ||
|
@@ -226,7 +200,7 @@ pub mod liquidity_lockbox { | |
authority: ctx.accounts.signer.to_account_info(), | ||
}, | ||
), | ||
delta_a, | ||
token_max_a, | ||
Comment on lines
-229
to
+203
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We now approve for max amount of tokens. |
||
)?; | ||
|
||
// Approve OLAS tokens for the lockbox | ||
|
@@ -239,7 +213,7 @@ pub mod liquidity_lockbox { | |
authority: ctx.accounts.signer.to_account_info(), | ||
}, | ||
), | ||
delta_b, | ||
token_max_b, | ||
)?; | ||
|
||
// Get lockbox signer seeds | ||
|
@@ -266,7 +240,7 @@ pub mod liquidity_lockbox { | |
cpi_accounts_modify_liquidity, | ||
signer_seeds | ||
); | ||
whirlpool::cpi::increase_liquidity(cpi_ctx_modify_liquidity, liquidity_amount, delta_a, delta_b)?; | ||
whirlpool::cpi::increase_liquidity(cpi_ctx_modify_liquidity, liquidity_amount as u128, token_max_a, token_max_b)?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what about the approval? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's in the code below :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We approve the max provided amounts, then approve back to zero There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh sorry! the approval is above for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix for .unwrap_or_else(|| panic!("Liquidity overflow")) in another PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will be done in a next PR There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LGTM |
||
|
||
// Mint bridged tokens in the amount of position liquidity | ||
invoke_signed( | ||
|
@@ -276,7 +250,7 @@ pub mod liquidity_lockbox { | |
ctx.accounts.bridged_token_account.to_account_info().key, | ||
ctx.accounts.lockbox.to_account_info().key, | ||
&[ctx.accounts.lockbox.to_account_info().key], | ||
position_liquidity, | ||
liquidity_amount, | ||
)?, | ||
&[ | ||
ctx.accounts.bridged_token_mint.to_account_info(), | ||
|
@@ -287,12 +261,36 @@ pub mod liquidity_lockbox { | |
&[&ctx.accounts.lockbox.seeds()], | ||
)?; | ||
|
||
// Revoke approval for unused SOL tokens | ||
token::approve( | ||
CpiContext::new( | ||
ctx.accounts.token_program.to_account_info(), | ||
Approve { | ||
to: ctx.accounts.token_owner_account_a.to_account_info(), | ||
delegate: ctx.accounts.lockbox.to_account_info(), | ||
authority: ctx.accounts.signer.to_account_info(), | ||
}, | ||
), | ||
0, | ||
)?; | ||
|
||
// Revoke approval for OLAS tokens | ||
token::approve( | ||
CpiContext::new( | ||
ctx.accounts.token_program.to_account_info(), | ||
Approve { | ||
to: ctx.accounts.token_owner_account_b.to_account_info(), | ||
delegate: ctx.accounts.lockbox.to_account_info(), | ||
authority: ctx.accounts.signer.to_account_info(), | ||
}, | ||
), | ||
0, | ||
)?; | ||
Comment on lines
+264
to
+288
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Revoke the approval of unused tokens. |
||
|
||
emit!(DepositEvent { | ||
signer: ctx.accounts.signer.key(), | ||
position: ctx.accounts.position.key(), | ||
amount_a: delta_a, | ||
amount_b: delta_b, | ||
deposit_liquidity: position_liquidity, | ||
deposit_liquidity: liquidity_amount, | ||
total_liquidity: ctx.accounts.lockbox.total_liquidity | ||
}); | ||
|
||
|
@@ -455,34 +453,6 @@ pub mod liquidity_lockbox { | |
} | ||
} | ||
|
||
// https://github.com/orca-so/whirlpools/blob/main/sdk/src/quotes/public/increase-liquidity-quote.ts#L147 | ||
// https://github.com/orca-so/whirlpools/blob/537306c096bcbbf9cb8d5cff337c989dcdd999b4/sdk/src/utils/position-util.ts#L69 | ||
/// Gets liquidity from token A parameters. | ||
/// | ||
/// ### Parameters | ||
/// - `amount` - Token A amount. | ||
/// - `sqrt_price_lower_x64` - Lower sqrt price. | ||
/// - `sqrt_price_upper_x64` - Upper sqrt price. | ||
fn get_liquidity_from_token_a(amount: u128, sqrt_price_lower_x64: u128, sqrt_price_upper_x64: u128 ) -> Result<u128> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This becomes obsolete as there's no need to calculate a liquidity here (already provided). |
||
// Δa = liquidity/sqrt_price_lower - liquidity/sqrt_price_upper | ||
// liquidity = Δa * ((sqrt_price_lower * sqrt_price_upper) / (sqrt_price_upper - sqrt_price_lower)) | ||
assert!(sqrt_price_lower_x64 < sqrt_price_upper_x64); | ||
let sqrt_price_diff = sqrt_price_upper_x64 - sqrt_price_lower_x64; | ||
|
||
let numerator = mul_u256(sqrt_price_lower_x64, sqrt_price_upper_x64); // x64 * x64 | ||
let denominator = U256Muldiv::new(0, sqrt_price_diff); // x64 | ||
|
||
let (quotient, _remainder) = numerator.div(denominator, false); | ||
|
||
let liquidity = quotient | ||
.mul(U256Muldiv::new(0, amount)) | ||
.shift_word_right() | ||
.try_into_u128() | ||
.or(Err(ErrorCode::WhirlpoolNumberDownCastError.into())); | ||
|
||
return liquidity; | ||
} | ||
|
||
#[derive(Accounts)] | ||
pub struct InitializeLiquidityLockbox<'info> { | ||
#[account(mut)] | ||
|
@@ -708,10 +678,6 @@ pub struct DepositEvent { | |
// Liquidity position | ||
#[index] | ||
pub position: Pubkey, | ||
// Amount of SOL token for the liquidity | ||
pub amount_a: u64, | ||
// Amount of OLAS token for the liquidity | ||
pub amount_b: u64, | ||
// Deposit liquidity amount | ||
pub deposit_liquidity: u64, | ||
// Total position liquidity | ||
|
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.
Adding a
liquidity_amount
parameter.