Skip to content

Commit be3e12c

Browse files
committed
feat(lazer): add treasury and fees to solana contract
1 parent a89055b commit be3e12c

File tree

3 files changed

+87
-28
lines changed

3 files changed

+87
-28
lines changed

lazer/contracts/solana/programs/pyth-lazer-solana-contract/src/lib.rs

Lines changed: 62 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,8 @@
11
mod signature;
22

3-
pub mod storage {
4-
use anchor_lang::prelude::{pubkey, Pubkey};
5-
6-
pub const ID: Pubkey = pubkey!("3rdJbqfnagQ4yx9HXJViD4zc4xpiSqmFsKpPuSCQVyQL");
7-
8-
#[test]
9-
fn test_storage_id() {
10-
use {crate::STORAGE_SEED, anchor_lang::prelude::Pubkey};
11-
12-
assert_eq!(
13-
Pubkey::find_program_address(&[STORAGE_SEED], &super::ID).0,
14-
ID
15-
);
16-
}
17-
}
18-
193
use {
20-
anchor_lang::{prelude::*, solana_program::pubkey::PUBKEY_BYTES},
4+
crate::signature::VerifiedMessage,
5+
anchor_lang::{prelude::*, solana_program::pubkey::PUBKEY_BYTES, system_program},
216
std::mem::size_of,
227
};
238

@@ -28,6 +13,21 @@ pub use {
2813

2914
declare_id!("pytd2yyk641x7ak7mkaasSJVXh6YYZnC7wTmtgAyxPt");
3015

16+
pub const STORAGE_ID: Pubkey = pubkey!("3rdJbqfnagQ4yx9HXJViD4zc4xpiSqmFsKpPuSCQVyQL");
17+
pub const TREASURY_ID: Pubkey = pubkey!("EN4aB3soE5iuCG2fGj2r5fksh4kLRVPV8g7N86vXm8WM");
18+
19+
#[test]
20+
fn test_ids() {
21+
assert_eq!(
22+
Pubkey::find_program_address(&[STORAGE_SEED], &ID).0,
23+
STORAGE_ID
24+
);
25+
assert_eq!(
26+
Pubkey::find_program_address(&[TREASURY_SEED], &ID).0,
27+
TREASURY_ID
28+
);
29+
}
30+
3131
pub const MAX_NUM_TRUSTED_SIGNERS: usize = 2;
3232

3333
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, AnchorSerialize, AnchorDeserialize)]
@@ -44,12 +44,14 @@ impl TrustedSignerInfo {
4444
pub struct Storage {
4545
pub top_authority: Pubkey,
4646
pub num_trusted_signers: u8,
47+
pub single_update_fee_in_lamports: u64,
4748
pub trusted_signers: [TrustedSignerInfo; MAX_NUM_TRUSTED_SIGNERS],
4849
}
4950

5051
impl Storage {
5152
const SERIALIZED_LEN: usize = PUBKEY_BYTES
5253
+ size_of::<u8>()
54+
+ size_of::<u64>()
5355
+ TrustedSignerInfo::SERIALIZED_LEN * MAX_NUM_TRUSTED_SIGNERS;
5456

5557
pub fn initialized_trusted_signers(&self) -> &[TrustedSignerInfo] {
@@ -58,15 +60,15 @@ impl Storage {
5860
}
5961

6062
pub const STORAGE_SEED: &[u8] = b"storage";
63+
pub const TREASURY_SEED: &[u8] = b"treasury";
6164

6265
#[program]
6366
pub mod pyth_lazer_solana_contract {
64-
use signature::VerifiedMessage;
65-
6667
use super::*;
6768

6869
pub fn initialize(ctx: Context<Initialize>, top_authority: Pubkey) -> Result<()> {
6970
ctx.accounts.storage.top_authority = top_authority;
71+
ctx.accounts.storage.single_update_fee_in_lamports = 1;
7072
Ok(())
7173
}
7274

@@ -128,9 +130,20 @@ pub mod pyth_lazer_solana_contract {
128130
signature_index: u8,
129131
message_offset: u16,
130132
) -> Result<VerifiedMessage> {
133+
system_program::transfer(
134+
CpiContext::new(
135+
ctx.accounts.system_program.to_account_info(),
136+
system_program::Transfer {
137+
from: ctx.accounts.payer.to_account_info(),
138+
to: ctx.accounts.treasury.to_account_info(),
139+
},
140+
),
141+
ctx.accounts.storage.single_update_fee_in_lamports,
142+
)?;
143+
131144
signature::verify_message(
132145
&ctx.accounts.storage,
133-
&ctx.accounts.sysvar,
146+
&ctx.accounts.instructions_sysvar,
134147
&message_data,
135148
ed25519_instruction_index,
136149
signature_index,
@@ -155,6 +168,18 @@ pub struct Initialize<'info> {
155168
bump,
156169
)]
157170
pub storage: Account<'info, Storage>,
171+
#[account(
172+
init,
173+
payer = payer,
174+
space = 0,
175+
owner = system_program::ID,
176+
seeds = [TREASURY_SEED],
177+
bump,
178+
)]
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>,
158183
pub system_program: Program<'info, System>,
159184
}
160185

@@ -172,10 +197,26 @@ pub struct Update<'info> {
172197

173198
#[derive(Accounts)]
174199
pub struct VerifyMessage<'info> {
200+
#[account(mut)]
201+
pub payer: Signer<'info>,
175202
#[account(
176203
seeds = [STORAGE_SEED],
177204
bump,
178205
)]
179206
pub storage: Account<'info, Storage>,
180-
pub sysvar: AccountInfo<'info>,
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.
216+
pub treasury: AccountInfo<'info>,
217+
pub system_program: Program<'info, System>,
218+
/// CHECK: account ID is checked in Solana SDK during calls
219+
/// (e.g. in `sysvar::instructions::load_instruction_at_checked`).
220+
/// This account is not usable with anchor's `Program` account type because it's not executable.
221+
pub instructions_sysvar: AccountInfo<'info>,
181222
}

