token_metadata_descriptor/instructions/
initialize_with_buffer.rs

1use anchor_lang::prelude::*;
2use anchor_spl::token::Mint;
3use mpl_token_metadata::state::{Metadata, TokenMetadataAccount};
4
5use crate::{
6    state::{Encoding, Range},
7    utils::{initialize_descriptor_helper, verify_empty_account, verify_metadata},
8};
9
10#[derive(Accounts)]
11#[instruction(range: Option<Range>, encoding: Encoding, bump: u8)]
12pub struct InitializeWithBuffer<'info> {
13    /// entity that funds transaction
14    #[account(mut)]
15    pub payer: Signer<'info>,
16
17    /// descriptor authority, same as metadata update authority
18    pub authority: Signer<'info>,
19
20    /// CHECK: descriptor account to initialize
21    #[account(mut)]
22    pub descriptor: UncheckedAccount<'info>,
23
24    /// mint associated with the descriptor
25    pub mint: Account<'info, Mint>,
26
27    /// CHECK: read-only account
28    pub buffer: UncheckedAccount<'info>,
29
30    /// CHECK: metadata associated with the mint
31    #[account(
32        constraint = token_metadata.owner == token_metadata_program.key &&
33        token_metadata.to_account_info().data_len() > 0
34    )]
35    pub token_metadata: UncheckedAccount<'info>,
36
37    /// CHECK: token metadata program
38    #[account(address = mpl_token_metadata::id())]
39    pub token_metadata_program: UncheckedAccount<'info>,
40
41    pub system_program: Program<'info, System>,
42}
43
44pub fn initialize_with_buffer_handler(
45    ctx: Context<InitializeWithBuffer>,
46    range: Option<Range>,
47    encoding: Encoding,
48    bump: u8,
49) -> Result<()> {
50    let payer_account_info = &ctx.accounts.payer.to_account_info();
51    let authority_account_info = &ctx.accounts.authority.to_account_info();
52    let descriptor_account_info = &ctx.accounts.descriptor.to_account_info();
53    let mint_account_info = &ctx.accounts.mint.to_account_info();
54    let token_metadata_account_info = &ctx.accounts.token_metadata.to_account_info();
55    let system_program_info = &ctx.accounts.system_program.to_account_info();
56    let buffer_account_info = &ctx.accounts.buffer.to_account_info();
57
58    let rent = Rent::get()?;
59    let mint_key = mint_account_info.key();
60
61    let metadata = Metadata::from_account_info(&token_metadata_account_info.to_account_info())?;
62
63    verify_metadata(
64        &metadata,
65        &authority_account_info.key(),
66        &mint_account_info.key(),
67    )?;
68    verify_empty_account(&descriptor_account_info)?;
69
70    let (buffer_start, buffer_end) = match range {
71        Some(r) => (r.start as usize, r.end as usize),
72        None => (0, buffer_account_info.data_len()),
73    };
74
75    let buffer_range_length = buffer_end - buffer_start;
76
77    let descriptor = initialize_descriptor_helper(
78        &payer_account_info,
79        &descriptor_account_info,
80        &system_program_info,
81        &rent,
82        bump,
83        &mint_key,
84        encoding,
85        buffer_range_length as u32,
86    )?;
87
88    let descriptor_bytes = descriptor.try_to_vec().unwrap();
89    let descriptor_attributes_len = descriptor_bytes.len();
90
91    let descriptor_account_data = &mut descriptor_account_info.data.borrow_mut();
92    descriptor_account_data[0..descriptor_attributes_len].copy_from_slice(&descriptor_bytes);
93
94    let descriptor_range_end = descriptor_bytes.len() + buffer_range_length;
95    descriptor_account_data[descriptor_attributes_len..descriptor_range_end]
96        .copy_from_slice(&buffer_account_info.data.borrow()[buffer_start..buffer_end]);
97
98    Ok(())
99}