spl: Bump token-2022 to v1 (#34412)
* Update toml and lockfiles * account-decoder: Add group and group member extensions * transaction-status: Add token group + pointer extensions * program-test: Update token-2022 binary
This commit is contained in:
parent
2fd0bae71e
commit
8a8466cd86
|
@ -5259,6 +5259,7 @@ dependencies = [
|
|||
"spl-pod",
|
||||
"spl-token",
|
||||
"spl-token-2022",
|
||||
"spl-token-group-interface",
|
||||
"spl-token-metadata-interface",
|
||||
"thiserror",
|
||||
"zstd",
|
||||
|
@ -7193,6 +7194,12 @@ dependencies = [
|
|||
"syn 2.0.42",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-security-txt"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183"
|
||||
|
||||
[[package]]
|
||||
name = "solana-send-transaction-service"
|
||||
version = "1.18.0"
|
||||
|
@ -7850,9 +7857,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "spl-associated-token-account"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "385e31c29981488f2820b2022d8e731aae3b02e6e18e2fd854e4c9a94dc44fc3"
|
||||
checksum = "992d9c64c2564cc8f63a4b508bf3ebcdf2254b0429b13cd1d31adb6162432a5f"
|
||||
dependencies = [
|
||||
"assert_matches",
|
||||
"borsh 0.10.3",
|
||||
|
@ -7958,9 +7965,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "spl-tlv-account-resolution"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "062e148d3eab7b165582757453632ffeef490c02c86a48bfdb4988f63eefb3b9"
|
||||
checksum = "3f7020347c07892c08560d230fbb8a980316c9e198e22b198b7b9d951ff96047"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"solana-program",
|
||||
|
@ -7987,9 +7994,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "spl-token-2022"
|
||||
version = "0.9.0"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4abf34a65ba420584a0c35f3903f8d727d1f13ababbdc3f714c6b065a686e86"
|
||||
checksum = "d697fac19fd74ff472dfcc13f0b442dd71403178ce1de7b5d16f83a33561c059"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"bytemuck",
|
||||
|
@ -7997,16 +8004,31 @@ dependencies = [
|
|||
"num-traits",
|
||||
"num_enum 0.7.1",
|
||||
"solana-program",
|
||||
"solana-security-txt",
|
||||
"solana-zk-token-sdk",
|
||||
"spl-memo",
|
||||
"spl-pod",
|
||||
"spl-token",
|
||||
"spl-token-group-interface",
|
||||
"spl-token-metadata-interface",
|
||||
"spl-transfer-hook-interface",
|
||||
"spl-type-length-value",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spl-token-group-interface"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b889509d49fa74a4a033ca5dae6c2307e9e918122d97e58562f5c4ffa795c75d"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"solana-program",
|
||||
"spl-discriminator",
|
||||
"spl-pod",
|
||||
"spl-program-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spl-token-metadata-interface"
|
||||
version = "0.2.0"
|
||||
|
@ -8023,9 +8045,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "spl-transfer-hook-interface"
|
||||
version = "0.3.0"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "051d31803f873cabe71aec3c1b849f35248beae5d19a347d93a5c9cccc5d5a9b"
|
||||
checksum = "7aabdb7c471566f6ddcee724beb8618449ea24b399e58d464d6b5bc7db550259"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"bytemuck",
|
||||
|
|
|
@ -389,12 +389,13 @@ solana-zk-keygen = { path = "zk-keygen", version = "=1.18.0" }
|
|||
solana-zk-token-proof-program = { path = "programs/zk-token-proof", version = "=1.18.0" }
|
||||
solana-zk-token-sdk = { path = "zk-token-sdk", version = "=1.18.0" }
|
||||
solana_rbpf = "=0.8.0"
|
||||
spl-associated-token-account = "=2.2.0"
|
||||
spl-associated-token-account = "=2.3.0"
|
||||
spl-instruction-padding = "0.1"
|
||||
spl-memo = "=4.0.0"
|
||||
spl-pod = "=0.1.0"
|
||||
spl-token = "=4.0.0"
|
||||
spl-token-2022 = "=0.9.0"
|
||||
spl-token-2022 = "=1.0.0"
|
||||
spl-token-group-interface = "=0.1.0"
|
||||
spl-token-metadata-interface = "=0.2.0"
|
||||
static_assertions = "1.1.0"
|
||||
stream-cancel = "0.8.2"
|
||||
|
|
|
@ -23,6 +23,7 @@ solana-config-program = { workspace = true }
|
|||
solana-sdk = { workspace = true }
|
||||
spl-token = { workspace = true, features = ["no-entrypoint"] }
|
||||
spl-token-2022 = { workspace = true, features = ["no-entrypoint"] }
|
||||
spl-token-group-interface = { workspace = true }
|
||||
spl-token-metadata-interface = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
zstd = { workspace = true }
|
||||
|
|
|
@ -6,6 +6,7 @@ use {
|
|||
solana_program::pubkey::Pubkey,
|
||||
solana_zk_token_sdk::zk_token_elgamal::pod::ElGamalPubkey,
|
||||
},
|
||||
spl_token_group_interface::state::{TokenGroup, TokenGroupMember},
|
||||
spl_token_metadata_interface::state::TokenMetadata,
|
||||
};
|
||||
|
||||
|
@ -32,6 +33,10 @@ pub enum UiExtension {
|
|||
TransferHookAccount(UiTransferHookAccount),
|
||||
MetadataPointer(UiMetadataPointer),
|
||||
TokenMetadata(UiTokenMetadata),
|
||||
GroupPointer(UiGroupPointer),
|
||||
GroupMemberPointer(UiGroupMemberPointer),
|
||||
TokenGroup(UiTokenGroup),
|
||||
TokenGroupMember(UiTokenGroupMember),
|
||||
UnparseableExtension,
|
||||
}
|
||||
|
||||
|
@ -108,6 +113,22 @@ pub fn parse_extension<S: BaseState>(
|
|||
.get_extension::<extension::transfer_hook::TransferHookAccount>()
|
||||
.map(|&extension| UiExtension::TransferHookAccount(extension.into()))
|
||||
.unwrap_or(UiExtension::UnparseableExtension),
|
||||
ExtensionType::GroupPointer => account
|
||||
.get_extension::<extension::group_pointer::GroupPointer>()
|
||||
.map(|&extension| UiExtension::GroupPointer(extension.into()))
|
||||
.unwrap_or(UiExtension::UnparseableExtension),
|
||||
ExtensionType::GroupMemberPointer => account
|
||||
.get_extension::<extension::group_member_pointer::GroupMemberPointer>()
|
||||
.map(|&extension| UiExtension::GroupMemberPointer(extension.into()))
|
||||
.unwrap_or(UiExtension::UnparseableExtension),
|
||||
ExtensionType::TokenGroup => account
|
||||
.get_extension::<TokenGroup>()
|
||||
.map(|&extension| UiExtension::TokenGroup(extension.into()))
|
||||
.unwrap_or(UiExtension::UnparseableExtension),
|
||||
ExtensionType::TokenGroupMember => account
|
||||
.get_extension::<TokenGroupMember>()
|
||||
.map(|&extension| UiExtension::TokenGroupMember(extension.into()))
|
||||
.unwrap_or(UiExtension::UnparseableExtension),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -481,3 +502,78 @@ impl From<extension::transfer_hook::TransferHookAccount> for UiTransferHookAccou
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UiGroupPointer {
|
||||
pub authority: Option<String>,
|
||||
pub group_address: Option<String>,
|
||||
}
|
||||
|
||||
impl From<extension::group_pointer::GroupPointer> for UiGroupPointer {
|
||||
fn from(group_pointer: extension::group_pointer::GroupPointer) -> Self {
|
||||
let authority: Option<Pubkey> = group_pointer.authority.into();
|
||||
let group_address: Option<Pubkey> = group_pointer.group_address.into();
|
||||
Self {
|
||||
authority: authority.map(|pubkey| pubkey.to_string()),
|
||||
group_address: group_address.map(|pubkey| pubkey.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UiGroupMemberPointer {
|
||||
pub authority: Option<String>,
|
||||
pub member_address: Option<String>,
|
||||
}
|
||||
|
||||
impl From<extension::group_member_pointer::GroupMemberPointer> for UiGroupMemberPointer {
|
||||
fn from(member_pointer: extension::group_member_pointer::GroupMemberPointer) -> Self {
|
||||
let authority: Option<Pubkey> = member_pointer.authority.into();
|
||||
let member_address: Option<Pubkey> = member_pointer.member_address.into();
|
||||
Self {
|
||||
authority: authority.map(|pubkey| pubkey.to_string()),
|
||||
member_address: member_address.map(|pubkey| pubkey.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UiTokenGroup {
|
||||
pub update_authority: Option<String>,
|
||||
pub mint: String,
|
||||
pub size: u32,
|
||||
pub max_size: u32,
|
||||
}
|
||||
|
||||
impl From<TokenGroup> for UiTokenGroup {
|
||||
fn from(token_group: TokenGroup) -> Self {
|
||||
let update_authority: Option<Pubkey> = token_group.update_authority.into();
|
||||
Self {
|
||||
update_authority: update_authority.map(|pubkey| pubkey.to_string()),
|
||||
mint: token_group.mint.to_string(),
|
||||
size: token_group.size.into(),
|
||||
max_size: token_group.max_size.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UiTokenGroupMember {
|
||||
pub mint: String,
|
||||
pub group: String,
|
||||
pub member_number: u32,
|
||||
}
|
||||
|
||||
impl From<TokenGroupMember> for UiTokenGroupMember {
|
||||
fn from(member: TokenGroupMember) -> Self {
|
||||
Self {
|
||||
mint: member.mint.to_string(),
|
||||
group: member.group.to_string(),
|
||||
member_number: member.member_number.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ static SPL_PROGRAMS: &[(Pubkey, Pubkey, &[u8])] = &[
|
|||
(
|
||||
spl_token_2022::ID,
|
||||
solana_sdk::bpf_loader_upgradeable::ID,
|
||||
include_bytes!("programs/spl_token_2022-0.9.0.so"),
|
||||
include_bytes!("programs/spl_token_2022-1.0.0.so"),
|
||||
),
|
||||
(
|
||||
spl_memo_1_0::ID,
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -4670,6 +4670,7 @@ dependencies = [
|
|||
"solana-sdk",
|
||||
"spl-token",
|
||||
"spl-token-2022",
|
||||
"spl-token-group-interface",
|
||||
"spl-token-metadata-interface",
|
||||
"thiserror",
|
||||
"zstd",
|
||||
|
@ -6294,6 +6295,12 @@ dependencies = [
|
|||
"syn 2.0.42",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-security-txt"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183"
|
||||
|
||||
[[package]]
|
||||
name = "solana-send-transaction-service"
|
||||
version = "1.18.0"
|
||||
|
@ -6776,9 +6783,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "spl-associated-token-account"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "385e31c29981488f2820b2022d8e731aae3b02e6e18e2fd854e4c9a94dc44fc3"
|
||||
checksum = "992d9c64c2564cc8f63a4b508bf3ebcdf2254b0429b13cd1d31adb6162432a5f"
|
||||
dependencies = [
|
||||
"assert_matches",
|
||||
"borsh 0.10.3",
|
||||
|
@ -6874,9 +6881,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "spl-tlv-account-resolution"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "062e148d3eab7b165582757453632ffeef490c02c86a48bfdb4988f63eefb3b9"
|
||||
checksum = "3f7020347c07892c08560d230fbb8a980316c9e198e22b198b7b9d951ff96047"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"solana-program",
|
||||
|
@ -6903,9 +6910,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "spl-token-2022"
|
||||
version = "0.9.0"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4abf34a65ba420584a0c35f3903f8d727d1f13ababbdc3f714c6b065a686e86"
|
||||
checksum = "d697fac19fd74ff472dfcc13f0b442dd71403178ce1de7b5d16f83a33561c059"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"bytemuck",
|
||||
|
@ -6913,16 +6920,31 @@ dependencies = [
|
|||
"num-traits",
|
||||
"num_enum 0.7.1",
|
||||
"solana-program",
|
||||
"solana-security-txt",
|
||||
"solana-zk-token-sdk",
|
||||
"spl-memo",
|
||||
"spl-pod",
|
||||
"spl-token",
|
||||
"spl-token-group-interface",
|
||||
"spl-token-metadata-interface",
|
||||
"spl-transfer-hook-interface",
|
||||
"spl-type-length-value",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spl-token-group-interface"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b889509d49fa74a4a033ca5dae6c2307e9e918122d97e58562f5c4ffa795c75d"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"solana-program",
|
||||
"spl-discriminator",
|
||||
"spl-pod",
|
||||
"spl-program-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spl-token-metadata-interface"
|
||||
version = "0.2.0"
|
||||
|
@ -6939,9 +6961,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "spl-transfer-hook-interface"
|
||||
version = "0.3.0"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "051d31803f873cabe71aec3c1b849f35248beae5d19a347d93a5c9cccc5d5a9b"
|
||||
checksum = "7aabdb7c471566f6ddcee724beb8618449ea24b399e58d464d6b5bc7db550259"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"bytemuck",
|
||||
|
|
|
@ -4,9 +4,9 @@ use {
|
|||
},
|
||||
extension::{
|
||||
confidential_transfer::*, confidential_transfer_fee::*, cpi_guard::*,
|
||||
default_account_state::*, interest_bearing_mint::*, memo_transfer::*, metadata_pointer::*,
|
||||
mint_close_authority::*, permanent_delegate::*, reallocate::*, transfer_fee::*,
|
||||
transfer_hook::*,
|
||||
default_account_state::*, group_member_pointer::*, group_pointer::*,
|
||||
interest_bearing_mint::*, memo_transfer::*, metadata_pointer::*, mint_close_authority::*,
|
||||
permanent_delegate::*, reallocate::*, transfer_fee::*, transfer_hook::*,
|
||||
},
|
||||
serde_json::{json, Map, Value},
|
||||
solana_account_decoder::parse_token::{token_amount_to_ui_amount, UiAccountState},
|
||||
|
@ -233,7 +233,9 @@ pub fn parse_token(
|
|||
| AuthorityType::ConfidentialTransferMint
|
||||
| AuthorityType::TransferHookProgramId
|
||||
| AuthorityType::ConfidentialTransferFeeConfig
|
||||
| AuthorityType::MetadataPointer => "mint",
|
||||
| AuthorityType::MetadataPointer
|
||||
| AuthorityType::GroupPointer
|
||||
| AuthorityType::GroupMemberPointer => "mint",
|
||||
AuthorityType::AccountOwner | AuthorityType::CloseAccount => "account",
|
||||
};
|
||||
let mut value = json!({
|
||||
|
@ -650,6 +652,30 @@ pub fn parse_token(
|
|||
account_keys,
|
||||
)
|
||||
}
|
||||
TokenInstruction::GroupPointerExtension => {
|
||||
if instruction.data.len() < 2 {
|
||||
return Err(ParseInstructionError::InstructionNotParsable(
|
||||
ParsableProgram::SplToken,
|
||||
));
|
||||
}
|
||||
parse_group_pointer_instruction(
|
||||
&instruction.data[1..],
|
||||
&instruction.accounts,
|
||||
account_keys,
|
||||
)
|
||||
}
|
||||
TokenInstruction::GroupMemberPointerExtension => {
|
||||
if instruction.data.len() < 2 {
|
||||
return Err(ParseInstructionError::InstructionNotParsable(
|
||||
ParsableProgram::SplToken,
|
||||
));
|
||||
}
|
||||
parse_group_member_pointer_instruction(
|
||||
&instruction.data[1..],
|
||||
&instruction.accounts,
|
||||
account_keys,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -669,6 +695,8 @@ pub enum UiAuthorityType {
|
|||
TransferHookProgramId,
|
||||
ConfidentialTransferFeeConfig,
|
||||
MetadataPointer,
|
||||
GroupPointer,
|
||||
GroupMemberPointer,
|
||||
}
|
||||
|
||||
impl From<AuthorityType> for UiAuthorityType {
|
||||
|
@ -689,6 +717,8 @@ impl From<AuthorityType> for UiAuthorityType {
|
|||
UiAuthorityType::ConfidentialTransferFeeConfig
|
||||
}
|
||||
AuthorityType::MetadataPointer => UiAuthorityType::MetadataPointer,
|
||||
AuthorityType::GroupPointer => UiAuthorityType::GroupPointer,
|
||||
AuthorityType::GroupMemberPointer => UiAuthorityType::GroupMemberPointer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -716,6 +746,10 @@ pub enum UiExtensionType {
|
|||
ConfidentialTransferFeeAmount,
|
||||
MetadataPointer,
|
||||
TokenMetadata,
|
||||
GroupPointer,
|
||||
GroupMemberPointer,
|
||||
TokenGroup,
|
||||
TokenGroupMember,
|
||||
}
|
||||
|
||||
impl From<ExtensionType> for UiExtensionType {
|
||||
|
@ -747,6 +781,10 @@ impl From<ExtensionType> for UiExtensionType {
|
|||
}
|
||||
ExtensionType::MetadataPointer => UiExtensionType::MetadataPointer,
|
||||
ExtensionType::TokenMetadata => UiExtensionType::TokenMetadata,
|
||||
ExtensionType::GroupPointer => UiExtensionType::GroupPointer,
|
||||
ExtensionType::GroupMemberPointer => UiExtensionType::GroupMemberPointer,
|
||||
ExtensionType::TokenGroup => UiExtensionType::TokenGroup,
|
||||
ExtensionType::TokenGroupMember => UiExtensionType::TokenGroupMember,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
use {
|
||||
super::*,
|
||||
spl_token_2022::{
|
||||
extension::group_member_pointer::instruction::*,
|
||||
instruction::{decode_instruction_data, decode_instruction_type},
|
||||
},
|
||||
};
|
||||
|
||||
pub(in crate::parse_token) fn parse_group_member_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))?
|
||||
{
|
||||
GroupMemberPointerInstruction::Initialize => {
|
||||
check_num_token_accounts(account_indexes, 1)?;
|
||||
let InitializeInstructionData {
|
||||
authority,
|
||||
member_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(member_address) = Option::<Pubkey>::from(member_address) {
|
||||
map.insert(
|
||||
"memberAddress".to_string(),
|
||||
json!(member_address.to_string()),
|
||||
);
|
||||
}
|
||||
Ok(ParsedInstructionEnum {
|
||||
instruction_type: "initializeGroupMemberPointer".to_string(),
|
||||
info: value,
|
||||
})
|
||||
}
|
||||
GroupMemberPointerInstruction::Update => {
|
||||
check_num_token_accounts(account_indexes, 2)?;
|
||||
let UpdateInstructionData { member_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(member_address) = Option::<Pubkey>::from(member_address) {
|
||||
map.insert(
|
||||
"memberAddress".to_string(),
|
||||
json!(member_address.to_string()),
|
||||
);
|
||||
}
|
||||
parse_signers(
|
||||
map,
|
||||
1,
|
||||
account_keys,
|
||||
account_indexes,
|
||||
"authority",
|
||||
"multisigAuthority",
|
||||
);
|
||||
Ok(ParsedInstructionEnum {
|
||||
instruction_type: "updateGroupMemberPointer".to_string(),
|
||||
info: value,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use {super::*, solana_sdk::pubkey::Pubkey, spl_token_2022::solana_program::message::Message};
|
||||
|
||||
#[test]
|
||||
fn test_parse_group_member_pointer_instruction() {
|
||||
let mint_pubkey = Pubkey::new_unique();
|
||||
let authority = Pubkey::new_unique();
|
||||
let member_address = Pubkey::new_unique();
|
||||
|
||||
// Initialize variations
|
||||
let init_ix = initialize(
|
||||
&spl_token_2022::id(),
|
||||
&mint_pubkey,
|
||||
Some(authority),
|
||||
Some(member_address),
|
||||
)
|
||||
.unwrap();
|
||||
let mut message = Message::new(&[init_ix], None);
|
||||
let compiled_instruction = &mut message.instructions[0];
|
||||
assert_eq!(
|
||||
parse_token(
|
||||
compiled_instruction,
|
||||
&AccountKeys::new(&message.account_keys, None)
|
||||
)
|
||||
.unwrap(),
|
||||
ParsedInstructionEnum {
|
||||
instruction_type: "initializeGroupMemberPointer".to_string(),
|
||||
info: json!({
|
||||
"mint": mint_pubkey.to_string(),
|
||||
"authority": authority.to_string(),
|
||||
"memberAddress": member_address.to_string(),
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
let init_ix = initialize(&spl_token_2022::id(), &mint_pubkey, None, None).unwrap();
|
||||
let mut message = Message::new(&[init_ix], None);
|
||||
let compiled_instruction = &mut message.instructions[0];
|
||||
assert_eq!(
|
||||
parse_token(
|
||||
compiled_instruction,
|
||||
&AccountKeys::new(&message.account_keys, None)
|
||||
)
|
||||
.unwrap(),
|
||||
ParsedInstructionEnum {
|
||||
instruction_type: "initializeGroupMemberPointer".to_string(),
|
||||
info: json!({
|
||||
"mint": mint_pubkey.to_string(),
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
// Single owner Update
|
||||
let update_ix = update(
|
||||
&spl_token_2022::id(),
|
||||
&mint_pubkey,
|
||||
&authority,
|
||||
&[],
|
||||
Some(member_address),
|
||||
)
|
||||
.unwrap();
|
||||
let mut message = Message::new(&[update_ix], None);
|
||||
let compiled_instruction = &mut message.instructions[0];
|
||||
assert_eq!(
|
||||
parse_token(
|
||||
compiled_instruction,
|
||||
&AccountKeys::new(&message.account_keys, None)
|
||||
)
|
||||
.unwrap(),
|
||||
ParsedInstructionEnum {
|
||||
instruction_type: "updateGroupMemberPointer".to_string(),
|
||||
info: json!({
|
||||
"mint": mint_pubkey.to_string(),
|
||||
"authority": authority.to_string(),
|
||||
"memberAddress": member_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(member_address),
|
||||
)
|
||||
.unwrap();
|
||||
let mut message = Message::new(&[update_ix], None);
|
||||
let compiled_instruction = &mut message.instructions[0];
|
||||
assert_eq!(
|
||||
parse_token(
|
||||
compiled_instruction,
|
||||
&AccountKeys::new(&message.account_keys, None)
|
||||
)
|
||||
.unwrap(),
|
||||
ParsedInstructionEnum {
|
||||
instruction_type: "updateGroupMemberPointer".to_string(),
|
||||
info: json!({
|
||||
"mint": mint_pubkey.to_string(),
|
||||
"memberAddress": member_address.to_string(),
|
||||
"multisigAuthority": multisig_pubkey.to_string(),
|
||||
"signers": vec![
|
||||
multisig_signer0.to_string(),
|
||||
multisig_signer1.to_string(),
|
||||
],
|
||||
})
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
use {
|
||||
super::*,
|
||||
spl_token_2022::{
|
||||
extension::group_pointer::instruction::*,
|
||||
instruction::{decode_instruction_data, decode_instruction_type},
|
||||
},
|
||||
};
|
||||
|
||||
pub(in crate::parse_token) fn parse_group_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))?
|
||||
{
|
||||
GroupPointerInstruction::Initialize => {
|
||||
check_num_token_accounts(account_indexes, 1)?;
|
||||
let InitializeInstructionData {
|
||||
authority,
|
||||
group_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(group_address) = Option::<Pubkey>::from(group_address) {
|
||||
map.insert("groupAddress".to_string(), json!(group_address.to_string()));
|
||||
}
|
||||
Ok(ParsedInstructionEnum {
|
||||
instruction_type: "initializeGroupPointer".to_string(),
|
||||
info: value,
|
||||
})
|
||||
}
|
||||
GroupPointerInstruction::Update => {
|
||||
check_num_token_accounts(account_indexes, 2)?;
|
||||
let UpdateInstructionData { group_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(group_address) = Option::<Pubkey>::from(group_address) {
|
||||
map.insert("groupAddress".to_string(), json!(group_address.to_string()));
|
||||
}
|
||||
parse_signers(
|
||||
map,
|
||||
1,
|
||||
account_keys,
|
||||
account_indexes,
|
||||
"authority",
|
||||
"multisigAuthority",
|
||||
);
|
||||
Ok(ParsedInstructionEnum {
|
||||
instruction_type: "updateGroupPointer".to_string(),
|
||||
info: value,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use {super::*, solana_sdk::pubkey::Pubkey, spl_token_2022::solana_program::message::Message};
|
||||
|
||||
#[test]
|
||||
fn test_parse_group_pointer_instruction() {
|
||||
let mint_pubkey = Pubkey::new_unique();
|
||||
let authority = Pubkey::new_unique();
|
||||
let group_address = Pubkey::new_unique();
|
||||
|
||||
// Initialize variations
|
||||
let init_ix = initialize(
|
||||
&spl_token_2022::id(),
|
||||
&mint_pubkey,
|
||||
Some(authority),
|
||||
Some(group_address),
|
||||
)
|
||||
.unwrap();
|
||||
let mut message = Message::new(&[init_ix], None);
|
||||
let compiled_instruction = &mut message.instructions[0];
|
||||
assert_eq!(
|
||||
parse_token(
|
||||
compiled_instruction,
|
||||
&AccountKeys::new(&message.account_keys, None)
|
||||
)
|
||||
.unwrap(),
|
||||
ParsedInstructionEnum {
|
||||
instruction_type: "initializeGroupPointer".to_string(),
|
||||
info: json!({
|
||||
"mint": mint_pubkey.to_string(),
|
||||
"authority": authority.to_string(),
|
||||
"groupAddress": group_address.to_string(),
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
let init_ix = initialize(&spl_token_2022::id(), &mint_pubkey, None, None).unwrap();
|
||||
let mut message = Message::new(&[init_ix], None);
|
||||
let compiled_instruction = &mut message.instructions[0];
|
||||
assert_eq!(
|
||||
parse_token(
|
||||
compiled_instruction,
|
||||
&AccountKeys::new(&message.account_keys, None)
|
||||
)
|
||||
.unwrap(),
|
||||
ParsedInstructionEnum {
|
||||
instruction_type: "initializeGroupPointer".to_string(),
|
||||
info: json!({
|
||||
"mint": mint_pubkey.to_string(),
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
// Single owner Update
|
||||
let update_ix = update(
|
||||
&spl_token_2022::id(),
|
||||
&mint_pubkey,
|
||||
&authority,
|
||||
&[],
|
||||
Some(group_address),
|
||||
)
|
||||
.unwrap();
|
||||
let mut message = Message::new(&[update_ix], None);
|
||||
let compiled_instruction = &mut message.instructions[0];
|
||||
assert_eq!(
|
||||
parse_token(
|
||||
compiled_instruction,
|
||||
&AccountKeys::new(&message.account_keys, None)
|
||||
)
|
||||
.unwrap(),
|
||||
ParsedInstructionEnum {
|
||||
instruction_type: "updateGroupPointer".to_string(),
|
||||
info: json!({
|
||||
"mint": mint_pubkey.to_string(),
|
||||
"authority": authority.to_string(),
|
||||
"groupAddress": group_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(group_address),
|
||||
)
|
||||
.unwrap();
|
||||
let mut message = Message::new(&[update_ix], None);
|
||||
let compiled_instruction = &mut message.instructions[0];
|
||||
assert_eq!(
|
||||
parse_token(
|
||||
compiled_instruction,
|
||||
&AccountKeys::new(&message.account_keys, None)
|
||||
)
|
||||
.unwrap(),
|
||||
ParsedInstructionEnum {
|
||||
instruction_type: "updateGroupPointer".to_string(),
|
||||
info: json!({
|
||||
"mint": mint_pubkey.to_string(),
|
||||
"groupAddress": group_address.to_string(),
|
||||
"multisigAuthority": multisig_pubkey.to_string(),
|
||||
"signers": vec![
|
||||
multisig_signer0.to_string(),
|
||||
multisig_signer1.to_string(),
|
||||
],
|
||||
})
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@ pub(super) mod confidential_transfer;
|
|||
pub(super) mod confidential_transfer_fee;
|
||||
pub(super) mod cpi_guard;
|
||||
pub(super) mod default_account_state;
|
||||
pub(super) mod group_member_pointer;
|
||||
pub(super) mod group_pointer;
|
||||
pub(super) mod interest_bearing_mint;
|
||||
pub(super) mod memo_transfer;
|
||||
pub(super) mod metadata_pointer;
|
||||
|
|
Loading…
Reference in New Issue