lazer/contracts/solana/programs/pyth-lazer-solana-contract/src/signature.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ impl From<SignatureVerificationError> for anchor_lang::error::Error {
159159
/// input data for the current instruction.
160160
pub fn verify_message(
161161
storage: &Storage,
162-
instruction_sysvar: &AccountInfo,
162+
instructions_sysvar: &AccountInfo,
163163
message_data: &[u8],
164164
ed25519_instruction_index: u16,
165165
signature_index: u8,
@@ -168,7 +168,7 @@ pub fn verify_message(
168168
const SOLANA_FORMAT_MAGIC_LE: u32 = 2182742457;
169169

170170
let self_instruction_index =
171-
sysvar::instructions::load_current_index_checked(instruction_sysvar)
171+
sysvar::instructions::load_current_index_checked(instructions_sysvar)
172172
.map_err(SignatureVerificationError::LoadCurrentIndexFailed)?;
173173

174174
if ed25519_instruction_index >= self_instruction_index {
@@ -177,7 +177,7 @@ pub fn verify_message(
177177

178178
let instruction = sysvar::instructions::load_instruction_at_checked(
179179
ed25519_instruction_index.into(),
180-
instruction_sysvar,
180+
instructions_sysvar,
181181
)
182182
.map_err(SignatureVerificationError::LoadInstructionAtFailed)?;
183183

lazer/contracts/solana/programs/pyth-lazer-solana-contract/tests/test1.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ async fn test1() {
3737
.data(),
3838
vec![
3939
AccountMeta::new(payer.pubkey(), true),
40-
AccountMeta::new(pyth_lazer_solana_contract::storage::ID, false),
40+
AccountMeta::new(pyth_lazer_solana_contract::STORAGE_ID, false),
41+
AccountMeta::new(pyth_lazer_solana_contract::TREASURY_ID, false),
4142
AccountMeta::new_readonly(system_program::ID, false),
4243
],
4344
)],
@@ -68,7 +69,7 @@ async fn test1() {
6869
.data(),
6970
vec![
7071
AccountMeta::new(payer.pubkey(), true),
71-
AccountMeta::new(pyth_lazer_solana_contract::storage::ID, false),
72+
AccountMeta::new(pyth_lazer_solana_contract::STORAGE_ID, false),
7273
],
7374
)],
7475
Some(&payer.pubkey()),
@@ -90,7 +91,12 @@ async fn test1() {
9091
message_offset,
9192
));
9293

93-
println!("ok1");
94+
let treasury_starting_lamports = banks_client
95+
.get_account(pyth_lazer_solana_contract::TREASURY_ID)
96+
.await
97+
.unwrap()
98+
.unwrap()
99+
.lamports;
94100
let mut transaction_verify = Transaction::new_with_payer(
95101
&[
96102
Instruction::new_with_bytes(
@@ -108,7 +114,10 @@ async fn test1() {
108114
}
109115
.data(),
110116
vec![
111-
AccountMeta::new_readonly(pyth_lazer_solana_contract::storage::ID, false),
117+
AccountMeta::new(payer.pubkey(), true),
118+
AccountMeta::new_readonly(pyth_lazer_solana_contract::STORAGE_ID, false),
119+
AccountMeta::new(pyth_lazer_solana_contract::TREASURY_ID, false),
120+
AccountMeta::new_readonly(system_program::ID, false),
112121
AccountMeta::new_readonly(sysvar::instructions::ID, false),
113122
],
114123
),
@@ -120,4 +129,13 @@ async fn test1() {
120129
.process_transaction(transaction_verify)
121130
.await
122131
.unwrap();
132+
assert_eq!(
133+
banks_client
134+
.get_account(pyth_lazer_solana_contract::TREASURY_ID)
135+
.await
136+
.unwrap()
137+
.unwrap()
138+
.lamports,
139+
treasury_starting_lamports + 1
140+
);
123141
}

0 commit comments

Comments
 (0)