@@ -3,6 +3,7 @@ mod signature;
3
3
use {
4
4
crate :: signature:: VerifiedMessage ,
5
5
anchor_lang:: { prelude:: * , solana_program:: pubkey:: PUBKEY_BYTES , system_program} ,
6
+ std:: io:: Cursor ,
6
7
std:: mem:: size_of,
7
8
} ;
8
9
@@ -14,18 +15,13 @@ pub use {
14
15
declare_id ! ( "pytd2yyk641x7ak7mkaasSJVXh6YYZnC7wTmtgAyxPt" ) ;
15
16
16
17
pub const STORAGE_ID : Pubkey = pubkey ! ( "3rdJbqfnagQ4yx9HXJViD4zc4xpiSqmFsKpPuSCQVyQL" ) ;
17
- pub const TREASURY_ID : Pubkey = pubkey ! ( "EN4aB3soE5iuCG2fGj2r5fksh4kLRVPV8g7N86vXm8WM" ) ;
18
18
19
19
#[ test]
20
20
fn test_ids ( ) {
21
21
assert_eq ! (
22
22
Pubkey :: find_program_address( & [ STORAGE_SEED ] , & ID ) . 0 ,
23
23
STORAGE_ID
24
24
) ;
25
- assert_eq ! (
26
- Pubkey :: find_program_address( & [ TREASURY_SEED ] , & ID ) . 0 ,
27
- TREASURY_ID
28
- ) ;
29
25
}
30
26
31
27
pub const MAX_NUM_TRUSTED_SIGNERS : usize = 2 ;
@@ -41,17 +37,35 @@ impl TrustedSignerInfo {
41
37
}
42
38
43
39
#[ account]
44
- pub struct Storage {
40
+ pub struct StorageV1 {
45
41
pub top_authority : Pubkey ,
46
42
pub num_trusted_signers : u8 ,
47
- pub single_update_fee_in_lamports : u64 ,
48
43
pub trusted_signers : [ TrustedSignerInfo ; MAX_NUM_TRUSTED_SIGNERS ] ,
49
44
}
50
45
51
- impl Storage {
46
+ impl StorageV1 {
52
47
const SERIALIZED_LEN : usize = PUBKEY_BYTES
53
48
+ size_of :: < u8 > ( )
49
+ + TrustedSignerInfo :: SERIALIZED_LEN * MAX_NUM_TRUSTED_SIGNERS ;
50
+
51
+ pub fn initialized_trusted_signers ( & self ) -> & [ TrustedSignerInfo ] {
52
+ & self . trusted_signers [ 0 ..usize:: from ( self . num_trusted_signers ) ]
53
+ }
54
+ }
55
+ #[ account]
56
+ pub struct StorageV2 {
57
+ pub top_authority : Pubkey ,
58
+ pub treasury : Pubkey ,
59
+ pub single_update_fee_in_lamports : u64 ,
60
+ pub num_trusted_signers : u8 ,
61
+ pub trusted_signers : [ TrustedSignerInfo ; MAX_NUM_TRUSTED_SIGNERS ] ,
62
+ }
63
+
64
+ impl StorageV2 {
65
+ const SERIALIZED_LEN : usize = PUBKEY_BYTES
66
+ + PUBKEY_BYTES
54
67
+ size_of :: < u64 > ( )
68
+ + size_of :: < u8 > ( )
55
69
+ TrustedSignerInfo :: SERIALIZED_LEN * MAX_NUM_TRUSTED_SIGNERS ;
56
70
57
71
pub fn initialized_trusted_signers ( & self ) -> & [ TrustedSignerInfo ] {
@@ -60,18 +74,53 @@ impl Storage {
60
74
}
61
75
62
76
pub const STORAGE_SEED : & [ u8 ] = b"storage" ;
63
- pub const TREASURY_SEED : & [ u8 ] = b"treasury" ;
64
77
65
78
#[ program]
66
79
pub mod pyth_lazer_solana_contract {
67
80
use super :: * ;
68
81
69
- pub fn initialize ( ctx : Context < Initialize > , top_authority : Pubkey ) -> Result < ( ) > {
82
+ pub fn initialize_v1 ( ctx : Context < InitializeV1 > , top_authority : Pubkey ) -> Result < ( ) > {
70
83
ctx. accounts . storage . top_authority = top_authority;
84
+ Ok ( ( ) )
85
+ }
86
+
87
+ pub fn initialize_v2 (
88
+ ctx : Context < InitializeV2 > ,
89
+ top_authority : Pubkey ,
90
+ treasury : Pubkey ,
91
+ ) -> Result < ( ) > {
92
+ ctx. accounts . storage . top_authority = top_authority;
93
+ ctx. accounts . storage . treasury = treasury;
71
94
ctx. accounts . storage . single_update_fee_in_lamports = 1 ;
72
95
Ok ( ( ) )
73
96
}
74
97
98
+ pub fn migrate_to_storage_v2 ( ctx : Context < MigrateToStorageV2 > , treasury : Pubkey ) -> Result < ( ) > {
99
+ let old_storage = StorageV1 :: try_deserialize ( & mut & * * ctx. accounts . storage . data . borrow ( ) ) ?;
100
+ if old_storage. top_authority != ctx. accounts . top_authority . key ( ) {
101
+ return Err ( ProgramError :: MissingRequiredSignature . into ( ) ) ;
102
+ }
103
+
104
+ let space = 8 + StorageV2 :: SERIALIZED_LEN ;
105
+ ctx. accounts . storage . realloc ( space, false ) ?;
106
+ let min_lamports = Rent :: get ( ) ?. minimum_balance ( space) ;
107
+ if ctx. accounts . storage . lamports ( ) < min_lamports {
108
+ return Err ( ProgramError :: AccountNotRentExempt . into ( ) ) ;
109
+ }
110
+
111
+ let new_storage = StorageV2 {
112
+ top_authority : old_storage. top_authority ,
113
+ treasury,
114
+ single_update_fee_in_lamports : 1 ,
115
+ num_trusted_signers : old_storage. num_trusted_signers ,
116
+ trusted_signers : old_storage. trusted_signers ,
117
+ } ;
118
+ new_storage. try_serialize ( & mut Cursor :: new (
119
+ & mut * * ctx. accounts . storage . data . borrow_mut ( ) ,
120
+ ) ) ?;
121
+ Ok ( ( ) )
122
+ }
123
+
75
124
pub fn update ( ctx : Context < Update > , trusted_signer : Pubkey , expires_at : i64 ) -> Result < ( ) > {
76
125
let num_trusted_signers: usize = ctx. accounts . storage . num_trusted_signers . into ( ) ;
77
126
if num_trusted_signers > ctx. accounts . storage . trusted_signers . len ( ) {
@@ -157,29 +206,45 @@ pub mod pyth_lazer_solana_contract {
157
206
}
158
207
159
208
#[ derive( Accounts ) ]
160
- pub struct Initialize < ' info > {
209
+ pub struct InitializeV1 < ' info > {
161
210
#[ account( mut ) ]
162
211
pub payer : Signer < ' info > ,
163
212
#[ account(
164
213
init,
165
214
payer = payer,
166
- space = 8 + Storage :: SERIALIZED_LEN ,
215
+ space = 8 + StorageV1 :: SERIALIZED_LEN ,
167
216
seeds = [ STORAGE_SEED ] ,
168
217
bump,
169
218
) ]
170
- pub storage : Account < ' info , Storage > ,
219
+ pub storage : Account < ' info , StorageV1 > ,
220
+ pub system_program : Program < ' info , System > ,
221
+ }
222
+
223
+ #[ derive( Accounts ) ]
224
+ pub struct MigrateToStorageV2 < ' info > {
225
+ pub top_authority : Signer < ' info > ,
226
+ #[ account(
227
+ mut ,
228
+ seeds = [ STORAGE_SEED ] ,
229
+ bump,
230
+ ) ]
231
+ /// CHECK: top_authority in storage must match top_authority account.
232
+ pub storage : AccountInfo < ' info > ,
233
+ pub system_program : Program < ' info , System > ,
234
+ }
235
+
236
+ #[ derive( Accounts ) ]
237
+ pub struct InitializeV2 < ' info > {
238
+ #[ account( mut ) ]
239
+ pub payer : Signer < ' info > ,
171
240
#[ account(
172
241
init,
173
242
payer = payer,
174
- space = 0 ,
175
- owner = system_program:: ID ,
176
- seeds = [ TREASURY_SEED ] ,
243
+ space = 8 + StorageV2 :: SERIALIZED_LEN ,
244
+ seeds = [ STORAGE_SEED ] ,
177
245
bump,
178
246
) ]
179
- /// CHECK: this is a system program account but using anchor's `SystemAccount`
180
- /// results in invalid output from the Accounts proc macro. No extra checks
181
- /// are necessary because all necessary constraints are specified in the attribute.
182
- pub treasury : AccountInfo < ' info > ,
247
+ pub storage : Account < ' info , StorageV2 > ,
183
248
pub system_program : Program < ' info , System > ,
184
249
}
185
250
@@ -192,7 +257,7 @@ pub struct Update<'info> {
192
257
bump,
193
258
has_one = top_authority,
194
259
) ]
195
- pub storage : Account < ' info , Storage > ,
260
+ pub storage : Account < ' info , StorageV2 > ,
196
261
}
197
262
198
263
#[ derive( Accounts ) ]
@@ -202,17 +267,10 @@ pub struct VerifyMessage<'info> {
202
267
#[ account(
203
268
seeds = [ STORAGE_SEED ] ,
204
269
bump,
270
+ has_one = treasury
205
271
) ]
206
- pub storage : Account < ' info , Storage > ,
207
- #[ account(
208
- mut ,
209
- owner = system_program:: ID ,
210
- seeds = [ TREASURY_SEED ] ,
211
- bump,
212
- ) ]
213
- /// CHECK: this is a system program account but using anchor's `SystemAccount`
214
- /// results in invalid output from the Accounts proc macro. No extra checks
215
- /// are necessary because all necessary constraints are specified in the attribute.
272
+ pub storage : Account < ' info , StorageV2 > ,
273
+ /// CHECK: this account doesn't need additional constraints.
216
274
pub treasury : AccountInfo < ' info > ,
217
275
pub system_program : Program < ' info , System > ,
218
276
/// CHECK: account ID is checked in Solana SDK during calls
0 commit comments