Skip to content

Commit c008130

Browse files
committed
nft-operations pinocchio: migrate to pinocchio 0.11
Rebased onto main, which bumped pinocchio 0.10 -> 0.11 and dropped the pinocchio-pubkey crate. Adapt to the 0.11 API: - Derive the mint-authority PDA on-chain with Address::find_program_address (via solana-address's curve25519 feature, matching the merged block-list example) instead of pinocchio_pubkey::derive_address; reject a non-canonical bump in each instruction. - process_instruction / instruction handlers take &mut [AccountView]; pass copied AccountViews into the Metaplex CPIs. - pinocchio-token MintTo gained multisig_signers (&[]).
1 parent dee10d6 commit c008130

7 files changed

Lines changed: 51 additions & 147 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tokens/nft-operations/pinocchio/program/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ edition = "2021"
66
[dependencies]
77
pinocchio.workspace = true
88
pinocchio-log.workspace = true
9-
pinocchio-pubkey.workspace = true
109
pinocchio-system.workspace = true
1110
pinocchio-token.workspace = true
1211
pinocchio-associated-token-account.workspace = true
12+
# `curve25519` enables on-chain `Address::find_program_address` (pinocchio 0.11
13+
# re-exports `Address` from `solana-address`); matches the merged block-list example.
14+
solana-address = { version = "2", features = ["curve25519"] }
1315

1416
[lib]
1517
crate-type = ["cdylib", "lib"]

tokens/nft-operations/pinocchio/program/src/instructions/create_collection.rs

Lines changed: 14 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@ use pinocchio::{
66
};
77
use pinocchio_associated_token_account::instructions::CreateIdempotent;
88
use pinocchio_log::log;
9-
use pinocchio_pubkey::derive_address;
109
use pinocchio_system::instructions::CreateAccount;
1110
use pinocchio_token::instructions::{InitializeMint2, MintTo};
1211

1312
use crate::instructions::{
14-
build_metadata_data, create_master_edition_cpi, create_metadata_cpi, read_bump, AUTHORITY_SEED,
15-
MINT_SIZE, TOKEN_DECIMALS,
13+
build_metadata_data, create_master_edition_cpi, create_metadata_cpi, read_bump, AUTHORITY_SEED, MINT_SIZE,
14+
TOKEN_DECIMALS,
1615
};
1716

1817
/// Creates a collection NFT: a 0-decimal mint whose authority is the program's
@@ -32,11 +31,7 @@ use crate::instructions::{
3231
/// 9. `[]` token metadata program
3332
///
3433
/// Instruction data: `[authority_bump: u8]`.
35-
pub fn create_collection(
36-
program_id: &Address,
37-
accounts: &[AccountView],
38-
args: &[u8],
39-
) -> ProgramResult {
34+
pub fn create_collection(program_id: &Address, accounts: &mut [AccountView], args: &[u8]) -> ProgramResult {
4035
let [user, mint, mint_authority, metadata, master_edition, destination, system_program, token_program, _associated_token_program, _token_metadata_program] =
4136
accounts
4237
else {
@@ -49,8 +44,9 @@ pub fn create_collection(
4944

5045
// Confirm the supplied account is the canonical mint-authority PDA.
5146
let bump = read_bump(args)?;
52-
let pda = derive_address(&[AUTHORITY_SEED], Some(bump), program_id.as_array());
53-
if mint_authority.address().as_array() != &pda {
47+
// Derive the canonical PDA on-chain and reject a non-canonical bump.
48+
let (pda, canonical_bump) = Address::find_program_address(&[AUTHORITY_SEED], program_id);
49+
if mint_authority.address() != &pda || bump != canonical_bump {
5450
return Err(ProgramError::InvalidSeeds);
5551
}
5652

@@ -59,14 +55,7 @@ pub fn create_collection(
5955
let rent = Rent::get()?;
6056
let lamports = rent.try_minimum_balance(MINT_SIZE)?;
6157
log!("Creating mint account");
62-
CreateAccount {
63-
from: user,
64-
to: mint,
65-
lamports,
66-
space: MINT_SIZE as u64,
67-
owner: &pinocchio_token::ID,
68-
}
69-
.invoke()?;
58+
CreateAccount { from: user, to: mint, lamports, space: MINT_SIZE as u64, owner: &pinocchio_token::ID }.invoke()?;
7059

7160
log!("Initializing mint account");
7261
InitializeMint2 {
@@ -83,43 +72,17 @@ pub fn create_collection(
8372
let signers = [Signer::from(&seeds)];
8473

8574
log!("Creating destination token account");
86-
CreateIdempotent {
87-
funding_account: user,
88-
account: destination,
89-
wallet: user,
90-
mint,
91-
system_program,
92-
token_program,
93-
}
94-
.invoke()?;
75+
CreateIdempotent { funding_account: user, account: destination, wallet: user, mint, system_program, token_program }
76+
.invoke()?;
9577

9678
log!("Minting collection NFT");
97-
MintTo {
98-
mint,
99-
account: destination,
100-
mint_authority,
101-
amount: 1,
102-
}
103-
.invoke_signed(&signers)?;
79+
MintTo { mint, account: destination, mint_authority, amount: 1, multisig_signers: &[] as &[&AccountView] }
80+
.invoke_signed(&signers)?;
10481

10582
log!("Creating metadata account");
106-
let metadata_data = build_metadata_data(
107-
"DummyCollection",
108-
"DC",
109-
"",
110-
mint_authority.address().as_array(),
111-
None,
112-
true,
113-
);
114-
create_metadata_cpi(
115-
metadata,
116-
mint,
117-
mint_authority,
118-
user,
119-
system_program,
120-
&metadata_data,
121-
&signers,
122-
)?;
83+
let metadata_data =
84+
build_metadata_data("DummyCollection", "DC", "", mint_authority.address().as_array(), None, true);
85+
create_metadata_cpi(metadata, mint, mint_authority, user, system_program, &metadata_data, &signers)?;
12386

12487
log!("Creating master edition account");
12588
create_master_edition_cpi(

tokens/nft-operations/pinocchio/program/src/instructions/mint_nft.rs

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@ use pinocchio::{
66
};
77
use pinocchio_associated_token_account::instructions::CreateIdempotent;
88
use pinocchio_log::log;
9-
use pinocchio_pubkey::derive_address;
109
use pinocchio_system::instructions::CreateAccount;
1110
use pinocchio_token::instructions::{InitializeMint2, MintTo};
1211

1312
use crate::instructions::{
14-
build_metadata_data, create_master_edition_cpi, create_metadata_cpi, read_bump, AUTHORITY_SEED,
15-
MINT_SIZE, TOKEN_DECIMALS,
13+
build_metadata_data, create_master_edition_cpi, create_metadata_cpi, read_bump, AUTHORITY_SEED, MINT_SIZE,
14+
TOKEN_DECIMALS,
1615
};
1716

1817
/// Mints an NFT that belongs to a collection: a 0-decimal mint (authority = the
@@ -34,7 +33,7 @@ use crate::instructions::{
3433
/// 10. `[]` token metadata program
3534
///
3635
/// Instruction data: `[authority_bump: u8]`.
37-
pub fn mint_nft(program_id: &Address, accounts: &[AccountView], args: &[u8]) -> ProgramResult {
36+
pub fn mint_nft(program_id: &Address, accounts: &mut [AccountView], args: &[u8]) -> ProgramResult {
3837
let [owner, mint, mint_authority, metadata, master_edition, destination, collection_mint, system_program, token_program, _associated_token_program, _token_metadata_program] =
3938
accounts
4039
else {
@@ -47,8 +46,9 @@ pub fn mint_nft(program_id: &Address, accounts: &[AccountView], args: &[u8]) ->
4746

4847
// Confirm the supplied account is the canonical mint-authority PDA.
4948
let bump = read_bump(args)?;
50-
let pda = derive_address(&[AUTHORITY_SEED], Some(bump), program_id.as_array());
51-
if mint_authority.address().as_array() != &pda {
49+
// Derive the canonical PDA on-chain and reject a non-canonical bump.
50+
let (pda, canonical_bump) = Address::find_program_address(&[AUTHORITY_SEED], program_id);
51+
if mint_authority.address() != &pda || bump != canonical_bump {
5252
return Err(ProgramError::InvalidSeeds);
5353
}
5454

@@ -57,14 +57,7 @@ pub fn mint_nft(program_id: &Address, accounts: &[AccountView], args: &[u8]) ->
5757
let rent = Rent::get()?;
5858
let lamports = rent.try_minimum_balance(MINT_SIZE)?;
5959
log!("Creating mint account");
60-
CreateAccount {
61-
from: owner,
62-
to: mint,
63-
lamports,
64-
space: MINT_SIZE as u64,
65-
owner: &pinocchio_token::ID,
66-
}
67-
.invoke()?;
60+
CreateAccount { from: owner, to: mint, lamports, space: MINT_SIZE as u64, owner: &pinocchio_token::ID }.invoke()?;
6861

6962
log!("Initializing mint account");
7063
InitializeMint2 {
@@ -92,13 +85,8 @@ pub fn mint_nft(program_id: &Address, accounts: &[AccountView], args: &[u8]) ->
9285
.invoke()?;
9386

9487
log!("Minting NFT");
95-
MintTo {
96-
mint,
97-
account: destination,
98-
mint_authority,
99-
amount: 1,
100-
}
101-
.invoke_signed(&signers)?;
88+
MintTo { mint, account: destination, mint_authority, amount: 1, multisig_signers: &[] as &[&AccountView] }
89+
.invoke_signed(&signers)?;
10290

10391
log!("Creating metadata account");
10492
let metadata_data = build_metadata_data(
@@ -109,15 +97,7 @@ pub fn mint_nft(program_id: &Address, accounts: &[AccountView], args: &[u8]) ->
10997
Some(collection_mint.address().as_array()),
11098
false,
11199
);
112-
create_metadata_cpi(
113-
metadata,
114-
mint,
115-
mint_authority,
116-
owner,
117-
system_program,
118-
&metadata_data,
119-
&signers,
120-
)?;
100+
create_metadata_cpi(metadata, mint, mint_authority, owner, system_program, &metadata_data, &signers)?;
121101

122102
log!("Creating master edition account");
123103
create_master_edition_cpi(

tokens/nft-operations/pinocchio/program/src/instructions/mod.rs

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,7 @@ const VERIFY_COLLECTION_V1: u8 = 1;
4242

4343
/// Reads the `authority_bump` carried by every instruction's data.
4444
pub(crate) fn read_bump(args: &[u8]) -> Result<u8, ProgramError> {
45-
args.first()
46-
.copied()
47-
.ok_or(ProgramError::InvalidInstructionData)
45+
args.first().copied().ok_or(ProgramError::InvalidInstructionData)
4846
}
4947

5048
/// Serializes the data for a Metaplex `CreateMetadataAccountV3` instruction.
@@ -149,23 +147,8 @@ pub(crate) fn create_metadata_cpi(
149147
InstructionAccount::readonly(mint_authority.address()),
150148
InstructionAccount::readonly(system_program.address()),
151149
];
152-
let instruction = InstructionView {
153-
program_id: &TOKEN_METADATA_PROGRAM_ID,
154-
accounts: &accounts,
155-
data,
156-
};
157-
invoke_signed(
158-
&instruction,
159-
&[
160-
metadata,
161-
mint,
162-
mint_authority,
163-
payer,
164-
mint_authority,
165-
system_program,
166-
],
167-
signers,
168-
)
150+
let instruction = InstructionView { program_id: &TOKEN_METADATA_PROGRAM_ID, accounts: &accounts, data };
151+
invoke_signed(&instruction, &[*metadata, *mint, *mint_authority, *payer, *mint_authority, *system_program], signers)
169152
}
170153

171154
/// Invokes Metaplex `CreateMasterEditionV3`, signed by the mint-authority PDA.
@@ -196,23 +179,10 @@ pub(crate) fn create_master_edition_cpi(
196179
InstructionAccount::readonly(token_program.address()),
197180
InstructionAccount::readonly(system_program.address()),
198181
];
199-
let instruction = InstructionView {
200-
program_id: &TOKEN_METADATA_PROGRAM_ID,
201-
accounts: &accounts,
202-
data: &data,
203-
};
182+
let instruction = InstructionView { program_id: &TOKEN_METADATA_PROGRAM_ID, accounts: &accounts, data: &data };
204183
invoke_signed(
205184
&instruction,
206-
&[
207-
edition,
208-
mint,
209-
mint_authority,
210-
mint_authority,
211-
payer,
212-
metadata,
213-
token_program,
214-
system_program,
215-
],
185+
&[*edition, *mint, *mint_authority, *mint_authority, *payer, *metadata, *token_program, *system_program],
216186
signers,
217187
)
218188
}

tokens/nft-operations/pinocchio/program/src/instructions/verify_collection.rs

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@ use pinocchio::{
55
AccountView, Address, ProgramResult,
66
};
77
use pinocchio_log::log;
8-
use pinocchio_pubkey::derive_address;
98

10-
use crate::instructions::{
11-
build_verify_collection_data, read_bump, AUTHORITY_SEED, TOKEN_METADATA_PROGRAM_ID,
12-
};
9+
use crate::instructions::{build_verify_collection_data, read_bump, AUTHORITY_SEED, TOKEN_METADATA_PROGRAM_ID};
1310

1411
/// Verifies an NFT as a member of its collection via the Metaplex `Verify`
1512
/// instruction (`VerificationArgs::CollectionV1`), signed by the collection's
@@ -27,11 +24,7 @@ use crate::instructions::{
2724
/// 8. `[]` token metadata program
2825
///
2926
/// Instruction data: `[authority_bump: u8]`.
30-
pub fn verify_collection(
31-
program_id: &Address,
32-
accounts: &[AccountView],
33-
args: &[u8],
34-
) -> ProgramResult {
27+
pub fn verify_collection(program_id: &Address, accounts: &mut [AccountView], args: &[u8]) -> ProgramResult {
3528
let [payer, mint_authority, metadata, collection_mint, collection_metadata, collection_master_edition, system_program, sysvar_instructions, token_metadata_program] =
3629
accounts
3730
else {
@@ -44,8 +37,9 @@ pub fn verify_collection(
4437

4538
// Confirm the supplied account is the canonical mint-authority PDA.
4639
let bump = read_bump(args)?;
47-
let pda = derive_address(&[AUTHORITY_SEED], Some(bump), program_id.as_array());
48-
if mint_authority.address().as_array() != &pda {
40+
// Derive the canonical PDA on-chain and reject a non-canonical bump.
41+
let (pda, canonical_bump) = Address::find_program_address(&[AUTHORITY_SEED], program_id);
42+
if mint_authority.address() != &pda || bump != canonical_bump {
4943
return Err(ProgramError::InvalidSeeds);
5044
}
5145

@@ -67,24 +61,21 @@ pub fn verify_collection(
6761
InstructionAccount::readonly(system_program.address()),
6862
InstructionAccount::readonly(sysvar_instructions.address()),
6963
];
70-
let instruction = InstructionView {
71-
program_id: &TOKEN_METADATA_PROGRAM_ID,
72-
accounts: &verify_accounts,
73-
data: &data,
74-
};
64+
let instruction =
65+
InstructionView { program_id: &TOKEN_METADATA_PROGRAM_ID, accounts: &verify_accounts, data: &data };
7566

7667
log!("Verifying collection");
7768
invoke_signed(
7869
&instruction,
7970
&[
80-
mint_authority,
81-
token_metadata_program,
82-
metadata,
83-
collection_mint,
84-
collection_metadata,
85-
collection_master_edition,
86-
system_program,
87-
sysvar_instructions,
71+
*mint_authority,
72+
*token_metadata_program,
73+
*metadata,
74+
*collection_mint,
75+
*collection_metadata,
76+
*collection_master_edition,
77+
*system_program,
78+
*sysvar_instructions,
8879
],
8980
&signers,
9081
)?;

tokens/nft-operations/pinocchio/program/src/processor.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,10 @@ use crate::instructions::{create_collection, mint_nft, verify_collection};
1515
/// derives this bump on-chain instead).
1616
pub fn process_instruction(
1717
program_id: &Address,
18-
accounts: &[AccountView],
18+
accounts: &mut [AccountView],
1919
instruction_data: &[u8],
2020
) -> ProgramResult {
21-
let (discriminator, args) = instruction_data
22-
.split_first()
23-
.ok_or(ProgramError::InvalidInstructionData)?;
21+
let (discriminator, args) = instruction_data.split_first().ok_or(ProgramError::InvalidInstructionData)?;
2422

2523
match *discriminator {
2624
0 => {

0 commit comments

Comments
 (0)