mirror of
https://github.com/uniwhale-io/pyth-crosschain.git
synced 2026-04-29 12:25:17 +08:00
[price-pusher] refactor index page (#636)
* refactor index page * remove pythcontractaddr * address comments * bug fix
This commit is contained in:
78
package-lock.json
generated
78
package-lock.json
generated
@@ -11095,6 +11095,36 @@
|
||||
"resolved": "target_chains/aptos/sdk/js",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@pythnetwork/pyth-common-js": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-common-js/-/pyth-common-js-1.4.0.tgz",
|
||||
"integrity": "sha512-ilK+0/+tivMVPMIFmup+UfUHklhsS2fqofZxS2+XCn4WBJfI0lIKtiAaBVjV7WmzmC2mDjujcTCDn4RbqpLVqg==",
|
||||
"dependencies": {
|
||||
"@pythnetwork/pyth-sdk-js": "^1.2.0",
|
||||
"@types/ws": "^8.5.3",
|
||||
"axios": "^0.26.1",
|
||||
"axios-retry": "^3.2.4",
|
||||
"isomorphic-ws": "^4.0.1",
|
||||
"ts-log": "^2.2.4",
|
||||
"ws": "^8.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@pythnetwork/pyth-common-js/node_modules/@types/ws": {
|
||||
"version": "8.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz",
|
||||
"integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@pythnetwork/pyth-common-js/node_modules/axios": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
|
||||
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@pythnetwork/pyth-evm-contract": {
|
||||
"resolved": "target_chains/ethereum/contracts",
|
||||
"link": true
|
||||
@@ -11111,6 +11141,11 @@
|
||||
"resolved": "governance/multisig_wh_message_builder",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@pythnetwork/pyth-sdk-js": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-sdk-js/-/pyth-sdk-js-1.2.0.tgz",
|
||||
"integrity": "sha512-grh6YCkp/nH73ACNu+Mew64lLVgz6egVBJm8JvdNkRggWkUn1PE4ZvV/6ceTIui5OhI369qzMCkldiAlIMBjnQ=="
|
||||
},
|
||||
"node_modules/@pythnetwork/pyth-sdk-solidity": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-sdk-solidity/-/pyth-sdk-solidity-2.2.0.tgz",
|
||||
@@ -47823,8 +47858,7 @@
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@injectivelabs/sdk-ts": "^1.0.457",
|
||||
"@pythnetwork/price-service-client": "*",
|
||||
"@pythnetwork/pyth-evm-js": "^1.1.0",
|
||||
"@pythnetwork/pyth-common-js": "^1.4.0",
|
||||
"@pythnetwork/pyth-sdk-solidity": "^2.2.0",
|
||||
"@truffle/hdwallet-provider": "^2.1.3",
|
||||
"joi": "^17.6.0",
|
||||
@@ -57546,6 +57580,38 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pythnetwork/pyth-common-js": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-common-js/-/pyth-common-js-1.4.0.tgz",
|
||||
"integrity": "sha512-ilK+0/+tivMVPMIFmup+UfUHklhsS2fqofZxS2+XCn4WBJfI0lIKtiAaBVjV7WmzmC2mDjujcTCDn4RbqpLVqg==",
|
||||
"requires": {
|
||||
"@pythnetwork/pyth-sdk-js": "^1.2.0",
|
||||
"@types/ws": "^8.5.3",
|
||||
"axios": "^0.26.1",
|
||||
"axios-retry": "^3.2.4",
|
||||
"isomorphic-ws": "^4.0.1",
|
||||
"ts-log": "^2.2.4",
|
||||
"ws": "^8.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/ws": {
|
||||
"version": "8.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz",
|
||||
"integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
|
||||
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.8"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pythnetwork/pyth-evm-contract": {
|
||||
"version": "file:target_chains/ethereum/contracts",
|
||||
"requires": {
|
||||
@@ -57609,8 +57675,7 @@
|
||||
"version": "file:price_pusher",
|
||||
"requires": {
|
||||
"@injectivelabs/sdk-ts": "^1.0.457",
|
||||
"@pythnetwork/price-service-client": "*",
|
||||
"@pythnetwork/pyth-evm-js": "^1.1.0",
|
||||
"@pythnetwork/pyth-common-js": "^1.4.0",
|
||||
"@pythnetwork/pyth-sdk-solidity": "^2.2.0",
|
||||
"@truffle/hdwallet-provider": "^2.1.3",
|
||||
"@types/ethereum-protocol": "^1.0.2",
|
||||
@@ -59529,6 +59594,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pythnetwork/pyth-sdk-js": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-sdk-js/-/pyth-sdk-js-1.2.0.tgz",
|
||||
"integrity": "sha512-grh6YCkp/nH73ACNu+Mew64lLVgz6egVBJm8JvdNkRggWkUn1PE4ZvV/6ceTIui5OhI369qzMCkldiAlIMBjnQ=="
|
||||
},
|
||||
"@pythnetwork/pyth-sdk-solidity": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-sdk-solidity/-/pyth-sdk-solidity-2.2.0.tgz",
|
||||
|
||||
@@ -47,8 +47,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@injectivelabs/sdk-ts": "^1.0.457",
|
||||
"@pythnetwork/price-service-client": "*",
|
||||
"@pythnetwork/pyth-evm-js": "^1.1.0",
|
||||
"@pythnetwork/pyth-common-js": "^1.4.0",
|
||||
"@pythnetwork/pyth-sdk-solidity": "^2.2.0",
|
||||
"@truffle/hdwallet-provider": "^2.1.3",
|
||||
"joi": "^17.6.0",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { UnixTimestamp } from "@pythnetwork/pyth-evm-js";
|
||||
import { UnixTimestamp } from "@pythnetwork/pyth-common-js";
|
||||
import { DurationInSeconds, sleep } from "./utils";
|
||||
import { ChainPricePusher, IPriceListener } from "./interface";
|
||||
import { PriceConfig, shouldUpdate } from "./price-config";
|
||||
@@ -18,6 +18,10 @@ export class Controller {
|
||||
}
|
||||
|
||||
async start() {
|
||||
// start the listeners
|
||||
await this.sourcePriceListener.start();
|
||||
await this.targetPriceListener.start();
|
||||
|
||||
for (;;) {
|
||||
const pricesToPush: PriceConfig[] = [];
|
||||
const pubTimesToPush: UnixTimestamp[] = [];
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
import {
|
||||
EvmPriceServiceConnection,
|
||||
HexString,
|
||||
UnixTimestamp,
|
||||
} from "@pythnetwork/pyth-evm-js";
|
||||
import { Contract, EventData } from "web3-eth-contract";
|
||||
import { PriceConfig } from "./price-config";
|
||||
import { ChainPricePusher, PriceInfo, ChainPriceListener } from "./interface";
|
||||
@@ -13,6 +8,11 @@ import HDWalletProvider from "@truffle/hdwallet-provider";
|
||||
import { Provider } from "web3/providers";
|
||||
import Web3 from "web3";
|
||||
import { isWsEndpoint } from "./utils";
|
||||
import {
|
||||
PriceServiceConnection,
|
||||
HexString,
|
||||
UnixTimestamp,
|
||||
} from "@pythnetwork/pyth-common-js";
|
||||
|
||||
export class EvmPriceListener extends ChainPriceListener {
|
||||
private pythContractFactory: PythContractFactory;
|
||||
@@ -116,7 +116,7 @@ export class EvmPriceListener extends ChainPriceListener {
|
||||
|
||||
export class EvmPricePusher implements ChainPricePusher {
|
||||
constructor(
|
||||
private connection: EvmPriceServiceConnection,
|
||||
private connection: PriceServiceConnection,
|
||||
private pythContract: Contract
|
||||
) {}
|
||||
// The pubTimes are passed here to use the values that triggered the push.
|
||||
@@ -135,7 +135,7 @@ export class EvmPricePusher implements ChainPricePusher {
|
||||
|
||||
const priceIdsWith0x = priceIds.map((priceId) => addLeading0x(priceId));
|
||||
|
||||
const priceFeedUpdateData = await this.connection.getPriceFeedsUpdateData(
|
||||
const priceFeedUpdateData = await this.getPriceFeedsUpdateData(
|
||||
priceIdsWith0x
|
||||
);
|
||||
|
||||
@@ -198,6 +198,15 @@ export class EvmPricePusher implements ChainPricePusher {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
private async getPriceFeedsUpdateData(
|
||||
priceIds: HexString[]
|
||||
): Promise<string[]> {
|
||||
const latestVaas = await this.connection.getLatestVaas(priceIds);
|
||||
return latestVaas.map(
|
||||
(vaa) => "0x" + Buffer.from(vaa, "base64").toString("hex")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class PythContractFactory {
|
||||
|
||||
@@ -4,17 +4,14 @@
|
||||
// FIXME: release a new version
|
||||
import yargs from "yargs";
|
||||
import { hideBin } from "yargs/helpers";
|
||||
import {
|
||||
EvmPriceServiceConnection,
|
||||
CONTRACT_ADDR,
|
||||
} from "@pythnetwork/pyth-evm-js";
|
||||
import { Controller } from "./controller";
|
||||
import { EvmPriceListener, EvmPricePusher, PythContractFactory } from "./evm";
|
||||
import { PythPriceListener } from "./pyth-price-listener";
|
||||
import fs from "fs";
|
||||
import { readPriceConfigFile } from "./price-config";
|
||||
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
|
||||
import { PriceServiceConnection } from "@pythnetwork/pyth-common-js";
|
||||
import { InjectivePriceListener, InjectivePricePusher } from "./injective";
|
||||
import { ChainPricePusher, IPriceListener } from "./interface";
|
||||
|
||||
const argv = yargs(hideBin(process.argv))
|
||||
.option("network", {
|
||||
@@ -27,7 +24,7 @@ const argv = yargs(hideBin(process.argv))
|
||||
description:
|
||||
"RPC endpoint URL for the network. If you provide a normal HTTP endpoint, the pusher " +
|
||||
"will periodically poll for updates. The polling interval is configurable via the " +
|
||||
"`polling-frequency` command-line argument. for the evm chains, if you provide a websocket RPC " +
|
||||
"`polling-frequency` command-line argument. For the evm chains, if you provide a websocket RPC " +
|
||||
"endpoint (`ws[s]://...`), the price pusher will use event subscriptions to read " +
|
||||
"the current EVM price in addition to polling. ",
|
||||
type: "string",
|
||||
@@ -79,102 +76,94 @@ const argv = yargs(hideBin(process.argv))
|
||||
})
|
||||
.parseSync();
|
||||
|
||||
let pythContractAddr: string;
|
||||
|
||||
if (CONTRACT_ADDR[argv.pythContract] !== undefined) {
|
||||
pythContractAddr = CONTRACT_ADDR[argv.pythContract];
|
||||
} else {
|
||||
pythContractAddr = argv.pythContract;
|
||||
}
|
||||
|
||||
const priceConfigs = readPriceConfigFile(argv.priceConfigFile);
|
||||
|
||||
async function injectiveRun() {
|
||||
const connection = new PriceServiceConnection(argv.priceEndpoint, {
|
||||
logger: console,
|
||||
});
|
||||
|
||||
const pythPriceListener = new PythPriceListener(connection, priceConfigs);
|
||||
|
||||
const injectivePriceListener = new InjectivePriceListener(
|
||||
pythContractAddr,
|
||||
argv.endpoint,
|
||||
priceConfigs,
|
||||
{ pollingFrequency: argv.pollingFrequency }
|
||||
);
|
||||
|
||||
const injectivePricePusher = new InjectivePricePusher(
|
||||
connection,
|
||||
argv.pythContract,
|
||||
argv.endpoint,
|
||||
fs.readFileSync(argv.mnemonicFile, "utf-8").trim()
|
||||
);
|
||||
|
||||
// TODO: name ChainPricePusher -> IPricePusher in a clean up PR
|
||||
// TODO: update listeners to not depend on the whole priceConfig
|
||||
async function start({
|
||||
sourcePriceListener,
|
||||
targetPriceListener,
|
||||
targetPricePusher,
|
||||
}: {
|
||||
sourcePriceListener: IPriceListener;
|
||||
targetPriceListener: IPriceListener;
|
||||
targetPricePusher: ChainPricePusher;
|
||||
}) {
|
||||
const handler = new Controller(
|
||||
priceConfigs,
|
||||
pythPriceListener,
|
||||
injectivePriceListener,
|
||||
injectivePricePusher,
|
||||
sourcePriceListener,
|
||||
targetPriceListener,
|
||||
targetPricePusher,
|
||||
{
|
||||
cooldownDuration: argv.cooldownDuration,
|
||||
}
|
||||
);
|
||||
|
||||
await injectivePriceListener.start();
|
||||
await pythPriceListener.start();
|
||||
|
||||
// Handler starts after the above listeners are started
|
||||
// which means that they have fetched their initial price information.
|
||||
await handler.start();
|
||||
}
|
||||
|
||||
async function evmRun() {
|
||||
const connection = new EvmPriceServiceConnection(argv.priceEndpoint, {
|
||||
logger: console,
|
||||
});
|
||||
const priceServiceConnection = new PriceServiceConnection(argv.priceEndpoint, {
|
||||
logger: console,
|
||||
});
|
||||
|
||||
const pythContractFactory = new PythContractFactory(
|
||||
argv.endpoint,
|
||||
fs.readFileSync(argv.mnemonicFile, "utf-8").trim(),
|
||||
pythContractAddr
|
||||
);
|
||||
const pythPriceListener = new PythPriceListener(
|
||||
priceServiceConnection,
|
||||
priceConfigs
|
||||
);
|
||||
|
||||
const evmPriceListener = new EvmPriceListener(
|
||||
pythContractFactory,
|
||||
priceConfigs,
|
||||
{
|
||||
pollingFrequency: argv.pollingFrequency,
|
||||
function getNetworkPriceListener(network: string): IPriceListener {
|
||||
switch (network) {
|
||||
case "evm": {
|
||||
const pythContractFactory = new PythContractFactory(
|
||||
argv.endpoint,
|
||||
fs.readFileSync(argv.mnemonicFile, "utf-8").trim(),
|
||||
argv.pythContract
|
||||
);
|
||||
|
||||
return new EvmPriceListener(pythContractFactory, priceConfigs, {
|
||||
pollingFrequency: argv.pollingFrequency,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const pythPriceListener = new PythPriceListener(connection, priceConfigs);
|
||||
|
||||
const evmPricePusher = new EvmPricePusher(
|
||||
connection,
|
||||
pythContractFactory.createPythContractWithPayer()
|
||||
);
|
||||
|
||||
const handler = new Controller(
|
||||
priceConfigs,
|
||||
pythPriceListener,
|
||||
evmPriceListener,
|
||||
evmPricePusher,
|
||||
{
|
||||
cooldownDuration: argv.cooldownDuration,
|
||||
}
|
||||
);
|
||||
|
||||
await evmPriceListener.start();
|
||||
await pythPriceListener.start();
|
||||
|
||||
// Handler starts after the above listeners are started
|
||||
// which means that they have fetched their initial price information.
|
||||
await handler.start();
|
||||
case "injective":
|
||||
return new InjectivePriceListener(
|
||||
argv.pythContract,
|
||||
argv.endpoint,
|
||||
priceConfigs,
|
||||
{ pollingFrequency: argv.pollingFrequency }
|
||||
);
|
||||
default:
|
||||
throw new Error("invalid network");
|
||||
}
|
||||
}
|
||||
|
||||
function run() {
|
||||
if (argv.network === "injective") injectiveRun();
|
||||
else if (argv.network === "evm") evmRun();
|
||||
function getNetworkPricePusher(network: string): ChainPricePusher {
|
||||
switch (network) {
|
||||
case "evm": {
|
||||
const pythContractFactory = new PythContractFactory(
|
||||
argv.endpoint,
|
||||
fs.readFileSync(argv.mnemonicFile, "utf-8").trim(),
|
||||
argv.pythContract
|
||||
);
|
||||
return new EvmPricePusher(
|
||||
priceServiceConnection,
|
||||
pythContractFactory.createPythContractWithPayer()
|
||||
);
|
||||
}
|
||||
case "injective":
|
||||
return new InjectivePricePusher(
|
||||
priceServiceConnection,
|
||||
argv.pythContract,
|
||||
argv.endpoint,
|
||||
fs.readFileSync(argv.mnemonicFile, "utf-8").trim()
|
||||
);
|
||||
default:
|
||||
throw new Error("invalid network");
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
||||
start({
|
||||
sourcePriceListener: pythPriceListener,
|
||||
targetPriceListener: getNetworkPriceListener(argv.network),
|
||||
targetPricePusher: getNetworkPricePusher(argv.network),
|
||||
});
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import {
|
||||
HexString,
|
||||
PriceServiceConnection,
|
||||
} from "@pythnetwork/price-service-client";
|
||||
import { HexString, PriceServiceConnection } from "@pythnetwork/pyth-common-js";
|
||||
import { ChainPricePusher, PriceInfo, ChainPriceListener } from "./interface";
|
||||
import { DurationInSeconds } from "./utils";
|
||||
import { PriceConfig } from "./price-config";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { HexString, UnixTimestamp } from "@pythnetwork/price-service-client";
|
||||
import { HexString, UnixTimestamp } from "@pythnetwork/pyth-common-js";
|
||||
import { DurationInSeconds } from "./utils";
|
||||
|
||||
export type PriceInfo = {
|
||||
@@ -8,6 +8,8 @@ export type PriceInfo = {
|
||||
};
|
||||
|
||||
export interface IPriceListener {
|
||||
// start fetches the latest price initially and then keep updating it
|
||||
start(): Promise<void>;
|
||||
getLatestPriceInfo(priceId: string): PriceInfo | undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { HexString } from "@pythnetwork/price-service-client";
|
||||
import { HexString } from "@pythnetwork/pyth-common-js";
|
||||
import Joi from "joi";
|
||||
import YAML from "yaml";
|
||||
import fs from "fs";
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
HexString,
|
||||
PriceFeed,
|
||||
PriceServiceConnection,
|
||||
} from "@pythnetwork/price-service-client";
|
||||
} from "@pythnetwork/pyth-common-js";
|
||||
import { PriceConfig } from "./price-config";
|
||||
import { PriceInfo, IPriceListener } from "./interface";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { HexString } from "@pythnetwork/pyth-evm-js";
|
||||
import { HexString } from "@pythnetwork/pyth-common-js";
|
||||
|
||||
export type PctNumber = number;
|
||||
export type DurationInSeconds = number;
|
||||
|
||||
Reference in New Issue
Block a user