Support token-2022 in RPC account parsing (#24619)

* Use token-2022 in parsed_token_account

* Parse token-2022 accounts
This commit is contained in:
Tyera Eulberg 2022-04-25 15:25:21 -04:00 committed by GitHub
parent 674c0d7602
commit d2dad51b8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 31 deletions

1
Cargo.lock generated
View File

@ -5514,6 +5514,7 @@ dependencies = [
"solana-version",
"solana-vote-program",
"spl-token",
"spl-token-2022",
"stream-cancel",
"symlink",
"thiserror",

View File

@ -4,7 +4,9 @@ use {
StringAmount, StringDecimals,
},
solana_sdk::pubkey::Pubkey,
spl_token::{
spl_token_2022::{
extension::StateWithExtensions,
generic_token_account::GenericTokenAccount,
solana_program::{
program_option::COption, program_pack::Pack, pubkey::Pubkey as SplTokenPubkey,
},
@ -60,58 +62,56 @@ pub fn parse_token(
data: &[u8],
mint_decimals: Option<u8>,
) -> Result<TokenAccountType, ParseAccountError> {
if data.len() == Account::get_packed_len() {
let account = Account::unpack(data)
.map_err(|_| ParseAccountError::AccountNotParsable(ParsableAccount::SplToken))?;
if let Ok(account) = StateWithExtensions::<Account>::unpack(data) {
let decimals = mint_decimals.ok_or_else(|| {
ParseAccountError::AdditionalDataMissing(
"no mint_decimals provided to parse spl-token account".to_string(),
)
})?;
Ok(TokenAccountType::Account(UiTokenAccount {
mint: account.mint.to_string(),
owner: account.owner.to_string(),
token_amount: token_amount_to_ui_amount(account.amount, decimals),
delegate: match account.delegate {
return Ok(TokenAccountType::Account(UiTokenAccount {
mint: account.base.mint.to_string(),
owner: account.base.owner.to_string(),
token_amount: token_amount_to_ui_amount(account.base.amount, decimals),
delegate: match account.base.delegate {
COption::Some(pubkey) => Some(pubkey.to_string()),
COption::None => None,
},
state: account.state.into(),
is_native: account.is_native(),
rent_exempt_reserve: match account.is_native {
state: account.base.state.into(),
is_native: account.base.is_native(),
rent_exempt_reserve: match account.base.is_native {
COption::Some(reserve) => Some(token_amount_to_ui_amount(reserve, decimals)),
COption::None => None,
},
delegated_amount: if account.delegate.is_none() {
delegated_amount: if account.base.delegate.is_none() {
None
} else {
Some(token_amount_to_ui_amount(
account.delegated_amount,
account.base.delegated_amount,
decimals,
))
},
close_authority: match account.close_authority {
close_authority: match account.base.close_authority {
COption::Some(pubkey) => Some(pubkey.to_string()),
COption::None => None,
},
}))
} else if data.len() == Mint::get_packed_len() {
let mint = Mint::unpack(data)
.map_err(|_| ParseAccountError::AccountNotParsable(ParsableAccount::SplToken))?;
Ok(TokenAccountType::Mint(UiMint {
mint_authority: match mint.mint_authority {
}));
}
if let Ok(mint) = StateWithExtensions::<Mint>::unpack(data) {
return Ok(TokenAccountType::Mint(UiMint {
mint_authority: match mint.base.mint_authority {
COption::Some(pubkey) => Some(pubkey.to_string()),
COption::None => None,
},
supply: mint.supply.to_string(),
decimals: mint.decimals,
is_initialized: mint.is_initialized,
freeze_authority: match mint.freeze_authority {
supply: mint.base.supply.to_string(),
decimals: mint.base.decimals,
is_initialized: mint.base.is_initialized,
freeze_authority: match mint.base.freeze_authority {
COption::Some(pubkey) => Some(pubkey.to_string()),
COption::None => None,
},
}))
} else if data.len() == Multisig::get_packed_len() {
}));
}
if data.len() == Multisig::get_packed_len() {
let multisig = Multisig::unpack(data)
.map_err(|_| ParseAccountError::AccountNotParsable(ParsableAccount::SplToken))?;
Ok(TokenAccountType::Multisig(UiMultisig {
@ -265,7 +265,7 @@ pub struct UiMultisig {
}
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]))
} else {
None
@ -370,6 +370,7 @@ mod test {
let mut account_data = vec![0; Account::get_packed_len()];
let mut account = Account::unpack_unchecked(&account_data).unwrap();
account.mint = mint_pubkey;
account.state = AccountState::Initialized;
Account::pack(account, &mut account_data).unwrap();
let expected_mint_pubkey = Pubkey::new(&[2; 32]);

View File

@ -4870,6 +4870,7 @@ dependencies = [
"solana-version",
"solana-vote-program",
"spl-token",
"spl-token-2022",
"stream-cancel",
"thiserror",
"tokio",

View File

@ -49,6 +49,7 @@ solana-transaction-status = { path = "../transaction-status", version = "=1.11.0
solana-version = { path = "../version", 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-2022 = { version = "=0.2.0", features = ["no-entrypoint"] }
stream-cancel = "0.8.1"
thiserror = "1.0"
tokio = { version = "1", features = ["full"] }

View File

@ -13,7 +13,7 @@ use {
account::{AccountSharedData, ReadableAccount},
pubkey::Pubkey,
},
spl_token::{solana_program::program_pack::Pack, state::Mint},
spl_token_2022::{extension::StateWithExtensions, state::Mint},
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> {
Mint::unpack(data)
StateWithExtensions::<Mint>::unpack(data)
.map_err(|_| {
Error::invalid_params("Invalid param: Token mint could not be unpacked".to_string())
})
.map(|mint| mint.decimals)
.map(|mint| mint.base.decimals)
}