spl: Bump token-2022 and friends (#33453)

* token: Update to 4.0.0

* token-2022: Bump and support new account and instruction types

* Update token-2022 in fetch_spl / program-test

* Fixup downstream uses

* Mint and destination were flipped in 0.9.0

* Don't use `convert_pubkey`

* Bump spl dependencies to versions which avoid recompilations
This commit is contained in:
Jon Cinque 2023-09-29 19:12:06 +02:00 committed by GitHub
parent 0e9e91c65e
commit de38b05ad1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 1255 additions and 200 deletions

224
Cargo.lock generated
View File

@ -709,7 +709,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b"
dependencies = [ dependencies = [
"borsh-derive 0.10.3", "borsh-derive 0.10.3",
"hashbrown 0.13.2", "hashbrown 0.12.3",
] ]
[[package]] [[package]]
@ -3299,6 +3299,17 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "num-derive"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
]
[[package]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.44" version = "0.1.44"
@ -3370,6 +3381,15 @@ dependencies = [
"num_enum_derive 0.6.1", "num_enum_derive 0.6.1",
] ]
[[package]]
name = "num_enum"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70bf6736f74634d299d00086f02986875b3c2d924781a6a2cb6c201e73da0ceb"
dependencies = [
"num_enum_derive 0.7.0",
]
[[package]] [[package]]
name = "num_enum_derive" name = "num_enum_derive"
version = "0.5.11" version = "0.5.11"
@ -3394,6 +3414,18 @@ dependencies = [
"syn 2.0.37", "syn 2.0.37",
] ]
[[package]]
name = "num_enum_derive"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56ea360eafe1022f7cc56cd7b869ed57330fb2453d0c7831d99b74c65d2f5597"
dependencies = [
"proc-macro-crate 1.1.0",
"proc-macro2",
"quote",
"syn 2.0.37",
]
[[package]] [[package]]
name = "num_threads" name = "num_threads"
version = "0.1.3" version = "0.1.3"
@ -5077,8 +5109,10 @@ dependencies = [
"serde_json", "serde_json",
"solana-config-program", "solana-config-program",
"solana-sdk", "solana-sdk",
"spl-pod",
"spl-token", "spl-token",
"spl-token-2022", "spl-token-2022",
"spl-token-metadata-interface",
"thiserror", "thiserror",
"zstd", "zstd",
] ]
@ -5155,7 +5189,7 @@ dependencies = [
"memmap2", "memmap2",
"memoffset 0.9.0", "memoffset 0.9.0",
"modular-bitfield", "modular-bitfield",
"num-derive", "num-derive 0.3.3",
"num-traits", "num-traits",
"num_cpus", "num_cpus",
"num_enum 0.6.1", "num_enum 0.6.1",
@ -5198,7 +5232,7 @@ dependencies = [
"bincode", "bincode",
"bytemuck", "bytemuck",
"log", "log",
"num-derive", "num-derive 0.3.3",
"num-traits", "num-traits",
"rustc_version 0.4.0", "rustc_version 0.4.0",
"serde", "serde",
@ -6160,6 +6194,7 @@ dependencies = [
"solana-transaction-status", "solana-transaction-status",
"solana-vote", "solana-vote",
"solana-vote-program", "solana-vote-program",
"spl-pod",
"spl-token", "spl-token",
"spl-token-2022", "spl-token-2022",
"static_assertions", "static_assertions",
@ -6483,7 +6518,7 @@ dependencies = [
"log", "log",
"memoffset 0.9.0", "memoffset 0.9.0",
"num-bigint 0.4.4", "num-bigint 0.4.4",
"num-derive", "num-derive 0.3.3",
"num-traits", "num-traits",
"parking_lot 0.12.1", "parking_lot 0.12.1",
"rand 0.8.5", "rand 0.8.5",
@ -6519,7 +6554,7 @@ dependencies = [
"libc", "libc",
"libsecp256k1", "libsecp256k1",
"log", "log",
"num-derive", "num-derive 0.3.3",
"num-traits", "num-traits",
"percentage", "percentage",
"rand 0.8.5", "rand 0.8.5",
@ -6632,7 +6667,7 @@ dependencies = [
"dialoguer", "dialoguer",
"hidapi", "hidapi",
"log", "log",
"num-derive", "num-derive 0.3.3",
"num-traits", "num-traits",
"parking_lot 0.12.1", "parking_lot 0.12.1",
"qstring", "qstring",
@ -6691,6 +6726,7 @@ dependencies = [
"solana-version", "solana-version",
"solana-vote", "solana-vote",
"solana-vote-program", "solana-vote-program",
"spl-pod",
"spl-token", "spl-token",
"spl-token-2022", "spl-token-2022",
"stream-cancel", "stream-cancel",
@ -6824,7 +6860,7 @@ dependencies = [
"memmap2", "memmap2",
"memoffset 0.9.0", "memoffset 0.9.0",
"modular-bitfield", "modular-bitfield",
"num-derive", "num-derive 0.3.3",
"num-traits", "num-traits",
"num_cpus", "num_cpus",
"num_enum 0.6.1", "num_enum 0.6.1",
@ -6904,7 +6940,7 @@ dependencies = [
"libsecp256k1", "libsecp256k1",
"log", "log",
"memmap2", "memmap2",
"num-derive", "num-derive 0.3.3",
"num-traits", "num-traits",
"num_enum 0.6.1", "num_enum 0.6.1",
"pbkdf2 0.11.0", "pbkdf2 0.11.0",
@ -7232,7 +7268,7 @@ dependencies = [
"Inflector", "Inflector",
"base64 0.21.4", "base64 0.21.4",
"bincode", "bincode",
"borsh 0.9.3", "borsh 0.10.3",
"bs58", "bs58",
"lazy_static", "lazy_static",
"log", "log",
@ -7410,7 +7446,7 @@ dependencies = [
"assert_matches", "assert_matches",
"bincode", "bincode",
"log", "log",
"num-derive", "num-derive 0.3.3",
"num-traits", "num-traits",
"rustc_version 0.4.0", "rustc_version 0.4.0",
"serde", "serde",
@ -7471,7 +7507,7 @@ dependencies = [
"bytemuck", "bytemuck",
"criterion", "criterion",
"curve25519-dalek", "curve25519-dalek",
"num-derive", "num-derive 0.3.3",
"num-traits", "num-traits",
"solana-program-runtime", "solana-program-runtime",
"solana-sdk", "solana-sdk",
@ -7504,7 +7540,7 @@ dependencies = [
"itertools", "itertools",
"lazy_static", "lazy_static",
"merlin", "merlin",
"num-derive", "num-derive 0.3.3",
"num-traits", "num-traits",
"rand 0.7.3", "rand 0.7.3",
"serde", "serde",
@ -7562,13 +7598,13 @@ dependencies = [
[[package]] [[package]]
name = "spl-associated-token-account" name = "spl-associated-token-account"
version = "1.1.3" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978dba3bcbe88d0c2c58366c254d9ea41c5f73357e72fc0bdee4d6b5fc99c8f4" checksum = "385e31c29981488f2820b2022d8e731aae3b02e6e18e2fd854e4c9a94dc44fc3"
dependencies = [ dependencies = [
"assert_matches", "assert_matches",
"borsh 0.9.3", "borsh 0.10.3",
"num-derive", "num-derive 0.4.0",
"num-traits", "num-traits",
"solana-program", "solana-program",
"spl-token", "spl-token",
@ -7576,6 +7612,41 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "spl-discriminator"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cce5d563b58ef1bb2cdbbfe0dfb9ffdc24903b10ae6a4df2d8f425ece375033f"
dependencies = [
"bytemuck",
"solana-program",
"spl-discriminator-derive",
]
[[package]]
name = "spl-discriminator-derive"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b"
dependencies = [
"quote",
"spl-discriminator-syn",
"syn 2.0.37",
]
[[package]]
name = "spl-discriminator-syn"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e5f2044ca42c8938d54d1255ce599c79a1ffd86b677dfab695caa20f9ffc3f2"
dependencies = [
"proc-macro2",
"quote",
"sha2 0.10.7",
"syn 2.0.37",
"thiserror",
]
[[package]] [[package]]
name = "spl-instruction-padding" name = "spl-instruction-padding"
version = "0.1.0" version = "0.1.0"
@ -7588,46 +7659,145 @@ dependencies = [
[[package]] [[package]]
name = "spl-memo" name = "spl-memo"
version = "3.0.1" version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0dc6f70db6bacea7ff25870b016a65ba1d1b6013536f08e4fd79a8f9005325" checksum = "f0f180b03318c3dbab3ef4e1e4d46d5211ae3c780940dd0a28695aba4b59a75a"
dependencies = [ dependencies = [
"solana-program", "solana-program",
] ]
[[package]] [[package]]
name = "spl-token" name = "spl-pod"
version = "3.5.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e85e168a785e82564160dcb87b2a8e04cee9bfd1f4d488c729d53d6a4bd300d" checksum = "2881dddfca792737c0706fa0175345ab282b1b0879c7d877bad129645737c079"
dependencies = [
"borsh 0.10.3",
"bytemuck",
"solana-program",
"solana-zk-token-sdk",
"spl-program-error",
]
[[package]]
name = "spl-program-error"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "249e0318493b6bcf27ae9902600566c689b7dfba9f1bdff5893e92253374e78c"
dependencies = [
"num-derive 0.4.0",
"num-traits",
"solana-program",
"spl-program-error-derive",
"thiserror",
]
[[package]]
name = "spl-program-error-derive"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5269c8e868da17b6552ef35a51355a017bd8e0eae269c201fef830d35fa52c"
dependencies = [
"proc-macro2",
"quote",
"sha2 0.10.7",
"syn 2.0.37",
]
[[package]]
name = "spl-tlv-account-resolution"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "062e148d3eab7b165582757453632ffeef490c02c86a48bfdb4988f63eefb3b9"
dependencies = [
"bytemuck",
"solana-program",
"spl-discriminator",
"spl-pod",
"spl-program-error",
"spl-type-length-value",
]
[[package]]
name = "spl-token"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08459ba1b8f7c1020b4582c4edf0f5c7511a5e099a7a97570c9698d4f2337060"
dependencies = [ dependencies = [
"arrayref", "arrayref",
"bytemuck", "bytemuck",
"num-derive", "num-derive 0.3.3",
"num-traits", "num-traits",
"num_enum 0.5.11", "num_enum 0.6.1",
"solana-program", "solana-program",
"thiserror", "thiserror",
] ]
[[package]] [[package]]
name = "spl-token-2022" name = "spl-token-2022"
version = "0.6.1" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0043b590232c400bad5ee9eb983ced003d15163c4c5d56b090ac6d9a57457b47" checksum = "e4abf34a65ba420584a0c35f3903f8d727d1f13ababbdc3f714c6b065a686e86"
dependencies = [ dependencies = [
"arrayref", "arrayref",
"bytemuck", "bytemuck",
"num-derive", "num-derive 0.4.0",
"num-traits", "num-traits",
"num_enum 0.5.11", "num_enum 0.7.0",
"solana-program", "solana-program",
"solana-zk-token-sdk", "solana-zk-token-sdk",
"spl-memo", "spl-memo",
"spl-pod",
"spl-token", "spl-token",
"spl-token-metadata-interface",
"spl-transfer-hook-interface",
"spl-type-length-value",
"thiserror", "thiserror",
] ]
[[package]]
name = "spl-token-metadata-interface"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c16ce3ba6979645fb7627aa1e435576172dd63088dc7848cb09aa331fa1fe4f"
dependencies = [
"borsh 0.10.3",
"solana-program",
"spl-discriminator",
"spl-pod",
"spl-program-error",
"spl-type-length-value",
]
[[package]]
name = "spl-transfer-hook-interface"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "051d31803f873cabe71aec3c1b849f35248beae5d19a347d93a5c9cccc5d5a9b"
dependencies = [
"arrayref",
"bytemuck",
"solana-program",
"spl-discriminator",
"spl-pod",
"spl-program-error",
"spl-tlv-account-resolution",
"spl-type-length-value",
]
[[package]]
name = "spl-type-length-value"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a468e6f6371f9c69aae760186ea9f1a01c2908351b06a5e0026d21cfc4d7ecac"
dependencies = [
"bytemuck",
"solana-program",
"spl-discriminator",
"spl-pod",
"spl-program-error",
]
[[package]] [[package]]
name = "static_assertions" name = "static_assertions"
version = "1.1.0" version = "1.1.0"

View File

@ -373,11 +373,13 @@ solana-vote-program = { path = "programs/vote", version = "=1.17.0" }
solana-zk-keygen = { path = "zk-keygen", version = "=1.17.0" } solana-zk-keygen = { path = "zk-keygen", version = "=1.17.0" }
solana-zk-token-proof-program = { path = "programs/zk-token-proof", version = "=1.17.0" } solana-zk-token-proof-program = { path = "programs/zk-token-proof", version = "=1.17.0" }
solana-zk-token-sdk = { path = "zk-token-sdk", version = "=1.17.0" } solana-zk-token-sdk = { path = "zk-token-sdk", version = "=1.17.0" }
spl-associated-token-account = "=1.1.3" spl-associated-token-account = "=2.2.0"
spl-instruction-padding = "0.1" spl-instruction-padding = "0.1"
spl-memo = "=3.0.1" spl-memo = "=4.0.0"
spl-token = "=3.5.0" spl-pod = "=0.1.0"
spl-token-2022 = "=0.6.1" spl-token = "=4.0.0"
spl-token-2022 = "=0.9.0"
spl-token-metadata-interface = "=0.2.0"
static_assertions = "1.1.0" static_assertions = "1.1.0"
stream-cancel = "0.8.1" stream-cancel = "0.8.1"
strum = "0.24" strum = "0.24"
@ -423,8 +425,10 @@ crossbeam-epoch = { git = "https://github.com/solana-labs/crossbeam", rev = "fd2
# * spl-associated-token-account # * spl-associated-token-account
# * spl-instruction-padding # * spl-instruction-padding
# * spl-memo # * spl-memo
# * spl-pod
# * spl-token # * spl-token
# * spl-token-2022 # * spl-token-2022
# * spl-token-metadata-interface
# #
# They, in turn, depend on a number of crates that we also include directly using `path` # They, in turn, depend on a number of crates that we also include directly using `path`
# specifications. For example, `spl-token` depends on `solana-program`. And we explicitly specify # specifications. For example, `spl-token` depends on `solana-program`. And we explicitly specify

View File

@ -23,11 +23,13 @@ solana-config-program = { workspace = true }
solana-sdk = { workspace = true } solana-sdk = { workspace = true }
spl-token = { workspace = true, features = ["no-entrypoint"] } spl-token = { workspace = true, features = ["no-entrypoint"] }
spl-token-2022 = { workspace = true, features = ["no-entrypoint"] } spl-token-2022 = { workspace = true, features = ["no-entrypoint"] }
spl-token-metadata-interface = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
zstd = { workspace = true } zstd = { workspace = true }
[dev-dependencies] [dev-dependencies]
assert_matches = { workspace = true } assert_matches = { workspace = true }
spl-pod = { workspace = true }
[package.metadata.docs.rs] [package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"] targets = ["x86_64-unknown-linux-gnu"]

View File

@ -290,12 +290,10 @@ mod test {
use { use {
super::*, super::*,
crate::parse_token_extension::{UiMemoTransfer, UiMintCloseAuthority}, crate::parse_token_extension::{UiMemoTransfer, UiMintCloseAuthority},
spl_token_2022::{ spl_pod::optional_keys::OptionalNonZeroPubkey,
extension::{ spl_token_2022::extension::{
immutable_owner::ImmutableOwner, memo_transfer::MemoTransfer, immutable_owner::ImmutableOwner, memo_transfer::MemoTransfer,
mint_close_authority::MintCloseAuthority, ExtensionType, StateWithExtensionsMut, mint_close_authority::MintCloseAuthority, ExtensionType, StateWithExtensionsMut,
},
pod::OptionalNonZeroPubkey,
}, },
}; };
@ -506,10 +504,11 @@ mod test {
delegate: COption::None, delegate: COption::None,
delegated_amount: 0, delegated_amount: 0,
}; };
let account_size = ExtensionType::get_account_len::<Account>(&[ let account_size = ExtensionType::try_calculate_account_len::<Account>(&[
ExtensionType::ImmutableOwner, ExtensionType::ImmutableOwner,
ExtensionType::MemoTransfer, ExtensionType::MemoTransfer,
]); ])
.unwrap();
let mut account_data = vec![0; account_size]; let mut account_data = vec![0; account_size];
let mut account_state = let mut account_state =
StateWithExtensionsMut::<Account>::unpack_uninitialized(&mut account_data).unwrap(); StateWithExtensionsMut::<Account>::unpack_uninitialized(&mut account_data).unwrap();
@ -586,7 +585,8 @@ mod test {
fn test_parse_token_mint_with_extensions() { fn test_parse_token_mint_with_extensions() {
let owner_pubkey = SplTokenPubkey::new_from_array([3; 32]); let owner_pubkey = SplTokenPubkey::new_from_array([3; 32]);
let mint_size = let mint_size =
ExtensionType::get_account_len::<Mint>(&[ExtensionType::MintCloseAuthority]); ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::MintCloseAuthority])
.unwrap();
let mint_base = Mint { let mint_base = Mint {
mint_authority: COption::Some(owner_pubkey), mint_authority: COption::Some(owner_pubkey),
supply: 42, supply: 42,

View File

@ -6,6 +6,7 @@ use {
solana_program::pubkey::Pubkey, solana_program::pubkey::Pubkey,
solana_zk_token_sdk::zk_token_elgamal::pod::ElGamalPubkey, solana_zk_token_sdk::zk_token_elgamal::pod::ElGamalPubkey,
}, },
spl_token_metadata_interface::state::TokenMetadata,
}; };
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
@ -24,15 +25,21 @@ pub enum UiExtension {
InterestBearingConfig(UiInterestBearingConfig), InterestBearingConfig(UiInterestBearingConfig),
CpiGuard(UiCpiGuard), CpiGuard(UiCpiGuard),
PermanentDelegate(UiPermanentDelegate), PermanentDelegate(UiPermanentDelegate),
UnparseableExtension,
NonTransferableAccount, NonTransferableAccount,
ConfidentialTransferFeeConfig(UiConfidentialTransferFeeConfig),
ConfidentialTransferFeeAmount(UiConfidentialTransferFeeAmount),
TransferHook(UiTransferHook),
TransferHookAccount(UiTransferHookAccount),
MetadataPointer(UiMetadataPointer),
TokenMetadata(UiTokenMetadata),
UnparseableExtension,
} }
pub fn parse_extension<S: BaseState>( pub fn parse_extension<S: BaseState>(
extension_type: &ExtensionType, extension_type: &ExtensionType,
account: &StateWithExtensions<S>, account: &StateWithExtensions<S>,
) -> UiExtension { ) -> UiExtension {
match &extension_type { match extension_type {
ExtensionType::Uninitialized => UiExtension::Uninitialized, ExtensionType::Uninitialized => UiExtension::Uninitialized,
ExtensionType::TransferFeeConfig => account ExtensionType::TransferFeeConfig => account
.get_extension::<extension::transfer_fee::TransferFeeConfig>() .get_extension::<extension::transfer_fee::TransferFeeConfig>()
@ -50,10 +57,18 @@ pub fn parse_extension<S: BaseState>(
.get_extension::<extension::confidential_transfer::ConfidentialTransferMint>() .get_extension::<extension::confidential_transfer::ConfidentialTransferMint>()
.map(|&extension| UiExtension::ConfidentialTransferMint(extension.into())) .map(|&extension| UiExtension::ConfidentialTransferMint(extension.into()))
.unwrap_or(UiExtension::UnparseableExtension), .unwrap_or(UiExtension::UnparseableExtension),
ExtensionType::ConfidentialTransferFeeConfig => account
.get_extension::<extension::confidential_transfer_fee::ConfidentialTransferFeeConfig>()
.map(|&extension| UiExtension::ConfidentialTransferFeeConfig(extension.into()))
.unwrap_or(UiExtension::UnparseableExtension),
ExtensionType::ConfidentialTransferAccount => account ExtensionType::ConfidentialTransferAccount => account
.get_extension::<extension::confidential_transfer::ConfidentialTransferAccount>() .get_extension::<extension::confidential_transfer::ConfidentialTransferAccount>()
.map(|&extension| UiExtension::ConfidentialTransferAccount(extension.into())) .map(|&extension| UiExtension::ConfidentialTransferAccount(extension.into()))
.unwrap_or(UiExtension::UnparseableExtension), .unwrap_or(UiExtension::UnparseableExtension),
ExtensionType::ConfidentialTransferFeeAmount => account
.get_extension::<extension::confidential_transfer_fee::ConfidentialTransferFeeAmount>()
.map(|&extension| UiExtension::ConfidentialTransferFeeAmount(extension.into()))
.unwrap_or(UiExtension::UnparseableExtension),
ExtensionType::DefaultAccountState => account ExtensionType::DefaultAccountState => account
.get_extension::<extension::default_account_state::DefaultAccountState>() .get_extension::<extension::default_account_state::DefaultAccountState>()
.map(|&extension| UiExtension::DefaultAccountState(extension.into())) .map(|&extension| UiExtension::DefaultAccountState(extension.into()))
@ -77,6 +92,22 @@ pub fn parse_extension<S: BaseState>(
.map(|&extension| UiExtension::PermanentDelegate(extension.into())) .map(|&extension| UiExtension::PermanentDelegate(extension.into()))
.unwrap_or(UiExtension::UnparseableExtension), .unwrap_or(UiExtension::UnparseableExtension),
ExtensionType::NonTransferableAccount => UiExtension::NonTransferableAccount, ExtensionType::NonTransferableAccount => UiExtension::NonTransferableAccount,
ExtensionType::MetadataPointer => account
.get_extension::<extension::metadata_pointer::MetadataPointer>()
.map(|&extension| UiExtension::MetadataPointer(extension.into()))
.unwrap_or(UiExtension::UnparseableExtension),
ExtensionType::TokenMetadata => account
.get_variable_len_extension::<TokenMetadata>()
.map(|extension| UiExtension::TokenMetadata(extension.into()))
.unwrap_or(UiExtension::UnparseableExtension),
ExtensionType::TransferHook => account
.get_extension::<extension::transfer_hook::TransferHook>()
.map(|&extension| UiExtension::TransferHook(extension.into()))
.unwrap_or(UiExtension::UnparseableExtension),
ExtensionType::TransferHookAccount => account
.get_extension::<extension::transfer_hook::TransferHookAccount>()
.map(|&extension| UiExtension::TransferHookAccount(extension.into()))
.unwrap_or(UiExtension::UnparseableExtension),
} }
} }
@ -251,9 +282,7 @@ impl From<extension::permanent_delegate::PermanentDelegate> for UiPermanentDeleg
pub struct UiConfidentialTransferMint { pub struct UiConfidentialTransferMint {
pub authority: Option<String>, pub authority: Option<String>,
pub auto_approve_new_accounts: bool, pub auto_approve_new_accounts: bool,
pub auditor_encryption_pubkey: Option<String>, pub auditor_elgamal_pubkey: Option<String>,
pub withdraw_withheld_authority_encryption_pubkey: Option<String>,
pub withheld_amount: String,
} }
impl From<extension::confidential_transfer::ConfidentialTransferMint> impl From<extension::confidential_transfer::ConfidentialTransferMint>
@ -263,19 +292,44 @@ impl From<extension::confidential_transfer::ConfidentialTransferMint>
confidential_transfer_mint: extension::confidential_transfer::ConfidentialTransferMint, confidential_transfer_mint: extension::confidential_transfer::ConfidentialTransferMint,
) -> Self { ) -> Self {
let authority: Option<Pubkey> = confidential_transfer_mint.authority.into(); let authority: Option<Pubkey> = confidential_transfer_mint.authority.into();
let auditor_encryption_pubkey: Option<ElGamalPubkey> = let auditor_elgamal_pubkey: Option<ElGamalPubkey> =
confidential_transfer_mint.auditor_encryption_pubkey.into(); confidential_transfer_mint.auditor_elgamal_pubkey.into();
let withdraw_withheld_authority_encryption_pubkey: Option<ElGamalPubkey> =
confidential_transfer_mint
.withdraw_withheld_authority_encryption_pubkey
.into();
Self { Self {
authority: authority.map(|pubkey| pubkey.to_string()), authority: authority.map(|pubkey| pubkey.to_string()),
auto_approve_new_accounts: confidential_transfer_mint.auto_approve_new_accounts.into(), auto_approve_new_accounts: confidential_transfer_mint.auto_approve_new_accounts.into(),
auditor_encryption_pubkey: auditor_encryption_pubkey.map(|pubkey| pubkey.to_string()), auditor_elgamal_pubkey: auditor_elgamal_pubkey.map(|pubkey| pubkey.to_string()),
withdraw_withheld_authority_encryption_pubkey: }
withdraw_withheld_authority_encryption_pubkey.map(|pubkey| pubkey.to_string()), }
withheld_amount: format!("{}", confidential_transfer_mint.withheld_amount), }
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct UiConfidentialTransferFeeConfig {
pub authority: Option<String>,
pub withdraw_withheld_authority_elgamal_pubkey: Option<String>,
pub harvest_to_mint_enabled: bool,
pub withheld_amount: String,
}
impl From<extension::confidential_transfer_fee::ConfidentialTransferFeeConfig>
for UiConfidentialTransferFeeConfig
{
fn from(
confidential_transfer_fee_config: extension::confidential_transfer_fee::ConfidentialTransferFeeConfig,
) -> Self {
let authority: Option<Pubkey> = confidential_transfer_fee_config.authority.into();
let withdraw_withheld_authority_elgamal_pubkey: Option<ElGamalPubkey> =
confidential_transfer_fee_config
.withdraw_withheld_authority_elgamal_pubkey
.into();
Self {
authority: authority.map(|pubkey| pubkey.to_string()),
withdraw_withheld_authority_elgamal_pubkey: withdraw_withheld_authority_elgamal_pubkey
.map(|pubkey| pubkey.to_string()),
harvest_to_mint_enabled: confidential_transfer_fee_config
.harvest_to_mint_enabled
.into(),
withheld_amount: format!("{}", confidential_transfer_fee_config.withheld_amount),
} }
} }
} }
@ -284,7 +338,7 @@ impl From<extension::confidential_transfer::ConfidentialTransferMint>
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct UiConfidentialTransferAccount { pub struct UiConfidentialTransferAccount {
pub approved: bool, pub approved: bool,
pub encryption_pubkey: String, pub elgamal_pubkey: String,
pub pending_balance_lo: String, pub pending_balance_lo: String,
pub pending_balance_hi: String, pub pending_balance_hi: String,
pub available_balance: String, pub available_balance: String,
@ -295,7 +349,6 @@ pub struct UiConfidentialTransferAccount {
pub maximum_pending_balance_credit_counter: u64, pub maximum_pending_balance_credit_counter: u64,
pub expected_pending_balance_credit_counter: u64, pub expected_pending_balance_credit_counter: u64,
pub actual_pending_balance_credit_counter: u64, pub actual_pending_balance_credit_counter: u64,
pub withheld_amount: String,
} }
impl From<extension::confidential_transfer::ConfidentialTransferAccount> impl From<extension::confidential_transfer::ConfidentialTransferAccount>
@ -306,7 +359,7 @@ impl From<extension::confidential_transfer::ConfidentialTransferAccount>
) -> Self { ) -> Self {
Self { Self {
approved: confidential_transfer_account.approved.into(), approved: confidential_transfer_account.approved.into(),
encryption_pubkey: format!("{}", confidential_transfer_account.encryption_pubkey), elgamal_pubkey: format!("{}", confidential_transfer_account.elgamal_pubkey),
pending_balance_lo: format!("{}", confidential_transfer_account.pending_balance_lo), pending_balance_lo: format!("{}", confidential_transfer_account.pending_balance_lo),
pending_balance_hi: format!("{}", confidential_transfer_account.pending_balance_hi), pending_balance_hi: format!("{}", confidential_transfer_account.pending_balance_hi),
available_balance: format!("{}", confidential_transfer_account.available_balance), available_balance: format!("{}", confidential_transfer_account.available_balance),
@ -332,7 +385,99 @@ impl From<extension::confidential_transfer::ConfidentialTransferAccount>
actual_pending_balance_credit_counter: confidential_transfer_account actual_pending_balance_credit_counter: confidential_transfer_account
.actual_pending_balance_credit_counter .actual_pending_balance_credit_counter
.into(), .into(),
withheld_amount: format!("{}", confidential_transfer_account.withheld_amount), }
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct UiConfidentialTransferFeeAmount {
pub withheld_amount: String,
}
impl From<extension::confidential_transfer_fee::ConfidentialTransferFeeAmount>
for UiConfidentialTransferFeeAmount
{
fn from(
confidential_transfer_fee_amount: extension::confidential_transfer_fee::ConfidentialTransferFeeAmount,
) -> Self {
Self {
withheld_amount: format!("{}", confidential_transfer_fee_amount.withheld_amount),
}
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct UiMetadataPointer {
pub authority: Option<String>,
pub metadata_address: Option<String>,
}
impl From<extension::metadata_pointer::MetadataPointer> for UiMetadataPointer {
fn from(metadata_pointer: extension::metadata_pointer::MetadataPointer) -> Self {
let authority: Option<Pubkey> = metadata_pointer.authority.into();
let metadata_address: Option<Pubkey> = metadata_pointer.metadata_address.into();
Self {
authority: authority.map(|pubkey| pubkey.to_string()),
metadata_address: metadata_address.map(|pubkey| pubkey.to_string()),
}
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct UiTokenMetadata {
pub update_authority: Option<String>,
pub mint: String,
pub name: String,
pub symbol: String,
pub uri: String,
pub additional_metadata: Vec<(String, String)>,
}
impl From<TokenMetadata> for UiTokenMetadata {
fn from(token_metadata: TokenMetadata) -> Self {
let update_authority: Option<Pubkey> = token_metadata.update_authority.into();
Self {
update_authority: update_authority.map(|pubkey| pubkey.to_string()),
mint: token_metadata.mint.to_string(),
name: token_metadata.name,
symbol: token_metadata.symbol,
uri: token_metadata.uri,
additional_metadata: token_metadata.additional_metadata,
}
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct UiTransferHook {
pub authority: Option<String>,
pub program_id: Option<String>,
}
impl From<extension::transfer_hook::TransferHook> for UiTransferHook {
fn from(transfer_hook: extension::transfer_hook::TransferHook) -> Self {
let authority: Option<Pubkey> = transfer_hook.authority.into();
let program_id: Option<Pubkey> = transfer_hook.program_id.into();
Self {
authority: authority.map(|pubkey| pubkey.to_string()),
program_id: program_id.map(|pubkey| pubkey.to_string()),
}
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct UiTransferHookAccount {
pub transferring: bool,
}
impl From<extension::transfer_hook::TransferHookAccount> for UiTransferHookAccount {
fn from(transfer_hook: extension::transfer_hook::TransferHookAccount) -> Self {
Self {
transferring: transfer_hook.transferring.into(),
} }
} }
} }

View File

@ -45,7 +45,7 @@ fetch_program() {
} }
fetch_program token 3.5.0 TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA BPFLoader2111111111111111111111111111111111 fetch_program token 3.5.0 TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA BPFLoader2111111111111111111111111111111111
fetch_program token-2022 0.6.0 TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb BPFLoaderUpgradeab1e11111111111111111111111 fetch_program token-2022 0.9.0 TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb BPFLoaderUpgradeab1e11111111111111111111111
fetch_program memo 1.0.0 Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo BPFLoader1111111111111111111111111111111111 fetch_program memo 1.0.0 Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo BPFLoader1111111111111111111111111111111111
fetch_program memo 3.0.0 MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr BPFLoader2111111111111111111111111111111111 fetch_program memo 3.0.0 MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr BPFLoader2111111111111111111111111111111111
fetch_program associated-token-account 1.1.2 ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL BPFLoader2111111111111111111111111111111111 fetch_program associated-token-account 1.1.2 ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL BPFLoader2111111111111111111111111111111111

View File

@ -78,6 +78,7 @@ features = ["lz4"]
bs58 = { workspace = true } bs58 = { workspace = true }
solana-account-decoder = { workspace = true } solana-account-decoder = { workspace = true }
solana-logger = { workspace = true } solana-logger = { workspace = true }
spl-pod = { workspace = true }
test-case = { workspace = true } test-case = { workspace = true }
[build-dependencies] [build-dependencies]

View File

@ -121,12 +121,12 @@ mod test {
use { use {
super::*, super::*,
solana_sdk::{account::Account, genesis_config::create_genesis_config}, solana_sdk::{account::Account, genesis_config::create_genesis_config},
spl_pod::optional_keys::OptionalNonZeroPubkey,
spl_token_2022::{ spl_token_2022::{
extension::{ extension::{
immutable_owner::ImmutableOwner, memo_transfer::MemoTransfer, immutable_owner::ImmutableOwner, memo_transfer::MemoTransfer,
mint_close_authority::MintCloseAuthority, ExtensionType, StateWithExtensionsMut, mint_close_authority::MintCloseAuthority, ExtensionType, StateWithExtensionsMut,
}, },
pod::OptionalNonZeroPubkey,
solana_program::{program_option::COption, program_pack::Pack}, solana_program::{program_option::COption, program_pack::Pack},
}, },
std::collections::BTreeMap, std::collections::BTreeMap,
@ -291,7 +291,8 @@ mod test {
let mint_authority = Pubkey::new_unique(); let mint_authority = Pubkey::new_unique();
let mint_size = let mint_size =
ExtensionType::get_account_len::<Mint>(&[ExtensionType::MintCloseAuthority]); ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::MintCloseAuthority])
.unwrap();
let mint_base = Mint { let mint_base = Mint {
mint_authority: COption::None, mint_authority: COption::None,
supply: 4242, supply: 4242,
@ -339,10 +340,11 @@ mod test {
delegated_amount: 0, delegated_amount: 0,
close_authority: COption::None, close_authority: COption::None,
}; };
let account_size = ExtensionType::get_account_len::<TokenAccount>(&[ let account_size = ExtensionType::try_calculate_account_len::<TokenAccount>(&[
ExtensionType::ImmutableOwner, ExtensionType::ImmutableOwner,
ExtensionType::MemoTransfer, ExtensionType::MemoTransfer,
]); ])
.unwrap();
let mut account_data = vec![0; account_size]; let mut account_data = vec![0; account_size];
let mut account_state = let mut account_state =
StateWithExtensionsMut::<TokenAccount>::unpack_uninitialized(&mut account_data) StateWithExtensionsMut::<TokenAccount>::unpack_uninitialized(&mut account_data)
@ -381,10 +383,11 @@ mod test {
delegated_amount: 0, delegated_amount: 0,
close_authority: COption::None, close_authority: COption::None,
}; };
let account_size = ExtensionType::get_account_len::<TokenAccount>(&[ let account_size = ExtensionType::try_calculate_account_len::<TokenAccount>(&[
ExtensionType::ImmutableOwner, ExtensionType::ImmutableOwner,
ExtensionType::MemoTransfer, ExtensionType::MemoTransfer,
]); ])
.unwrap();
let mut account_data = vec![0; account_size]; let mut account_data = vec![0; account_size];
let mut account_state = let mut account_state =
StateWithExtensionsMut::<TokenAccount>::unpack_uninitialized(&mut account_data) StateWithExtensionsMut::<TokenAccount>::unpack_uninitialized(&mut account_data)

View File

@ -30,7 +30,7 @@ static SPL_PROGRAMS: &[(Pubkey, Pubkey, &[u8])] = &[
( (
spl_token_2022::ID, spl_token_2022::ID,
solana_sdk::bpf_loader_upgradeable::ID, solana_sdk::bpf_loader_upgradeable::ID,
include_bytes!("programs/spl_token_2022-0.6.0.so"), include_bytes!("programs/spl_token_2022-0.9.0.so"),
), ),
( (
spl_memo_1_0::ID, spl_memo_1_0::ID,

Binary file not shown.

234
programs/sbf/Cargo.lock generated
View File

@ -2918,6 +2918,17 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "num-derive"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
]
[[package]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.42" version = "0.1.42"
@ -2970,15 +2981,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "num_enum"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d829733185c1ca374f17e52b762f24f535ec625d2cc1f070e34c8a9068f341b"
dependencies = [
"num_enum_derive 0.5.9",
]
[[package]] [[package]]
name = "num_enum" name = "num_enum"
version = "0.6.1" version = "0.6.1"
@ -2989,15 +2991,12 @@ dependencies = [
] ]
[[package]] [[package]]
name = "num_enum_derive" name = "num_enum"
version = "0.5.9" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2be1598bf1c313dcdd12092e3f1920f463462525a21b7b4e11b4168353d0123e" checksum = "70bf6736f74634d299d00086f02986875b3c2d924781a6a2cb6c201e73da0ceb"
dependencies = [ dependencies = [
"proc-macro-crate 1.1.3", "num_enum_derive 0.7.0",
"proc-macro2",
"quote",
"syn 1.0.109",
] ]
[[package]] [[package]]
@ -3012,6 +3011,18 @@ dependencies = [
"syn 2.0.37", "syn 2.0.37",
] ]
[[package]]
name = "num_enum_derive"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56ea360eafe1022f7cc56cd7b869ed57330fb2453d0c7831d99b74c65d2f5597"
dependencies = [
"proc-macro-crate 1.1.3",
"proc-macro2",
"quote",
"syn 2.0.37",
]
[[package]] [[package]]
name = "num_threads" name = "num_threads"
version = "0.1.5" version = "0.1.5"
@ -4450,6 +4461,7 @@ dependencies = [
"solana-sdk", "solana-sdk",
"spl-token", "spl-token",
"spl-token-2022", "spl-token-2022",
"spl-token-metadata-interface",
"thiserror", "thiserror",
"zstd", "zstd",
] ]
@ -4478,7 +4490,7 @@ dependencies = [
"lz4", "lz4",
"memmap2", "memmap2",
"modular-bitfield", "modular-bitfield",
"num-derive", "num-derive 0.3.0",
"num-traits", "num-traits",
"num_cpus", "num_cpus",
"num_enum 0.6.1", "num_enum 0.6.1",
@ -4518,7 +4530,7 @@ dependencies = [
"bincode", "bincode",
"bytemuck", "bytemuck",
"log", "log",
"num-derive", "num-derive 0.3.0",
"num-traits", "num-traits",
"rustc_version", "rustc_version",
"serde", "serde",
@ -5241,7 +5253,7 @@ dependencies = [
"log", "log",
"memoffset 0.9.0", "memoffset 0.9.0",
"num-bigint 0.4.4", "num-bigint 0.4.4",
"num-derive", "num-derive 0.3.0",
"num-traits", "num-traits",
"parking_lot 0.12.1", "parking_lot 0.12.1",
"rand 0.8.5", "rand 0.8.5",
@ -5273,7 +5285,7 @@ dependencies = [
"itertools", "itertools",
"libc", "libc",
"log", "log",
"num-derive", "num-derive 0.3.0",
"num-traits", "num-traits",
"percentage", "percentage",
"rand 0.8.5", "rand 0.8.5",
@ -5378,7 +5390,7 @@ dependencies = [
"console", "console",
"dialoguer", "dialoguer",
"log", "log",
"num-derive", "num-derive 0.3.0",
"num-traits", "num-traits",
"parking_lot 0.12.1", "parking_lot 0.12.1",
"qstring", "qstring",
@ -5525,7 +5537,7 @@ dependencies = [
"lz4", "lz4",
"memmap2", "memmap2",
"modular-bitfield", "modular-bitfield",
"num-derive", "num-derive 0.3.0",
"num-traits", "num-traits",
"num_cpus", "num_cpus",
"num_enum 0.6.1", "num_enum 0.6.1",
@ -5695,7 +5707,7 @@ dependencies = [
name = "solana-sbf-rust-error-handling" name = "solana-sbf-rust-error-handling"
version = "1.17.0" version = "1.17.0"
dependencies = [ dependencies = [
"num-derive", "num-derive 0.3.0",
"num-traits", "num-traits",
"solana-program", "solana-program",
"thiserror", "thiserror",
@ -6020,7 +6032,7 @@ dependencies = [
"libsecp256k1 0.6.0", "libsecp256k1 0.6.0",
"log", "log",
"memmap2", "memmap2",
"num-derive", "num-derive 0.3.0",
"num-traits", "num-traits",
"num_enum 0.6.1", "num_enum 0.6.1",
"pbkdf2 0.11.0", "pbkdf2 0.11.0",
@ -6246,7 +6258,7 @@ dependencies = [
"Inflector", "Inflector",
"base64 0.21.4", "base64 0.21.4",
"bincode", "bincode",
"borsh 0.9.3", "borsh 0.10.3",
"bs58", "bs58",
"lazy_static", "lazy_static",
"log", "log",
@ -6409,7 +6421,7 @@ version = "1.17.0"
dependencies = [ dependencies = [
"bincode", "bincode",
"log", "log",
"num-derive", "num-derive 0.3.0",
"num-traits", "num-traits",
"rustc_version", "rustc_version",
"serde", "serde",
@ -6428,7 +6440,7 @@ name = "solana-zk-token-proof-program"
version = "1.17.0" version = "1.17.0"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"num-derive", "num-derive 0.3.0",
"num-traits", "num-traits",
"solana-program-runtime", "solana-program-runtime",
"solana-sdk", "solana-sdk",
@ -6449,7 +6461,7 @@ dependencies = [
"itertools", "itertools",
"lazy_static", "lazy_static",
"merlin", "merlin",
"num-derive", "num-derive 0.3.0",
"num-traits", "num-traits",
"rand 0.7.3", "rand 0.7.3",
"serde", "serde",
@ -6505,13 +6517,13 @@ dependencies = [
[[package]] [[package]]
name = "spl-associated-token-account" name = "spl-associated-token-account"
version = "1.1.3" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978dba3bcbe88d0c2c58366c254d9ea41c5f73357e72fc0bdee4d6b5fc99c8f4" checksum = "385e31c29981488f2820b2022d8e731aae3b02e6e18e2fd854e4c9a94dc44fc3"
dependencies = [ dependencies = [
"assert_matches", "assert_matches",
"borsh 0.9.3", "borsh 0.10.3",
"num-derive", "num-derive 0.4.0",
"num-traits", "num-traits",
"solana-program", "solana-program",
"spl-token", "spl-token",
@ -6520,47 +6532,181 @@ dependencies = [
] ]
[[package]] [[package]]
name = "spl-memo" name = "spl-discriminator"
version = "3.0.1" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0dc6f70db6bacea7ff25870b016a65ba1d1b6013536f08e4fd79a8f9005325" checksum = "cce5d563b58ef1bb2cdbbfe0dfb9ffdc24903b10ae6a4df2d8f425ece375033f"
dependencies = [
"bytemuck",
"solana-program",
"spl-discriminator-derive",
]
[[package]]
name = "spl-discriminator-derive"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b"
dependencies = [
"quote",
"spl-discriminator-syn",
"syn 2.0.37",
]
[[package]]
name = "spl-discriminator-syn"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e5f2044ca42c8938d54d1255ce599c79a1ffd86b677dfab695caa20f9ffc3f2"
dependencies = [
"proc-macro2",
"quote",
"sha2 0.10.7",
"syn 2.0.37",
"thiserror",
]
[[package]]
name = "spl-memo"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f180b03318c3dbab3ef4e1e4d46d5211ae3c780940dd0a28695aba4b59a75a"
dependencies = [ dependencies = [
"solana-program", "solana-program",
] ]
[[package]] [[package]]
name = "spl-token" name = "spl-pod"
version = "3.5.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e85e168a785e82564160dcb87b2a8e04cee9bfd1f4d488c729d53d6a4bd300d" checksum = "2881dddfca792737c0706fa0175345ab282b1b0879c7d877bad129645737c079"
dependencies = [
"borsh 0.10.3",
"bytemuck",
"solana-program",
"solana-zk-token-sdk",
"spl-program-error",
]
[[package]]
name = "spl-program-error"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "249e0318493b6bcf27ae9902600566c689b7dfba9f1bdff5893e92253374e78c"
dependencies = [
"num-derive 0.4.0",
"num-traits",
"solana-program",
"spl-program-error-derive",
"thiserror",
]
[[package]]
name = "spl-program-error-derive"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5269c8e868da17b6552ef35a51355a017bd8e0eae269c201fef830d35fa52c"
dependencies = [
"proc-macro2",
"quote",
"sha2 0.10.7",
"syn 2.0.37",
]
[[package]]
name = "spl-tlv-account-resolution"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "062e148d3eab7b165582757453632ffeef490c02c86a48bfdb4988f63eefb3b9"
dependencies = [
"bytemuck",
"solana-program",
"spl-discriminator",
"spl-pod",
"spl-program-error",
"spl-type-length-value",
]
[[package]]
name = "spl-token"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08459ba1b8f7c1020b4582c4edf0f5c7511a5e099a7a97570c9698d4f2337060"
dependencies = [ dependencies = [
"arrayref", "arrayref",
"bytemuck", "bytemuck",
"num-derive", "num-derive 0.3.0",
"num-traits", "num-traits",
"num_enum 0.5.9", "num_enum 0.6.1",
"solana-program", "solana-program",
"thiserror", "thiserror",
] ]
[[package]] [[package]]
name = "spl-token-2022" name = "spl-token-2022"
version = "0.6.1" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0043b590232c400bad5ee9eb983ced003d15163c4c5d56b090ac6d9a57457b47" checksum = "e4abf34a65ba420584a0c35f3903f8d727d1f13ababbdc3f714c6b065a686e86"
dependencies = [ dependencies = [
"arrayref", "arrayref",
"bytemuck", "bytemuck",
"num-derive", "num-derive 0.4.0",
"num-traits", "num-traits",
"num_enum 0.5.9", "num_enum 0.7.0",
"solana-program", "solana-program",
"solana-zk-token-sdk", "solana-zk-token-sdk",
"spl-memo", "spl-memo",
"spl-pod",
"spl-token", "spl-token",
"spl-token-metadata-interface",
"spl-transfer-hook-interface",
"spl-type-length-value",
"thiserror", "thiserror",
] ]
[[package]]
name = "spl-token-metadata-interface"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c16ce3ba6979645fb7627aa1e435576172dd63088dc7848cb09aa331fa1fe4f"
dependencies = [
"borsh 0.10.3",
"solana-program",
"spl-discriminator",
"spl-pod",
"spl-program-error",
"spl-type-length-value",
]
[[package]]
name = "spl-transfer-hook-interface"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "051d31803f873cabe71aec3c1b849f35248beae5d19a347d93a5c9cccc5d5a9b"
dependencies = [
"arrayref",
"bytemuck",
"solana-program",
"spl-discriminator",
"spl-pod",
"spl-program-error",
"spl-tlv-account-resolution",
"spl-type-length-value",
]
[[package]]
name = "spl-type-length-value"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a468e6f6371f9c69aae760186ea9f1a01c2908351b06a5e0026d21cfc4d7ecac"
dependencies = [
"bytemuck",
"solana-program",
"spl-discriminator",
"spl-pod",
"spl-program-error",
]
[[package]] [[package]]
name = "static_assertions" name = "static_assertions"
version = "1.1.0" version = "1.1.0"

View File

@ -171,8 +171,10 @@ targets = ["x86_64-unknown-linux-gnu"]
# * spl-associated-token-account # * spl-associated-token-account
# * spl-instruction-padding # * spl-instruction-padding
# * spl-memo # * spl-memo
# * spl-pod
# * spl-token # * spl-token
# * spl-token-2022 # * spl-token-2022
# * spl-token-metadata-interface
# #
# They are included indirectly, for example, `account-decoder` depends on # They are included indirectly, for example, `account-decoder` depends on
# #

View File

@ -64,6 +64,7 @@ tokio-util = { workspace = true, features = ["codec", "compat"] }
serial_test = { workspace = true } serial_test = { workspace = true }
solana-net-utils = { workspace = true } solana-net-utils = { workspace = true }
solana-stake-program = { workspace = true } solana-stake-program = { workspace = true }
spl-pod = { workspace = true }
symlink = { workspace = true } symlink = { workspace = true }
[lib] [lib]

View File

@ -4683,12 +4683,12 @@ pub mod tests {
vote_instruction, vote_instruction,
vote_state::{self, Vote, VoteInit, VoteStateVersions, MAX_LOCKOUT_HISTORY}, vote_state::{self, Vote, VoteInit, VoteStateVersions, MAX_LOCKOUT_HISTORY},
}, },
spl_pod::optional_keys::OptionalNonZeroPubkey,
spl_token_2022::{ spl_token_2022::{
extension::{ extension::{
immutable_owner::ImmutableOwner, memo_transfer::MemoTransfer, immutable_owner::ImmutableOwner, memo_transfer::MemoTransfer,
mint_close_authority::MintCloseAuthority, ExtensionType, StateWithExtensionsMut, mint_close_authority::MintCloseAuthority, ExtensionType, StateWithExtensionsMut,
}, },
pod::OptionalNonZeroPubkey,
solana_program::{program_option::COption, pubkey::Pubkey as SplTokenPubkey}, solana_program::{program_option::COption, pubkey::Pubkey as SplTokenPubkey},
state::{AccountState as TokenAccountState, Mint}, state::{AccountState as TokenAccountState, Mint},
}, },
@ -7439,10 +7439,11 @@ pub mod tests {
delegated_amount: 30, delegated_amount: 30,
close_authority: COption::Some(owner), close_authority: COption::Some(owner),
}; };
let account_size = ExtensionType::get_account_len::<TokenAccount>(&[ let account_size = ExtensionType::try_calculate_account_len::<TokenAccount>(&[
ExtensionType::ImmutableOwner, ExtensionType::ImmutableOwner,
ExtensionType::MemoTransfer, ExtensionType::MemoTransfer,
]); ])
.unwrap();
let mut account_data = vec![0; account_size]; let mut account_data = vec![0; account_size];
let mut account_state = let mut account_state =
StateWithExtensionsMut::<TokenAccount>::unpack_uninitialized(&mut account_data) StateWithExtensionsMut::<TokenAccount>::unpack_uninitialized(&mut account_data)
@ -7466,8 +7467,10 @@ pub mod tests {
bank.store_account(&token_account_pubkey, &token_account); bank.store_account(&token_account_pubkey, &token_account);
// Add the mint // Add the mint
let mint_size = let mint_size = ExtensionType::try_calculate_account_len::<Mint>(&[
ExtensionType::get_account_len::<Mint>(&[ExtensionType::MintCloseAuthority]); ExtensionType::MintCloseAuthority,
])
.unwrap();
let mint_base = Mint { let mint_base = Mint {
mint_authority: COption::Some(owner), mint_authority: COption::Some(owner),
supply: 500, supply: 500,
@ -7931,10 +7934,11 @@ pub mod tests {
delegated_amount: 30, delegated_amount: 30,
close_authority: COption::Some(owner), close_authority: COption::Some(owner),
}; };
let account_size = ExtensionType::get_account_len::<TokenAccount>(&[ let account_size = ExtensionType::try_calculate_account_len::<TokenAccount>(&[
ExtensionType::ImmutableOwner, ExtensionType::ImmutableOwner,
ExtensionType::MemoTransfer, ExtensionType::MemoTransfer,
]); ])
.unwrap();
let mut account_data = vec![0; account_size]; let mut account_data = vec![0; account_size];
let mut account_state = let mut account_state =
StateWithExtensionsMut::<TokenAccount>::unpack_uninitialized(&mut account_data) StateWithExtensionsMut::<TokenAccount>::unpack_uninitialized(&mut account_data)
@ -7957,8 +7961,10 @@ pub mod tests {
}); });
bank.store_account(&token_account_pubkey, &token_account); bank.store_account(&token_account_pubkey, &token_account);
let mint_size = let mint_size = ExtensionType::try_calculate_account_len::<Mint>(&[
ExtensionType::get_account_len::<Mint>(&[ExtensionType::MintCloseAuthority]); ExtensionType::MintCloseAuthority,
])
.unwrap();
let mint_base = Mint { let mint_base = Mint {
mint_authority: COption::Some(owner), mint_authority: COption::Some(owner),
supply: 500, supply: 500,

View File

@ -13,8 +13,7 @@ edition = { workspace = true }
Inflector = { workspace = true } Inflector = { workspace = true }
base64 = { workspace = true } base64 = { workspace = true }
bincode = { workspace = true } bincode = { workspace = true }
# NOTE: Use the workspace version once spl-associated-token-account uses borsh 0.10. borsh = { workspace = true }
borsh0-9 = { package = "borsh", version = "0.9.3" }
bs58 = { workspace = true } bs58 = { workspace = true }
lazy_static = { workspace = true } lazy_static = { workspace = true }
log = { workspace = true } log = { workspace = true }

View File

@ -2,7 +2,7 @@ use {
crate::parse_instruction::{ crate::parse_instruction::{
check_num_accounts, ParsableProgram, ParseInstructionError, ParsedInstructionEnum, check_num_accounts, ParsableProgram, ParseInstructionError, ParsedInstructionEnum,
}, },
borsh0_9::BorshDeserialize, borsh::BorshDeserialize,
serde_json::json, serde_json::json,
solana_sdk::{instruction::CompiledInstruction, message::AccountKeys, pubkey::Pubkey}, solana_sdk::{instruction::CompiledInstruction, message::AccountKeys, pubkey::Pubkey},
spl_associated_token_account::instruction::AssociatedTokenAccountInstruction, spl_associated_token_account::instruction::AssociatedTokenAccountInstruction,

View File

@ -3,9 +3,10 @@ use {
check_num_accounts, ParsableProgram, ParseInstructionError, ParsedInstructionEnum, check_num_accounts, ParsableProgram, ParseInstructionError, ParsedInstructionEnum,
}, },
extension::{ extension::{
confidential_transfer::*, cpi_guard::*, default_account_state::*, interest_bearing_mint::*, confidential_transfer::*, confidential_transfer_fee::*, cpi_guard::*,
memo_transfer::*, mint_close_authority::*, permanent_delegate::*, reallocate::*, default_account_state::*, interest_bearing_mint::*, memo_transfer::*, metadata_pointer::*,
transfer_fee::*, mint_close_authority::*, permanent_delegate::*, reallocate::*, transfer_fee::*,
transfer_hook::*,
}, },
serde_json::{json, Map, Value}, serde_json::{json, Map, Value},
solana_account_decoder::parse_token::{token_amount_to_ui_amount, UiAccountState}, solana_account_decoder::parse_token::{token_amount_to_ui_amount, UiAccountState},
@ -229,7 +230,10 @@ pub fn parse_token(
| AuthorityType::CloseMint | AuthorityType::CloseMint
| AuthorityType::InterestRate | AuthorityType::InterestRate
| AuthorityType::PermanentDelegate | AuthorityType::PermanentDelegate
| AuthorityType::ConfidentialTransferMint => "mint", | AuthorityType::ConfidentialTransferMint
| AuthorityType::TransferHookProgramId
| AuthorityType::ConfidentialTransferFeeConfig
| AuthorityType::MetadataPointer => "mint",
AuthorityType::AccountOwner | AuthorityType::CloseAccount => "account", AuthorityType::AccountOwner | AuthorityType::CloseAccount => "account",
}; };
let mut value = json!({ let mut value = json!({
@ -590,6 +594,62 @@ pub fn parse_token(
account_keys, account_keys,
) )
} }
TokenInstruction::TransferHookExtension => {
if instruction.data.len() < 2 {
return Err(ParseInstructionError::InstructionNotParsable(
ParsableProgram::SplToken,
));
}
parse_transfer_hook_instruction(
&instruction.data[1..],
&instruction.accounts,
account_keys,
)
}
TokenInstruction::ConfidentialTransferFeeExtension => {
if instruction.data.len() < 2 {
return Err(ParseInstructionError::InstructionNotParsable(
ParsableProgram::SplToken,
));
}
parse_confidential_transfer_fee_instruction(
&instruction.data[1..],
&instruction.accounts,
account_keys,
)
}
TokenInstruction::WithdrawExcessLamports => {
check_num_token_accounts(&instruction.accounts, 3)?;
let mut value = json!({
"source": account_keys[instruction.accounts[0] as usize].to_string(),
"destination": account_keys[instruction.accounts[1] as usize].to_string(),
});
let map = value.as_object_mut().unwrap();
parse_signers(
map,
2,
account_keys,
&instruction.accounts,
"authority",
"multisigAuthority",
);
Ok(ParsedInstructionEnum {
instruction_type: "withdrawExcessLamports".to_string(),
info: value,
})
}
TokenInstruction::MetadataPointerExtension => {
if instruction.data.len() < 2 {
return Err(ParseInstructionError::InstructionNotParsable(
ParsableProgram::SplToken,
));
}
parse_metadata_pointer_instruction(
&instruction.data[1..],
&instruction.accounts,
account_keys,
)
}
} }
} }
@ -606,6 +666,9 @@ pub enum UiAuthorityType {
InterestRate, InterestRate,
PermanentDelegate, PermanentDelegate,
ConfidentialTransferMint, ConfidentialTransferMint,
TransferHookProgramId,
ConfidentialTransferFeeConfig,
MetadataPointer,
} }
impl From<AuthorityType> for UiAuthorityType { impl From<AuthorityType> for UiAuthorityType {
@ -621,6 +684,11 @@ impl From<AuthorityType> for UiAuthorityType {
AuthorityType::InterestRate => UiAuthorityType::InterestRate, AuthorityType::InterestRate => UiAuthorityType::InterestRate,
AuthorityType::PermanentDelegate => UiAuthorityType::PermanentDelegate, AuthorityType::PermanentDelegate => UiAuthorityType::PermanentDelegate,
AuthorityType::ConfidentialTransferMint => UiAuthorityType::ConfidentialTransferMint, AuthorityType::ConfidentialTransferMint => UiAuthorityType::ConfidentialTransferMint,
AuthorityType::TransferHookProgramId => UiAuthorityType::TransferHookProgramId,
AuthorityType::ConfidentialTransferFeeConfig => {
UiAuthorityType::ConfidentialTransferFeeConfig
}
AuthorityType::MetadataPointer => UiAuthorityType::MetadataPointer,
} }
} }
} }
@ -642,6 +710,12 @@ pub enum UiExtensionType {
CpiGuard, CpiGuard,
PermanentDelegate, PermanentDelegate,
NonTransferableAccount, NonTransferableAccount,
TransferHook,
TransferHookAccount,
ConfidentialTransferFeeConfig,
ConfidentialTransferFeeAmount,
MetadataPointer,
TokenMetadata,
} }
impl From<ExtensionType> for UiExtensionType { impl From<ExtensionType> for UiExtensionType {
@ -663,6 +737,16 @@ impl From<ExtensionType> for UiExtensionType {
ExtensionType::CpiGuard => UiExtensionType::CpiGuard, ExtensionType::CpiGuard => UiExtensionType::CpiGuard,
ExtensionType::PermanentDelegate => UiExtensionType::PermanentDelegate, ExtensionType::PermanentDelegate => UiExtensionType::PermanentDelegate,
ExtensionType::NonTransferableAccount => UiExtensionType::NonTransferableAccount, ExtensionType::NonTransferableAccount => UiExtensionType::NonTransferableAccount,
ExtensionType::TransferHook => UiExtensionType::TransferHook,
ExtensionType::TransferHookAccount => UiExtensionType::TransferHookAccount,
ExtensionType::ConfidentialTransferFeeConfig => {
UiExtensionType::ConfidentialTransferFeeConfig
}
ExtensionType::ConfidentialTransferFeeAmount => {
UiExtensionType::ConfidentialTransferFeeAmount
}
ExtensionType::MetadataPointer => UiExtensionType::MetadataPointer,
ExtensionType::TokenMetadata => UiExtensionType::TokenMetadata,
} }
} }
} }

View File

@ -192,8 +192,8 @@ pub(in crate::parse_token) fn parse_confidential_transfer_instruction(
let proof_instruction_offset: i8 = transfer_data.proof_instruction_offset; let proof_instruction_offset: i8 = transfer_data.proof_instruction_offset;
let mut value = json!({ let mut value = json!({
"source": account_keys[account_indexes[0] as usize].to_string(), "source": account_keys[account_indexes[0] as usize].to_string(),
"destination": account_keys[account_indexes[1] as usize].to_string(), "mint": account_keys[account_indexes[1] as usize].to_string(),
"mint": account_keys[account_indexes[2] as usize].to_string(), "destination": account_keys[account_indexes[2] as usize].to_string(),
"instructionsSysvar": account_keys[account_indexes[3] as usize].to_string(), "instructionsSysvar": account_keys[account_indexes[3] as usize].to_string(),
"newSourceDecryptableAvailableBalance": format!("{}", transfer_data.new_source_decryptable_available_balance), "newSourceDecryptableAvailableBalance": format!("{}", transfer_data.new_source_decryptable_available_balance),
"proofInstructionOffset": proof_instruction_offset, "proofInstructionOffset": proof_instruction_offset,
@ -322,85 +322,37 @@ pub(in crate::parse_token) fn parse_confidential_transfer_instruction(
info: value, info: value,
}) })
} }
ConfidentialTransferInstruction::WithdrawWithheldTokensFromMint => { ConfidentialTransferInstruction::TransferWithSplitProofs => {
check_num_token_accounts(account_indexes, 4)?; check_num_token_accounts(account_indexes, 7)?;
let withdraw_withheld_data: WithdrawWithheldTokensFromMintData = let transfer_data: TransferWithSplitProofsInstructionData =
*decode_instruction_data(instruction_data).map_err(|_| { *decode_instruction_data(instruction_data).map_err(|_| {
ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken) ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken)
})?; })?;
let proof_instruction_offset: i8 = withdraw_withheld_data.proof_instruction_offset;
let mut value = json!({ let mut value = json!({
"mint": account_keys[account_indexes[0] as usize].to_string(), "source": account_keys[account_indexes[0] as usize].to_string(),
"feeRecipient": account_keys[account_indexes[1] as usize].to_string(), "mint": account_keys[account_indexes[1] as usize].to_string(),
"instructionsSysvar": account_keys[account_indexes[2] as usize].to_string(), "destination": account_keys[account_indexes[2] as usize].to_string(),
"proofInstructionOffset": proof_instruction_offset, "ciphertextCommitmentEqualityContext": account_keys[account_indexes[3] as usize].to_string(),
"batchedGroupedCiphertext2HandlesValidityContext": account_keys[account_indexes[4] as usize].to_string(),
"batchedRangeProofContext": account_keys[account_indexes[5] as usize].to_string(),
"owner": account_keys[account_indexes[6] as usize].to_string(),
"newSourceDecryptableAvailableBalance": format!("{}", transfer_data.new_source_decryptable_available_balance),
"noOpOnUninitializedSplitContextState": bool::from(transfer_data.no_op_on_uninitialized_split_context_state),
"closeSplitContextStateOnExecution": bool::from(transfer_data.close_split_context_state_on_execution),
}); });
let map = value.as_object_mut().unwrap(); let map = value.as_object_mut().unwrap();
parse_signers( if transfer_data.close_split_context_state_on_execution.into() {
map, map.insert(
3, "lamportDestination".to_string(),
account_keys, json!(account_keys[account_indexes[7] as usize].to_string()),
account_indexes, );
"withdrawWithheldAuthority", map.insert(
"multisigWithdrawWithheldAuthority", "contextStateOwner".to_string(),
); json!(account_keys[account_indexes[8] as usize].to_string()),
Ok(ParsedInstructionEnum { );
instruction_type: "withdrawWithheldConfidentialTransferTokensFromMint".to_string(),
info: value,
})
}
ConfidentialTransferInstruction::WithdrawWithheldTokensFromAccounts => {
let withdraw_withheld_data: WithdrawWithheldTokensFromAccountsData =
*decode_instruction_data(instruction_data).map_err(|_| {
ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken)
})?;
let num_token_accounts = withdraw_withheld_data.num_token_accounts;
check_num_token_accounts(account_indexes, 4 + num_token_accounts as usize)?;
let proof_instruction_offset: i8 = withdraw_withheld_data.proof_instruction_offset;
let mut value = json!({
"mint": account_keys[account_indexes[0] as usize].to_string(),
"feeRecipient": account_keys[account_indexes[1] as usize].to_string(),
"instructionsSysvar": account_keys[account_indexes[2] as usize].to_string(),
"proofInstructionOffset": proof_instruction_offset,
});
let map = value.as_object_mut().unwrap();
let mut source_accounts: Vec<String> = vec![];
let first_source_account_index = account_indexes
.len()
.saturating_sub(num_token_accounts as usize);
for i in account_indexes[first_source_account_index..].iter() {
source_accounts.push(account_keys[*i as usize].to_string());
} }
map.insert("sourceAccounts".to_string(), json!(source_accounts));
parse_signers(
map,
3,
account_keys,
&account_indexes[..first_source_account_index],
"withdrawWithheldAuthority",
"multisigWithdrawWithheldAuthority",
);
Ok(ParsedInstructionEnum { Ok(ParsedInstructionEnum {
instruction_type: "withdrawWithheldConfidentialTransferTokensFromAccounts" instruction_type: "confidentialTransferWithSplitProofs".to_string(),
.to_string(),
info: value,
})
}
ConfidentialTransferInstruction::HarvestWithheldTokensToMint => {
check_num_token_accounts(account_indexes, 1)?;
let mut value = json!({
"mint": account_keys[account_indexes[0] as usize].to_string(),
});
let map = value.as_object_mut().unwrap();
let mut source_accounts: Vec<String> = vec![];
for i in account_indexes.iter().skip(1) {
source_accounts.push(account_keys[*i as usize].to_string());
}
map.insert("sourceAccounts".to_string(), json!(source_accounts));
Ok(ParsedInstructionEnum {
instruction_type: "harvestWithheldConfidentialTransferTokensToMint".to_string(),
info: value, info: value,
}) })
} }

View File

@ -0,0 +1,159 @@
use {
super::*,
solana_account_decoder::parse_token_extension::UiConfidentialTransferFeeConfig,
spl_token_2022::{
extension::confidential_transfer_fee::{instruction::*, ConfidentialTransferFeeConfig},
instruction::{decode_instruction_data, decode_instruction_type},
},
};
pub(in crate::parse_token) fn parse_confidential_transfer_fee_instruction(
instruction_data: &[u8],
account_indexes: &[u8],
account_keys: &AccountKeys,
) -> Result<ParsedInstructionEnum, ParseInstructionError> {
match decode_instruction_type(instruction_data)
.map_err(|_| ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken))?
{
ConfidentialTransferFeeInstruction::InitializeConfidentialTransferFeeConfig => {
check_num_token_accounts(account_indexes, 1)?;
let confidential_transfer_mint: ConfidentialTransferFeeConfig =
*decode_instruction_data(instruction_data).map_err(|_| {
ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken)
})?;
let confidential_transfer_mint: UiConfidentialTransferFeeConfig =
confidential_transfer_mint.into();
let mut value = json!({
"mint": account_keys[account_indexes[0] as usize].to_string(),
});
let map = value.as_object_mut().unwrap();
map.append(json!(confidential_transfer_mint).as_object_mut().unwrap());
Ok(ParsedInstructionEnum {
instruction_type: "initializeConfidentialTransferFeeConfig".to_string(),
info: value,
})
}
ConfidentialTransferFeeInstruction::WithdrawWithheldTokensFromMint => {
check_num_token_accounts(account_indexes, 4)?;
let withdraw_withheld_data: WithdrawWithheldTokensFromMintData =
*decode_instruction_data(instruction_data).map_err(|_| {
ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken)
})?;
let proof_instruction_offset: i8 = withdraw_withheld_data.proof_instruction_offset;
let mut value = json!({
"mint": account_keys[account_indexes[0] as usize].to_string(),
"feeRecipient": account_keys[account_indexes[1] as usize].to_string(),
"instructionsSysvar": account_keys[account_indexes[2] as usize].to_string(),
"proofInstructionOffset": proof_instruction_offset,
});
let map = value.as_object_mut().unwrap();
parse_signers(
map,
3,
account_keys,
account_indexes,
"withdrawWithheldAuthority",
"multisigWithdrawWithheldAuthority",
);
Ok(ParsedInstructionEnum {
instruction_type: "withdrawWithheldConfidentialTransferTokensFromMint".to_string(),
info: value,
})
}
ConfidentialTransferFeeInstruction::WithdrawWithheldTokensFromAccounts => {
let withdraw_withheld_data: WithdrawWithheldTokensFromAccountsData =
*decode_instruction_data(instruction_data).map_err(|_| {
ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken)
})?;
let num_token_accounts = withdraw_withheld_data.num_token_accounts;
check_num_token_accounts(account_indexes, 4 + num_token_accounts as usize)?;
let proof_instruction_offset: i8 = withdraw_withheld_data.proof_instruction_offset;
let mut value = json!({
"mint": account_keys[account_indexes[0] as usize].to_string(),
"feeRecipient": account_keys[account_indexes[1] as usize].to_string(),
"instructionsSysvar": account_keys[account_indexes[2] as usize].to_string(),
"proofInstructionOffset": proof_instruction_offset,
});
let map = value.as_object_mut().unwrap();
let mut source_accounts: Vec<String> = vec![];
let first_source_account_index = account_indexes
.len()
.saturating_sub(num_token_accounts as usize);
for i in account_indexes[first_source_account_index..].iter() {
source_accounts.push(account_keys[*i as usize].to_string());
}
map.insert("sourceAccounts".to_string(), json!(source_accounts));
parse_signers(
map,
3,
account_keys,
&account_indexes[..first_source_account_index],
"withdrawWithheldAuthority",
"multisigWithdrawWithheldAuthority",
);
Ok(ParsedInstructionEnum {
instruction_type: "withdrawWithheldConfidentialTransferTokensFromAccounts"
.to_string(),
info: value,
})
}
ConfidentialTransferFeeInstruction::HarvestWithheldTokensToMint => {
check_num_token_accounts(account_indexes, 1)?;
let mut value = json!({
"mint": account_keys[account_indexes[0] as usize].to_string(),
});
let map = value.as_object_mut().unwrap();
let mut source_accounts: Vec<String> = vec![];
for i in account_indexes.iter().skip(1) {
source_accounts.push(account_keys[*i as usize].to_string());
}
map.insert("sourceAccounts".to_string(), json!(source_accounts));
Ok(ParsedInstructionEnum {
instruction_type: "harvestWithheldConfidentialTransferTokensToMint".to_string(),
info: value,
})
}
ConfidentialTransferFeeInstruction::EnableHarvestToMint => {
check_num_token_accounts(account_indexes, 2)?;
let mut value = json!({
"account": account_keys[account_indexes[0] as usize].to_string(),
});
let map = value.as_object_mut().unwrap();
parse_signers(
map,
1,
account_keys,
account_indexes,
"owner",
"multisigOwner",
);
Ok(ParsedInstructionEnum {
instruction_type: "enableConfidentialTransferFeeHarvestToMint".to_string(),
info: value,
})
}
ConfidentialTransferFeeInstruction::DisableHarvestToMint => {
check_num_token_accounts(account_indexes, 2)?;
let mut value = json!({
"account": account_keys[account_indexes[0] as usize].to_string(),
});
let map = value.as_object_mut().unwrap();
parse_signers(
map,
1,
account_keys,
account_indexes,
"owner",
"multisigOwner",
);
Ok(ParsedInstructionEnum {
instruction_type: "disableConfidentialTransferFeeHarvestToMint".to_string(),
info: value,
})
}
}
}

View File

@ -0,0 +1,192 @@
use {
super::*,
spl_token_2022::{
extension::metadata_pointer::instruction::*,
instruction::{decode_instruction_data, decode_instruction_type},
},
};
pub(in crate::parse_token) fn parse_metadata_pointer_instruction(
instruction_data: &[u8],
account_indexes: &[u8],
account_keys: &AccountKeys,
) -> Result<ParsedInstructionEnum, ParseInstructionError> {
match decode_instruction_type(instruction_data)
.map_err(|_| ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken))?
{
MetadataPointerInstruction::Initialize => {
check_num_token_accounts(account_indexes, 1)?;
let InitializeInstructionData {
authority,
metadata_address,
} = *decode_instruction_data(instruction_data).map_err(|_| {
ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken)
})?;
let mut value = json!({
"mint": account_keys[account_indexes[0] as usize].to_string(),
});
let map = value.as_object_mut().unwrap();
if let Some(authority) = Option::<Pubkey>::from(authority) {
map.insert("authority".to_string(), json!(authority.to_string()));
}
if let Some(metadata_address) = Option::<Pubkey>::from(metadata_address) {
map.insert(
"metadataAddress".to_string(),
json!(metadata_address.to_string()),
);
}
Ok(ParsedInstructionEnum {
instruction_type: "initializeMetadataPointer".to_string(),
info: value,
})
}
MetadataPointerInstruction::Update => {
check_num_token_accounts(account_indexes, 2)?;
let UpdateInstructionData { metadata_address } =
*decode_instruction_data(instruction_data).map_err(|_| {
ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken)
})?;
let mut value = json!({
"mint": account_keys[account_indexes[0] as usize].to_string(),
});
let map = value.as_object_mut().unwrap();
if let Some(metadata_address) = Option::<Pubkey>::from(metadata_address) {
map.insert(
"metadataAddress".to_string(),
json!(metadata_address.to_string()),
);
}
parse_signers(
map,
1,
account_keys,
account_indexes,
"authority",
"multisigAuthority",
);
Ok(ParsedInstructionEnum {
instruction_type: "updateMetadataPointer".to_string(),
info: value,
})
}
}
}
#[cfg(test)]
mod test {
use {
super::*, crate::parse_token::test::*, solana_sdk::pubkey::Pubkey,
spl_token_2022::solana_program::message::Message,
};
#[test]
fn test_parse_metadata_pointer_instruction() {
let mint_pubkey = Pubkey::new_unique();
let authority = Pubkey::new_unique();
let metadata_address = Pubkey::new_unique();
// Initialize variations
let init_ix = initialize(
&spl_token_2022::id(),
&mint_pubkey,
Some(authority),
Some(metadata_address),
)
.unwrap();
let message = Message::new(&[init_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(
&compiled_instruction,
&AccountKeys::new(&message.account_keys, None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "initializeMetadataPointer".to_string(),
info: json!({
"mint": mint_pubkey.to_string(),
"authority": authority.to_string(),
"metadataAddress": metadata_address.to_string(),
})
}
);
let init_ix = initialize(&spl_token_2022::id(), &mint_pubkey, None, None).unwrap();
let message = Message::new(&[init_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(
&compiled_instruction,
&AccountKeys::new(&message.account_keys, None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "initializeMetadataPointer".to_string(),
info: json!({
"mint": mint_pubkey.to_string(),
})
}
);
// Single owner Update
let update_ix = update(
&spl_token_2022::id(),
&mint_pubkey,
&authority,
&[],
Some(metadata_address),
)
.unwrap();
let message = Message::new(&[update_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(
&compiled_instruction,
&AccountKeys::new(&message.account_keys, None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "updateMetadataPointer".to_string(),
info: json!({
"mint": mint_pubkey.to_string(),
"authority": authority.to_string(),
"metadataAddress": metadata_address.to_string(),
})
}
);
// Multisig Update
let multisig_pubkey = Pubkey::new_unique();
let multisig_signer0 = Pubkey::new_unique();
let multisig_signer1 = Pubkey::new_unique();
let update_ix = update(
&spl_token_2022::id(),
&mint_pubkey,
&multisig_pubkey,
&[&multisig_signer0, &multisig_signer1],
Some(metadata_address),
)
.unwrap();
let message = Message::new(&[update_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(
&compiled_instruction,
&AccountKeys::new(&message.account_keys, None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "updateMetadataPointer".to_string(),
info: json!({
"mint": mint_pubkey.to_string(),
"metadataAddress": metadata_address.to_string(),
"multisigAuthority": multisig_pubkey.to_string(),
"signers": vec![
multisig_signer0.to_string(),
multisig_signer1.to_string(),
],
})
}
);
}
}

View File

@ -1,11 +1,14 @@
use super::*; use super::*;
pub(super) mod confidential_transfer; pub(super) mod confidential_transfer;
pub(super) mod confidential_transfer_fee;
pub(super) mod cpi_guard; pub(super) mod cpi_guard;
pub(super) mod default_account_state; pub(super) mod default_account_state;
pub(super) mod interest_bearing_mint; pub(super) mod interest_bearing_mint;
pub(super) mod memo_transfer; pub(super) mod memo_transfer;
pub(super) mod metadata_pointer;
pub(super) mod mint_close_authority; pub(super) mod mint_close_authority;
pub(super) mod permanent_delegate; pub(super) mod permanent_delegate;
pub(super) mod reallocate; pub(super) mod reallocate;
pub(super) mod transfer_fee; pub(super) mod transfer_fee;
pub(super) mod transfer_hook;

View File

@ -0,0 +1,186 @@
use {
super::*,
spl_token_2022::{
extension::transfer_hook::instruction::*,
instruction::{decode_instruction_data, decode_instruction_type},
},
};
pub(in crate::parse_token) fn parse_transfer_hook_instruction(
instruction_data: &[u8],
account_indexes: &[u8],
account_keys: &AccountKeys,
) -> Result<ParsedInstructionEnum, ParseInstructionError> {
match decode_instruction_type(instruction_data)
.map_err(|_| ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken))?
{
TransferHookInstruction::Initialize => {
check_num_token_accounts(account_indexes, 1)?;
let InitializeInstructionData {
authority,
program_id,
} = *decode_instruction_data(instruction_data).map_err(|_| {
ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken)
})?;
let mut value = json!({
"mint": account_keys[account_indexes[0] as usize].to_string(),
});
let map = value.as_object_mut().unwrap();
if let Some(authority) = Option::<Pubkey>::from(authority) {
map.insert("authority".to_string(), json!(authority.to_string()));
}
if let Some(program_id) = Option::<Pubkey>::from(program_id) {
map.insert("programId".to_string(), json!(program_id.to_string()));
}
Ok(ParsedInstructionEnum {
instruction_type: "initializeTransferHook".to_string(),
info: value,
})
}
TransferHookInstruction::Update => {
check_num_token_accounts(account_indexes, 2)?;
let UpdateInstructionData { program_id } = *decode_instruction_data(instruction_data)
.map_err(|_| {
ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken)
})?;
let mut value = json!({
"mint": account_keys[account_indexes[0] as usize].to_string(),
});
let map = value.as_object_mut().unwrap();
if let Some(program_id) = Option::<Pubkey>::from(program_id) {
map.insert("programId".to_string(), json!(program_id.to_string()));
}
parse_signers(
map,
1,
account_keys,
account_indexes,
"authority",
"multisigAuthority",
);
Ok(ParsedInstructionEnum {
instruction_type: "updateTransferHook".to_string(),
info: value,
})
}
}
}
#[cfg(test)]
mod test {
use {
super::*, crate::parse_token::test::*, solana_sdk::pubkey::Pubkey,
spl_token_2022::solana_program::message::Message,
};
#[test]
fn test_parse_transfer_hook_instruction() {
let mint_pubkey = Pubkey::new_unique();
let authority = Pubkey::new_unique();
let program_id = Pubkey::new_unique();
// Initialize variations
let init_ix = initialize(
&spl_token_2022::id(),
&mint_pubkey,
Some(authority),
Some(program_id),
)
.unwrap();
let message = Message::new(&[init_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(
&compiled_instruction,
&AccountKeys::new(&message.account_keys, None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "initializeTransferHook".to_string(),
info: json!({
"mint": mint_pubkey.to_string(),
"authority": authority.to_string(),
"programId": program_id.to_string(),
})
}
);
let init_ix = initialize(&spl_token_2022::id(), &mint_pubkey, None, None).unwrap();
let message = Message::new(&[init_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(
&compiled_instruction,
&AccountKeys::new(&message.account_keys, None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "initializeTransferHook".to_string(),
info: json!({
"mint": mint_pubkey.to_string(),
})
}
);
// Single owner Update
let update_ix = update(
&spl_token_2022::id(),
&mint_pubkey,
&authority,
&[],
Some(program_id),
)
.unwrap();
let message = Message::new(&[update_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(
&compiled_instruction,
&AccountKeys::new(&message.account_keys, None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "updateTransferHook".to_string(),
info: json!({
"mint": mint_pubkey.to_string(),
"authority": authority.to_string(),
"programId": program_id.to_string(),
})
}
);
// Multisig Update
let multisig_pubkey = Pubkey::new_unique();
let multisig_signer0 = Pubkey::new_unique();
let multisig_signer1 = Pubkey::new_unique();
let update_ix = update(
&spl_token_2022::id(),
&mint_pubkey,
&multisig_pubkey,
&[&multisig_signer0, &multisig_signer1],
Some(program_id),
)
.unwrap();
let message = Message::new(&[update_ix], None);
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
assert_eq!(
parse_token(
&compiled_instruction,
&AccountKeys::new(&message.account_keys, None)
)
.unwrap(),
ParsedInstructionEnum {
instruction_type: "updateTransferHook".to_string(),
info: json!({
"mint": mint_pubkey.to_string(),
"programId": program_id.to_string(),
"multisigAuthority": multisig_pubkey.to_string(),
"signers": vec![
multisig_signer0.to_string(),
multisig_signer1.to_string(),
],
})
}
);
}
}