1
- use anchor_lang:: prelude:: * ;
2
- use anchor_lang:: Discriminator ;
3
- use anchor_spl:: token_interface:: spl_token_metadata_interface:: borsh:: BorshDeserialize ;
1
+ use anchor_lang:: { prelude:: * , Discriminator } ;
4
2
use bytemuck:: { Pod , Zeroable } ;
5
- use solana_program:: instruction:: Instruction ;
6
- use solana_program:: keccak;
7
- use solana_program:: program:: invoke_signed_unchecked;
8
- use wormhole_svm_shim:: verify_vaa:: VerifyHash ;
9
- use wormhole_svm_shim:: verify_vaa:: VerifyHashAccounts ;
10
- use wormhole_svm_shim:: verify_vaa:: VerifyHashData ;
3
+ use solana_program:: { instruction:: Instruction , keccak, program:: invoke_signed_unchecked} ;
4
+ use wormhole_svm_shim:: verify_vaa;
11
5
12
- use super :: helpers:: create_account_reliably;
13
-
14
- use super :: helpers:: require_min_account_infos_len;
15
- use super :: FallbackMatchingEngineInstruction ;
16
- use crate :: error:: MatchingEngineError ;
17
- use crate :: state:: FastMarketOrder as FastMarketOrderState ;
18
- use crate :: ID ;
6
+ use crate :: { error:: MatchingEngineError , state:: FastMarketOrder , ID } ;
19
7
20
8
pub struct InitializeFastMarketOrderAccounts < ' ix > {
21
- /// The signer of the transaction
9
+ /// Lamports from this signer will be used to create the new fast market
10
+ /// order account. This account will be the only authority allowed to
11
+ /// close this account.
12
+ /// TODO: Rename to "payer".
22
13
pub signer : & ' ix Pubkey ,
23
- /// The fast market order account pubkey (that is created by the instruction)
14
+ /// The fast market order account pubkey (that is created by the
15
+ /// instruction).
16
+ /// TODO: Rename to "new_fast_market_order".
24
17
pub fast_market_order_account : & ' ix Pubkey ,
25
- /// The guardian set account pubkey
18
+ /// Wormhole guardian set account used to check recovered pubkeys using
19
+ /// [Self::guardian_set_signatures].
20
+ /// TODO: Rename to "wormhole_guardian_set"
26
21
pub guardian_set : & ' ix Pubkey ,
27
- /// The guardian set signatures account pubkey (created by the post verify vaa shim program)
22
+ /// The guardian set signatures of fast market order VAA.
23
+ /// TODO: Rename to "shim_guardian_signatures".
28
24
pub guardian_set_signatures : & ' ix Pubkey ,
29
- /// The verify vaa shim program pubkey
30
25
pub verify_vaa_shim_program : & ' ix Pubkey ,
31
- /// The system program account pubkey
26
+ /// TODO: Remove.
32
27
pub system_program : & ' ix Pubkey ,
33
28
}
34
29
35
- impl < ' ix > InitializeFastMarketOrderAccounts < ' ix > {
36
- pub fn to_account_metas ( & self ) -> Vec < AccountMeta > {
37
- vec ! [
38
- AccountMeta :: new( * self . signer, true ) , // This will be the refund recipient
39
- AccountMeta :: new( * self . fast_market_order_account, false ) ,
40
- AccountMeta :: new_readonly( * self . guardian_set, false ) ,
41
- AccountMeta :: new_readonly( * self . guardian_set_signatures, false ) ,
42
- AccountMeta :: new_readonly( * self . verify_vaa_shim_program, false ) ,
43
- AccountMeta :: new_readonly( * self . system_program, false ) ,
44
- ]
45
- }
46
- }
47
-
48
30
#[ derive( Debug , Copy , Clone , Pod , Zeroable ) ]
49
31
#[ repr( C ) ]
50
32
pub struct InitializeFastMarketOrderData {
51
33
/// The fast market order as the bytemuck struct
52
- pub fast_market_order : FastMarketOrderState ,
34
+ pub fast_market_order : FastMarketOrder ,
53
35
/// The guardian set bump
54
36
pub guardian_set_bump : u8 ,
55
37
/// Padding to ensure bytemuck deserialization works
56
38
_padding : [ u8 ; 7 ] ,
57
39
}
40
+
58
41
impl InitializeFastMarketOrderData {
59
42
// Adds the padding to the InitializeFastMarketOrderData
60
- pub fn new ( fast_market_order : FastMarketOrderState , guardian_set_bump : u8 ) -> Self {
43
+ pub fn new ( fast_market_order : FastMarketOrder , guardian_set_bump : u8 ) -> Self {
61
44
Self {
62
45
fast_market_order,
63
46
guardian_set_bump,
64
- _padding : [ 0_u8 ; 7 ] ,
47
+ _padding : Default :: default ( ) ,
65
48
}
66
49
}
67
50
68
- /// Deserializes the InitializeFastMarketOrderData from a byte slice
51
+ /// Deserializes the InitializeFastMarketOrderData from a byte slice.
69
52
///
70
53
/// # Arguments
71
54
///
72
- /// * `data` - A byte slice containing the InitializeFastMarketOrderData
55
+ /// * `data` - A byte slice containing the InitializeFastMarketOrderData.
73
56
///
74
57
/// # Returns
75
58
///
76
- /// Option<&Self> - The deserialized InitializeFastMarketOrderData or None if the byte slice is not the correct length
59
+ /// Option<&Self> - The deserialized `InitializeFastMarketOrderData`` or
60
+ /// `None` if the byte slice is not the correct length.
77
61
pub fn from_bytes ( data : & [ u8 ] ) -> Option < & Self > {
78
- bytemuck:: try_from_bytes :: < Self > ( data) . ok ( )
62
+ bytemuck:: try_from_bytes ( data) . ok ( )
79
63
}
80
64
}
81
65
66
+ /// Initializes the fast market order account.
67
+ ///
68
+ /// The verify shim program first checks that the digest of the fast market
69
+ /// order is correct, and that the guardian signature is correct and
70
+ /// recoverable. If this is the case, the fast market order account is created.
71
+ /// The fast market order account is owned by the matching engine program. It
72
+ /// can be closed by the close fast market order instruction, which returns the
73
+ /// lamports to the close account refund recipient.
82
74
pub struct InitializeFastMarketOrder < ' ix > {
83
75
pub program_id : & ' ix Pubkey ,
84
76
pub accounts : InitializeFastMarketOrderAccounts < ' ix > ,
@@ -87,113 +79,120 @@ pub struct InitializeFastMarketOrder<'ix> {
87
79
88
80
impl InitializeFastMarketOrder < ' _ > {
89
81
pub fn instruction ( & self ) -> Instruction {
82
+ let InitializeFastMarketOrderAccounts {
83
+ signer : payer,
84
+ fast_market_order_account : new_fast_market_order,
85
+ guardian_set : wormhole_guardian_set,
86
+ guardian_set_signatures : shim_guardian_signatures,
87
+ verify_vaa_shim_program,
88
+ system_program : _,
89
+ } = self . accounts ;
90
+
90
91
Instruction {
91
92
program_id : * self . program_id ,
92
- accounts : self . accounts . to_account_metas ( ) ,
93
- data : FallbackMatchingEngineInstruction :: InitializeFastMarketOrder ( & self . data ) . to_vec ( ) ,
93
+ accounts : vec ! [
94
+ AccountMeta :: new( * payer, true ) ,
95
+ AccountMeta :: new( * new_fast_market_order, false ) ,
96
+ AccountMeta :: new_readonly( * wormhole_guardian_set, false ) ,
97
+ AccountMeta :: new_readonly( * shim_guardian_signatures, false ) ,
98
+ AccountMeta :: new_readonly( * verify_vaa_shim_program, false ) ,
99
+ AccountMeta :: new_readonly( solana_program:: system_program:: ID , false ) ,
100
+ ] ,
101
+ data : super :: FallbackMatchingEngineInstruction :: InitializeFastMarketOrder ( & self . data )
102
+ . to_vec ( ) ,
94
103
}
95
104
}
96
105
}
97
106
98
- /// Initializes the fast market order account
99
- ///
100
- /// The verify shim program first checks that the digest of the fast market order is correct, and that the guardian signature is correct and recoverable.
101
- /// If this is the case, the fast market order account is created. The fast market order account is owned by the matching engine program. It can be closed
102
- /// by the close fast market order instruction, which returns the lamports to the close account refund recipient.
103
- ///
104
- /// # Arguments
105
- ///
106
- /// * `accounts` - The accounts of the fast market order and the guardian set
107
- ///
108
- /// # Returns
109
- ///
110
- /// Result<()>
111
- pub fn initialize_fast_market_order (
107
+ pub ( super ) fn process (
112
108
accounts : & [ AccountInfo ] ,
113
109
data : & InitializeFastMarketOrderData ,
114
110
) -> Result < ( ) > {
115
- require_min_account_infos_len ( accounts, 6 ) ?;
116
-
117
- let signer = & accounts[ 0 ] ;
118
- let fast_market_order_account = & accounts[ 1 ] ;
119
- let guardian_set = & accounts[ 2 ] ;
120
- let guardian_set_signatures = & accounts[ 3 ] ;
121
-
122
- let InitializeFastMarketOrderData {
123
- fast_market_order,
124
- guardian_set_bump,
125
- _padding : _,
126
- } = data;
127
- // Start of cpi call to verify the shim.
128
- // ------------------------------------------------------------------------------------------------
111
+ super :: helpers:: require_min_account_infos_len ( accounts, 6 ) ?;
112
+
113
+ let fast_market_order = & data. fast_market_order ;
114
+
115
+ // Generate the VAA digest, which will be used to verify the guardian
116
+ // signatures.
129
117
let fast_market_order_vaa_digest = fast_market_order. digest ( ) ;
130
- let fast_market_order_vaa_digest_hash =
131
- keccak:: Hash :: try_from_slice ( & fast_market_order_vaa_digest) . unwrap ( ) ;
132
- let verify_hash_data =
133
- VerifyHashData :: new ( * guardian_set_bump, fast_market_order_vaa_digest_hash) ;
134
- let verify_hash_shim_ix = VerifyHash {
135
- program_id : & wormhole_svm_definitions:: solana:: VERIFY_VAA_SHIM_PROGRAM_ID ,
136
- accounts : VerifyHashAccounts {
137
- guardian_set : & guardian_set. key ( ) ,
138
- guardian_signatures : & guardian_set_signatures. key ( ) ,
139
- } ,
140
- data : verify_hash_data,
141
- }
142
- . instruction ( ) ;
143
- // Make the cpi call to verify the shim.
144
- invoke_signed_unchecked ( & verify_hash_shim_ix, accounts, & [ ] ) ?;
145
- // ------------------------------------------------------------------------------------------------
146
- // End of cpi call to verify the shim.
147
-
148
- // Start of fast market order account creation
149
- // ------------------------------------------------------------------------------------------------
150
- let fast_market_order_key = fast_market_order_account. key ( ) ;
151
- let space = 8_usize . saturating_add ( std:: mem:: size_of :: < FastMarketOrderState > ( ) ) ;
152
- let ( fast_market_order_pda, fast_market_order_bump) = Pubkey :: find_program_address (
118
+
119
+ // This payer will send lamports to the new fast market order account and
120
+ // will be the "owner" of this account. Only this account can close the
121
+ // fast market order account.
122
+ let payer_info = & accounts[ 0 ] ;
123
+
124
+ // Verify that the fast market order account's key is derived correctly.
125
+ let new_fast_market_order_info = & accounts[ 1 ] ;
126
+ let fast_market_order_key = new_fast_market_order_info. key ;
127
+ let ( expected_fast_market_order_key, fast_market_order_bump) = Pubkey :: find_program_address (
153
128
& [
154
- FastMarketOrderState :: SEED_PREFIX ,
155
- fast_market_order_vaa_digest. as_ref ( ) ,
129
+ FastMarketOrder :: SEED_PREFIX ,
130
+ & fast_market_order_vaa_digest,
156
131
fast_market_order. close_account_refund_recipient . as_ref ( ) ,
157
132
] ,
158
133
& ID ,
159
134
) ;
160
135
161
- if fast_market_order_pda != fast_market_order_key {
162
- msg ! ( "Fast market order pda is invalid" ) ;
163
- return Err ( MatchingEngineError :: InvalidPda . into ( ) )
164
- . map_err ( |e : Error | e. with_pubkeys ( ( fast_market_order_key, fast_market_order_pda) ) ) ;
136
+ if fast_market_order_key != & expected_fast_market_order_key {
137
+ return Err ( MatchingEngineError :: InvalidPda . into ( ) ) . map_err ( |e : Error | {
138
+ e. with_account_name ( "fast_market_order" )
139
+ . with_pubkeys ( ( * fast_market_order_key, expected_fast_market_order_key) )
140
+ } ) ;
165
141
}
166
- let fast_market_order_seeds = [
167
- FastMarketOrderState :: SEED_PREFIX ,
168
- fast_market_order_vaa_digest. as_ref ( ) ,
169
- fast_market_order. close_account_refund_recipient . as_ref ( ) ,
170
- & [ fast_market_order_bump] ,
171
- ] ;
172
- let fast_market_order_signer_seeds = & [ & fast_market_order_seeds[ ..] ] ;
173
- // Create the account using the system program. The create account reliably ensures that the account creation cannot be raced.
174
- create_account_reliably (
175
- & signer. key ( ) ,
176
- & fast_market_order_key,
177
- fast_market_order_account. lamports ( ) ,
178
- space,
142
+
143
+ // These accounts will be used by the Verify VAA shim program.
144
+ let wormhole_guardian_set_info = & accounts[ 2 ] ;
145
+ let shim_guardian_signatures_info = & accounts[ 3 ] ;
146
+
147
+ // Verify the VAA digest with the Verify VAA shim program.
148
+ invoke_signed_unchecked (
149
+ & verify_vaa:: VerifyHash {
150
+ program_id : & wormhole_svm_definitions:: solana:: VERIFY_VAA_SHIM_PROGRAM_ID ,
151
+ accounts : verify_vaa:: VerifyHashAccounts {
152
+ guardian_set : wormhole_guardian_set_info. key ,
153
+ guardian_signatures : shim_guardian_signatures_info. key ,
154
+ } ,
155
+ data : verify_vaa:: VerifyHashData :: new (
156
+ data. guardian_set_bump ,
157
+ keccak:: Hash ( fast_market_order_vaa_digest) ,
158
+ ) ,
159
+ }
160
+ . instruction ( ) ,
179
161
accounts,
180
- & ID ,
181
- fast_market_order_signer_seeds,
162
+ & [ ] ,
182
163
) ?;
183
- // Borrow the account data mutably
184
- let mut fast_market_order_account_data = fast_market_order_account. try_borrow_mut_data ( ) ?;
185
164
186
- // Write the discriminator to the first 8 bytes
187
- let discriminator = FastMarketOrderState :: discriminator ( ) ;
188
- fast_market_order_account_data[ 0 ..8 ] . copy_from_slice ( & discriminator) ;
165
+ // Create the new fast market order account and serialize the instruction
166
+ // data into it.
167
+
168
+ const DISCRIMINATOR_LEN : usize = FastMarketOrder :: DISCRIMINATOR . len ( ) ;
169
+ const FAST_MARKET_ORDER_DATA_LEN : usize =
170
+ DISCRIMINATOR_LEN + std:: mem:: size_of :: < FastMarketOrder > ( ) ;
171
+
172
+ super :: helpers:: create_account_reliably (
173
+ payer_info. key ,
174
+ fast_market_order_key,
175
+ new_fast_market_order_info. lamports ( ) ,
176
+ FAST_MARKET_ORDER_DATA_LEN ,
177
+ accounts,
178
+ & ID ,
179
+ & [ & [
180
+ FastMarketOrder :: SEED_PREFIX ,
181
+ & fast_market_order_vaa_digest,
182
+ // TODO: Replace with payer_info.key.
183
+ fast_market_order. close_account_refund_recipient . as_ref ( ) ,
184
+ & [ fast_market_order_bump] ,
185
+ ] ] ,
186
+ ) ?;
189
187
190
- let fast_market_order_bytes = bytemuck :: bytes_of ( fast_market_order ) ;
188
+ let mut new_fast_market_order_info_data = new_fast_market_order_info . try_borrow_mut_data ( ) ? ;
191
189
192
- // Write the fast_market_order struct to the account
193
- fast_market_order_account_data[ 8 ..8_usize . saturating_add ( fast_market_order_bytes. len ( ) ) ]
194
- . copy_from_slice ( fast_market_order_bytes) ;
195
- // End of fast market order account creation
196
- // ------------------------------------------------------------------------------------------------
190
+ // Write provided fast market order data to account starting with its
191
+ // discriminator.
192
+ new_fast_market_order_info_data[ 0 ..DISCRIMINATOR_LEN ]
193
+ . copy_from_slice ( & FastMarketOrder :: DISCRIMINATOR ) ;
194
+ new_fast_market_order_info_data[ DISCRIMINATOR_LEN ..FAST_MARKET_ORDER_DATA_LEN ]
195
+ . copy_from_slice ( bytemuck:: bytes_of ( fast_market_order) ) ;
197
196
198
197
Ok ( ( ) )
199
198
}
0 commit comments