Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions price_pusher/src/custom-gas-station.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Web3 from "web3";
import {
CustomGasChainId,
TxSpeed,
verifyValidOption,
txSpeeds,
customGasChainIds,
} from "./utils";

type chainMethods = Record<CustomGasChainId, () => Promise<string>>;

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]();
}

private 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();
}
}
14 changes: 10 additions & 4 deletions price_pusher/src/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
HexString,
UnixTimestamp,
} from "@pythnetwork/pyth-common-js";
import { CustomGasStation } from "./custom-gas-station";

export class EvmPriceListener extends ChainPriceListener {
private pythContractFactory: PythContractFactory;
Expand Down Expand Up @@ -117,10 +118,14 @@ export class EvmPriceListener extends ChainPriceListener {
}

export class EvmPricePusher implements ChainPricePusher {
private customGasStation?: CustomGasStation;
constructor(
private connection: PriceServiceConnection,
private pythContract: Contract
) {}
private pythContract: Contract,
customGasStation?: CustomGasStation
) {
this.customGasStation = customGasStation;
}
// The pubTimes are passed here to use the values that triggered the push.
// This is an optimization to avoid getting a newer value (as an update comes)
// and will help multiple price pushers to have consistent behaviour.
Expand All @@ -145,19 +150,20 @@ export class EvmPricePusher implements ChainPricePusher {
"Pushing ",
priceIdsWith0x.map((priceIdWith0x) => `${priceIdWith0x}`)
);

const updateFee = await this.pythContract.methods
.getUpdateFee(priceFeedUpdateData)
.call();
console.log(`Update fee: ${updateFee}`);

const gasPrice = await this.customGasStation?.getCustomGasPrice();

this.pythContract.methods
.updatePriceFeedsIfNecessary(
priceFeedUpdateData,
priceIdsWith0x,
pubTimesToPush
)
.send({ value: updateFee })
.send({ value: updateFee, gasPrice })
.on("transactionHash", (hash: string) => {
console.log(`Successful. Tx hash: ${hash}`);
})
Expand Down
23 changes: 22 additions & 1 deletion price_pusher/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { readPriceConfigFile } from "./price-config";
import { PriceServiceConnection } from "@pythnetwork/pyth-common-js";
import { InjectivePriceListener, InjectivePricePusher } from "./injective";
import { ChainPricePusher, IPriceListener } from "./interface";
import { CustomGasStation } from "./custom-gas-station";

const argv = yargs(hideBin(process.argv))
.option("network", {
Expand Down Expand Up @@ -69,6 +70,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({
Expand Down Expand Up @@ -139,6 +152,7 @@ function getNetworkPriceListener(network: string): IPriceListener {
}

function getNetworkPricePusher(network: string): ChainPricePusher {
const gasStation = getCustomGasStation(argv.customGasStation, argv.txSpeed);
switch (network) {
case "evm": {
const pythContractFactory = new PythContractFactory(
Expand All @@ -148,7 +162,8 @@ function getNetworkPricePusher(network: string): ChainPricePusher {
);
return new EvmPricePusher(
priceServiceConnection,
pythContractFactory.createPythContractWithPayer()
pythContractFactory.createPythContractWithPayer(),
gasStation
);
}
case "injective":
Expand All @@ -163,6 +178,12 @@ function getNetworkPricePusher(network: string): ChainPricePusher {
}
}

function getCustomGasStation(customGasStation?: number, txSpeed?: string) {
if (customGasStation && txSpeed) {
return new CustomGasStation(customGasStation, txSpeed);
}
}

start({
sourcePriceListener: pythPriceListener,
targetPriceListener: getNetworkPriceListener(argv.network),
Expand Down
16 changes: 16 additions & 0 deletions price_pusher/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import { HexString } from "@pythnetwork/pyth-common-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<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
Expand Down Expand Up @@ -31,3 +35,15 @@ export function isWsEndpoint(endpoint: string): boolean {

return false;
}

export function verifyValidOption<
options extends Readonly<Array<any>>,
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);
}