66//! 3. Construct EQ02 signed quote
77//! 4. CPI to Executor's request_for_execution
88
9+ use bytemuck:: { Pod , Zeroable } ;
910use pinocchio:: {
1011 account_info:: AccountInfo , program_error:: ProgramError , pubkey:: Pubkey , ProgramResult ,
1112} ;
@@ -18,6 +19,27 @@ use crate::{
1819 state:: { load_account, Config , QuoterRegistration , EXPIRY_TIME_MAX } ,
1920} ;
2021
22+ /// Fixed header for RequestExecution instruction data.
23+ /// Fields are ordered for optimal alignment (amount first as u64).
24+ /// Variable-length fields (request_bytes, relay_instructions) follow after.
25+ /// Total size: 104 bytes (padded for u64 alignment).
26+ #[ repr( C ) ]
27+ #[ derive( Pod , Zeroable , Clone , Copy ) ]
28+ pub struct RequestExecutionHeader {
29+ pub amount : u64 ,
30+ pub quoter_address : [ u8 ; 20 ] ,
31+ pub dst_chain : u16 ,
32+ pub dst_addr : [ u8 ; 32 ] ,
33+ pub refund_addr : [ u8 ; 32 ] ,
34+ pub _padding1 : [ u8 ; 2 ] ,
35+ pub request_bytes_len : u32 ,
36+ pub _padding2 : [ u8 ; 4 ] ,
37+ }
38+
39+ impl RequestExecutionHeader {
40+ pub const LEN : usize = core:: mem:: size_of :: < Self > ( ) ;
41+ }
42+
2143/// RequestExecution instruction.
2244///
2345/// Accounts:
@@ -30,67 +52,49 @@ use crate::{
3052/// 6. `[writable]` refund_addr - Receives any excess payment
3153/// 7. `[]` system_program
3254/// 8-11. `[]` quoter accounts: quoter_config, chain_info, quote_body, event_cpi
33- ///
34- /// Instruction data layout:
35- /// - quoter_address: [u8; 20] (20 bytes)
36- /// - amount: u64 le (8 bytes) - The amount being paid (msg.value equivalent)
37- /// - dst_chain: u16 le (2 bytes)
38- /// - dst_addr: [u8; 32] (32 bytes)
39- /// - refund_addr_bytes: [u8; 32] (32 bytes) - Universal address for refund
40- /// - request_bytes_len: u32 le (4 bytes)
41- /// - request_bytes: [u8; request_bytes_len]
42- /// - relay_instructions_len: u32 le (4 bytes)
43- /// - relay_instructions: [u8; relay_instructions_len]
4455pub fn process ( program_id : & Pubkey , accounts : & [ AccountInfo ] , data : & [ u8 ] ) -> ProgramResult {
45- // Minimum data: 20 + 8 + 2 + 32 + 32 + 4 + 4 = 102 bytes
46- if data. len ( ) < 102 {
56+ // Minimum: header (98) + relay_instructions_len (4) = 102 bytes
57+ if data. len ( ) < RequestExecutionHeader :: LEN + 4 {
4758 return Err ( ExecutorQuoterRouterError :: InvalidInstructionData . into ( ) ) ;
4859 }
4960
50- // Parse quoter_address
51- let mut quoter_address = [ 0u8 ; 20 ] ;
52- quoter_address. copy_from_slice ( & data[ 0 ..20 ] ) ;
61+ // Parse fixed header
62+ let header: RequestExecutionHeader =
63+ bytemuck:: try_pod_read_unaligned ( & data[ ..RequestExecutionHeader :: LEN ] )
64+ . map_err ( |_| ExecutorQuoterRouterError :: InvalidInstructionData ) ?;
5365
54- // Parse amount
55- let mut amount_bytes = [ 0u8 ; 8 ] ;
56- amount_bytes. copy_from_slice ( & data[ 20 ..28 ] ) ;
57- let amount = u64:: from_le_bytes ( amount_bytes) ;
66+ let amount = header. amount ;
67+ let quoter_address = header. quoter_address ;
68+ let dst_chain = header. dst_chain ;
69+ let dst_addr = header. dst_addr ;
70+ let refund_addr_bytes = header. refund_addr ;
5871
59- // Parse dst_chain
60- let mut dst_chain_bytes = [ 0u8 ; 2 ] ;
61- dst_chain_bytes . copy_from_slice ( & data [ 28 .. 30 ] ) ;
62- let dst_chain = u16 :: from_le_bytes ( dst_chain_bytes ) ;
72+ // Parse variable-length fields after header
73+ let request_bytes_len = header . request_bytes_len as usize ;
74+ let request_bytes_start = RequestExecutionHeader :: LEN ;
75+ let request_bytes_end = request_bytes_start + request_bytes_len ;
6376
64- // Parse dst_addr
65- let mut dst_addr = [ 0u8 ; 32 ] ;
66- dst_addr. copy_from_slice ( & data[ 30 ..62 ] ) ;
67-
68- // Parse refund_addr_bytes
69- let mut refund_addr_bytes = [ 0u8 ; 32 ] ;
70- refund_addr_bytes. copy_from_slice ( & data[ 62 ..94 ] ) ;
71-
72- // Parse request_bytes
73- let mut request_bytes_len_arr = [ 0u8 ; 4 ] ;
74- request_bytes_len_arr. copy_from_slice ( & data[ 94 ..98 ] ) ;
75- let request_bytes_len = u32:: from_le_bytes ( request_bytes_len_arr) as usize ;
76-
77- if data. len ( ) < 98 + request_bytes_len + 4 {
77+ if data. len ( ) < request_bytes_end + 4 {
7878 return Err ( ExecutorQuoterRouterError :: InvalidInstructionData . into ( ) ) ;
7979 }
8080
81- let request_bytes = & data[ 98 ..98 + request_bytes_len] ;
81+ let request_bytes = & data[ request_bytes_start..request_bytes_end] ;
82+
83+ let relay_len_start = request_bytes_end;
84+ let relay_instructions_len = u32:: from_le_bytes (
85+ data[ relay_len_start..relay_len_start + 4 ]
86+ . try_into ( )
87+ . map_err ( |_| ExecutorQuoterRouterError :: InvalidInstructionData ) ?,
88+ ) as usize ;
8289
83- // Parse relay_instructions
84- let relay_start = 98 + request_bytes_len;
85- let mut relay_len_arr = [ 0u8 ; 4 ] ;
86- relay_len_arr. copy_from_slice ( & data[ relay_start..relay_start + 4 ] ) ;
87- let relay_instructions_len = u32:: from_le_bytes ( relay_len_arr) as usize ;
90+ let relay_instructions_start = relay_len_start + 4 ;
91+ let relay_instructions_end = relay_instructions_start + relay_instructions_len;
8892
89- if data. len ( ) < relay_start + 4 + relay_instructions_len {
93+ if data. len ( ) < relay_instructions_end {
9094 return Err ( ExecutorQuoterRouterError :: InvalidInstructionData . into ( ) ) ;
9195 }
9296
93- let relay_instructions = & data[ relay_start + 4 ..relay_start + 4 + relay_instructions_len ] ;
97+ let relay_instructions = & data[ relay_instructions_start..relay_instructions_end ] ;
9498
9599 // Parse accounts
96100 let [ payer, config_account, quoter_registration_account, quoter_program, _executor_program, payee, refund_account, system_program, quoter_config, quoter_chain_info, quoter_quote_body, event_cpi] =
0 commit comments