spl_token_2022/extension/metadata_pointer/
instruction.rs

1#[cfg(feature = "serde-traits")]
2use serde::{Deserialize, Serialize};
3use {
4    crate::{
5        check_program_account,
6        instruction::{encode_instruction, TokenInstruction},
7    },
8    bytemuck::{Pod, Zeroable},
9    num_enum::{IntoPrimitive, TryFromPrimitive},
10    solana_instruction::{AccountMeta, Instruction},
11    solana_program_error::ProgramError,
12    solana_pubkey::Pubkey,
13    spl_pod::optional_keys::OptionalNonZeroPubkey,
14    std::convert::TryInto,
15};
16
17/// Metadata pointer extension instructions
18#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
19#[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))]
20#[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive, TryFromPrimitive)]
21#[repr(u8)]
22pub enum MetadataPointerInstruction {
23    /// Initialize a new mint with a metadata pointer
24    ///
25    /// Fails if the mint has already been initialized, so must be called before
26    /// `InitializeMint`.
27    ///
28    /// The mint must have exactly enough space allocated for the base mint (82
29    /// bytes), plus 83 bytes of padding, 1 byte reserved for the account type,
30    /// then space required for this extension, plus any others.
31    ///
32    /// Accounts expected by this instruction:
33    ///
34    ///   0. `[writable]` The mint to initialize.
35    ///
36    /// Data expected by this instruction:
37    ///   `crate::extension::metadata_pointer::instruction::InitializeInstructionData`
38    Initialize,
39    /// Update the metadata pointer address. Only supported for mints that
40    /// include the `MetadataPointer` extension.
41    ///
42    /// Accounts expected by this instruction:
43    ///
44    ///   * Single authority
45    ///   0. `[writable]` The mint.
46    ///   1. `[signer]` The metadata pointer authority.
47    ///
48    ///   * Multisignature authority
49    ///   0. `[writable]` The mint.
50    ///   1. `[]` The mint's metadata pointer authority.
51    ///   2. `..2+M` `[signer]` M signer accounts.
52    ///
53    /// Data expected by this instruction:
54    ///   `crate::extension::metadata_pointer::instruction::UpdateInstructionData`
55    Update,
56}
57
58/// Data expected by `Initialize`
59#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
60#[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))]
61#[derive(Clone, Copy, Pod, Zeroable)]
62#[repr(C)]
63pub struct InitializeInstructionData {
64    /// The public key for the account that can update the metadata address
65    pub authority: OptionalNonZeroPubkey,
66    /// The account address that holds the metadata
67    pub metadata_address: OptionalNonZeroPubkey,
68}
69
70/// Data expected by `Update`
71#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
72#[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))]
73#[derive(Clone, Copy, Pod, Zeroable)]
74#[repr(C)]
75pub struct UpdateInstructionData {
76    /// The new account address that holds the metadata
77    pub metadata_address: OptionalNonZeroPubkey,
78}
79
80/// Create an `Initialize` instruction
81pub fn initialize(
82    token_program_id: &Pubkey,
83    mint: &Pubkey,
84    authority: Option<Pubkey>,
85    metadata_address: Option<Pubkey>,
86) -> Result<Instruction, ProgramError> {
87    check_program_account(token_program_id)?;
88    let accounts = vec![AccountMeta::new(*mint, false)];
89    Ok(encode_instruction(
90        token_program_id,
91        accounts,
92        TokenInstruction::MetadataPointerExtension,
93        MetadataPointerInstruction::Initialize,
94        &InitializeInstructionData {
95            authority: authority.try_into()?,
96            metadata_address: metadata_address.try_into()?,
97        },
98    ))
99}
100
101/// Create an `Update` instruction
102pub fn update(
103    token_program_id: &Pubkey,
104    mint: &Pubkey,
105    authority: &Pubkey,
106    signers: &[&Pubkey],
107    metadata_address: Option<Pubkey>,
108) -> Result<Instruction, ProgramError> {
109    check_program_account(token_program_id)?;
110    let mut accounts = vec![
111        AccountMeta::new(*mint, false),
112        AccountMeta::new_readonly(*authority, signers.is_empty()),
113    ];
114    for signer_pubkey in signers.iter() {
115        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
116    }
117    Ok(encode_instruction(
118        token_program_id,
119        accounts,
120        TokenInstruction::MetadataPointerExtension,
121        MetadataPointerInstruction::Update,
122        &UpdateInstructionData {
123            metadata_address: metadata_address.try_into()?,
124        },
125    ))
126}