antegen_fiber_program/state/
instruction.rs1use anchor_lang::prelude::*;
2use anchor_lang::solana_program::instruction::{AccountMeta, Instruction};
3use std::collections::HashMap;
4
5#[derive(AnchorDeserialize, AnchorSerialize, Clone, Debug)]
7pub struct SerializableInstruction {
8 pub program_id: Pubkey,
9 pub accounts: Vec<SerializableAccountMeta>,
10 pub data: Vec<u8>,
11}
12
13#[derive(AnchorDeserialize, AnchorSerialize, Clone, Debug)]
15pub struct SerializableAccountMeta {
16 pub pubkey: Pubkey,
17 pub is_signer: bool,
18 pub is_writable: bool,
19}
20
21impl From<Instruction> for SerializableInstruction {
22 fn from(ix: Instruction) -> Self {
23 SerializableInstruction {
24 program_id: ix.program_id,
25 accounts: ix
26 .accounts
27 .into_iter()
28 .map(|acc| SerializableAccountMeta {
29 pubkey: acc.pubkey,
30 is_signer: acc.is_signer,
31 is_writable: acc.is_writable,
32 })
33 .collect(),
34 data: ix.data,
35 }
36 }
37}
38
39impl From<SerializableInstruction> for Instruction {
40 fn from(ix: SerializableInstruction) -> Self {
41 Instruction {
42 program_id: ix.program_id,
43 accounts: ix
44 .accounts
45 .into_iter()
46 .map(|acc| AccountMeta {
47 pubkey: acc.pubkey,
48 is_signer: acc.is_signer,
49 is_writable: acc.is_writable,
50 })
51 .collect(),
52 data: ix.data,
53 }
54 }
55}
56
57#[derive(AnchorDeserialize, AnchorSerialize, Clone, Debug)]
59pub struct CompiledInstructionData {
60 pub program_id_index: u8,
61 pub accounts: Vec<u8>,
62 pub data: Vec<u8>,
63}
64
65#[derive(AnchorDeserialize, AnchorSerialize, Clone, Debug)]
67pub struct CompiledInstructionV0 {
68 pub num_ro_signers: u8,
69 pub num_rw_signers: u8,
70 pub num_rw: u8,
71 pub instructions: Vec<CompiledInstructionData>,
72 pub accounts: Vec<Pubkey>,
73}
74
75pub fn compile_instruction(
77 instruction: Instruction,
78) -> Result<CompiledInstructionV0> {
79 let mut pubkeys_to_metadata: HashMap<Pubkey, AccountMeta> = HashMap::new();
80
81 pubkeys_to_metadata.insert(
83 instruction.program_id,
84 AccountMeta {
85 pubkey: instruction.program_id,
86 is_signer: false,
87 is_writable: false,
88 },
89 );
90
91 for acc in &instruction.accounts {
93 let entry = pubkeys_to_metadata
94 .entry(acc.pubkey)
95 .or_insert(AccountMeta {
96 pubkey: acc.pubkey,
97 is_signer: false,
98 is_writable: false,
99 });
100 if acc.pubkey != instruction.program_id {
104 entry.is_signer |= acc.is_signer;
105 entry.is_writable |= acc.is_writable;
106 }
107 }
108
109 let mut sorted_accounts: Vec<Pubkey> = pubkeys_to_metadata.keys().cloned().collect();
111 sorted_accounts.sort_by(|a, b| {
112 let a_meta = &pubkeys_to_metadata[a];
113 let b_meta = &pubkeys_to_metadata[b];
114
115 fn get_priority(meta: &AccountMeta) -> u8 {
116 match (meta.is_signer, meta.is_writable) {
117 (true, true) => 0,
118 (true, false) => 1,
119 (false, true) => 2,
120 (false, false) => 3,
121 }
122 }
123
124 get_priority(a_meta).cmp(&get_priority(b_meta))
125 });
126
127 let mut num_rw_signers = 0u8;
129 let mut num_ro_signers = 0u8;
130 let mut num_rw = 0u8;
131
132 for pubkey in &sorted_accounts {
133 let meta = &pubkeys_to_metadata[pubkey];
134 if meta.is_signer && meta.is_writable {
135 num_rw_signers += 1;
136 } else if meta.is_signer && !meta.is_writable {
137 num_ro_signers += 1;
138 } else if meta.is_writable {
139 num_rw += 1;
140 }
141 }
142
143 let accounts_to_index: HashMap<Pubkey, u8> = sorted_accounts
145 .iter()
146 .enumerate()
147 .map(|(i, k)| (*k, i as u8))
148 .collect();
149
150 let compiled_instruction = CompiledInstructionData {
152 program_id_index: *accounts_to_index.get(&instruction.program_id).unwrap(),
153 accounts: instruction
154 .accounts
155 .iter()
156 .map(|acc| *accounts_to_index.get(&acc.pubkey).unwrap())
157 .collect(),
158 data: instruction.data,
159 };
160
161 Ok(CompiledInstructionV0 {
162 num_ro_signers,
163 num_rw_signers,
164 num_rw,
165 instructions: vec![compiled_instruction],
166 accounts: sorted_accounts,
167 })
168}
169
170pub fn decompile_instruction(compiled: &CompiledInstructionV0) -> Result<Instruction> {
172 if compiled.instructions.is_empty() {
173 return Err(ProgramError::InvalidInstructionData.into());
174 }
175
176 let ix = &compiled.instructions[0];
177 let program_id = compiled.accounts[ix.program_id_index as usize];
178
179 let accounts: Vec<AccountMeta> = ix
180 .accounts
181 .iter()
182 .enumerate()
183 .map(|(_i, &idx)| {
184 let pubkey = compiled.accounts[idx as usize];
185 let is_writable = if idx < compiled.num_rw_signers {
186 true
187 } else if idx < compiled.num_rw_signers + compiled.num_ro_signers {
188 false
189 } else if idx < compiled.num_rw_signers + compiled.num_ro_signers + compiled.num_rw {
190 true
191 } else {
192 false
193 };
194 let is_signer = idx < compiled.num_rw_signers + compiled.num_ro_signers;
195
196 AccountMeta {
197 pubkey,
198 is_signer,
199 is_writable,
200 }
201 })
202 .collect();
203
204 Ok(Instruction {
205 program_id,
206 accounts,
207 data: ix.data.clone(),
208 })
209}