Skip to main content

klend_interface/helpers/
withdraw.rs

1use solana_instruction::Instruction;
2use solana_pubkey::Pubkey;
3
4use super::{
5    common::{
6        build_refresh_all_obligation_reserves, build_refresh_obligation, build_refresh_reserve,
7    },
8    info::{FarmsAccounts, ObligationInfo, ReserveInfo},
9};
10use crate::{
11    instructions::withdraw::{
12        redeem_reserve_collateral, withdraw_obligation_collateral_and_redeem_reserve_collateral_v2,
13        withdraw_obligation_collateral_v2, RedeemReserveCollateralAccounts,
14        WithdrawObligationCollateralAndRedeemReserveCollateralV2Accounts,
15        WithdrawObligationCollateralV2Accounts,
16    },
17    pda::{self, ReservePdas},
18    KLEND_PROGRAM_ID,
19};
20
21/// Build instructions to withdraw collateral from an obligation **and** redeem
22/// it for the underlying liquidity tokens.
23///
24/// `obligation_reserves` should contain [`ReserveInfo`] for every deposit and
25/// borrow reserve on the obligation. Any reserves not already refreshed by this
26/// helper are refreshed automatically so that `refresh_obligation` succeeds.
27///
28/// Returns: `[refresh_other_reserves..., refresh_withdraw_reserve, refresh_obligation, withdraw_and_redeem]`
29pub fn withdraw(
30    owner: Pubkey,
31    withdraw_reserve: &ReserveInfo,
32    obligation: &ObligationInfo,
33    obligation_reserves: &[ReserveInfo],
34    user_destination_liquidity: Pubkey,
35    collateral_amount: u64,
36    farms: Option<&FarmsAccounts>,
37) -> Vec<Instruction> {
38    let pdas = ReservePdas::derive(&KLEND_PROGRAM_ID, &withdraw_reserve.address);
39    let (lma, _) =
40        pda::lending_market_authority(&KLEND_PROGRAM_ID, &withdraw_reserve.lending_market);
41
42    let mut ixs = build_refresh_all_obligation_reserves(
43        obligation,
44        obligation_reserves,
45        &[withdraw_reserve.address],
46    );
47    ixs.push(build_refresh_reserve(withdraw_reserve));
48    ixs.push(build_refresh_obligation(
49        &withdraw_reserve.lending_market,
50        obligation,
51    ));
52    ixs.push(
53        withdraw_obligation_collateral_and_redeem_reserve_collateral_v2(
54            WithdrawObligationCollateralAndRedeemReserveCollateralV2Accounts {
55                owner,
56                obligation: obligation.address,
57                lending_market: withdraw_reserve.lending_market,
58                lending_market_authority: lma,
59                withdraw_reserve: withdraw_reserve.address,
60                reserve_liquidity_mint: withdraw_reserve.liquidity_mint,
61                reserve_source_collateral: pdas.collateral_supply_vault,
62                reserve_collateral_mint: pdas.collateral_mint,
63                reserve_liquidity_supply: pdas.liquidity_supply_vault,
64                user_destination_liquidity,
65                placeholder_user_destination_collateral: None,
66                liquidity_token_program: withdraw_reserve.liquidity_token_program,
67                obligation_farm_user_state: farms.map(|f| f.obligation_farm_user_state),
68                reserve_farm_state: farms.map(|f| f.reserve_farm_state),
69            },
70            collateral_amount,
71        ),
72    );
73
74    ixs
75}
76
77/// Build instructions to withdraw collateral (cTokens) from an obligation
78/// **without** redeeming them for liquidity.
79///
80/// `obligation_reserves` should contain [`ReserveInfo`] for every deposit and
81/// borrow reserve on the obligation.
82///
83/// Returns: `[refresh_other_reserves..., refresh_withdraw_reserve, refresh_obligation, withdraw_obligation_collateral_v2]`
84pub fn withdraw_collateral(
85    owner: Pubkey,
86    withdraw_reserve: &ReserveInfo,
87    obligation: &ObligationInfo,
88    obligation_reserves: &[ReserveInfo],
89    user_destination_collateral: Pubkey,
90    collateral_amount: u64,
91    farms: Option<&FarmsAccounts>,
92) -> Vec<Instruction> {
93    let pdas = ReservePdas::derive(&KLEND_PROGRAM_ID, &withdraw_reserve.address);
94    let (lma, _) =
95        pda::lending_market_authority(&KLEND_PROGRAM_ID, &withdraw_reserve.lending_market);
96
97    let mut ixs = build_refresh_all_obligation_reserves(
98        obligation,
99        obligation_reserves,
100        &[withdraw_reserve.address],
101    );
102    ixs.push(build_refresh_reserve(withdraw_reserve));
103    ixs.push(build_refresh_obligation(
104        &withdraw_reserve.lending_market,
105        obligation,
106    ));
107    ixs.push(withdraw_obligation_collateral_v2(
108        WithdrawObligationCollateralV2Accounts {
109            owner,
110            obligation: obligation.address,
111            lending_market: withdraw_reserve.lending_market,
112            lending_market_authority: lma,
113            withdraw_reserve: withdraw_reserve.address,
114            reserve_source_collateral: pdas.collateral_supply_vault,
115            user_destination_collateral,
116            obligation_farm_user_state: farms.map(|f| f.obligation_farm_user_state),
117            reserve_farm_state: farms.map(|f| f.reserve_farm_state),
118        },
119        collateral_amount,
120    ));
121
122    ixs
123}
124
125/// Build instructions to redeem cTokens for underlying liquidity (no obligation).
126///
127/// Returns: `[refresh_reserve, redeem_reserve_collateral]`
128pub fn redeem(
129    owner: Pubkey,
130    reserve: &ReserveInfo,
131    user_source_collateral: Pubkey,
132    user_destination_liquidity: Pubkey,
133    collateral_amount: u64,
134) -> Vec<Instruction> {
135    let pdas = ReservePdas::derive(&KLEND_PROGRAM_ID, &reserve.address);
136    let (lma, _) = pda::lending_market_authority(&KLEND_PROGRAM_ID, &reserve.lending_market);
137
138    vec![
139        build_refresh_reserve(reserve),
140        redeem_reserve_collateral(
141            RedeemReserveCollateralAccounts {
142                owner,
143                lending_market: reserve.lending_market,
144                reserve: reserve.address,
145                lending_market_authority: lma,
146                reserve_liquidity_mint: reserve.liquidity_mint,
147                reserve_collateral_mint: pdas.collateral_mint,
148                reserve_liquidity_supply: pdas.liquidity_supply_vault,
149                user_source_collateral,
150                user_destination_liquidity,
151                liquidity_token_program: reserve.liquidity_token_program,
152            },
153            collateral_amount,
154        ),
155    ]
156}