From e972091f09d9c225253ddada137630e4f6091c22 Mon Sep 17 00:00:00 2001 From: Maurechi Date: Tue, 28 Feb 2023 14:04:53 +0100 Subject: [PATCH 1/2] added custom-gas-station --- .../src/custom-gas-station.ts | 34 +++++++++++++++++++ pyth-evm-price-pusher/src/index.ts | 25 +++++++++++++- pyth-evm-price-pusher/src/pusher.ts | 11 ++++-- pyth-evm-price-pusher/src/utils.ts | 16 +++++++++ 4 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 pyth-evm-price-pusher/src/custom-gas-station.ts diff --git a/pyth-evm-price-pusher/src/custom-gas-station.ts b/pyth-evm-price-pusher/src/custom-gas-station.ts new file mode 100644 index 0000000..254238d --- /dev/null +++ b/pyth-evm-price-pusher/src/custom-gas-station.ts @@ -0,0 +1,34 @@ +import Web3 from "web3"; +import { + CustomGasChainId, + TxSpeed, + verifyValidOption, + txSpeeds, + customGasChainIds, +} from "./utils"; + +type chainMethods = Record Promise>; + +export class CustomGasStation { + private chain: CustomGasChainId; + private speed: TxSpeed; + private chainMethods: chainMethods = { + 137: this.fetchMaticMainnetGasPrice.bind(this), + }; + constructor(chain: number, speed: string) { + this.speed = verifyValidOption(speed, txSpeeds); + this.chain = verifyValidOption(chain, customGasChainIds); + } + + async getCustomGasPrice() { + return this.chainMethods[this.chain](); + } + + async fetchMaticMainnetGasPrice() { + const res = await fetch("https://gasstation-mainnet.matic.network/v2"); + const jsonRes = await res.json(); + const gasPrice = jsonRes[this.speed].maxFee; + const gweiGasPrice = Web3.utils.toWei(gasPrice.toFixed(2), "Gwei"); + return gweiGasPrice.toString(); + } +} diff --git a/pyth-evm-price-pusher/src/index.ts b/pyth-evm-price-pusher/src/index.ts index c1b4546..da29a97 100644 --- a/pyth-evm-price-pusher/src/index.ts +++ b/pyth-evm-price-pusher/src/index.ts @@ -12,6 +12,7 @@ import { PythPriceListener } from "./pyth-price-listener"; import fs from "fs"; import { readPriceConfigFile } from "./price-config"; import { PythContractFactory } from "./pyth-contract-factory"; +import { CustomGasStation } from "./custom-gas-station"; const argv = yargs(hideBin(process.argv)) .option("evm-endpoint", { @@ -63,6 +64,18 @@ const argv = yargs(hideBin(process.argv)) required: false, default: 5, }) + .option("custom-gas-station", { + description: + "If using a custom gas station, chainId of custom gas station to use", + type: "number", + required: false, + }) + .option("tx-speed", { + description: + "txSpeed for custom gas station. choose between 'slow'|'standard'|'fast'", + type: "string", + required: false, + }) .help() .alias("help", "h") .parserConfiguration({ @@ -101,6 +114,15 @@ async function run() { const pythPriceListener = new PythPriceListener(connection, priceConfigs); + let customGasStation: CustomGasStation | undefined; + + if (argv.customGasStation && argv.txSpeed) { + customGasStation = new CustomGasStation( + argv.customGasStation, + argv.txSpeed + ); + } + const handler = new Pusher( connection, pythContractFactory, @@ -109,7 +131,8 @@ async function run() { priceConfigs, { cooldownDuration: argv.cooldownDuration, - } + }, + customGasStation ); await evmPriceListener.start(); diff --git a/pyth-evm-price-pusher/src/pusher.ts b/pyth-evm-price-pusher/src/pusher.ts index 6fc76ec..ee1283b 100644 --- a/pyth-evm-price-pusher/src/pusher.ts +++ b/pyth-evm-price-pusher/src/pusher.ts @@ -8,6 +8,7 @@ import { Contract } from "web3-eth-contract"; import { PriceConfig } from "./price-config"; import { TransactionReceipt } from "ethereum-protocol"; import { PythContractFactory } from "./pyth-contract-factory"; +import { CustomGasStation } from "./custom-gas-station"; export class Pusher { private connection: EvmPriceServiceConnection; @@ -16,8 +17,8 @@ export class Pusher { private targetPriceListener: PriceListener; private sourcePriceListener: PriceListener; private priceConfigs: PriceConfig[]; - private cooldownDuration: DurationInSeconds; + private customGasStation?: CustomGasStation; constructor( connection: EvmPriceServiceConnection, @@ -27,7 +28,8 @@ export class Pusher { priceConfigs: PriceConfig[], config: { cooldownDuration: DurationInSeconds; - } + }, + customGasStation?: CustomGasStation ) { this.connection = connection; this.targetPriceListener = targetPriceListener; @@ -38,6 +40,7 @@ export class Pusher { this.pythContractFactory = pythContractFactory; this.pythContract = this.pythContractFactory.createPythContractWithPayer(); + this.customGasStation = customGasStation; } async start() { @@ -96,13 +99,15 @@ export class Pusher { .call(); console.log(`Update fee: ${updateFee}`); + const gasPrice = await this.customGasStation?.getCustomGasPrice(); + this.pythContract.methods .updatePriceFeedsIfNecessary( priceFeedUpdateData, priceIds, pubTimesToPush ) - .send({ value: updateFee }) + .send({ value: updateFee, gasPrice }) .on("transactionHash", (hash: string) => { console.log(`Successful. Tx hash: ${hash}`); }) diff --git a/pyth-evm-price-pusher/src/utils.ts b/pyth-evm-price-pusher/src/utils.ts index a04ee5f..eb757de 100644 --- a/pyth-evm-price-pusher/src/utils.ts +++ b/pyth-evm-price-pusher/src/utils.ts @@ -2,6 +2,10 @@ import { HexString } from "@pythnetwork/pyth-evm-js"; export type PctNumber = number; export type DurationInSeconds = number; +export const txSpeeds = ["slow", "standard", "fast"] as const; +export type TxSpeed = typeof txSpeeds[number]; +export const customGasChainIds = [137] as const; +export type CustomGasChainId = typeof customGasChainIds[number]; export async function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); @@ -31,3 +35,15 @@ export function isWsEndpoint(endpoint: string): boolean { return false; } + +export function verifyValidOption< + options extends Readonly>, + validOption extends options[number] +>(option: any, validOptions: options) { + if (validOptions.includes(option)) { + return option as validOption; + } + const errorString = + option + " is not a valid option. Please choose between " + validOptions; + throw new Error(errorString); +} From bb2f6453bb008b550844a4261c51a0c7891dca4a Mon Sep 17 00:00:00 2001 From: Maurechi Date: Tue, 28 Feb 2023 14:08:21 +0100 Subject: [PATCH 2/2] made specific chain function private --- pyth-evm-price-pusher/src/custom-gas-station.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyth-evm-price-pusher/src/custom-gas-station.ts b/pyth-evm-price-pusher/src/custom-gas-station.ts index 254238d..93d551c 100644 --- a/pyth-evm-price-pusher/src/custom-gas-station.ts +++ b/pyth-evm-price-pusher/src/custom-gas-station.ts @@ -24,7 +24,7 @@ export class CustomGasStation { return this.chainMethods[this.chain](); } - async fetchMaticMainnetGasPrice() { + private async fetchMaticMainnetGasPrice() { const res = await fetch("https://gasstation-mainnet.matic.network/v2"); const jsonRes = await res.json(); const gasPrice = jsonRes[this.speed].maxFee;