diff --git a/pages/lazer/integrate-as-consumer/svm.mdx b/pages/lazer/integrate-as-consumer/svm.mdx
index 4b5eb74a..a0658573 100644
--- a/pages/lazer/integrate-as-consumer/svm.mdx
+++ b/pages/lazer/integrate-as-consumer/svm.mdx
@@ -14,19 +14,34 @@ Integrating with Pyth Lazer in smart contracts as a consumer is a three-step pro
### Use Pyth Lazer SDK into smart contracts
-Pyth Lazer provides a [Rust SDK](https://github.com/pyth-network/pyth-crosschain/tree/main/lazer/sdk/rust), which allows consumers to parse the price updates.
+Pyth Lazer provides a [Solana SDK](https://docs.rs/pyth-lazer-solana-contract/latest/pyth_lazer_solana_contract/), which allows consumers to parse and verify the price updates on Solana-compatible chains.
-Add the following to your `Cargo.toml` file:
+To start, add the following to your `Cargo.toml` file (please check the current latest version at [crates.io](https://crates.io/crates/pyth-lazer-solana-contract)):
```toml copy
[dependencies]
-pyth-lazer-sdk = 0.1.0
+pyth-lazer-solana-contract = { version = "x.y.z", features = ["no-entrypoint"] }
```
Now you can create an instruction or multiple instructions that will receive Pyth Lazer messages.
The instruction data sent to your program should include a byte array containing the Pyth Lazer message. The instruction data can also contain any other parameters your contracts may need.
-In order to successfully validate the Pyth Lazer message, the instruction needs to receive the standard Solana sysvar account and Pyth Lazer storage account (`3rdJbqfnagQ4yx9HXJViD4zc4xpiSqmFsKpPuSCQVyQL`). You may also add any other accounts you need.
+In order to successfully validate the Pyth Lazer message, the instruction needs to receive the following accounts:
+
+- Fee payer account
+- Pyth Lazer program account
+- Pyth Lazer storage account
+- Pyth Lazer treasury account
+- The standard Solana system program account
+- The standard Solana instructions sysvar account
+
+You may also add any other accounts your contract needs.
+
+
+ The code snippets below are part of the full consumer contract example
+ [available on
+ Github](https://github.com/pyth-network/pyth-examples/tree/main/lazer/solana).
+
The following code can be used to set up a new instruction within a Solana contract:
@@ -40,9 +55,13 @@ pub enum Instruction {
/// Update price.
/// Data: `UpdateArgs` followed by a signed Pyth Lazer update.
/// Accounts:
- /// 1. sysvar account [readonly] - required for Pyth Lazer
- /// 2. data account [writable] - needed by our example contract
- /// 3. pyth storage account [readonly] - required for Pyth Lazer
+ /// 1. payer account
+ /// 2. example data account [writable]
+ /// 3. pyth program account [readonly]
+ /// 4. pyth storage account [readonly]
+ /// 5. pyth treasury account [writable]
+ /// 6. system program [readonly]
+ /// 7. instructions sysvar sysvar account [readonly]
Update = 1,
}
@@ -82,36 +101,54 @@ pub fn process_update_instruction(
instruction_args: &[u8],
) -> ProgramResult {
// Verify accounts passed to the instruction.
- if accounts.len() != 3 {
+ if accounts.len() != 7 {
return Err(ProgramError::NotEnoughAccountKeys);
}
- let sysvar_account = &accounts[0];
+ let payer_account = &accounts[0];
let data_account = &accounts[1];
- let pyth_storage_account = &accounts[2];
+ let _pyth_program_account = &accounts[2];
+ let pyth_storage_account = &accounts[3];
+ let pyth_treasury_account = &accounts[4];
+ let system_program_account = &accounts[5];
+ let instructions_sysvar_account = &accounts[6];
// See below for next steps...
}
```
-Call `pyth_lazer_sdk::verify_message{:rust}` function with appropriate arguments to validate the Pyth Lazer signature of the message.
+Invoke the Pyth Lazer on-chain program with appropriate arguments to validate the Pyth Lazer signature of the message.
```rust copy
-// Offset of pyth message within the original instruction_data.
-// 1 byte is the instruction id.
-let pyth_message_total_offset = size_of::() + 1;
// We expect the instruction to the built-in ed25519 program to be
// the first instruction within the transaction.
let ed25519_instruction_index = 0;
// We expect our signature to be the first (and only) signature to be checked
// by the built-in ed25519 program within the transaction.
let signature_index = 0;
-// Check signature verification.
-let verified = pyth_lazer_sdk::verify_message(
- pyth_storage_account,
- sysvar_account,
- pyth_message,
- ed25519_instruction_index,
- signature_index,
- pyth_message_total_offset.try_into().unwrap(),
+// Verify Lazer signature.
+invoke(
+ &ProgramInstruction::new_with_bytes(
+ pyth_lazer_solana_contract::ID,
+ &VerifyMessage {
+ message_data: pyth_message.to_vec(),
+ ed25519_instruction_index,
+ signature_index,
+ }
+ .data(),
+ vec![
+ AccountMeta::new(*payer_account.key, true),
+ AccountMeta::new_readonly(*pyth_storage_account.key, false),
+ AccountMeta::new(*pyth_treasury_account.key, false),
+ AccountMeta::new_readonly(*system_program_account.key, false),
+ AccountMeta::new_readonly(*instructions_sysvar_account.key, false),
+ ],
+ ),
+ &[
+ payer_account.clone(),
+ pyth_storage_account.clone(),
+ pyth_treasury_account.clone(),
+ system_program_account.clone(),
+ instructions_sysvar_account.clone(),
+ ],
)?;
```
@@ -125,7 +162,7 @@ let verified = pyth_lazer_sdk::verify_message(
correctly called in the transaction.
-Now Parse the Pyth Lazer message.
+Now parse the Pyth Lazer message.
```rust copy
// Deserialize and use the payload.
@@ -161,6 +198,12 @@ state.latest_price = price.into_inner().into();
state.latest_timestamp = data.timestamp_us.0;
```
+
+ Pyth Lazer also provides
+ [pyth_lazer_protocol](https://docs.rs/pyth-lazer-protocol/latest/pyth_lazer_protocol/)
+ Rust crate, which allows consumers to parse the price updates off-chain.
+
+
### Subscribe to Pyth Lazer to receive Price Updates
Pyth Lazer provides a websocket endpoint to receive price updates. Moreover, Pyth Lazer also provides a [typescript SDK](https://github.com/pyth-network/pyth-crosschain/tree/main/lazer/sdk/js) to subscribe to the websocket endpoint.
@@ -171,6 +214,55 @@ Consult [How to fetch price updates from Pyth Lazer](../fetch-price-updates.mdx)
Now that you have the price updates, and your smart contract is able to parse the price updates, you can include the price updates into the smart contract transactions by passing the price updates received from the previous step as an argument to the `update_price` method of your smart contract.
+In order to execute signature verification, you need to include an instruction for the built-in Solana ed25519 program in your transaction.
+
+
+
+ In Rust, you can leverage helpers provided in the `pyth_lazer_solana_contract` crate:
+
+```rust copy
+// Instruction #0 will be ed25519 instruction;
+// Instruction #1 will be our contract instruction.
+let instruction_index = 1;
+// Total offset of Pyth Lazer update within the instruction data;
+// 1 byte is the instruction type.
+let message_offset = (size_of::() + 1).try_into().unwrap();
+let ed25519_args = pyth_lazer_solana_contract::Ed25519SignatureOffsets::new(
+ &message,
+ instruction_index,
+ message_offset,
+);
+let mut tx = Transaction::new_with_payer(
+ &[
+ Instruction::new_with_bytes(
+ solana_program::ed25519_program::ID,
+ &pyth_lazer_solana_contract::ed25519_program_args(&[ed25519_args]),
+ vec![],
+ ),
+ Instruction::new_with_bytes(
+ pyth_lazer_solana_example::ID,
+ &update_data,
+ vec![
+ AccountMeta::new(payer.pubkey(), true),
+ AccountMeta::new(data_pda_key, false),
+ AccountMeta::new(pyth_lazer_solana_contract::ID, false),
+ AccountMeta::new_readonly(pyth_lazer_solana_contract::STORAGE_ID, false),
+ AccountMeta::new(treasury, false),
+ AccountMeta::new_readonly(system_program::ID, false),
+ AccountMeta::new_readonly(sysvar::instructions::ID, false),
+ ],
+ ),
+ ],
+ Some(&payer.pubkey()),
+);
+```
+
+
+
+ In TypeScript and JavaScript, you can leverage helpers provided in the `@pythnetwork/pyth-lazer-sdk` NPM package.
+ {/* TODO: add example code */}
+
+
## Additional Resources