974 lines
39 KiB
Rust
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(),
|
|
}
|
|
}
|