1
- use alloy_primitives:: Address ;
2
- use ethers:: abi:: FixedBytes ;
3
- use structs:: DataSource ;
1
+ use alloc:: vec:: Vec ;
2
+ use stylus_sdk:: alloy_primitives:: { Address , FixedBytes , U16 } ;
3
+ use crate :: structs:: DataSource ;
4
+ use crate :: error:: PythReceiverError ;
4
5
5
- #[ derive( Drop , Copy , Debug , PartialEq , Serde , Hash ) ]
6
+ const MAGIC : u32 = 0x5054474d ;
7
+ const MODULE_TARGET : u8 = 1 ;
8
+
9
+ #[ derive( Clone , Debug , PartialEq ) ]
6
10
pub enum GovernanceAction {
7
11
UpgradeContract ,
8
12
AuthorizeGovernanceDataSourceTransfer ,
@@ -14,88 +18,265 @@ pub enum GovernanceAction {
14
18
SetFeeInToken ,
15
19
}
16
20
17
- impl U8TryIntoGovernanceAction of TryInto < u8 , GovernanceAction > {
18
- fn try_into ( self : u8 ) -> Option < GovernanceAction > {
19
- let v = match self {
20
- 0 => GovernanceAction :: UpgradeContract ,
21
- 1 => GovernanceAction :: AuthorizeGovernanceDataSourceTransfer ,
22
- 2 => GovernanceAction :: SetDataSources ,
23
- 3 => GovernanceAction :: SetFee ,
24
- 4 => GovernanceAction :: SetValidPeriod ,
25
- 5 => GovernanceAction :: RequestGovernanceDataSourceTransfer ,
26
- 6 => GovernanceAction :: SetWormholeAddress ,
27
- 7 => GovernanceAction :: SetFeeInToken ,
28
- _ => { return Option :: None ; } ,
29
- } ;
30
- Option :: Some ( v)
21
+ impl TryFrom < u8 > for GovernanceAction {
22
+ type Error = PythReceiverError ;
23
+
24
+ fn try_from ( value : u8 ) -> Result < Self , Self :: Error > {
25
+ match value {
26
+ 0 => Ok ( GovernanceAction :: UpgradeContract ) ,
27
+ 1 => Ok ( GovernanceAction :: AuthorizeGovernanceDataSourceTransfer ) ,
28
+ 2 => Ok ( GovernanceAction :: SetDataSources ) ,
29
+ 3 => Ok ( GovernanceAction :: SetFee ) ,
30
+ 4 => Ok ( GovernanceAction :: SetValidPeriod ) ,
31
+ 5 => Ok ( GovernanceAction :: RequestGovernanceDataSourceTransfer ) ,
32
+ 6 => Ok ( GovernanceAction :: SetWormholeAddress ) ,
33
+ 7 => Ok ( GovernanceAction :: SetFeeInToken ) ,
34
+ _ => Err ( PythReceiverError :: InvalidGovernanceAction ) ,
35
+ }
31
36
}
32
37
}
33
38
34
- #[ derive( Drop , Clone , Debug , PartialEq , Serde ) ]
39
+ #[ derive( Clone , Debug , PartialEq ) ]
35
40
pub struct GovernanceInstruction {
36
41
pub target_chain_id : u16 ,
37
42
pub payload : GovernancePayload ,
38
43
}
39
44
40
- #[ derive( Drop , Clone , Debug , PartialEq , Serde ) ]
45
+ #[ derive( Clone , Debug , PartialEq ) ]
41
46
pub enum GovernancePayload {
42
- UpgradeContract ,
43
- AuthorizeGovernanceDataSourceTransfer ,
44
- SetDataSources ,
45
- SetFee ,
46
- RequestGovernanceDataSourceTransfer ,
47
- SetWormholeAddress ,
48
- SetFeeInToken ,
47
+ UpgradeContract ( UpgradeContract ) ,
48
+ AuthorizeGovernanceDataSourceTransfer ( AuthorizeGovernanceDataSourceTransfer ) ,
49
+ SetDataSources ( SetDataSources ) ,
50
+ SetFee ( SetFee ) ,
51
+ RequestGovernanceDataSourceTransfer ( RequestGovernanceDataSourceTransfer ) ,
52
+ SetWormholeAddress ( SetWormholeAddress ) ,
53
+ SetFeeInToken ( SetFeeInToken ) ,
49
54
}
50
55
51
- #[ derive( Drop , Clone , Debug , PartialEq , Serde ) ]
56
+ #[ derive( Clone , Debug , PartialEq ) ]
52
57
pub struct SetFee {
53
58
pub value : u64 ,
54
59
pub expo : u64 ,
55
60
}
56
61
57
- #[ derive( Drop , Clone , Debug , PartialEq , Serde ) ]
62
+ #[ derive( Clone , Debug , PartialEq ) ]
58
63
pub struct SetFeeInToken {
59
64
pub value : u64 ,
60
65
pub expo : u64 ,
61
- pub token : ContractAddress ,
66
+ pub token : Address ,
62
67
}
63
68
64
- #[ derive( Drop , Clone , Debug , PartialEq , Serde ) ]
69
+ #[ derive( Clone , Debug , PartialEq ) ]
65
70
pub struct SetDataSources {
66
- pub sources : Array < DataSource > ,
71
+ pub sources : Vec < DataSource > ,
67
72
}
68
73
69
- #[ derive( Drop , Clone , Debug , PartialEq , Serde ) ]
74
+ #[ derive( Clone , Debug , PartialEq ) ]
70
75
pub struct SetWormholeAddress {
71
76
pub address : Address ,
72
77
}
73
78
74
- #[ derive( Drop , Clone , Debug , PartialEq , Serde ) ]
79
+ #[ derive( Clone , Debug , PartialEq ) ]
75
80
pub struct RequestGovernanceDataSourceTransfer {
76
- // Index is used to prevent replay attacks
77
- // So a claimVaa cannot be used twice.
78
81
pub governance_data_source_index : u32 ,
79
82
}
80
83
81
- #[ derive( Drop , Clone , Debug , PartialEq , Serde ) ]
84
+ #[ derive( Clone , Debug , PartialEq ) ]
82
85
pub struct AuthorizeGovernanceDataSourceTransfer {
83
- // Transfer governance control over this contract to another data source.
84
- // The claim_vaa field is a VAA created by the new data source; using a VAA prevents mistakes
85
- // in the handoff by ensuring that the new data source can send VAAs (i.e., is not an invalid
86
- // address).
87
- pub claim_vaa : FixedBytes < 32 > ,
86
+ pub claim_vaa : Vec < u8 > ,
88
87
}
89
88
90
- // #[derive(Drop, Clone, Debug, PartialEq, Serde)]
91
- // pub struct UpgradeContract {
92
- // // Class hash of the new contract class. The contract class must already be deployed on the
93
- // // network (e.g. with `starkli declare`). Class hash is a Poseidon hash of all properties
94
- // // of the contract code, including entry points, ABI, and bytecode,
95
- // // so specifying a hash securely identifies the new implementation.
96
- // pub new_implementation: ClassHash,
97
- // }
89
+ #[ derive( Clone , Debug , PartialEq ) ]
90
+ pub struct UpgradeContract {
91
+ pub new_implementation : FixedBytes < 32 > ,
92
+ }
98
93
99
- pub fn parse_instruction ( payload : Vec < u8 > ) -> GovernanceInstruction {
94
+ pub fn parse_instruction ( payload : Vec < u8 > ) -> Result < GovernanceInstruction , PythReceiverError > {
95
+ if payload. len ( ) < 8 {
96
+ return Err ( PythReceiverError :: InvalidGovernanceMessage ) ;
97
+ }
100
98
101
- }
99
+ let mut cursor = 0 ;
100
+
101
+ let magic = u32:: from_be_bytes ( [
102
+ payload[ cursor] ,
103
+ payload[ cursor + 1 ] ,
104
+ payload[ cursor + 2 ] ,
105
+ payload[ cursor + 3 ] ,
106
+ ] ) ;
107
+ cursor += 4 ;
108
+
109
+ if magic != MAGIC {
110
+ return Err ( PythReceiverError :: InvalidGovernanceMessage ) ;
111
+ }
112
+
113
+ let module = payload[ cursor] ;
114
+ cursor += 1 ;
115
+
116
+ if module != MODULE_TARGET {
117
+ return Err ( PythReceiverError :: InvalidGovernanceTarget ) ;
118
+ }
119
+
120
+ let action = GovernanceAction :: try_from ( payload[ cursor] ) ?;
121
+ cursor += 1 ;
122
+
123
+ let target_chain_id = u16:: from_be_bytes ( [ payload[ cursor] , payload[ cursor + 1 ] ] ) ;
124
+ cursor += 2 ;
125
+
126
+ let governance_payload = match action {
127
+ GovernanceAction :: UpgradeContract => {
128
+ if payload. len ( ) < cursor + 32 {
129
+ return Err ( PythReceiverError :: InvalidGovernanceMessage ) ;
130
+ }
131
+ let mut new_implementation = [ 0u8 ; 32 ] ;
132
+ new_implementation. copy_from_slice ( & payload[ cursor..cursor + 32 ] ) ;
133
+ cursor += 32 ;
134
+ GovernancePayload :: UpgradeContract ( UpgradeContract {
135
+ new_implementation : FixedBytes :: from ( new_implementation) ,
136
+ } )
137
+ }
138
+ GovernanceAction :: AuthorizeGovernanceDataSourceTransfer => {
139
+ let claim_vaa = payload[ cursor..] . to_vec ( ) ;
140
+ GovernancePayload :: AuthorizeGovernanceDataSourceTransfer (
141
+ AuthorizeGovernanceDataSourceTransfer { claim_vaa } ,
142
+ )
143
+ }
144
+ GovernanceAction :: RequestGovernanceDataSourceTransfer => {
145
+ if payload. len ( ) < cursor + 4 {
146
+ return Err ( PythReceiverError :: InvalidGovernanceMessage ) ;
147
+ }
148
+ let governance_data_source_index = u32:: from_be_bytes ( [
149
+ payload[ cursor] ,
150
+ payload[ cursor + 1 ] ,
151
+ payload[ cursor + 2 ] ,
152
+ payload[ cursor + 3 ] ,
153
+ ] ) ;
154
+ cursor += 4 ;
155
+ GovernancePayload :: RequestGovernanceDataSourceTransfer (
156
+ RequestGovernanceDataSourceTransfer {
157
+ governance_data_source_index,
158
+ } ,
159
+ )
160
+ }
161
+ GovernanceAction :: SetDataSources => {
162
+ if payload. len ( ) < cursor + 1 {
163
+ return Err ( PythReceiverError :: InvalidGovernanceMessage ) ;
164
+ }
165
+ let num_sources = payload[ cursor] ;
166
+ cursor += 1 ;
167
+
168
+ let mut sources = Vec :: new ( ) ;
169
+ for _ in 0 ..num_sources {
170
+ if payload. len ( ) < cursor + 34 {
171
+ return Err ( PythReceiverError :: InvalidGovernanceMessage ) ;
172
+ }
173
+ let emitter_chain_id = u16:: from_be_bytes ( [ payload[ cursor] , payload[ cursor + 1 ] ] ) ;
174
+ cursor += 2 ;
175
+
176
+ let mut emitter_address = [ 0u8 ; 32 ] ;
177
+ emitter_address. copy_from_slice ( & payload[ cursor..cursor + 32 ] ) ;
178
+ cursor += 32 ;
179
+
180
+ sources. push ( DataSource {
181
+ chain_id : U16 :: from ( emitter_chain_id) ,
182
+ emitter_address : FixedBytes :: from ( emitter_address) ,
183
+ } ) ;
184
+ }
185
+ GovernancePayload :: SetDataSources ( SetDataSources { sources } )
186
+ }
187
+ GovernanceAction :: SetFee => {
188
+ if payload. len ( ) < cursor + 16 {
189
+ return Err ( PythReceiverError :: InvalidGovernanceMessage ) ;
190
+ }
191
+ let value = u64:: from_be_bytes ( [
192
+ payload[ cursor] ,
193
+ payload[ cursor + 1 ] ,
194
+ payload[ cursor + 2 ] ,
195
+ payload[ cursor + 3 ] ,
196
+ payload[ cursor + 4 ] ,
197
+ payload[ cursor + 5 ] ,
198
+ payload[ cursor + 6 ] ,
199
+ payload[ cursor + 7 ] ,
200
+ ] ) ;
201
+ cursor += 8 ;
202
+ let expo = u64:: from_be_bytes ( [
203
+ payload[ cursor] ,
204
+ payload[ cursor + 1 ] ,
205
+ payload[ cursor + 2 ] ,
206
+ payload[ cursor + 3 ] ,
207
+ payload[ cursor + 4 ] ,
208
+ payload[ cursor + 5 ] ,
209
+ payload[ cursor + 6 ] ,
210
+ payload[ cursor + 7 ] ,
211
+ ] ) ;
212
+ cursor += 8 ;
213
+ GovernancePayload :: SetFee ( SetFee { value, expo } )
214
+ }
215
+ GovernanceAction :: SetFeeInToken => {
216
+ if payload. len ( ) < cursor + 17 {
217
+ return Err ( PythReceiverError :: InvalidGovernanceMessage ) ;
218
+ }
219
+ let value = u64:: from_be_bytes ( [
220
+ payload[ cursor] ,
221
+ payload[ cursor + 1 ] ,
222
+ payload[ cursor + 2 ] ,
223
+ payload[ cursor + 3 ] ,
224
+ payload[ cursor + 4 ] ,
225
+ payload[ cursor + 5 ] ,
226
+ payload[ cursor + 6 ] ,
227
+ payload[ cursor + 7 ] ,
228
+ ] ) ;
229
+ cursor += 8 ;
230
+ let expo = u64:: from_be_bytes ( [
231
+ payload[ cursor] ,
232
+ payload[ cursor + 1 ] ,
233
+ payload[ cursor + 2 ] ,
234
+ payload[ cursor + 3 ] ,
235
+ payload[ cursor + 4 ] ,
236
+ payload[ cursor + 5 ] ,
237
+ payload[ cursor + 6 ] ,
238
+ payload[ cursor + 7 ] ,
239
+ ] ) ;
240
+ cursor += 8 ;
241
+ let token_len = payload[ cursor] ;
242
+ cursor += 1 ;
243
+ if token_len != 20 {
244
+ return Err ( PythReceiverError :: InvalidGovernanceMessage ) ;
245
+ }
246
+ if payload. len ( ) < cursor + 20 {
247
+ return Err ( PythReceiverError :: InvalidGovernanceMessage ) ;
248
+ }
249
+ let mut token_bytes = [ 0u8 ; 20 ] ;
250
+ token_bytes. copy_from_slice ( & payload[ cursor..cursor + 20 ] ) ;
251
+ cursor += 20 ;
252
+ GovernancePayload :: SetFeeInToken ( SetFeeInToken {
253
+ value,
254
+ expo,
255
+ token : Address :: from ( token_bytes) ,
256
+ } )
257
+ }
258
+ GovernanceAction :: SetValidPeriod => {
259
+ return Err ( PythReceiverError :: InvalidGovernanceMessage ) ;
260
+ }
261
+ GovernanceAction :: SetWormholeAddress => {
262
+ if payload. len ( ) < cursor + 20 {
263
+ return Err ( PythReceiverError :: InvalidGovernanceMessage ) ;
264
+ }
265
+ let mut address_bytes = [ 0u8 ; 20 ] ;
266
+ address_bytes. copy_from_slice ( & payload[ cursor..cursor + 20 ] ) ;
267
+ cursor += 20 ;
268
+ GovernancePayload :: SetWormholeAddress ( SetWormholeAddress {
269
+ address : Address :: from ( address_bytes) ,
270
+ } )
271
+ }
272
+ } ;
273
+
274
+ if cursor != payload. len ( ) {
275
+ return Err ( PythReceiverError :: InvalidGovernanceMessage ) ;
276
+ }
277
+
278
+ Ok ( GovernanceInstruction {
279
+ target_chain_id,
280
+ payload : governance_payload,
281
+ } )
282
+ }
0 commit comments