name_tokenizer/processor/
edit_data.rs

1//! Edit the data registry of a tokenized domain name
2
3use {
4    bonfida_utils::{
5        checks::{check_account_key, check_account_owner, check_signer},
6        BorshSize, InstructionsAccount,
7    },
8    borsh::{BorshDeserialize, BorshSerialize},
9    solana_program::{
10        account_info::{next_account_info, AccountInfo},
11        entrypoint::ProgramResult,
12        program::invoke_signed,
13        program_error::ProgramError,
14        pubkey::Pubkey,
15    },
16};
17
18use solana_program::{msg, program_pack::Pack};
19use spl_name_service::instruction::update;
20use spl_token::state::Account;
21
22use crate::state::{NftRecord, Tag};
23
24#[derive(BorshDeserialize, BorshSerialize, BorshSize)]
25pub struct Params {
26    /// Offset at which the data should be written into the domain name registry
27    pub offset: u32,
28    /// The data to be written into the registry (overwrites any previous data)
29    pub data: Vec<u8>,
30}
31
32#[derive(InstructionsAccount, Debug)]
33pub struct Accounts<'a, T> {
34    /// The NFT owner account
35    #[cons(signer)]
36    pub nft_owner: &'a T,
37
38    /// The NFT account
39    pub nft_account: &'a T,
40
41    /// The NFT record account
42    pub nft_record: &'a T,
43
44    /// The domain name account
45    #[cons(writable)]
46    pub name_account: &'a T,
47
48    /// The SPL token program account
49    pub spl_token_program: &'a T,
50
51    /// The SPL name service program account
52    pub spl_name_service_program: &'a T,
53}
54
55impl<'a, 'b: 'a> Accounts<'a, AccountInfo<'b>> {
56    pub fn parse(
57        accounts: &'a [AccountInfo<'b>],
58        program_id: &Pubkey,
59    ) -> Result<Self, ProgramError> {
60        let accounts_iter = &mut accounts.iter();
61        let accounts = Accounts {
62            nft_owner: next_account_info(accounts_iter)?,
63            nft_account: next_account_info(accounts_iter)?,
64            nft_record: next_account_info(accounts_iter)?,
65            name_account: next_account_info(accounts_iter)?,
66            spl_token_program: next_account_info(accounts_iter)?,
67            spl_name_service_program: next_account_info(accounts_iter)?,
68        };
69
70        // Check keys
71        check_account_key(accounts.spl_token_program, &spl_token::ID)?;
72        check_account_key(accounts.spl_name_service_program, &spl_name_service::ID)?;
73
74        // Check owners
75        check_account_owner(accounts.nft_account, &spl_token::ID)?;
76        check_account_owner(accounts.nft_record, program_id)?;
77        check_account_owner(accounts.name_account, &spl_name_service::ID)?;
78
79        // Check signer
80        check_signer(accounts.nft_owner)?;
81
82        Ok(accounts)
83    }
84}
85
86pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], params: Params) -> ProgramResult {
87    let accounts = Accounts::parse(accounts, program_id)?;
88
89    let (nft_record_key, _) = NftRecord::find_key(accounts.name_account.key, program_id);
90    check_account_key(accounts.nft_record, &nft_record_key)?;
91
92    let nft_record = NftRecord::from_account_info(accounts.nft_record, Tag::ActiveRecord)?;
93    let nft = Account::unpack(&accounts.nft_account.data.borrow())?;
94
95    if nft.mint != nft_record.nft_mint {
96        msg!("+ NFT mint mismatch");
97        return Err(ProgramError::InvalidArgument);
98    }
99    if nft.amount != 1 {
100        msg!("+ Invalid NFT amount, received {}", nft.amount);
101        return Err(ProgramError::InvalidArgument);
102    }
103    check_account_key(accounts.nft_owner, &nft.owner)?;
104
105    let ix = update(
106        spl_name_service::ID,
107        params.offset,
108        params.data,
109        *accounts.name_account.key,
110        *accounts.nft_record.key,
111        None,
112    )?;
113    let seeds: &[&[u8]] = &[
114        NftRecord::SEED,
115        &accounts.name_account.key.to_bytes(),
116        &[nft_record.nonce],
117    ];
118    invoke_signed(
119        &ix,
120        &[
121            accounts.spl_name_service_program.clone(),
122            accounts.nft_record.clone(),
123            accounts.name_account.clone(),
124        ],
125        &[seeds],
126    )?;
127
128    Ok(())
129}