Open
Description
right now all instructions are wrapped behind structs, and instruction data are mostly inside implementation inside invoke_signed
.
we can add a trait to export/serialize these instructions.
there're two benefits for this:
- we can easily test against other libraries (e.g. solana-program, anchor, etc.) to see if our pinocchio instruction has the same results
- developers may have more control over the instruction data (not common but may be useful for some hacky stuff)
a draft interface:
pub trait IxSerialize {
fn to_ix_data(&self) -> Box<[u8]>;
}
// For e.g. construction of transaction
impl IxSerialize for Transfer<'_> {
fn to_ix_data(&self) -> Box<[u8]> {
self.to_ix_data()
}
}
and an example impl of token::transfer
impl Transfer<'_> {
#[inline(always)]
pub fn invoke(&self) -> ProgramResult {
self.invoke_signed(&[])
}
pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
// account metadata
let account_metas: [AccountMeta; 3] = [
AccountMeta::writable(self.from.key()),
AccountMeta::writable(self.to.key()),
AccountMeta::readonly_signer(self.authority.key()),
];
let instruction_data = self.to_ix_data();
let instruction = Instruction {
program_id: &crate::ID,
accounts: &account_metas,
data: &instruction_data,
};
invoke_signed(&instruction, &[self.from, self.to, self.authority], signers)
}
fn to_ix_data(&self) -> Box<[u8]> {
// Instruction data layout:
// - [0]: instruction discriminator (1 byte, u8)
// - [1..9]: amount (8 bytes, u64)
let mut instruction_data = Box::new_uninit_slice(9);
// Set discriminator as u8 at offset [0]
write_bytes(&mut instruction_data, &[3]);
// Set amount as u64 at offset [1..9]
write_bytes(&mut instruction_data[1..9], &self.amount.to_le_bytes());
unsafe { instruction_data.assume_init() }
}
}
impl<'a> IxSerialize for Transfer<'a> {
fn to_ix_data(&self) -> Box<[u8]> {
self.to_ix_data()
}
}
Metadata
Metadata
Assignees
Labels
No labels