1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#![deny(rustdoc::all)]
#![allow(rustdoc::missing_doc_code_examples)]
use anchor_lang::prelude::*;
use anchor_lang::solana_program::instruction::Instruction;
use anchor_lang::solana_program::program::invoke_signed;
use anchor_lang::Key;
use anchor_spl::token::TokenAccount;
use vipers::assert_keys;
use vipers::validate::Validate;
mod account_validators;
declare_id!("NFTUJzSHuUCsMMqMRJpB7PmbsaU7Wm51acdPk2FXMLn");
#[program]
pub mod token_signer {
use super::*;
#[access_control(ctx.accounts.validate())]
pub fn invoke_signed_instruction(
ctx: Context<InvokeSignedInstruction>,
data: Vec<u8>,
) -> ProgramResult {
let mint = ctx.accounts.nft_account.mint.to_bytes();
let seeds: &[&[u8]] = &[b"GokiTokenSigner", &mint];
let (nft_addr, bump) = Pubkey::find_program_address(seeds, ctx.program_id);
let full_seeds = &[b"GokiTokenSigner" as &[u8], &mint, &[bump]];
assert_keys!(nft_addr, ctx.accounts.nft_pda, "nft_pda");
let accounts: Vec<AccountMeta> = ctx
.remaining_accounts
.iter()
.map(|acc| AccountMeta {
pubkey: acc.key(),
is_signer: if acc.key() == ctx.accounts.nft_pda.key() {
true
} else {
acc.is_signer
},
is_writable: acc.is_writable,
})
.collect();
let ix = Instruction {
program_id: ctx.remaining_accounts[0].key(),
accounts,
data,
};
invoke_signed(&ix, ctx.remaining_accounts, &[full_seeds])?;
Ok(())
}
}
#[derive(Accounts)]
#[instruction(bump: u8)]
pub struct InvokeSignedInstruction<'info> {
pub owner_authority: Signer<'info>,
pub nft_account: Account<'info, TokenAccount>,
#[account(
seeds = [
b"GokiTokenSigner",
nft_account.mint.as_ref()
],
bump = bump,
)]
pub nft_pda: UncheckedAccount<'info>,
}
#[error]
pub enum ErrorCode {
#[msg("Unauthorized.")]
Unauthorized,
}