solend_sdk/
instruction.rs

1//! Instruction types
2
3use crate::{
4    error::LendingError,
5    state::{ReserveConfig, ReserveFees},
6};
7use solana_program::{
8    instruction::{AccountMeta, Instruction},
9    msg,
10    program_error::ProgramError,
11    pubkey::{Pubkey, PUBKEY_BYTES},
12    sysvar,
13};
14use std::{convert::TryInto, mem::size_of};
15
16/// Instructions supported by the lending program.
17#[derive(Clone, Debug, PartialEq, Eq)]
18pub enum LendingInstruction {
19    // 0
20    /// Initializes a new lending market.
21    ///
22    /// Accounts expected by this instruction:
23    ///
24    ///   0. `[writable]` Lending market account - uninitialized.
25    ///   1. `[]` Rent sysvar.
26    ///   2. `[]` Token program id.
27    ///   3. `[]` Oracle program id.
28    ///   4. `[]` Switchboard Oracle program id.
29    InitLendingMarket {
30        /// Owner authority which can add new reserves
31        owner: Pubkey,
32        /// Currency market prices are quoted in
33        /// e.g. "USD" null padded (`*b"USD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"`) or SPL token mint pubkey
34        quote_currency: [u8; 32],
35    },
36
37    // 1
38    /// Sets the new owner of a lending market.
39    ///
40    /// Accounts expected by this instruction:
41    ///
42    ///   0. `[writable]` Lending market account.
43    ///   1. `[signer]` Current owner.
44    SetLendingMarketOwner {
45        /// The new owner
46        new_owner: Pubkey,
47    },
48
49    // 2
50    /// Initializes a new lending market reserve.
51    ///
52    /// Accounts expected by this instruction:
53    ///
54    ///   0. `[writable]` Source liquidity token account.
55    ///                     $authority can transfer $liquidity_amount.
56    ///   1. `[writable]` Destination collateral token account - uninitialized.
57    ///   2. `[writable]` Reserve account - uninitialized.
58    ///   3. `[]` Reserve liquidity SPL Token mint.
59    ///   4. `[writable]` Reserve liquidity supply SPL Token account - uninitialized.
60    ///   5. `[writable]` Reserve liquidity fee receiver - uninitialized.
61    ///   6. `[writable]` Reserve collateral SPL Token mint - uninitialized.
62    ///   7 `[writable]` Reserve collateral token supply - uninitialized.
63    ///   8. `[]` Pyth product account.
64    ///   9. `[]` Pyth price account.
65    ///             This will be used as the reserve liquidity oracle account.
66    ///   10. `[]` Switchboard price feed account. used as a backup oracle
67    ///   11 `[]` Lending market account.
68    ///   12 `[]` Derived lending market authority.
69    ///   13 `[signer]` Lending market owner.
70    ///   14 `[signer]` User transfer authority ($authority).
71    ///   15 `[]` Clock sysvar (optional, will be removed soon).
72    ///   16 `[]` Rent sysvar.
73    ///   17 `[]` Token program id.
74    InitReserve {
75        /// Initial amount of liquidity to deposit into the new reserve
76        liquidity_amount: u64,
77        /// Reserve configuration values
78        config: ReserveConfig,
79    },
80
81    // 3
82    /// Accrue interest and update market price of liquidity on a reserve.
83    ///
84    /// Accounts expected by this instruction:
85    ///
86    ///   0. `[writable]` Reserve account.
87    ///   1. `[]` Pyth Reserve liquidity oracle account.
88    ///             Must be the Pyth price account specified at InitReserve.
89    ///   2. `[]` Switchboard Reserve liquidity oracle account.
90    ///             Must be the Switchboard price feed account specified at InitReserve.
91    ///   3. `[]` Clock sysvar (optional, will be removed soon).
92    RefreshReserve,
93
94    // 4
95    /// Deposit liquidity into a reserve in exchange for collateral. Collateral represents a share
96    /// of the reserve liquidity pool.
97    ///
98    /// Accounts expected by this instruction:
99    ///
100    ///   0. `[writable]` Source liquidity token account.
101    ///                     $authority can transfer $liquidity_amount.
102    ///   1. `[writable]` Destination collateral token account.
103    ///   2. `[writable]` Reserve account.
104    ///   3. `[writable]` Reserve liquidity supply SPL Token account.
105    ///   4. `[writable]` Reserve collateral SPL Token mint.
106    ///   5. `[]` Lending market account.
107    ///   6. `[]` Derived lending market authority.
108    ///   7. `[signer]` User transfer authority ($authority).
109    ///   8. `[]` Clock sysvar (optional, will be removed soon).
110    ///   9. `[]` Token program id.
111    DepositReserveLiquidity {
112        /// Amount of liquidity to deposit in exchange for collateral tokens
113        liquidity_amount: u64,
114    },
115
116    // 5
117    /// Redeem collateral from a reserve in exchange for liquidity.
118    ///
119    /// Accounts expected by this instruction:
120    ///
121    ///   0. `[writable]` Source collateral token account.
122    ///                     $authority can transfer $collateral_amount.
123    ///   1. `[writable]` Destination liquidity token account.
124    ///   2. `[writable]` Reserve account.
125    ///   3. `[writable]` Reserve collateral SPL Token mint.
126    ///   4. `[writable]` Reserve liquidity supply SPL Token account.
127    ///   5. `[]` Lending market account.
128    ///   6. `[]` Derived lending market authority.
129    ///   7. `[signer]` User transfer authority ($authority).
130    ///   8. `[]` Clock sysvar (optional, will be removed soon).
131    ///   9. `[]` Token program id.
132    RedeemReserveCollateral {
133        /// Amount of collateral tokens to redeem in exchange for liquidity
134        collateral_amount: u64,
135    },
136
137    // 6
138    /// Initializes a new lending market obligation.
139    ///
140    /// Accounts expected by this instruction:
141    ///
142    ///   0. `[writable]` Obligation account - uninitialized.
143    ///   1. `[]` Lending market account.
144    ///   2. `[signer]` Obligation owner.
145    ///   3. `[]` Clock sysvar (optional, will be removed soon).
146    ///   4. `[]` Rent sysvar.
147    ///   5. `[]` Token program id.
148    InitObligation,
149
150    // 7
151    /// Refresh an obligation's accrued interest and collateral and liquidity prices. Requires
152    /// refreshed reserves, as all obligation collateral deposit reserves in order, followed by all
153    /// liquidity borrow reserves in order.
154    ///
155    /// Accounts expected by this instruction:
156    ///
157    ///   0. `[writable]` Obligation account.
158    ///   1. `[]` Clock sysvar (optional, will be removed soon).
159    ///   .. `[]` Collateral deposit reserve accounts - refreshed, all, in order.
160    ///   .. `[]` Liquidity borrow reserve accounts - refreshed, all, in order.
161    RefreshObligation,
162
163    // 8
164    /// Deposit collateral to an obligation.
165    ///
166    /// Accounts expected by this instruction:
167    ///
168    ///   0. `[writable]` Source collateral token account.
169    ///                     Minted by deposit reserve collateral mint.
170    ///                     $authority can transfer $collateral_amount.
171    ///   1. `[writable]` Destination deposit reserve collateral supply SPL Token account.
172    ///   2. `[writable]` Deposit reserve account.
173    ///   3. `[writable]` Obligation account.
174    ///   4. `[]` Lending market account.
175    ///   5. `[signer]` Obligation owner.
176    ///   6. `[signer]` User transfer authority ($authority).
177    ///   7. `[]` Clock sysvar (optional, will be removed soon).
178    ///   8. `[]` Token program id.
179    DepositObligationCollateral {
180        /// Amount of collateral tokens to deposit
181        collateral_amount: u64,
182    },
183
184    // 9
185    /// Withdraw collateral from an obligation. Requires a refreshed obligation and reserve.
186    ///
187    /// Accounts expected by this instruction:
188    ///
189    ///   0. `[writable]` Source withdraw reserve collateral supply SPL Token account.
190    ///   1. `[writable]` Destination collateral token account.
191    ///                     Minted by withdraw reserve collateral mint.
192    ///   2. `[]` Withdraw reserve account - refreshed.
193    ///   3. `[writable]` Obligation account - refreshed.
194    ///   4. `[]` Lending market account.
195    ///   5. `[]` Derived lending market authority.
196    ///   6. `[signer]` Obligation owner.
197    ///   7. `[]` Clock sysvar (optional, will be removed soon).
198    ///   8. `[]` Token program id.
199    WithdrawObligationCollateral {
200        /// Amount of collateral tokens to withdraw - u64::MAX for up to 100% of deposited amount
201        collateral_amount: u64,
202    },
203
204    // 10
205    /// Borrow liquidity from a reserve by depositing collateral tokens. Requires a refreshed
206    /// obligation and reserve.
207    ///
208    /// Accounts expected by this instruction:
209    ///
210    ///   0. `[writable]` Source borrow reserve liquidity supply SPL Token account.
211    ///   1. `[writable]` Destination liquidity token account.
212    ///                     Minted by borrow reserve liquidity mint.
213    ///   2. `[writable]` Borrow reserve account - refreshed.
214    ///   3. `[writable]` Borrow reserve liquidity fee receiver account.
215    ///                     Must be the fee account specified at InitReserve.
216    ///   4. `[writable]` Obligation account - refreshed.
217    ///   5. `[]` Lending market account.
218    ///   6. `[]` Derived lending market authority.
219    ///   7. `[signer]` Obligation owner.
220    ///   8. `[]` Clock sysvar (optional, will be removed soon).
221    ///   9. `[]` Token program id.
222    ///   10 `[optional, writable]` Host fee receiver account.
223    BorrowObligationLiquidity {
224        /// Amount of liquidity to borrow - u64::MAX for 100% of borrowing power
225        liquidity_amount: u64,
226        // @TODO: slippage constraint - https://git.io/JmV67
227    },
228
229    // 11
230    /// Repay borrowed liquidity to a reserve. Requires a refreshed obligation and reserve.
231    ///
232    /// Accounts expected by this instruction:
233    ///
234    ///   0. `[writable]` Source liquidity token account.
235    ///                     Minted by repay reserve liquidity mint.
236    ///                     $authority can transfer $liquidity_amount.
237    ///   1. `[writable]` Destination repay reserve liquidity supply SPL Token account.
238    ///   2. `[writable]` Repay reserve account - refreshed.
239    ///   3. `[writable]` Obligation account - refreshed.
240    ///   4. `[]` Lending market account.
241    ///   5. `[signer]` User transfer authority ($authority).
242    ///   6. `[]` Clock sysvar (optional, will be removed soon).
243    ///   7. `[]` Token program id.
244    RepayObligationLiquidity {
245        /// Amount of liquidity to repay - u64::MAX for 100% of borrowed amount
246        liquidity_amount: u64,
247    },
248
249    // 12
250    /// Repay borrowed liquidity to a reserve to receive collateral at a discount from an unhealthy
251    /// obligation. Requires a refreshed obligation and reserves.
252    ///
253    /// Accounts expected by this instruction:
254    ///
255    ///   0. `[writable]` Source liquidity token account.
256    ///                     Minted by repay reserve liquidity mint.
257    ///                     $authority can transfer $liquidity_amount.
258    ///   1. `[writable]` Destination collateral token account.
259    ///                     Minted by withdraw reserve collateral mint.
260    ///   2. `[writable]` Repay reserve account - refreshed.
261    ///   3. `[writable]` Repay reserve liquidity supply SPL Token account.
262    ///   4. `[]` Withdraw reserve account - refreshed.
263    ///   5. `[writable]` Withdraw reserve collateral supply SPL Token account.
264    ///   6. `[writable]` Obligation account - refreshed.
265    ///   7. `[]` Lending market account.
266    ///   8. `[]` Derived lending market authority.
267    ///   9. `[signer]` User transfer authority ($authority).
268    ///   10 `[]` Clock sysvar (optional, will be removed soon).
269    ///   11 `[]` Token program id.
270    LiquidateObligation {
271        /// Amount of liquidity to repay - u64::MAX for up to 100% of borrowed amount
272        liquidity_amount: u64,
273    },
274
275    // 13
276    /// This instruction is now deprecated. Use FlashBorrowReserveLiquidity instead.
277    /// Make a flash loan.
278    ///
279    /// Accounts expected by this instruction:
280    ///
281    ///   0. `[writable]` Source liquidity token account.
282    ///                     Minted by reserve liquidity mint.
283    ///                     Must match the reserve liquidity supply.
284    ///   1. `[writable]` Destination liquidity token account.
285    ///                     Minted by reserve liquidity mint.
286    ///   2. `[writable]` Reserve account.
287    ///   3. `[writable]` Flash loan fee receiver account.
288    ///                     Must match the reserve liquidity fee receiver.
289    ///   4. `[writable]` Host fee receiver.
290    ///   5. `[]` Lending market account.
291    ///   6. `[]` Derived lending market authority.
292    ///   7. `[]` Token program id.
293    ///   8. `[]` Flash loan receiver program id.
294    ///             Must implement an instruction that has tag of 0 and a signature of `(amount: u64)`
295    ///             This instruction must return the amount to the source liquidity account.
296    ///   .. `[any]` Additional accounts expected by the receiving program's `ReceiveFlashLoan` instruction.
297    ///
298    ///   The flash loan receiver program that is to be invoked should contain an instruction with
299    ///   tag `0` and accept the total amount (including fee) that needs to be returned back after
300    ///   its execution has completed.
301    ///
302    ///   Flash loan receiver should have an instruction with the following signature:
303    ///
304    ///   0. `[writable]` Source liquidity (matching the destination from above).
305    ///   1. `[writable]` Destination liquidity (matching the source from above).
306    ///   2. `[]` Token program id
307    ///   .. `[any]` Additional accounts provided to the lending program's `FlashLoan` instruction above.
308    ///   ReceiveFlashLoan {
309    ///       // Amount that must be repaid by the receiver program
310    ///       amount: u64
311    ///   }
312    FlashLoan {
313        /// The amount that is to be borrowed - u64::MAX for up to 100% of available liquidity
314        amount: u64,
315    },
316
317    // 14
318    /// Combines DepositReserveLiquidity and DepositObligationCollateral
319    ///
320    /// Accounts expected by this instruction:
321    ///
322    ///   0. `[writable]` Source liquidity token account.
323    ///                     $authority can transfer $liquidity_amount.
324    ///   1. `[writable]` Destination collateral token account.
325    ///   2. `[writable]` Reserve account.
326    ///   3. `[writable]` Reserve liquidity supply SPL Token account.
327    ///   4. `[writable]` Reserve collateral SPL Token mint.
328    ///   5. `[]` Lending market account.
329    ///   6. `[]` Derived lending market authority.
330    ///   7. `[writable]` Destination deposit reserve collateral supply SPL Token account.
331    ///   8. `[writable]` Obligation account.
332    ///   9. `[signer]` Obligation owner.
333    ///   10 `[]` Pyth price oracle account.
334    ///   11 `[]` Switchboard price feed oracle account.
335    ///   12 `[signer]` User transfer authority ($authority).
336    ///   13 `[]` Clock sysvar (optional, will be removed soon).
337    ///   14 `[]` Token program id.
338    DepositReserveLiquidityAndObligationCollateral {
339        /// Amount of liquidity to deposit in exchange
340        liquidity_amount: u64,
341    },
342
343    // 15
344    /// Combines WithdrawObligationCollateral and RedeemReserveCollateral
345    ///
346    /// Accounts expected by this instruction:
347    ///
348    ///   0. `[writable]` Source withdraw reserve collateral supply SPL Token account.
349    ///   1. `[writable]` Destination collateral token account.
350    ///                     Minted by withdraw reserve collateral mint.
351    ///   2. `[writable]` Withdraw reserve account - refreshed.
352    ///   3. `[writable]` Obligation account - refreshed.
353    ///   4. `[]` Lending market account.
354    ///   5. `[]` Derived lending market authority.
355    ///   6. `[writable]` User liquidity token account.
356    ///   7. `[writable]` Reserve collateral SPL Token mint.
357    ///   8. `[writable]` Reserve liquidity supply SPL Token account.
358    ///   9. `[signer]` Obligation owner
359    ///   10 `[signer]` User transfer authority ($authority).
360    ///   11. `[]` Clock sysvar (optional, will be removed soon).
361    ///   12. `[]` Token program id.
362    WithdrawObligationCollateralAndRedeemReserveCollateral {
363        /// liquidity_amount is the amount of collateral tokens to withdraw
364        collateral_amount: u64,
365    },
366
367    // 16
368    /// Updates a reserves config and a reserve price oracle pubkeys
369    ///
370    /// Accounts expected by this instruction:
371    ///
372    ///   1. `[writable]` Reserve account - refreshed
373    ///   2 `[]` Lending market account.
374    ///   3 `[]` Derived lending market authority.
375    ///   4 `[signer]` Lending market owner.
376    ///   5 `[]` Pyth product key.
377    ///   6 `[]` Pyth price key.
378    ///   7 `[]` Switchboard key.
379    UpdateReserveConfig {
380        /// Reserve config to update to
381        config: ReserveConfig,
382    },
383
384    // 17
385    /// Repay borrowed liquidity to a reserve to receive collateral at a discount from an unhealthy
386    /// obligation. Requires a refreshed obligation and reserves.
387    ///
388    /// Accounts expected by this instruction:
389    ///
390    ///   0. `[writable]` Source liquidity token account.
391    ///                     Minted by repay reserve liquidity mint.
392    ///                     $authority can transfer $liquidity_amount.
393    ///   1. `[writable]` Destination collateral token account.
394    ///                     Minted by withdraw reserve collateral mint.
395    ///   2. `[writable]` Destination liquidity token account.
396    ///   3. `[writable]` Repay reserve account - refreshed.
397    ///   4. `[writable]` Repay reserve liquidity supply SPL Token account.
398    ///   5. `[writable]` Withdraw reserve account - refreshed.
399    ///   6. `[writable]` Withdraw reserve collateral SPL Token mint.
400    ///   7. `[writable]` Withdraw reserve collateral supply SPL Token account.
401    ///   8. `[writable]` Withdraw reserve liquidity supply SPL Token account.
402    ///   9. `[writable]` Withdraw reserve liquidity fee receiver account.
403    ///   10 `[writable]` Obligation account - refreshed.
404    ///   11 `[]` Lending market account.
405    ///   12 `[]` Derived lending market authority.
406    ///   13 `[signer]` User transfer authority ($authority).
407    ///   14 `[]` Token program id.
408    LiquidateObligationAndRedeemReserveCollateral {
409        /// Amount of liquidity to repay - u64::MAX for up to 100% of borrowed amount
410        liquidity_amount: u64,
411    },
412
413    // 18
414    ///   0. `[writable]` Reserve account.
415    ///   1. `[writable]` Borrow reserve liquidity fee receiver account.
416    ///                     Must be the fee account specified at InitReserve.
417    ///   2. `[writable]` Reserve liquidity supply SPL Token account.
418    ///   3. `[]` Lending market account.
419    ///   4. `[]` Derived lending market authority.
420    ///   5. `[]` Token program id.
421    RedeemFees,
422
423    // 19
424    /// Flash borrow reserve liquidity
425    //
426    /// Accounts expected by this instruction:
427    ///
428    ///   0. `[writable]` Source liquidity token account.
429    ///   1. `[writable]` Destination liquidity token account.
430    ///   2. `[writable]` Reserve account.
431    ///   3. `[]` Lending market account.
432    ///   4. `[]` Derived lending market authority.
433    ///   5. `[]` Instructions sysvar.
434    ///   6. `[]` Token program id.
435    ///   7. `[]` Clock sysvar (optional, will be removed soon).
436    FlashBorrowReserveLiquidity {
437        /// Amount of liquidity to flash borrow
438        liquidity_amount: u64,
439    },
440
441    // 18
442    /// Flash repay reserve liquidity
443    //
444    /// Accounts expected by this instruction:
445    ///
446    ///   0. `[writable]` Source liquidity token account.
447    ///                     $authority can transfer $liquidity_amount.
448    ///   1. `[writable]` Destination liquidity token account.
449    ///   2. `[writable]` Flash loan fee receiver account.
450    ///                     Must match the reserve liquidity fee receiver.
451    ///   3. `[writable]` Host fee receiver.
452    ///   4. `[writable]` Reserve account.
453    ///   5. `[]` Lending market account.
454    ///   6. `[signer]` User transfer authority ($authority).
455    ///   7. `[]` Instructions sysvar.
456    ///   8. `[]` Token program id.
457    FlashRepayReserveLiquidity {
458        /// Amount of liquidity to flash repay
459        liquidity_amount: u64,
460        /// Index of FlashBorrowReserveLiquidity instruction
461        borrow_instruction_index: u8,
462    },
463}
464
465impl LendingInstruction {
466    /// Unpacks a byte buffer into a [LendingInstruction](enum.LendingInstruction.html).
467    pub fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
468        let (&tag, rest) = input
469            .split_first()
470            .ok_or(LendingError::InstructionUnpackError)?;
471        Ok(match tag {
472            0 => {
473                let (owner, rest) = Self::unpack_pubkey(rest)?;
474                let (quote_currency, _rest) = Self::unpack_bytes32(rest)?;
475                Self::InitLendingMarket {
476                    owner,
477                    quote_currency: *quote_currency,
478                }
479            }
480            1 => {
481                let (new_owner, _rest) = Self::unpack_pubkey(rest)?;
482                Self::SetLendingMarketOwner { new_owner }
483            }
484            2 => {
485                let (liquidity_amount, rest) = Self::unpack_u64(rest)?;
486                let (optimal_utilization_rate, rest) = Self::unpack_u8(rest)?;
487                let (loan_to_value_ratio, rest) = Self::unpack_u8(rest)?;
488                let (liquidation_bonus, rest) = Self::unpack_u8(rest)?;
489                let (liquidation_threshold, rest) = Self::unpack_u8(rest)?;
490                let (min_borrow_rate, rest) = Self::unpack_u8(rest)?;
491                let (optimal_borrow_rate, rest) = Self::unpack_u8(rest)?;
492                let (max_borrow_rate, rest) = Self::unpack_u8(rest)?;
493                let (borrow_fee_wad, rest) = Self::unpack_u64(rest)?;
494                let (flash_loan_fee_wad, rest) = Self::unpack_u64(rest)?;
495                let (host_fee_percentage, rest) = Self::unpack_u8(rest)?;
496                let (deposit_limit, rest) = Self::unpack_u64(rest)?;
497                let (borrow_limit, rest) = Self::unpack_u64(rest)?;
498                let (fee_receiver, rest) = Self::unpack_pubkey(rest)?;
499                let (protocol_liquidation_fee, rest) = Self::unpack_u8(rest)?;
500                let (protocol_take_rate, _rest) = Self::unpack_u8(rest)?;
501                Self::InitReserve {
502                    liquidity_amount,
503                    config: ReserveConfig {
504                        optimal_utilization_rate,
505                        loan_to_value_ratio,
506                        liquidation_bonus,
507                        liquidation_threshold,
508                        min_borrow_rate,
509                        optimal_borrow_rate,
510                        max_borrow_rate,
511                        fees: ReserveFees {
512                            borrow_fee_wad,
513                            flash_loan_fee_wad,
514                            host_fee_percentage,
515                        },
516                        deposit_limit,
517                        borrow_limit,
518                        fee_receiver,
519                        protocol_liquidation_fee,
520                        protocol_take_rate,
521                    },
522                }
523            }
524            3 => Self::RefreshReserve,
525            4 => {
526                let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
527                Self::DepositReserveLiquidity { liquidity_amount }
528            }
529            5 => {
530                let (collateral_amount, _rest) = Self::unpack_u64(rest)?;
531                Self::RedeemReserveCollateral { collateral_amount }
532            }
533            6 => Self::InitObligation,
534            7 => Self::RefreshObligation,
535            8 => {
536                let (collateral_amount, _rest) = Self::unpack_u64(rest)?;
537                Self::DepositObligationCollateral { collateral_amount }
538            }
539            9 => {
540                let (collateral_amount, _rest) = Self::unpack_u64(rest)?;
541                Self::WithdrawObligationCollateral { collateral_amount }
542            }
543            10 => {
544                let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
545                Self::BorrowObligationLiquidity { liquidity_amount }
546            }
547            11 => {
548                let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
549                Self::RepayObligationLiquidity { liquidity_amount }
550            }
551            12 => {
552                let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
553                Self::LiquidateObligation { liquidity_amount }
554            }
555            13 => {
556                let (amount, _rest) = Self::unpack_u64(rest)?;
557                Self::FlashLoan { amount }
558            }
559            14 => {
560                let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
561                Self::DepositReserveLiquidityAndObligationCollateral { liquidity_amount }
562            }
563            15 => {
564                let (collateral_amount, _rest) = Self::unpack_u64(rest)?;
565                Self::WithdrawObligationCollateralAndRedeemReserveCollateral { collateral_amount }
566            }
567            16 => {
568                let (optimal_utilization_rate, rest) = Self::unpack_u8(rest)?;
569                let (loan_to_value_ratio, rest) = Self::unpack_u8(rest)?;
570                let (liquidation_bonus, rest) = Self::unpack_u8(rest)?;
571                let (liquidation_threshold, rest) = Self::unpack_u8(rest)?;
572                let (min_borrow_rate, rest) = Self::unpack_u8(rest)?;
573                let (optimal_borrow_rate, rest) = Self::unpack_u8(rest)?;
574                let (max_borrow_rate, rest) = Self::unpack_u8(rest)?;
575                let (borrow_fee_wad, rest) = Self::unpack_u64(rest)?;
576                let (flash_loan_fee_wad, rest) = Self::unpack_u64(rest)?;
577                let (host_fee_percentage, rest) = Self::unpack_u8(rest)?;
578                let (deposit_limit, rest) = Self::unpack_u64(rest)?;
579                let (borrow_limit, rest) = Self::unpack_u64(rest)?;
580                let (fee_receiver, rest) = Self::unpack_pubkey(rest)?;
581                let (protocol_liquidation_fee, rest) = Self::unpack_u8(rest)?;
582                let (protocol_take_rate, _rest) = Self::unpack_u8(rest)?;
583                Self::UpdateReserveConfig {
584                    config: ReserveConfig {
585                        optimal_utilization_rate,
586                        loan_to_value_ratio,
587                        liquidation_bonus,
588                        liquidation_threshold,
589                        min_borrow_rate,
590                        optimal_borrow_rate,
591                        max_borrow_rate,
592                        fees: ReserveFees {
593                            borrow_fee_wad,
594                            flash_loan_fee_wad,
595                            host_fee_percentage,
596                        },
597                        deposit_limit,
598                        borrow_limit,
599                        fee_receiver,
600                        protocol_liquidation_fee,
601                        protocol_take_rate,
602                    },
603                }
604            }
605            17 => {
606                let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
607                Self::LiquidateObligationAndRedeemReserveCollateral { liquidity_amount }
608            }
609            18 => Self::RedeemFees,
610            19 => {
611                let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
612                Self::FlashBorrowReserveLiquidity { liquidity_amount }
613            }
614            20 => {
615                let (liquidity_amount, rest) = Self::unpack_u64(rest)?;
616                let (borrow_instruction_index, _rest) = Self::unpack_u8(rest)?;
617                Self::FlashRepayReserveLiquidity {
618                    liquidity_amount,
619                    borrow_instruction_index,
620                }
621            }
622            _ => {
623                msg!("Instruction cannot be unpacked");
624                return Err(LendingError::InstructionUnpackError.into());
625            }
626        })
627    }
628
629    fn unpack_u64(input: &[u8]) -> Result<(u64, &[u8]), ProgramError> {
630        if input.len() < 8 {
631            msg!("u64 cannot be unpacked");
632            return Err(LendingError::InstructionUnpackError.into());
633        }
634        let (bytes, rest) = input.split_at(8);
635        let value = bytes
636            .get(..8)
637            .and_then(|slice| slice.try_into().ok())
638            .map(u64::from_le_bytes)
639            .ok_or(LendingError::InstructionUnpackError)?;
640        Ok((value, rest))
641    }
642
643    fn unpack_u8(input: &[u8]) -> Result<(u8, &[u8]), ProgramError> {
644        if input.is_empty() {
645            msg!("u8 cannot be unpacked");
646            return Err(LendingError::InstructionUnpackError.into());
647        }
648        let (bytes, rest) = input.split_at(1);
649        let value = bytes
650            .get(..1)
651            .and_then(|slice| slice.try_into().ok())
652            .map(u8::from_le_bytes)
653            .ok_or(LendingError::InstructionUnpackError)?;
654        Ok((value, rest))
655    }
656
657    fn unpack_bytes32(input: &[u8]) -> Result<(&[u8; 32], &[u8]), ProgramError> {
658        if input.len() < 32 {
659            msg!("32 bytes cannot be unpacked");
660            return Err(LendingError::InstructionUnpackError.into());
661        }
662        let (bytes, rest) = input.split_at(32);
663        Ok((
664            bytes
665                .try_into()
666                .map_err(|_| LendingError::InstructionUnpackError)?,
667            rest,
668        ))
669    }
670
671    fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> {
672        if input.len() < PUBKEY_BYTES {
673            msg!("Pubkey cannot be unpacked");
674            return Err(LendingError::InstructionUnpackError.into());
675        }
676        let (key, rest) = input.split_at(PUBKEY_BYTES);
677        let pk = Pubkey::new(key);
678        Ok((pk, rest))
679    }
680
681    /// Packs a [LendingInstruction](enum.LendingInstruction.html) into a byte buffer.
682    pub fn pack(&self) -> Vec<u8> {
683        let mut buf = Vec::with_capacity(size_of::<Self>());
684        match *self {
685            Self::InitLendingMarket {
686                owner,
687                quote_currency,
688            } => {
689                buf.push(0);
690                buf.extend_from_slice(owner.as_ref());
691                buf.extend_from_slice(quote_currency.as_ref());
692            }
693            Self::SetLendingMarketOwner { new_owner } => {
694                buf.push(1);
695                buf.extend_from_slice(new_owner.as_ref());
696            }
697            Self::InitReserve {
698                liquidity_amount,
699                config:
700                    ReserveConfig {
701                        optimal_utilization_rate,
702                        loan_to_value_ratio,
703                        liquidation_bonus,
704                        liquidation_threshold,
705                        min_borrow_rate,
706                        optimal_borrow_rate,
707                        max_borrow_rate,
708                        fees:
709                            ReserveFees {
710                                borrow_fee_wad,
711                                flash_loan_fee_wad,
712                                host_fee_percentage,
713                            },
714                        deposit_limit,
715                        borrow_limit,
716                        fee_receiver,
717                        protocol_liquidation_fee,
718                        protocol_take_rate,
719                    },
720            } => {
721                buf.push(2);
722                buf.extend_from_slice(&liquidity_amount.to_le_bytes());
723                buf.extend_from_slice(&optimal_utilization_rate.to_le_bytes());
724                buf.extend_from_slice(&loan_to_value_ratio.to_le_bytes());
725                buf.extend_from_slice(&liquidation_bonus.to_le_bytes());
726                buf.extend_from_slice(&liquidation_threshold.to_le_bytes());
727                buf.extend_from_slice(&min_borrow_rate.to_le_bytes());
728                buf.extend_from_slice(&optimal_borrow_rate.to_le_bytes());
729                buf.extend_from_slice(&max_borrow_rate.to_le_bytes());
730                buf.extend_from_slice(&borrow_fee_wad.to_le_bytes());
731                buf.extend_from_slice(&flash_loan_fee_wad.to_le_bytes());
732                buf.extend_from_slice(&host_fee_percentage.to_le_bytes());
733                buf.extend_from_slice(&deposit_limit.to_le_bytes());
734                buf.extend_from_slice(&borrow_limit.to_le_bytes());
735                buf.extend_from_slice(&fee_receiver.to_bytes());
736                buf.extend_from_slice(&protocol_liquidation_fee.to_le_bytes());
737                buf.extend_from_slice(&protocol_take_rate.to_le_bytes());
738            }
739            Self::RefreshReserve => {
740                buf.push(3);
741            }
742            Self::DepositReserveLiquidity { liquidity_amount } => {
743                buf.push(4);
744                buf.extend_from_slice(&liquidity_amount.to_le_bytes());
745            }
746            Self::RedeemReserveCollateral { collateral_amount } => {
747                buf.push(5);
748                buf.extend_from_slice(&collateral_amount.to_le_bytes());
749            }
750            Self::InitObligation => {
751                buf.push(6);
752            }
753            Self::RefreshObligation => {
754                buf.push(7);
755            }
756            Self::DepositObligationCollateral { collateral_amount } => {
757                buf.push(8);
758                buf.extend_from_slice(&collateral_amount.to_le_bytes());
759            }
760            Self::WithdrawObligationCollateral { collateral_amount } => {
761                buf.push(9);
762                buf.extend_from_slice(&collateral_amount.to_le_bytes());
763            }
764            Self::BorrowObligationLiquidity { liquidity_amount } => {
765                buf.push(10);
766                buf.extend_from_slice(&liquidity_amount.to_le_bytes());
767            }
768            Self::RepayObligationLiquidity { liquidity_amount } => {
769                buf.push(11);
770                buf.extend_from_slice(&liquidity_amount.to_le_bytes());
771            }
772            Self::LiquidateObligation { liquidity_amount } => {
773                buf.push(12);
774                buf.extend_from_slice(&liquidity_amount.to_le_bytes());
775            }
776            Self::FlashLoan { amount } => {
777                buf.push(13);
778                buf.extend_from_slice(&amount.to_le_bytes());
779            }
780            Self::DepositReserveLiquidityAndObligationCollateral { liquidity_amount } => {
781                buf.push(14);
782                buf.extend_from_slice(&liquidity_amount.to_le_bytes());
783            }
784            Self::WithdrawObligationCollateralAndRedeemReserveCollateral { collateral_amount } => {
785                buf.push(15);
786                buf.extend_from_slice(&collateral_amount.to_le_bytes());
787            }
788            Self::UpdateReserveConfig { config } => {
789                buf.push(16);
790                buf.extend_from_slice(&config.optimal_utilization_rate.to_le_bytes());
791                buf.extend_from_slice(&config.loan_to_value_ratio.to_le_bytes());
792                buf.extend_from_slice(&config.liquidation_bonus.to_le_bytes());
793                buf.extend_from_slice(&config.liquidation_threshold.to_le_bytes());
794                buf.extend_from_slice(&config.min_borrow_rate.to_le_bytes());
795                buf.extend_from_slice(&config.optimal_borrow_rate.to_le_bytes());
796                buf.extend_from_slice(&config.max_borrow_rate.to_le_bytes());
797                buf.extend_from_slice(&config.fees.borrow_fee_wad.to_le_bytes());
798                buf.extend_from_slice(&config.fees.flash_loan_fee_wad.to_le_bytes());
799                buf.extend_from_slice(&config.fees.host_fee_percentage.to_le_bytes());
800                buf.extend_from_slice(&config.deposit_limit.to_le_bytes());
801                buf.extend_from_slice(&config.borrow_limit.to_le_bytes());
802                buf.extend_from_slice(&config.fee_receiver.to_bytes());
803                buf.extend_from_slice(&config.protocol_liquidation_fee.to_le_bytes());
804                buf.extend_from_slice(&config.protocol_take_rate.to_le_bytes());
805            }
806            Self::LiquidateObligationAndRedeemReserveCollateral { liquidity_amount } => {
807                buf.push(17);
808                buf.extend_from_slice(&liquidity_amount.to_le_bytes());
809            }
810            Self::RedeemFees {} => {
811                buf.push(18);
812            }
813            Self::FlashBorrowReserveLiquidity { liquidity_amount } => {
814                buf.push(19);
815                buf.extend_from_slice(&liquidity_amount.to_le_bytes());
816            }
817            Self::FlashRepayReserveLiquidity {
818                liquidity_amount,
819                borrow_instruction_index,
820            } => {
821                buf.push(20);
822                buf.extend_from_slice(&liquidity_amount.to_le_bytes());
823                buf.extend_from_slice(&borrow_instruction_index.to_le_bytes());
824            }
825        }
826        buf
827    }
828}
829
830/// Creates an 'InitLendingMarket' instruction.
831pub fn init_lending_market(
832    program_id: Pubkey,
833    owner: Pubkey,
834    quote_currency: [u8; 32],
835    lending_market_pubkey: Pubkey,
836    oracle_program_id: Pubkey,
837    switchboard_oracle_program_id: Pubkey,
838) -> Instruction {
839    Instruction {
840        program_id,
841        accounts: vec![
842            AccountMeta::new(lending_market_pubkey, false),
843            AccountMeta::new_readonly(sysvar::rent::id(), false),
844            AccountMeta::new_readonly(spl_token::id(), false),
845            AccountMeta::new_readonly(oracle_program_id, false),
846            AccountMeta::new_readonly(switchboard_oracle_program_id, false),
847        ],
848        data: LendingInstruction::InitLendingMarket {
849            owner,
850            quote_currency,
851        }
852        .pack(),
853    }
854}
855
856/// Creates a 'SetLendingMarketOwner' instruction.
857pub fn set_lending_market_owner(
858    program_id: Pubkey,
859    lending_market_pubkey: Pubkey,
860    lending_market_owner: Pubkey,
861    new_owner: Pubkey,
862) -> Instruction {
863    Instruction {
864        program_id,
865        accounts: vec![
866            AccountMeta::new(lending_market_pubkey, false),
867            AccountMeta::new_readonly(lending_market_owner, true),
868        ],
869        data: LendingInstruction::SetLendingMarketOwner { new_owner }.pack(),
870    }
871}
872
873/// Creates an 'InitReserve' instruction.
874#[allow(clippy::too_many_arguments)]
875pub fn init_reserve(
876    program_id: Pubkey,
877    liquidity_amount: u64,
878    config: ReserveConfig,
879    source_liquidity_pubkey: Pubkey,
880    destination_collateral_pubkey: Pubkey,
881    reserve_pubkey: Pubkey,
882    reserve_liquidity_mint_pubkey: Pubkey,
883    reserve_liquidity_supply_pubkey: Pubkey,
884    reserve_collateral_mint_pubkey: Pubkey,
885    reserve_collateral_supply_pubkey: Pubkey,
886    pyth_product_pubkey: Pubkey,
887    pyth_price_pubkey: Pubkey,
888    switchboard_feed_pubkey: Pubkey,
889    lending_market_pubkey: Pubkey,
890    lending_market_owner_pubkey: Pubkey,
891    user_transfer_authority_pubkey: Pubkey,
892) -> Instruction {
893    let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
894        &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
895        &program_id,
896    );
897    let accounts = vec![
898        AccountMeta::new(source_liquidity_pubkey, false),
899        AccountMeta::new(destination_collateral_pubkey, false),
900        AccountMeta::new(reserve_pubkey, false),
901        AccountMeta::new_readonly(reserve_liquidity_mint_pubkey, false),
902        AccountMeta::new(reserve_liquidity_supply_pubkey, false),
903        AccountMeta::new(config.fee_receiver, false),
904        AccountMeta::new(reserve_collateral_mint_pubkey, false),
905        AccountMeta::new(reserve_collateral_supply_pubkey, false),
906        AccountMeta::new_readonly(pyth_product_pubkey, false),
907        AccountMeta::new_readonly(pyth_price_pubkey, false),
908        AccountMeta::new_readonly(switchboard_feed_pubkey, false),
909        AccountMeta::new_readonly(lending_market_pubkey, false),
910        AccountMeta::new_readonly(lending_market_authority_pubkey, false),
911        AccountMeta::new_readonly(lending_market_owner_pubkey, true),
912        AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
913        AccountMeta::new_readonly(sysvar::rent::id(), false),
914        AccountMeta::new_readonly(spl_token::id(), false),
915    ];
916    Instruction {
917        program_id,
918        accounts,
919        data: LendingInstruction::InitReserve {
920            liquidity_amount,
921            config,
922        }
923        .pack(),
924    }
925}
926
927/// Creates a `RefreshReserve` instruction
928pub fn refresh_reserve(
929    program_id: Pubkey,
930    reserve_pubkey: Pubkey,
931    reserve_liquidity_pyth_oracle_pubkey: Pubkey,
932    reserve_liquidity_switchboard_oracle_pubkey: Pubkey,
933) -> Instruction {
934    let accounts = vec![
935        AccountMeta::new(reserve_pubkey, false),
936        AccountMeta::new_readonly(reserve_liquidity_pyth_oracle_pubkey, false),
937        AccountMeta::new_readonly(reserve_liquidity_switchboard_oracle_pubkey, false),
938    ];
939    Instruction {
940        program_id,
941        accounts,
942        data: LendingInstruction::RefreshReserve.pack(),
943    }
944}
945
946/// Creates a 'DepositReserveLiquidity' instruction.
947#[allow(clippy::too_many_arguments)]
948pub fn deposit_reserve_liquidity(
949    program_id: Pubkey,
950    liquidity_amount: u64,
951    source_liquidity_pubkey: Pubkey,
952    destination_collateral_pubkey: Pubkey,
953    reserve_pubkey: Pubkey,
954    reserve_liquidity_supply_pubkey: Pubkey,
955    reserve_collateral_mint_pubkey: Pubkey,
956    lending_market_pubkey: Pubkey,
957    user_transfer_authority_pubkey: Pubkey,
958) -> Instruction {
959    let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
960        &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
961        &program_id,
962    );
963    Instruction {
964        program_id,
965        accounts: vec![
966            AccountMeta::new(source_liquidity_pubkey, false),
967            AccountMeta::new(destination_collateral_pubkey, false),
968            AccountMeta::new(reserve_pubkey, false),
969            AccountMeta::new(reserve_liquidity_supply_pubkey, false),
970            AccountMeta::new(reserve_collateral_mint_pubkey, false),
971            AccountMeta::new_readonly(lending_market_pubkey, false),
972            AccountMeta::new_readonly(lending_market_authority_pubkey, false),
973            AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
974            AccountMeta::new_readonly(spl_token::id(), false),
975        ],
976        data: LendingInstruction::DepositReserveLiquidity { liquidity_amount }.pack(),
977    }
978}
979
980/// Creates a 'RedeemReserveCollateral' instruction.
981#[allow(clippy::too_many_arguments)]
982pub fn redeem_reserve_collateral(
983    program_id: Pubkey,
984    collateral_amount: u64,
985    source_collateral_pubkey: Pubkey,
986    destination_liquidity_pubkey: Pubkey,
987    reserve_pubkey: Pubkey,
988    reserve_collateral_mint_pubkey: Pubkey,
989    reserve_liquidity_supply_pubkey: Pubkey,
990    lending_market_pubkey: Pubkey,
991    user_transfer_authority_pubkey: Pubkey,
992) -> Instruction {
993    let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
994        &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
995        &program_id,
996    );
997    Instruction {
998        program_id,
999        accounts: vec![
1000            AccountMeta::new(source_collateral_pubkey, false),
1001            AccountMeta::new(destination_liquidity_pubkey, false),
1002            AccountMeta::new(reserve_pubkey, false),
1003            AccountMeta::new(reserve_collateral_mint_pubkey, false),
1004            AccountMeta::new(reserve_liquidity_supply_pubkey, false),
1005            AccountMeta::new_readonly(lending_market_pubkey, false),
1006            AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1007            AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
1008            AccountMeta::new_readonly(spl_token::id(), false),
1009        ],
1010        data: LendingInstruction::RedeemReserveCollateral { collateral_amount }.pack(),
1011    }
1012}
1013
1014/// Creates an 'InitObligation' instruction.
1015#[allow(clippy::too_many_arguments)]
1016pub fn init_obligation(
1017    program_id: Pubkey,
1018    obligation_pubkey: Pubkey,
1019    lending_market_pubkey: Pubkey,
1020    obligation_owner_pubkey: Pubkey,
1021) -> Instruction {
1022    Instruction {
1023        program_id,
1024        accounts: vec![
1025            AccountMeta::new(obligation_pubkey, false),
1026            AccountMeta::new_readonly(lending_market_pubkey, false),
1027            AccountMeta::new_readonly(obligation_owner_pubkey, true),
1028            AccountMeta::new_readonly(sysvar::rent::id(), false),
1029            AccountMeta::new_readonly(spl_token::id(), false),
1030        ],
1031        data: LendingInstruction::InitObligation.pack(),
1032    }
1033}
1034
1035/// Creates a 'RefreshObligation' instruction.
1036#[allow(clippy::too_many_arguments)]
1037pub fn refresh_obligation(
1038    program_id: Pubkey,
1039    obligation_pubkey: Pubkey,
1040    reserve_pubkeys: Vec<Pubkey>,
1041) -> Instruction {
1042    let mut accounts = vec![AccountMeta::new(obligation_pubkey, false)];
1043    accounts.extend(
1044        reserve_pubkeys
1045            .into_iter()
1046            .map(|pubkey| AccountMeta::new_readonly(pubkey, false)),
1047    );
1048    Instruction {
1049        program_id,
1050        accounts,
1051        data: LendingInstruction::RefreshObligation.pack(),
1052    }
1053}
1054
1055/// Creates a 'DepositObligationCollateral' instruction.
1056#[allow(clippy::too_many_arguments)]
1057pub fn deposit_obligation_collateral(
1058    program_id: Pubkey,
1059    collateral_amount: u64,
1060    source_collateral_pubkey: Pubkey,
1061    destination_collateral_pubkey: Pubkey,
1062    deposit_reserve_pubkey: Pubkey,
1063    obligation_pubkey: Pubkey,
1064    lending_market_pubkey: Pubkey,
1065    obligation_owner_pubkey: Pubkey,
1066    user_transfer_authority_pubkey: Pubkey,
1067) -> Instruction {
1068    Instruction {
1069        program_id,
1070        accounts: vec![
1071            AccountMeta::new(source_collateral_pubkey, false),
1072            AccountMeta::new(destination_collateral_pubkey, false),
1073            AccountMeta::new(deposit_reserve_pubkey, false),
1074            AccountMeta::new(obligation_pubkey, false),
1075            AccountMeta::new_readonly(lending_market_pubkey, false),
1076            AccountMeta::new_readonly(obligation_owner_pubkey, true),
1077            AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
1078            AccountMeta::new_readonly(spl_token::id(), false),
1079        ],
1080        data: LendingInstruction::DepositObligationCollateral { collateral_amount }.pack(),
1081    }
1082}
1083
1084/// Creates a 'DepositReserveLiquidityAndObligationCollateral' instruction.
1085#[allow(clippy::too_many_arguments)]
1086pub fn deposit_reserve_liquidity_and_obligation_collateral(
1087    program_id: Pubkey,
1088    liquidity_amount: u64,
1089    source_liquidity_pubkey: Pubkey,
1090    user_collateral_pubkey: Pubkey,
1091    reserve_pubkey: Pubkey,
1092    reserve_liquidity_supply_pubkey: Pubkey,
1093    reserve_collateral_mint_pubkey: Pubkey,
1094    lending_market_pubkey: Pubkey,
1095    destination_deposit_collateral_pubkey: Pubkey,
1096    obligation_pubkey: Pubkey,
1097    obligation_owner_pubkey: Pubkey,
1098    reserve_liquidity_pyth_oracle_pubkey: Pubkey,
1099    reserve_liquidity_switchboard_oracle_pubkey: Pubkey,
1100    user_transfer_authority_pubkey: Pubkey,
1101) -> Instruction {
1102    let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1103        &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1104        &program_id,
1105    );
1106    Instruction {
1107        program_id,
1108        accounts: vec![
1109            AccountMeta::new(source_liquidity_pubkey, false),
1110            AccountMeta::new(user_collateral_pubkey, false),
1111            AccountMeta::new(reserve_pubkey, false),
1112            AccountMeta::new(reserve_liquidity_supply_pubkey, false),
1113            AccountMeta::new(reserve_collateral_mint_pubkey, false),
1114            AccountMeta::new_readonly(lending_market_pubkey, false),
1115            AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1116            AccountMeta::new(destination_deposit_collateral_pubkey, false),
1117            AccountMeta::new(obligation_pubkey, false),
1118            AccountMeta::new(obligation_owner_pubkey, true),
1119            AccountMeta::new_readonly(reserve_liquidity_pyth_oracle_pubkey, false),
1120            AccountMeta::new_readonly(reserve_liquidity_switchboard_oracle_pubkey, false),
1121            AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
1122            AccountMeta::new_readonly(spl_token::id(), false),
1123        ],
1124        data: LendingInstruction::DepositReserveLiquidityAndObligationCollateral {
1125            liquidity_amount,
1126        }
1127        .pack(),
1128    }
1129}
1130
1131/// Creates a 'WithdrawObligationCollateralAndRedeemReserveCollateral' instruction.
1132#[allow(clippy::too_many_arguments)]
1133pub fn withdraw_obligation_collateral_and_redeem_reserve_collateral(
1134    program_id: Pubkey,
1135    collateral_amount: u64,
1136    source_collateral_pubkey: Pubkey,
1137    destination_collateral_pubkey: Pubkey,
1138    withdraw_reserve_pubkey: Pubkey,
1139    obligation_pubkey: Pubkey,
1140    lending_market_pubkey: Pubkey,
1141    destination_liquidity_pubkey: Pubkey,
1142    reserve_collateral_mint_pubkey: Pubkey,
1143    reserve_liquidity_supply_pubkey: Pubkey,
1144    obligation_owner_pubkey: Pubkey,
1145    user_transfer_authority_pubkey: Pubkey,
1146) -> Instruction {
1147    let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1148        &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1149        &program_id,
1150    );
1151    Instruction {
1152        program_id,
1153        accounts: vec![
1154            AccountMeta::new(source_collateral_pubkey, false),
1155            AccountMeta::new(destination_collateral_pubkey, false),
1156            AccountMeta::new(withdraw_reserve_pubkey, false),
1157            AccountMeta::new(obligation_pubkey, false),
1158            AccountMeta::new_readonly(lending_market_pubkey, false),
1159            AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1160            AccountMeta::new(destination_liquidity_pubkey, false),
1161            AccountMeta::new(reserve_collateral_mint_pubkey, false),
1162            AccountMeta::new(reserve_liquidity_supply_pubkey, false),
1163            AccountMeta::new_readonly(obligation_owner_pubkey, true),
1164            AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
1165            AccountMeta::new_readonly(spl_token::id(), false),
1166        ],
1167        data: LendingInstruction::WithdrawObligationCollateralAndRedeemReserveCollateral {
1168            collateral_amount,
1169        }
1170        .pack(),
1171    }
1172}
1173
1174/// Creates a 'WithdrawObligationCollateral' instruction.
1175#[allow(clippy::too_many_arguments)]
1176pub fn withdraw_obligation_collateral(
1177    program_id: Pubkey,
1178    collateral_amount: u64,
1179    source_collateral_pubkey: Pubkey,
1180    destination_collateral_pubkey: Pubkey,
1181    withdraw_reserve_pubkey: Pubkey,
1182    obligation_pubkey: Pubkey,
1183    lending_market_pubkey: Pubkey,
1184    obligation_owner_pubkey: Pubkey,
1185) -> Instruction {
1186    let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1187        &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1188        &program_id,
1189    );
1190    Instruction {
1191        program_id,
1192        accounts: vec![
1193            AccountMeta::new(source_collateral_pubkey, false),
1194            AccountMeta::new(destination_collateral_pubkey, false),
1195            AccountMeta::new_readonly(withdraw_reserve_pubkey, false),
1196            AccountMeta::new(obligation_pubkey, false),
1197            AccountMeta::new_readonly(lending_market_pubkey, false),
1198            AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1199            AccountMeta::new_readonly(obligation_owner_pubkey, true),
1200            AccountMeta::new_readonly(spl_token::id(), false),
1201        ],
1202        data: LendingInstruction::WithdrawObligationCollateral { collateral_amount }.pack(),
1203    }
1204}
1205
1206/// Creates a 'BorrowObligationLiquidity' instruction.
1207#[allow(clippy::too_many_arguments)]
1208pub fn borrow_obligation_liquidity(
1209    program_id: Pubkey,
1210    liquidity_amount: u64,
1211    source_liquidity_pubkey: Pubkey,
1212    destination_liquidity_pubkey: Pubkey,
1213    borrow_reserve_pubkey: Pubkey,
1214    borrow_reserve_liquidity_fee_receiver_pubkey: Pubkey,
1215    obligation_pubkey: Pubkey,
1216    lending_market_pubkey: Pubkey,
1217    obligation_owner_pubkey: Pubkey,
1218    host_fee_receiver_pubkey: Option<Pubkey>,
1219) -> Instruction {
1220    let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1221        &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1222        &program_id,
1223    );
1224    let mut accounts = vec![
1225        AccountMeta::new(source_liquidity_pubkey, false),
1226        AccountMeta::new(destination_liquidity_pubkey, false),
1227        AccountMeta::new(borrow_reserve_pubkey, false),
1228        AccountMeta::new(borrow_reserve_liquidity_fee_receiver_pubkey, false),
1229        AccountMeta::new(obligation_pubkey, false),
1230        AccountMeta::new_readonly(lending_market_pubkey, false),
1231        AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1232        AccountMeta::new_readonly(obligation_owner_pubkey, true),
1233        AccountMeta::new_readonly(spl_token::id(), false),
1234    ];
1235    if let Some(host_fee_receiver_pubkey) = host_fee_receiver_pubkey {
1236        accounts.push(AccountMeta::new(host_fee_receiver_pubkey, false));
1237    }
1238    Instruction {
1239        program_id,
1240        accounts,
1241        data: LendingInstruction::BorrowObligationLiquidity { liquidity_amount }.pack(),
1242    }
1243}
1244
1245/// Creates a `RepayObligationLiquidity` instruction
1246#[allow(clippy::too_many_arguments)]
1247pub fn repay_obligation_liquidity(
1248    program_id: Pubkey,
1249    liquidity_amount: u64,
1250    source_liquidity_pubkey: Pubkey,
1251    destination_liquidity_pubkey: Pubkey,
1252    repay_reserve_pubkey: Pubkey,
1253    obligation_pubkey: Pubkey,
1254    lending_market_pubkey: Pubkey,
1255    user_transfer_authority_pubkey: Pubkey,
1256) -> Instruction {
1257    Instruction {
1258        program_id,
1259        accounts: vec![
1260            AccountMeta::new(source_liquidity_pubkey, false),
1261            AccountMeta::new(destination_liquidity_pubkey, false),
1262            AccountMeta::new(repay_reserve_pubkey, false),
1263            AccountMeta::new(obligation_pubkey, false),
1264            AccountMeta::new_readonly(lending_market_pubkey, false),
1265            AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
1266            AccountMeta::new_readonly(spl_token::id(), false),
1267        ],
1268        data: LendingInstruction::RepayObligationLiquidity { liquidity_amount }.pack(),
1269    }
1270}
1271
1272/// Creates a `LiquidateObligation` instruction
1273#[allow(clippy::too_many_arguments)]
1274pub fn liquidate_obligation(
1275    program_id: Pubkey,
1276    liquidity_amount: u64,
1277    source_liquidity_pubkey: Pubkey,
1278    destination_collateral_pubkey: Pubkey,
1279    repay_reserve_pubkey: Pubkey,
1280    repay_reserve_liquidity_supply_pubkey: Pubkey,
1281    withdraw_reserve_pubkey: Pubkey,
1282    withdraw_reserve_collateral_supply_pubkey: Pubkey,
1283    obligation_pubkey: Pubkey,
1284    lending_market_pubkey: Pubkey,
1285    user_transfer_authority_pubkey: Pubkey,
1286) -> Instruction {
1287    let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1288        &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1289        &program_id,
1290    );
1291    Instruction {
1292        program_id,
1293        accounts: vec![
1294            AccountMeta::new(source_liquidity_pubkey, false),
1295            AccountMeta::new(destination_collateral_pubkey, false),
1296            AccountMeta::new(repay_reserve_pubkey, false),
1297            AccountMeta::new(repay_reserve_liquidity_supply_pubkey, false),
1298            AccountMeta::new_readonly(withdraw_reserve_pubkey, false),
1299            AccountMeta::new(withdraw_reserve_collateral_supply_pubkey, false),
1300            AccountMeta::new(obligation_pubkey, false),
1301            AccountMeta::new_readonly(lending_market_pubkey, false),
1302            AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1303            AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
1304            AccountMeta::new_readonly(spl_token::id(), false),
1305        ],
1306        data: LendingInstruction::LiquidateObligation { liquidity_amount }.pack(),
1307    }
1308}
1309
1310/// Creates an 'UpdateReserveConfig' instruction.
1311#[allow(clippy::too_many_arguments)]
1312pub fn update_reserve_config(
1313    program_id: Pubkey,
1314    config: ReserveConfig,
1315    reserve_pubkey: Pubkey,
1316    lending_market_pubkey: Pubkey,
1317    lending_market_owner_pubkey: Pubkey,
1318    pyth_product_pubkey: Pubkey,
1319    pyth_price_pubkey: Pubkey,
1320    switchboard_feed_pubkey: Pubkey,
1321) -> Instruction {
1322    let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1323        &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1324        &program_id,
1325    );
1326    let accounts = vec![
1327        AccountMeta::new(reserve_pubkey, false),
1328        AccountMeta::new_readonly(lending_market_pubkey, false),
1329        AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1330        AccountMeta::new_readonly(lending_market_owner_pubkey, true),
1331        AccountMeta::new_readonly(pyth_product_pubkey, false),
1332        AccountMeta::new_readonly(pyth_price_pubkey, false),
1333        AccountMeta::new_readonly(switchboard_feed_pubkey, false),
1334    ];
1335    Instruction {
1336        program_id,
1337        accounts,
1338        data: LendingInstruction::UpdateReserveConfig { config }.pack(),
1339    }
1340}
1341
1342/// Creates a `LiquidateObligationAndRedeemReserveCollateral` instruction
1343#[allow(clippy::too_many_arguments)]
1344pub fn liquidate_obligation_and_redeem_reserve_collateral(
1345    program_id: Pubkey,
1346    liquidity_amount: u64,
1347    source_liquidity_pubkey: Pubkey,
1348    destination_collateral_pubkey: Pubkey,
1349    destination_liquidity_pubkey: Pubkey,
1350    repay_reserve_pubkey: Pubkey,
1351    repay_reserve_liquidity_supply_pubkey: Pubkey,
1352    withdraw_reserve_pubkey: Pubkey,
1353    withdraw_reserve_collateral_mint_pubkey: Pubkey,
1354    withdraw_reserve_collateral_supply_pubkey: Pubkey,
1355    withdraw_reserve_liquidity_supply_pubkey: Pubkey,
1356    withdraw_reserve_liquidity_fee_receiver_pubkey: Pubkey,
1357    obligation_pubkey: Pubkey,
1358    lending_market_pubkey: Pubkey,
1359    user_transfer_authority_pubkey: Pubkey,
1360) -> Instruction {
1361    let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1362        &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1363        &program_id,
1364    );
1365    Instruction {
1366        program_id,
1367        accounts: vec![
1368            AccountMeta::new(source_liquidity_pubkey, false),
1369            AccountMeta::new(destination_collateral_pubkey, false),
1370            AccountMeta::new(destination_liquidity_pubkey, false),
1371            AccountMeta::new(repay_reserve_pubkey, false),
1372            AccountMeta::new(repay_reserve_liquidity_supply_pubkey, false),
1373            AccountMeta::new(withdraw_reserve_pubkey, false),
1374            AccountMeta::new(withdraw_reserve_collateral_mint_pubkey, false),
1375            AccountMeta::new(withdraw_reserve_collateral_supply_pubkey, false),
1376            AccountMeta::new(withdraw_reserve_liquidity_supply_pubkey, false),
1377            AccountMeta::new(withdraw_reserve_liquidity_fee_receiver_pubkey, false),
1378            AccountMeta::new(obligation_pubkey, false),
1379            AccountMeta::new_readonly(lending_market_pubkey, false),
1380            AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1381            AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
1382            AccountMeta::new_readonly(spl_token::id(), false),
1383        ],
1384        data: LendingInstruction::LiquidateObligationAndRedeemReserveCollateral {
1385            liquidity_amount,
1386        }
1387        .pack(),
1388    }
1389}
1390
1391/// Creates a `RedeemFees` instruction
1392pub fn redeem_fees(
1393    program_id: Pubkey,
1394    reserve_pubkey: Pubkey,
1395    reserve_liquidity_fee_receiver_pubkey: Pubkey,
1396    reserve_supply_liquidity_pubkey: Pubkey,
1397    lending_market_pubkey: Pubkey,
1398) -> Instruction {
1399    let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1400        &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1401        &program_id,
1402    );
1403    let accounts = vec![
1404        AccountMeta::new(reserve_pubkey, false),
1405        AccountMeta::new(reserve_liquidity_fee_receiver_pubkey, false),
1406        AccountMeta::new(reserve_supply_liquidity_pubkey, false),
1407        AccountMeta::new_readonly(lending_market_pubkey, false),
1408        AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1409        AccountMeta::new_readonly(spl_token::id(), false),
1410    ];
1411    Instruction {
1412        program_id,
1413        accounts,
1414        data: LendingInstruction::RedeemFees.pack(),
1415    }
1416}
1417
1418/// Creates a 'FlashBorrowReserveLiquidity' instruction.
1419#[allow(clippy::too_many_arguments)]
1420pub fn flash_borrow_reserve_liquidity(
1421    program_id: Pubkey,
1422    liquidity_amount: u64,
1423    source_liquidity_pubkey: Pubkey,
1424    destination_liquidity_pubkey: Pubkey,
1425    reserve_pubkey: Pubkey,
1426    lending_market_pubkey: Pubkey,
1427) -> Instruction {
1428    let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1429        &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1430        &program_id,
1431    );
1432
1433    Instruction {
1434        program_id,
1435        accounts: vec![
1436            AccountMeta::new(source_liquidity_pubkey, false),
1437            AccountMeta::new(destination_liquidity_pubkey, false),
1438            AccountMeta::new(reserve_pubkey, false),
1439            AccountMeta::new_readonly(lending_market_pubkey, false),
1440            AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1441            AccountMeta::new_readonly(sysvar::instructions::id(), false),
1442            AccountMeta::new_readonly(spl_token::id(), false),
1443        ],
1444        data: LendingInstruction::FlashBorrowReserveLiquidity { liquidity_amount }.pack(),
1445    }
1446}
1447
1448/// Creates a 'FlashRepayReserveLiquidity' instruction.
1449#[allow(clippy::too_many_arguments)]
1450pub fn flash_repay_reserve_liquidity(
1451    program_id: Pubkey,
1452    liquidity_amount: u64,
1453    borrow_instruction_index: u8,
1454    source_liquidity_pubkey: Pubkey,
1455    destination_liquidity_pubkey: Pubkey,
1456    reserve_liquidity_fee_receiver_pubkey: Pubkey,
1457    host_fee_receiver_pubkey: Pubkey,
1458    reserve_pubkey: Pubkey,
1459    lending_market_pubkey: Pubkey,
1460    user_transfer_authority_pubkey: Pubkey,
1461) -> Instruction {
1462    Instruction {
1463        program_id,
1464        accounts: vec![
1465            AccountMeta::new(source_liquidity_pubkey, false),
1466            AccountMeta::new(destination_liquidity_pubkey, false),
1467            AccountMeta::new(reserve_liquidity_fee_receiver_pubkey, false),
1468            AccountMeta::new(host_fee_receiver_pubkey, false),
1469            AccountMeta::new(reserve_pubkey, false),
1470            AccountMeta::new_readonly(lending_market_pubkey, false),
1471            AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
1472            AccountMeta::new_readonly(sysvar::instructions::id(), false),
1473            AccountMeta::new_readonly(spl_token::id(), false),
1474        ],
1475        data: LendingInstruction::FlashRepayReserveLiquidity {
1476            liquidity_amount,
1477            borrow_instruction_index,
1478        }
1479        .pack(),
1480    }
1481}