jup_lend_sdk/oracle/
simulations.rs

1use std::sync::Arc;
2
3use crate::borrow::errors::ErrorCodes;
4use crate::math::casting::Cast;
5use crate::oracle::{OraclePriceLiquidate, ORACLE_PROGRAM_ID};
6use crate::programs::oracle;
7use crate::ReadKeypair;
8
9use anchor_client::solana_sdk::message::Message;
10use anchor_client::solana_sdk::transaction::Transaction;
11use anchor_client::{
12    solana_client::rpc_config::RpcSimulateTransactionConfig,
13    solana_sdk::{commitment_config::CommitmentConfig, signer::Signer},
14    Client, Cluster,
15};
16use anchor_lang::prelude::{AccountMeta, Pubkey};
17
18pub async fn get_oracle_price_liquidate(
19    oracle: Pubkey,
20    cluster: Cluster,
21) -> anyhow::Result<OraclePriceLiquidate> {
22    let payer = ReadKeypair::new();
23    let provider = Client::new_with_options(
24        cluster.clone(),
25        Arc::new(payer.clone()),
26        CommitmentConfig::processed(),
27    );
28    let program = provider.program(ORACLE_PROGRAM_ID)?;
29    let oracle_data: oracle::accounts::Oracle = program.account(oracle).await?;
30
31    let mut remaining_accounts = vec![];
32
33    for source in &oracle_data.sources {
34        remaining_accounts.push(AccountMeta::new_readonly(source.source, false));
35    }
36
37    get_oracle_price_liquidate_from_remaining_accounts(
38        oracle,
39        &remaining_accounts,
40        &vec![remaining_accounts.len() as u8],
41        cluster,
42    )
43    .await
44}
45
46pub async fn get_oracle_price_liquidate_from_remaining_accounts(
47    oracle: Pubkey,
48    remaining_accounts: &Vec<AccountMeta>,
49    remaining_accounts_indices: &Vec<u8>,
50    cluster: Cluster,
51) -> anyhow::Result<OraclePriceLiquidate> {
52    let payer = ReadKeypair::new();
53    let provider = Client::new_with_options(
54        cluster.clone(),
55        Arc::new(payer.clone()),
56        CommitmentConfig::processed(),
57    );
58    let program = provider.program(ORACLE_PROGRAM_ID)?;
59    let oracle_data: oracle::accounts::Oracle = program.account(oracle).await?;
60
61    let mut price = 0;
62
63    let start_index: usize = 0;
64    let end_index: usize = start_index + remaining_accounts_indices[0].cast::<usize>()?;
65
66    if remaining_accounts.len() < end_index {
67        return Err(ErrorCodes::VaultLiquidateRemainingAccountsTooShort.into());
68    }
69
70    let remaining_accounts = remaining_accounts
71        .iter()
72        .take(end_index)
73        .skip(start_index)
74        .map(|x| x.clone())
75        .collect::<Vec<_>>();
76
77    let instructions = program
78        .request()
79        .accounts(oracle::client::accounts::GetExchangeRateLiquidate { oracle })
80        .accounts(remaining_accounts)
81        .args(oracle::client::args::GetExchangeRateLiquidate {
82            _nonce: oracle_data.nonce,
83        })
84        .instructions()?;
85
86    let message = Message::new(&instructions, Some(&payer.pubkey()));
87    let transaction = Transaction::new_unsigned(message);
88
89    let simulation = program
90        .rpc()
91        .simulate_transaction_with_config(
92            &transaction,
93            RpcSimulateTransactionConfig {
94                replace_recent_blockhash: true,
95                sig_verify: false,
96                ..Default::default()
97            },
98        )
99        .await?;
100
101    if let Some(data) = &simulation.value.return_data {
102        #[allow(deprecated)]
103        let raw_bytes = base64::decode(&data.data.0)?;
104        price = u128::from_le_bytes(raw_bytes.try_into().unwrap());
105    }
106
107    Ok(OraclePriceLiquidate {
108        price,
109        sources: oracle_data.sources,
110    })
111}