Skip to content

Commit 7db2e3a

Browse files
authored
chore(price-puhser) Use Hermes Client (#2312)
* initial commit * update-2 * update-3 * removed test * wip * update * update * update * ton-config-update * 1.0.0 * version bump * update
1 parent bc25ee2 commit 7db2e3a

32 files changed

+693
-462
lines changed

apps/price_pusher/README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,7 @@ human-readable logs, you can pipe the output of the program to `pino-pretty`. Se
203203

204204
You can configure the log level of some of the modules of the price pusher as well. The available modules are PriceServiceConnection, which
205205
is responsible for connecting to the Hermes price service, and Controller, which is responsible for checking the prices from the Hermes
206-
and the on-chain Pyth contract and deciding whether to push a new price. You can configure the log level of these modules by passing the
207-
`--price-service-connection-log-level` and `--controller-log-level` arguments, respectively.
206+
and the on-chain Pyth contract and deciding whether to push a new price. You can configure the log level of these modules by passing the `--controller-log-level` arguments, respectively.
208207

209208
### Example
210209

apps/price_pusher/config.aptos.testnet.sample.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"endpoint": "https://fullnode.testnet.aptoslabs.com/v1",
2+
"endpoint": "https://api.testnet.aptoslabs.com/v1",
33
"pyth-contract-address": "0x7e783b349d3e89cf5931af376ebeadbfab855b3fa239b7ada8f5a92fbea6b387",
44
"price-service-endpoint": "https://hermes-beta.pyth.network",
55
"mnemonic-file": "./mnemonic",

apps/price_pusher/config.injective.testnet.sample.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"grpc-endpoint": "https://k8s.testnet.chain.grpc-web.injective.network",
3-
"pyth-contract-address": "inj1z60tg0tekdzcasenhuuwq3htjcd5slmgf7gpez",
3+
"pyth-contract-address": "inj18rlflp3735h25jmjx97d22c72sxk260amdjxlu",
44
"price-service-endpoint": "https://hermes-beta.pyth.network",
55
"mnemonic-file": "./mnemonic",
66
"price-config-file": "./price-config.beta.sample.yaml",

apps/price_pusher/config.sui.mainnet.sample.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"endpoint": "https://sui-testnet-rpc.allthatnode.com",
3-
"pyth-package-id": "0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302",
4-
"pyth-state-id": "0xf9ff3ef935ef6cdfb659a203bf2754cebeb63346e29114a535ea6f41315e5a3f",
2+
"endpoint": "https://sui-mainnet-endpoint.blockvision.org",
3+
"pyth-package-id": "0x04e20ddf36af412a4096f9014f4a565af9e812db9a05cc40254846cf6ed0ad91",
4+
"pyth-state-id": "0x1f9310238ee9298fb703c3419030b35b22bb1cc37113e3bb5007c99aec79e5b8",
55
"wormhole-package-id": "0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a",
66
"wormhole-state-id": "0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c",
77
"price-feed-to-price-info-object-table-id": "0x14b4697477d24c30c8eecc31dd1bd49a3115a9fe0db6bd4fd570cf14640b79a0",

apps/price_pusher/config.ton.mainnet.sample.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"endpoint": "https://toncenter.com/api/v2/jsonRPC",
3-
"pyth-contract-address": "EQBU6k8HH6yX4Jf3d18swWbnYr31D3PJI7PgjXT",
3+
"pyth-contract-address": "EQBU6k8HH6yX4Jf3d18swWbnYr31D3PJI7PgjXT-flsKHqql",
44
"price-service-endpoint": "https://hermes.pyth.network",
55
"private-key-file": "./mnemonic",
66
"price-config-file": "./price-config.stable.sample.yaml"

apps/price_pusher/package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pythnetwork/price-pusher",
3-
"version": "8.3.3",
3+
"version": "9.0.0",
44
"description": "Pyth Price Pusher",
55
"homepage": "https://pyth.network",
66
"main": "lib/index.js",
@@ -24,7 +24,6 @@
2424
"format": "prettier --write \"src/**/*.ts\"",
2525
"test:lint": "eslint src/",
2626
"start": "node lib/index.js",
27-
"test": "jest",
2827
"dev": "ts-node src/index.ts",
2928
"prepublishOnly": "pnpm run build && pnpm run test:lint",
3029
"preversion": "pnpm run test:lint",
@@ -61,7 +60,7 @@
6160
"@injectivelabs/networks": "^1.14.6",
6261
"@injectivelabs/sdk-ts": "1.10.72",
6362
"@mysten/sui": "^1.3.0",
64-
"@pythnetwork/price-service-client": "workspace:*",
63+
"@pythnetwork/hermes-client": "^1.3.1",
6564
"@pythnetwork/price-service-sdk": "workspace:^",
6665
"@pythnetwork/pyth-fuel-js": "workspace:*",
6766
"@pythnetwork/pyth-sdk-solidity": "workspace:*",

apps/price_pusher/price-config.stable.sample.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,8 @@
1212
time_difference: 30
1313
price_deviation: 0.5
1414
confidence_ratio: 0.1
15+
- alias: PYTH/USD
16+
id: 2f95862b045670cd22bee3114c39763a4a08beeb663b145d283c31d7d1101c23
17+
time_difference: 60
18+
price_deviation: 0.5
19+
confidence_ratio: 1

apps/price_pusher/src/__tests__/pyth-price-listener.test.ts

Lines changed: 0 additions & 101 deletions
This file was deleted.

apps/price_pusher/src/aptos/aptos.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
} from "../interface";
77
import { AptosAccount, AptosClient } from "aptos";
88
import { DurationInSeconds } from "../utils";
9-
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
9+
import { HermesClient } from "@pythnetwork/hermes-client";
1010
import { Logger } from "pino";
1111

