solana-program-library/token-lending/program/src/instruction.rs

974 lines
39 KiB
Rust

//! Instruction types
use crate::{
error::LendingError,
state::{ReserveConfig, ReserveFees},
};
use solana_program::{
instruction::{AccountMeta, Instruction},
msg,
program_error::ProgramError,
pubkey::{Pubkey, PUBKEY_BYTES},
sysvar,
};
use std::{convert::TryInto, mem::size_of};
/// Instructions supported by the lending program.
#[derive(Clone, Debug, PartialEq)]
pub enum LendingInstruction {
// 0
/// Initializes a new lending market.
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Lending market account - uninitialized.
/// 1. `[]` Quote currency SPL Token mint.
/// 2. `[]` Rent sysvar.
/// 3. `[]` Token program id.
InitLendingMarket {
/// Owner authority which can add new reserves
owner: Pubkey,
},
// 1
/// Sets the new owner of a lending market.
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Lending market account.
/// 1. `[signer]` Current owner.
SetLendingMarketOwner {
/// The new owner
new_owner: Pubkey,
},
// 2
/// Initializes a new lending market reserve.
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Source liquidity token account.
/// $authority can transfer $liquidity_amount.
/// 1. `[writable]` Destination collateral token account - uninitialized.
/// 2. `[writable]` Reserve account - uninitialized.
/// 3. `[]` Reserve liquidity SPL Token mint.
/// 4. `[writable]` Reserve liquidity supply SPL Token account - uninitialized.
/// 5. `[writable]` Reserve liquidity fee receiver - uninitialized.
/// 6. `[writable]` Reserve collateral SPL Token mint - uninitialized.
/// 7. `[writable]` Reserve collateral token supply - uninitialized.
/// 8. `[]` Quote currency SPL Token mint.
/// 9. `[]` Lending market account.
/// 10 `[]` Derived lending market authority.
/// 11 `[signer]` Lending market owner.
/// 12 `[signer]` User transfer authority ($authority).
/// 13 `[]` Clock sysvar.
/// 13 `[]` Rent sysvar.
/// 14 `[]` Token program id.
/// 15 `[optional]` Reserve liquidity oracle account.
/// Not required for quote currency reserves.
/// Must match base and quote currency mint, and quote currency decimals.
InitReserve {
/// Initial amount of liquidity to deposit into the new reserve
liquidity_amount: u64,
/// Reserve configuration values
config: ReserveConfig,
},
// 3
/// Accrue interest and update market price of liquidity on a reserve.
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Reserve account.
/// 1. `[]` Clock sysvar.
/// 2. `[optional]` Reserve liquidity oracle account.
/// Required if the reserve currency is not the lending market quote
/// currency.
RefreshReserve,
// 4
/// Deposit liquidity into a reserve in exchange for collateral. Collateral represents a share
/// of the reserve liquidity pool.
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Source liquidity token account.
/// $authority can transfer $liquidity_amount.
/// 1. `[writable]` Destination collateral token account.
/// 2. `[writable]` Reserve account.
/// 3. `[writable]` Reserve liquidity supply SPL Token account.
/// 4. `[writable]` Reserve collateral SPL Token mint.
/// 5. `[]` Lending market account.
/// 6. `[]` Derived lending market authority.
/// 7. `[signer]` User transfer authority ($authority).
/// 8. `[]` Clock sysvar.
/// 9. `[]` Token program id.
DepositReserveLiquidity {
/// Amount of liquidity to deposit in exchange for collateral tokens
liquidity_amount: u64,
},
// 5
/// Redeem collateral from a reserve in exchange for liquidity.
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Source collateral token account.
/// $authority can transfer $collateral_amount.
/// 1. `[writable]` Destination liquidity token account.
/// 2. `[writable]` Reserve account.
/// 3. `[writable]` Reserve collateral SPL Token mint.
/// 4. `[writable]` Reserve liquidity supply SPL Token account.
/// 5. `[]` Lending market account.
/// 6. `[]` Derived lending market authority.
/// 7. `[signer]` User transfer authority ($authority).
/// 8. `[]` Clock sysvar.
/// 9. `[]` Token program id.
RedeemReserveCollateral {
/// Amount of collateral tokens to redeem in exchange for liquidity
collateral_amount: u64,
},
// 6
/// Initializes a new lending market obligation.
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Obligation account - uninitialized.
/// 1. `[]` Lending market account.
/// 2. `[signer]` Obligation owner.
/// 3. `[]` Clock sysvar.
/// 4. `[]` Rent sysvar.
/// 5. `[]` Token program id.
InitObligation,
// 7
/// Refresh an obligation's accrued interest and collateral and liquidity prices. Requires
/// refreshed reserves, as all obligation collateral deposit reserves in order, followed by all
/// liquidity borrow reserves in order.
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Obligation account.
/// 1. `[]` Clock sysvar.
/// .. `[]` Collateral deposit reserve accounts - refreshed, all, in order.
/// .. `[]` Liquidity borrow reserve accounts - refreshed, all, in order.
RefreshObligation,
// 8
/// Deposit collateral to an obligation. Requires a refreshed reserve.
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Source collateral token account.
/// Minted by deposit reserve collateral mint.
/// $authority can transfer $collateral_amount.
/// 1. `[writable]` Destination deposit reserve collateral supply SPL Token account.
/// 2. `[]` Deposit reserve account - refreshed.
/// 3. `[writable]` Obligation account.
/// 4. `[]` Lending market account.
/// 5. `[]` Derived lending market authority.
/// 6. `[signer]` Obligation owner.
/// 7. `[signer]` User transfer authority ($authority).
/// 8. `[]` Clock sysvar.
/// 9. `[]` Token program id.
DepositObligationCollateral {
/// Amount of collateral tokens to deposit
collateral_amount: u64,
},
// 9
/// Withdraw collateral from an obligation. Requires a refreshed obligation and reserve.
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Source withdraw reserve collateral supply SPL Token account.
/// 1. `[writable]` Destination collateral token account.
/// Minted by withdraw reserve collateral mint.
/// 2. `[]` Withdraw reserve account - refreshed.
/// 3. `[writable]` Obligation account - refreshed.
/// 4. `[]` Lending market account.
/// 5. `[]` Derived lending market authority.
/// 6. `[signer]` Obligation owner.
/// 7. `[]` Clock sysvar.
/// 8. `[]` Token program id.
WithdrawObligationCollateral {
/// Amount of collateral tokens to withdraw - u64::MAX for up to 100% of deposited amount
collateral_amount: u64,
},
// @TODO: rename cf. https://git.io/JOOE6
// 10
/// Borrow liquidity from a reserve by depositing collateral tokens. Requires a refreshed
/// obligation and reserve.
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Source borrow reserve liquidity supply SPL Token account.
/// 1. `[writable]` Destination liquidity token account.
/// Minted by borrow reserve liquidity mint.
/// 2. `[writable]` Borrow reserve account - refreshed.
/// 3. `[writable]` Borrow reserve liquidity fee receiver account.
/// Must be the fee account specified at InitReserve.
/// 4. `[writable]` Obligation account - refreshed.
/// 5. `[]` Lending market account.
/// 6. `[]` Derived lending market authority.
/// 7. `[signer]` Obligation owner.
/// 8. `[]` Clock sysvar.
/// 9. `[]` Token program id.
/// 10 `[optional, writable]` Host fee receiver account.
BorrowObligationLiquidity {
/// Amount of liquidity to borrow - u64::MAX for 100% of borrowing power
liquidity_amount: u64,
// @TODO: slippage constraint - https://git.io/JmV67
},
// 11
/// Repay borrowed liquidity to a reserve. Requires a refreshed obligation and reserve.
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Source liquidity token account.
/// Minted by repay reserve liquidity mint.
/// $authority can transfer $liquidity_amount.
/// 1. `[writable]` Destination repay reserve liquidity supply SPL Token account.
/// 2. `[writable]` Repay reserve account - refreshed.
/// 3. `[writable]` Obligation account - refreshed.
/// 4. `[]` Lending market account.
/// 5. `[]` Derived lending market authority.
/// 6. `[signer]` User transfer authority ($authority).
/// 7. `[]` Clock sysvar.
/// 8. `[]` Token program id.
RepayObligationLiquidity {
/// Amount of liquidity to repay - u64::MAX for 100% of borrowed amount
liquidity_amount: u64,
},
// 12
/// Repay borrowed liquidity to a reserve to receive collateral at a discount from an unhealthy
/// obligation. Requires a refreshed obligation and reserves.
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Source liquidity token account.
/// Minted by repay reserve liquidity mint.
/// $authority can transfer $liquidity_amount.
/// 1. `[writable]` Destination collateral token account.
/// Minted by withdraw reserve collateral mint.
/// 2. `[writable]` Repay reserve account - refreshed.
/// 3. `[writable]` Repay reserve liquidity supply SPL Token account.
/// 4. `[]` Withdraw reserve account - refreshed.
/// 5. `[writable]` Withdraw reserve collateral supply SPL Token account.
/// 6. `[writable]` Obligation account - refreshed.
/// 7. `[]` Lending market account.
/// 8. `[]` Derived lending market authority.
/// 9. `[signer]` User transfer authority ($authority).
/// 10 `[]` Clock sysvar.
/// 11 `[]` Token program id.
LiquidateObligation {
/// Amount of liquidity to repay - u64::MAX for up to 100% of borrowed amount
liquidity_amount: u64,
},
// 13
/// Make a flash loan.
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Source liquidity token account.
/// Minted by reserve liquidity mint.
/// Must match the reserve liquidity supply.
/// 1. `[writable]` Destination liquidity token account.
/// Minted by reserve liquidity mint.
/// 2. `[writable]` Reserve account.
/// 3. `[]` Lending market account.
/// 4. `[]` Derived lending market authority.
/// 5. `[]` Flash loan receiver program account.
/// Must implement an instruction that has tag of 0 and a signature of `(repay_amount: u64)`
/// This instruction must return the amount to the source liquidity account.
/// 6. `[]` Token program id.
/// 7. `[writable]` Flash loan fee receiver account.
/// Must match the reserve liquidity fee receiver.
/// 8. `[writable]` Host fee receiver.
/// .. `[any]` Additional accounts expected by the receiving program's `ReceiveFlashLoan` instruction.
///
/// The flash loan receiver program that is to be invoked should contain an instruction with
/// tag `0` and accept the total amount (including fee) that needs to be returned back after
/// its execution has completed.
///
/// Flash loan receiver should have an instruction with the following signature:
///
/// 0. `[writable]` Source liquidity (matching the destination from above).
/// 1. `[writable]` Destination liquidity (matching the source from above).
/// 2. `[]` Token program id
/// .. `[any]` Additional accounts provided to the lending program's `FlashLoan` instruction above.
/// ReceiveFlashLoan {
/// // Amount that is loaned to the receiver program
/// amount: u64
/// }
FlashLoan {
/// The amount that is to be borrowed - u64::MAX for up to 100% of available liquidity
amount: u64,
},
}
impl LendingInstruction {
/// Unpacks a byte buffer into a [LendingInstruction](enum.LendingInstruction.html).
pub fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
let (&tag, rest) = input
.split_first()
.ok_or(LendingError::InstructionUnpackError)?;
Ok(match tag {
0 => {
let (owner, _rest) = Self::unpack_pubkey(rest)?;
Self::InitLendingMarket { owner }
}
1 => {
let (new_owner, _rest) = Self::unpack_pubkey(rest)?;
Self::SetLendingMarketOwner { new_owner }
}
2 => {
let (liquidity_amount, rest) = Self::unpack_u64(rest)?;
let (optimal_utilization_rate, rest) = Self::unpack_u8(rest)?;
let (loan_to_value_ratio, rest) = Self::unpack_u8(rest)?;
let (liquidation_bonus, rest) = Self::unpack_u8(rest)?;
let (liquidation_threshold, rest) = Self::unpack_u8(rest)?;
let (min_borrow_rate, rest) = Self::unpack_u8(rest)?;
let (optimal_borrow_rate, rest) = Self::unpack_u8(rest)?;
let (max_borrow_rate, rest) = Self::unpack_u8(rest)?;
let (borrow_fee_wad, rest) = Self::unpack_u64(rest)?;
let (flash_loan_fee_wad, rest) = Self::unpack_u64(rest)?;
let (host_fee_percentage, _rest) = Self::unpack_u8(rest)?;
Self::InitReserve {
liquidity_amount,
config: ReserveConfig {
optimal_utilization_rate,
loan_to_value_ratio,
liquidation_bonus,
liquidation_threshold,
min_borrow_rate,
optimal_borrow_rate,
max_borrow_rate,
fees: ReserveFees {
borrow_fee_wad,
flash_loan_fee_wad,
host_fee_percentage,
},
},
}
}
3 => Self::RefreshReserve,
4 => {
let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
Self::DepositReserveLiquidity { liquidity_amount }
}
5 => {
let (collateral_amount, _rest) = Self::unpack_u64(rest)?;
Self::RedeemReserveCollateral { collateral_amount }
}
6 => Self::InitObligation,
7 => Self::RefreshObligation,
8 => {
let (collateral_amount, _rest) = Self::unpack_u64(rest)?;
Self::DepositObligationCollateral { collateral_amount }
}
9 => {
let (collateral_amount, _rest) = Self::unpack_u64(rest)?;
Self::WithdrawObligationCollateral { collateral_amount }
}
10 => {
let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
Self::BorrowObligationLiquidity { liquidity_amount }
}
11 => {
let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
Self::RepayObligationLiquidity { liquidity_amount }
}
12 => {
let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
Self::LiquidateObligation { liquidity_amount }
}
13 => {
let (amount, _rest) = Self::unpack_u64(rest)?;
Self::FlashLoan { amount }
}
_ => {
msg!("Instruction cannot be unpacked");
return Err(LendingError::InstructionUnpackError.into());
}
})
}
fn unpack_u64(input: &[u8]) -> Result<(u64, &[u8]), ProgramError> {
if input.len() < 8 {
msg!("u64 cannot be unpacked");
return Err(LendingError::InstructionUnpackError.into());
}
let (amount, rest) = input.split_at(8);
let amount = amount
.get(..8)
.and_then(|slice| slice.try_into().ok())
.map(u64::from_le_bytes)
.ok_or(LendingError::InstructionUnpackError)?;
Ok((amount, rest))
}
fn unpack_u8(input: &[u8]) -> Result<(u8, &[u8]), ProgramError> {
if input.is_empty() {
msg!("u8 cannot be unpacked");
return Err(LendingError::InstructionUnpackError.into());
}
let (amount, rest) = input.split_at(1);
let amount = amount
.get(..1)
.and_then(|slice| slice.try_into().ok())
.map(u8::from_le_bytes)
.ok_or(LendingError::InstructionUnpackError)?;
Ok((amount, rest))
}
fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> {
if input.len() < PUBKEY_BYTES {
msg!("Pubkey cannot be unpacked");
return Err(LendingError::InstructionUnpackError.into());
}
let (key, rest) = input.split_at(PUBKEY_BYTES);
let pk = Pubkey::new(key);
Ok((pk, rest))
}
/// Packs a [LendingInstruction](enum.LendingInstruction.html) into a byte buffer.
pub fn pack(&self) -> Vec<u8> {
let mut buf = Vec::with_capacity(size_of::<Self>());
match *self {
Self::InitLendingMarket { owner } => {
buf.push(0);
buf.extend_from_slice(owner.as_ref());
}
Self::SetLendingMarketOwner { new_owner } => {
buf.push(1);
buf.extend_from_slice(new_owner.as_ref());
}
Self::InitReserve {
liquidity_amount,
config:
ReserveConfig {
optimal_utilization_rate,
loan_to_value_ratio,
liquidation_bonus,
liquidation_threshold,
min_borrow_rate,
optimal_borrow_rate,
max_borrow_rate,
fees:
ReserveFees {
borrow_fee_wad,
flash_loan_fee_wad,
host_fee_percentage,
},
},
} => {
buf.push(2);
buf.extend_from_slice(&liquidity_amount.to_le_bytes());
buf.extend_from_slice(&optimal_utilization_rate.to_le_bytes());
buf.extend_from_slice(&loan_to_value_ratio.to_le_bytes());
buf.extend_from_slice(&liquidation_bonus.to_le_bytes());
buf.extend_from_slice(&liquidation_threshold.to_le_bytes());
buf.extend_from_slice(&min_borrow_rate.to_le_bytes());
buf.extend_from_slice(&optimal_borrow_rate.to_le_bytes());
buf.extend_from_slice(&max_borrow_rate.to_le_bytes());
buf.extend_from_slice(&borrow_fee_wad.to_le_bytes());
buf.extend_from_slice(&flash_loan_fee_wad.to_le_bytes());
buf.extend_from_slice(&host_fee_percentage.to_le_bytes());
}
Self::RefreshReserve => {
buf.push(3);
}
Self::DepositReserveLiquidity { liquidity_amount } => {
buf.push(4);
buf.extend_from_slice(&liquidity_amount.to_le_bytes());
}
Self::RedeemReserveCollateral { collateral_amount } => {
buf.push(5);
buf.extend_from_slice(&collateral_amount.to_le_bytes());
}
Self::InitObligation => {
buf.push(6);
}
Self::RefreshObligation => {
buf.push(7);
}
Self::DepositObligationCollateral { collateral_amount } => {
buf.push(8);
buf.extend_from_slice(&collateral_amount.to_le_bytes());
}
Self::WithdrawObligationCollateral { collateral_amount } => {
buf.push(9);
buf.extend_from_slice(&collateral_amount.to_le_bytes());
}
Self::BorrowObligationLiquidity { liquidity_amount } => {
buf.push(10);
buf.extend_from_slice(&liquidity_amount.to_le_bytes());
}
Self::RepayObligationLiquidity { liquidity_amount } => {
buf.push(11);
buf.extend_from_slice(&liquidity_amount.to_le_bytes());
}
Self::LiquidateObligation { liquidity_amount } => {
buf.push(12);
buf.extend_from_slice(&liquidity_amount.to_le_bytes());
}
Self::FlashLoan { amount } => {
buf.push(13);
buf.extend_from_slice(&amount.to_le_bytes());
}
}
buf
}
}
/// Creates an 'InitLendingMarket' instruction.
pub fn init_lending_market(
program_id: Pubkey,
lending_market_pubkey: Pubkey,
lending_market_owner: Pubkey,
quote_token_mint: Pubkey,
) -> Instruction {
Instruction {
program_id,
accounts: vec![
AccountMeta::new(lending_market_pubkey, false),
AccountMeta::new_readonly(quote_token_mint, false),
AccountMeta::new_readonly(sysvar::rent::id(), false),
AccountMeta::new_readonly(spl_token::id(), false),
],
data: LendingInstruction::InitLendingMarket {
owner: lending_market_owner,
}
.pack(),
}
}
/// Creates a 'SetLendingMarketOwner' instruction.
pub fn set_lending_market_owner(
program_id: Pubkey,
lending_market_pubkey: Pubkey,
lending_market_owner: Pubkey,
new_owner: Pubkey,
) -> Instruction {
Instruction {
program_id,
accounts: vec![
AccountMeta::new(lending_market_pubkey, false),
AccountMeta::new_readonly(lending_market_owner, true),
],
data: LendingInstruction::SetLendingMarketOwner { new_owner }.pack(),
}
}
/// Creates an 'InitReserve' instruction.
#[allow(clippy::too_many_arguments)]
pub fn init_reserve(
program_id: Pubkey,
liquidity_amount: u64,
config: ReserveConfig,
source_liquidity_pubkey: Pubkey,
destination_collateral_pubkey: Pubkey,
reserve_pubkey: Pubkey,
reserve_liquidity_mint_pubkey: Pubkey,
reserve_liquidity_supply_pubkey: Pubkey,
reserve_liquidity_fee_receiver_pubkey: Pubkey,
reserve_collateral_mint_pubkey: Pubkey,
reserve_collateral_supply_pubkey: Pubkey,
quote_token_mint_pubkey: Pubkey,
lending_market_pubkey: Pubkey,
lending_market_owner_pubkey: Pubkey,
user_transfer_authority_pubkey: Pubkey,
reserve_liquidity_oracle_pubkey: Option<Pubkey>,
) -> Instruction {
let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
&[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
&program_id,
);
let mut accounts = vec![
AccountMeta::new(source_liquidity_pubkey, false),
AccountMeta::new(destination_collateral_pubkey, false),
AccountMeta::new(reserve_pubkey, false),
AccountMeta::new_readonly(reserve_liquidity_mint_pubkey, false),
AccountMeta::new(reserve_liquidity_supply_pubkey, false),
AccountMeta::new(reserve_liquidity_fee_receiver_pubkey, false),
AccountMeta::new(reserve_collateral_mint_pubkey, false),
AccountMeta::new(reserve_collateral_supply_pubkey, false),
AccountMeta::new_readonly(quote_token_mint_pubkey, false),
AccountMeta::new_readonly(lending_market_pubkey, false),
AccountMeta::new_readonly(lending_market_authority_pubkey, false),
AccountMeta::new_readonly(lending_market_owner_pubkey, true),
AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(sysvar::rent::id(), false),
AccountMeta::new_readonly(spl_token::id(), false),
];
if let Some(reserve_liquidity_oracle_pubkey) = reserve_liquidity_oracle_pubkey {
accounts.push(AccountMeta::new_readonly(
reserve_liquidity_oracle_pubkey,
false,
));
}
Instruction {
program_id,
accounts,
data: LendingInstruction::InitReserve {
liquidity_amount,
config,
}
.pack(),
}
}
/// Creates a `RefreshReserve` instruction
pub fn refresh_reserve(
program_id: Pubkey,
reserve_pubkey: Pubkey,
reserve_liquidity_oracle_pubkey: Option<Pubkey>,
) -> Instruction {
let mut accounts = vec![
AccountMeta::new(reserve_pubkey, false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
];
if let Some(reserve_liquidity_oracle_pubkey) = reserve_liquidity_oracle_pubkey {
accounts.push(AccountMeta::new_readonly(
reserve_liquidity_oracle_pubkey,
false,
));
}
Instruction {
program_id,
accounts,
data: LendingInstruction::RefreshReserve.pack(),
}
}
/// Creates a 'DepositReserveLiquidity' instruction.
#[allow(clippy::too_many_arguments)]
pub fn deposit_reserve_liquidity(
program_id: Pubkey,
liquidity_amount: u64,
source_liquidity_pubkey: Pubkey,
destination_collateral_pubkey: Pubkey,
reserve_pubkey: Pubkey,
reserve_liquidity_supply_pubkey: Pubkey,
reserve_collateral_mint_pubkey: Pubkey,
lending_market_pubkey: Pubkey,
user_transfer_authority_pubkey: Pubkey,
) -> Instruction {
let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
&[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
&program_id,
);
Instruction {
program_id,
accounts: vec![
AccountMeta::new(source_liquidity_pubkey, false),
AccountMeta::new(destination_collateral_pubkey, false),
AccountMeta::new(reserve_pubkey, false),
AccountMeta::new(reserve_liquidity_supply_pubkey, false),
AccountMeta::new(reserve_collateral_mint_pubkey, false),
AccountMeta::new_readonly(lending_market_pubkey, false),
AccountMeta::new_readonly(lending_market_authority_pubkey, false),
AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(spl_token::id(), false),
],
data: LendingInstruction::DepositReserveLiquidity { liquidity_amount }.pack(),
}
}
/// Creates a 'RedeemReserveCollateral' instruction.
#[allow(clippy::too_many_arguments)]
pub fn redeem_reserve_collateral(
program_id: Pubkey,
collateral_amount: u64,
source_collateral_pubkey: Pubkey,
destination_liquidity_pubkey: Pubkey,
reserve_pubkey: Pubkey,
reserve_collateral_mint_pubkey: Pubkey,
reserve_liquidity_supply_pubkey: Pubkey,
lending_market_pubkey: Pubkey,
user_transfer_authority_pubkey: Pubkey,
) -> Instruction {
let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
&[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
&program_id,
);
Instruction {
program_id,
accounts: vec![
AccountMeta::new(source_collateral_pubkey, false),
AccountMeta::new(destination_liquidity_pubkey, false),
AccountMeta::new(reserve_pubkey, false),
AccountMeta::new(reserve_collateral_mint_pubkey, false),
AccountMeta::new(reserve_liquidity_supply_pubkey, false),
AccountMeta::new_readonly(lending_market_pubkey, false),
AccountMeta::new_readonly(lending_market_authority_pubkey, false),
AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(spl_token::id(), false),
],
data: LendingInstruction::RedeemReserveCollateral { collateral_amount }.pack(),
}
}
/// Creates an 'InitObligation' instruction.
#[allow(clippy::too_many_arguments)]
pub fn init_obligation(
program_id: Pubkey,
obligation_pubkey: Pubkey,
lending_market_pubkey: Pubkey,
obligation_owner_pubkey: Pubkey,
) -> Instruction {
Instruction {
program_id,
accounts: vec![
AccountMeta::new(obligation_pubkey, false),
AccountMeta::new_readonly(lending_market_pubkey, false),
AccountMeta::new_readonly(obligation_owner_pubkey, true),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(sysvar::rent::id(), false),
AccountMeta::new_readonly(spl_token::id(), false),
],
data: LendingInstruction::InitObligation.pack(),
}
}
/// Creates a 'RefreshObligation' instruction.
#[allow(clippy::too_many_arguments)]
pub fn refresh_obligation(
program_id: Pubkey,
obligation_pubkey: Pubkey,
reserve_pubkeys: Vec<Pubkey>,
) -> Instruction {
let mut accounts = vec![
AccountMeta::new(obligation_pubkey, false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
];
accounts.extend(
reserve_pubkeys
.into_iter()
.map(|pubkey| AccountMeta::new_readonly(pubkey, false)),
);
Instruction {
program_id,
accounts,
data: LendingInstruction::RefreshObligation.pack(),
}
}
/// Creates a 'DepositObligationCollateral' instruction.
#[allow(clippy::too_many_arguments)]
pub fn deposit_obligation_collateral(
program_id: Pubkey,
collateral_amount: u64,
source_collateral_pubkey: Pubkey,
destination_collateral_pubkey: Pubkey,
deposit_reserve_pubkey: Pubkey,
obligation_pubkey: Pubkey,
lending_market_pubkey: Pubkey,
obligation_owner_pubkey: Pubkey,
user_transfer_authority_pubkey: Pubkey,
) -> Instruction {
let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
&[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
&program_id,
);
Instruction {
program_id,
accounts: vec![
AccountMeta::new(source_collateral_pubkey, false),
AccountMeta::new(destination_collateral_pubkey, false),
AccountMeta::new_readonly(deposit_reserve_pubkey, false),
AccountMeta::new(obligation_pubkey, false),
AccountMeta::new_readonly(lending_market_pubkey, false),
AccountMeta::new_readonly(lending_market_authority_pubkey, false),
AccountMeta::new_readonly(obligation_owner_pubkey, true),
AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(spl_token::id(), false),
],
data: LendingInstruction::DepositObligationCollateral { collateral_amount }.pack(),
}
}
/// Creates a 'WithdrawObligationCollateral' instruction.
#[allow(clippy::too_many_arguments)]
pub fn withdraw_obligation_collateral(
program_id: Pubkey,
collateral_amount: u64,
source_collateral_pubkey: Pubkey,
destination_collateral_pubkey: Pubkey,
withdraw_reserve_pubkey: Pubkey,
obligation_pubkey: Pubkey,
lending_market_pubkey: Pubkey,
obligation_owner_pubkey: Pubkey,
) -> Instruction {
let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
&[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
&program_id,
);
Instruction {
program_id,
accounts: vec![
AccountMeta::new(source_collateral_pubkey, false),
AccountMeta::new(destination_collateral_pubkey, false),
AccountMeta::new_readonly(withdraw_reserve_pubkey, false),
AccountMeta::new(obligation_pubkey, false),
AccountMeta::new_readonly(lending_market_pubkey, false),
AccountMeta::new_readonly(lending_market_authority_pubkey, false),
AccountMeta::new_readonly(obligation_owner_pubkey, true),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(spl_token::id(), false),
],
data: LendingInstruction::WithdrawObligationCollateral { collateral_amount }.pack(),
}
}
/// Creates a 'BorrowObligationLiquidity' instruction.
#[allow(clippy::too_many_arguments)]
pub fn borrow_obligation_liquidity(
program_id: Pubkey,
liquidity_amount: u64,
source_liquidity_pubkey: Pubkey,
destination_liquidity_pubkey: Pubkey,
borrow_reserve_pubkey: Pubkey,
borrow_reserve_liquidity_fee_receiver_pubkey: Pubkey,
obligation_pubkey: Pubkey,
lending_market_pubkey: Pubkey,
obligation_owner_pubkey: Pubkey,
host_fee_receiver_pubkey: Option<Pubkey>,
) -> Instruction {
let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
&[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
&program_id,
);
let mut accounts = vec![
AccountMeta::new(source_liquidity_pubkey, false),
AccountMeta::new(destination_liquidity_pubkey, false),
AccountMeta::new(borrow_reserve_pubkey, false),
AccountMeta::new(borrow_reserve_liquidity_fee_receiver_pubkey, false),
AccountMeta::new(obligation_pubkey, false),
AccountMeta::new_readonly(lending_market_pubkey, false),
AccountMeta::new_readonly(lending_market_authority_pubkey, false),
AccountMeta::new_readonly(obligation_owner_pubkey, true),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(spl_token::id(), false),
];
if let Some(host_fee_receiver_pubkey) = host_fee_receiver_pubkey {
accounts.push(AccountMeta::new(host_fee_receiver_pubkey, false));
}
Instruction {
program_id,
accounts,
data: LendingInstruction::BorrowObligationLiquidity { liquidity_amount }.pack(),
}
}
/// Creates a `RepayObligationLiquidity` instruction
#[allow(clippy::too_many_arguments)]
pub fn repay_obligation_liquidity(
program_id: Pubkey,
liquidity_amount: u64,
source_liquidity_pubkey: Pubkey,
destination_liquidity_pubkey: Pubkey,
repay_reserve_pubkey: Pubkey,
obligation_pubkey: Pubkey,
lending_market_pubkey: Pubkey,
user_transfer_authority_pubkey: Pubkey,
) -> Instruction {
Instruction {
program_id,
accounts: vec![
AccountMeta::new(source_liquidity_pubkey, false),
AccountMeta::new(destination_liquidity_pubkey, false),
AccountMeta::new(repay_reserve_pubkey, false),
AccountMeta::new(obligation_pubkey, false),
AccountMeta::new_readonly(lending_market_pubkey, false),
AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(spl_token::id(), false),
],
data: LendingInstruction::RepayObligationLiquidity { liquidity_amount }.pack(),
}
}
/// Creates a `LiquidateObligation` instruction
#[allow(clippy::too_many_arguments)]
pub fn liquidate_obligation(
program_id: Pubkey,
liquidity_amount: u64,
source_liquidity_pubkey: Pubkey,
destination_collateral_pubkey: Pubkey,
repay_reserve_pubkey: Pubkey,
repay_reserve_liquidity_supply_pubkey: Pubkey,
withdraw_reserve_pubkey: Pubkey,
withdraw_reserve_collateral_supply_pubkey: Pubkey,
obligation_pubkey: Pubkey,
lending_market_pubkey: Pubkey,
user_transfer_authority_pubkey: Pubkey,
) -> Instruction {
let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
&[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
&program_id,
);
Instruction {
program_id,
accounts: vec![
AccountMeta::new(source_liquidity_pubkey, false),
AccountMeta::new(destination_collateral_pubkey, false),
AccountMeta::new(repay_reserve_pubkey, false),
AccountMeta::new(repay_reserve_liquidity_supply_pubkey, false),
AccountMeta::new_readonly(withdraw_reserve_pubkey, false),
AccountMeta::new(withdraw_reserve_collateral_supply_pubkey, false),
AccountMeta::new(obligation_pubkey, false),
AccountMeta::new_readonly(lending_market_pubkey, false),
AccountMeta::new_readonly(lending_market_authority_pubkey, false),
AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(spl_token::id(), false),
],
data: LendingInstruction::LiquidateObligation { liquidity_amount }.pack(),
}
}
/// Creates a `FlashLoan` instruction.
#[allow(clippy::too_many_arguments)]
pub fn flash_loan(
program_id: Pubkey,
amount: u64,
reserve_liquidity_pubkey: Pubkey,
destination_liquidity_pubkey: Pubkey,
reserve_pubkey: Pubkey,
lending_market_pubkey: Pubkey,
derived_lending_market_authority_pubkey: Pubkey,
flash_loan_receiver_pubkey: Pubkey,
flash_loan_fee_receiver_pubkey: Pubkey,
host_fee_receiver_pubkey: Pubkey,
flash_loan_receiver_program_account_meta: Vec<AccountMeta>,
) -> Instruction {
let mut accounts = vec![
AccountMeta::new(reserve_liquidity_pubkey, false),
AccountMeta::new(destination_liquidity_pubkey, false),
AccountMeta::new_readonly(reserve_pubkey, false),
AccountMeta::new_readonly(lending_market_pubkey, false),
AccountMeta::new_readonly(derived_lending_market_authority_pubkey, false),
AccountMeta::new_readonly(flash_loan_receiver_pubkey, false),
AccountMeta::new(flash_loan_fee_receiver_pubkey, false),
AccountMeta::new(host_fee_receiver_pubkey, false),
AccountMeta::new_readonly(spl_token::id(), false),
];
accounts.extend(flash_loan_receiver_program_account_meta);
Instruction {
program_id,
accounts,
data: LendingInstruction::FlashLoan { amount }.pack(),
}
}