@@ -3,6 +3,7 @@ mod signature;
33use {
44 crate :: signature:: VerifiedMessage ,
55 anchor_lang:: { prelude:: * , solana_program:: pubkey:: PUBKEY_BYTES , system_program} ,
6+ std:: io:: Cursor ,
67 std:: mem:: size_of,
78} ;
89
@@ -14,18 +15,13 @@ pub use {
1415declare_id ! ( "pytd2yyk641x7ak7mkaasSJVXh6YYZnC7wTmtgAyxPt" ) ;
1516
1617pub const STORAGE_ID : Pubkey = pubkey ! ( "3rdJbqfnagQ4yx9HXJViD4zc4xpiSqmFsKpPuSCQVyQL" ) ;
17- pub const TREASURY_ID : Pubkey = pubkey ! ( "EN4aB3soE5iuCG2fGj2r5fksh4kLRVPV8g7N86vXm8WM" ) ;
1818
1919#[ test]
2020fn test_ids ( ) {
2121 assert_eq ! (
2222 Pubkey :: find_program_address( & [ STORAGE_SEED ] , & ID ) . 0 ,
2323 STORAGE_ID
2424 ) ;
25- assert_eq ! (
26- Pubkey :: find_program_address( & [ TREASURY_SEED ] , & ID ) . 0 ,
27- TREASURY_ID
28- ) ;
2925}
3026
3127pub const MAX_NUM_TRUSTED_SIGNERS : usize = 2 ;
@@ -41,17 +37,35 @@ impl TrustedSignerInfo {
4137}
4238
4339#[ account]
44- pub struct Storage {
40+ pub struct StorageV1 {
4541 pub top_authority : Pubkey ,
4642 pub num_trusted_signers : u8 ,
47- pub single_update_fee_in_lamports : u64 ,
4843 pub trusted_signers : [ TrustedSignerInfo ; MAX_NUM_TRUSTED_SIGNERS ] ,
4944}
5045
51- impl Storage {
46+ impl StorageV1 {
5247 const SERIALIZED_LEN : usize = PUBKEY_BYTES
5348 + 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
5467 + size_of :: < u64 > ( )
68+ + size_of :: < u8 > ( )
5569 + TrustedSignerInfo :: SERIALIZED_LEN * MAX_NUM_TRUSTED_SIGNERS ;
5670
5771 pub fn initialized_trusted_signers ( & self ) -> & [ TrustedSignerInfo ] {
@@ -60,18 +74,53 @@ impl Storage {
6074}
6175
6276pub const STORAGE_SEED : & [ u8 ] = b"storage" ;
63- pub const TREASURY_SEED : & [ u8 ] = b"treasury" ;
6477
6578#[ program]
6679pub mod pyth_lazer_solana_contract {
6780 use super :: * ;
6881
69- pub fn initialize ( ctx : Context < Initialize > , top_authority : Pubkey ) -> Result < ( ) > {
82+ pub fn initialize_v1 ( ctx : Context < InitializeV1 > , top_authority : Pubkey ) -> Result < ( ) > {
7083 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;
7194 ctx. accounts . storage . single_update_fee_in_lamports = 1 ;
7295 Ok ( ( ) )
7396 }
7497
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+
75124 pub fn update ( ctx : Context < Update > , trusted_signer : Pubkey , expires_at : i64 ) -> Result < ( ) > {
76125 let num_trusted_signers: usize = ctx. accounts . storage . num_trusted_signers . into ( ) ;
77126 if num_trusted_signers > ctx. accounts . storage . trusted_signers . len ( ) {
@@ -157,29 +206,45 @@ pub mod pyth_lazer_solana_contract {
157206}
158207
159208#[ derive( Accounts ) ]
160- pub struct Initialize < ' info > {
209+ pub struct InitializeV1 < ' info > {
161210 #[ account( mut ) ]
162211 pub payer : Signer < ' info > ,
163212 #[ account(
164213 init,
165214 payer = payer,
166- space = 8 + Storage :: SERIALIZED_LEN ,
215+ space = 8 + StorageV1 :: SERIALIZED_LEN ,
167216 seeds = [ STORAGE_SEED ] ,
168217 bump,
169218 ) ]
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 > ,
171240 #[ account(
172241 init,
173242 payer = payer,
174- space = 0 ,
175- owner = system_program:: ID ,
176- seeds = [ TREASURY_SEED ] ,
243+ space = 8 + StorageV2 :: SERIALIZED_LEN ,
244+ seeds = [ STORAGE_SEED ] ,
177245 bump,
178246 ) ]
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 > ,
183248 pub system_program : Program < ' info , System > ,
184249}
185250
@@ -192,7 +257,7 @@ pub struct Update<'info> {
192257 bump,
193258 has_one = top_authority,
194259 ) ]
195- pub storage : Account < ' info , Storage > ,
260+ pub storage : Account < ' info , StorageV2 > ,
196261}
197262
198263#[ derive( Accounts ) ]
@@ -202,17 +267,10 @@ pub struct VerifyMessage<'info> {
202267 #[ account(
203268 seeds = [ STORAGE_SEED ] ,
204269 bump,
270+ has_one = treasury
205271 ) ]
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.
216274 pub treasury : AccountInfo < ' info > ,
217275 pub system_program : Program < ' info , System > ,
218276 /// CHECK: account ID is checked in Solana SDK during calls
0 commit comments