Skip to content

Commit

Permalink
docs: code docs for solana sdk (#1330)
Browse files Browse the repository at this point in the history
* Do it

* Remove some duplicate code

* Cleanup

* Cleanup

* Cleanup import

* Correct description

* Fix path

* Cleanup deps

* Unique

* Works

* Continue

* Lint

* Lint config

* Fix ci

* Checkpoint

* Checkpoint

* Gitignore

* Cleanup

* Cleanup

* Continue building the sdk

* build function

* Remove files

* Remove files

* Rename

* Refactor : make transaction builder

* Make commitment

* Move

* Progress

* Checkpoint

* Ephemeral signers 2

* Checkpoint

* Checkpoint

* Fix bug

* Cleanup idls

* Compute units

* Make program addresses configurable

* Handle arrays

* Handle arrays

* Move PythSolanaReceiver

* Cleanup constants

* Contants

* Refactor constants

* Gitignore refactor

* package lock

* Cleanup idl

* Add useful static

* Add useful static

* Add useful static

* Lint

* Add lint config

* Docs

* Comments

* Docs

* Don't touch this

* Readme

* Readme

* Cleanup

* Readme

* Fix

* address readme comments

* from pyth, not pythnet

* Add a couple more comments

* Rename cleanup to close

* Go go go
  • Loading branch information
guibescos authored Mar 13, 2024
1 parent 04b66fa commit 16cc46e
Show file tree
Hide file tree
Showing 9 changed files with 526 additions and 62 deletions.
161 changes: 161 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions target_chains/solana/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@

This folder contains:

- A Pyth receiver program to receive Pythnet price feeds on Solana in `programs/pyth-solana-receiver`
- A Pyth receiver program to receive Pyth price updates on Solana in `programs/pyth-solana-receiver`
- A Cli that acts as a simple client to interact with the Pyth receiver program in `cli/`

# Overview of the design

Receiving a price update from Pythnet involves two steps:
Posting a Pyth price update involves two steps:

- First, verifying the VAA i.e. verifying the Wormhole guardians' signatures on the accumulator root that contains all the price updates for a given Pythnet slot.
- Second, verifying the price update by providing an inclusion proof that proves the price update is part of the accumulator root that was verified in the first step.

# Implementation

This contract offers two ways to post a price update from Pythnet onto Solana:
This contract offers two ways to post a Pyth price update onto Solana:

- `post_update` allows you to do it in 2 transactions and checks all the Wormhole guardian signatures (the quorum is currently 13 signatures). It relies on the Wormhole contract to verify the signatures.
- `post_update_atomic` allows you to do it in 1 transaction but only partially checks the Wormhole guardian signatures (5 signatures seems like the best it can currently do). Therefore it is less secure. It relies on a guardian set account from the Wormhole contract to check the signatures against the guardian keys.
Expand Down
83 changes: 83 additions & 0 deletions target_chains/solana/sdk/js/pyth_solana_receiver/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Pyth Solana Receiver JS SDK

This is a Javascript SDK to interact with the Pyth Solana Receiver contract whose code lives [here](/target_chains/solana).

## Pull model

The Pyth Solana Receiver allows users to consume Pyth price updates on a pull basis. This means that the user is responsible for submitting the price data on-chain whenever they want to interact with an app that requires a price update.

Price updates get posted into price update accounts, owned by the Receiver contract. Once an update has been posted to a price update account, it can be used by anyone by simply passing the price update account as one of the accounts in a Solana instruction.
Price update accounts can be closed by whoever wrote them to recover the rent.

## Example use

```ts
import { Connection, PublicKey } from '@solana/web3.js';
import { PriceServiceConnection } from '@pythnetwork/price-service-client';
import { PythSolanaReceiver } from '@pythnetwork/pyth-solana-receiver';
import { MyFirstPythApp, IDL } from './idl/my_first_pyth_app';


const SOL_PRICE_FEED_ID = "0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d"
const ETH_PRICE_FEED_ID = "0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace"

const priceServiceConnection = new PriceServiceConnection("https://hermes.pyth.network/", { priceFeedRequestConfig: { binary: true } });
const priceUpdateData = await priceServiceConnection.getLatestVaas([SOL_PRICE_FEED_ID, ETH_PRICE_FEED_ID]); // Fetch off-chain price update data


const myFirstPythApp = new Program<MyFirstPythApp>(IDL as MyFirstPythApp, , PublicKey.unique(), {})
const getInstructions = async (priceFeedIdToPriceUpdateAccount: Record<string, PublicKey>) => { return [{ instruction: await myFirstApp.methods.consume().accounts({ solPriceUpdate: priceFeedIdToPriceUpdateAccount[SOL_PRICE_FEED_ID], ethPriceUpdate: priceFeedIdToPriceUpdateAccount[ETH_PRICE_FEED_ID] }).instruction(), signers: [] }] };

const pythSolanaReceiver = new PythSolanaReceiver({ connection, wallet });
const transactions = await pythSolanaReceiver.withPriceUpdate(priceUpdateData, getInstructions, {})
await pythSolanaReceiver.provider.sendAll(transactions);
```

Or, alternatively:

```ts
import { PublicKey } from "@solana/web3.js";
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
import { PythSolanaReceiver } from "@pythnetwork/pyth-solana-receiver";
import { MyFirstPythApp, IDL } from "./idl/my_first_pyth_app";

const SOL_PRICE_FEED_ID =
"0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d";
const ETH_PRICE_FEED_ID =
"0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace";

const priceServiceConnection = new PriceServiceConnection(
"https://hermes.pyth.network/",
{ priceFeedRequestConfig: { binary: true } }
);
const priceUpdateData = await priceServiceConnection.getLatestVaas([
SOL_PRICE_FEED_ID,
ETH_PRICE_FEED_ID,
]); // Fetch off-chain price update data

const pythSolanaReceiver = new PythSolanaReceiver({ connection, wallet });
const { postInstructions, closeInstructions, priceFeedIdToPriceUpdateAccount } =
await pythSolanaReceiver.buildPostPriceUpdateInstructions(priceUpdateData); // Get instructions to post the price update data and to close the accounts later

const myFirstPythApp = new Program<MyFirstPythApp>(
IDL as MyFirstPythApp,
PublicKey.unique(),
{}
);
const consumerInstruction: InstructionWithEphemeralSigners = {
instruction: await myFirstPythApp.methods
.consume()
.accounts({
solPriceUpdate: priceFeedIdToPriceUpdateAccount[SOL_PRICE_FEED_ID],
ethPriceUpdate: priceFeedIdToPriceUpdateAccount[ETH_PRICE_FEED_ID],
})
.instruction(),
signers: [],
};

const transactions = pythSolanaReceiver.batchIntoVersionedTransactions(
[...postInstructions, consumerInstruction, ...closeInstructions],
{}
); // Put all the instructions together
await pythSolanaReceiver.provider.sendAll(transactions);
```
Loading

0 comments on commit 16cc46e

Please sign in to comment.