Skip to content

Commit

Permalink
Fix: add option slippage control for deposit and withdraw instructions (
Browse files Browse the repository at this point in the history
  • Loading branch information
RainRaydium authored Sep 29, 2024
1 parent ec2ef3d commit 0a73400
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 5 deletions.
52 changes: 47 additions & 5 deletions program/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ pub struct DepositInstruction {
pub max_coin_amount: u64,
pub max_pc_amount: u64,
pub base_side: u64,
pub other_amount_min: Option<u64>,
}

#[repr(C)]
Expand All @@ -69,6 +70,8 @@ pub struct WithdrawInstruction {
/// Pool token amount to transfer. token_a and token_b amount are set by
/// the current exchange rate and size of the pool
pub amount: u64,
pub min_coin_amount: Option<u64>,
pub min_pc_amount: Option<u64>,
}

#[repr(C)]
Expand Down Expand Up @@ -405,16 +408,34 @@ impl AmmInstruction {
3 => {
let (max_coin_amount, rest) = Self::unpack_u64(rest)?;
let (max_pc_amount, rest) = Self::unpack_u64(rest)?;
let (base_side, _rest) = Self::unpack_u64(rest)?;
let (base_side, rest) = Self::unpack_u64(rest)?;
let other_amount_min = if rest.len() >= 8 {
let (other_amount_min, _rest) = Self::unpack_u64(rest)?;
Some(other_amount_min)
} else {
None
};
Self::Deposit(DepositInstruction {
max_coin_amount,
max_pc_amount,
base_side,
other_amount_min,
})
}
4 => {
let (amount, _rest) = Self::unpack_u64(rest)?;
Self::Withdraw(WithdrawInstruction { amount })
let (amount, rest) = Self::unpack_u64(rest)?;
let (min_coin_amount, min_pc_amount) = if rest.len() >= 16 {
let (min_coin_amount, rest) = Self::unpack_u64(rest)?;
let (min_pc_amount, _rest) = Self::unpack_u64(rest)?;
(Some(min_coin_amount), Some(min_pc_amount))
} else {
(None, None)
};
Self::Withdraw(WithdrawInstruction {
amount,
min_coin_amount,
min_pc_amount,
})
}
5 => Self::MigrateToOpenBook,
6 => {
Expand Down Expand Up @@ -656,15 +677,27 @@ impl AmmInstruction {
max_coin_amount,
max_pc_amount,
base_side,
other_amount_min,
}) => {
buf.push(3);
buf.extend_from_slice(&max_coin_amount.to_le_bytes());
buf.extend_from_slice(&max_pc_amount.to_le_bytes());
buf.extend_from_slice(&base_side.to_le_bytes());
if other_amount_min.is_some() {
buf.extend_from_slice(&other_amount_min.unwrap().to_le_bytes());
}
}
Self::Withdraw(WithdrawInstruction { amount }) => {
Self::Withdraw(WithdrawInstruction {
amount,
min_coin_amount,
min_pc_amount,
}) => {
buf.push(4);
buf.extend_from_slice(&amount.to_le_bytes());
if min_coin_amount.is_some() && min_pc_amount.is_some() {
buf.extend_from_slice(&min_coin_amount.unwrap().to_le_bytes());
buf.extend_from_slice(&min_pc_amount.unwrap().to_le_bytes());
}
}
Self::MigrateToOpenBook => {
buf.push(5);
Expand Down Expand Up @@ -896,11 +929,13 @@ pub fn deposit(
max_coin_amount: u64,
max_pc_amount: u64,
base_side: u64,
other_amount_min: Option<u64>,
) -> Result<Instruction, ProgramError> {
let data = AmmInstruction::Deposit(DepositInstruction {
max_coin_amount,
max_pc_amount,
base_side,
other_amount_min,
})
.pack()?;

Expand Down Expand Up @@ -958,8 +993,15 @@ pub fn withdraw(
referrer_pc_account: Option<&Pubkey>,

amount: u64,
min_coin_amount: Option<u64>,
min_pc_amount: Option<u64>,
) -> Result<Instruction, ProgramError> {
let data = AmmInstruction::Withdraw(WithdrawInstruction { amount }).pack()?;
let data = AmmInstruction::Withdraw(WithdrawInstruction {
amount,
min_coin_amount,
min_pc_amount,
})
.pack()?;

let mut accounts = vec![
// spl token
Expand Down
48 changes: 48 additions & 0 deletions program/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1446,6 +1446,26 @@ impl Processor {
});
return Err(AmmError::ExceededSlippage.into());
}
// base coin, check other_amount_min if need
if deposit.other_amount_min.is_some() {
if deduct_pc_amount < deposit.other_amount_min.unwrap() {
encode_ray_log(DepositLog {
log_type: LogType::Deposit.into_u8(),
max_coin: deposit.max_coin_amount,
max_pc: deposit.max_pc_amount,
base: deposit.base_side,
pool_coin: total_coin_without_take_pnl,
pool_pc: total_pc_without_take_pnl,
pool_lp: amm.lp_amount,
calc_pnl_x: target_orders.calc_pnl_x,
calc_pnl_y: target_orders.calc_pnl_y,
deduct_coin: deduct_coin_amount,
deduct_pc: deduct_pc_amount,
mint_lp: 0,
});
return Err(AmmError::ExceededSlippage.into());
}
}
// coin_amount/ (total_coin_amount + coin_amount)  = output / (lp_mint.supply + output) =>  output = coin_amount / total_coin_amount * lp_mint.supply
let invariant_coin = InvariantPool {
token_input: deduct_coin_amount,
Expand Down Expand Up @@ -1477,6 +1497,27 @@ impl Processor {
});
return Err(AmmError::ExceededSlippage.into());
}
// base pc, check other_amount_min if need
if deposit.other_amount_min.is_some() {
if deduct_coin_amount < deposit.other_amount_min.unwrap() {
encode_ray_log(DepositLog {
log_type: LogType::Deposit.into_u8(),
max_coin: deposit.max_coin_amount,
max_pc: deposit.max_pc_amount,
base: deposit.base_side,
pool_coin: total_coin_without_take_pnl,
pool_pc: total_pc_without_take_pnl,
pool_lp: amm.lp_amount,
calc_pnl_x: target_orders.calc_pnl_x,
calc_pnl_y: target_orders.calc_pnl_y,
deduct_coin: deduct_coin_amount,
deduct_pc: deduct_pc_amount,
mint_lp: 0,
});
return Err(AmmError::ExceededSlippage.into());
}
}

let invariant_pc = InvariantPool {
token_input: deduct_pc_amount,
token_total: total_pc_without_take_pnl,
Expand Down Expand Up @@ -2135,6 +2176,13 @@ impl Processor {
}

if coin_amount < amm_coin_vault.amount && pc_amount < amm_pc_vault.amount {
if withdraw.min_coin_amount.is_some() && withdraw.min_pc_amount.is_some() {
if withdraw.min_coin_amount.unwrap() > coin_amount
|| withdraw.min_pc_amount.unwrap() > pc_amount
{
return Err(AmmError::ExceededSlippage.into());
}
}
Invokers::token_transfer_with_authority(
token_program_info.clone(),
amm_coin_vault_info.clone(),
Expand Down

0 comments on commit 0a73400

Please sign in to comment.