Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 32 additions & 9 deletions programs/clmm/src/instructions/decrease_liquidity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub fn decrease_liquidity<'b, 'c: 'info, 'info>(
tick_array_upper_info: &AccountInfo<'info>,
recipient_token_account_0: &AccountInfo<'info>,
recipient_token_account_1: &AccountInfo<'info>,
rent_recipient: &AccountInfo<'info>,
token_program: &'b Program<'info, Token>,
token_program_2022: Option<Program<'info, Token2022>>,
_memo_program: Option<UncheckedAccount<'info>>,
Expand Down Expand Up @@ -89,6 +90,7 @@ pub fn decrease_liquidity<'b, 'c: 'info, 'info>(
tick_array_lower_info,
tick_array_upper_info,
tickarray_bitmap_extension,
rent_recipient,
liquidity,
)?;

Expand Down Expand Up @@ -198,6 +200,7 @@ pub fn decrease_liquidity_and_update_position<'c: 'info, 'info>(
tick_array_lower_info: &AccountInfo<'info>,
tick_array_upper_info: &AccountInfo<'info>,
tick_array_bitmap_extension: Option<&'c AccountInfo<'info>>,
rent_recipient: &AccountInfo<'info>,
liquidity: u128,
) -> Result<(u64, u64, u64, u64)> {
let mut pool_state = pool_state_loader.load_mut()?;
Expand All @@ -216,6 +219,7 @@ pub fn decrease_liquidity_and_update_position<'c: 'info, 'info>(
tick_array_lower_info,
tick_array_upper_info,
tick_array_bitmap_extension,
rent_recipient,
personal_position.tick_lower_index,
personal_position.tick_upper_index,
liquidity,
Expand Down Expand Up @@ -273,6 +277,7 @@ pub fn burn_liquidity<'c: 'info, 'info>(
tick_array_lower_info: &AccountInfo<'info>,
tick_array_upper_info: &AccountInfo<'info>,
tickarray_bitmap_extension: Option<&'c AccountInfo<'info>>,
rent_recipient: &AccountInfo<'info>,
tick_lower_index: i32,
tick_upper_index: i32,
liquidity: u128,
Expand Down Expand Up @@ -330,27 +335,45 @@ pub fn burn_liquidity<'c: 'info, 'info>(
}; // Drop mutable borrows here
drop(tick_arrays); // Release RefMut so realloc and re-load can access the account

// Realloc for dynamic tick arrays (shrink only, no rent refund)
// Realloc for dynamic tick arrays (shrink) and refund excess rent to caller
let rent = Rent::get()?;
if is_same_array {
let mut delta: i64 = 0;
if result.tick_array_realloc.lower_shrink { delta -= DynamicTickData::LEN as i64; }
if result.tick_array_realloc.upper_shrink { delta -= DynamicTickData::LEN as i64; }
if delta < 0 {
let new_size = (tick_array_lower_info.data_len() as i64 + delta) as usize;
tick_array_lower_info.realloc(new_size, true)?;
let excess = tick_array_lower_info.lamports()
.checked_sub(rent.minimum_balance(new_size))
.unwrap_or(0);
if excess > 0 {
**tick_array_lower_info.try_borrow_mut_lamports()? -= excess;
**rent_recipient.try_borrow_mut_lamports()? += excess;
}
}
} else {
if result.tick_array_realloc.lower_shrink {
tick_array_lower_info.realloc(
tick_array_lower_info.data_len() - DynamicTickData::LEN,
true,
)?;
let new_size = tick_array_lower_info.data_len() - DynamicTickData::LEN;
tick_array_lower_info.realloc(new_size, true)?;
let excess = tick_array_lower_info.lamports()
.checked_sub(rent.minimum_balance(new_size))
.unwrap_or(0);
if excess > 0 {
**tick_array_lower_info.try_borrow_mut_lamports()? -= excess;
**rent_recipient.try_borrow_mut_lamports()? += excess;
}
}
if result.tick_array_realloc.upper_shrink {
tick_array_upper_info.realloc(
tick_array_upper_info.data_len() - DynamicTickData::LEN,
true,
)?;
let new_size = tick_array_upper_info.data_len() - DynamicTickData::LEN;
tick_array_upper_info.realloc(new_size, true)?;
let excess = tick_array_upper_info.lamports()
.checked_sub(rent.minimum_balance(new_size))
.unwrap_or(0);
if excess > 0 {
**tick_array_upper_info.try_borrow_mut_lamports()? -= excess;
**rent_recipient.try_borrow_mut_lamports()? += excess;
}
}
}

Expand Down
5 changes: 4 additions & 1 deletion programs/clmm/src/instructions/decrease_liquidity_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use anchor_spl::token_interface::{Token2022, TokenAccount};
#[derive(Accounts)]
pub struct DecreaseLiquidityV2<'info> {
/// The position owner or delegated authority
#[account(mut)]
pub nft_owner: Signer<'info>,

/// The token account for the tokenized position
Expand Down Expand Up @@ -107,13 +108,14 @@ pub fn decrease_liquidity_v2<'a, 'b, 'c: 'info, 'info>(
amount_1_min: u64,
) -> Result<()> {
// Store AccountInfo values to avoid temporary lifetime issues
let nft_owner_info = ctx.accounts.nft_owner.to_account_info();
let tick_array_lower_info = ctx.accounts.tick_array_lower.to_account_info();
let tick_array_upper_info = ctx.accounts.tick_array_upper.to_account_info();
let token_vault_0_info = ctx.accounts.token_vault_0.to_account_info();
let token_vault_1_info = ctx.accounts.token_vault_1.to_account_info();
let recipient_token_account_0_info = ctx.accounts.recipient_token_account_0.to_account_info();
let recipient_token_account_1_info = ctx.accounts.recipient_token_account_1.to_account_info();

decrease_liquidity(
&ctx.accounts.pool_state,
&mut ctx.accounts.personal_position,
Expand All @@ -123,6 +125,7 @@ pub fn decrease_liquidity_v2<'a, 'b, 'c: 'info, 'info>(
&tick_array_upper_info,
&recipient_token_account_0_info,
&recipient_token_account_1_info,
&nft_owner_info,
&ctx.accounts.token_program,
Some(ctx.accounts.token_program_2022.clone()),
Some(ctx.accounts.memo_program.clone()),
Expand Down
2 changes: 1 addition & 1 deletion tests/helpers/init-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ export async function decreaseLiquidity(
const ix = new TransactionInstruction({
programId: PROGRAM_ID,
keys: [
{ pubkey: payer.publicKey, isSigner: true, isWritable: false }, // nft_owner
{ pubkey: payer.publicKey, isSigner: true, isWritable: true }, // nft_owner (mut for rent refund)
{ pubkey: positionNftAccount, isSigner: false, isWritable: false }, // nft_account
{ pubkey: personalPosition, isSigner: false, isWritable: true }, // personal_position
{ pubkey: poolPda, isSigner: false, isWritable: true }, // pool_state
Expand Down
Loading