390 lines
12 KiB
Rust
390 lines
12 KiB
Rust
#![allow(clippy::integer_arithmetic)]
|
|
#![cfg(feature = "test-sbf")]
|
|
|
|
mod helpers;
|
|
|
|
use helpers::*;
|
|
use solana_program::pubkey::Pubkey;
|
|
use solana_program_test::*;
|
|
use solana_sdk::{
|
|
instruction::InstructionError,
|
|
signature::{read_keypair_file, Keypair, Signer},
|
|
transaction::{Transaction, TransactionError},
|
|
};
|
|
use spl_token_lending::{
|
|
error::LendingError,
|
|
instruction::modify_reserve_config,
|
|
processor::process_instruction,
|
|
state::{
|
|
InitLendingMarketParams, LendingMarket, ReserveConfig, ReserveFees,
|
|
INITIAL_COLLATERAL_RATIO,
|
|
},
|
|
};
|
|
|
|
#[tokio::test]
|
|
async fn modify_reserve_config_success() {
|
|
let mut test = ProgramTest::new(
|
|
"spl_token_lending",
|
|
spl_token_lending::id(),
|
|
processor!(process_instruction),
|
|
);
|
|
|
|
test.set_compute_max_units(70_000);
|
|
|
|
let user_accounts_owner = Keypair::new();
|
|
let lending_market = add_lending_market(&mut test);
|
|
let sol_oracle = add_sol_oracle(&mut test);
|
|
|
|
const SOL_DEPOSIT_AMOUNT_LAMPORTS: u64 = 10 * LAMPORTS_TO_SOL * INITIAL_COLLATERAL_RATIO;
|
|
const SOL_RESERVE_COLLATERAL_LAMPORTS: u64 = 2 * SOL_DEPOSIT_AMOUNT_LAMPORTS;
|
|
|
|
let sol_test_reserve = add_reserve(
|
|
&mut test,
|
|
&lending_market,
|
|
&sol_oracle,
|
|
&user_accounts_owner,
|
|
AddReserveArgs {
|
|
user_liquidity_amount: SOL_RESERVE_COLLATERAL_LAMPORTS,
|
|
liquidity_amount: SOL_RESERVE_COLLATERAL_LAMPORTS,
|
|
liquidity_mint_decimals: 9,
|
|
liquidity_mint_pubkey: spl_token::native_mint::id(),
|
|
config: TEST_RESERVE_CONFIG,
|
|
mark_fresh: true,
|
|
..AddReserveArgs::default()
|
|
},
|
|
);
|
|
|
|
let (mut banks_client, payer, recent_blockhash) = test.start().await;
|
|
|
|
const OPTIMAL_UTILIZATION_RATE_CHANGE: u8 = 10;
|
|
|
|
let new_config = ReserveConfig {
|
|
optimal_utilization_rate: TEST_RESERVE_CONFIG.optimal_utilization_rate
|
|
- OPTIMAL_UTILIZATION_RATE_CHANGE,
|
|
loan_to_value_ratio: 50,
|
|
liquidation_bonus: 5,
|
|
liquidation_threshold: 55,
|
|
min_borrow_rate: 0,
|
|
optimal_borrow_rate: 4,
|
|
max_borrow_rate: 30,
|
|
fees: ReserveFees {
|
|
borrow_fee_wad: 100_000_000_000,
|
|
flash_loan_fee_wad: 3_000_000_000_000_000,
|
|
host_fee_percentage: 20,
|
|
},
|
|
};
|
|
|
|
let mut transaction = Transaction::new_with_payer(
|
|
&[modify_reserve_config(
|
|
spl_token_lending::id(),
|
|
new_config,
|
|
sol_test_reserve.pubkey,
|
|
lending_market.pubkey,
|
|
lending_market.owner.pubkey(),
|
|
)],
|
|
Some(&payer.pubkey()),
|
|
);
|
|
|
|
transaction.sign(&[&payer, &lending_market.owner], recent_blockhash);
|
|
|
|
banks_client
|
|
.process_transaction(transaction)
|
|
.await
|
|
.map_err(|e| e.unwrap())
|
|
.unwrap();
|
|
|
|
let reserve_info = sol_test_reserve.get_state(&mut banks_client).await;
|
|
assert_eq!(reserve_info.config, new_config);
|
|
}
|
|
|
|
#[tokio::test]
|
|
// Invalid Signer - Right owner, right market but owner is not a signer
|
|
async fn wrong_signer_of_lending_market_cannot_change_reserve_config() {
|
|
let mut test = ProgramTest::new(
|
|
"spl_token_lending",
|
|
spl_token_lending::id(),
|
|
processor!(process_instruction),
|
|
);
|
|
|
|
test.set_compute_max_units(70_000);
|
|
|
|
let user_accounts_owner = Keypair::new();
|
|
let lending_market = add_lending_market(&mut test);
|
|
let sol_oracle = add_sol_oracle(&mut test);
|
|
|
|
const SOL_DEPOSIT_AMOUNT_LAMPORTS: u64 = 10 * LAMPORTS_TO_SOL * INITIAL_COLLATERAL_RATIO;
|
|
const SOL_RESERVE_COLLATERAL_LAMPORTS: u64 = 2 * SOL_DEPOSIT_AMOUNT_LAMPORTS;
|
|
|
|
let sol_test_reserve = add_reserve(
|
|
&mut test,
|
|
&lending_market,
|
|
&sol_oracle,
|
|
&user_accounts_owner,
|
|
AddReserveArgs {
|
|
user_liquidity_amount: SOL_RESERVE_COLLATERAL_LAMPORTS,
|
|
liquidity_amount: SOL_RESERVE_COLLATERAL_LAMPORTS,
|
|
liquidity_mint_decimals: 9,
|
|
liquidity_mint_pubkey: spl_token::native_mint::id(),
|
|
config: TEST_RESERVE_CONFIG,
|
|
mark_fresh: true,
|
|
..AddReserveArgs::default()
|
|
},
|
|
);
|
|
|
|
let mut other_lending_market = add_lending_market(&mut test);
|
|
let other_lending_market_owner = Keypair::new();
|
|
other_lending_market.owner = other_lending_market_owner;
|
|
|
|
let (mut banks_client, payer, recent_blockhash) = test.start().await;
|
|
|
|
const OPTIMAL_UTILIZATION_RATE_CHANGE: u8 = 10;
|
|
|
|
let new_config = ReserveConfig {
|
|
optimal_utilization_rate: TEST_RESERVE_CONFIG.optimal_utilization_rate
|
|
- OPTIMAL_UTILIZATION_RATE_CHANGE,
|
|
loan_to_value_ratio: 50,
|
|
liquidation_bonus: 5,
|
|
liquidation_threshold: 55,
|
|
min_borrow_rate: 0,
|
|
optimal_borrow_rate: 4,
|
|
max_borrow_rate: 30,
|
|
fees: ReserveFees {
|
|
borrow_fee_wad: 100_000_000_000,
|
|
flash_loan_fee_wad: 3_000_000_000_000_000,
|
|
host_fee_percentage: 20,
|
|
},
|
|
};
|
|
|
|
let mut instruction = modify_reserve_config(
|
|
spl_token_lending::id(),
|
|
new_config,
|
|
sol_test_reserve.pubkey,
|
|
lending_market.pubkey,
|
|
lending_market.owner.pubkey(),
|
|
);
|
|
instruction.accounts[2].is_signer = false;
|
|
|
|
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
|
|
|
|
transaction.sign(&[&payer], recent_blockhash);
|
|
|
|
let result = banks_client
|
|
.process_transaction(transaction)
|
|
.await
|
|
.map_err(|e| e.unwrap());
|
|
|
|
assert_eq!(
|
|
result.unwrap_err(),
|
|
TransactionError::InstructionError(
|
|
0,
|
|
InstructionError::Custom(LendingError::InvalidSigner as u32)
|
|
)
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
// Right lending market, wrong owner
|
|
async fn owner_of_different_lending_market_cannot_change_reserve_config() {
|
|
let mut test = ProgramTest::new(
|
|
"spl_token_lending",
|
|
spl_token_lending::id(),
|
|
processor!(process_instruction),
|
|
);
|
|
|
|
test.set_compute_max_units(70_000);
|
|
|
|
let user_accounts_owner = Keypair::new();
|
|
let lending_market = add_lending_market(&mut test);
|
|
let sol_oracle = add_sol_oracle(&mut test);
|
|
|
|
const SOL_DEPOSIT_AMOUNT_LAMPORTS: u64 = 10 * LAMPORTS_TO_SOL * INITIAL_COLLATERAL_RATIO;
|
|
const SOL_RESERVE_COLLATERAL_LAMPORTS: u64 = 2 * SOL_DEPOSIT_AMOUNT_LAMPORTS;
|
|
|
|
let sol_test_reserve = add_reserve(
|
|
&mut test,
|
|
&lending_market,
|
|
&sol_oracle,
|
|
&user_accounts_owner,
|
|
AddReserveArgs {
|
|
user_liquidity_amount: SOL_RESERVE_COLLATERAL_LAMPORTS,
|
|
liquidity_amount: SOL_RESERVE_COLLATERAL_LAMPORTS,
|
|
liquidity_mint_decimals: 9,
|
|
liquidity_mint_pubkey: spl_token::native_mint::id(),
|
|
config: TEST_RESERVE_CONFIG,
|
|
mark_fresh: true,
|
|
..AddReserveArgs::default()
|
|
},
|
|
);
|
|
|
|
// Add a different lending market with a *different* owner
|
|
let other_lending_market_pubkey = Pubkey::new_unique();
|
|
let (other_lending_market_authority, bump_seed) = Pubkey::find_program_address(
|
|
&[other_lending_market_pubkey.as_ref()],
|
|
&spl_token_lending::id(),
|
|
);
|
|
|
|
let other_lending_market_owner = Keypair::new();
|
|
let oracle_program_id = read_keypair_file("tests/fixtures/oracle_program_id.json")
|
|
.unwrap()
|
|
.pubkey();
|
|
|
|
test.add_packable_account(
|
|
other_lending_market_pubkey,
|
|
u32::MAX as u64,
|
|
&LendingMarket::new(InitLendingMarketParams {
|
|
bump_seed,
|
|
owner: other_lending_market_owner.pubkey(),
|
|
quote_currency: QUOTE_CURRENCY,
|
|
token_program_id: spl_token::id(),
|
|
oracle_program_id,
|
|
}),
|
|
&spl_token_lending::id(),
|
|
);
|
|
|
|
let other_lending_market = TestLendingMarket {
|
|
pubkey: other_lending_market_pubkey,
|
|
owner: other_lending_market_owner,
|
|
authority: other_lending_market_authority,
|
|
quote_currency: QUOTE_CURRENCY,
|
|
oracle_program_id,
|
|
};
|
|
|
|
let (mut banks_client, payer, recent_blockhash) = test.start().await;
|
|
// Test modify reserve config instruction
|
|
const OPTIMAL_UTILIZATION_RATE_CHANGE: u8 = 10;
|
|
|
|
let new_config = ReserveConfig {
|
|
optimal_utilization_rate: TEST_RESERVE_CONFIG.optimal_utilization_rate
|
|
- OPTIMAL_UTILIZATION_RATE_CHANGE,
|
|
loan_to_value_ratio: 50,
|
|
liquidation_bonus: 5,
|
|
liquidation_threshold: 55,
|
|
min_borrow_rate: 0,
|
|
optimal_borrow_rate: 4,
|
|
max_borrow_rate: 30,
|
|
fees: ReserveFees {
|
|
borrow_fee_wad: 100_000_000_000,
|
|
flash_loan_fee_wad: 3_000_000_000_000_000,
|
|
host_fee_percentage: 20,
|
|
},
|
|
};
|
|
|
|
let mut transaction = Transaction::new_with_payer(
|
|
&[modify_reserve_config(
|
|
spl_token_lending::id(),
|
|
new_config,
|
|
sol_test_reserve.pubkey,
|
|
lending_market.pubkey,
|
|
other_lending_market.owner.pubkey(),
|
|
)],
|
|
Some(&payer.pubkey()),
|
|
);
|
|
|
|
transaction.sign(&[&payer, &other_lending_market.owner], recent_blockhash);
|
|
|
|
let result = banks_client
|
|
.process_transaction(transaction)
|
|
.await
|
|
.map_err(|e| e.unwrap());
|
|
|
|
assert_eq!(
|
|
result.unwrap_err(),
|
|
TransactionError::InstructionError(
|
|
0,
|
|
InstructionError::Custom(LendingError::InvalidMarketOwner as u32)
|
|
)
|
|
);
|
|
|
|
let reserve_info = sol_test_reserve.get_state(&mut banks_client).await;
|
|
assert_eq!(reserve_info.config, TEST_RESERVE_CONFIG);
|
|
}
|
|
|
|
#[tokio::test]
|
|
// Right owner, wrong lending market
|
|
async fn correct_owner_providing_wrong_lending_market_fails() {
|
|
// When the correct owner of the lending market and reserve provides, perhaps inadvertently,
|
|
// a lending market that is different from the given reserve's corresponding lending market,
|
|
// then the transaction to modify the current reserve config should fail.
|
|
let mut test = ProgramTest::new(
|
|
"spl_token_lending",
|
|
spl_token_lending::id(),
|
|
processor!(process_instruction),
|
|
);
|
|
|
|
test.set_compute_max_units(70_000);
|
|
|
|
let user_accounts_owner = Keypair::new();
|
|
let lending_market = add_lending_market(&mut test);
|
|
let sol_oracle = add_sol_oracle(&mut test);
|
|
|
|
const SOL_DEPOSIT_AMOUNT_LAMPORTS: u64 = 10 * LAMPORTS_TO_SOL * INITIAL_COLLATERAL_RATIO;
|
|
const SOL_RESERVE_COLLATERAL_LAMPORTS: u64 = 2 * SOL_DEPOSIT_AMOUNT_LAMPORTS;
|
|
|
|
let sol_test_reserve = add_reserve(
|
|
&mut test,
|
|
&lending_market,
|
|
&sol_oracle,
|
|
&user_accounts_owner,
|
|
AddReserveArgs {
|
|
user_liquidity_amount: SOL_RESERVE_COLLATERAL_LAMPORTS,
|
|
liquidity_amount: SOL_RESERVE_COLLATERAL_LAMPORTS,
|
|
liquidity_mint_decimals: 9,
|
|
liquidity_mint_pubkey: spl_token::native_mint::id(),
|
|
config: TEST_RESERVE_CONFIG,
|
|
mark_fresh: true,
|
|
..AddReserveArgs::default()
|
|
},
|
|
);
|
|
|
|
let other_lending_market = add_lending_market(&mut test);
|
|
|
|
let (mut banks_client, payer, recent_blockhash) = test.start().await;
|
|
|
|
const OPTIMAL_UTILIZATION_RATE_CHANGE: u8 = 10;
|
|
|
|
let new_config = ReserveConfig {
|
|
optimal_utilization_rate: TEST_RESERVE_CONFIG.optimal_utilization_rate
|
|
- OPTIMAL_UTILIZATION_RATE_CHANGE,
|
|
loan_to_value_ratio: 50,
|
|
liquidation_bonus: 5,
|
|
liquidation_threshold: 55,
|
|
min_borrow_rate: 0,
|
|
optimal_borrow_rate: 4,
|
|
max_borrow_rate: 30,
|
|
fees: ReserveFees {
|
|
borrow_fee_wad: 100_000_000_000,
|
|
flash_loan_fee_wad: 3_000_000_000_000_000,
|
|
host_fee_percentage: 20,
|
|
},
|
|
};
|
|
|
|
let mut transaction = Transaction::new_with_payer(
|
|
&[modify_reserve_config(
|
|
spl_token_lending::id(),
|
|
new_config,
|
|
sol_test_reserve.pubkey,
|
|
other_lending_market.pubkey,
|
|
lending_market.owner.pubkey(), //lending_market.owner == other_lending_market.owner, defined by `add_lending_market`
|
|
)],
|
|
Some(&payer.pubkey()),
|
|
);
|
|
|
|
transaction.sign(&[&payer, &lending_market.owner], recent_blockhash);
|
|
|
|
let result = banks_client
|
|
.process_transaction(transaction)
|
|
.await
|
|
.map_err(|e| e.unwrap());
|
|
|
|
assert_eq!(
|
|
result.unwrap_err(),
|
|
TransactionError::InstructionError(
|
|
0,
|
|
InstructionError::Custom(LendingError::InvalidAccountInput as u32)
|
|
)
|
|
);
|
|
|
|
let reserve_info = sol_test_reserve.get_state(&mut banks_client).await;
|
|
assert_eq!(reserve_info.config, TEST_RESERVE_CONFIG);
|
|
}
|