diff --git a/Cargo.lock b/Cargo.lock index 3820208696..d112a9aa5b 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" @@ -1268,15 +1250,6 @@ dependencies = [ "autocfg 1.0.0", ] -[[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" @@ -2119,6 +2092,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" @@ -3569,7 +3564,7 @@ dependencies = [ "solana-rayon-threadlimit", "solana-runtime", "solana-sdk 1.4.0", - "solana-sdk-macro-frozen-abi", + "solana-sdk-macro-frozen-abi 1.4.0", "solana-stake-program", "solana-storage-bigtable", "solana-streamer", @@ -3591,9 +3586,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", @@ -3934,9 +3929,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", @@ -4172,7 +4167,7 @@ dependencies = [ "solana-noop-program", "solana-rayon-threadlimit", "solana-sdk 1.4.0", - "solana-sdk-macro-frozen-abi", + "solana-sdk-macro-frozen-abi 1.4.0", "solana-stake-program", "solana-vote-program", "symlink", @@ -4192,9 +4187,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", @@ -4202,6 +4197,7 @@ dependencies = [ "bv", "byteorder", "chrono", + "curve25519-dalek", "ed25519-dalek", "generic-array 0.14.3", "hex", @@ -4221,9 +4217,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.4", "thiserror", ] @@ -4260,16 +4257,16 @@ dependencies = [ "solana-crate-features 1.4.0", "solana-logger 1.4.0", "solana-sdk-macro 1.4.0", - "solana-sdk-macro-frozen-abi", + "solana-sdk-macro-frozen-abi 1.4.0", "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", @@ -4289,6 +4286,19 @@ dependencies = [ "syn 1.0.27", ] +[[package]] +name = "solana-sdk-macro-frozen-abi" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cd736a8433b19b8bdf420689219db3403a1f2959f0f8baae57462ddc2fe6911" +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.4.0" @@ -4373,7 +4383,7 @@ dependencies = [ "solana-logger 1.4.0", "solana-metrics", "solana-sdk 1.4.0", - "solana-sdk-macro-frozen-abi", + "solana-sdk-macro-frozen-abi 1.4.0", "solana-vote-program", "thiserror", ] @@ -4531,7 +4541,7 @@ dependencies = [ "serde_derive", "solana-logger 1.4.0", "solana-sdk 1.4.0", - "solana-sdk-macro-frozen-abi", + "solana-sdk-macro-frozen-abi 1.4.0", ] [[package]] @@ -4564,7 +4574,7 @@ dependencies = [ "solana-logger 1.4.0", "solana-metrics", "solana-sdk 1.4.0", - "solana-sdk-macro-frozen-abi", + "solana-sdk-macro-frozen-abi 1.4.0", "thiserror", ] @@ -4634,20 +4644,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", ] @@ -5676,12 +5687,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 e9c823f308..b3271c656d 100644 --- a/account-decoder/Cargo.toml +++ b/account-decoder/Cargo.toml @@ -19,7 +19,7 @@ solana-config-program = { path = "../programs/config", version = "1.4.0" } solana-sdk = { path = "../sdk", version = "1.4.0" } solana-stake-program = { path = "../programs/stake", version = "1.4.0" } solana-vote-program = { path = "../programs/vote", version = "1.4.0" } -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/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 1c812c5005..52da410bcc 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -67,7 +67,7 @@ solana-transaction-status = { path = "../transaction-status", version = "1.4.0" solana-version = { path = "../version", version = "1.4.0" } solana-vote-program = { path = "../programs/vote", version = "1.4.0" } solana-vote-signer = { path = "../vote-signer", version = "1.4.0" } -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 = { version = "0.2.22", features = ["full"] } diff --git a/core/src/rpc.rs b/core/src/rpc.rs index ee98b433d4..5d23e48500 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}, @@ -242,7 +245,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) @@ -290,7 +293,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 @@ -1020,16 +1023,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)?; @@ -1043,32 +1044,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)) } @@ -1079,9 +1067,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![ @@ -1097,9 +1085,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 { @@ -1363,15 +1350,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( @@ -1385,8 +1372,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()) @@ -1397,12 +1384,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] @@ -1687,7 +1673,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")] @@ -2500,8 +2486,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; @@ -4741,24 +4728,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(); @@ -4766,17 +4756,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); @@ -4805,10 +4799,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, @@ -4819,8 +4810,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 @@ -4833,24 +4824,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(); @@ -4865,7 +4863,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")) @@ -4883,7 +4881,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")) @@ -4947,7 +4945,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")) @@ -4965,7 +4963,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")) @@ -5030,7 +5028,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")) @@ -5041,17 +5039,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( @@ -5059,21 +5061,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(); @@ -5117,24 +5122,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(); @@ -5142,17 +5150,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); @@ -5168,7 +5180,7 @@ pub mod tests { result["result"]["value"]["data"], json!({ "program": "spl-token", - "space": 120, + "space": 176, "parsed": { "type": "account", "info": { @@ -5180,13 +5192,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(), } } }) @@ -5204,13 +5222,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 075f2344f8..7a230614fc 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 0d1d9a6ae5..2c6da13e28 100644 --- a/transaction-status/Cargo.toml +++ b/transaction-status/Cargo.toml @@ -19,7 +19,7 @@ solana-sdk = { path = "../sdk", version = "1.4.0" } solana-stake-program = { path = "../programs/stake", version = "1.4.0" } solana-vote-program = { path = "../programs/vote", version = "1.4.0" } 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 049fab9c3e..4c23c2bfd2 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, @@ -320,11 +505,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(); @@ -336,20 +520,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(); @@ -361,40 +544,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]), @@ -410,18 +569,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, ) @@ -435,14 +595,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]), @@ -466,7 +627,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]), @@ -492,7 +653,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]), @@ -516,7 +677,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]), @@ -542,7 +703,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]), &[], @@ -562,31 +723,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]), @@ -603,7 +791,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, }) } @@ -611,8 +799,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, @@ -626,6 +815,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, }) @@ -634,7 +824,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]), @@ -654,6 +844,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] @@ -666,27 +1072,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(); @@ -698,11 +1087,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(); @@ -715,7 +1103,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]), @@ -723,14 +1111,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]), @@ -742,14 +1130,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]), @@ -765,7 +1153,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]), @@ -782,7 +1170,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]), @@ -798,7 +1186,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]), @@ -815,7 +1203,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]), &[], @@ -828,25 +1216,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]), @@ -863,8 +1252,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, @@ -872,14 +1262,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]), @@ -892,5 +1282,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()); } }