Support token-2022 in RPC account parsing (#24619)
* Use token-2022 in parsed_token_account * Parse token-2022 accounts
This commit is contained in:
parent
674c0d7602
commit
d2dad51b8c
|
@ -5514,6 +5514,7 @@ dependencies = [
|
||||||
"solana-version",
|
"solana-version",
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
"spl-token",
|
"spl-token",
|
||||||
|
"spl-token-2022",
|
||||||
"stream-cancel",
|
"stream-cancel",
|
||||||
"symlink",
|
"symlink",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
|
|
@ -4,7 +4,9 @@ use {
|
||||||
StringAmount, StringDecimals,
|
StringAmount, StringDecimals,
|
||||||
},
|
},
|
||||||
solana_sdk::pubkey::Pubkey,
|
solana_sdk::pubkey::Pubkey,
|
||||||
spl_token::{
|
spl_token_2022::{
|
||||||
|
extension::StateWithExtensions,
|
||||||
|
generic_token_account::GenericTokenAccount,
|
||||||
solana_program::{
|
solana_program::{
|
||||||
program_option::COption, program_pack::Pack, pubkey::Pubkey as SplTokenPubkey,
|
program_option::COption, program_pack::Pack, pubkey::Pubkey as SplTokenPubkey,
|
||||||
},
|
},
|
||||||
|
@ -60,58 +62,56 @@ pub fn parse_token(
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
mint_decimals: Option<u8>,
|
mint_decimals: Option<u8>,
|
||||||
) -> Result<TokenAccountType, ParseAccountError> {
|
) -> Result<TokenAccountType, ParseAccountError> {
|
||||||
if data.len() == Account::get_packed_len() {
|
if let Ok(account) = StateWithExtensions::<Account>::unpack(data) {
|
||||||
let account = Account::unpack(data)
|
|
||||||
.map_err(|_| ParseAccountError::AccountNotParsable(ParsableAccount::SplToken))?;
|
|
||||||
let decimals = mint_decimals.ok_or_else(|| {
|
let decimals = mint_decimals.ok_or_else(|| {
|
||||||
ParseAccountError::AdditionalDataMissing(
|
ParseAccountError::AdditionalDataMissing(
|
||||||
"no mint_decimals provided to parse spl-token account".to_string(),
|
"no mint_decimals provided to parse spl-token account".to_string(),
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
Ok(TokenAccountType::Account(UiTokenAccount {
|
return Ok(TokenAccountType::Account(UiTokenAccount {
|
||||||
mint: account.mint.to_string(),
|
mint: account.base.mint.to_string(),
|
||||||
owner: account.owner.to_string(),
|
owner: account.base.owner.to_string(),
|
||||||
token_amount: token_amount_to_ui_amount(account.amount, decimals),
|
token_amount: token_amount_to_ui_amount(account.base.amount, decimals),
|
||||||
delegate: match account.delegate {
|
delegate: match account.base.delegate {
|
||||||
COption::Some(pubkey) => Some(pubkey.to_string()),
|
COption::Some(pubkey) => Some(pubkey.to_string()),
|
||||||
COption::None => None,
|
COption::None => None,
|
||||||
},
|
},
|
||||||
state: account.state.into(),
|
state: account.base.state.into(),
|
||||||
is_native: account.is_native(),
|
is_native: account.base.is_native(),
|
||||||
rent_exempt_reserve: match account.is_native {
|
rent_exempt_reserve: match account.base.is_native {
|
||||||
COption::Some(reserve) => Some(token_amount_to_ui_amount(reserve, decimals)),
|
COption::Some(reserve) => Some(token_amount_to_ui_amount(reserve, decimals)),
|
||||||
COption::None => None,
|
COption::None => None,
|
||||||
},
|
},
|
||||||
delegated_amount: if account.delegate.is_none() {
|
delegated_amount: if account.base.delegate.is_none() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(token_amount_to_ui_amount(
|
Some(token_amount_to_ui_amount(
|
||||||
account.delegated_amount,
|
account.base.delegated_amount,
|
||||||
decimals,
|
decimals,
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
close_authority: match account.close_authority {
|
close_authority: match account.base.close_authority {
|
||||||
COption::Some(pubkey) => Some(pubkey.to_string()),
|
COption::Some(pubkey) => Some(pubkey.to_string()),
|
||||||
COption::None => None,
|
COption::None => None,
|
||||||
},
|
},
|
||||||
}))
|
}));
|
||||||
} else if data.len() == Mint::get_packed_len() {
|
}
|
||||||
let mint = Mint::unpack(data)
|
if let Ok(mint) = StateWithExtensions::<Mint>::unpack(data) {
|
||||||
.map_err(|_| ParseAccountError::AccountNotParsable(ParsableAccount::SplToken))?;
|
return Ok(TokenAccountType::Mint(UiMint {
|
||||||
Ok(TokenAccountType::Mint(UiMint {
|
mint_authority: match mint.base.mint_authority {
|
||||||
mint_authority: match mint.mint_authority {
|
|
||||||
COption::Some(pubkey) => Some(pubkey.to_string()),
|
COption::Some(pubkey) => Some(pubkey.to_string()),
|
||||||
COption::None => None,
|
COption::None => None,
|
||||||
},
|
},
|
||||||
supply: mint.supply.to_string(),
|
supply: mint.base.supply.to_string(),
|
||||||
decimals: mint.decimals,
|
decimals: mint.base.decimals,
|
||||||
is_initialized: mint.is_initialized,
|
is_initialized: mint.base.is_initialized,
|
||||||
freeze_authority: match mint.freeze_authority {
|
freeze_authority: match mint.base.freeze_authority {
|
||||||
COption::Some(pubkey) => Some(pubkey.to_string()),
|
COption::Some(pubkey) => Some(pubkey.to_string()),
|
||||||
COption::None => None,
|
COption::None => None,
|
||||||
},
|
},
|
||||||
}))
|
}));
|
||||||
} else if data.len() == Multisig::get_packed_len() {
|
}
|
||||||
|
if data.len() == Multisig::get_packed_len() {
|
||||||
let multisig = Multisig::unpack(data)
|
let multisig = Multisig::unpack(data)
|
||||||
.map_err(|_| ParseAccountError::AccountNotParsable(ParsableAccount::SplToken))?;
|
.map_err(|_| ParseAccountError::AccountNotParsable(ParsableAccount::SplToken))?;
|
||||||
Ok(TokenAccountType::Multisig(UiMultisig {
|
Ok(TokenAccountType::Multisig(UiMultisig {
|
||||||
|
@ -265,7 +265,7 @@ pub struct UiMultisig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_token_account_mint(data: &[u8]) -> Option<Pubkey> {
|
pub fn get_token_account_mint(data: &[u8]) -> Option<Pubkey> {
|
||||||
if data.len() == Account::get_packed_len() {
|
if Account::valid_account_data(data) {
|
||||||
Some(Pubkey::new(&data[0..32]))
|
Some(Pubkey::new(&data[0..32]))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -370,6 +370,7 @@ mod test {
|
||||||
let mut account_data = vec![0; Account::get_packed_len()];
|
let mut account_data = vec![0; Account::get_packed_len()];
|
||||||
let mut account = Account::unpack_unchecked(&account_data).unwrap();
|
let mut account = Account::unpack_unchecked(&account_data).unwrap();
|
||||||
account.mint = mint_pubkey;
|
account.mint = mint_pubkey;
|
||||||
|
account.state = AccountState::Initialized;
|
||||||
Account::pack(account, &mut account_data).unwrap();
|
Account::pack(account, &mut account_data).unwrap();
|
||||||
|
|
||||||
let expected_mint_pubkey = Pubkey::new(&[2; 32]);
|
let expected_mint_pubkey = Pubkey::new(&[2; 32]);
|
||||||
|
|
|
@ -4870,6 +4870,7 @@ dependencies = [
|
||||||
"solana-version",
|
"solana-version",
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
"spl-token",
|
"spl-token",
|
||||||
|
"spl-token-2022",
|
||||||
"stream-cancel",
|
"stream-cancel",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|
|
@ -49,6 +49,7 @@ solana-transaction-status = { path = "../transaction-status", version = "=1.11.0
|
||||||
solana-version = { path = "../version", version = "=1.11.0" }
|
solana-version = { path = "../version", version = "=1.11.0" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "=1.11.0" }
|
solana-vote-program = { path = "../programs/vote", version = "=1.11.0" }
|
||||||
spl-token = { version = "=3.3.0", features = ["no-entrypoint"] }
|
spl-token = { version = "=3.3.0", features = ["no-entrypoint"] }
|
||||||
|
spl-token-2022 = { version = "=0.2.0", features = ["no-entrypoint"] }
|
||||||
stream-cancel = "0.8.1"
|
stream-cancel = "0.8.1"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
|
|
@ -13,7 +13,7 @@ use {
|
||||||
account::{AccountSharedData, ReadableAccount},
|
account::{AccountSharedData, ReadableAccount},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
},
|
},
|
||||||
spl_token::{solana_program::program_pack::Pack, state::Mint},
|
spl_token_2022::{extension::StateWithExtensions, state::Mint},
|
||||||
std::{collections::HashMap, sync::Arc},
|
std::{collections::HashMap, sync::Arc},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -91,9 +91,9 @@ pub fn get_mint_owner_and_decimals(bank: &Arc<Bank>, mint: &Pubkey) -> Result<(P
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_mint_decimals(data: &[u8]) -> Result<u8> {
|
fn get_mint_decimals(data: &[u8]) -> Result<u8> {
|
||||||
Mint::unpack(data)
|
StateWithExtensions::<Mint>::unpack(data)
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
Error::invalid_params("Invalid param: Token mint could not be unpacked".to_string())
|
Error::invalid_params("Invalid param: Token mint could not be unpacked".to_string())
|
||||||
})
|
})
|
||||||
.map(|mint| mint.decimals)
|
.map(|mint| mint.base.decimals)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue