Skip to main content

klend_interface/helpers/
repay.rs

1use solana_instruction::Instruction;
2use solana_pubkey::Pubkey;
3
4use super::{
5    common::{
6        build_deposit_reserves_remaining, build_refresh_all_obligation_reserves,
7        build_refresh_obligation, build_refresh_reserve,
8    },
9    info::{FarmsAccounts, ObligationInfo, ReserveInfo},
10};
11use crate::{
12    instructions::repay::{
13        repay_and_withdraw_and_redeem, repay_obligation_liquidity_v2,
14        RepayAndWithdrawAndRedeemAccounts, RepayObligationLiquidityV2Accounts,
15    },
16    pda::{self, ReservePdas},
17    KLEND_PROGRAM_ID,
18};
19
20/// Build instructions to repay borrowed liquidity.
21///
22/// `obligation_reserves` should contain [`ReserveInfo`] for every deposit and
23/// borrow reserve on the obligation.
24///
25/// Returns: `[refresh_other_reserves..., refresh_repay_reserve, refresh_obligation, repay_obligation_liquidity_v2]`
26pub fn repay(
27    owner: Pubkey,
28    repay_reserve: &ReserveInfo,
29    obligation: &ObligationInfo,
30    obligation_reserves: &[ReserveInfo],
31    user_source_liquidity: Pubkey,
32    liquidity_amount: u64,
33    farms: Option<&FarmsAccounts>,
34) -> Vec<Instruction> {
35    let pdas = ReservePdas::derive(&KLEND_PROGRAM_ID, &repay_reserve.address);
36    let (lma, _) = pda::lending_market_authority(&KLEND_PROGRAM_ID, &repay_reserve.lending_market);
37
38    let remaining = build_deposit_reserves_remaining(obligation);
39
40    let mut ixs = build_refresh_all_obligation_reserves(
41        obligation,
42        obligation_reserves,
43        &[repay_reserve.address],
44    );
45    ixs.push(build_refresh_reserve(repay_reserve));
46    ixs.push(build_refresh_obligation(
47        &repay_reserve.lending_market,
48        obligation,
49    ));
50    ixs.push(repay_obligation_liquidity_v2(
51        RepayObligationLiquidityV2Accounts {
52            owner,
53            obligation: obligation.address,
54            lending_market: repay_reserve.lending_market,
55            repay_reserve: repay_reserve.address,
56            reserve_liquidity_mint: repay_reserve.liquidity_mint,
57            reserve_destination_liquidity: pdas.liquidity_supply_vault,
58            user_source_liquidity,
59            token_program: repay_reserve.liquidity_token_program,
60            obligation_farm_user_state: farms.map(|f| f.obligation_farm_user_state),
61            reserve_farm_state: farms.map(|f| f.reserve_farm_state),
62            lending_market_authority: lma,
63        },
64        liquidity_amount,
65        remaining,
66    ));
67
68    ixs
69}
70
71/// Build instructions to atomically repay a borrow, withdraw collateral, and
72/// redeem it for the underlying liquidity — all in a single instruction.
73///
74/// This is the "close position" flow: repay debt on `repay_reserve`, then
75/// withdraw + redeem collateral from `withdraw_reserve`.
76///
77/// `obligation_reserves` should contain [`ReserveInfo`] for every deposit and
78/// borrow reserve on the obligation.
79///
80/// Returns: `[refresh_other_reserves..., refresh_repay_reserve, refresh_withdraw_reserve,
81///            refresh_obligation, repay_and_withdraw_and_redeem]`
82#[allow(clippy::too_many_arguments)]
83pub fn repay_and_withdraw(
84    owner: Pubkey,
85    repay_reserve: &ReserveInfo,
86    withdraw_reserve: &ReserveInfo,
87    obligation: &ObligationInfo,
88    obligation_reserves: &[ReserveInfo],
89    user_source_liquidity: Pubkey,
90    user_destination_liquidity: Pubkey,
91    repay_amount: u64,
92    withdraw_collateral_amount: u64,
93    collateral_farms: Option<&FarmsAccounts>,
94    debt_farms: Option<&FarmsAccounts>,
95) -> Vec<Instruction> {
96    let (lma, _) = pda::lending_market_authority(&KLEND_PROGRAM_ID, &repay_reserve.lending_market);
97    let repay_pdas = ReservePdas::derive(&KLEND_PROGRAM_ID, &repay_reserve.address);
98    let withdraw_pdas = ReservePdas::derive(&KLEND_PROGRAM_ID, &withdraw_reserve.address);
99
100    let remaining = build_deposit_reserves_remaining(obligation);
101
102    let mut ixs = build_refresh_all_obligation_reserves(
103        obligation,
104        obligation_reserves,
105        &[repay_reserve.address, withdraw_reserve.address],
106    );
107    ixs.push(build_refresh_reserve(repay_reserve));
108    ixs.push(build_refresh_reserve(withdraw_reserve));
109    ixs.push(build_refresh_obligation(
110        &repay_reserve.lending_market,
111        obligation,
112    ));
113    ixs.push(repay_and_withdraw_and_redeem(
114        RepayAndWithdrawAndRedeemAccounts {
115            owner,
116            obligation: obligation.address,
117            lending_market: repay_reserve.lending_market,
118            repay_reserve: repay_reserve.address,
119            reserve_liquidity_mint: repay_reserve.liquidity_mint,
120            reserve_destination_liquidity: repay_pdas.liquidity_supply_vault,
121            user_source_liquidity,
122            token_program: repay_reserve.liquidity_token_program,
123            lending_market_authority: lma,
124            withdraw_reserve: withdraw_reserve.address,
125            withdraw_reserve_liquidity_mint: withdraw_reserve.liquidity_mint,
126            withdraw_reserve_source_collateral: withdraw_pdas.collateral_supply_vault,
127            withdraw_reserve_collateral_mint: withdraw_pdas.collateral_mint,
128            withdraw_reserve_liquidity_supply: withdraw_pdas.liquidity_supply_vault,
129            user_destination_liquidity,
130            placeholder_user_destination_collateral: None,
131            withdraw_liquidity_token_program: withdraw_reserve.liquidity_token_program,
132            collateral_obligation_farm_user_state: collateral_farms
133                .map(|f| f.obligation_farm_user_state),
134            collateral_reserve_farm_state: collateral_farms.map(|f| f.reserve_farm_state),
135            debt_obligation_farm_user_state: debt_farms.map(|f| f.obligation_farm_user_state),
136            debt_reserve_farm_state: debt_farms.map(|f| f.reserve_farm_state),
137        },
138        repay_amount,
139        withdraw_collateral_amount,
140        remaining,
141    ));
142
143    ixs
144}