Skip to content

Commit 3d8215e

Browse files
authored
[price-pusher] Add nonce for evm + refactor (#679)
* [price-pusher] Add nonce for evm + refactor * Rename cooldown-duration to pushing-frequency * Update readme
1 parent 5aa38d2 commit 3d8215e

12 files changed

+177
-48
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ bigtable-writer.json
1515
.aptos
1616
tsconfig.tsbuildinfo
1717
*~
18+
*mnemonic*

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

price_pusher/README.md

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,18 @@ npm run start -- evm --endpoint wss://example-rpc.com \
5454
--price-service-endpoint https://example-pyth-price.com \
5555
--price-config-file "path/to/price-config-file.yaml.testnet.sample.yaml" \
5656
--mnemonic-file "path/to/mnemonic.txt" \
57-
[--cooldown-duration 10] \
58-
[--polling-frequency 5]
57+
[--pushing-frequency 10] \
58+
[--polling-frequency 5] \
59+
[--override-gas-price-multiplier 1.1]
5960

6061
# For Injective
6162
npm run start -- injective --grpc-endpoint https://grpc-endpoint.com \
6263
--pyth-contract-address inj1z60tg0... --price-service-endpoint "https://example-pyth-price.com" \
6364
--price-config-file "path/to/price-config-file.yaml.testnet.sample.yaml" \
6465
--mnemonic-file "path/to/mnemonic.txt" \
65-
[--cooldown-duration 10] \
66-
[--polling-frequency 5]
66+
[--pushing-frequency 10] \
67+
[--polling-frequency 5] \
68+
6769

6870
# Or, run the price pusher docker image instead of building from the source
6971
docker run public.ecr.aws/pyth-network/xc-price-pusher:v<version> -- <above-arguments>
@@ -82,11 +84,11 @@ npm run start -- {network} --help
8284

8385
### Example
8486

85-
For example, to push `BTC/USD` and `BNB/USD` prices on BNB testnet, run the following command:
87+
For example, to push `BTC/USD` and `BNB/USD` prices on Fantom testnet, run the following command:
8688

8789
```sh
8890
npm run dev -- evm --endpoint https://endpoints.omniatech.io/v1/fantom/testnet/public \
89-
--pyth-contract-address 0xd7308b14BF4008e7C7196eC35610B1427C5702EA --price-service-endpoint https://xc-testnet.pyth.network \
91+
--pyth-contract-address 0xff1a0f4744e8582DF1aE09D5611b887B6a12925C --price-service-endpoint https://xc-testnet.pyth.network \
9092
--mnemonic-file "./mnemonic" --price-config-file "./price-config.testnet.sample.yaml"
9193
```
9294

@@ -125,3 +127,13 @@ docker-compose -f docker-compose.testnet.sample.yaml up
125127
It will take a few minutes until all the services are up and running.
126128

127129
[pyth price service]: https://github.com/pyth-network/pyth-crosschain/tree/main/price_service/server
130+
131+
## Reliability
132+
133+
You can run multiple instances of the price pusher to increase the reliability. It is better to use
134+
difference RPCs to get better reliability in case an RPC goes down. **If you use the same payer account
135+
in different pushers, then due to blockchains nonce or sequence for accounts, a transaction won't be
136+
pushed twiced and you won't pay additional costs most of the time.** However, there might be some race
137+
condiitons in the RPCs because they are often behind a load balancer than can sometimes cause rejected
138+
transactions land on-chain. You can reduce the chances of additional cost overhead by reducing the
139+
pushing frequency.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"endpoint": "https://endpoints.omniatech.io/v1/fantom/testnet/public",
3+
"pyth-contract-address": "0xff1a0f4744e8582DF1aE09D5611b887B6a12925CZ",
4+
"price-service-endpoint": "https://xc-testnet.pyth.network",
5+
"mnemonic-file": "./mnemonic",
6+
"price-config-file": "./price-config.testnet.sample.yaml"
7+
}

price_pusher/docker-compose.testnet.sample.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,17 @@ services:
6565
- "/command_config"
6666
configs:
6767
- command_config
68+
- mnemonic
69+
- price_config
6870
depends_on:
6971
price-service:
7072
condition: service_healthy
7173
configs:
7274
command_config:
73-
file: ./config.injective.testnet.sample.json # Replace this with the path to the configuration file
75+
# Replace this with the path to the configuration file. You need to update the paths defined in
76+
# the config file
77+
file: ./config.injective.testnet.sample.json
78+
mnemonic:
79+
file: ./mnemonic # Replace this with the path to the mnemonic file
80+
price_config:
81+
file: ./price-config.testnet.sample.yaml # Replace this with the path to the price configuration file

price_pusher/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pythnetwork/pyth-price-pusher",
3-
"version": "3.0.0",
3+
"version": "4.0.0",
44
"description": "Pyth Price Pusher",
55
"homepage": "https://pyth.network",
66
"main": "lib/index.js",

price_pusher/src/controller.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ import { IPricePusher, IPriceListener } from "./interface";
44
import { PriceConfig, shouldUpdate } from "./price-config";
55

