Skip to main content

klend_interface/helpers/
withdraw_queue.rs

1use solana_instruction::Instruction;
2use solana_pubkey::Pubkey;
3
4use super::{
5    common::build_refresh_reserve,
6    info::{CallbackAccounts, ReserveInfo},
7};
8use crate::{
9    instructions::withdraw_queue::{
10        CancelWithdrawTicketAccounts, EnqueueToWithdrawAccounts, WithdrawQueuedLiquidityAccounts,
11    },
12    pda::{self, ReservePdas},
13    types, KLEND_PROGRAM_ID, TOKEN_PROGRAM_ID,
14};
15
16/// Build instructions to enqueue collateral for delayed withdrawal.
17///
18/// Used for reserves with withdrawal queues. The `ticket_sequence_number` is
19/// the next sequence number from the reserve's withdraw queue state.
20///
21/// Returns: `[refresh_reserve, enqueue_to_withdraw]`
22pub fn enqueue_to_withdraw(
23    owner: Pubkey,
24    reserve: &ReserveInfo,
25    user_source_collateral: Pubkey,
26    user_destination_liquidity: Pubkey,
27    collateral_amount: u64,
28    ticket_sequence_number: u64,
29    callback: Option<&CallbackAccounts>,
30) -> Vec<Instruction> {
31    let pdas = ReservePdas::derive(&KLEND_PROGRAM_ID, &reserve.address);
32    let (lma, _) = pda::lending_market_authority(&KLEND_PROGRAM_ID, &reserve.lending_market);
33    let (ticket, _) =
34        pda::withdraw_ticket(&KLEND_PROGRAM_ID, &reserve.address, ticket_sequence_number);
35    let (queued_vault, _) =
36        pda::owner_queued_collateral_vault(&KLEND_PROGRAM_ID, &reserve.address, &owner);
37
38    let progress_callback_type = callback
39        .map(|c| c.progress_callback_type)
40        .unwrap_or(types::ProgressCallbackType::None);
41
42    vec![
43        build_refresh_reserve(reserve),
44        crate::instructions::withdraw_queue::enqueue_to_withdraw(
45            EnqueueToWithdrawAccounts {
46                owner,
47                lending_market: reserve.lending_market,
48                lending_market_authority: lma,
49                reserve: reserve.address,
50                user_source_collateral_ta: user_source_collateral,
51                user_destination_liquidity_ta: user_destination_liquidity,
52                reserve_liquidity_mint: reserve.liquidity_mint,
53                reserve_collateral_mint: pdas.collateral_mint,
54                withdraw_ticket: ticket,
55                owner_queued_collateral_vault: queued_vault,
56                progress_callback_custom_account_0: callback.and_then(|c| c.custom_account_0),
57                progress_callback_custom_account_1: callback.and_then(|c| c.custom_account_1),
58            },
59            collateral_amount,
60            progress_callback_type,
61        ),
62    ]
63}
64
65/// Build instructions to execute a queued withdrawal (redeem a withdraw ticket).
66///
67/// The `payer` cranks the withdrawal; the ticket owner receives the liquidity.
68///
69/// Returns: `[refresh_reserve, withdraw_queued_liquidity]`
70pub fn withdraw_queued_liquidity(
71    payer: Pubkey,
72    reserve: &ReserveInfo,
73    ticket_owner: Pubkey,
74    user_destination_liquidity: Pubkey,
75    ticket_sequence_number: u64,
76    callback: Option<&CallbackAccounts>,
77) -> Vec<Instruction> {
78    let pdas = ReservePdas::derive(&KLEND_PROGRAM_ID, &reserve.address);
79    let (lma, _) = pda::lending_market_authority(&KLEND_PROGRAM_ID, &reserve.lending_market);
80    let (ticket, _) =
81        pda::withdraw_ticket(&KLEND_PROGRAM_ID, &reserve.address, ticket_sequence_number);
82    let (queued_vault, _) =
83        pda::owner_queued_collateral_vault(&KLEND_PROGRAM_ID, &reserve.address, &ticket_owner);
84
85    let progress_callback_program = callback.and_then(|c| {
86        if c.progress_callback_type != types::ProgressCallbackType::None {
87            Some(c.progress_callback_type.program_address())
88        } else {
89            None
90        }
91    });
92
93    vec![
94        build_refresh_reserve(reserve),
95        crate::instructions::withdraw_queue::withdraw_queued_liquidity(
96            WithdrawQueuedLiquidityAccounts {
97                payer,
98                lending_market: reserve.lending_market,
99                lending_market_authority: lma,
100                reserve: reserve.address,
101                reserve_liquidity_mint: reserve.liquidity_mint,
102                reserve_collateral_mint: pdas.collateral_mint,
103                reserve_liquidity_supply: pdas.liquidity_supply_vault,
104                owner_queued_collateral_vault: queued_vault,
105                user_destination_liquidity,
106                liquidity_token_program: reserve.liquidity_token_program,
107                withdraw_ticket: ticket,
108                withdraw_ticket_owner: ticket_owner,
109                progress_callback_program,
110                progress_callback_custom_account_0: callback.and_then(|c| c.custom_account_0),
111                progress_callback_custom_account_1: callback.and_then(|c| c.custom_account_1),
112            },
113        ),
114    ]
115}
116
117/// Build instructions to cancel a queued withdrawal and recover ctokens.
118///
119/// Returns: `[refresh_reserve, cancel_withdraw_ticket]`
120pub fn cancel_withdraw_ticket(
121    owner: Pubkey,
122    reserve: &ReserveInfo,
123    user_destination_collateral: Pubkey,
124    ticket_sequence_number: u64,
125    collateral_amount_to_cancel: u64,
126) -> Vec<Instruction> {
127    let pdas = ReservePdas::derive(&KLEND_PROGRAM_ID, &reserve.address);
128    let (lma, _) = pda::lending_market_authority(&KLEND_PROGRAM_ID, &reserve.lending_market);
129    let (ticket, _) =
130        pda::withdraw_ticket(&KLEND_PROGRAM_ID, &reserve.address, ticket_sequence_number);
131    let (queued_vault, _) =
132        pda::owner_queued_collateral_vault(&KLEND_PROGRAM_ID, &reserve.address, &owner);
133
134    vec![
135        build_refresh_reserve(reserve),
136        crate::instructions::withdraw_queue::cancel_withdraw_ticket(
137            CancelWithdrawTicketAccounts {
138                owner,
139                lending_market: reserve.lending_market,
140                lending_market_authority: lma,
141                reserve: reserve.address,
142                reserve_collateral_mint: pdas.collateral_mint,
143                owner_queued_collateral_vault: queued_vault,
144                user_destination_collateral,
145                collateral_token_program: TOKEN_PROGRAM_ID,
146                withdraw_ticket: ticket,
147            },
148            ticket_sequence_number,
149            collateral_amount_to_cancel,
150        ),
151    ]
152}