Skip to content

Commit

Permalink
feat(HermesClient): Add TWAP endpoint support (#2165)
Browse files Browse the repository at this point in the history
* add latest twap endpoint

* refactor: add logs, clean up

* fix: update HermesClient usage in post_twap_update

* fix: fix window_seconds arg, better log
  • Loading branch information
tejasbadadare authored Jan 3, 2025
1 parent 48690ec commit 512f637
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 8 deletions.
2 changes: 1 addition & 1 deletion apps/hermes/client/js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pythnetwork/hermes-client",
"version": "1.2.0",
"version": "1.3.0",
"description": "Pyth Hermes Client",
"author": {
"name": "Pyth Data Association"
Expand Down
48 changes: 47 additions & 1 deletion apps/hermes/client/js/src/HermesClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type EncodingType = z.infer<typeof schemas.EncodingType>;
export type PriceFeedMetadata = z.infer<typeof schemas.PriceFeedMetadata>;
export type PriceIdInput = z.infer<typeof schemas.PriceIdInput>;
export type PriceUpdate = z.infer<typeof schemas.PriceUpdate>;
export type TwapsResponse = z.infer<typeof schemas.TwapsResponse>;
export type PublisherCaps = z.infer<
typeof schemas.LatestPublisherStakeCapsUpdateDataResponse
>;
Expand Down Expand Up @@ -80,7 +81,12 @@ export class HermesClient {
const response = await fetch(url, options);
clearTimeout(timeout); // Clear the timeout if the request completes in time
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
const errorBody = await response.text();
throw new Error(
`HTTP error! status: ${response.status}${
errorBody ? `, body: ${errorBody}` : ""
}`
);
}
const data = await response.json();
return schema.parse(data);
Expand Down Expand Up @@ -258,6 +264,46 @@ export class HermesClient {
return new EventSource(url.toString(), { headers: this.headers });
}

/**
* Fetch the latest TWAP (time weighted average price) for a set of price feed IDs.
* This endpoint can be customized by specifying the encoding type and whether the results should also return the calculated TWAP using the options object.
* This will throw an error if there is a network problem or the price service returns a non-ok response.
*
* @param ids Array of hex-encoded price feed IDs for which updates are requested.
* @param window_seconds The time window in seconds over which to calculate the TWAP, ending at the current time.
* For example, a value of 300 would return the most recent 5 minute TWAP. Must be greater than 0 and less than or equal to 600 seconds (10 minutes).
* @param options Optional parameters:
* - encoding: Encoding type. If specified, return the TWAP binary data in the encoding specified by the encoding parameter. Default is hex.
* - parsed: Boolean to specify if the calculated TWAP should be included in the response. Default is false.
* - ignoreInvalidPriceIds: Boolean to specify if invalid price IDs should be ignored instead of returning an error. Default is false.
*
* @returns TwapsResponse object containing the latest TWAPs.
*/
async getLatestTwaps(
ids: HexString[],
window_seconds: number,
options?: {
encoding?: EncodingType;
parsed?: boolean;
ignoreInvalidPriceIds?: boolean;
}
): Promise<TwapsResponse> {
const url = new URL(
`v2/updates/twap/${window_seconds}/latest`,
this.baseURL
);
for (const id of ids) {
url.searchParams.append("ids[]", id);
}

if (options) {
const transformedOptions = camelToSnakeCaseObject(options);
this.appendUrlSearchParams(url, transformedOptions);
}

return this.httpRequest(url.toString(), schemas.TwapsResponse);
}

private appendUrlSearchParams(
url: URL,
params: Record<string, string | boolean>
Expand Down
8 changes: 8 additions & 0 deletions apps/hermes/client/js/src/examples/HermesClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,25 @@ async function run() {
const priceIds = argv.priceIds as string[];

// Get price feeds
console.log(`Price feeds matching "btc" with asset type "crypto":`);
const priceFeeds = await connection.getPriceFeeds({
query: "btc",
filter: "crypto",
});
console.log(priceFeeds);

// Latest price updates
console.log(`Latest price updates for price IDs ${priceIds}:`);
const priceUpdates = await connection.getLatestPriceUpdates(priceIds);
console.log(priceUpdates);

// Get the latest 5 second TWAPs
console.log(`Latest 5 second TWAPs for price IDs ${priceIds}`);
const twapUpdates = await connection.getLatestTwaps(priceIds, 5);
console.log(twapUpdates);

// Streaming price updates
console.log(`Streaming latest prices for price IDs ${priceIds}...`);
const eventSource = await connection.getPriceUpdatesStream(priceIds, {
encoding: "hex",
parsed: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ async function main() {
// Post the TWAP updates to ephemeral accounts, one per price feed
await transactionBuilder.addPostTwapUpdates(twapUpdateData);
console.log(
"The SOL/USD TWAP update will get posted to:",
transactionBuilder.getTwapUpdateAccount(SOL_PRICE_FEED_ID).toBase58()
`\nThe SOL/USD TWAP update will get posted to: ${transactionBuilder
.getTwapUpdateAccount(SOL_PRICE_FEED_ID)
.toBase58()}\n`
);

await transactionBuilder.addTwapConsumerInstructions(
Expand Down Expand Up @@ -69,10 +70,10 @@ async function main() {
async function getTwapUpdateData() {
const hermesConnection = new HermesClient("https://hermes.pyth.network/", {});

// Request TWAP updates for the last hour (3600 seconds)
const response = await hermesConnection.getLatestTwapUpdates(
// Request TWAP updates with a 5 minute window (300 seconds)
const response = await hermesConnection.getLatestTwaps(
[SOL_PRICE_FEED_ID, ETH_PRICE_FEED_ID],
3600,
300,
{ encoding: "base64" }
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pythnetwork/pyth-solana-receiver",
"version": "0.9.0",
"version": "0.9.1",
"description": "Pyth solana receiver SDK",
"homepage": "https://pyth.network",
"main": "lib/index.js",
Expand Down

0 comments on commit 512f637

Please sign in to comment.