v0.4.8-pre.013

This commit is contained in:
2026-08-08 22:28:17 +02:00
parent f5efce576b
commit 8b831f8692
77 changed files with 15590 additions and 1585 deletions

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/decoder/metadata/metaplex_token_metadata/account.rs
// version: 12
// version: 15
//! Bounded decoding and PDA validation for Metaplex Token Metadata accounts.
@@ -103,6 +103,10 @@ const MAX_NAME_BYTES: usize = 32;
const MAX_SYMBOL_BYTES: usize = 10;
const MAX_URI_BYTES: usize = 200;
const MAX_CREATORS: usize = 5;
const COMPACT_MASTER_EDITION_ACCOUNT_BYTES: usize = 20;
const LEGACY_MASTER_EDITION_ACCOUNT_BYTES: usize = 282;
const COMPACT_EDITION_ACCOUNT_BYTES: usize = 42;
const LEGACY_EDITION_ACCOUNT_BYTES: usize = 241;
const EDITION_MARKER_V1_BITS: u64 = 248;
const MAX_EDITION_MARKER_V2_LEDGER_BYTES: usize = 1_048_576;
@@ -325,6 +329,75 @@ pub fn decoder_metadata_metaplex_token_metadata_decode_metadata_account(
});
}
fn validate_known_account_allocation(
data: &[u8],
serialized_len: usize,
padded_account_lengths: &[usize],
) -> std::result::Result<(), DcMetadataMtmMetadataAccountDecodeError> {
if data.len() == serialized_len {
return std::result::Result::Ok(());
}
if data.len() < serialized_len || !padded_account_lengths.contains(&data.len()) {
return std::result::Result::Err(
DcMetadataMtmMetadataAccountDecodeError::InvalidDataLength,
);
}
if data[serialized_len..].iter().any(|byte| return *byte != 0) {
return std::result::Result::Err(
DcMetadataMtmMetadataAccountDecodeError::InvalidMetadataLayout,
);
}
return std::result::Result::Ok(());
}
fn validate_master_edition_allocation(
data: &[u8],
serialized_len: usize,
padded_account_lengths: &[usize],
) -> std::result::Result<(), DcMetadataMtmMetadataAccountDecodeError> {
if data.len() == serialized_len {
return std::result::Result::Ok(());
}
if data.len() < serialized_len || !padded_account_lengths.contains(&data.len()) {
return std::result::Result::Err(
DcMetadataMtmMetadataAccountDecodeError::InvalidDataLength,
);
}
let trailer_start = match data.len().checked_sub(2) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(
DcMetadataMtmMetadataAccountDecodeError::InvalidDataLength,
);
},
};
if trailer_start < serialized_len {
return std::result::Result::Err(
DcMetadataMtmMetadataAccountDecodeError::InvalidDataLength,
);
}
if data[serialized_len..trailer_start].iter().any(|byte| return *byte != 0) {
return std::result::Result::Err(
DcMetadataMtmMetadataAccountDecodeError::InvalidMetadataLayout,
);
}
let fee_flag = data[trailer_start];
if fee_flag > 1 {
return std::result::Result::Err(
DcMetadataMtmMetadataAccountDecodeError::InvalidMetadataLayout,
);
}
let token_standard = data[trailer_start + 1];
if token_standard != mpl_token_metadata::types::TokenStandard::NonFungible as u8
&& token_standard != mpl_token_metadata::types::TokenStandard::ProgrammableNonFungible as u8
{
return std::result::Result::Err(
DcMetadataMtmMetadataAccountDecodeError::InvalidMetadataLayout,
);
}
return std::result::Result::Ok(());
}
/// Supported edition account layout.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum DcMetadataMtmEditionAccountKind {
@@ -396,7 +469,7 @@ pub fn decoder_metadata_metaplex_token_metadata_decode_edition_account(
if owner_key != expected_owner {
return std::result::Result::Err(DcMetadataMtmMetadataAccountDecodeError::ForeignOwner);
}
if data.is_empty() || data.len() > 128 {
if data.is_empty() || data.len() > LEGACY_MASTER_EDITION_ACCOUNT_BYTES {
return std::result::Result::Err(
DcMetadataMtmMetadataAccountDecodeError::InvalidDataLength,
);
@@ -427,6 +500,14 @@ pub fn decoder_metadata_metaplex_token_metadata_decode_edition_account(
);
},
};
let serialized_len = if value.max_supply.is_some() { 82 } else { 74 };
if let std::result::Result::Err(error) = validate_master_edition_allocation(
data,
serialized_len,
&[LEGACY_MASTER_EDITION_ACCOUNT_BYTES],
) {
return std::result::Result::Err(error);
}
let payload_json = match serde_json::to_value(&value) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => {
@@ -460,6 +541,14 @@ pub fn decoder_metadata_metaplex_token_metadata_decode_edition_account(
);
},
};
let serialized_len = if value.max_supply.is_some() { 18 } else { 10 };
if let std::result::Result::Err(error) = validate_master_edition_allocation(
data,
serialized_len,
&[COMPACT_MASTER_EDITION_ACCOUNT_BYTES, LEGACY_MASTER_EDITION_ACCOUNT_BYTES],
) {
return std::result::Result::Err(error);
}
let payload_json = match serde_json::to_value(&value) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => {
@@ -483,11 +572,6 @@ pub fn decoder_metadata_metaplex_token_metadata_decode_edition_account(
});
}
if key == mpl_token_metadata::types::Key::EditionV1 as u8 {
if data.len() != mpl_token_metadata::accounts::Edition::LEN {
return std::result::Result::Err(
DcMetadataMtmMetadataAccountDecodeError::InvalidDataLength,
);
}
let value = match mpl_token_metadata::accounts::Edition::from_bytes(data) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => {
@@ -496,6 +580,13 @@ pub fn decoder_metadata_metaplex_token_metadata_decode_edition_account(
);
},
};
if let std::result::Result::Err(error) = validate_known_account_allocation(
data,
mpl_token_metadata::accounts::Edition::LEN,
&[COMPACT_EDITION_ACCOUNT_BYTES, LEGACY_EDITION_ACCOUNT_BYTES],
) {
return std::result::Result::Err(error);
}
let payload_json = match serde_json::to_value(&value) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => {
@@ -851,17 +942,21 @@ pub fn decoder_metadata_metaplex_token_metadata_decode_token_record_account(
DcMetadataMtmMetadataAccountDecodeError::InvalidTokenRecordPda,
);
}
let payload_json = match serde_json::to_value(&value) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => {
return std::result::Result::Err(
DcMetadataMtmMetadataAccountDecodeError::ProjectionFailed,
);
},
};
let state = format!("{:?}", value.state);
let delegate = value.delegate.map(|delegate| return delegate.to_string());
let delegate_role = value.delegate_role.as_ref().map(|role| return format!("{role:?}"));
let locked_transfer =
value.locked_transfer.map(|locked_transfer| return locked_transfer.to_string());
let locked = value.state == mpl_token_metadata::types::TokenState::Locked;
let payload_json = serde_json::json!({
"key": "TokenRecord",
"bump": value.bump,
"state": &state,
"rule_set_revision": value.rule_set_revision,
"delegate": &delegate,
"delegate_role": &delegate_role,
"locked_transfer": &locked_transfer,
});
return std::result::Result::Ok(DcMetadataMtmTokenRecordAccountSnapshot {
account: account_key.to_string(),
bump,
@@ -870,11 +965,9 @@ pub fn decoder_metadata_metaplex_token_metadata_decode_token_record_account(
stored_bump: value.bump,
state,
rule_set_revision: value.rule_set_revision,
delegate: value.delegate.map(|delegate| return delegate.to_string()),
delegate,
delegate_role,
locked_transfer: value
.locked_transfer
.map(|locked_transfer| return locked_transfer.to_string()),
locked_transfer,
locked,
payload_json,
});
@@ -1975,6 +2068,179 @@ mod tests {
assert_eq!(edition_snapshot.edition, std::option::Option::Some(u64::MAX));
}
#[test]
fn edition_and_master_edition_accept_only_known_allocations() {
let mint = mpl_token_metadata::ID;
let (account, _) = mpl_token_metadata::accounts::MasterEdition::find_pda(&mint);
let master = mpl_token_metadata::accounts::MasterEdition {
key: mpl_token_metadata::types::Key::MasterEditionV2,
supply: 1,
max_supply: std::option::Option::Some(1),
};
let master_data = match borsh_0_10::to_vec(&master) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
panic!("master edition serialization failed: {error}")
},
};
for allocated_len in [
super::COMPACT_MASTER_EDITION_ACCOUNT_BYTES,
super::LEGACY_MASTER_EDITION_ACCOUNT_BYTES,
] {
let mut padded = master_data.clone();
padded.resize(allocated_len, 0);
assert!(
crate::decoder_metadata_metaplex_token_metadata_decode_edition_account(
&account.to_string(),
kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID,
&mint.to_string(),
padded.as_slice(),
)
.is_ok()
);
}
let edition = mpl_token_metadata::accounts::Edition {
key: mpl_token_metadata::types::Key::EditionV1,
parent: account,
edition: 1,
};
let edition_data = match borsh_0_10::to_vec(&edition) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => panic!("edition serialization failed: {error}"),
};
for allocated_len in
[super::COMPACT_EDITION_ACCOUNT_BYTES, super::LEGACY_EDITION_ACCOUNT_BYTES]
{
let mut padded = edition_data.clone();
padded.resize(allocated_len, 0);
assert!(
crate::decoder_metadata_metaplex_token_metadata_decode_edition_account(
&account.to_string(),
kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID,
&mint.to_string(),
padded.as_slice(),
)
.is_ok()
);
}
let mut unexpected_len = edition_data.clone();
unexpected_len.resize(super::COMPACT_EDITION_ACCOUNT_BYTES + 1, 0);
assert_eq!(
crate::decoder_metadata_metaplex_token_metadata_decode_edition_account(
&account.to_string(),
kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID,
&mint.to_string(),
unexpected_len.as_slice(),
),
std::result::Result::Err(
crate::DcMetadataMtmMetadataAccountDecodeError::InvalidDataLength
),
);
let mut non_zero_padding = edition_data;
non_zero_padding.resize(super::COMPACT_EDITION_ACCOUNT_BYTES, 1);
assert_eq!(
crate::decoder_metadata_metaplex_token_metadata_decode_edition_account(
&account.to_string(),
kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID,
&mint.to_string(),
non_zero_padding.as_slice(),
),
std::result::Result::Err(
crate::DcMetadataMtmMetadataAccountDecodeError::InvalidMetadataLayout
),
);
}
#[test]
fn compact_master_edition_trailer_accepts_pnft_and_rejects_invalid_flags() {
let mint = mpl_token_metadata::ID;
let (account, _) = mpl_token_metadata::accounts::MasterEdition::find_pda(&mint);
let master = mpl_token_metadata::accounts::MasterEdition {
key: mpl_token_metadata::types::Key::MasterEditionV2,
supply: 0,
max_supply: std::option::Option::Some(0),
};
let serialized = match borsh_0_10::to_vec(&master) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
panic!("master edition serialization failed: {error}")
},
};
let mut pnft = serialized.clone();
pnft.resize(super::COMPACT_MASTER_EDITION_ACCOUNT_BYTES, 0);
pnft[super::COMPACT_MASTER_EDITION_ACCOUNT_BYTES - 2] = 1;
pnft[super::COMPACT_MASTER_EDITION_ACCOUNT_BYTES - 1] =
mpl_token_metadata::types::TokenStandard::ProgrammableNonFungible as u8;
let snapshot = match crate::decoder_metadata_metaplex_token_metadata_decode_edition_account(
&account.to_string(),
kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID,
&mint.to_string(),
pnft.as_slice(),
) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
panic!("compact pNFT master edition decode failed: {error}")
},
};
assert_eq!(snapshot.kind, crate::DcMetadataMtmEditionAccountKind::MasterEditionV2);
assert_eq!(snapshot.supply, std::option::Option::Some(0));
assert_eq!(snapshot.max_supply, std::option::Option::Some(0));
let mut invalid_fee_flag = pnft.clone();
invalid_fee_flag[super::COMPACT_MASTER_EDITION_ACCOUNT_BYTES - 2] = 2;
assert_eq!(
crate::decoder_metadata_metaplex_token_metadata_decode_edition_account(
&account.to_string(),
kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID,
&mint.to_string(),
invalid_fee_flag.as_slice(),
),
std::result::Result::Err(
crate::DcMetadataMtmMetadataAccountDecodeError::InvalidMetadataLayout
),
);
let mut invalid_token_standard = pnft;
invalid_token_standard[super::COMPACT_MASTER_EDITION_ACCOUNT_BYTES - 1] =
mpl_token_metadata::types::TokenStandard::Fungible as u8;
assert_eq!(
crate::decoder_metadata_metaplex_token_metadata_decode_edition_account(
&account.to_string(),
kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID,
&mint.to_string(),
invalid_token_standard.as_slice(),
),
std::result::Result::Err(
crate::DcMetadataMtmMetadataAccountDecodeError::InvalidMetadataLayout
),
);
let master_without_limit = mpl_token_metadata::accounts::MasterEdition {
key: mpl_token_metadata::types::Key::MasterEditionV2,
supply: 0,
max_supply: std::option::Option::None,
};
let mut invalid_reserved = match borsh_0_10::to_vec(&master_without_limit) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
panic!("master edition serialization failed: {error}")
},
};
let serialized_len = invalid_reserved.len();
invalid_reserved.resize(super::COMPACT_MASTER_EDITION_ACCOUNT_BYTES, 0);
invalid_reserved[serialized_len] = 1;
invalid_reserved[super::COMPACT_MASTER_EDITION_ACCOUNT_BYTES - 1] =
mpl_token_metadata::types::TokenStandard::ProgrammableNonFungible as u8;
assert_eq!(
crate::decoder_metadata_metaplex_token_metadata_decode_edition_account(
&account.to_string(),
kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID,
&mint.to_string(),
invalid_reserved.as_slice(),
),
std::result::Result::Err(
crate::DcMetadataMtmMetadataAccountDecodeError::InvalidMetadataLayout
),
);
}
#[test]
fn historical_master_edition_v1_and_invalid_boundaries_are_explicit() {
let mint = mpl_token_metadata::ID;
@@ -2218,6 +2484,15 @@ mod tests {
snapshot.locked_transfer,
std::option::Option::Some(mpl_token_metadata::ID.to_string())
);
assert_eq!(
snapshot.payload_json["delegate"],
serde_json::json!(mpl_token_metadata::ID.to_string())
);
assert_eq!(snapshot.payload_json["delegate_role"], serde_json::json!("Transfer"));
assert_eq!(
snapshot.payload_json["locked_transfer"],
serde_json::json!(mpl_token_metadata::ID.to_string())
);
}
#[test]

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/decoder/metadata/metaplex_token_metadata/decoder.rs
// version: 32
// version: 39
//! Exact contextual dispatch for Metaplex Token Metadata.
@@ -633,6 +633,69 @@ mod tests {
);
}
#[test]
fn modern_create_accepts_preexisting_mint_and_transaction_privilege_supersets() {
let decoder = crate::DcMetadataMetaplexTokenMetadataDecoder;
let result = crate::DcApiInstructionDecoder::decode(
&decoder,
&input_with_flags(
modern_create_wire().as_slice(),
&[
(false, true),
(false, true),
(false, true),
(true, true),
(true, true),
(true, true),
(false, false),
(false, false),
(false, false),
],
false,
"modern_create_preexisting_mint",
),
);
assert_eq!(result.status, crate::DcApiDecoderOutcomeStatus::Decoded);
assert_eq!(result.recognized_entry_code.as_deref(), std::option::Option::Some("create"));
}
#[test]
fn modern_mint_accepts_authority_owner_payer_privilege_supersets() {
let decoder = crate::DcMetadataMetaplexTokenMetadataDecoder;
let args = mpl_token_metadata::types::MintArgs::V1 {
amount: 1,
authorization_data: std::option::Option::None,
};
let wire = programmable_wire(crate::DC_METADATA_MTM_MINT_DISCRIMINATOR, &args);
let result = crate::DcApiInstructionDecoder::decode(
&decoder,
&input_with_flags(
wire.as_slice(),
&[
(false, true),
(true, true),
(false, false),
(false, true),
(false, true),
(false, true),
(true, true),
(false, false),
(true, true),
(false, false),
(false, false),
(false, false),
(false, false),
(false, false),
(false, false),
],
false,
"modern_mint_privilege_superset",
),
);
assert_eq!(result.status, crate::DcApiDecoderOutcomeStatus::Decoded);
assert_eq!(result.recognized_entry_code.as_deref(), std::option::Option::Some("mint"));
}
#[test]
fn modern_create_rejects_truncated_invalid_and_suffix_wires() {
let decoder = crate::DcMetadataMetaplexTokenMetadataDecoder;
@@ -661,12 +724,12 @@ mod tests {
&input_with_flags(
modern_create_wire().as_slice(),
&[
(false, true),
(false, false),
(false, true),
(false, true),
(true, false),
(true, true),
(true, false),
(false, false),
(false, false),
(false, false),
(false, false),
@@ -852,6 +915,53 @@ mod tests {
assert!(!v2.observations[0].observation_committed);
}
#[test]
fn modern_print_accepts_transaction_privilege_supersets() {
let decoder = crate::DcMetadataMetaplexTokenMetadataDecoder;
let flags = [
(false, true),
(false, true),
(true, true),
(true, true),
(false, true),
(true, true),
(false, true),
(false, true),
(false, true),
(true, true),
(true, true),
(false, false),
(false, false),
(true, true),
(false, false),
(false, false),
(false, false),
(false, false),
];
let decoded = crate::DcApiInstructionDecoder::decode(
&decoder,
&input_with_flags(
modern_print_wire_v1(1).as_slice(),
&flags,
false,
"modern_print_privilege_superset",
),
);
assert_eq!(decoded.status, crate::DcApiDecoderOutcomeStatus::Decoded);
let mut missing_mint_signature = flags;
missing_mint_signature[2] = (false, true);
let rejected = crate::DcApiInstructionDecoder::decode(
&decoder,
&input_with_flags(
modern_print_wire_v1(1).as_slice(),
&missing_mint_signature,
false,
"modern_print_missing_mint_signature",
),
);
assert_eq!(rejected.status, crate::DcApiDecoderOutcomeStatus::Failed);
}
#[test]
fn modern_print_rejects_truncated_invalid_and_suffix_wires() {
let decoder = crate::DcMetadataMetaplexTokenMetadataDecoder;
@@ -915,10 +1025,10 @@ mod tests {
}
#[test]
fn modern_update_variants_decode_exact_contract() {
fn modern_update_variants_accept_transaction_privilege_supersets() {
let decoder = crate::DcMetadataMetaplexTokenMetadataDecoder;
let flags = [
(true, false),
(true, true),
(false, false),
(false, false),
(false, false),
@@ -1012,13 +1122,13 @@ mod tests {
fn modern_use_verify_and_unverify_decode_exact_contracts() {
let decoder = crate::DcMetadataMetaplexTokenMetadataDecoder;
let use_flags = [
(true, false),
(true, true),
(false, true),
(false, true),
(false, false),
(false, true),
(false, true),
(true, false),
(true, true),
(false, false),
(false, false),
(false, false),
@@ -1081,6 +1191,74 @@ mod tests {
assert!(!unverify.observations[0].observation_committed);
}
#[test]
fn modern_verify_and_unverify_accept_fee_payer_privilege_supersets() {
let decoder = crate::DcMetadataMetaplexTokenMetadataDecoder;
let verify_flags = [
(true, true),
(false, false),
(false, true),
(false, false),
(false, true),
(false, false),
(false, false),
(false, false),
];
let verify = crate::DcApiInstructionDecoder::decode(
&decoder,
&input_with_flags(
modern_verification_wire(
crate::DC_METADATA_MTM_VERIFY_DISCRIMINATOR,
mpl_token_metadata::types::VerificationArgs::CollectionV1,
)
.as_slice(),
&verify_flags,
false,
"modern_verify_fee_payer",
),
);
assert_eq!(verify.status, crate::DcApiDecoderOutcomeStatus::Decoded);
let unverify_flags = [
(true, true),
(false, false),
(false, true),
(false, false),
(false, true),
(false, false),
(false, false),
];
let unverify = crate::DcApiInstructionDecoder::decode(
&decoder,
&input_with_flags(
modern_verification_wire(
crate::DC_METADATA_MTM_UNVERIFY_DISCRIMINATOR,
mpl_token_metadata::types::VerificationArgs::CollectionV1,
)
.as_slice(),
&unverify_flags,
false,
"modern_unverify_fee_payer",
),
);
assert_eq!(unverify.status, crate::DcApiDecoderOutcomeStatus::Decoded);
let mut missing_authority_signature = verify_flags;
missing_authority_signature[0] = (false, true);
let invalid = crate::DcApiInstructionDecoder::decode(
&decoder,
&input_with_flags(
modern_verification_wire(
crate::DC_METADATA_MTM_VERIFY_DISCRIMINATOR,
mpl_token_metadata::types::VerificationArgs::CollectionV1,
)
.as_slice(),
&missing_authority_signature,
false,
"modern_verify_missing_authority_signature",
),
);
assert_eq!(invalid.status, crate::DcApiDecoderOutcomeStatus::Failed);
}
#[test]
fn modern_use_verify_and_unverify_reject_invalid_wires() {
let decoder = crate::DcMetadataMetaplexTokenMetadataDecoder;
@@ -1120,6 +1298,18 @@ mod tests {
),
);
assert_eq!(invalid.status, crate::DcApiDecoderOutcomeStatus::Failed);
let mut readonly_token = use_flags;
readonly_token[2] = (false, false);
let invalid = crate::DcApiInstructionDecoder::decode(
&decoder,
&input_with_flags(
modern_use_wire().as_slice(),
&readonly_token,
false,
"modern_use_readonly_token",
),
);
assert_eq!(invalid.status, crate::DcApiDecoderOutcomeStatus::Failed);
let verify_flags = [
(true, false),
(false, false),
@@ -2261,6 +2451,93 @@ mod tests {
assert_eq!(revoke.observations[0].payload_json["parameters"], "StandardV1");
}
#[test]
fn programmable_delegate_revoke_lock_and_unlock_accept_transaction_privilege_supersets() {
let decoder = crate::DcMetadataMetaplexTokenMetadataDecoder;
let delegate_flags = &[
(false, true),
(false, false),
(false, true),
(false, false),
(false, true),
(false, false),
(false, true),
(true, true),
(true, true),
(false, false),
(false, false),
(false, false),
(false, false),
(false, false),
];
for (wire, path) in [
(
delegate_wire(&mpl_token_metadata::types::DelegateArgs::StakingV1 {
amount: 1,
authorization_data: std::option::Option::None,
}),
"delegate_privilege_superset",
),
(
revoke_wire(&mpl_token_metadata::types::RevokeArgs::StakingV1),
"revoke_privilege_superset",
),
] {
let result = crate::DcApiInstructionDecoder::decode(
&decoder,
&input_with_flags(wire.as_slice(), delegate_flags, false, path),
);
assert_eq!(result.status, crate::DcApiDecoderOutcomeStatus::Decoded);
}
let lock_flags = &[
(true, false),
(true, true),
(false, true),
(false, false),
(false, true),
(false, false),
(false, true),
(true, true),
(false, false),
(false, false),
(false, false),
(false, false),
(false, false),
];
let lock = crate::DcApiInstructionDecoder::decode(
&decoder,
&input_with_flags(
programmable_wire(
crate::DC_METADATA_MTM_LOCK_DISCRIMINATOR,
&mpl_token_metadata::types::LockArgs::V1 {
authorization_data: std::option::Option::None,
},
)
.as_slice(),
lock_flags,
false,
"lock_privilege_superset",
),
);
assert_eq!(lock.status, crate::DcApiDecoderOutcomeStatus::Decoded);
let unlock = crate::DcApiInstructionDecoder::decode(
&decoder,
&input_with_flags(
programmable_wire(
crate::DC_METADATA_MTM_UNLOCK_DISCRIMINATOR,
&mpl_token_metadata::types::UnlockArgs::V1 {
authorization_data: std::option::Option::None,
},
)
.as_slice(),
lock_flags,
false,
"unlock_privilege_superset",
),
);
assert_eq!(unlock.status, crate::DcApiDecoderOutcomeStatus::Decoded);
}
#[test]
fn programmable_delegate_and_revoke_reject_truncated_invalid_and_suffix_wires() {
let decoder = crate::DcMetadataMetaplexTokenMetadataDecoder;

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/decoder/metadata/metaplex_token_metadata/instruction.rs
// version: 28
// version: 34
//! Bounded Metaplex Token Metadata instruction wire decoding.
@@ -1159,26 +1159,18 @@ fn validate_accounts(
accounts.len()
));
}
let mandatory: &[(usize, bool, bool)] = &[
(0, false, true),
(2, true, true),
(3, true, false),
(4, true, true),
(5, true, false),
(6, false, false),
(7, false, false),
(8, false, false),
];
for (index, signer, writable) in mandatory {
let required_privileges: &[(usize, bool, bool)] =
&[(0, false, true), (2, false, true), (3, true, false), (4, true, true)];
for (index, signer, writable) in required_privileges {
let account = match accounts.get(*index) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(format!("create is missing account {index}"));
},
};
if account.signer != *signer || account.writable != *writable {
if (*signer && !account.signer) || (*writable && !account.writable) {
return std::result::Result::Err(format!(
"create account {index} has invalid signer/writable flags"
"create account {index} lacks required signer/writable privileges"
));
}
}
@@ -1190,9 +1182,12 @@ fn validate_accounts(
);
},
};
if master_edition.signer {
if master_edition.account_key.as_str()
!= kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID
&& !master_edition.writable
{
return std::result::Result::Err(
"create master edition account must not sign".to_string(),
"create master edition account lacks required writable privilege".to_string(),
);
}
return std::result::Result::Ok(());
@@ -1204,31 +1199,22 @@ fn validate_accounts(
accounts.len()
));
}
let mandatory: &[(usize, bool, bool)] = &[
(0, false, true),
(2, false, false),
(5, false, true),
(6, true, false),
(8, true, true),
(9, false, false),
(10, false, false),
(11, false, false),
(12, false, false),
];
for (index, signer, writable) in mandatory {
let required_privileges: &[(usize, bool, bool)] =
&[(0, false, true), (5, false, true), (6, true, false), (8, true, true)];
for (index, signer, writable) in required_privileges {
let account = match accounts.get(*index) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(format!("mint is missing account {index}"));
},
};
if account.signer != *signer || account.writable != *writable {
if (*signer && !account.signer) || (*writable && !account.writable) {
return std::result::Result::Err(format!(
"mint account {index} has invalid signer/writable flags"
"mint account {index} lacks required signer/writable privileges"
));
}
}
for index in [1_usize, 3_usize, 4_usize, 7_usize, 13_usize, 14_usize] {
for index in [3_usize, 4_usize] {
let account = match accounts.get(index) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
@@ -1237,9 +1223,12 @@ fn validate_accounts(
));
},
};
if account.signer {
if account.account_key.as_str()
!= kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID
&& !account.writable
{
return std::result::Result::Err(format!(
"mint optional account {index} must not sign"
"mint optional account {index} lacks required writable privilege"
));
}
}
@@ -1252,35 +1241,27 @@ fn validate_accounts(
accounts.len()
));
}
let mandatory: &[(usize, bool, bool)] = &[
let required_privileges: &[(usize, bool, bool)] = &[
(0, false, true),
(1, false, true),
(2, true, true),
(3, false, false),
(4, false, true),
(5, true, false),
(7, false, true),
(8, false, true),
(9, true, true),
(10, true, false),
(11, false, false),
(12, false, false),
(13, false, false),
(14, false, false),
(15, false, false),
(16, false, false),
(17, false, false),
];
for (index, signer, writable) in mandatory {
for (index, signer, writable) in required_privileges {
let account = match accounts.get(*index) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(format!("print is missing account {index}"));
},
};
if account.signer != *signer || account.writable != *writable {
if (*signer && !account.signer) || (*writable && !account.writable) {
return std::result::Result::Err(format!(
"print account {index} has invalid signer/writable flags"
"print account {index} lacks required signer/writable privileges"
));
}
}
@@ -1297,6 +1278,14 @@ fn validate_accounts(
"print edition token record must not sign".to_string(),
);
}
if edition_token_record.account_key.as_str()
!= kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID
&& !edition_token_record.writable
{
return std::result::Result::Err(
"print edition token record lacks required writable privilege".to_string(),
);
}
return std::result::Result::Ok(());
}
if code == "update" {
@@ -1321,9 +1310,9 @@ fn validate_accounts(
return std::result::Result::Err(format!("update is missing account {index}"));
},
};
if account.signer != *signer || account.writable != *writable {
if (*signer && !account.signer) || (*writable && !account.writable) {
return std::result::Result::Err(format!(
"update account {index} has invalid signer/writable flags"
"update account {index} lacks required signer/writable privileges"
));
}
}
@@ -1503,42 +1492,36 @@ fn validate_accounts(
accounts.len()
));
}
let mandatory: &[(usize, bool, bool)] = &[
(0, true, false),
(2, false, true),
(3, false, false),
(4, false, true),
(7, true, true),
(8, false, false),
(9, false, false),
];
for (index, signer, writable) in mandatory {
let required_privileges: &[(usize, bool, bool)] =
&[(0, true, false), (2, false, true), (4, false, true), (7, true, true)];
for (index, signer, writable) in required_privileges {
let account = match accounts.get(*index) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(format!("{code} is missing account {index}"));
},
};
if account.signer != *signer || account.writable != *writable {
if (*signer && !account.signer) || (*writable && !account.writable) {
return std::result::Result::Err(format!(
"{code} account {index} has invalid signer/writable flags"
"{code} account {index} lacks required signer/writable privileges"
));
}
}
for index in [1_usize, 5_usize, 6_usize, 10_usize, 11_usize, 12_usize] {
let account = match accounts.get(index) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(format!(
"{code} is missing optional placeholder account {index}"
));
},
};
if account.signer {
let token_record = match accounts.get(6) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(format!(
"{code} optional account {index} must not sign"
"{code} is missing token record placeholder"
));
}
},
};
if token_record.account_key.as_str()
!= kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID
&& !token_record.writable
{
return std::result::Result::Err(format!(
"{code} token record lacks required writable privilege"
));
}
return std::result::Result::Ok(());
}
@@ -1549,27 +1532,18 @@ fn validate_accounts(
accounts.len()
));
}
let mandatory: &[(usize, bool, bool)] = &[
(0, true, false),
(3, false, false),
(4, false, true),
(6, true, false),
(7, false, false),
(8, false, false),
(9, false, false),
(10, false, false),
(11, false, false),
];
for (index, signer, writable) in mandatory {
let required_privileges: &[(usize, bool, bool)] =
&[(0, true, false), (4, false, true), (6, true, false)];
for (index, signer, writable) in required_privileges {
let account = match accounts.get(*index) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(format!("use is missing account {index}"));
},
};
if account.signer != *signer || account.writable != *writable {
if (*signer && !account.signer) || (*writable && !account.writable) {
return std::result::Result::Err(format!(
"use account {index} has invalid signer/writable flags"
"use account {index} lacks required signer/writable privileges"
));
}
}
@@ -1587,46 +1561,95 @@ fn validate_accounts(
"use optional account {index} must not sign"
));
}
if account.account_key.as_str()
!= kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID
&& !account.writable
{
return std::result::Result::Err(format!(
"use optional account {index} lacks required writable privilege"
));
}
}
return std::result::Result::Ok(());
}
if code == "verify" || code == "unverify" {
if code == "verify" {
if accounts.len() < 8 {
return std::result::Result::Err(format!(
"{code} requires 8 positional accounts, received {}",
"verify requires 8 positional accounts, received {}",
accounts.len()
));
}
let mandatory: &[(usize, bool, bool)] =
&[(0, true, false), (2, false, true), (6, false, false), (7, false, false)];
for (index, signer, writable) in mandatory {
let required_privileges: &[(usize, bool, bool)] = &[(0, true, false), (2, false, true)];
for (index, signer, writable) in required_privileges {
let account = match accounts.get(*index) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(format!("{code} is missing account {index}"));
return std::result::Result::Err(format!("verify is missing account {index}"));
},
};
if account.signer != *signer || account.writable != *writable {
if (*signer && !account.signer) || (*writable && !account.writable) {
return std::result::Result::Err(format!(
"{code} account {index} has invalid signer/writable flags"
"verify account {index} lacks required signer/writable privileges"
));
}
}
for index in [1_usize, 3_usize, 4_usize, 5_usize] {
let account = match accounts.get(index) {
let collection_metadata = match accounts.get(4) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(
"verify is missing collection metadata placeholder".to_string(),
);
},
};
if collection_metadata.account_key.as_str()
!= kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID
&& !collection_metadata.writable
{
return std::result::Result::Err(
"verify collection metadata lacks required writable privilege".to_string(),
);
}
return std::result::Result::Ok(());
}
if code == "unverify" {
if accounts.len() < 7 {
return std::result::Result::Err(format!(
"unverify requires 7 positional accounts, received {}",
accounts.len()
));
}
let required_privileges: &[(usize, bool, bool)] = &[(0, true, false), (2, false, true)];
for (index, signer, writable) in required_privileges {
let account = match accounts.get(*index) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(format!(
"{code} is missing optional placeholder account {index}"
"unverify is missing account {index}"
));
},
};
if account.signer {
if (*signer && !account.signer) || (*writable && !account.writable) {
return std::result::Result::Err(format!(
"{code} optional account {index} must not sign"
"unverify account {index} lacks required signer/writable privileges"
));
}
}
let collection_metadata = match accounts.get(4) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(
"unverify is missing collection metadata placeholder".to_string(),
);
},
};
if collection_metadata.account_key.as_str()
!= kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID
&& !collection_metadata.writable
{
return std::result::Result::Err(
"unverify collection metadata lacks required writable privilege".to_string(),
);
}
return std::result::Result::Ok(());
}
if code == "burn" {
@@ -1682,29 +1705,18 @@ fn validate_accounts(
accounts.len()
));
}
let mandatory: &[(usize, bool, bool)] = &[
(1, false, false),
(2, false, true),
(3, false, false),
(5, false, false),
(7, true, false),
(8, true, true),
(9, false, false),
(10, false, false),
(11, false, false),
(12, false, false),
(13, false, false),
];
for (index, signer, writable) in mandatory {
let required_privileges: &[(usize, bool, bool)] =
&[(2, false, true), (7, true, false), (8, true, true)];
for (index, signer, writable) in required_privileges {
let account = match accounts.get(*index) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(format!("{code} is missing account {index}"));
},
};
if account.signer != *signer || account.writable != *writable {
if (*signer && !account.signer) || (*writable && !account.writable) {
return std::result::Result::Err(format!(
"{code} account {index} has invalid signer/writable flags"
"{code} account {index} lacks required signer/writable privileges"
));
}
}
@@ -1717,9 +1729,12 @@ fn validate_accounts(
));
},
};
if account.signer {
if account.account_key.as_str()
!= kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID
&& !account.writable
{
return std::result::Result::Err(format!(
"{code} optional account {index} must not sign"
"{code} optional account {index} lacks required writable privilege"
));
}
}

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/executor/metadata/metaplex_token_metadata/builder.rs
// version: 8
// version: 11
//! Official Metaplex builders and conservative plan validation.
@@ -181,15 +181,15 @@ pub(crate) fn executor_metaplex_token_metadata_build_prepared_plan(
crate::ExMetaplexTokenMetadataOperation::Utilize { metadata, token_account, mint, use_authority, owner, token_program, ata_program, system_program, rent, use_authority_record, burner, args } => build_idl_instruction_with_args(19, &[(metadata, false, true), (token_account, false, true), (mint, false, true), (use_authority, true, true), (owner, false, false), (token_program, false, false), (ata_program, false, false), (system_program, false, false), (rent, false, false), (use_authority_record, false, true), (burner, false, false)], args),
crate::ExMetaplexTokenMetadataOperation::ApproveUseAuthority { use_authority_record, owner, payer, user, owner_token_account, metadata, mint, burner, token_program, system_program, rent, args } => build_idl_instruction_with_args(20, &[(use_authority_record, false, true), (owner, true, true), (payer, true, true), (user, false, false), (owner_token_account, false, true), (metadata, false, false), (mint, false, false), (burner, false, false), (token_program, false, false), (system_program, false, false), (rent, false, false)], args),
crate::ExMetaplexTokenMetadataOperation::RevokeUseAuthority { use_authority_record, owner, user, owner_token_account, mint, metadata, token_program, system_program, rent } => build_idl_instruction_no_args(21, &[(use_authority_record, false, true), (owner, true, true), (user, false, false), (owner_token_account, false, true), (mint, false, false), (metadata, false, false), (token_program, false, false), (system_program, false, false), (rent, false, false)]),
crate::ExMetaplexTokenMetadataOperation::CreateEscrowAccount { escrow, metadata, mint, token_account, edition, payer, system_program, sysvar_instructions, authority } => build_idl_instruction_no_args(38, &[(escrow, false, true), (metadata, false, true), (mint, false, false), (token_account, false, false), (edition, false, false), (payer, true, true), (system_program, false, false), (sysvar_instructions, false, false), (authority, true, false)]),
crate::ExMetaplexTokenMetadataOperation::CreateEscrowAccount { escrow, metadata, mint, token_account, edition, payer, system_program, sysvar_instructions, authority } => build_idl_instruction_trailing_optional_no_args(38, &[(escrow, false, true), (metadata, false, true), (mint, false, false), (token_account, false, false), (edition, false, false), (payer, true, true), (system_program, false, false), (sysvar_instructions, false, false)], authority.as_ref().map(|value| return (value, true, false))),
crate::ExMetaplexTokenMetadataOperation::CloseEscrowAccount { escrow, metadata, mint, token_account, edition, payer, system_program, sysvar_instructions } => build_idl_instruction_no_args(39, &[(escrow, false, true), (metadata, false, true), (mint, false, false), (token_account, false, false), (edition, false, false), (payer, true, true), (system_program, false, false), (sysvar_instructions, false, false)]),
crate::ExMetaplexTokenMetadataOperation::TransferOutOfEscrow { escrow, metadata, payer, attribute_mint, attribute_src, attribute_dst, escrow_mint, escrow_account, system_program, ata_program, token_program, sysvar_instructions, authority, args } => build_idl_instruction_with_args(40, &[(escrow, false, false), (metadata, false, true), (payer, true, true), (attribute_mint, false, false), (attribute_src, false, true), (attribute_dst, false, true), (escrow_mint, false, false), (escrow_account, false, false), (system_program, false, false), (ata_program, false, false), (token_program, false, false), (sysvar_instructions, false, false), (authority, true, false)], args),
crate::ExMetaplexTokenMetadataOperation::Mint { token, token_owner, metadata, master_edition, token_record, mint, authority, delegate_record, payer, system_program, sysvar_instructions, spl_token_program, spl_ata_program, authorization_rules_program, authorization_rules, args } => build_idl_instruction_with_args(43, &[(token, false, true), (token_owner, false, false), (metadata, false, false), (master_edition, false, true), (token_record, false, true), (mint, false, true), (authority, true, false), (delegate_record, false, false), (payer, true, true), (system_program, false, false), (sysvar_instructions, false, false), (spl_token_program, false, false), (spl_ata_program, false, false), (authorization_rules_program, false, false), (authorization_rules, false, false)], args),
crate::ExMetaplexTokenMetadataOperation::Migrate { metadata, edition, token, token_owner, mint, payer, authority, collection_metadata, delegate_record, token_record, system_program, sysvar_instructions, spl_token_program, authorization_rules_program, authorization_rules } => build_idl_instruction_no_args(48, &[(metadata, false, true), (edition, false, true), (token, false, true), (token_owner, false, false), (mint, false, false), (payer, true, true), (authority, true, false), (collection_metadata, false, false), (delegate_record, false, false), (token_record, false, true), (system_program, false, false), (sysvar_instructions, false, false), (spl_token_program, false, false), (authorization_rules_program, false, false), (authorization_rules, false, false)]),
crate::ExMetaplexTokenMetadataOperation::Use { authority, delegate_record, token, mint, metadata, edition, payer, system_program, sysvar_instructions, spl_token_program, authorization_rules_program, authorization_rules, args } => build_idl_instruction_with_args(51, &[(authority, true, false), (delegate_record, false, true), (token, false, true), (mint, false, false), (metadata, false, true), (edition, false, true), (payer, true, false), (system_program, false, false), (sysvar_instructions, false, false), (spl_token_program, false, false), (authorization_rules_program, false, false), (authorization_rules, false, false)], args),
crate::ExMetaplexTokenMetadataOperation::TransferOutOfEscrow { escrow, metadata, payer, attribute_mint, attribute_src, attribute_dst, escrow_mint, escrow_account, system_program, ata_program, token_program, sysvar_instructions, authority, args } => build_idl_instruction_trailing_optional_with_args(40, &[(escrow, false, false), (metadata, false, true), (payer, true, true), (attribute_mint, false, false), (attribute_src, false, true), (attribute_dst, false, true), (escrow_mint, false, false), (escrow_account, false, false), (system_program, false, false), (ata_program, false, false), (token_program, false, false), (sysvar_instructions, false, false)], authority.as_ref().map(|value| return (value, true, false)), args),
crate::ExMetaplexTokenMetadataOperation::Mint { token, token_owner, metadata, master_edition, token_record, mint, authority, delegate_record, payer, system_program, sysvar_instructions, spl_token_program, spl_ata_program, authorization_rules_program, authorization_rules, args } => build_idl_instruction_optional_with_args(43, &[(std::option::Option::Some(token), false, true), (token_owner.as_ref(), false, false), (std::option::Option::Some(metadata), false, false), (master_edition.as_ref(), false, true), (token_record.as_ref(), false, true), (std::option::Option::Some(mint), false, true), (std::option::Option::Some(authority), true, false), (delegate_record.as_ref(), false, false), (std::option::Option::Some(payer), true, true), (std::option::Option::Some(system_program), false, false), (std::option::Option::Some(sysvar_instructions), false, false), (std::option::Option::Some(spl_token_program), false, false), (std::option::Option::Some(spl_ata_program), false, false), (authorization_rules_program.as_ref(), false, false), (authorization_rules.as_ref(), false, false)], args),
crate::ExMetaplexTokenMetadataOperation::Migrate { metadata, edition, token, token_owner, mint, payer, authority, collection_metadata, delegate_record, token_record, system_program, sysvar_instructions, spl_token_program, authorization_rules_program, authorization_rules } => build_idl_instruction_optional_no_args(48, &[(std::option::Option::Some(metadata), false, true), (std::option::Option::Some(edition), false, true), (std::option::Option::Some(token), false, true), (std::option::Option::Some(token_owner), false, false), (std::option::Option::Some(mint), false, false), (std::option::Option::Some(payer), true, true), (std::option::Option::Some(authority), true, false), (std::option::Option::Some(collection_metadata), false, false), (std::option::Option::Some(delegate_record), false, false), (std::option::Option::Some(token_record), false, true), (std::option::Option::Some(system_program), false, false), (std::option::Option::Some(sysvar_instructions), false, false), (std::option::Option::Some(spl_token_program), false, false), (authorization_rules_program.as_ref(), false, false), (authorization_rules.as_ref(), false, false)]),
crate::ExMetaplexTokenMetadataOperation::Use { authority, delegate_record, token, mint, metadata, edition, payer, system_program, sysvar_instructions, spl_token_program, authorization_rules_program, authorization_rules, args } => build_idl_instruction_optional_with_args(51, &[(std::option::Option::Some(authority), true, false), (delegate_record.as_ref(), false, true), (token.as_ref(), false, true), (std::option::Option::Some(mint), false, false), (std::option::Option::Some(metadata), false, true), (edition.as_ref(), false, true), (std::option::Option::Some(payer), true, false), (std::option::Option::Some(system_program), false, false), (std::option::Option::Some(sysvar_instructions), false, false), (spl_token_program.as_ref(), false, false), (authorization_rules_program.as_ref(), false, false), (authorization_rules.as_ref(), false, false)], args),
crate::ExMetaplexTokenMetadataOperation::Collect { authority, recipient } => build_idl_instruction_no_args(54, &[(authority, true, false), (recipient, false, false)]),
crate::ExMetaplexTokenMetadataOperation::Print { edition_metadata, edition, edition_mint, edition_token_account_owner, edition_token_account, edition_mint_authority, edition_token_record, master_edition, edition_marker_pda, payer, master_token_account_owner, master_token_account, master_metadata, update_authority, spl_token_program, spl_ata_program, sysvar_instructions, system_program, args } => build_idl_instruction_with_args(55, &[(edition_metadata, false, true), (edition, false, true), (edition_mint, false, true), (edition_token_account_owner, false, false), (edition_token_account, false, true), (edition_mint_authority, true, false), (edition_token_record, false, true), (master_edition, false, true), (edition_marker_pda, false, true), (payer, true, true), (master_token_account_owner, false, false), (master_token_account, false, false), (master_metadata, false, false), (update_authority, false, false), (spl_token_program, false, false), (spl_ata_program, false, false), (sysvar_instructions, false, false), (system_program, false, false)], args),
crate::ExMetaplexTokenMetadataOperation::Resize { metadata, edition, mint, payer, authority, token, system_program } => build_idl_instruction_no_args(56, &[(metadata, false, true), (edition, false, true), (mint, false, false), (payer, false, true), (authority, true, false), (token, false, false), (system_program, false, false)]),
crate::ExMetaplexTokenMetadataOperation::Print { edition_metadata, edition, edition_mint, edition_token_account_owner, edition_token_account, edition_mint_authority, edition_token_record, master_edition, edition_marker_pda, payer, master_token_account_owner, master_token_account, master_metadata, update_authority, spl_token_program, spl_ata_program, sysvar_instructions, system_program, args } => build_print(edition_metadata, edition, edition_mint, edition_token_account_owner, edition_token_account, edition_mint_authority, edition_token_record.as_ref(), master_edition, edition_marker_pda, payer, master_token_account_owner, master_token_account, master_metadata, update_authority, spl_token_program, spl_ata_program, sysvar_instructions, system_program, args),
crate::ExMetaplexTokenMetadataOperation::Resize { metadata, edition, mint, payer, authority, token, system_program } => build_resize(metadata, edition, mint, payer, authority.as_ref(), token.as_ref(), system_program),
};
let instruction = match instruction_result {
std::result::Result::Ok(value) => value,
@@ -1207,6 +1207,192 @@ fn build_close_accounts(
return std::result::Result::Ok(convert_official_instruction!(official));
}
#[allow(clippy::too_many_arguments)]
fn build_print(
edition_metadata: &crate::MdPubkey,
edition: &crate::MdPubkey,
edition_mint: &crate::MdPubkey,
edition_token_account_owner: &crate::MdPubkey,
edition_token_account: &crate::MdPubkey,
edition_mint_authority: &crate::MdPubkey,
edition_token_record: std::option::Option<&crate::MdPubkey>,
master_edition: &crate::MdPubkey,
edition_marker_pda: &crate::MdPubkey,
payer: &crate::MdPubkey,
master_token_account_owner: &crate::MdPubkey,
master_token_account: &crate::MdPubkey,
master_metadata: &crate::MdPubkey,
update_authority: &crate::MdPubkey,
spl_token_program: &crate::MdPubkey,
spl_ata_program: &crate::MdPubkey,
sysvar_instructions: &crate::MdPubkey,
system_program: &crate::MdPubkey,
args: &mpl_token_metadata::types::PrintArgs,
) -> kb_core::Result<solana_instruction::Instruction> {
let mut builder = mpl_token_metadata::instructions::PrintBuilder::new();
builder
.edition_metadata(parse_official_pubkey!(&edition_metadata.0, "edition_metadata"))
.edition(parse_official_pubkey!(&edition.0, "edition"))
.edition_mint(parse_official_pubkey!(&edition_mint.0, "edition_mint"), true)
.edition_token_account_owner(parse_official_pubkey!(
&edition_token_account_owner.0,
"edition_token_account_owner"
))
.edition_token_account(parse_official_pubkey!(
&edition_token_account.0,
"edition_token_account"
))
.edition_mint_authority(parse_official_pubkey!(
&edition_mint_authority.0,
"edition_mint_authority"
))
.edition_token_record(parse_optional_official_pubkey!(
edition_token_record,
"edition_token_record"
))
.master_edition(parse_official_pubkey!(&master_edition.0, "master_edition"))
.edition_marker_pda(parse_official_pubkey!(&edition_marker_pda.0, "edition_marker_pda"))
.payer(parse_official_pubkey!(&payer.0, "payer"))
.master_token_account_owner(
parse_official_pubkey!(&master_token_account_owner.0, "master_token_account_owner"),
true,
)
.master_token_account(parse_official_pubkey!(
&master_token_account.0,
"master_token_account"
))
.master_metadata(parse_official_pubkey!(&master_metadata.0, "master_metadata"))
.update_authority(parse_official_pubkey!(&update_authority.0, "update_authority"))
.spl_token_program(parse_official_pubkey!(&spl_token_program.0, "spl_token_program"))
.spl_ata_program(parse_official_pubkey!(&spl_ata_program.0, "spl_ata_program"))
.sysvar_instructions(parse_official_pubkey!(&sysvar_instructions.0, "sysvar_instructions"))
.system_program(parse_official_pubkey!(&system_program.0, "system_program"))
.print_args(args.clone());
let official = builder.instruction();
return std::result::Result::Ok(convert_official_instruction!(official));
}
fn build_resize(
metadata: &crate::MdPubkey,
edition: &crate::MdPubkey,
mint: &crate::MdPubkey,
payer: &crate::MdPubkey,
authority: std::option::Option<&crate::MdPubkey>,
token: std::option::Option<&crate::MdPubkey>,
system_program: &crate::MdPubkey,
) -> kb_core::Result<solana_instruction::Instruction> {
let mut builder = mpl_token_metadata::instructions::ResizeBuilder::new();
builder
.metadata(parse_official_pubkey!(&metadata.0, "metadata"))
.edition(parse_official_pubkey!(&edition.0, "edition"))
.mint(parse_official_pubkey!(&mint.0, "mint"))
.payer(parse_official_pubkey!(&payer.0, "payer"), true)
.authority(parse_optional_official_pubkey!(authority, "authority"))
.token(parse_optional_official_pubkey!(token, "token"))
.system_program(parse_official_pubkey!(&system_program.0, "system_program"));
let official = builder.instruction();
return std::result::Result::Ok(convert_official_instruction!(official));
}
fn build_idl_instruction_trailing_optional_no_args(
discriminator: u8,
accounts: &[(&crate::MdPubkey, bool, bool)],
trailing_account: std::option::Option<(&crate::MdPubkey, bool, bool)>,
) -> kb_core::Result<solana_instruction::Instruction> {
let mut exact_accounts = accounts.to_vec();
if let std::option::Option::Some(value) = trailing_account {
exact_accounts.push(value);
}
return build_idl_instruction_no_args(discriminator, exact_accounts.as_slice());
}
fn build_idl_instruction_trailing_optional_with_args<T: borsh_0_10::BorshSerialize>(
discriminator: u8,
accounts: &[(&crate::MdPubkey, bool, bool)],
trailing_account: std::option::Option<(&crate::MdPubkey, bool, bool)>,
args: &T,
) -> kb_core::Result<solana_instruction::Instruction> {
let mut exact_accounts = accounts.to_vec();
if let std::option::Option::Some(value) = trailing_account {
exact_accounts.push(value);
}
return build_idl_instruction_with_args(discriminator, exact_accounts.as_slice(), args);
}
fn build_idl_instruction_optional_no_args(
discriminator: u8,
accounts: &[(std::option::Option<&crate::MdPubkey>, bool, bool)],
) -> kb_core::Result<solana_instruction::Instruction> {
return build_idl_instruction_optional(discriminator, accounts, std::option::Option::None);
}
fn build_idl_instruction_optional_with_args<T: borsh_0_10::BorshSerialize>(
discriminator: u8,
accounts: &[(std::option::Option<&crate::MdPubkey>, bool, bool)],
args: &T,
) -> kb_core::Result<solana_instruction::Instruction> {
let encoded = match borsh_0_10::BorshSerialize::try_to_vec(args) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
return std::result::Result::Err(kb_core::Error::new(
"execution_metaplex_arguments_serialize_failed",
error.to_string(),
));
},
};
return build_idl_instruction_optional(
discriminator,
accounts,
std::option::Option::Some(encoded),
);
}
fn build_idl_instruction_optional(
discriminator: u8,
accounts: &[(std::option::Option<&crate::MdPubkey>, bool, bool)],
encoded_args: std::option::Option<std::vec::Vec<u8>>,
) -> kb_core::Result<solana_instruction::Instruction> {
let program_id = match parse_str_pubkey(
kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID,
"program_id",
) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let mut metas = std::vec::Vec::with_capacity(accounts.len());
for (value, is_signer, is_writable) in accounts {
match value {
std::option::Option::Some(value) => {
let pubkey = match parse_pubkey(value, "instruction_account") {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
metas.push(solana_instruction::AccountMeta {
pubkey,
is_signer: *is_signer,
is_writable: *is_writable,
});
},
std::option::Option::None => {
metas.push(solana_instruction::AccountMeta {
pubkey: program_id,
is_signer: false,
is_writable: false,
});
},
}
}
let mut data = vec![discriminator];
if let std::option::Option::Some(mut value) = encoded_args {
data.append(&mut value);
}
return std::result::Result::Ok(solana_instruction::Instruction {
program_id,
accounts: metas,
data,
});
}
fn build_idl_instruction_no_args(
discriminator: u8,
accounts: &[(&crate::MdPubkey, bool, bool)],
@@ -1447,6 +1633,316 @@ mod tests {
assert!(instruction.accounts[3].is_signer);
}
#[test]
fn print_uses_current_official_signer_contract() {
let accounts: std::vec::Vec<crate::MdPubkey> = (0..18)
.map(|_| return crate::MdPubkey(solana_pubkey::Pubkey::new_unique().to_string()))
.collect();
let result = super::build_print(
&accounts[0],
&accounts[1],
&accounts[2],
&accounts[3],
&accounts[4],
&accounts[5],
std::option::Option::Some(&accounts[6]),
&accounts[7],
&accounts[8],
&accounts[9],
&accounts[10],
&accounts[11],
&accounts[12],
&accounts[13],
&accounts[14],
&accounts[15],
&accounts[16],
&accounts[17],
&mpl_token_metadata::types::PrintArgs::V1 { edition: 1 },
);
assert!(result.is_ok());
let instruction = match result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
assert_eq!(instruction.data.first().copied(), std::option::Option::Some(55));
assert_eq!(instruction.accounts.len(), 18);
assert!(instruction.accounts[2].is_signer);
assert!(instruction.accounts[2].is_writable);
assert!(instruction.accounts[5].is_signer);
assert!(!instruction.accounts[5].is_writable);
assert!(instruction.accounts[9].is_signer);
assert!(instruction.accounts[9].is_writable);
assert!(instruction.accounts[10].is_signer);
assert!(!instruction.accounts[10].is_writable);
}
#[test]
fn resize_uses_current_official_payer_signer_contract() {
let accounts: std::vec::Vec<crate::MdPubkey> = (0..7)
.map(|_| return crate::MdPubkey(solana_pubkey::Pubkey::new_unique().to_string()))
.collect();
let result = super::build_resize(
&accounts[0],
&accounts[1],
&accounts[2],
&accounts[3],
std::option::Option::Some(&accounts[4]),
std::option::Option::Some(&accounts[5]),
&accounts[6],
);
assert!(result.is_ok());
let instruction = match result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
assert_eq!(instruction.data, vec![56]);
assert_eq!(instruction.accounts.len(), 7);
assert!(instruction.accounts[3].is_signer);
assert!(instruction.accounts[3].is_writable);
assert!(instruction.accounts[4].is_signer);
assert!(!instruction.accounts[4].is_writable);
}
#[test]
fn positional_optional_accounts_use_placeholders_but_escrow_tail_is_omitted() {
let accounts: std::vec::Vec<crate::MdPubkey> = (0..15)
.map(|_| return crate::MdPubkey(solana_pubkey::Pubkey::new_unique().to_string()))
.collect();
let program_id = match super::parse_str_pubkey(
kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID,
"program_id",
) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let create = super::build_idl_instruction_trailing_optional_no_args(
38,
&[
(&accounts[0], false, true),
(&accounts[1], false, true),
(&accounts[2], false, false),
(&accounts[3], false, false),
(&accounts[4], false, false),
(&accounts[5], true, true),
(&accounts[6], false, false),
(&accounts[7], false, false),
],
std::option::Option::None,
);
assert!(create.is_ok());
let create = match create {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
assert_eq!(create.accounts.len(), 8);
let create_with_authority = super::build_idl_instruction_trailing_optional_no_args(
38,
&[
(&accounts[0], false, true),
(&accounts[1], false, true),
(&accounts[2], false, false),
(&accounts[3], false, false),
(&accounts[4], false, false),
(&accounts[5], true, true),
(&accounts[6], false, false),
(&accounts[7], false, false),
],
std::option::Option::Some((&accounts[8], true, false)),
);
assert!(create_with_authority.is_ok());
let create_with_authority = match create_with_authority {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
assert_eq!(create_with_authority.accounts.len(), 9);
assert_eq!(create_with_authority.accounts[8].pubkey.to_string(), accounts[8].0);
assert!(create_with_authority.accounts[8].is_signer);
assert!(!create_with_authority.accounts[8].is_writable);
let transfer_out = super::build_idl_instruction_trailing_optional_with_args(
40,
&[
(&accounts[0], false, false),
(&accounts[1], false, true),
(&accounts[2], true, true),
(&accounts[3], false, false),
(&accounts[4], false, true),
(&accounts[5], false, true),
(&accounts[6], false, false),
(&accounts[7], false, false),
(&accounts[8], false, false),
(&accounts[9], false, false),
(&accounts[10], false, false),
(&accounts[11], false, false),
],
std::option::Option::None,
&mpl_token_metadata::instructions::TransferOutOfEscrowInstructionArgs { amount: 1 },
);
assert!(transfer_out.is_ok());
let transfer_out = match transfer_out {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
assert_eq!(transfer_out.accounts.len(), 12);
let mint = super::build_idl_instruction_optional_with_args(
43,
&[
(std::option::Option::Some(&accounts[0]), false, true),
(std::option::Option::None, false, false),
(std::option::Option::Some(&accounts[2]), false, false),
(std::option::Option::None, false, true),
(std::option::Option::None, false, true),
(std::option::Option::Some(&accounts[5]), false, true),
(std::option::Option::Some(&accounts[6]), true, false),
(std::option::Option::None, false, false),
(std::option::Option::Some(&accounts[8]), true, true),
(std::option::Option::Some(&accounts[9]), false, false),
(std::option::Option::Some(&accounts[10]), false, false),
(std::option::Option::Some(&accounts[11]), false, false),
(std::option::Option::Some(&accounts[12]), false, false),
(std::option::Option::None, false, false),
(std::option::Option::None, false, false),
],
&mpl_token_metadata::types::MintArgs::V1 {
amount: 1,
authorization_data: std::option::Option::None,
},
);
assert!(mint.is_ok());
let mint = match mint {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
assert_eq!(mint.accounts.len(), 15);
for index in [1_usize, 3, 4, 7, 13, 14] {
assert_eq!(mint.accounts[index].pubkey, program_id);
assert!(!mint.accounts[index].is_signer);
assert!(!mint.accounts[index].is_writable);
}
let migrate = super::build_idl_instruction_optional_no_args(
48,
&[
(std::option::Option::Some(&accounts[0]), false, true),
(std::option::Option::Some(&accounts[1]), false, true),
(std::option::Option::Some(&accounts[2]), false, true),
(std::option::Option::Some(&accounts[3]), false, false),
(std::option::Option::Some(&accounts[4]), false, false),
(std::option::Option::Some(&accounts[5]), true, true),
(std::option::Option::Some(&accounts[6]), true, false),
(std::option::Option::Some(&accounts[7]), false, false),
(std::option::Option::Some(&accounts[8]), false, false),
(std::option::Option::Some(&accounts[9]), false, true),
(std::option::Option::Some(&accounts[10]), false, false),
(std::option::Option::Some(&accounts[11]), false, false),
(std::option::Option::Some(&accounts[12]), false, false),
(std::option::Option::None, false, false),
(std::option::Option::None, false, false),
],
);
assert!(migrate.is_ok());
let migrate = match migrate {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
assert_eq!(migrate.accounts[13].pubkey, program_id);
assert_eq!(migrate.accounts[14].pubkey, program_id);
let use_instruction = super::build_idl_instruction_optional_with_args(
51,
&[
(std::option::Option::Some(&accounts[0]), true, false),
(std::option::Option::None, false, true),
(std::option::Option::None, false, true),
(std::option::Option::Some(&accounts[3]), false, false),
(std::option::Option::Some(&accounts[4]), false, true),
(std::option::Option::None, false, true),
(std::option::Option::Some(&accounts[6]), true, false),
(std::option::Option::Some(&accounts[7]), false, false),
(std::option::Option::Some(&accounts[8]), false, false),
(std::option::Option::None, false, false),
(std::option::Option::None, false, false),
(std::option::Option::None, false, false),
],
&mpl_token_metadata::types::UseArgs::V1 {
authorization_data: std::option::Option::None,
},
);
assert!(use_instruction.is_ok());
let use_instruction = match use_instruction {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
assert_eq!(use_instruction.accounts.len(), 12);
for index in [1_usize, 2, 5, 9, 10, 11] {
assert_eq!(use_instruction.accounts[index].pubkey, program_id);
assert!(!use_instruction.accounts[index].is_signer);
assert!(!use_instruction.accounts[index].is_writable);
}
}
#[test]
fn print_and_resize_accept_absent_current_optional_accounts() {
let accounts: std::vec::Vec<crate::MdPubkey> = (0..18)
.map(|_| return crate::MdPubkey(solana_pubkey::Pubkey::new_unique().to_string()))
.collect();
let program_id = match super::parse_str_pubkey(
kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID,
"program_id",
) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let print = super::build_print(
&accounts[0],
&accounts[1],
&accounts[2],
&accounts[3],
&accounts[4],
&accounts[5],
std::option::Option::None,
&accounts[7],
&accounts[8],
&accounts[9],
&accounts[10],
&accounts[11],
&accounts[12],
&accounts[13],
&accounts[14],
&accounts[15],
&accounts[16],
&accounts[17],
&mpl_token_metadata::types::PrintArgs::V1 { edition: 1 },
);
assert!(print.is_ok());
let print = match print {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
assert_eq!(print.accounts.len(), 18);
assert_eq!(print.accounts[6].pubkey, program_id);
assert!(!print.accounts[6].is_signer);
assert!(!print.accounts[6].is_writable);
let resize = super::build_resize(
&accounts[0],
&accounts[1],
&accounts[2],
&accounts[3],
std::option::Option::None,
std::option::Option::None,
&accounts[6],
);
assert!(resize.is_ok());
let resize = match resize {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
assert_eq!(resize.accounts.len(), 7);
assert_eq!(resize.accounts[4].pubkey, program_id);
assert_eq!(resize.accounts[5].pubkey, program_id);
assert!(!resize.accounts[4].is_signer);
assert!(!resize.accounts[4].is_writable);
assert!(!resize.accounts[5].is_signer);
assert!(!resize.accounts[5].is_writable);
}
#[test]
fn collect_builds_exact_discriminator_and_signer_contract() {
let authority = crate::MdPubkey("11111111111111111111111111111111".to_string());

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/executor/metadata/metaplex_token_metadata/intent.rs
// version: 8
// version: 9
//! Typed current and deprecated Metaplex Token Metadata execution intents.
@@ -729,8 +729,8 @@ pub enum ExMetaplexTokenMetadataOperation {
system_program: crate::MdPubkey,
/// Account `sysvarInstructions` from the official IDL contract.
sysvar_instructions: crate::MdPubkey,
/// Account `authority` from the official IDL contract.
authority: crate::MdPubkey,
/// Optional authority from the current SDK contract.
authority: std::option::Option<crate::MdPubkey>,
},
/// Build the current CloseEscrowAccount instruction.
CloseEscrowAccount {
@@ -777,30 +777,30 @@ pub enum ExMetaplexTokenMetadataOperation {
token_program: crate::MdPubkey,
/// Account `sysvarInstructions` from the official IDL contract.
sysvar_instructions: crate::MdPubkey,
/// Account `authority` from the official IDL contract.
authority: crate::MdPubkey,
/// Optional authority from the current SDK contract.
authority: std::option::Option<crate::MdPubkey>,
/// Official Metaplex instruction arguments.
#[ts(type = "unknown")]
args: mpl_token_metadata::instructions::TransferOutOfEscrowInstructionArgs,
},
/// Build the current Mint instruction.
Mint {
/// Account `token` from the official IDL contract.
/// Account `token` from the current SDK contract.
token: crate::MdPubkey,
/// Account `tokenOwner` from the official IDL contract.
token_owner: crate::MdPubkey,
/// Optional owner of the token account in the current SDK contract.
token_owner: std::option::Option<crate::MdPubkey>,
/// Account `metadata` from the official IDL contract.
metadata: crate::MdPubkey,
/// Account `masterEdition` from the official IDL contract.
master_edition: crate::MdPubkey,
/// Account `tokenRecord` from the official IDL contract.
token_record: crate::MdPubkey,
/// Optional Master Edition account in the current SDK contract.
master_edition: std::option::Option<crate::MdPubkey>,
/// Optional token record account in the current SDK contract.
token_record: std::option::Option<crate::MdPubkey>,
/// Account `mint` from the official IDL contract.
mint: crate::MdPubkey,
/// Account `authority` from the official IDL contract.
authority: crate::MdPubkey,
/// Account `delegateRecord` from the official IDL contract.
delegate_record: crate::MdPubkey,
/// Optional delegate record account in the current SDK contract.
delegate_record: std::option::Option<crate::MdPubkey>,
/// Account `payer` from the official IDL contract.
payer: crate::MdPubkey,
/// Account `systemProgram` from the official IDL contract.
@@ -811,10 +811,10 @@ pub enum ExMetaplexTokenMetadataOperation {
spl_token_program: crate::MdPubkey,
/// Account `splAtaProgram` from the official IDL contract.
spl_ata_program: crate::MdPubkey,
/// Account `authorizationRulesProgram` from the official IDL contract.
authorization_rules_program: crate::MdPubkey,
/// Account `authorizationRules` from the official IDL contract.
authorization_rules: crate::MdPubkey,
/// Optional Token Authorization Rules program in the current SDK contract.
authorization_rules_program: std::option::Option<crate::MdPubkey>,
/// Optional Token Authorization Rules account in the current SDK contract.
authorization_rules: std::option::Option<crate::MdPubkey>,
/// Official Metaplex instruction arguments.
#[ts(type = "unknown")]
args: mpl_token_metadata::types::MintArgs,
@@ -847,25 +847,25 @@ pub enum ExMetaplexTokenMetadataOperation {
sysvar_instructions: crate::MdPubkey,
/// Account `splTokenProgram` from the official IDL contract.
spl_token_program: crate::MdPubkey,
/// Account `authorizationRulesProgram` from the official IDL contract.
authorization_rules_program: crate::MdPubkey,
/// Account `authorizationRules` from the official IDL contract.
authorization_rules: crate::MdPubkey,
/// Optional Token Authorization Rules program in the current SDK contract.
authorization_rules_program: std::option::Option<crate::MdPubkey>,
/// Optional Token Authorization Rules account in the current SDK contract.
authorization_rules: std::option::Option<crate::MdPubkey>,
},
/// Build the current Use instruction.
Use {
/// Account `authority` from the official IDL contract.
authority: crate::MdPubkey,
/// Account `delegateRecord` from the official IDL contract.
delegate_record: crate::MdPubkey,
/// Optional delegate record account in the current SDK contract.
delegate_record: std::option::Option<crate::MdPubkey>,
/// Account `token` from the official IDL contract.
token: crate::MdPubkey,
token: std::option::Option<crate::MdPubkey>,
/// Account `mint` from the official IDL contract.
mint: crate::MdPubkey,
/// Account `metadata` from the official IDL contract.
metadata: crate::MdPubkey,
/// Account `edition` from the official IDL contract.
edition: crate::MdPubkey,
edition: std::option::Option<crate::MdPubkey>,
/// Account `payer` from the official IDL contract.
payer: crate::MdPubkey,
/// Account `systemProgram` from the official IDL contract.
@@ -873,11 +873,11 @@ pub enum ExMetaplexTokenMetadataOperation {
/// Account `sysvarInstructions` from the official IDL contract.
sysvar_instructions: crate::MdPubkey,
/// Account `splTokenProgram` from the official IDL contract.
spl_token_program: crate::MdPubkey,
/// Account `authorizationRulesProgram` from the official IDL contract.
authorization_rules_program: crate::MdPubkey,
/// Account `authorizationRules` from the official IDL contract.
authorization_rules: crate::MdPubkey,
spl_token_program: std::option::Option<crate::MdPubkey>,
/// Optional Token Authorization Rules program in the current SDK contract.
authorization_rules_program: std::option::Option<crate::MdPubkey>,
/// Optional Token Authorization Rules account in the current SDK contract.
authorization_rules: std::option::Option<crate::MdPubkey>,
/// Official Metaplex instruction arguments.
#[ts(type = "unknown")]
args: mpl_token_metadata::types::UseArgs,
@@ -903,8 +903,8 @@ pub enum ExMetaplexTokenMetadataOperation {
edition_token_account: crate::MdPubkey,
/// Account `editionMintAuthority` from the official IDL contract.
edition_mint_authority: crate::MdPubkey,
/// Account `editionTokenRecord` from the official IDL contract.
edition_token_record: crate::MdPubkey,
/// Optional edition token record account in the current SDK contract.
edition_token_record: std::option::Option<crate::MdPubkey>,
/// Account `masterEdition` from the official IDL contract.
master_edition: crate::MdPubkey,
/// Account `editionMarkerPda` from the official IDL contract.
@@ -941,10 +941,10 @@ pub enum ExMetaplexTokenMetadataOperation {
mint: crate::MdPubkey,
/// Account `payer` from the official IDL contract.
payer: crate::MdPubkey,
/// Account `authority` from the official IDL contract.
authority: crate::MdPubkey,
/// Account `token` from the official IDL contract.
token: crate::MdPubkey,
/// Optional authority from the current SDK contract.
authority: std::option::Option<crate::MdPubkey>,
/// Optional token account from the current SDK contract.
token: std::option::Option<crate::MdPubkey>,
/// Account `systemProgram` from the official IDL contract.
system_program: crate::MdPubkey,
},