diff --git a/Cargo.lock b/Cargo.lock index e25287cf4e..ca6b751e06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -403,24 +403,6 @@ dependencies = [ "rustc_version", ] -[[package]] -name = "cbindgen" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "104ca409bbff8293739438c71820a2606111b5f8f81835536dc673dfd807369e" -dependencies = [ - "clap", - "heck", - "log 0.4.8", - "proc-macro2 1.0.19", - "quote 1.0.6", - "serde", - "serde_json", - "syn 1.0.27", - "tempfile", - "toml", -] - [[package]] name = "cc" version = "1.0.49" @@ -1259,15 +1241,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "heck" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "hermit-abi" version = "0.1.13" @@ -2109,6 +2082,28 @@ dependencies = [ "libc", ] +[[package]] +name = "num_enum" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "226b45a5c2ac4dd696ed30fa6b94b057ad909c7b7fc2e0d0808192bced894066" +dependencies = [ + "derivative", + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c0fd9eba1d5db0994a239e09c1be402d35622277e35468ba891aa5e3188ce7e" +dependencies = [ + "proc-macro-crate", + "proc-macro2 1.0.19", + "quote 1.0.6", + "syn 1.0.27", +] + [[package]] name = "number_prefix" version = "0.3.0" @@ -3562,7 +3557,7 @@ dependencies = [ "solana-rayon-threadlimit", "solana-runtime", "solana-sdk 1.3.6", - "solana-sdk-macro-frozen-abi", + "solana-sdk-macro-frozen-abi 1.3.6", "solana-stake-program", "solana-storage-bigtable", "solana-streamer", @@ -3584,9 +3579,9 @@ dependencies = [ [[package]] name = "solana-crate-features" -version = "1.2.17" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "610ba71932d0bf4abf88eabb081ee43fa1ee6bb5137c4fa6776ea9dd8630ca5c" +checksum = "3e93b888ccc34b2c7a7fa3e1c804ce5f1a4b521d09b8779de3a80e70e3be2f82" dependencies = [ "backtrace", "bytes 0.4.12", @@ -3927,9 +3922,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.2.17" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc703cb2807e9d713f70df32ac8c3a7a9c8af437dd0d468b1b77cfd8e8b4cbc8" +checksum = "7c8d27af0c30536bf91abbf40db5133e905bfd61ed24b8096c6e0a5cfb92c1e6" dependencies = [ "env_logger", "lazy_static", @@ -4165,7 +4160,7 @@ dependencies = [ "solana-noop-program", "solana-rayon-threadlimit", "solana-sdk 1.3.6", - "solana-sdk-macro-frozen-abi", + "solana-sdk-macro-frozen-abi 1.3.6", "solana-stake-program", "solana-vote-program", "symlink", @@ -4185,9 +4180,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.2.17" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a556c1b456609b760ff47b933912f27563ea8a9a1692864cbc1014c02f5b981e" +checksum = "15ca11bc0623ec67bb2dfbf5eff025c67c099f0ac808e192a12210a317417b9b" dependencies = [ "assert_matches", "bincode", @@ -4195,6 +4190,7 @@ dependencies = [ "bv", "byteorder", "chrono", + "curve25519-dalek", "ed25519-dalek", "generic-array 0.14.3", "hex", @@ -4214,9 +4210,10 @@ dependencies = [ "serde_derive", "serde_json", "sha2", - "solana-crate-features 1.2.17", - "solana-logger 1.2.17", - "solana-sdk-macro 1.2.17", + "solana-crate-features 1.3.4", + "solana-logger 1.3.4", + "solana-sdk-macro 1.3.4", + "solana-sdk-macro-frozen-abi 1.3.5", "thiserror", ] @@ -4253,16 +4250,16 @@ dependencies = [ "solana-crate-features 1.3.6", "solana-logger 1.3.6", "solana-sdk-macro 1.3.6", - "solana-sdk-macro-frozen-abi", + "solana-sdk-macro-frozen-abi 1.3.6", "thiserror", "tiny-bip39", ] [[package]] name = "solana-sdk-macro" -version = "1.2.17" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc386020de692562a29c0696a71c14a3d94455a9a785a97c7b254c38d6a2c8" +checksum = "d5ef3b2acbb22a28edc32e36ed5d3b0c902007befe51f28f46c3e78a825acf71" dependencies = [ "bs58", "proc-macro2 1.0.19", @@ -4282,6 +4279,19 @@ dependencies = [ "syn 1.0.27", ] +[[package]] +name = "solana-sdk-macro-frozen-abi" +version = "1.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9b012fab0634311c8b6176ee1d6874a39f7b0bad8b647fe2cf36f687151728" +dependencies = [ + "lazy_static", + "proc-macro2 1.0.19", + "quote 1.0.6", + "rustc_version", + "syn 1.0.27", +] + [[package]] name = "solana-sdk-macro-frozen-abi" version = "1.3.6" @@ -4366,7 +4376,7 @@ dependencies = [ "solana-logger 1.3.6", "solana-metrics", "solana-sdk 1.3.6", - "solana-sdk-macro-frozen-abi", + "solana-sdk-macro-frozen-abi 1.3.6", "solana-vote-program", "thiserror", ] @@ -4520,7 +4530,7 @@ dependencies = [ "serde_derive", "solana-logger 1.3.6", "solana-sdk 1.3.6", - "solana-sdk-macro-frozen-abi", + "solana-sdk-macro-frozen-abi 1.3.6", ] [[package]] @@ -4553,7 +4563,7 @@ dependencies = [ "solana-logger 1.3.6", "solana-metrics", "solana-sdk 1.3.6", - "solana-sdk-macro-frozen-abi", + "solana-sdk-macro-frozen-abi 1.3.6", "thiserror", ] @@ -4623,20 +4633,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b303bab17e0c696de6d7550ba6f05a5a6dbf5c5d1597e68a4592899072e1c07a" dependencies = [ - "solana-sdk 1.2.17", + "solana-sdk 1.3.4", ] [[package]] name = "spl-token" -version = "1.0.8" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8bee8b59279b46d0627490b544c3bc38e440ff4da9851a34a26ab0a24bfe7d" +checksum = "89ee48031d5b189a9da7295076ba07bf0ccd407e0fee1279281fb2c3258fa9fb" dependencies = [ - "cbindgen", + "arrayref", "num-derive 0.3.0", "num-traits", + "num_enum", "remove_dir_all", - "solana-sdk 1.2.17", + "solana-sdk 1.3.4", "thiserror", ] @@ -5665,12 +5676,6 @@ dependencies = [ "smallvec 1.4.0", ] -[[package]] -name = "unicode-segmentation" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" - [[package]] name = "unicode-width" version = "0.1.7" diff --git a/account-decoder/Cargo.toml b/account-decoder/Cargo.toml index c23d096d7d..1aeacb82db 100644 --- a/account-decoder/Cargo.toml +++ b/account-decoder/Cargo.toml @@ -22,7 +22,7 @@ solana-config-program = { path = "../programs/config", version = "1.3.6" } solana-sdk = { path = "../sdk", version = "1.3.6" } solana-stake-program = { path = "../programs/stake", version = "1.3.6" } solana-vote-program = { path = "../programs/vote", version = "1.3.6" } -spl-token-v1-0 = { package = "spl-token", version = "1.0.8", features = ["skip-no-mangle"] } +spl-token-v2-0 = { package = "spl-token", version = "2.0.1", features = ["skip-no-mangle"] } thiserror = "1.0" [package.metadata.docs.rs] diff --git a/account-decoder/src/parse_account_data.rs b/account-decoder/src/parse_account_data.rs index 8f92cda547..a9f4aedf99 100644 --- a/account-decoder/src/parse_account_data.rs +++ b/account-decoder/src/parse_account_data.rs @@ -3,7 +3,7 @@ use crate::{ parse_nonce::parse_nonce, parse_stake::parse_stake, parse_sysvar::parse_sysvar, - parse_token::{parse_token, spl_token_id_v1_0}, + parse_token::{parse_token, spl_token_id_v2_0}, parse_vote::parse_vote, }; use inflector::Inflector; @@ -17,7 +17,7 @@ lazy_static! { static ref STAKE_PROGRAM_ID: Pubkey = solana_stake_program::id(); static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id(); static ref SYSVAR_PROGRAM_ID: Pubkey = sysvar::id(); - static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v1_0(); + static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0(); static ref VOTE_PROGRAM_ID: Pubkey = solana_vote_program::id(); pub static ref PARSABLE_PROGRAM_IDS: HashMap = { let mut m = HashMap::new(); diff --git a/account-decoder/src/parse_token.rs b/account-decoder/src/parse_token.rs index 459846835d..e3f890470d 100644 --- a/account-decoder/src/parse_token.rs +++ b/account-decoder/src/parse_token.rs @@ -3,32 +3,32 @@ use crate::{ StringAmount, }; use solana_sdk::pubkey::Pubkey; -use spl_token_v1_0::{ +use spl_token_v2_0::{ option::COption, + pack::Pack, solana_sdk::pubkey::Pubkey as SplTokenPubkey, - state::{unpack, Account, Mint, Multisig}, + state::{Account, AccountState, Mint, Multisig}, }; use std::{mem::size_of, str::FromStr}; -// A helper function to convert spl_token_v1_0::id() as spl_sdk::pubkey::Pubkey to +// A helper function to convert spl_token_v2_0::id() as spl_sdk::pubkey::Pubkey to // solana_sdk::pubkey::Pubkey -pub fn spl_token_id_v1_0() -> Pubkey { - Pubkey::from_str(&spl_token_v1_0::id().to_string()).unwrap() +pub fn spl_token_id_v2_0() -> Pubkey { + Pubkey::from_str(&spl_token_v2_0::id().to_string()).unwrap() } -// A helper function to convert spl_token_v1_0::native_mint::id() as spl_sdk::pubkey::Pubkey to +// A helper function to convert spl_token_v2_0::native_mint::id() as spl_sdk::pubkey::Pubkey to // solana_sdk::pubkey::Pubkey -pub fn spl_token_v1_0_native_mint() -> Pubkey { - Pubkey::from_str(&spl_token_v1_0::native_mint::id().to_string()).unwrap() +pub fn spl_token_v2_0_native_mint() -> Pubkey { + Pubkey::from_str(&spl_token_v2_0::native_mint::id().to_string()).unwrap() } pub fn parse_token( data: &[u8], mint_decimals: Option, ) -> Result { - let mut data = data.to_vec(); if data.len() == size_of::() { - let account: Account = *unpack(&mut data) + let account = Account::unpack(data) .map_err(|_| ParseAccountError::AccountNotParsable(ParsableAccount::SplToken))?; let decimals = mint_decimals.ok_or_else(|| { ParseAccountError::AdditionalDataMissing( @@ -43,8 +43,12 @@ pub fn parse_token( COption::Some(pubkey) => Some(pubkey.to_string()), COption::None => None, }, - is_initialized: account.is_initialized, - is_native: account.is_native, + state: account.state.into(), + is_native: account.is_native(), + rent_exempt_reserve: match account.is_native { + COption::Some(reserve) => Some(token_amount_to_ui_amount(reserve, decimals)), + COption::None => None, + }, delegated_amount: if account.delegate.is_none() { None } else { @@ -53,20 +57,29 @@ pub fn parse_token( decimals, )) }, - })) - } else if data.len() == size_of::() { - let mint: Mint = *unpack(&mut data) - .map_err(|_| ParseAccountError::AccountNotParsable(ParsableAccount::SplToken))?; - Ok(TokenAccountType::Mint(UiMint { - owner: match mint.owner { + close_authority: match account.close_authority { COption::Some(pubkey) => Some(pubkey.to_string()), COption::None => None, }, + })) + } else if data.len() == size_of::() { + let mint = Mint::unpack(data) + .map_err(|_| ParseAccountError::AccountNotParsable(ParsableAccount::SplToken))?; + Ok(TokenAccountType::Mint(UiMint { + mint_authority: match mint.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 { + COption::Some(pubkey) => Some(pubkey.to_string()), + COption::None => None, + }, })) } else if data.len() == size_of::() { - let multisig: Multisig = *unpack(&mut data) + let multisig = Multisig::unpack(data) .map_err(|_| ParseAccountError::AccountNotParsable(ParsableAccount::SplToken))?; Ok(TokenAccountType::Multisig(UiMultisig { num_required_signers: multisig.m, @@ -107,10 +120,32 @@ pub struct UiTokenAccount { pub token_amount: UiTokenAmount, #[serde(skip_serializing_if = "Option::is_none")] pub delegate: Option, - pub is_initialized: bool, + pub state: UiAccountState, pub is_native: bool, #[serde(skip_serializing_if = "Option::is_none")] + pub rent_exempt_reserve: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub delegated_amount: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub close_authority: Option, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub enum UiAccountState { + Uninitialized, + Initialized, + Frozen, +} + +impl From for UiAccountState { + fn from(state: AccountState) -> Self { + match state { + AccountState::Uninitialized => UiAccountState::Uninitialized, + AccountState::Initialized => UiAccountState::Initialized, + AccountState::Frozen => UiAccountState::Frozen, + } + } } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] @@ -134,9 +169,11 @@ pub fn token_amount_to_ui_amount(amount: u64, decimals: u8) -> UiTokenAmount { #[derive(Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct UiMint { - pub owner: Option, + pub mint_authority: Option, + pub supply: StringAmount, pub decimals: u8, pub is_initialized: bool, + pub freeze_authority: Option, } #[derive(Debug, Serialize, Deserialize, PartialEq)] @@ -159,18 +196,23 @@ pub fn get_token_account_mint(data: &[u8]) -> Option { #[cfg(test)] mod test { use super::*; - use spl_token_v1_0::state::unpack_unchecked; #[test] fn test_parse_token() { let mint_pubkey = SplTokenPubkey::new(&[2; 32]); let owner_pubkey = SplTokenPubkey::new(&[3; 32]); let mut account_data = [0; size_of::()]; - let mut account: &mut Account = unpack_unchecked(&mut account_data).unwrap(); - account.mint = mint_pubkey; - account.owner = owner_pubkey; - account.amount = 42; - account.is_initialized = true; + Account::unpack_unchecked_mut(&mut account_data, &mut |account: &mut Account| { + account.mint = mint_pubkey; + account.owner = owner_pubkey; + account.amount = 42; + account.state = AccountState::Initialized; + account.is_native = COption::None; + account.close_authority = COption::Some(owner_pubkey); + Ok(()) + }) + .unwrap(); + assert!(parse_token(&account_data, None).is_err()); assert_eq!( parse_token(&account_data, Some(2)).unwrap(), @@ -183,23 +225,33 @@ mod test { amount: "42".to_string() }, delegate: None, - is_initialized: true, + state: UiAccountState::Initialized, is_native: false, + rent_exempt_reserve: None, delegated_amount: None, + close_authority: Some(owner_pubkey.to_string()), }), ); let mut mint_data = [0; size_of::()]; - let mut mint: &mut Mint = unpack_unchecked(&mut mint_data).unwrap(); - mint.owner = COption::Some(owner_pubkey); - mint.decimals = 3; - mint.is_initialized = true; + Mint::unpack_unchecked_mut(&mut mint_data, &mut |mint: &mut Mint| { + mint.mint_authority = COption::Some(owner_pubkey); + mint.supply = 42; + mint.decimals = 3; + mint.is_initialized = true; + mint.freeze_authority = COption::Some(owner_pubkey); + Ok(()) + }) + .unwrap(); + assert_eq!( parse_token(&mint_data, None).unwrap(), TokenAccountType::Mint(UiMint { - owner: Some(owner_pubkey.to_string()), + mint_authority: Some(owner_pubkey.to_string()), + supply: 42.to_string(), decimals: 3, is_initialized: true, + freeze_authority: Some(owner_pubkey.to_string()), }), ); @@ -207,15 +259,18 @@ mod test { let signer2 = SplTokenPubkey::new(&[2; 32]); let signer3 = SplTokenPubkey::new(&[3; 32]); let mut multisig_data = [0; size_of::()]; - let mut multisig: &mut Multisig = unpack_unchecked(&mut multisig_data).unwrap(); let mut signers = [SplTokenPubkey::default(); 11]; signers[0] = signer1; signers[1] = signer2; signers[2] = signer3; - multisig.m = 2; - multisig.n = 3; - multisig.is_initialized = true; - multisig.signers = signers; + Multisig::unpack_unchecked_mut(&mut multisig_data, &mut |multisig: &mut Multisig| { + multisig.m = 2; + multisig.n = 3; + multisig.is_initialized = true; + multisig.signers = signers; + Ok(()) + }) + .unwrap(); assert_eq!( parse_token(&multisig_data, None).unwrap(), TokenAccountType::Multisig(UiMultisig { @@ -238,8 +293,11 @@ mod test { fn test_get_token_account_mint() { let mint_pubkey = SplTokenPubkey::new(&[2; 32]); let mut account_data = [0; size_of::()]; - let mut account: &mut Account = unpack_unchecked(&mut account_data).unwrap(); - account.mint = mint_pubkey; + Account::unpack_unchecked_mut(&mut account_data, &mut |account: &mut Account| { + account.mint = mint_pubkey; + Ok(()) + }) + .unwrap(); let expected_mint_pubkey = Pubkey::new(&[2; 32]); assert_eq!( diff --git a/core/Cargo.toml b/core/Cargo.toml index af5c2c1b7b..799d0dfa65 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -69,7 +69,7 @@ solana-transaction-status = { path = "../transaction-status", version = "1.3.6" solana-version = { path = "../version", version = "1.3.6" } solana-vote-program = { path = "../programs/vote", version = "1.3.6" } solana-vote-signer = { path = "../vote-signer", version = "1.3.6" } -spl-token-v1-0 = { package = "spl-token", version = "1.0.8", features = ["skip-no-mangle"] } +spl-token-v2-0 = { package = "spl-token", version = "2.0.1", features = ["skip-no-mangle"] } tempfile = "3.1.0" thiserror = "1.0" tokio_01 = { version = "0.1", package = "tokio" } diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 637e72e58e..7081c54b48 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -11,7 +11,7 @@ use jsonrpc_derive::rpc; use solana_account_decoder::{ parse_account_data::AccountAdditionalData, parse_token::{ - get_token_account_mint, spl_token_id_v1_0, spl_token_v1_0_native_mint, + get_token_account_mint, spl_token_id_v2_0, spl_token_v2_0_native_mint, token_amount_to_ui_amount, UiTokenAmount, }, UiAccount, UiAccountEncoding, @@ -58,7 +58,10 @@ use solana_transaction_status::{ ConfirmedBlock, ConfirmedTransaction, TransactionStatus, UiTransactionEncoding, }; use solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY}; -use spl_token_v1_0::state::{Account as TokenAccount, Mint}; +use spl_token_v2_0::{ + pack::Pack, + state::{Account as TokenAccount, Mint}, +}; use std::{ cmp::{max, min}, collections::{HashMap, HashSet}, @@ -247,7 +250,7 @@ impl JsonRpcRequestProcessor { check_slice_and_encoding(&encoding, config.data_slice.is_some())?; let mut response = None; if let Some(account) = bank.get_account(pubkey) { - if account.owner == spl_token_id_v1_0() && encoding == UiAccountEncoding::JsonParsed { + if account.owner == spl_token_id_v2_0() && encoding == UiAccountEncoding::JsonParsed { response = Some(get_parsed_token_account(bank.clone(), pubkey, account)); } else if (encoding == UiAccountEncoding::Binary || encoding == UiAccountEncoding::Base58) @@ -295,7 +298,7 @@ impl JsonRpcRequestProcessor { check_slice_and_encoding(&encoding, data_slice_config.is_some())?; let keyed_accounts = get_filtered_program_accounts(&bank, program_id, filters); let result = - if program_id == &spl_token_id_v1_0() && encoding == UiAccountEncoding::JsonParsed { + if program_id == &spl_token_id_v2_0() && encoding == UiAccountEncoding::JsonParsed { get_parsed_token_accounts(bank, keyed_accounts).collect() } else { keyed_accounts @@ -1025,16 +1028,14 @@ impl JsonRpcRequestProcessor { Error::invalid_params("Invalid param: could not find account".to_string()) })?; - if account.owner != spl_token_id_v1_0() { + if account.owner != spl_token_id_v2_0() { return Err(Error::invalid_params( - "Invalid param: not a v1.0 Token account".to_string(), + "Invalid param: not a v2.0 Token account".to_string(), )); } - let mut data = account.data.to_vec(); - let token_account = - spl_token_v1_0::state::unpack::(&mut data).map_err(|_| { - Error::invalid_params("Invalid param: not a v1.0 Token account".to_string()) - })?; + let token_account = TokenAccount::unpack(&account.data).map_err(|_| { + Error::invalid_params("Invalid param: not a v2.0 Token account".to_string()) + })?; let mint = &Pubkey::from_str(&token_account.mint.to_string()) .expect("Token account mint should be convertible to Pubkey"); let (_, decimals) = get_mint_owner_and_decimals(&bank, &mint)?; @@ -1048,32 +1049,19 @@ impl JsonRpcRequestProcessor { commitment: Option, ) -> Result> { let bank = self.bank(commitment); - let (mint_owner, decimals) = get_mint_owner_and_decimals(&bank, mint)?; - if mint_owner != spl_token_id_v1_0() { + let mint_account = bank.get_account(mint).ok_or_else(|| { + Error::invalid_params("Invalid param: could not find account".to_string()) + })?; + if mint_account.owner != spl_token_id_v2_0() { return Err(Error::invalid_params( - "Invalid param: not a v1.0 Token mint".to_string(), + "Invalid param: not a v2.0 Token mint".to_string(), )); } + let mint = Mint::unpack(&mint_account.data).map_err(|_| { + Error::invalid_params("Invalid param: mint could not be unpacked".to_string()) + })?; - let filters = vec![ - // Filter on Mint address - RpcFilterType::Memcmp(Memcmp { - offset: 0, - bytes: MemcmpEncodedBytes::Binary(mint.to_string()), - encoding: None, - }), - // Filter on Token Account state - RpcFilterType::DataSize(size_of::() as u64), - ]; - let supply = get_filtered_program_accounts(&bank, &mint_owner, filters) - .map(|(_pubkey, account)| { - let mut data = account.data.to_vec(); - spl_token_v1_0::state::unpack(&mut data) - .map(|account: &mut TokenAccount| account.amount) - .unwrap_or(0) - }) - .sum(); - let supply = token_amount_to_ui_amount(supply, decimals); + let supply = token_amount_to_ui_amount(mint.supply, mint.decimals); Ok(new_response(&bank, supply)) } @@ -1084,9 +1072,9 @@ impl JsonRpcRequestProcessor { ) -> Result>> { let bank = self.bank(commitment); let (mint_owner, decimals) = get_mint_owner_and_decimals(&bank, mint)?; - if mint_owner != spl_token_id_v1_0() { + if mint_owner != spl_token_id_v2_0() { return Err(Error::invalid_params( - "Invalid param: not a v1.0 Token mint".to_string(), + "Invalid param: not a v2.0 Token mint".to_string(), )); } let filters = vec![ @@ -1102,9 +1090,8 @@ impl JsonRpcRequestProcessor { let mut token_balances: Vec = get_filtered_program_accounts(&bank, &mint_owner, filters) .map(|(address, account)| { - let mut data = account.data.to_vec(); - let amount = spl_token_v1_0::state::unpack(&mut data) - .map(|account: &mut TokenAccount| account.amount) + let amount = TokenAccount::unpack(&account.data) + .map(|account| account.amount) .unwrap_or(0); let amount = token_amount_to_ui_amount(amount, decimals); RpcTokenAccountBalance { @@ -1368,15 +1355,15 @@ fn get_token_program_id_and_mint( match token_account_filter { TokenAccountsFilter::Mint(mint) => { let (mint_owner, _) = get_mint_owner_and_decimals(&bank, &mint)?; - if mint_owner != spl_token_id_v1_0() { + if mint_owner != spl_token_id_v2_0() { return Err(Error::invalid_params( - "Invalid param: not a v1.0 Token mint".to_string(), + "Invalid param: not a v2.0 Token mint".to_string(), )); } Ok((mint_owner, Some(mint))) } TokenAccountsFilter::ProgramId(program_id) => { - if program_id == spl_token_id_v1_0() { + if program_id == spl_token_id_v2_0() { Ok((program_id, None)) } else { Err(Error::invalid_params( @@ -1390,8 +1377,8 @@ fn get_token_program_id_and_mint( /// Analyze a mint Pubkey that may be the native_mint and get the mint-account owner (token /// program_id) and decimals fn get_mint_owner_and_decimals(bank: &Arc, mint: &Pubkey) -> Result<(Pubkey, u8)> { - if mint == &spl_token_v1_0_native_mint() { - Ok((spl_token_id_v1_0(), spl_token_v1_0::native_mint::DECIMALS)) + if mint == &spl_token_v2_0_native_mint() { + Ok((spl_token_id_v2_0(), spl_token_v2_0::native_mint::DECIMALS)) } else { let mint_account = bank.get_account(mint).ok_or_else(|| { Error::invalid_params("Invalid param: could not find mint".to_string()) @@ -1402,12 +1389,11 @@ fn get_mint_owner_and_decimals(bank: &Arc, mint: &Pubkey) -> Result<(Pubke } fn get_mint_decimals(data: &[u8]) -> Result { - let mut data = data.to_vec(); - spl_token_v1_0::state::unpack(&mut data) + Mint::unpack(data) .map_err(|_| { Error::invalid_params("Invalid param: Token mint could not be unpacked".to_string()) }) - .map(|mint: &mut Mint| mint.decimals) + .map(|mint| mint.decimals) } #[rpc] @@ -1692,7 +1678,7 @@ pub trait RpcSol { ) -> Result; // SPL Token-specific RPC endpoints - // See https://github.com/solana-labs/solana-program-library/releases/tag/token-v1.0.0 for + // See https://github.com/solana-labs/solana-program-library/releases/tag/token-v2.0.0 for // program details #[rpc(meta, name = "getTokenAccountBalance")] @@ -2505,8 +2491,9 @@ pub mod tests { vote_instruction, vote_state::{Vote, VoteInit, MAX_LOCKOUT_HISTORY}, }; - use spl_token_v1_0::{ - option::COption, solana_sdk::pubkey::Pubkey as SplTokenPubkey, state::Mint, + use spl_token_v2_0::{ + option::COption, solana_sdk::pubkey::Pubkey as SplTokenPubkey, + state::AccountState as TokenAccountState, state::Mint, }; use std::collections::HashMap; @@ -4762,24 +4749,27 @@ pub mod tests { let RpcHandler { io, meta, bank, .. } = start_rpc_handler_with_tx(&Pubkey::new_rand()); let mut account_data = [0; size_of::()]; - let account: &mut TokenAccount = - spl_token_v1_0::state::unpack_unchecked(&mut account_data).unwrap(); let mint = SplTokenPubkey::new(&[2; 32]); let owner = SplTokenPubkey::new(&[3; 32]); let delegate = SplTokenPubkey::new(&[4; 32]); - *account = TokenAccount { - mint, - owner, - delegate: COption::Some(delegate), - amount: 420, - is_initialized: true, - is_native: false, - delegated_amount: 30, - }; + TokenAccount::unpack_unchecked_mut(&mut account_data, &mut |account: &mut TokenAccount| { + *account = TokenAccount { + mint, + owner, + delegate: COption::Some(delegate), + amount: 420, + state: TokenAccountState::Initialized, + is_native: COption::None, + delegated_amount: 30, + close_authority: COption::Some(owner), + }; + Ok(()) + }) + .unwrap(); let token_account = Account { lamports: 111, data: account_data.to_vec(), - owner: spl_token_id_v1_0(), + owner: spl_token_id_v2_0(), ..Account::default() }; let token_account_pubkey = Pubkey::new_rand(); @@ -4787,17 +4777,21 @@ pub mod tests { // Add the mint let mut mint_data = [0; size_of::()]; - let mint_state: &mut Mint = - spl_token_v1_0::state::unpack_unchecked(&mut mint_data).unwrap(); - *mint_state = Mint { - owner: COption::Some(owner), - decimals: 2, - is_initialized: true, - }; + Mint::unpack_unchecked_mut(&mut mint_data, &mut |mint: &mut Mint| { + *mint = Mint { + mint_authority: COption::Some(owner), + supply: 500, + decimals: 2, + is_initialized: true, + freeze_authority: COption::Some(owner), + }; + Ok(()) + }) + .unwrap(); let mint_account = Account { lamports: 111, data: mint_data.to_vec(), - owner: spl_token_id_v1_0(), + owner: spl_token_id_v2_0(), ..Account::default() }; bank.store_account(&Pubkey::from_str(&mint.to_string()).unwrap(), &mint_account); @@ -4826,10 +4820,7 @@ pub mod tests { .expect("actual response deserialization"); assert!(result.get("error").is_some()); - // Add another token account to ensure getTokenSupply sums all mint accounts - let other_token_account_pubkey = Pubkey::new_rand(); - bank.store_account(&other_token_account_pubkey, &token_account); - + // Test get token supply, pulls supply from mint let req = format!( r#"{{"jsonrpc":"2.0","id":1,"method":"getTokenSupply","params":["{}"]}}"#, mint, @@ -4840,8 +4831,8 @@ pub mod tests { let supply: UiTokenAmount = serde_json::from_value(result["result"]["value"].clone()).unwrap(); let error = f64::EPSILON; - assert!((supply.ui_amount - 2.0 * 4.2).abs() < error); - assert_eq!(supply.amount, (2 * 420).to_string()); + assert!((supply.ui_amount - 5.0).abs() < error); + assert_eq!(supply.amount, 500.to_string()); assert_eq!(supply.decimals, 2); // Test non-existent mint address @@ -4854,24 +4845,31 @@ pub mod tests { .expect("actual response deserialization"); assert!(result.get("error").is_some()); + // Add another token account with the same owner, delegate, and mint + let other_token_account_pubkey = Pubkey::new_rand(); + bank.store_account(&other_token_account_pubkey, &token_account); + // Add another token account with the same owner and delegate but different mint let mut account_data = [0; size_of::()]; - let account: &mut TokenAccount = - spl_token_v1_0::state::unpack_unchecked(&mut account_data).unwrap(); let new_mint = SplTokenPubkey::new(&[5; 32]); - *account = TokenAccount { - mint: new_mint, - owner, - delegate: COption::Some(delegate), - amount: 42, - is_initialized: true, - is_native: false, - delegated_amount: 30, - }; + TokenAccount::unpack_unchecked_mut(&mut account_data, &mut |account: &mut TokenAccount| { + *account = TokenAccount { + mint: new_mint, + owner, + delegate: COption::Some(delegate), + amount: 42, + state: TokenAccountState::Initialized, + is_native: COption::None, + delegated_amount: 30, + close_authority: COption::Some(owner), + }; + Ok(()) + }) + .unwrap(); let token_account = Account { lamports: 111, data: account_data.to_vec(), - owner: spl_token_id_v1_0(), + owner: spl_token_id_v2_0(), ..Account::default() }; let token_with_different_mint_pubkey = Pubkey::new_rand(); @@ -4886,7 +4884,7 @@ pub mod tests { "params":["{}", {{"programId": "{}"}}] }}"#, owner, - spl_token_id_v1_0(), + spl_token_id_v2_0(), ); let res = io.handle_request_sync(&req, meta.clone()); let result: Value = serde_json::from_str(&res.expect("actual response")) @@ -4904,7 +4902,7 @@ pub mod tests { "params":["{}", {{"programId": "{}"}}, {{"encoding": "jsonParsed"}}] }}"#, owner, - spl_token_id_v1_0(), + spl_token_id_v2_0(), ); let res = io.handle_request_sync(&req, meta.clone()); let result: Value = serde_json::from_str(&res.expect("actual response")) @@ -4968,7 +4966,7 @@ pub mod tests { "params":["{}", {{"programId": "{}"}}] }}"#, Pubkey::new_rand(), - spl_token_id_v1_0(), + spl_token_id_v2_0(), ); let res = io.handle_request_sync(&req, meta.clone()); let result: Value = serde_json::from_str(&res.expect("actual response")) @@ -4986,7 +4984,7 @@ pub mod tests { "params":["{}", {{"programId": "{}"}}] }}"#, delegate, - spl_token_id_v1_0(), + spl_token_id_v2_0(), ); let res = io.handle_request_sync(&req, meta.clone()); let result: Value = serde_json::from_str(&res.expect("actual response")) @@ -5051,7 +5049,7 @@ pub mod tests { "params":["{}", {{"programId": "{}"}}] }}"#, Pubkey::new_rand(), - spl_token_id_v1_0(), + spl_token_id_v2_0(), ); let res = io.handle_request_sync(&req, meta.clone()); let result: Value = serde_json::from_str(&res.expect("actual response")) @@ -5062,17 +5060,21 @@ pub mod tests { // Add new_mint, and another token account on new_mint with different balance let mut mint_data = [0; size_of::()]; - let mint_state: &mut Mint = - spl_token_v1_0::state::unpack_unchecked(&mut mint_data).unwrap(); - *mint_state = Mint { - owner: COption::Some(owner), - decimals: 2, - is_initialized: true, - }; + Mint::unpack_unchecked_mut(&mut mint_data, &mut |mint: &mut Mint| { + *mint = Mint { + mint_authority: COption::Some(owner), + supply: 500, + decimals: 2, + is_initialized: true, + freeze_authority: COption::Some(owner), + }; + Ok(()) + }) + .unwrap(); let mint_account = Account { lamports: 111, data: mint_data.to_vec(), - owner: spl_token_id_v1_0(), + owner: spl_token_id_v2_0(), ..Account::default() }; bank.store_account( @@ -5080,21 +5082,24 @@ pub mod tests { &mint_account, ); let mut account_data = [0; size_of::()]; - let account: &mut TokenAccount = - spl_token_v1_0::state::unpack_unchecked(&mut account_data).unwrap(); - *account = TokenAccount { - mint: new_mint, - owner, - delegate: COption::Some(delegate), - amount: 10, - is_initialized: true, - is_native: false, - delegated_amount: 30, - }; + TokenAccount::unpack_unchecked_mut(&mut account_data, &mut |account: &mut TokenAccount| { + *account = TokenAccount { + mint: new_mint, + owner, + delegate: COption::Some(delegate), + amount: 10, + state: TokenAccountState::Initialized, + is_native: COption::None, + delegated_amount: 30, + close_authority: COption::Some(owner), + }; + Ok(()) + }) + .unwrap(); let token_account = Account { lamports: 111, data: account_data.to_vec(), - owner: spl_token_id_v1_0(), + owner: spl_token_id_v2_0(), ..Account::default() }; let token_with_smaller_balance = Pubkey::new_rand(); @@ -5138,24 +5143,27 @@ pub mod tests { let RpcHandler { io, meta, bank, .. } = start_rpc_handler_with_tx(&Pubkey::new_rand()); let mut account_data = [0; size_of::()]; - let account: &mut TokenAccount = - spl_token_v1_0::state::unpack_unchecked(&mut account_data).unwrap(); let mint = SplTokenPubkey::new(&[2; 32]); let owner = SplTokenPubkey::new(&[3; 32]); let delegate = SplTokenPubkey::new(&[4; 32]); - *account = TokenAccount { - mint, - owner, - delegate: COption::Some(delegate), - amount: 420, - is_initialized: true, - is_native: false, - delegated_amount: 30, - }; + TokenAccount::unpack_unchecked_mut(&mut account_data, &mut |account: &mut TokenAccount| { + *account = TokenAccount { + mint, + owner, + delegate: COption::Some(delegate), + amount: 420, + state: TokenAccountState::Initialized, + is_native: COption::Some(10), + delegated_amount: 30, + close_authority: COption::Some(owner), + }; + Ok(()) + }) + .unwrap(); let token_account = Account { lamports: 111, data: account_data.to_vec(), - owner: spl_token_id_v1_0(), + owner: spl_token_id_v2_0(), ..Account::default() }; let token_account_pubkey = Pubkey::new_rand(); @@ -5163,17 +5171,21 @@ pub mod tests { // Add the mint let mut mint_data = [0; size_of::()]; - let mint_state: &mut Mint = - spl_token_v1_0::state::unpack_unchecked(&mut mint_data).unwrap(); - *mint_state = Mint { - owner: COption::Some(owner), - decimals: 2, - is_initialized: true, - }; + Mint::unpack_unchecked_mut(&mut mint_data, &mut |mint: &mut Mint| { + *mint = Mint { + mint_authority: COption::Some(owner), + supply: 500, + decimals: 2, + is_initialized: true, + freeze_authority: COption::Some(owner), + }; + Ok(()) + }) + .unwrap(); let mint_account = Account { lamports: 111, data: mint_data.to_vec(), - owner: spl_token_id_v1_0(), + owner: spl_token_id_v2_0(), ..Account::default() }; bank.store_account(&Pubkey::from_str(&mint.to_string()).unwrap(), &mint_account); @@ -5189,7 +5201,7 @@ pub mod tests { result["result"]["value"]["data"], json!({ "program": "spl-token", - "space": 120, + "space": 176, "parsed": { "type": "account", "info": { @@ -5201,13 +5213,19 @@ pub mod tests { "amount": "420", }, "delegate": delegate.to_string(), - "isInitialized": true, - "isNative": false, + "state": "initialized", + "isNative": true, + "rentExemptReserve": { + "uiAmount": 0.1, + "decimals": 2, + "amount": "10", + }, "delegatedAmount": { "uiAmount": 0.3, "decimals": 2, "amount": "30", }, + "closeAuthority": owner.to_string(), } } }) @@ -5225,13 +5243,15 @@ pub mod tests { result["result"]["value"]["data"], json!({ "program": "spl-token", - "space": 40, + "space": 88, "parsed": { "type": "mint", "info": { - "owner": owner.to_string(), + "mintAuthority": owner.to_string(), "decimals": 2, + "supply": "500".to_string(), "isInitialized": true, + "freezeAuthority": owner.to_string(), } } }) diff --git a/core/src/rpc_subscriptions.rs b/core/src/rpc_subscriptions.rs index 3b6166e626..0baf441a9c 100644 --- a/core/src/rpc_subscriptions.rs +++ b/core/src/rpc_subscriptions.rs @@ -8,7 +8,7 @@ use jsonrpc_pubsub::{ SubscriptionId, }; use serde::Serialize; -use solana_account_decoder::{parse_token::spl_token_id_v1_0, UiAccount, UiAccountEncoding}; +use solana_account_decoder::{parse_token::spl_token_id_v2_0, UiAccount, UiAccountEncoding}; use solana_client::{ rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig}, rpc_filter::RpcFilterType, @@ -256,7 +256,7 @@ fn filter_account_result( // and should notify that the account state has been reverted. if fork != last_notified_slot { let encoding = encoding.unwrap_or(UiAccountEncoding::Binary); - if account.owner == spl_token_id_v1_0() && encoding == UiAccountEncoding::JsonParsed { + if account.owner == spl_token_id_v2_0() && encoding == UiAccountEncoding::JsonParsed { let bank = bank.unwrap(); // If result.is_some(), bank must also be Some return ( Box::new(iter::once(get_parsed_token_account(bank, pubkey, account))), diff --git a/transaction-status/Cargo.toml b/transaction-status/Cargo.toml index 0dd9dbe773..674350aa1a 100644 --- a/transaction-status/Cargo.toml +++ b/transaction-status/Cargo.toml @@ -19,7 +19,7 @@ solana-sdk = { path = "../sdk", version = "1.3.6" } solana-stake-program = { path = "../programs/stake", version = "1.3.6" } solana-vote-program = { path = "../programs/vote", version = "1.3.6" } spl-memo-v1-0 = { package = "spl-memo", version = "1.0.7", features = ["skip-no-mangle"] } -spl-token-v1-0 = { package = "spl-token", version = "1.0.8", features = ["skip-no-mangle"] } +spl-token-v2-0 = { package = "spl-token", version = "2.0.1", features = ["skip-no-mangle"] } serde = "1.0.112" serde_derive = "1.0.103" serde_json = "1.0.56" diff --git a/transaction-status/src/parse_instruction.rs b/transaction-status/src/parse_instruction.rs index aaa6ac0616..ebaac0922a 100644 --- a/transaction-status/src/parse_instruction.rs +++ b/transaction-status/src/parse_instruction.rs @@ -1,7 +1,7 @@ use crate::parse_token::parse_token; use inflector::Inflector; use serde_json::Value; -use solana_account_decoder::parse_token::spl_token_id_v1_0; +use solana_account_decoder::parse_token::spl_token_id_v2_0; use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey}; use std::{ collections::HashMap, @@ -12,7 +12,7 @@ use thiserror::Error; lazy_static! { static ref MEMO_PROGRAM_ID: Pubkey = Pubkey::from_str(&spl_memo_v1_0::id().to_string()).unwrap(); - static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v1_0(); + static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0(); static ref PARSABLE_PROGRAM_IDS: HashMap = { let mut m = HashMap::new(); m.insert(*MEMO_PROGRAM_ID, ParsableProgram::SplMemo); diff --git a/transaction-status/src/parse_token.rs b/transaction-status/src/parse_token.rs index 84db788b71..bd4b69d346 100644 --- a/transaction-status/src/parse_token.rs +++ b/transaction-status/src/parse_token.rs @@ -1,7 +1,10 @@ use crate::parse_instruction::{ParsableProgram, ParseInstructionError, ParsedInstructionEnum}; use serde_json::{json, Map, Value}; use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey}; -use spl_token_v1_0::instruction::TokenInstruction; +use spl_token_v2_0::{ + instruction::{AuthorityType, TokenInstruction}, + option::COption, +}; pub fn parse_token( instruction: &CompiledInstruction, @@ -16,7 +19,11 @@ pub fn parse_token( )); } match token_instruction { - TokenInstruction::InitializeMint { amount, decimals } => { + TokenInstruction::InitializeMint { + decimals, + mint_authority, + freeze_authority, + } => { if instruction.accounts.len() < 2 { return Err(ParseInstructionError::InstructionKeyMismatch( ParsableProgram::SplToken, @@ -24,26 +31,16 @@ pub fn parse_token( } let mut value = json!({ "mint": account_keys[instruction.accounts[0] as usize].to_string(), - "amount": amount, - "decimals":decimals, + "decimals": decimals, + "mintAuthority": mint_authority.to_string(), + "rentSysvar": account_keys[instruction.accounts[1] as usize].to_string(), }); let map = value.as_object_mut().unwrap(); - if amount == 0 { + if let COption::Some(freeze_authority) = freeze_authority { map.insert( - "owner".to_string(), - json!(account_keys[instruction.accounts[1] as usize].to_string()), + "freezeAuthority".to_string(), + json!(freeze_authority.to_string()), ); - } else { - map.insert( - "account".to_string(), - json!(account_keys[instruction.accounts[1] as usize].to_string()), - ); - if let Some(i) = instruction.accounts.get(2) { - map.insert( - "owner".to_string(), - json!(account_keys[*i as usize].to_string()), - ); - } } Ok(ParsedInstructionEnum { instruction_type: "initializeMint".to_string(), @@ -51,7 +48,7 @@ pub fn parse_token( }) } TokenInstruction::InitializeAccount => { - if instruction.accounts.len() < 3 { + if instruction.accounts.len() < 4 { return Err(ParseInstructionError::InstructionKeyMismatch( ParsableProgram::SplToken, )); @@ -62,23 +59,25 @@ pub fn parse_token( "account": account_keys[instruction.accounts[0] as usize].to_string(), "mint": account_keys[instruction.accounts[1] as usize].to_string(), "owner": account_keys[instruction.accounts[2] as usize].to_string(), + "rentSysvar": account_keys[instruction.accounts[3] as usize].to_string(), }), }) } TokenInstruction::InitializeMultisig { m } => { - if instruction.accounts.len() < 2 { + if instruction.accounts.len() < 3 { return Err(ParseInstructionError::InstructionKeyMismatch( ParsableProgram::SplToken, )); } let mut signers: Vec = vec![]; - for i in instruction.accounts[1..].iter() { + for i in instruction.accounts[2..].iter() { signers.push(account_keys[*i as usize].to_string()); } Ok(ParsedInstructionEnum { instruction_type: "initializeMultisig".to_string(), info: json!({ "multisig": account_keys[instruction.accounts[0] as usize].to_string(), + "rentSysvar": account_keys[instruction.accounts[1] as usize].to_string(), "signers": signers, "m": m, }), @@ -157,27 +156,38 @@ pub fn parse_token( info: value, }) } - TokenInstruction::SetOwner => { - if instruction.accounts.len() < 3 { + TokenInstruction::SetAuthority { + authority_type, + new_authority, + } => { + if instruction.accounts.len() < 2 { return Err(ParseInstructionError::InstructionKeyMismatch( ParsableProgram::SplToken, )); } + let owned = match authority_type { + AuthorityType::MintTokens | AuthorityType::FreezeAccount => "mint", + AuthorityType::AccountOwner | AuthorityType::CloseAccount => "account", + }; let mut value = json!({ - "owned": account_keys[instruction.accounts[0] as usize].to_string(), - "newOwner": account_keys[instruction.accounts[1] as usize].to_string(), + owned: account_keys[instruction.accounts[0] as usize].to_string(), + "authorityType": Into::::into(authority_type), + "newAuthority": match new_authority { + COption::Some(authority) => Some(authority.to_string()), + COption::None => None, + }, }); let mut map = value.as_object_mut().unwrap(); parse_signers( &mut map, - 2, + 1, account_keys, &instruction.accounts, - "owner", - "multisigOwner", + "authority", + "multisigAuthority", ); Ok(ParsedInstructionEnum { - instruction_type: "setOwner".to_string(), + instruction_type: "setAuthority".to_string(), info: value, }) } @@ -198,8 +208,8 @@ pub fn parse_token( 2, account_keys, &instruction.accounts, - "owner", - "multisigOwner", + "mintAuthority", + "multisigMintAuthority", ); Ok(ParsedInstructionEnum { instruction_type: "mintTo".to_string(), @@ -207,19 +217,20 @@ pub fn parse_token( }) } TokenInstruction::Burn { amount } => { - if instruction.accounts.len() < 2 { + if instruction.accounts.len() < 3 { return Err(ParseInstructionError::InstructionKeyMismatch( ParsableProgram::SplToken, )); } let mut value = json!({ "account": account_keys[instruction.accounts[0] as usize].to_string(), + "mint": account_keys[instruction.accounts[1] as usize].to_string(), "amount": amount, }); let mut map = value.as_object_mut().unwrap(); parse_signers( &mut map, - 1, + 2, account_keys, &instruction.accounts, "authority", @@ -254,6 +265,180 @@ pub fn parse_token( info: value, }) } + TokenInstruction::FreezeAccount => { + if instruction.accounts.len() < 3 { + return Err(ParseInstructionError::InstructionKeyMismatch( + ParsableProgram::SplToken, + )); + } + let mut value = json!({ + "account": account_keys[instruction.accounts[0] as usize].to_string(), + "mint": account_keys[instruction.accounts[1] as usize].to_string(), + }); + let mut map = value.as_object_mut().unwrap(); + parse_signers( + &mut map, + 2, + account_keys, + &instruction.accounts, + "freezeAuthority", + "multisigFreezeAuthority", + ); + Ok(ParsedInstructionEnum { + instruction_type: "freezeAccount".to_string(), + info: value, + }) + } + TokenInstruction::ThawAccount => { + if instruction.accounts.len() < 3 { + return Err(ParseInstructionError::InstructionKeyMismatch( + ParsableProgram::SplToken, + )); + } + let mut value = json!({ + "account": account_keys[instruction.accounts[0] as usize].to_string(), + "mint": account_keys[instruction.accounts[1] as usize].to_string(), + }); + let mut map = value.as_object_mut().unwrap(); + parse_signers( + &mut map, + 2, + account_keys, + &instruction.accounts, + "freezeAuthority", + "multisigFreezeAuthority", + ); + Ok(ParsedInstructionEnum { + instruction_type: "thawAccount".to_string(), + info: value, + }) + } + TokenInstruction::Transfer2 { amount, decimals } => { + if instruction.accounts.len() < 4 { + return Err(ParseInstructionError::InstructionKeyMismatch( + ParsableProgram::SplToken, + )); + } + let mut value = json!({ + "source": account_keys[instruction.accounts[0] as usize].to_string(), + "mint": account_keys[instruction.accounts[1] as usize].to_string(), + "destination": account_keys[instruction.accounts[2] as usize].to_string(), + "amount": amount, + "decimals": decimals, + }); + let mut map = value.as_object_mut().unwrap(); + parse_signers( + &mut map, + 3, + account_keys, + &instruction.accounts, + "authority", + "multisigAuthority", + ); + Ok(ParsedInstructionEnum { + instruction_type: "transfer2".to_string(), + info: value, + }) + } + TokenInstruction::Approve2 { amount, decimals } => { + if instruction.accounts.len() < 4 { + return Err(ParseInstructionError::InstructionKeyMismatch( + ParsableProgram::SplToken, + )); + } + let mut value = json!({ + "source": account_keys[instruction.accounts[0] as usize].to_string(), + "mint": account_keys[instruction.accounts[1] as usize].to_string(), + "delegate": account_keys[instruction.accounts[2] as usize].to_string(), + "amount": amount, + "decimals": decimals, + }); + let mut map = value.as_object_mut().unwrap(); + parse_signers( + &mut map, + 3, + account_keys, + &instruction.accounts, + "owner", + "multisigOwner", + ); + Ok(ParsedInstructionEnum { + instruction_type: "approve2".to_string(), + info: value, + }) + } + TokenInstruction::MintTo2 { amount, decimals } => { + if instruction.accounts.len() < 3 { + return Err(ParseInstructionError::InstructionKeyMismatch( + ParsableProgram::SplToken, + )); + } + let mut value = json!({ + "mint": account_keys[instruction.accounts[0] as usize].to_string(), + "account": account_keys[instruction.accounts[1] as usize].to_string(), + "amount": amount, + "decimals": decimals, + }); + let mut map = value.as_object_mut().unwrap(); + parse_signers( + &mut map, + 2, + account_keys, + &instruction.accounts, + "mintAuthority", + "multisigMintAuthority", + ); + Ok(ParsedInstructionEnum { + instruction_type: "mintTo2".to_string(), + info: value, + }) + } + TokenInstruction::Burn2 { amount, decimals } => { + if instruction.accounts.len() < 3 { + return Err(ParseInstructionError::InstructionKeyMismatch( + ParsableProgram::SplToken, + )); + } + let mut value = json!({ + "account": account_keys[instruction.accounts[0] as usize].to_string(), + "mint": account_keys[instruction.accounts[1] as usize].to_string(), + "amount": amount, + "decimals": decimals, + }); + let mut map = value.as_object_mut().unwrap(); + parse_signers( + &mut map, + 2, + account_keys, + &instruction.accounts, + "authority", + "multisigAuthority", + ); + Ok(ParsedInstructionEnum { + instruction_type: "burn2".to_string(), + info: value, + }) + } + } +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub enum UiAuthorityType { + MintTokens, + FreezeAccount, + AccountOwner, + CloseAccount, +} + +impl From for UiAuthorityType { + fn from(authority_type: AuthorityType) -> Self { + match authority_type { + AuthorityType::MintTokens => UiAuthorityType::MintTokens, + AuthorityType::FreezeAccount => UiAuthorityType::FreezeAccount, + AuthorityType::AccountOwner => UiAuthorityType::AccountOwner, + AuthorityType::CloseAccount => UiAuthorityType::CloseAccount, + } } } @@ -287,7 +472,7 @@ fn parse_signers( mod test { use super::*; use solana_sdk::instruction::CompiledInstruction; - use spl_token_v1_0::{ + use spl_token_v2_0::{ instruction::*, solana_sdk::{ instruction::CompiledInstruction as SplTokenCompiledInstruction, message::Message, @@ -319,11 +504,10 @@ mod test { // Test InitializeMint variations let initialize_mint_ix = initialize_mint( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[0]), - Some(&convert_pubkey(keys[1])), - Some(&convert_pubkey(keys[2])), - 42, + &convert_pubkey(keys[2]), + Some(&convert_pubkey(keys[3])), 2, ) .unwrap(); @@ -335,20 +519,19 @@ mod test { instruction_type: "initializeMint".to_string(), info: json!({ "mint": keys[0].to_string(), - "amount": 42, "decimals": 2, - "account": keys[1].to_string(), - "owner": keys[2].to_string(), + "mintAuthority": keys[2].to_string(), + "freezeAuthority": keys[3].to_string(), + "rentSysvar": keys[1].to_string(), }) } ); let initialize_mint_ix = initialize_mint( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[0]), - Some(&convert_pubkey(keys[1])), + &convert_pubkey(keys[2]), None, - 42, 2, ) .unwrap(); @@ -360,40 +543,16 @@ mod test { instruction_type: "initializeMint".to_string(), info: json!({ "mint": keys[0].to_string(), - "amount": 42, "decimals": 2, - "account": keys[1].to_string(), - }) - } - ); - - let initialize_mint_ix = initialize_mint( - &spl_token_v1_0::id(), - &convert_pubkey(keys[0]), - None, - Some(&convert_pubkey(keys[1])), - 0, - 2, - ) - .unwrap(); - let message = Message::new(&[initialize_mint_ix], None); - let compiled_instruction = convert_compiled_instruction(&message.instructions[0]); - assert_eq!( - parse_token(&compiled_instruction, &keys).unwrap(), - ParsedInstructionEnum { - instruction_type: "initializeMint".to_string(), - info: json!({ - "mint": keys[0].to_string(), - "amount": 0, - "decimals": 2, - "owner": keys[1].to_string(), + "mintAuthority": keys[2].to_string(), + "rentSysvar": keys[1].to_string(), }) } ); // Test InitializeAccount let initialize_account_ix = initialize_account( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[0]), &convert_pubkey(keys[1]), &convert_pubkey(keys[2]), @@ -409,18 +568,19 @@ mod test { "account": keys[0].to_string(), "mint": keys[1].to_string(), "owner": keys[2].to_string(), + "rentSysvar": keys[3].to_string(), }) } ); // Test InitializeMultisig let initialize_multisig_ix = initialize_multisig( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[0]), &[ - &convert_pubkey(keys[1]), &convert_pubkey(keys[2]), &convert_pubkey(keys[3]), + &convert_pubkey(keys[4]), ], 2, ) @@ -434,14 +594,15 @@ mod test { info: json!({ "multisig": keys[0].to_string(), "m": 2, - "signers": keys[1..4].iter().map(|key| key.to_string()).collect::>(), + "rentSysvar": keys[1].to_string(), + "signers": keys[2..5].iter().map(|key| key.to_string()).collect::>(), }) } ); // Test Transfer, incl multisig let transfer_ix = transfer( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[1]), &convert_pubkey(keys[2]), &convert_pubkey(keys[0]), @@ -465,7 +626,7 @@ mod test { ); let transfer_ix = transfer( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[2]), &convert_pubkey(keys[3]), &convert_pubkey(keys[4]), @@ -491,7 +652,7 @@ mod test { // Test Approve, incl multisig let approve_ix = approve( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[1]), &convert_pubkey(keys[2]), &convert_pubkey(keys[0]), @@ -515,7 +676,7 @@ mod test { ); let approve_ix = approve( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[2]), &convert_pubkey(keys[3]), &convert_pubkey(keys[4]), @@ -541,7 +702,7 @@ mod test { // Test Revoke let revoke_ix = revoke( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[1]), &convert_pubkey(keys[0]), &[], @@ -561,31 +722,58 @@ mod test { ); // Test SetOwner - let set_owner_ix = set_owner( - &spl_token_v1_0::id(), - &convert_pubkey(keys[1]), - &convert_pubkey(keys[2]), + let set_authority_ix = set_authority( + &spl_token_v2_0::id(), &convert_pubkey(keys[0]), + Some(&convert_pubkey(keys[2])), + AuthorityType::FreezeAccount, + &convert_pubkey(keys[1]), &[], ) .unwrap(); - let message = Message::new(&[set_owner_ix], None); + let message = Message::new(&[set_authority_ix], None); let compiled_instruction = convert_compiled_instruction(&message.instructions[0]); assert_eq!( parse_token(&compiled_instruction, &keys).unwrap(), ParsedInstructionEnum { - instruction_type: "setOwner".to_string(), + instruction_type: "setAuthority".to_string(), info: json!({ - "owned": keys[1].to_string(), - "newOwner": keys[2].to_string(), - "owner": keys[0].to_string(), + "mint": keys[1].to_string(), + "newAuthority": keys[2].to_string(), + "authority": keys[0].to_string(), + "authorityType": "freezeAccount".to_string(), + }) + } + ); + + let set_authority_ix = set_authority( + &spl_token_v2_0::id(), + &convert_pubkey(keys[1]), + None, + AuthorityType::CloseAccount, + &convert_pubkey(keys[0]), + &[], + ) + .unwrap(); + let message = Message::new(&[set_authority_ix], None); + let compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + let new_authority: Option = None; + assert_eq!( + parse_token(&compiled_instruction, &keys).unwrap(), + ParsedInstructionEnum { + instruction_type: "setAuthority".to_string(), + info: json!({ + "account": keys[1].to_string(), + "newAuthority": new_authority, + "authority": keys[0].to_string(), + "authorityType": "closeAccount".to_string(), }) } ); // Test MintTo let mint_to_ix = mint_to( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[1]), &convert_pubkey(keys[2]), &convert_pubkey(keys[0]), @@ -602,7 +790,7 @@ mod test { info: json!({ "mint": keys[1].to_string(), "account": keys[2].to_string(), - "owner": keys[0].to_string(), + "mintAuthority": keys[0].to_string(), "amount": 42, }) } @@ -610,8 +798,9 @@ mod test { // Test Burn let burn_ix = burn( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[1]), + &convert_pubkey(keys[2]), &convert_pubkey(keys[0]), &[], 42, @@ -625,6 +814,7 @@ mod test { instruction_type: "burn".to_string(), info: json!({ "account": keys[1].to_string(), + "mint": keys[2].to_string(), "authority": keys[0].to_string(), "amount": 42, }) @@ -633,7 +823,7 @@ mod test { // Test CloseAccount let close_account_ix = close_account( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[1]), &convert_pubkey(keys[2]), &convert_pubkey(keys[0]), @@ -653,6 +843,222 @@ mod test { }) } ); + + // Test FreezeAccount + let freeze_account_ix = freeze_account( + &spl_token_v2_0::id(), + &convert_pubkey(keys[1]), + &convert_pubkey(keys[2]), + &convert_pubkey(keys[0]), + &[], + ) + .unwrap(); + let message = Message::new(&[freeze_account_ix], None); + let compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + assert_eq!( + parse_token(&compiled_instruction, &keys).unwrap(), + ParsedInstructionEnum { + instruction_type: "freezeAccount".to_string(), + info: json!({ + "account": keys[1].to_string(), + "mint": keys[2].to_string(), + "freezeAuthority": keys[0].to_string(), + }) + } + ); + + // Test ThawAccount + let thaw_account_ix = thaw_account( + &spl_token_v2_0::id(), + &convert_pubkey(keys[1]), + &convert_pubkey(keys[2]), + &convert_pubkey(keys[0]), + &[], + ) + .unwrap(); + let message = Message::new(&[thaw_account_ix], None); + let compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + assert_eq!( + parse_token(&compiled_instruction, &keys).unwrap(), + ParsedInstructionEnum { + instruction_type: "thawAccount".to_string(), + info: json!({ + "account": keys[1].to_string(), + "mint": keys[2].to_string(), + "freezeAuthority": keys[0].to_string(), + }) + } + ); + + // Test Transfer2, incl multisig + let transfer_ix = transfer2( + &spl_token_v2_0::id(), + &convert_pubkey(keys[0]), + &convert_pubkey(keys[1]), + &convert_pubkey(keys[2]), + &convert_pubkey(keys[3]), + &[], + 42, + 2, + ) + .unwrap(); + let message = Message::new(&[transfer_ix], None); + let compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + assert_eq!( + parse_token(&compiled_instruction, &keys).unwrap(), + ParsedInstructionEnum { + instruction_type: "transfer2".to_string(), + info: json!({ + "source": keys[1].to_string(), + "destination": keys[2].to_string(), + "mint": keys[3].to_string(), + "authority": keys[0].to_string(), + "amount": 42, + "decimals": 2, + }) + } + ); + + let transfer_ix = transfer2( + &spl_token_v2_0::id(), + &convert_pubkey(keys[2]), + &convert_pubkey(keys[3]), + &convert_pubkey(keys[4]), + &convert_pubkey(keys[5]), + &[&convert_pubkey(keys[0]), &convert_pubkey(keys[1])], + 42, + 2, + ) + .unwrap(); + let message = Message::new(&[transfer_ix], None); + let compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + assert_eq!( + parse_token(&compiled_instruction, &keys).unwrap(), + ParsedInstructionEnum { + instruction_type: "transfer2".to_string(), + info: json!({ + "source": keys[2].to_string(), + "destination": keys[3].to_string(), + "mint": keys[4].to_string(), + "multisigAuthority": keys[5].to_string(), + "signers": keys[0..2].iter().map(|key| key.to_string()).collect::>(), + "amount": 42, + "decimals": 2, + }) + } + ); + + // Test Approve2, incl multisig + let approve_ix = approve2( + &spl_token_v2_0::id(), + &convert_pubkey(keys[1]), + &convert_pubkey(keys[2]), + &convert_pubkey(keys[3]), + &convert_pubkey(keys[0]), + &[], + 42, + 2, + ) + .unwrap(); + let message = Message::new(&[approve_ix], None); + let compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + assert_eq!( + parse_token(&compiled_instruction, &keys).unwrap(), + ParsedInstructionEnum { + instruction_type: "approve2".to_string(), + info: json!({ + "source": keys[1].to_string(), + "mint": keys[2].to_string(), + "delegate": keys[3].to_string(), + "owner": keys[0].to_string(), + "amount": 42, + "decimals": 2, + }) + } + ); + + let approve_ix = approve2( + &spl_token_v2_0::id(), + &convert_pubkey(keys[2]), + &convert_pubkey(keys[3]), + &convert_pubkey(keys[4]), + &convert_pubkey(keys[5]), + &[&convert_pubkey(keys[0]), &convert_pubkey(keys[1])], + 42, + 2, + ) + .unwrap(); + let message = Message::new(&[approve_ix], None); + let compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + assert_eq!( + parse_token(&compiled_instruction, &keys).unwrap(), + ParsedInstructionEnum { + instruction_type: "approve2".to_string(), + info: json!({ + "source": keys[2].to_string(), + "mint": keys[3].to_string(), + "delegate": keys[4].to_string(), + "multisigOwner": keys[5].to_string(), + "signers": keys[0..2].iter().map(|key| key.to_string()).collect::>(), + "amount": 42, + "decimals": 2, + }) + } + ); + + // Test MintTo2 + let mint_to_ix = mint_to2( + &spl_token_v2_0::id(), + &convert_pubkey(keys[1]), + &convert_pubkey(keys[2]), + &convert_pubkey(keys[0]), + &[], + 42, + 2, + ) + .unwrap(); + let message = Message::new(&[mint_to_ix], None); + let compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + assert_eq!( + parse_token(&compiled_instruction, &keys).unwrap(), + ParsedInstructionEnum { + instruction_type: "mintTo2".to_string(), + info: json!({ + "mint": keys[1].to_string(), + "account": keys[2].to_string(), + "mintAuthority": keys[0].to_string(), + "amount": 42, + "decimals": 2, + }) + } + ); + + // Test Burn2 + let burn_ix = burn2( + &spl_token_v2_0::id(), + &convert_pubkey(keys[1]), + &convert_pubkey(keys[2]), + &convert_pubkey(keys[0]), + &[], + 42, + 2, + ) + .unwrap(); + let message = Message::new(&[burn_ix], None); + let compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + assert_eq!( + parse_token(&compiled_instruction, &keys).unwrap(), + ParsedInstructionEnum { + instruction_type: "burn2".to_string(), + info: json!({ + "account": keys[1].to_string(), + "mint": keys[2].to_string(), + "authority": keys[0].to_string(), + "amount": 42, + "decimals": 2, + }) + } + ); } #[test] @@ -664,27 +1070,10 @@ mod test { // Test InitializeMint variations let initialize_mint_ix = initialize_mint( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[0]), - Some(&convert_pubkey(keys[1])), + &convert_pubkey(keys[1]), Some(&convert_pubkey(keys[2])), - 42, - 2, - ) - .unwrap(); - let message = Message::new(&[initialize_mint_ix], None); - let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]); - assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err()); - compiled_instruction.accounts = - compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 2].to_vec(); - assert!(parse_token(&compiled_instruction, &keys).is_err()); - - let initialize_mint_ix = initialize_mint( - &spl_token_v1_0::id(), - &convert_pubkey(keys[0]), - Some(&convert_pubkey(keys[1])), - None, - 42, 2, ) .unwrap(); @@ -696,11 +1085,10 @@ mod test { assert!(parse_token(&compiled_instruction, &keys).is_err()); let initialize_mint_ix = initialize_mint( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[0]), + &convert_pubkey(keys[1]), None, - Some(&convert_pubkey(keys[1])), - 0, 2, ) .unwrap(); @@ -713,7 +1101,7 @@ mod test { // Test InitializeAccount let initialize_account_ix = initialize_account( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[0]), &convert_pubkey(keys[1]), &convert_pubkey(keys[2]), @@ -721,14 +1109,14 @@ mod test { .unwrap(); let message = Message::new(&[initialize_account_ix], None); let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]); - assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err()); + assert!(parse_token(&compiled_instruction, &keys[0..3]).is_err()); compiled_instruction.accounts = compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec(); assert!(parse_token(&compiled_instruction, &keys).is_err()); // Test InitializeMultisig let initialize_multisig_ix = initialize_multisig( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[0]), &[ &convert_pubkey(keys[1]), @@ -740,14 +1128,14 @@ mod test { .unwrap(); let message = Message::new(&[initialize_multisig_ix], None); let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]); - assert!(parse_token(&compiled_instruction, &keys[0..3]).is_err()); + assert!(parse_token(&compiled_instruction, &keys[0..4]).is_err()); compiled_instruction.accounts = compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec(); assert!(parse_token(&compiled_instruction, &keys).is_err()); // Test Transfer, incl multisig let transfer_ix = transfer( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[1]), &convert_pubkey(keys[2]), &convert_pubkey(keys[0]), @@ -763,7 +1151,7 @@ mod test { assert!(parse_token(&compiled_instruction, &keys).is_err()); let transfer_ix = transfer( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[2]), &convert_pubkey(keys[3]), &convert_pubkey(keys[4]), @@ -780,7 +1168,7 @@ mod test { // Test Approve, incl multisig let approve_ix = approve( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[1]), &convert_pubkey(keys[2]), &convert_pubkey(keys[0]), @@ -796,7 +1184,7 @@ mod test { assert!(parse_token(&compiled_instruction, &keys).is_err()); let approve_ix = approve( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[2]), &convert_pubkey(keys[3]), &convert_pubkey(keys[4]), @@ -813,7 +1201,7 @@ mod test { // Test Revoke let revoke_ix = revoke( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[1]), &convert_pubkey(keys[0]), &[], @@ -826,25 +1214,26 @@ mod test { compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec(); assert!(parse_token(&compiled_instruction, &keys).is_err()); - // Test SetOwner - let set_owner_ix = set_owner( - &spl_token_v1_0::id(), + // Test SetAuthority + let set_authority_ix = set_authority( + &spl_token_v2_0::id(), &convert_pubkey(keys[1]), - &convert_pubkey(keys[2]), + Some(&convert_pubkey(keys[2])), + AuthorityType::FreezeAccount, &convert_pubkey(keys[0]), &[], ) .unwrap(); - let message = Message::new(&[set_owner_ix], None); + let message = Message::new(&[set_authority_ix], None); let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]); - assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err()); + assert!(parse_token(&compiled_instruction, &keys[0..1]).is_err()); compiled_instruction.accounts = compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec(); assert!(parse_token(&compiled_instruction, &keys).is_err()); // Test MintTo let mint_to_ix = mint_to( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[1]), &convert_pubkey(keys[2]), &convert_pubkey(keys[0]), @@ -861,8 +1250,9 @@ mod test { // Test Burn let burn_ix = burn( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[1]), + &convert_pubkey(keys[2]), &convert_pubkey(keys[0]), &[], 42, @@ -870,14 +1260,14 @@ mod test { .unwrap(); let message = Message::new(&[burn_ix], None); let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]); - assert!(parse_token(&compiled_instruction, &keys[0..1]).is_err()); + assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err()); compiled_instruction.accounts = compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec(); assert!(parse_token(&compiled_instruction, &keys).is_err()); // Test CloseAccount let close_account_ix = close_account( - &spl_token_v1_0::id(), + &spl_token_v2_0::id(), &convert_pubkey(keys[1]), &convert_pubkey(keys[2]), &convert_pubkey(keys[0]), @@ -890,5 +1280,147 @@ mod test { compiled_instruction.accounts = compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec(); assert!(parse_token(&compiled_instruction, &keys).is_err()); + + // Test FreezeAccount + let freeze_account_ix = freeze_account( + &spl_token_v2_0::id(), + &convert_pubkey(keys[1]), + &convert_pubkey(keys[2]), + &convert_pubkey(keys[0]), + &[], + ) + .unwrap(); + let message = Message::new(&[freeze_account_ix], None); + let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err()); + compiled_instruction.accounts = + compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec(); + assert!(parse_token(&compiled_instruction, &keys).is_err()); + + // Test ThawAccount + let thaw_account_ix = thaw_account( + &spl_token_v2_0::id(), + &convert_pubkey(keys[1]), + &convert_pubkey(keys[2]), + &convert_pubkey(keys[0]), + &[], + ) + .unwrap(); + let message = Message::new(&[thaw_account_ix], None); + let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err()); + compiled_instruction.accounts = + compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec(); + assert!(parse_token(&compiled_instruction, &keys).is_err()); + + // Test Transfer2, incl multisig + let transfer_ix = transfer2( + &spl_token_v2_0::id(), + &convert_pubkey(keys[1]), + &convert_pubkey(keys[2]), + &convert_pubkey(keys[3]), + &convert_pubkey(keys[0]), + &[], + 42, + 2, + ) + .unwrap(); + let message = Message::new(&[transfer_ix], None); + let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + assert!(parse_token(&compiled_instruction, &keys[0..3]).is_err()); + compiled_instruction.accounts = + compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec(); + assert!(parse_token(&compiled_instruction, &keys).is_err()); + + let transfer_ix = transfer2( + &spl_token_v2_0::id(), + &convert_pubkey(keys[2]), + &convert_pubkey(keys[3]), + &convert_pubkey(keys[4]), + &convert_pubkey(keys[5]), + &[&convert_pubkey(keys[0]), &convert_pubkey(keys[1])], + 42, + 2, + ) + .unwrap(); + let message = Message::new(&[transfer_ix], None); + let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + assert!(parse_token(&compiled_instruction, &keys[0..5]).is_err()); + compiled_instruction.accounts = + compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec(); + assert!(parse_token(&compiled_instruction, &keys).is_err()); + + // Test Approve2, incl multisig + let approve_ix = approve2( + &spl_token_v2_0::id(), + &convert_pubkey(keys[1]), + &convert_pubkey(keys[2]), + &convert_pubkey(keys[3]), + &convert_pubkey(keys[0]), + &[], + 42, + 2, + ) + .unwrap(); + let message = Message::new(&[approve_ix], None); + let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + assert!(parse_token(&compiled_instruction, &keys[0..3]).is_err()); + compiled_instruction.accounts = + compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec(); + assert!(parse_token(&compiled_instruction, &keys).is_err()); + + let approve_ix = approve2( + &spl_token_v2_0::id(), + &convert_pubkey(keys[2]), + &convert_pubkey(keys[3]), + &convert_pubkey(keys[4]), + &convert_pubkey(keys[5]), + &[&convert_pubkey(keys[0]), &convert_pubkey(keys[1])], + 42, + 2, + ) + .unwrap(); + let message = Message::new(&[approve_ix], None); + let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + assert!(parse_token(&compiled_instruction, &keys[0..5]).is_err()); + compiled_instruction.accounts = + compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec(); + assert!(parse_token(&compiled_instruction, &keys).is_err()); + + // Test MintTo2 + let mint_to_ix = mint_to2( + &spl_token_v2_0::id(), + &convert_pubkey(keys[1]), + &convert_pubkey(keys[2]), + &convert_pubkey(keys[0]), + &[], + 42, + 2, + ) + .unwrap(); + let message = Message::new(&[mint_to_ix], None); + let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err()); + compiled_instruction.accounts = + compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec(); + assert!(parse_token(&compiled_instruction, &keys).is_err()); + + // Test Burn2 + let burn_ix = burn2( + &spl_token_v2_0::id(), + &convert_pubkey(keys[1]), + &convert_pubkey(keys[2]), + &convert_pubkey(keys[0]), + &[], + 42, + 2, + ) + .unwrap(); + let message = Message::new(&[burn_ix], None); + let mut compiled_instruction = convert_compiled_instruction(&message.instructions[0]); + assert!(parse_token(&compiled_instruction, &keys[0..2]).is_err()); + compiled_instruction.accounts = + compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec(); + assert!(parse_token(&compiled_instruction, &keys).is_err()); } }