66
export class Controller {
7-
private cooldownDuration: DurationInSeconds;
7+
private pushingFrequency: DurationInSeconds;
88
constructor(
99
private priceConfigs: PriceConfig[],
1010
private sourcePriceListener: IPriceListener,
1111
private targetPriceListener: IPriceListener,
1212
private targetChainPricePusher: IPricePusher,
1313
config: {
14-
cooldownDuration: DurationInSeconds;
14+
pushingFrequency: DurationInSeconds;
1515
}
1616
) {
17-
this.cooldownDuration = config.cooldownDuration;
17+
this.pushingFrequency = config.pushingFrequency;
1818
}
1919

2020
async start() {
@@ -25,7 +25,7 @@ export class Controller {
2525
// wait for the listeners to get updated. There could be a restart
2626
// before this run and we need to respect the cooldown duration as
2727
// their might be a message sent before.
28-
await sleep(this.cooldownDuration * 1000);
28+
await sleep(this.pushingFrequency * 1000);
2929

3030
for (;;) {
3131
const pricesToPush: PriceConfig[] = [];
@@ -58,7 +58,7 @@ export class Controller {
5858
);
5959
}
6060

61-
await sleep(this.cooldownDuration * 1000);
61+
await sleep(this.pushingFrequency * 1000);
6262
}
6363
}
6464
}

price_pusher/src/evm/command.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,19 @@ export default {
3434
choices: ["slow", "standard", "fast"],
3535
required: false,
3636
} as Options,
37+
"override-gas-price-multiplier": {
38+
description:
39+
"Multiply the gas price by this number if the transaction is not landing to override it. Default to 1.1",
40+
type: "number",
41+
required: false,
42+
default: 1.1,
43+
} as Options,
3744
...options.priceConfigFile,
3845
...options.priceServiceEndpoint,
3946
...options.mnemonicFile,
4047
...options.pythContractAddress,
4148
...options.pollingFrequency,
42-
...options.cooldownDuration,
49+
...options.pushingFrequency,
4350
},
4451
handler: function (argv: any) {
4552
// FIXME: type checks for this
@@ -49,17 +56,25 @@ export default {
4956
priceServiceEndpoint,
5057
mnemonicFile,
5158
pythContractAddress,
52-
cooldownDuration,
59+
pushingFrequency,
5360
pollingFrequency,
5461
customGasStation,
5562
txSpeed,
63+
overrideGasPriceMultiplier,
5664
} = argv;
5765

5866
const priceConfigs = readPriceConfigFile(priceConfigFile);
5967
const priceServiceConnection = new PriceServiceConnection(
6068
priceServiceEndpoint,
6169
{
62-
logger: console,
70+
logger: {
71+
// Log only warnings and errors from the price service client
72+
info: () => undefined,
73+
warn: console.warn,
74+
error: console.error,
75+
debug: () => undefined,
76+
trace: () => undefined,
77+
},
6378
}
6479
);
6580
const mnemonic = fs.readFileSync(mnemonicFile, "utf-8").trim();
@@ -84,7 +99,8 @@ export default {
8499
const gasStation = getCustomGasStation(customGasStation, txSpeed);
85100
const evmPusher = new EvmPricePusher(
86101
priceServiceConnection,
87-
pythContractFactory.createPythContractWithPayer(),
102+
pythContractFactory,
103+
overrideGasPriceMultiplier,
88104
gasStation
89105
);
90106

@@ -93,7 +109,7 @@ export default {
93109
pythListener,
94110
evmListener,
95111
evmPusher,
96-
{ cooldownDuration }
112+
{ pushingFrequency }
97113
);
98114

99115
controller.start();

price_pusher/src/evm/custom-gas-station.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
customGasChainIds,
88
} from "../utils";
99

10-
type chainMethods = Record<CustomGasChainId, () => Promise<string>>;
10+
type chainMethods = Record<CustomGasChainId, () => Promise<string | undefined>>;
1111

1212
export class CustomGasStation {
1313
private chain: CustomGasChainId;
@@ -25,11 +25,19 @@ export class CustomGasStation {
2525
}
2626

2727
private async fetchMaticMainnetGasPrice() {
28-
const res = await fetch("https://gasstation-mainnet.matic.network/v2");
29-
const jsonRes = await res.json();
30-
const gasPrice = jsonRes[this.speed].maxFee;
31-
const gweiGasPrice = Web3.utils.toWei(gasPrice.toFixed(2), "Gwei");
32-
return gweiGasPrice.toString();
28+
try {
29+
const res = await fetch("https://gasstation-mainnet.matic.network/v2");
30+
const jsonRes = await res.json();
31+
const gasPrice = jsonRes[this.speed].maxFee;
32+
const gweiGasPrice = Web3.utils.toWei(gasPrice.toFixed(2), "Gwei");
33+
return gweiGasPrice.toString();
34+
} catch (e) {
35+
console.error(
36+
"Failed to fetch gas price from Matic mainnet. Returning undefined"
37+
);
38+
console.error(e);
39+
return undefined;
40+
}
3341
}
3442
}
3543

0 commit comments

Comments
 (0)