|
|
@@ -0,0 +1,117 @@
|
|
|
+import Web3 from "web3";
|
|
|
+import yargs from "yargs";
|
|
|
+import { hideBin } from "yargs/helpers";
|
|
|
+
|
|
|
+import { EvmPriceServiceConnection } from "../index";
|
|
|
+import HDWalletProvider from "@truffle/hdwallet-provider";
|
|
|
+import PythInterfaceAbi from "@pythnetwork/pyth-sdk-solidity/abis/IPyth.json";
|
|
|
+
|
|
|
+const argv = yargs(hideBin(process.argv))
|
|
|
+ .option("network", {
|
|
|
+ description: "RPC of the network to relay on.",
|
|
|
+ type: "string",
|
|
|
+ required: true,
|
|
|
+ })
|
|
|
+ .option("endpoint", {
|
|
|
+ description:
|
|
|
+ "Endpoint URL for the price service. e.g: https://endpoint/example",
|
|
|
+ type: "string",
|
|
|
+ required: true,
|
|
|
+ })
|
|
|
+ .option("pyth-contract", {
|
|
|
+ description: "Pyth contract address.",
|
|
|
+ type: "string",
|
|
|
+ required: true,
|
|
|
+ })
|
|
|
+ .option("price-id", {
|
|
|
+ description:
|
|
|
+ "Price feed id (in hex) to fetch" + " e.g: 0xf9c0172ba10dfa4d19088d...",
|
|
|
+ type: "string",
|
|
|
+ required: true,
|
|
|
+ })
|
|
|
+ .option("timestamp", {
|
|
|
+ description: "Timestamp of the prices to fetch" + " e.g., 2022-", // TODO
|
|
|
+ type: "string",
|
|
|
+ required: true,
|
|
|
+ })
|
|
|
+ .option("mnemonic", {
|
|
|
+ description: "Mnemonic (private key) for sender",
|
|
|
+ type: "string",
|
|
|
+ required: true,
|
|
|
+ })
|
|
|
+ .help()
|
|
|
+ .alias("help", "h")
|
|
|
+ .parserConfiguration({
|
|
|
+ "parse-numbers": false,
|
|
|
+ })
|
|
|
+ .parseSync();
|
|
|
+
|
|
|
+const network = argv.network;
|
|
|
+const pythContractAddr = argv.pythContract;
|
|
|
+
|
|
|
+const connection = new EvmPriceServiceConnection(argv.endpoint);
|
|
|
+
|
|
|
+async function run() {
|
|
|
+ const provider = new HDWalletProvider({
|
|
|
+ mnemonic: {
|
|
|
+ phrase: argv.mnemonic,
|
|
|
+ },
|
|
|
+ providerOrUrl: network,
|
|
|
+ });
|
|
|
+
|
|
|
+ // @ts-ignore
|
|
|
+ const web3 = new Web3(provider);
|
|
|
+ const priceId = argv.priceId as string;
|
|
|
+ // The unix timestamp in seconds
|
|
|
+ const unixTimestamp = Date.parse(argv.timestamp) / 1000;
|
|
|
+
|
|
|
+ console.log(`Querying unix timestamp: ${unixTimestamp}`);
|
|
|
+
|
|
|
+ const [priceFeedUpdateVaa, updateTimestamp] = await connection.getVaa(
|
|
|
+ priceId,
|
|
|
+ unixTimestamp
|
|
|
+ );
|
|
|
+ console.log(`Next pyth update was at: ${updateTimestamp}`);
|
|
|
+ console.log(priceFeedUpdateVaa);
|
|
|
+
|
|
|
+ const priceFeedUpdate =
|
|
|
+ "0x" + Buffer.from(priceFeedUpdateVaa, "base64").toString("hex");
|
|
|
+
|
|
|
+ const pythContract = new web3.eth.Contract(
|
|
|
+ PythInterfaceAbi as any,
|
|
|
+ pythContractAddr,
|
|
|
+ {
|
|
|
+ from: provider.getAddress(0),
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ const updateFee = await pythContract.methods
|
|
|
+ .getUpdateFee([priceFeedUpdate])
|
|
|
+ .call();
|
|
|
+ console.log(`Update fee: ${updateFee}`);
|
|
|
+
|
|
|
+ // In real use cases, you would pass the update to your contract, then call parsePriceFeedUpdates within your contract.
|
|
|
+ // When invoked on-chain, this function will return a PriceFeed struct containing the data in the price update
|
|
|
+ // (such as the current price).
|
|
|
+ await pythContract.methods
|
|
|
+ .parsePriceFeedUpdates(
|
|
|
+ [priceFeedUpdate],
|
|
|
+ [priceId],
|
|
|
+ // parsePriceFeedUpdates will reject any price update outside of the time window provided in the following
|
|
|
+ // two arguments. Integrators can use this to specify the timestamp of the update they are expecting.
|
|
|
+ unixTimestamp,
|
|
|
+ unixTimestamp + 5
|
|
|
+ )
|
|
|
+ .send({ value: updateFee })
|
|
|
+ .on("transactionHash", (hash: string) => {
|
|
|
+ console.log(`Tx hash: ${hash}`);
|
|
|
+ })
|
|
|
+ .on("error", (err: any, receipt: any) => {
|
|
|
+ console.error(receipt);
|
|
|
+ throw err;
|
|
|
+ });
|
|
|
+
|
|
|
+ provider.engine.stop();
|
|
|
+}
|
|
|
+
|
|
|
+run();
|