Skip to content

Commit e31c902

Browse files
refactor(compression+oracles): convert impl blocks to free handle_* functions
All compression examples (cnft-burn, cnft-vault, cutils) and oracles (pyth) refactored. Pyth lib.rs call site updated though the instruction file itself is missing (pre-existing incomplete example).
1 parent cd72458 commit e31c902

9 files changed

Lines changed: 434 additions & 448 deletions

File tree

compression/cnft-burn/quasar/src/instructions/burn_cnft.rs

Lines changed: 68 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -30,87 +30,84 @@ pub struct BurnCnft<'info> {
3030
pub system_program: &'info Program<System>,
3131
}
3232

33-
impl<'info> BurnCnft<'info> {
34-
pub fn burn_cnft(
35-
&self,
36-
ctx: &CtxWithRemaining<'info, BurnCnft<'info>>,
37-
) -> Result<(), ProgramError> {
38-
// Parse instruction args from raw data:
39-
// root(32) + data_hash(32) + creator_hash(32) + nonce(8) + index(4) = 108 bytes
40-
let data = ctx.data;
41-
if data.len() < 108 {
42-
return Err(ProgramError::InvalidInstructionData);
43-
}
33+
pub fn handle_burn_cnft<'info>(
34+
accounts: &BurnCnft<'info>, ctx: &CtxWithRemaining<'info, BurnCnft<'info>>,
35+
) -> Result<(), ProgramError> {
36+
// Parse instruction args from raw data:
37+
// root(32) + data_hash(32) + creator_hash(32) + nonce(8) + index(4) = 108 bytes
38+
let data = ctx.data;
39+
if data.len() < 108 {
40+
return Err(ProgramError::InvalidInstructionData);
41+
}
4442

45-
// Build instruction data: discriminator + args
46-
// 8 + 32 + 32 + 32 + 8 + 4 = 116 bytes
47-
let mut ix_data = [0u8; 116];
48-
ix_data[0..8].copy_from_slice(&BURN_DISCRIMINATOR);
49-
ix_data[8..116].copy_from_slice(&data[0..108]);
43+
// Build instruction data: discriminator + args
44+
// 8 + 32 + 32 + 32 + 8 + 4 = 116 bytes
45+
let mut ix_data = [0u8; 116];
46+
ix_data[0..8].copy_from_slice(&BURN_DISCRIMINATOR);
47+
ix_data[8..116].copy_from_slice(&data[0..108]);
5048

51-
// Collect remaining accounts (proof nodes) into a stack buffer
52-
let remaining = ctx.remaining_accounts();
53-
let placeholder = self.system_program.to_account_view().clone();
54-
let mut proof_views: [AccountView; MAX_PROOF_NODES] =
55-
core::array::from_fn(|_| placeholder.clone());
56-
let mut proof_count = 0usize;
57-
for result in remaining.iter() {
58-
if proof_count >= MAX_PROOF_NODES {
59-
break;
60-
}
61-
proof_views[proof_count] = result?;
62-
proof_count += 1;
49+
// Collect remaining accounts (proof nodes) into a stack buffer
50+
let remaining = ctx.remaining_accounts();
51+
let placeholder = accounts.system_program.to_account_view().clone();
52+
let mut proof_views: [AccountView; MAX_PROOF_NODES] =
53+
core::array::from_fn(|_| placeholder.clone());
54+
let mut proof_count = 0usize;
55+
for result in remaining.iter() {
56+
if proof_count >= MAX_PROOF_NODES {
57+
break;
6358
}
59+
proof_views[proof_count] = result?;
60+
proof_count += 1;
61+
}
6462

65-
let total_accounts = 7 + proof_count;
63+
let total_accounts = 7 + proof_count;
6664

67-
// Build instruction account metas.
68-
// Layout matches mpl-bubblegum Burn: tree_authority, leaf_owner (signer),
69-
// leaf_delegate (= leaf_owner, not signer), merkle_tree, log_wrapper,
70-
// compression_program, system_program, then proof nodes.
71-
let sys_addr = self.system_program.address();
72-
let mut ix_accounts: [InstructionAccount; MAX_CPI_ACCOUNTS] = core::array::from_fn(|_| {
73-
InstructionAccount::readonly(sys_addr)
74-
});
65+
// Build instruction account metas.
66+
// Layout matches mpl-bubblegum Burn: tree_authority, leaf_owner (signer),
67+
// leaf_delegate (= leaf_owner, not signer), merkle_tree, log_wrapper,
68+
// compression_program, system_program, then proof nodes.
69+
let sys_addr = accounts.system_program.address();
70+
let mut ix_accounts: [InstructionAccount; MAX_CPI_ACCOUNTS] = core::array::from_fn(|_| {
71+
InstructionAccount::readonly(sys_addr)
72+
});
7573

76-
ix_accounts[0] = InstructionAccount::readonly(self.tree_authority.address());
77-
ix_accounts[1] = InstructionAccount::readonly_signer(self.leaf_owner.address());
78-
// leaf_delegate = leaf_owner, not a signer in this call
79-
ix_accounts[2] = InstructionAccount::readonly(self.leaf_owner.address());
80-
ix_accounts[3] = InstructionAccount::writable(self.merkle_tree.address());
81-
ix_accounts[4] = InstructionAccount::readonly(self.log_wrapper.address());
82-
ix_accounts[5] = InstructionAccount::readonly(self.compression_program.address());
83-
ix_accounts[6] = InstructionAccount::readonly(self.system_program.address());
74+
ix_accounts[0] = InstructionAccount::readonly(accounts.tree_authority.address());
75+
ix_accounts[1] = InstructionAccount::readonly_signer(accounts.leaf_owner.address());
76+
// leaf_delegate = leaf_owner, not a signer in this call
77+
ix_accounts[2] = InstructionAccount::readonly(accounts.leaf_owner.address());
78+
ix_accounts[3] = InstructionAccount::writable(accounts.merkle_tree.address());
79+
ix_accounts[4] = InstructionAccount::readonly(accounts.log_wrapper.address());
80+
ix_accounts[5] = InstructionAccount::readonly(accounts.compression_program.address());
81+
ix_accounts[6] = InstructionAccount::readonly(accounts.system_program.address());
8482

85-
for i in 0..proof_count {
86-
ix_accounts[7 + i] = InstructionAccount::readonly(proof_views[i].address());
87-
}
83+
for i in 0..proof_count {
84+
ix_accounts[7 + i] = InstructionAccount::readonly(proof_views[i].address());
85+
}
8886

89-
// Build account views array for the CPI
90-
let sys_view = self.system_program.to_account_view().clone();
91-
let mut views: [AccountView; MAX_CPI_ACCOUNTS] = core::array::from_fn(|_| sys_view.clone());
87+
// Build account views array for the CPI
88+
let sys_view = accounts.system_program.to_account_view().clone();
89+
let mut views: [AccountView; MAX_CPI_ACCOUNTS] = core::array::from_fn(|_| sys_view.clone());
9290

93-
views[0] = self.tree_authority.to_account_view().clone();
94-
views[1] = self.leaf_owner.to_account_view().clone();
95-
views[2] = self.leaf_owner.to_account_view().clone(); // leaf_delegate = leaf_owner
96-
views[3] = self.merkle_tree.to_account_view().clone();
97-
views[4] = self.log_wrapper.to_account_view().clone();
98-
views[5] = self.compression_program.to_account_view().clone();
99-
views[6] = self.system_program.to_account_view().clone();
91+
views[0] = accounts.tree_authority.to_account_view().clone();
92+
views[1] = accounts.leaf_owner.to_account_view().clone();
93+
views[2] = accounts.leaf_owner.to_account_view().clone(); // leaf_delegate = leaf_owner
94+
views[3] = accounts.merkle_tree.to_account_view().clone();
95+
views[4] = accounts.log_wrapper.to_account_view().clone();
96+
views[5] = accounts.compression_program.to_account_view().clone();
97+
views[6] = accounts.system_program.to_account_view().clone();
10098

101-
for i in 0..proof_count {
102-
views[7 + i] = proof_views[i].clone();
103-
}
99+
for i in 0..proof_count {
100+
views[7 + i] = proof_views[i].clone();
101+
}
104102

105-
let instruction = InstructionView {
106-
program_id: &MPL_BUBBLEGUM_ID,
107-
data: &ix_data,
108-
accounts: &ix_accounts[..total_accounts],
109-
};
103+
let instruction = InstructionView {
104+
program_id: &MPL_BUBBLEGUM_ID,
105+
data: &ix_data,
106+
accounts: &ix_accounts[..total_accounts],
107+
};
110108

111-
solana_instruction_view::cpi::invoke_with_bounds::<MAX_CPI_ACCOUNTS, AccountView>(
112-
&instruction,
113-
&views[..total_accounts],
114-
)
115-
}
109+
solana_instruction_view::cpi::invoke_with_bounds::<MAX_CPI_ACCOUNTS, AccountView>(
110+
&instruction,
111+
&views[..total_accounts],
112+
)
116113
}

compression/cnft-burn/quasar/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ mod quasar_cnft_burn {
3232

3333
#[instruction(discriminator = 0)]
3434
pub fn burn_cnft(ctx: CtxWithRemaining<BurnCnft>) -> Result<(), ProgramError> {
35-
ctx.accounts.burn_cnft(&ctx)
35+
instructions::handle_burn_cnft(&ctx.accounts, &ctx)
3636
}
3737
}

compression/cnft-vault/quasar/src/instructions/withdraw.rs

Lines changed: 79 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -43,91 +43,88 @@ fn build_transfer_data(args: &[u8]) -> [u8; 8 + TRANSFER_ARGS_LEN] {
4343
ix_data
4444
}
4545

46-
impl<'info> Withdraw<'info> {
47-
pub fn withdraw_cnft(
48-
&self,
49-
ctx: &CtxWithRemaining<'info, Withdraw<'info>>,
50-
) -> Result<(), ProgramError> {
51-
let data = ctx.data;
52-
if data.len() < TRANSFER_ARGS_LEN {
53-
return Err(ProgramError::InvalidInstructionData);
54-
}
55-
56-
let ix_data = build_transfer_data(&data[0..TRANSFER_ARGS_LEN]);
57-
58-
// Collect proof nodes
59-
let remaining = ctx.remaining_accounts();
60-
let placeholder = self.system_program.to_account_view().clone();
61-
let mut proof_views: [AccountView; MAX_PROOF_NODES] =
62-
core::array::from_fn(|_| placeholder.clone());
63-
let mut proof_count = 0usize;
64-
for result in remaining.iter() {
65-
if proof_count >= MAX_PROOF_NODES {
66-
break;
67-
}
68-
proof_views[proof_count] = result?;
69-
proof_count += 1;
70-
}
46+
pub fn handle_withdraw_cnft<'info>(
47+
accounts: &Withdraw<'info>, ctx: &CtxWithRemaining<'info, Withdraw<'info>>,
48+
) -> Result<(), ProgramError> {
49+
let data = ctx.data;
50+
if data.len() < TRANSFER_ARGS_LEN {
51+
return Err(ProgramError::InvalidInstructionData);
52+
}
7153

72-
let total_accounts = 8 + proof_count;
73-
74-
// Build instruction account metas matching mpl-bubblegum Transfer layout:
75-
// tree_config, leaf_owner (signer/PDA), leaf_delegate, new_leaf_owner,
76-
// merkle_tree, log_wrapper, compression_program, system_program, then proofs.
77-
let sys_addr = self.system_program.address();
78-
let mut ix_accounts: [InstructionAccount; MAX_CPI_ACCOUNTS] =
79-
core::array::from_fn(|_| InstructionAccount::readonly(sys_addr));
80-
81-
ix_accounts[0] = InstructionAccount::readonly(self.tree_authority.address());
82-
ix_accounts[1] = InstructionAccount::readonly_signer(self.leaf_owner.address());
83-
// leaf_delegate = leaf_owner, not an additional signer
84-
ix_accounts[2] = InstructionAccount::readonly(self.leaf_owner.address());
85-
ix_accounts[3] = InstructionAccount::readonly(self.new_leaf_owner.address());
86-
ix_accounts[4] = InstructionAccount::writable(self.merkle_tree.address());
87-
ix_accounts[5] = InstructionAccount::readonly(self.log_wrapper.address());
88-
ix_accounts[6] = InstructionAccount::readonly(self.compression_program.address());
89-
ix_accounts[7] = InstructionAccount::readonly(self.system_program.address());
90-
91-
for i in 0..proof_count {
92-
ix_accounts[8 + i] = InstructionAccount::readonly(proof_views[i].address());
54+
let ix_data = build_transfer_data(&data[0..TRANSFER_ARGS_LEN]);
55+
56+
// Collect proof nodes
57+
let remaining = ctx.remaining_accounts();
58+
let placeholder = accounts.system_program.to_account_view().clone();
59+
let mut proof_views: [AccountView; MAX_PROOF_NODES] =
60+
core::array::from_fn(|_| placeholder.clone());
61+
let mut proof_count = 0usize;
62+
for result in remaining.iter() {
63+
if proof_count >= MAX_PROOF_NODES {
64+
break;
9365
}
66+
proof_views[proof_count] = result?;
67+
proof_count += 1;
68+
}
9469

95-
// Build account views
96-
let sys_view = self.system_program.to_account_view().clone();
97-
let mut views: [AccountView; MAX_CPI_ACCOUNTS] =
98-
core::array::from_fn(|_| sys_view.clone());
99-
100-
views[0] = self.tree_authority.to_account_view().clone();
101-
views[1] = self.leaf_owner.to_account_view().clone();
102-
views[2] = self.leaf_owner.to_account_view().clone();
103-
views[3] = self.new_leaf_owner.to_account_view().clone();
104-
views[4] = self.merkle_tree.to_account_view().clone();
105-
views[5] = self.log_wrapper.to_account_view().clone();
106-
views[6] = self.compression_program.to_account_view().clone();
107-
views[7] = self.system_program.to_account_view().clone();
108-
109-
for i in 0..proof_count {
110-
views[8 + i] = proof_views[i].clone();
111-
}
70+
let total_accounts = 8 + proof_count;
71+
72+
// Build instruction account metas matching mpl-bubblegum Transfer layout:
73+
// tree_config, leaf_owner (signer/PDA), leaf_delegate, new_leaf_owner,
74+
// merkle_tree, log_wrapper, compression_program, system_program, then proofs.
75+
let sys_addr = accounts.system_program.address();
76+
let mut ix_accounts: [InstructionAccount; MAX_CPI_ACCOUNTS] =
77+
core::array::from_fn(|_| InstructionAccount::readonly(sys_addr));
78+
79+
ix_accounts[0] = InstructionAccount::readonly(accounts.tree_authority.address());
80+
ix_accounts[1] = InstructionAccount::readonly_signer(accounts.leaf_owner.address());
81+
// leaf_delegate = leaf_owner, not an additional signer
82+
ix_accounts[2] = InstructionAccount::readonly(accounts.leaf_owner.address());
83+
ix_accounts[3] = InstructionAccount::readonly(accounts.new_leaf_owner.address());
84+
ix_accounts[4] = InstructionAccount::writable(accounts.merkle_tree.address());
85+
ix_accounts[5] = InstructionAccount::readonly(accounts.log_wrapper.address());
86+
ix_accounts[6] = InstructionAccount::readonly(accounts.compression_program.address());
87+
ix_accounts[7] = InstructionAccount::readonly(accounts.system_program.address());
88+
89+
for i in 0..proof_count {
90+
ix_accounts[8 + i] = InstructionAccount::readonly(proof_views[i].address());
91+
}
11292

113-
let instruction = InstructionView {
114-
program_id: &MPL_BUBBLEGUM_ID,
115-
data: &ix_data,
116-
accounts: &ix_accounts[..total_accounts],
117-
};
118-
119-
// PDA signer seeds: ["cNFT-vault", bump]
120-
let bump_bytes = [ctx.bumps.leaf_owner];
121-
let seeds: [Seed; 2] = [
122-
Seed::from(b"cNFT-vault" as &[u8]),
123-
Seed::from(&bump_bytes as &[u8]),
124-
];
125-
let signer = Signer::from(&seeds as &[Seed]);
126-
127-
solana_instruction_view::cpi::invoke_signed_with_bounds::<MAX_CPI_ACCOUNTS, AccountView>(
128-
&instruction,
129-
&views[..total_accounts],
130-
&[signer],
131-
)
93+
// Build account views
94+
let sys_view = accounts.system_program.to_account_view().clone();
95+
let mut views: [AccountView; MAX_CPI_ACCOUNTS] =
96+
core::array::from_fn(|_| sys_view.clone());
97+
98+
views[0] = accounts.tree_authority.to_account_view().clone();
99+
views[1] = accounts.leaf_owner.to_account_view().clone();
100+
views[2] = accounts.leaf_owner.to_account_view().clone();
101+
views[3] = accounts.new_leaf_owner.to_account_view().clone();
102+
views[4] = accounts.merkle_tree.to_account_view().clone();
103+
views[5] = accounts.log_wrapper.to_account_view().clone();
104+
views[6] = accounts.compression_program.to_account_view().clone();
105+
views[7] = accounts.system_program.to_account_view().clone();
106+
107+
for i in 0..proof_count {
108+
views[8 + i] = proof_views[i].clone();
132109
}
110+
111+
let instruction = InstructionView {
112+
program_id: &MPL_BUBBLEGUM_ID,
113+
data: &ix_data,
114+
accounts: &ix_accounts[..total_accounts],
115+
};
116+
117+
// PDA signer seeds: ["cNFT-vault", bump]
118+
let bump_bytes = [ctx.bumps.leaf_owner];
119+
let seeds: [Seed; 2] = [
120+
Seed::from(b"cNFT-vault" as &[u8]),
121+
Seed::from(&bump_bytes as &[u8]),
122+
];
123+
let signer = Signer::from(&seeds as &[Seed]);
124+
125+
solana_instruction_view::cpi::invoke_signed_with_bounds::<MAX_CPI_ACCOUNTS, AccountView>(
126+
&instruction,
127+
&views[..total_accounts],
128+
&[signer],
129+
)
133130
}

0 commit comments

Comments
 (0)