-
Notifications
You must be signed in to change notification settings - Fork 35
Add Solana TWAP documentation #650
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
0c8893d
8d43b1b
a7269f2
6449055
2d21106
05a352c
89cf7b0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -241,6 +241,141 @@ The [SDK documentation](https://github.com/pyth-network/pyth-crosschain/tree/mai | |
partially verified price updates. | ||
</Callout> | ||
|
||
## Time-Weighted Average Price (TWAP) | ||
|
||
Pyth also provides Time-Weighted Average Price (TWAP) for Solana applications. TWAP represents the average price over a specified time window, which can be useful for reducing the impact of short-term price volatility. | ||
|
||
<Callout type="warning" emoji="⚠️"> | ||
The TWAP window is currently limited to a maximum of 10 minutes (600 seconds). | ||
</Callout> | ||
|
||
### Using TWAP in Solana Programs | ||
|
||
To use TWAP in your Solana program, import the `TwapUpdate` struct from the Pyth Solana receiver SDK: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mention that this process is the same as pulling a regular price update from hermes and posting it on chain |
||
|
||
```rust copy | ||
use pyth_solana_receiver_sdk::price_update::{TwapUpdate}; | ||
|
||
#[derive(Accounts)] | ||
#[instruction(amount_in_usd : u64, twap_window_seconds: u64)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
pub struct SampleWithTwap<'info> { | ||
#[account(mut)] | ||
pub payer: Signer<'info>, | ||
// Add this account to any instruction Context that needs TWAP data | ||
pub twap_update: Account<'info, TwapUpdate>, | ||
} | ||
``` | ||
|
||
Update your instruction logic to read the TWAP from the update account: | ||
|
||
```rust copy | ||
pub fn sample_with_twap( | ||
ctx: Context<SampleWithTwap>, | ||
amount_in_usd: u64, | ||
twap_window_seconds: u64, | ||
) -> Result<()> { | ||
let twap_update = &mut ctx.accounts.twap_update; | ||
// get_twap_no_older_than will fail if the price update is more than 30 seconds old | ||
let maximum_age: u64 = 30; | ||
// Specify the price feed ID and the window in seconds for the TWAP | ||
let feed_id: [u8; 32] = get_feed_id_from_hex("0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43")?; | ||
let price = twap_update.get_twap_no_older_than( | ||
&Clock::get()?, | ||
maximum_age, | ||
twap_window_seconds, | ||
&feed_id, | ||
)?; | ||
|
||
// Sample output: | ||
// The TWAP price is (7160106530699 ± 5129162301) * 10^-8 | ||
msg!("The TWAP price is ({} ± {}) * 10^{}", price.price, price.conf, price.exponent); | ||
|
||
Ok(()) | ||
} | ||
``` | ||
|
||
### Fetching and Posting TWAP Updates | ||
|
||
To use TWAP updates in your application, you need to fetch them from Hermes and post them to Solana: | ||
|
||
#### Fetch TWAP updates from Hermes | ||
|
||
Use `HermesClient` from `@pythnetwork/hermes-client` to fetch TWAP updates: | ||
|
||
```typescript copy | ||
import { HermesClient } from "@pythnetwork/hermes-client"; | ||
|
||
// The URL below is a public Hermes instance operated by the Pyth Data Association. | ||
// Hermes is also available from several third-party providers listed here: | ||
// https://docs.pyth.network/price-feeds/api-instances-and-providers/hermes | ||
const hermesClient = new HermesClient("https://hermes.pyth.network/", {}); | ||
|
||
// Specify the price feed ID and the TWAP window in seconds (maximum 600 seconds) | ||
const twapWindowSeconds = 300; // 5 minutes | ||
const twapUpdateData = await hermesClient.getLatestTwaps( | ||
["0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"], // BTC/USD feed ID | ||
twapWindowSeconds, | ||
{ encoding: "base64" } | ||
); | ||
|
||
// TWAP updates are strings of base64-encoded binary data | ||
console.log(twapUpdateData.binary.data); | ||
``` | ||
|
||
For a complete example of fetching TWAP updates from Hermes, see the [HermesClient example script](https://github.com/pyth-network/pyth-crosschain/blob/main/apps/hermes/client/js/src/examples/HermesClient.ts) in the Pyth crosschain repository. | ||
|
||
#### Post TWAP updates to Solana | ||
|
||
Use `PythSolanaReceiver` to post the TWAP updates and consume them in your application: | ||
|
||
```typescript copy | ||
import { PythSolanaReceiver } from "@pythnetwork/pyth-solana-receiver"; | ||
|
||
// You will need a Connection from @solana/web3.js and a Wallet from @coral-xyz/anchor | ||
const connection: Connection; | ||
const wallet: Wallet; | ||
const pythSolanaReceiver = new PythSolanaReceiver({ connection, wallet }); | ||
|
||
// Create a transaction builder | ||
const transactionBuilder = pythSolanaReceiver.newTransactionBuilder({ | ||
closeUpdateAccounts: false, | ||
}); | ||
|
||
// Add the TWAP update to the transaction | ||
await transactionBuilder.addPostTwapUpdates(twapUpdateData.binary.data); | ||
|
||
// Add your application's instructions that use the TWAP update | ||
await transactionBuilder.addTwapConsumerInstructions( | ||
async ( | ||
getTwapUpdateAccount: (priceFeedId: string) => PublicKey | ||
): Promise<InstructionWithEphemeralSigners[]> => { | ||
// Generate instructions here that use the TWAP updates posted above | ||
// getTwapUpdateAccount(<price feed id>) will give you the account for each TWAP update | ||
return []; // Replace with your actual instructions | ||
} | ||
); | ||
|
||
// Send the instructions | ||
await pythSolanaReceiver.provider.sendAll( | ||
await transactionBuilder.buildVersionedTransactions({ | ||
computeUnitPriceMicroLamports: 50000, | ||
}), | ||
{ skipPreflight: true } | ||
); | ||
``` | ||
|
||
For a complete example of posting TWAP updates to Solana, see the [post_twap_update.ts example script](https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/solana/sdk/js/pyth_solana_receiver/examples/post_twap_update.ts) in the Pyth crosschain repository. | ||
|
||
### Example Application | ||
|
||
The [Solana TWAP example](https://github.com/pyth-network/pyth-examples/tree/main/price_feeds/solana/send_usd) demonstrates how to fetch TWAP data from Hermes, post it to Solana, and consume it from a smart contract. The example includes: | ||
|
||
- A React frontend for interacting with the contract | ||
- A Solana program that consumes TWAP updates | ||
- Complete transaction building for posting and consuming TWAP data | ||
|
||
The example allows users to send a USD-denominated amount of SOL using either spot prices or TWAP prices, demonstrating how TWAP can be used to reduce the impact of price volatility. | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I might clarify the wording here since I believe this is an existing demo app to which you've added TWAP functionality. |
||
## Additional Resources | ||
|
||
You may find these additional resources helpful for developing your Solana application. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't make this a callout, just add the sentence to the previous block