From d2dad51b8c540e38e33787173d6e8dcdaa014049 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Mon, 25 Apr 2022 15:25:21 -0400 Subject: [PATCH] Support token-2022 in RPC account parsing (#24619) * Use token-2022 in parsed_token_account * Parse token-2022 accounts --- Cargo.lock | 1 + account-decoder/src/parse_token.rs | 57 +++++++++++++++--------------- programs/bpf/Cargo.lock | 1 + rpc/Cargo.toml | 1 + rpc/src/parsed_token_accounts.rs | 6 ++-- 5 files changed, 35 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5f1b1fb9b..2af143e74 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5514,6 +5514,7 @@ dependencies = [ "solana-version", "solana-vote-program", "spl-token", + "spl-token-2022", "stream-cancel", "symlink", "thiserror", diff --git a/account-decoder/src/parse_token.rs b/account-decoder/src/parse_token.rs index 9368baa7e..2df61bb4e 100644 --- a/account-decoder/src/parse_token.rs +++ b/account-decoder/src/parse_token.rs @@ -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, ) -> Result { - if data.len() == Account::get_packed_len() { - let account = Account::unpack(data) - .map_err(|_| ParseAccountError::AccountNotParsable(ParsableAccount::SplToken))?; + if let Ok(account) = StateWithExtensions::::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::::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 { - 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]); diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index a2c39300b..f8262a2ea 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -4870,6 +4870,7 @@ dependencies = [ "solana-version", "solana-vote-program", "spl-token", + "spl-token-2022", "stream-cancel", "thiserror", "tokio", diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 8012da067..d3f7ac44d 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -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"] } diff --git a/rpc/src/parsed_token_accounts.rs b/rpc/src/parsed_token_accounts.rs index 6ae63d546..06843d1ff 100644 --- a/rpc/src/parsed_token_accounts.rs +++ b/rpc/src/parsed_token_accounts.rs @@ -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, mint: &Pubkey) -> Result<(P } fn get_mint_decimals(data: &[u8]) -> Result { - Mint::unpack(data) + StateWithExtensions::::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) }