use std::collections::BTreeMap;
use std::sync::OnceLock;
use crate::decode::schema::{
EnumVariant, FieldType, InstructionSchema, NamedAccount, NamedField, ProgramSchema,
};
pub fn metaplex_token_metadata() -> &'static ProgramSchema {
static CACHED: OnceLock<ProgramSchema> = OnceLock::new();
CACHED.get_or_init(build)
}
fn build() -> ProgramSchema {
let defined = defined_types();
let mut ix: BTreeMap<Vec<u8>, InstructionSchema> = BTreeMap::new();
ix.insert(
vec![0x00],
InstructionSchema {
name: "CreateMetadataAccount".to_string(),
discriminator: vec![0x00],
accounts: create_metadata_account_v1_accounts(),
args: vec![
NamedField {
name: "data".to_string(),
ty: FieldType::Defined("Data".to_string()),
},
NamedField {
name: "is_mutable".to_string(),
ty: FieldType::Bool,
},
],
},
);
ix.insert(
vec![0x0f],
InstructionSchema {
name: "UpdateMetadataAccountV2".to_string(),
discriminator: vec![0x0f],
accounts: vec![
NamedAccount {
name: "metadata".into(),
writable: true,
signer: false,
optional: false,
},
NamedAccount {
name: "update_authority".into(),
writable: false,
signer: true,
optional: false,
},
],
args: vec![
NamedField {
name: "data".into(),
ty: FieldType::Option(Box::new(FieldType::Defined("DataV2".into()))),
},
NamedField {
name: "update_authority".into(),
ty: FieldType::Option(Box::new(FieldType::Pubkey)),
},
NamedField {
name: "primary_sale_happened".into(),
ty: FieldType::Option(Box::new(FieldType::Bool)),
},
NamedField {
name: "is_mutable".into(),
ty: FieldType::Option(Box::new(FieldType::Bool)),
},
],
},
);
ix.insert(
vec![0x11],
InstructionSchema {
name: "CreateMasterEditionV3".to_string(),
discriminator: vec![0x11],
accounts: create_master_edition_v3_accounts(),
args: vec![NamedField {
name: "max_supply".into(),
ty: FieldType::Option(Box::new(FieldType::U64)),
}],
},
);
ix.insert(
vec![0x12],
InstructionSchema {
name: "VerifyCollection".to_string(),
discriminator: vec![0x12],
accounts: vec![
NamedAccount {
name: "metadata".into(),
writable: true,
signer: false,
optional: false,
},
NamedAccount {
name: "collection_authority".into(),
writable: false,
signer: true,
optional: false,
},
NamedAccount {
name: "payer".into(),
writable: true,
signer: true,
optional: false,
},
NamedAccount {
name: "collection_mint".into(),
writable: false,
signer: false,
optional: false,
},
NamedAccount {
name: "collection".into(),
writable: false,
signer: false,
optional: false,
},
NamedAccount {
name: "collection_master_edition_account".into(),
writable: false,
signer: false,
optional: false,
},
NamedAccount {
name: "collection_authority_record".into(),
writable: false,
signer: false,
optional: true,
},
],
args: vec![],
},
);
ix.insert(
vec![0x21],
InstructionSchema {
name: "CreateMetadataAccountV3".to_string(),
discriminator: vec![0x21],
accounts: create_metadata_account_v3_accounts(),
args: vec![
NamedField {
name: "data".into(),
ty: FieldType::Defined("DataV2".into()),
},
NamedField {
name: "is_mutable".into(),
ty: FieldType::Bool,
},
NamedField {
name: "collection_details".into(),
ty: FieldType::Option(Box::new(FieldType::Defined("CollectionDetails".into()))),
},
],
},
);
ix.insert(
vec![0x29],
InstructionSchema {
name: "Burn".to_string(),
discriminator: vec![0x29],
accounts: burn_accounts(),
args: vec![NamedField {
name: "burn_args".into(),
ty: FieldType::Defined("BurnArgs".into()),
}],
},
);
ProgramSchema::build(
"metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s".to_string(),
ix,
defined,
)
}
fn defined_types() -> BTreeMap<String, FieldType> {
let mut t: BTreeMap<String, FieldType> = BTreeMap::new();
t.insert(
"Data".into(),
FieldType::Struct(vec![
NamedField {
name: "name".into(),
ty: FieldType::String,
},
NamedField {
name: "symbol".into(),
ty: FieldType::String,
},
NamedField {
name: "uri".into(),
ty: FieldType::String,
},
NamedField {
name: "seller_fee_basis_points".into(),
ty: FieldType::U16,
},
NamedField {
name: "creators".into(),
ty: FieldType::Option(Box::new(FieldType::Vec(Box::new(FieldType::Defined(
"Creator".into(),
))))),
},
]),
);
t.insert(
"DataV2".into(),
FieldType::Struct(vec![
NamedField {
name: "name".into(),
ty: FieldType::String,
},
NamedField {
name: "symbol".into(),
ty: FieldType::String,
},
NamedField {
name: "uri".into(),
ty: FieldType::String,
},
NamedField {
name: "seller_fee_basis_points".into(),
ty: FieldType::U16,
},
NamedField {
name: "creators".into(),
ty: FieldType::Option(Box::new(FieldType::Vec(Box::new(FieldType::Defined(
"Creator".into(),
))))),
},
NamedField {
name: "collection".into(),
ty: FieldType::Option(Box::new(FieldType::Defined("Collection".into()))),
},
NamedField {
name: "uses".into(),
ty: FieldType::Option(Box::new(FieldType::Defined("Uses".into()))),
},
]),
);
t.insert(
"Creator".into(),
FieldType::Struct(vec![
NamedField {
name: "address".into(),
ty: FieldType::Pubkey,
},
NamedField {
name: "verified".into(),
ty: FieldType::Bool,
},
NamedField {
name: "share".into(),
ty: FieldType::U8,
},
]),
);
t.insert(
"Collection".into(),
FieldType::Struct(vec![
NamedField {
name: "verified".into(),
ty: FieldType::Bool,
},
NamedField {
name: "key".into(),
ty: FieldType::Pubkey,
},
]),
);
t.insert(
"Uses".into(),
FieldType::Struct(vec![
NamedField {
name: "use_method".into(),
ty: FieldType::Defined("UseMethod".into()),
},
NamedField {
name: "remaining".into(),
ty: FieldType::U64,
},
NamedField {
name: "total".into(),
ty: FieldType::U64,
},
]),
);
t.insert(
"UseMethod".into(),
FieldType::Enum(vec![
EnumVariant {
name: "Burn".into(),
fields: None,
},
EnumVariant {
name: "Multiple".into(),
fields: None,
},
EnumVariant {
name: "Single".into(),
fields: None,
},
]),
);
t.insert(
"CollectionDetails".into(),
FieldType::Enum(vec![EnumVariant {
name: "V1".into(),
fields: Some(vec![NamedField {
name: "size".into(),
ty: FieldType::U64,
}]),
}]),
);
t.insert(
"BurnArgs".into(),
FieldType::Enum(vec![EnumVariant {
name: "V1".into(),
fields: Some(vec![NamedField {
name: "amount".into(),
ty: FieldType::U64,
}]),
}]),
);
t
}
fn create_metadata_account_v1_accounts() -> Vec<NamedAccount> {
vec![
NamedAccount {
name: "metadata".into(),
writable: true,
signer: false,
optional: false,
},
NamedAccount {
name: "mint".into(),
writable: false,
signer: false,
optional: false,
},
NamedAccount {
name: "mint_authority".into(),
writable: false,
signer: true,
optional: false,
},
NamedAccount {
name: "payer".into(),
writable: true,
signer: true,
optional: false,
},
NamedAccount {
name: "update_authority".into(),
writable: false,
signer: false,
optional: false,
},
NamedAccount {
name: "system_program".into(),
writable: false,
signer: false,
optional: false,
},
NamedAccount {
name: "rent".into(),
writable: false,
signer: false,
optional: false,
},
]
}
fn create_metadata_account_v3_accounts() -> Vec<NamedAccount> {
vec![
NamedAccount {
name: "metadata".into(),
writable: true,
signer: false,
optional: false,
},
NamedAccount {
name: "mint".into(),
writable: false,
signer: false,
optional: false,
},
NamedAccount {
name: "mint_authority".into(),
writable: false,
signer: true,
optional: false,
},
NamedAccount {
name: "payer".into(),
writable: true,
signer: true,
optional: false,
},
NamedAccount {
name: "update_authority".into(),
writable: false,
signer: false,
optional: false,
},
NamedAccount {
name: "system_program".into(),
writable: false,
signer: false,
optional: false,
},
NamedAccount {
name: "rent".into(),
writable: false,
signer: false,
optional: true,
},
]
}
fn create_master_edition_v3_accounts() -> Vec<NamedAccount> {
vec![
NamedAccount {
name: "edition".into(),
writable: true,
signer: false,
optional: false,
},
NamedAccount {
name: "mint".into(),
writable: true,
signer: false,
optional: false,
},
NamedAccount {
name: "update_authority".into(),
writable: false,
signer: true,
optional: false,
},
NamedAccount {
name: "mint_authority".into(),
writable: false,
signer: true,
optional: false,
},
NamedAccount {
name: "payer".into(),
writable: true,
signer: true,
optional: false,
},
NamedAccount {
name: "metadata".into(),
writable: false,
signer: false,
optional: false,
},
NamedAccount {
name: "token_program".into(),
writable: false,
signer: false,
optional: false,
},
NamedAccount {
name: "system_program".into(),
writable: false,
signer: false,
optional: false,
},
NamedAccount {
name: "rent".into(),
writable: false,
signer: false,
optional: true,
},
]
}
fn burn_accounts() -> Vec<NamedAccount> {
vec![
NamedAccount {
name: "authority".into(),
writable: true,
signer: true,
optional: false,
},
NamedAccount {
name: "collection_metadata".into(),
writable: true,
signer: false,
optional: false,
},
NamedAccount {
name: "metadata".into(),
writable: true,
signer: false,
optional: false,
},
NamedAccount {
name: "edition".into(),
writable: true,
signer: false,
optional: false,
},
NamedAccount {
name: "mint".into(),
writable: true,
signer: false,
optional: false,
},
NamedAccount {
name: "token".into(),
writable: true,
signer: false,
optional: false,
},
NamedAccount {
name: "master_edition".into(),
writable: true,
signer: false,
optional: false,
},
NamedAccount {
name: "master_edition_mint".into(),
writable: false,
signer: false,
optional: false,
},
NamedAccount {
name: "master_edition_token".into(),
writable: false,
signer: false,
optional: false,
},
NamedAccount {
name: "edition_marker".into(),
writable: true,
signer: false,
optional: false,
},
NamedAccount {
name: "token_record".into(),
writable: true,
signer: false,
optional: false,
},
NamedAccount {
name: "system_program".into(),
writable: false,
signer: false,
optional: false,
},
NamedAccount {
name: "sysvar_instructions".into(),
writable: false,
signer: false,
optional: false,
},
NamedAccount {
name: "spl_token_program".into(),
writable: false,
signer: false,
optional: false,
},
]
}