Adapt RpcClient to recent token method changes (#11519)
* Avoid skip_serializing_if since that breaks deserialization * Adapt RpcClient to recent token method changes
This commit is contained in:
@ -45,7 +45,14 @@ pub fn parse_token(
|
|||||||
},
|
},
|
||||||
is_initialized: account.is_initialized,
|
is_initialized: account.is_initialized,
|
||||||
is_native: account.is_native,
|
is_native: account.is_native,
|
||||||
delegated_amount: token_amount_to_ui_amount(account.delegated_amount, decimals),
|
delegated_amount: if account.delegate.is_none() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(token_amount_to_ui_amount(
|
||||||
|
account.delegated_amount,
|
||||||
|
decimals,
|
||||||
|
))
|
||||||
|
},
|
||||||
}))
|
}))
|
||||||
} else if data.len() == size_of::<Mint>() {
|
} else if data.len() == size_of::<Mint>() {
|
||||||
let mint: Mint = *unpack(&mut data)
|
let mint: Mint = *unpack(&mut data)
|
||||||
@ -102,8 +109,8 @@ pub struct UiTokenAccount {
|
|||||||
pub delegate: Option<String>,
|
pub delegate: Option<String>,
|
||||||
pub is_initialized: bool,
|
pub is_initialized: bool,
|
||||||
pub is_native: bool,
|
pub is_native: bool,
|
||||||
#[serde(skip_serializing_if = "UiTokenAmount::is_zero")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub delegated_amount: UiTokenAmount,
|
pub delegated_amount: Option<UiTokenAmount>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||||
@ -114,16 +121,6 @@ pub struct UiTokenAmount {
|
|||||||
pub amount: StringAmount,
|
pub amount: StringAmount,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UiTokenAmount {
|
|
||||||
fn is_zero(&self) -> bool {
|
|
||||||
if let Ok(amount) = self.amount.parse::<u64>() {
|
|
||||||
amount == 0
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn token_amount_to_ui_amount(amount: u64, decimals: u8) -> UiTokenAmount {
|
pub fn token_amount_to_ui_amount(amount: u64, decimals: u8) -> UiTokenAmount {
|
||||||
// Use `amount_to_ui_amount()` once spl_token is bumped to a version that supports it: https://github.com/solana-labs/solana-program-library/pull/211
|
// Use `amount_to_ui_amount()` once spl_token is bumped to a version that supports it: https://github.com/solana-labs/solana-program-library/pull/211
|
||||||
let amount_decimals = amount as f64 / 10_usize.pow(decimals as u32) as f64;
|
let amount_decimals = amount as f64 / 10_usize.pow(decimals as u32) as f64;
|
||||||
@ -188,11 +185,7 @@ mod test {
|
|||||||
delegate: None,
|
delegate: None,
|
||||||
is_initialized: true,
|
is_initialized: true,
|
||||||
is_native: false,
|
is_native: false,
|
||||||
delegated_amount: UiTokenAmount {
|
delegated_amount: None,
|
||||||
ui_amount: 0.0,
|
|
||||||
decimals: 2,
|
|
||||||
amount: "0".to_string()
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -16,10 +16,7 @@ use indicatif::{ProgressBar, ProgressStyle};
|
|||||||
use log::*;
|
use log::*;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use solana_account_decoder::{
|
use solana_account_decoder::{
|
||||||
parse_token::{
|
parse_token::UiTokenAmount,
|
||||||
get_token_account_mint, parse_token, TokenAccountType, UiMint, UiMultisig, UiTokenAccount,
|
|
||||||
UiTokenAmount,
|
|
||||||
},
|
|
||||||
UiAccount,
|
UiAccount,
|
||||||
UiAccountData::{Binary, Binary64},
|
UiAccountData::{Binary, Binary64},
|
||||||
UiAccountEncoding,
|
UiAccountEncoding,
|
||||||
@ -44,7 +41,6 @@ use solana_transaction_status::{
|
|||||||
};
|
};
|
||||||
use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY;
|
use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
thread::sleep,
|
thread::sleep,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
@ -703,103 +699,6 @@ impl RpcClient {
|
|||||||
Ok(hash)
|
Ok(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_token_account(&self, pubkey: &Pubkey) -> ClientResult<Option<UiTokenAccount>> {
|
|
||||||
Ok(self
|
|
||||||
.get_token_account_with_commitment(pubkey, CommitmentConfig::default())?
|
|
||||||
.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_token_account_with_commitment(
|
|
||||||
&self,
|
|
||||||
pubkey: &Pubkey,
|
|
||||||
commitment_config: CommitmentConfig,
|
|
||||||
) -> RpcResult<Option<UiTokenAccount>> {
|
|
||||||
let Response {
|
|
||||||
context,
|
|
||||||
value: account,
|
|
||||||
} = self.get_account_with_commitment(pubkey, commitment_config)?;
|
|
||||||
|
|
||||||
if account.is_none() {
|
|
||||||
return Err(RpcError::ForUser(format!("AccountNotFound: pubkey={}", pubkey)).into());
|
|
||||||
}
|
|
||||||
let account = account.unwrap();
|
|
||||||
let mint = get_token_account_mint(&account.data)
|
|
||||||
.and_then(|mint_pubkey| {
|
|
||||||
self.get_token_mint_with_commitment(&mint_pubkey, commitment_config)
|
|
||||||
.ok()
|
|
||||||
.map(|response| response.value)
|
|
||||||
.flatten()
|
|
||||||
})
|
|
||||||
.ok_or_else(|| {
|
|
||||||
Into::<ClientError>::into(RpcError::ForUser(format!(
|
|
||||||
"AccountNotFound: mint for token acccount pubkey={}",
|
|
||||||
pubkey
|
|
||||||
)))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(Response {
|
|
||||||
context,
|
|
||||||
value: match parse_token(&account.data, Some(mint.decimals)) {
|
|
||||||
Ok(TokenAccountType::Account(ui_token_account)) => Some(ui_token_account),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_token_mint(&self, pubkey: &Pubkey) -> ClientResult<Option<UiMint>> {
|
|
||||||
Ok(self
|
|
||||||
.get_token_mint_with_commitment(pubkey, CommitmentConfig::default())?
|
|
||||||
.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_token_mint_with_commitment(
|
|
||||||
&self,
|
|
||||||
pubkey: &Pubkey,
|
|
||||||
commitment_config: CommitmentConfig,
|
|
||||||
) -> RpcResult<Option<UiMint>> {
|
|
||||||
let Response {
|
|
||||||
context,
|
|
||||||
value: account,
|
|
||||||
} = self.get_account_with_commitment(pubkey, commitment_config)?;
|
|
||||||
|
|
||||||
Ok(Response {
|
|
||||||
context,
|
|
||||||
value: account
|
|
||||||
.map(|account| match parse_token(&account.data, None) {
|
|
||||||
Ok(TokenAccountType::Mint(ui_token_mint)) => Some(ui_token_mint),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.flatten(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_token_multisig(&self, pubkey: &Pubkey) -> ClientResult<Option<UiMultisig>> {
|
|
||||||
Ok(self
|
|
||||||
.get_token_multisig_with_commitment(pubkey, CommitmentConfig::default())?
|
|
||||||
.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_token_multisig_with_commitment(
|
|
||||||
&self,
|
|
||||||
pubkey: &Pubkey,
|
|
||||||
commitment_config: CommitmentConfig,
|
|
||||||
) -> RpcResult<Option<UiMultisig>> {
|
|
||||||
let Response {
|
|
||||||
context,
|
|
||||||
value: account,
|
|
||||||
} = self.get_account_with_commitment(pubkey, commitment_config)?;
|
|
||||||
|
|
||||||
Ok(Response {
|
|
||||||
context,
|
|
||||||
value: account
|
|
||||||
.map(|account| match parse_token(&account.data, None) {
|
|
||||||
Ok(TokenAccountType::Multisig(ui_token_multisig)) => Some(ui_token_multisig),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.flatten(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_token_account_balance(&self, pubkey: &Pubkey) -> ClientResult<UiTokenAmount> {
|
pub fn get_token_account_balance(&self, pubkey: &Pubkey) -> ClientResult<UiTokenAmount> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.get_token_account_balance_with_commitment(pubkey, CommitmentConfig::default())?
|
.get_token_account_balance_with_commitment(pubkey, CommitmentConfig::default())?
|
||||||
@ -821,7 +720,7 @@ impl RpcClient {
|
|||||||
&self,
|
&self,
|
||||||
delegate: &Pubkey,
|
delegate: &Pubkey,
|
||||||
token_account_filter: TokenAccountsFilter,
|
token_account_filter: TokenAccountsFilter,
|
||||||
) -> ClientResult<Vec<(Pubkey, UiTokenAccount)>> {
|
) -> ClientResult<Vec<RpcKeyedAccount>> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.get_token_accounts_by_delegate_with_commitment(
|
.get_token_accounts_by_delegate_with_commitment(
|
||||||
delegate,
|
delegate,
|
||||||
@ -836,39 +735,31 @@ impl RpcClient {
|
|||||||
delegate: &Pubkey,
|
delegate: &Pubkey,
|
||||||
token_account_filter: TokenAccountsFilter,
|
token_account_filter: TokenAccountsFilter,
|
||||||
commitment_config: CommitmentConfig,
|
commitment_config: CommitmentConfig,
|
||||||
) -> RpcResult<Vec<(Pubkey, UiTokenAccount)>> {
|
) -> RpcResult<Vec<RpcKeyedAccount>> {
|
||||||
let token_account_filter = match token_account_filter {
|
let token_account_filter = match token_account_filter {
|
||||||
TokenAccountsFilter::Mint(mint) => RpcTokenAccountsFilter::Mint(mint.to_string()),
|
TokenAccountsFilter::Mint(mint) => RpcTokenAccountsFilter::Mint(mint.to_string()),
|
||||||
TokenAccountsFilter::ProgramId(program_id) => {
|
TokenAccountsFilter::ProgramId(program_id) => {
|
||||||
RpcTokenAccountsFilter::ProgramId(program_id.to_string())
|
RpcTokenAccountsFilter::ProgramId(program_id.to_string())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let Response {
|
|
||||||
context,
|
let config = RpcAccountInfoConfig {
|
||||||
value: accounts,
|
encoding: Some(UiAccountEncoding::JsonParsed),
|
||||||
} = self.send(
|
commitment: Some(commitment_config),
|
||||||
RpcRequest::GetTokenAccountsByDelegate,
|
data_slice: None,
|
||||||
json!([
|
};
|
||||||
delegate.to_string(),
|
|
||||||
token_account_filter,
|
self.send(
|
||||||
commitment_config
|
RpcRequest::GetTokenAccountsByOwner,
|
||||||
]),
|
json!([delegate.to_string(), token_account_filter, config]),
|
||||||
)?;
|
)
|
||||||
let pubkey_accounts = self.accounts_to_token_accounts(
|
|
||||||
commitment_config,
|
|
||||||
parse_keyed_accounts(accounts, RpcRequest::GetTokenAccountsByDelegate)?,
|
|
||||||
);
|
|
||||||
Ok(Response {
|
|
||||||
context,
|
|
||||||
value: pubkey_accounts,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_token_accounts_by_owner(
|
pub fn get_token_accounts_by_owner(
|
||||||
&self,
|
&self,
|
||||||
owner: &Pubkey,
|
owner: &Pubkey,
|
||||||
token_account_filter: TokenAccountsFilter,
|
token_account_filter: TokenAccountsFilter,
|
||||||
) -> ClientResult<Vec<(Pubkey, UiTokenAccount)>> {
|
) -> ClientResult<Vec<RpcKeyedAccount>> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.get_token_accounts_by_owner_with_commitment(
|
.get_token_accounts_by_owner_with_commitment(
|
||||||
owner,
|
owner,
|
||||||
@ -883,28 +774,24 @@ impl RpcClient {
|
|||||||
owner: &Pubkey,
|
owner: &Pubkey,
|
||||||
token_account_filter: TokenAccountsFilter,
|
token_account_filter: TokenAccountsFilter,
|
||||||
commitment_config: CommitmentConfig,
|
commitment_config: CommitmentConfig,
|
||||||
) -> RpcResult<Vec<(Pubkey, UiTokenAccount)>> {
|
) -> RpcResult<Vec<RpcKeyedAccount>> {
|
||||||
let token_account_filter = match token_account_filter {
|
let token_account_filter = match token_account_filter {
|
||||||
TokenAccountsFilter::Mint(mint) => RpcTokenAccountsFilter::Mint(mint.to_string()),
|
TokenAccountsFilter::Mint(mint) => RpcTokenAccountsFilter::Mint(mint.to_string()),
|
||||||
TokenAccountsFilter::ProgramId(program_id) => {
|
TokenAccountsFilter::ProgramId(program_id) => {
|
||||||
RpcTokenAccountsFilter::ProgramId(program_id.to_string())
|
RpcTokenAccountsFilter::ProgramId(program_id.to_string())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let Response {
|
|
||||||
context,
|
let config = RpcAccountInfoConfig {
|
||||||
value: accounts,
|
encoding: Some(UiAccountEncoding::JsonParsed),
|
||||||
} = self.send(
|
commitment: Some(commitment_config),
|
||||||
|
data_slice: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.send(
|
||||||
RpcRequest::GetTokenAccountsByOwner,
|
RpcRequest::GetTokenAccountsByOwner,
|
||||||
json!([owner.to_string(), token_account_filter, commitment_config]),
|
json!([owner.to_string(), token_account_filter, config]),
|
||||||
)?;
|
)
|
||||||
let pubkey_accounts = self.accounts_to_token_accounts(
|
|
||||||
commitment_config,
|
|
||||||
parse_keyed_accounts(accounts, RpcRequest::GetTokenAccountsByDelegate)?,
|
|
||||||
);
|
|
||||||
Ok(Response {
|
|
||||||
context,
|
|
||||||
value: pubkey_accounts,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_token_supply(&self, mint: &Pubkey) -> ClientResult<UiTokenAmount> {
|
pub fn get_token_supply(&self, mint: &Pubkey) -> ClientResult<UiTokenAmount> {
|
||||||
@ -924,35 +811,6 @@ impl RpcClient {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accounts_to_token_accounts(
|
|
||||||
&self,
|
|
||||||
commitment_config: CommitmentConfig,
|
|
||||||
pubkey_accounts: Vec<(Pubkey, Account)>,
|
|
||||||
) -> Vec<(Pubkey, UiTokenAccount)> {
|
|
||||||
let mut mint_decimals: HashMap<Pubkey, u8> = HashMap::new();
|
|
||||||
pubkey_accounts
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|(pubkey, account)| {
|
|
||||||
let mint_pubkey = get_token_account_mint(&account.data)?;
|
|
||||||
let decimals = mint_decimals.get(&mint_pubkey).cloned().or_else(|| {
|
|
||||||
let mint = self
|
|
||||||
.get_token_mint_with_commitment(&mint_pubkey, commitment_config)
|
|
||||||
.ok()
|
|
||||||
.map(|response| response.value)
|
|
||||||
.flatten()?;
|
|
||||||
mint_decimals.insert(mint_pubkey, mint.decimals);
|
|
||||||
Some(mint.decimals)
|
|
||||||
})?;
|
|
||||||
match parse_token(&account.data, Some(decimals)) {
|
|
||||||
Ok(TokenAccountType::Account(ui_token_account)) => {
|
|
||||||
Some((pubkey, ui_token_account))
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_balance_with_timeout_and_commitment(
|
fn poll_balance_with_timeout_and_commitment(
|
||||||
&self,
|
&self,
|
||||||
pubkey: &Pubkey,
|
pubkey: &Pubkey,
|
||||||
|
Reference in New Issue
Block a user