1212
export class AptosPriceListener extends ChainPriceListener {
@@ -89,7 +89,7 @@ export class AptosPricePusher implements IPricePusher {
8989
private sequenceNumberLocked: boolean;
9090

9191
constructor(
92-
private priceServiceConnection: PriceServiceConnection,
92+
private hermesClient: HermesClient,
9393
private logger: Logger,
9494
private pythContractAddress: string,
9595
private endpoint: string,
@@ -107,11 +107,12 @@ export class AptosPricePusher implements IPricePusher {
107107
* @returns Array of price update data.
108108
*/
109109
async getPriceFeedsUpdateData(priceIds: string[]): Promise<number[][]> {
110-
// Fetch the latest price feed update VAAs from the price service
111-
const latestVaas = await this.priceServiceConnection.getLatestVaas(
112-
priceIds
110+
const response = await this.hermesClient.getLatestPriceUpdates(priceIds, {
111+
encoding: "base64",
112+
});
113+
return response.binary.data.map((data) =>
114+
Array.from(Buffer.from(data, "base64"))
113115
);
114-
return latestVaas.map((vaa) => Array.from(Buffer.from(vaa, "base64")));
115116
}
116117

117118
async updatePriceFeed(
@@ -226,7 +227,7 @@ export class AptosPricePusher implements IPricePusher {
226227
);
227228
return this.lastSequenceNumber;
228229
} catch (e: any) {
229-
throw new Error("Failed to retrieve sequence number");
230+
throw new Error("Failed to retrieve sequence number" + e);
230231
} finally {
231232
this.sequenceNumberLocked = false;
232233
}

apps/price_pusher/src/aptos/command.ts

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
1+
import { HermesClient } from "@pythnetwork/hermes-client";
22
import * as options from "../options";
33
import { readPriceConfigFile } from "../price-config";
44
import fs from "fs";
@@ -12,7 +12,7 @@ import {
1212
} from "./aptos";
1313
import { AptosAccount } from "aptos";
1414
import pino from "pino";
15-
15+
import { filterInvalidPriceItems } from "../utils";
1616
export default {
1717
command: "aptos",
1818
describe: "run price pusher for aptos",
@@ -39,10 +39,9 @@ export default {
3939
...options.pollingFrequency,
4040
...options.pushingFrequency,
4141
...options.logLevel,
42-
...options.priceServiceConnectionLogLevel,
4342
...options.controllerLogLevel,
4443
},
45-
handler: function (argv: any) {
44+
handler: async function (argv: any) {
4645
// FIXME: type checks for this
4746
const {
4847
endpoint,
@@ -54,22 +53,13 @@ export default {
5453
pollingFrequency,
5554
overrideGasPriceMultiplier,
5655
logLevel,
57-
priceServiceConnectionLogLevel,
5856
controllerLogLevel,
5957
} = argv;
6058

6159
const logger = pino({ level: logLevel });
6260

6361
const priceConfigs = readPriceConfigFile(priceConfigFile);
64-
const priceServiceConnection = new PriceServiceConnection(
65-
priceServiceEndpoint,
66-
{
67-
logger: logger.child(
68-
{ module: "PriceServiceConnection" },
69-
{ level: priceServiceConnectionLogLevel }
70-
),
71-
}
72-
);
62+
const hermesClient = new HermesClient(priceServiceEndpoint);
7363

7464
const mnemonic = fs.readFileSync(mnemonicFile, "utf-8").trim();
7565
const account = AptosAccount.fromDerivePath(
@@ -78,10 +68,24 @@ export default {
7868
);
7969
logger.info(`Pushing from account address: ${account.address()}`);
8070

81-
const priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
71+
let priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
72+
73+
// Better to filter out invalid price items before creating the pyth listener
74+
const { existingPriceItems, invalidPriceItems } =
75+
await filterInvalidPriceItems(hermesClient, priceItems);
76+
77+
if (invalidPriceItems.length > 0) {
78+
logger.error(
79+
`Invalid price id submitted for: ${invalidPriceItems
80+
.map(({ alias }) => alias)
81+
.join(", ")}`
82+
);
83+
}
84+
85+
priceItems = existingPriceItems;
8286

8387
const pythListener = new PythPriceListener(
84-
priceServiceConnection,
88+
hermesClient,
8589
priceItems,
8690
logger.child({ module: "PythPriceListener" })
8791
);
@@ -95,7 +99,7 @@ export default {
9599
);
96100

97101
const aptosPusher = new AptosPricePusher(
98-
priceServiceConnection,
102+
hermesClient,
99103
logger.child({ module: "AptosPricePusher" }),
100104
pythContractAddress,
101105
endpoint,

apps/price_pusher/src/controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { UnixTimestamp } from "@pythnetwork/price-service-client";
1+
import { UnixTimestamp } from "@pythnetwork/hermes-client";
22
import { DurationInSeconds, sleep } from "./utils";
33
import { IPriceListener, IPricePusher } from "./interface";
44
import { PriceConfig, shouldUpdate, UpdateCondition } from "./price-config";

apps/price_pusher/src/evm/command.ts

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
1+
import { HermesClient } from "@pythnetwork/hermes-client";
22
import fs from "fs";
33
import { Options } from "yargs";
44
import * as options from "../options";
@@ -10,7 +10,7 @@ import { getCustomGasStation } from "./custom-gas-station";
1010
import pino from "pino";
1111
import { createClient } from "./super-wallet";
1212
import { createPythContract } from "./pyth-contract";
13-
import { isWsEndpoint } from "../utils";
13+
import { isWsEndpoint, filterInvalidPriceItems } from "../utils";
1414

1515
export default {
1616
command: "evm",
@@ -77,7 +77,6 @@ export default {
7777
...options.pollingFrequency,
7878
...options.pushingFrequency,
7979
...options.logLevel,
80-
...options.priceServiceConnectionLogLevel,
8180
...options.controllerLogLevel,
8281
},
8382
handler: async function (argv: any) {
@@ -97,29 +96,37 @@ export default {
9796
gasLimit,
9897
updateFeeMultiplier,
9998
logLevel,
100-
priceServiceConnectionLogLevel,
10199
controllerLogLevel,
102100
} = argv;
101+
console.log("***** priceServiceEndpoint *****", priceServiceEndpoint);
103102

104-
const logger = pino({ level: logLevel });
103+
const logger = pino({
104+
level: logLevel,
105+
});
105106

106107
const priceConfigs = readPriceConfigFile(priceConfigFile);
107-
const priceServiceConnection = new PriceServiceConnection(
108-
priceServiceEndpoint,
109-
{
110-
logger: logger.child(
111-
{ module: "PriceServiceConnection" },
112-
{ level: priceServiceConnectionLogLevel }
113-
),
114-
}
115-
);
108+
const hermesClient = new HermesClient(priceServiceEndpoint);
116109

117110
const mnemonic = fs.readFileSync(mnemonicFile, "utf-8").trim();
118111

119-
const priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
112+
let priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
113+
114+
// Better to filter out invalid price items before creating the pyth listener
115+
const { existingPriceItems, invalidPriceItems } =
116+
await filterInvalidPriceItems(hermesClient, priceItems);
117+
118+
if (invalidPriceItems.length > 0) {
119+
logger.error(
120+
`Invalid price id submitted for: ${invalidPriceItems
121+
.map(({ alias }) => alias)
122+
.join(", ")}`
123+
);
124+
}
125+
126+
priceItems = existingPriceItems;
120127

121128
const pythListener = new PythPriceListener(
122-
priceServiceConnection,
129+
hermesClient,
123130
priceItems,
124131
logger.child({ module: "PythPriceListener" })
125132
);
@@ -152,7 +159,7 @@ export default {
152159
txSpeed
153160
);
154161
const evmPusher = new EvmPricePusher(
155-
priceServiceConnection,
162+
hermesClient,
156163
client,
157164
pythContract,
158165
logger.child({ module: "EvmPricePusher" }),

0 commit comments

Comments
 (0)