test: add fallback oracle withdrawal test

This commit is contained in:
Lou-Kamades 2023-11-20 15:00:57 -06:00
parent d4017e6038
commit 20261bf734
7 changed files with 173 additions and 17 deletions

View File

@ -228,7 +228,7 @@ fn pyth_get_price(
/// Returns the price of one native base token, in native quote tokens
///
/// Example: The for SOL at 40 USDC/SOL it would return 0.04 (the unit is USDC-native/SOL-native)
/// Example: The price for SOL at 40 USDC/SOL it would return 0.04 (the unit is USDC-native/SOL-native)
///
/// This currently assumes that quote decimals (i.e. decimals for USD) is 6, like for USDC.
///

View File

@ -286,6 +286,7 @@ async fn test_basic() -> Result<(), TransportError> {
send_tx(
solana,
StubOracleCloseInstruction {
oracle: tokens[0].oracle,
group,
mint: bank_data.mint,
admin,

View File

@ -68,7 +68,7 @@ async fn test_health_compute_tokens() -> Result<(), TransportError> {
let avg_cu_increase = cu_measurements.windows(2).map(|p| p[1] - p[0]).sum::<u64>()
/ (cu_measurements.len() - 1) as u64;
println!("average cu increase: {avg_cu_increase}");
assert!(avg_cu_increase < 3200);
assert!(avg_cu_increase < 3230);
Ok(())
}

View File

@ -244,7 +244,7 @@ async fn test_margin_trade() -> Result<(), BanksClientError> {
#[tokio::test]
async fn test_flash_loan_swap_fee() -> Result<(), BanksClientError> {
let mut test_builder = TestContextBuilder::new();
test_builder.test().set_compute_max_units(100_000);
test_builder.test().set_compute_max_units(150_000);
let context = test_builder.start_default().await;
let solana = &context.solana.clone();

View File

@ -975,7 +975,7 @@ async fn test_perp_pnl_settle_limit() -> Result<(), TransportError> {
send_tx(
solana,
StubOracleSetInstruction {
oracle: tokens[0].oracle,
oracle: tokens[1].oracle,
group,
admin,
mint: mints[1].pubkey,

View File

@ -1,9 +1,10 @@
use super::*;
use anchor_lang::prelude::AccountMeta;
#[tokio::test]
async fn test_stale_oracle_deposit_withdraw() -> Result<(), TransportError> {
let mut test_builder = TestContextBuilder::new();
test_builder.test().set_compute_max_units(100_000); // bad oracles log a lot
test_builder.test().set_compute_max_units(150_000); // bad oracles log a lot
let context = test_builder.start_default().await;
let solana = &context.solana.clone();
@ -174,3 +175,147 @@ async fn test_stale_oracle_deposit_withdraw() -> Result<(), TransportError> {
.unwrap();
Ok(())
}
#[tokio::test]
async fn test_fallback_oracle_withdraw() -> Result<(), TransportError> {
let mut test_builder = TestContextBuilder::new();
test_builder.test().set_compute_max_units(150_000); // bad oracles log a lot
let context = test_builder.start_default().await;
let solana = &context.solana.clone();
let fallback_oracle_kp = TestKeypair::new();
let fallback_oracle = fallback_oracle_kp.pubkey();
let admin = TestKeypair::new();
let owner = context.users[0].key;
let payer = context.users[1].key;
let mints = &context.mints[0..3];
let payer_token_accounts = &context.users[1].token_accounts[0..3];
//
// SETUP: Create a group, account, register tokens
//Foracle_
let mango_setup::GroupWithTokens { group, tokens, .. } = mango_setup::GroupWithTokensConfig {
admin,
payer,
mints: mints.to_vec(),
..mango_setup::GroupWithTokensConfig::default()
}
.create(solana)
.await;
// setup fallback_oracle
send_tx(
solana,
StubOracleCreate {
oracle: fallback_oracle_kp,
group,
mint: mints[2].pubkey,
admin,
payer,
},
)
.await
.unwrap();
// add a fallback oracle
send_tx(
solana,
TokenEdit {
group,
admin,
mint: mints[2].pubkey,
options: mango_v4::instruction::TokenEdit {
fallback_oracle_opt: Some(fallback_oracle),
..token_edit_instruction_default()
},
},
)
.await
.unwrap();
let bank_data: Bank = solana.get_account(tokens[2].bank).await;
assert!(bank_data.fallback_oracle == fallback_oracle);
// fill vaults, so we can borrow
let _vault_account = create_funded_account(
&solana,
group,
owner,
2,
&context.users[1],
mints,
100_000,
0,
)
.await;
// Create account with token3 of deposits
let account = create_funded_account(
&solana,
group,
owner,
0,
&context.users[1],
&[mints[2]],
1_000_000,
0,
)
.await;
// Create some token1 borrows
send_tx(
solana,
TokenWithdrawInstruction {
amount: 1,
allow_borrow: true,
account,
owner,
token_account: payer_token_accounts[1],
bank_index: 0,
},
)
.await
.unwrap();
// Make oracle invalid by increasing deviation
send_tx(
solana,
StubOracleSetTestInstruction {
oracle: tokens[2].oracle,
group,
mint: mints[2].pubkey,
admin,
price: 1.0,
last_update_slot: 0,
deviation: 100.0,
},
)
.await
.unwrap();
let token_withdraw_ix = TokenWithdrawInstruction {
amount: 1,
allow_borrow: true,
account,
owner,
token_account: payer_token_accounts[2],
bank_index: 0,
};
// Verify that withdrawing collateral won't work
assert!(send_tx(solana, token_withdraw_ix.clone(),).await.is_err());
// now send txn with a fallback oracle in the remaining accounts
let fallback_oracle_meta = AccountMeta {
pubkey: fallback_oracle,
is_writable: false,
is_signer: false,
};
send_tx_with_extra_accounts(solana, token_withdraw_ix, vec![fallback_oracle_meta])
.await
.unwrap();
Ok(())
}

View File

@ -41,7 +41,7 @@ impl ClientAccountLoader for &SolanaCookie {
}
}
// This fill return a failure if the tx resulted in an error
// This will return a failure if the tx resulted in an error
pub async fn send_tx<CI: ClientInstruction>(
solana: &SolanaCookie,
ix: CI,
@ -57,6 +57,23 @@ pub async fn send_tx<CI: ClientInstruction>(
Ok(accounts)
}
// This will return a failure if the tx resulted in an error
pub async fn send_tx_with_extra_accounts<CI: ClientInstruction>(
solana: &SolanaCookie,
ix: CI,
account_metas: Vec<AccountMeta>,
) -> std::result::Result<CI::Accounts, TransportError> {
let (accounts, mut instruction) = ix.to_instruction(solana).await;
instruction.accounts.extend(account_metas);
let signers = ix.signers();
let instructions = vec![instruction.clone()];
let result = solana
.process_transaction(&instructions, Some(&signers[..]))
.await?;
result.result?;
Ok(accounts)
}
// This will return success even if the tx failed to finish
pub async fn send_tx_get_metadata<CI: ClientInstruction>(
solana: &SolanaCookie,
@ -724,6 +741,7 @@ impl ClientInstruction for FlashLoanEndInstruction {
}
}
#[derive(Clone)]
pub struct TokenWithdrawInstruction {
pub amount: u64,
pub allow_borrow: bool,
@ -795,6 +813,7 @@ impl ClientInstruction for TokenWithdrawInstruction {
}
}
#[derive(Clone)]
pub struct TokenDepositInstruction {
pub amount: u64,
pub reduce_only: bool,
@ -1670,6 +1689,7 @@ impl ClientInstruction for StubOracleCreate {
}
pub struct StubOracleCloseInstruction {
pub oracle: Pubkey,
pub group: Pubkey,
pub mint: Pubkey,
pub admin: TestKeypair,
@ -1687,20 +1707,10 @@ impl ClientInstruction for StubOracleCloseInstruction {
let program_id = mango_v4::id();
let instruction = Self::Instruction {};
let oracle = Pubkey::find_program_address(
&[
b"StubOracle".as_ref(),
self.group.as_ref(),
self.mint.as_ref(),
],
&program_id,
)
.0;
let accounts = Self::Accounts {
group: self.group,
admin: self.admin.pubkey(),
oracle,
oracle: self.oracle,
sol_destination: self.sol_destination,
token_program: Token::id(),
};