@pythnetwork/price-pusher 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +13 -0
- package/README.md +141 -0
- package/lib/controller.d.ts +14 -0
- package/lib/controller.js +52 -0
- package/lib/evm/command.d.ts +19 -0
- package/lib/evm/command.js +99 -0
- package/lib/evm/custom-gas-station.d.ts +9 -0
- package/lib/evm/custom-gas-station.js +43 -0
- package/lib/evm/evm.d.ts +53 -0
- package/lib/evm/evm.js +265 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +16 -0
- package/lib/injective/command.d.ts +16 -0
- package/lib/injective/command.js +78 -0
- package/lib/injective/injective.d.ts +29 -0
- package/lib/injective/injective.js +167 -0
- package/lib/interface.d.ts +31 -0
- package/lib/interface.js +46 -0
- package/lib/options.d.ts +19 -0
- package/lib/options.js +50 -0
- package/lib/price-config.d.ts +18 -0
- package/lib/price-config.js +79 -0
- package/lib/pyth-price-listener.d.ts +12 -0
- package/lib/pyth-price-listener.js +49 -0
- package/lib/utils.d.ts +12 -0
- package/lib/utils.js +40 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright 2023 Pyth Contributors.
|
|
2
|
+
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
See the License for the specific language governing permissions and
|
|
13
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Pyth price pusher
|
|
2
|
+
|
|
3
|
+
Pyth price pusher is a service that regularly pushes updates to the on-chain Pyth price based on configurable conditions.
|
|
4
|
+
|
|
5
|
+
## Background
|
|
6
|
+
|
|
7
|
+
Pyth is a cross-chain oracle that streams price updates over the peer-to-peer [Wormhole Network](https://wormholenetwork.com/).
|
|
8
|
+
These price updates can be consumed on any chain that has a deployment of the Pyth contract.
|
|
9
|
+
By default, Pyth does not automatically update the on-chain price every time the off-chain price changes;
|
|
10
|
+
instead, anyone can permissionlessly update the on-chain price prior to using it.
|
|
11
|
+
For more information please refer to [this document](https://docs.pyth.network/design-overview).
|
|
12
|
+
|
|
13
|
+
Protocols integrating with can update the on-chain Pyth prices in two different ways.
|
|
14
|
+
The first approach is on-demand updates: package a Pyth price update together with each transaction that depends on it.
|
|
15
|
+
On-demand updates minimize latency and are more gas efficient, as prices are only updated on-chain when they are needed.
|
|
16
|
+
|
|
17
|
+
The second approach is to run this service to regularly push updates to the on-chain price.
|
|
18
|
+
This approach is useful for protocols that already depend on regular push updates.
|
|
19
|
+
|
|
20
|
+
## Running Price Pusher
|
|
21
|
+
|
|
22
|
+
The price pusher service monitors both the off-chain and on-chain Pyth price for a configured set of price feeds.
|
|
23
|
+
It then pushes a price update to an on-chain Pyth contract if any of the following conditions are met:
|
|
24
|
+
|
|
25
|
+
- Time difference: The on-chain price is older than `time_difference` seconds
|
|
26
|
+
from the latest Pyth price.
|
|
27
|
+
- Price deviation: The latest Pyth price feed has changed more than `price_deviation` percent
|
|
28
|
+
from the on-chain price feed price.
|
|
29
|
+
- Confidence ratio: The latest Pyth price feed has confidence to price ratio of more than
|
|
30
|
+
`confidence_ratio`.
|
|
31
|
+
|
|
32
|
+
The parameters above are configured per price feed in a price configuration YAML file. The structure looks like this:
|
|
33
|
+
|
|
34
|
+
```yaml
|
|
35
|
+
- alias: A/USD # Arbitrary alias for the price feed. It is used in enhance logging.
|
|
36
|
+
id: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef # id of a price feed, a 32-byte hex string.
|
|
37
|
+
time_difference: 60 # Time difference threshold (in seconds) to push a newer price feed.
|
|
38
|
+
price_deviation: 0.5 # The price deviation (%) threshold to push a newer price feed.
|
|
39
|
+
confidence_ratio: 1 # The confidence/price (%) threshold to push a newer price feed.
|
|
40
|
+
- ...
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
You can get the list of available price feeds from
|
|
44
|
+
[here](https://pyth.network/developers/price-feed-ids/).
|
|
45
|
+
|
|
46
|
+
To run the price pusher, please run the following commands, replacing the command line arguments as necessary:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
# Only run it the first time to build the code
|
|
50
|
+
npm install
|
|
51
|
+
npx lerna run build
|
|
52
|
+
|
|
53
|
+
# For EVM
|
|
54
|
+
npm run start -- evm --endpoint wss://example-rpc.com \
|
|
55
|
+
--pyth-contract-address 0xff1a0f4744e8582DF...... \
|
|
56
|
+
--price-service-endpoint https://example-pyth-price.com \
|
|
57
|
+
--price-config-file "path/to/price-config-file.yaml.testnet.sample.yaml" \
|
|
58
|
+
--mnemonic-file "path/to/mnemonic.txt" \
|
|
59
|
+
[--pushing-frequency 10] \
|
|
60
|
+
[--polling-frequency 5] \
|
|
61
|
+
[--override-gas-price-multiplier 1.1]
|
|
62
|
+
|
|
63
|
+
# For Injective
|
|
64
|
+
npm run start -- injective --grpc-endpoint https://grpc-endpoint.com \
|
|
65
|
+
--pyth-contract-address inj1z60tg0... --price-service-endpoint "https://example-pyth-price.com" \
|
|
66
|
+
--price-config-file "path/to/price-config-file.yaml.testnet.sample.yaml" \
|
|
67
|
+
--mnemonic-file "path/to/mnemonic.txt" \
|
|
68
|
+
[--pushing-frequency 10] \
|
|
69
|
+
[--polling-frequency 5] \
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# Or, run the price pusher docker image instead of building from the source
|
|
73
|
+
docker run public.ecr.aws/pyth-network/xc-price-pusher:v<version> -- <above-arguments>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Command Line Arguments
|
|
77
|
+
|
|
78
|
+
To know more about the arguments the price-pusher accepts. You can run:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
npm run start -- --help
|
|
82
|
+
|
|
83
|
+
# for specific network run
|
|
84
|
+
npm run start -- {network} --help
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Example
|
|
88
|
+
|
|
89
|
+
For example, to push `BTC/USD` and `BNB/USD` prices on Fantom testnet, run the following command:
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
npm run dev -- evm --endpoint https://endpoints.omniatech.io/v1/fantom/testnet/public \
|
|
93
|
+
--pyth-contract-address 0xff1a0f4744e8582DF1aE09D5611b887B6a12925C --price-service-endpoint https://xc-testnet.pyth.network \
|
|
94
|
+
--mnemonic-file "./mnemonic" --price-config-file "./price-config.testnet.sample.yaml"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
[`price-config.testnet.sample.yaml`](./price-config.testnet.sample.yaml) contains configuration for `BTC/USD`
|
|
98
|
+
and `BNB/USD` price feeds on Pyth testnet. [`price-config.mainnet.sample.yaml`](./price-config.mainnet.sample.yaml)
|
|
99
|
+
contains the same configuration for `BTC/USD` and `BNB/USD` on Pyth mainnet.
|
|
100
|
+
|
|
101
|
+
You can also provide a config file instead of providing command line options, run the following command:
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
npm run start -- injective --config "./config.injective.sample.json"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
[`config.injective.sample.json`](./config.injective.sample.json) contains configuration to publish on Injective testnet.
|
|
108
|
+
|
|
109
|
+
## Running using a standalone price service (via docker-compose)
|
|
110
|
+
|
|
111
|
+
Price pusher communicates with [Pyth price service][] to get the most recent price updates. Pyth price service listens to the
|
|
112
|
+
Wormhole network to get latest price updates, and serves REST and websocket APIs for consumers to fetch the updates.
|
|
113
|
+
Pyth hosts public endpoints for the price service; however, it is recommended to run it standalone to achieve more resiliency and
|
|
114
|
+
scalability.
|
|
115
|
+
|
|
116
|
+
This directory contains sample docker compose files ([testnet](./docker-compose.testnet.sample.yaml),
|
|
117
|
+
[mainnet](./docker-compose.mainnet.sample.yaml)) a price pusher and its dependencies, including a
|
|
118
|
+
price service and a Wormhole spy. A price service depends on a Wormhole spy. A spy listens to the Wormhole
|
|
119
|
+
network and reports all Pyth-related Wormhole messages to the price service.
|
|
120
|
+
|
|
121
|
+
To run the services via docker-compose, please modify the your target network (testnet, mainnet) sample docker-compose file to adjust the configurations.
|
|
122
|
+
|
|
123
|
+
Then, start the docker-compose like this:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
docker-compose -f docker-compose.testnet.sample.yaml up
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
It will take a few minutes until all the services are up and running.
|
|
130
|
+
|
|
131
|
+
[pyth price service]: https://github.com/pyth-network/pyth-crosschain/tree/main/price_service/server
|
|
132
|
+
|
|
133
|
+
## Reliability
|
|
134
|
+
|
|
135
|
+
You can run multiple instances of the price pusher to increase the reliability. It is better to use
|
|
136
|
+
difference RPCs to get better reliability in case an RPC goes down. **If you use the same payer account
|
|
137
|
+
in different pushers, then due to blockchains nonce or sequence for accounts, a transaction won't be
|
|
138
|
+
pushed twiced and you won't pay additional costs most of the time.** However, there might be some race
|
|
139
|
+
condiitons in the RPCs because they are often behind a load balancer than can sometimes cause rejected
|
|
140
|
+
transactions land on-chain. You can reduce the chances of additional cost overhead by reducing the
|
|
141
|
+
pushing frequency.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DurationInSeconds } from "./utils";
|
|
2
|
+
import { IPricePusher, IPriceListener } from "./interface";
|
|
3
|
+
import { PriceConfig } from "./price-config";
|
|
4
|
+
export declare class Controller {
|
|
5
|
+
private priceConfigs;
|
|
6
|
+
private sourcePriceListener;
|
|
7
|
+
private targetPriceListener;
|
|
8
|
+
private targetChainPricePusher;
|
|
9
|
+
private pushingFrequency;
|
|
10
|
+
constructor(priceConfigs: PriceConfig[], sourcePriceListener: IPriceListener, targetPriceListener: IPriceListener, targetChainPricePusher: IPricePusher, config: {
|
|
11
|
+
pushingFrequency: DurationInSeconds;
|
|
12
|
+
});
|
|
13
|
+
start(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Controller = void 0;
|
|
4
|
+
const utils_1 = require("./utils");
|
|
5
|
+
const price_config_1 = require("./price-config");
|
|
6
|
+
class Controller {
|
|
7
|
+
priceConfigs;
|
|
8
|
+
sourcePriceListener;
|
|
9
|
+
targetPriceListener;
|
|
10
|
+
targetChainPricePusher;
|
|
11
|
+
pushingFrequency;
|
|
12
|
+
constructor(priceConfigs, sourcePriceListener, targetPriceListener, targetChainPricePusher, config) {
|
|
13
|
+
this.priceConfigs = priceConfigs;
|
|
14
|
+
this.sourcePriceListener = sourcePriceListener;
|
|
15
|
+
this.targetPriceListener = targetPriceListener;
|
|
16
|
+
this.targetChainPricePusher = targetChainPricePusher;
|
|
17
|
+
this.pushingFrequency = config.pushingFrequency;
|
|
18
|
+
}
|
|
19
|
+
async start() {
|
|
20
|
+
// start the listeners
|
|
21
|
+
await this.sourcePriceListener.start();
|
|
22
|
+
await this.targetPriceListener.start();
|
|
23
|
+
// wait for the listeners to get updated. There could be a restart
|
|
24
|
+
// before this run and we need to respect the cooldown duration as
|
|
25
|
+
// their might be a message sent before.
|
|
26
|
+
await (0, utils_1.sleep)(this.pushingFrequency * 1000);
|
|
27
|
+
for (;;) {
|
|
28
|
+
const pricesToPush = [];
|
|
29
|
+
const pubTimesToPush = [];
|
|
30
|
+
for (const priceConfig of this.priceConfigs) {
|
|
31
|
+
const priceId = priceConfig.id;
|
|
32
|
+
const targetLatestPrice = this.targetPriceListener.getLatestPriceInfo(priceId);
|
|
33
|
+
const sourceLatestPrice = this.sourcePriceListener.getLatestPriceInfo(priceId);
|
|
34
|
+
if ((0, price_config_1.shouldUpdate)(priceConfig, sourceLatestPrice, targetLatestPrice)) {
|
|
35
|
+
pricesToPush.push(priceConfig);
|
|
36
|
+
pubTimesToPush.push((targetLatestPrice?.publishTime || 0) + 1);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (pricesToPush.length !== 0) {
|
|
40
|
+
console.log("Some of the above values passed the threshold. Will push the price.");
|
|
41
|
+
// note that the priceIds are without leading "0x"
|
|
42
|
+
const priceIds = pricesToPush.map((priceConfig) => priceConfig.id);
|
|
43
|
+
this.targetChainPricePusher.updatePriceFeed(priceIds, pubTimesToPush);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
console.log("None of the above values passed the threshold. No push needed.");
|
|
47
|
+
}
|
|
48
|
+
await (0, utils_1.sleep)(this.pushingFrequency * 1000);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.Controller = Controller;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Options } from "yargs";
|
|
2
|
+
declare const _default: {
|
|
3
|
+
command: string;
|
|
4
|
+
describe: string;
|
|
5
|
+
builder: {
|
|
6
|
+
"pushing-frequency": Options;
|
|
7
|
+
"polling-frequency": Options;
|
|
8
|
+
"pyth-contract-address": Options;
|
|
9
|
+
"mnemonic-file": Options;
|
|
10
|
+
"price-service-endpoint": Options;
|
|
11
|
+
"price-config-file": Options;
|
|
12
|
+
endpoint: Options;
|
|
13
|
+
"custom-gas-station": Options;
|
|
14
|
+
"tx-speed": Options;
|
|
15
|
+
"override-gas-price-multiplier": Options;
|
|
16
|
+
};
|
|
17
|
+
handler: (argv: any) => void;
|
|
18
|
+
};
|
|
19
|
+
export default _default;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
const price_service_client_1 = require("@pythnetwork/price-service-client");
|
|
30
|
+
const options = __importStar(require("../options"));
|
|
31
|
+
const price_config_1 = require("../price-config");
|
|
32
|
+
const fs_1 = __importDefault(require("fs"));
|
|
33
|
+
const pyth_price_listener_1 = require("../pyth-price-listener");
|
|
34
|
+
const controller_1 = require("../controller");
|
|
35
|
+
const evm_1 = require("./evm");
|
|
36
|
+
const custom_gas_station_1 = require("./custom-gas-station");
|
|
37
|
+
exports.default = {
|
|
38
|
+
command: "evm",
|
|
39
|
+
describe: "run price pusher for evm",
|
|
40
|
+
builder: {
|
|
41
|
+
endpoint: {
|
|
42
|
+
description: "RPC endpoint URL for evm network. If you provide a normal HTTP endpoint, the pusher " +
|
|
43
|
+
"will periodically poll for updates. The polling interval is configurable via the " +
|
|
44
|
+
"`polling-frequency` command-line argument. If you provide a websocket RPC " +
|
|
45
|
+
"endpoint (`ws[s]://...`), the price pusher will use event subscriptions to read " +
|
|
46
|
+
"the current EVM price in addition to polling. ",
|
|
47
|
+
type: "string",
|
|
48
|
+
required: true,
|
|
49
|
+
},
|
|
50
|
+
"custom-gas-station": {
|
|
51
|
+
description: "If using a custom gas station, chainId of custom gas station to use",
|
|
52
|
+
type: "number",
|
|
53
|
+
required: false,
|
|
54
|
+
},
|
|
55
|
+
"tx-speed": {
|
|
56
|
+
description: "txSpeed for custom gas station. choose between 'slow'|'standard'|'fast'",
|
|
57
|
+
choices: ["slow", "standard", "fast"],
|
|
58
|
+
required: false,
|
|
59
|
+
},
|
|
60
|
+
"override-gas-price-multiplier": {
|
|
61
|
+
description: "Multiply the gas price by this number if the transaction is not landing to override it. Default to 1.1",
|
|
62
|
+
type: "number",
|
|
63
|
+
required: false,
|
|
64
|
+
default: 1.1,
|
|
65
|
+
},
|
|
66
|
+
...options.priceConfigFile,
|
|
67
|
+
...options.priceServiceEndpoint,
|
|
68
|
+
...options.mnemonicFile,
|
|
69
|
+
...options.pythContractAddress,
|
|
70
|
+
...options.pollingFrequency,
|
|
71
|
+
...options.pushingFrequency,
|
|
72
|
+
},
|
|
73
|
+
handler: function (argv) {
|
|
74
|
+
// FIXME: type checks for this
|
|
75
|
+
const { endpoint, priceConfigFile, priceServiceEndpoint, mnemonicFile, pythContractAddress, pushingFrequency, pollingFrequency, customGasStation, txSpeed, overrideGasPriceMultiplier, } = argv;
|
|
76
|
+
const priceConfigs = (0, price_config_1.readPriceConfigFile)(priceConfigFile);
|
|
77
|
+
const priceServiceConnection = new price_service_client_1.PriceServiceConnection(priceServiceEndpoint, {
|
|
78
|
+
logger: {
|
|
79
|
+
// Log only warnings and errors from the price service client
|
|
80
|
+
info: () => undefined,
|
|
81
|
+
warn: console.warn,
|
|
82
|
+
error: console.error,
|
|
83
|
+
debug: () => undefined,
|
|
84
|
+
trace: () => undefined,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
const mnemonic = fs_1.default.readFileSync(mnemonicFile, "utf-8").trim();
|
|
88
|
+
const priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
|
|
89
|
+
const pythListener = new pyth_price_listener_1.PythPriceListener(priceServiceConnection, priceItems);
|
|
90
|
+
const pythContractFactory = new evm_1.PythContractFactory(endpoint, mnemonic, pythContractAddress);
|
|
91
|
+
const evmListener = new evm_1.EvmPriceListener(pythContractFactory, priceItems, {
|
|
92
|
+
pollingFrequency,
|
|
93
|
+
});
|
|
94
|
+
const gasStation = (0, custom_gas_station_1.getCustomGasStation)(customGasStation, txSpeed);
|
|
95
|
+
const evmPusher = new evm_1.EvmPricePusher(priceServiceConnection, pythContractFactory, overrideGasPriceMultiplier, gasStation);
|
|
96
|
+
const controller = new controller_1.Controller(priceConfigs, pythListener, evmListener, evmPusher, { pushingFrequency });
|
|
97
|
+
controller.start();
|
|
98
|
+
},
|
|
99
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare class CustomGasStation {
|
|
2
|
+
private chain;
|
|
3
|
+
private speed;
|
|
4
|
+
private chainMethods;
|
|
5
|
+
constructor(chain: number, speed: string);
|
|
6
|
+
getCustomGasPrice(): Promise<string | undefined>;
|
|
7
|
+
private fetchMaticMainnetGasPrice;
|
|
8
|
+
}
|
|
9
|
+
export declare function getCustomGasStation(customGasStation?: number, txSpeed?: string): CustomGasStation | undefined;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getCustomGasStation = exports.CustomGasStation = void 0;
|
|
7
|
+
const web3_1 = __importDefault(require("web3"));
|
|
8
|
+
const utils_1 = require("../utils");
|
|
9
|
+
class CustomGasStation {
|
|
10
|
+
chain;
|
|
11
|
+
speed;
|
|
12
|
+
chainMethods = {
|
|
13
|
+
137: this.fetchMaticMainnetGasPrice.bind(this),
|
|
14
|
+
};
|
|
15
|
+
constructor(chain, speed) {
|
|
16
|
+
this.speed = (0, utils_1.verifyValidOption)(speed, utils_1.txSpeeds);
|
|
17
|
+
this.chain = (0, utils_1.verifyValidOption)(chain, utils_1.customGasChainIds);
|
|
18
|
+
}
|
|
19
|
+
async getCustomGasPrice() {
|
|
20
|
+
return this.chainMethods[this.chain]();
|
|
21
|
+
}
|
|
22
|
+
async fetchMaticMainnetGasPrice() {
|
|
23
|
+
try {
|
|
24
|
+
const res = await fetch("https://gasstation-mainnet.matic.network/v2");
|
|
25
|
+
const jsonRes = await res.json();
|
|
26
|
+
const gasPrice = jsonRes[this.speed].maxFee;
|
|
27
|
+
const gweiGasPrice = web3_1.default.utils.toWei(gasPrice.toFixed(2), "Gwei");
|
|
28
|
+
return gweiGasPrice.toString();
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
console.error("Failed to fetch gas price from Matic mainnet. Returning undefined");
|
|
32
|
+
console.error(e);
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.CustomGasStation = CustomGasStation;
|
|
38
|
+
function getCustomGasStation(customGasStation, txSpeed) {
|
|
39
|
+
if (customGasStation && txSpeed) {
|
|
40
|
+
return new CustomGasStation(customGasStation, txSpeed);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.getCustomGasStation = getCustomGasStation;
|
package/lib/evm/evm.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Contract } from "web3-eth-contract";
|
|
2
|
+
import { IPricePusher, PriceInfo, ChainPriceListener, PriceItem } from "../interface";
|
|
3
|
+
import { DurationInSeconds } from "../utils";
|
|
4
|
+
import HDWalletProvider from "@truffle/hdwallet-provider";
|
|
5
|
+
import { PriceServiceConnection, HexString, UnixTimestamp } from "@pythnetwork/price-service-client";
|
|
6
|
+
import { CustomGasStation } from "./custom-gas-station";
|
|
7
|
+
export declare class EvmPriceListener extends ChainPriceListener {
|
|
8
|
+
private pythContractFactory;
|
|
9
|
+
private pythContract;
|
|
10
|
+
constructor(pythContractFactory: PythContractFactory, priceItems: PriceItem[], config: {
|
|
11
|
+
pollingFrequency: DurationInSeconds;
|
|
12
|
+
});
|
|
13
|
+
start(): Promise<void>;
|
|
14
|
+
private startSubscription;
|
|
15
|
+
private onPriceFeedUpdate;
|
|
16
|
+
getOnChainPriceInfo(priceId: HexString): Promise<PriceInfo | undefined>;
|
|
17
|
+
}
|
|
18
|
+
export declare class EvmPricePusher implements IPricePusher {
|
|
19
|
+
private connection;
|
|
20
|
+
private overrideGasPriceMultiplier;
|
|
21
|
+
private customGasStation?;
|
|
22
|
+
private pythContract;
|
|
23
|
+
private web3;
|
|
24
|
+
private pusherAddress;
|
|
25
|
+
private lastPushAttempt;
|
|
26
|
+
constructor(connection: PriceServiceConnection, pythContractFactory: PythContractFactory, overrideGasPriceMultiplier: number, customGasStation?: CustomGasStation);
|
|
27
|
+
updatePriceFeed(priceIds: string[], pubTimesToPush: UnixTimestamp[]): Promise<void>;
|
|
28
|
+
private getPriceFeedsUpdateData;
|
|
29
|
+
}
|
|
30
|
+
export declare class PythContractFactory {
|
|
31
|
+
private endpoint;
|
|
32
|
+
private mnemonic;
|
|
33
|
+
private pythContractAddress;
|
|
34
|
+
constructor(endpoint: string, mnemonic: string, pythContractAddress: string);
|
|
35
|
+
/**
|
|
36
|
+
* This method creates a web3 Pyth contract with payer (based on HDWalletProvider). As this
|
|
37
|
+
* provider is an HDWalletProvider it does not support subscriptions even if the
|
|
38
|
+
* endpoint is a websocket endpoint.
|
|
39
|
+
*
|
|
40
|
+
* @returns Pyth contract
|
|
41
|
+
*/
|
|
42
|
+
createPythContractWithPayer(): Contract;
|
|
43
|
+
/**
|
|
44
|
+
* This method creates a web3 Pyth contract with the given endpoint as its provider. If
|
|
45
|
+
* the endpoint is a websocket endpoint the contract will support subscriptions.
|
|
46
|
+
*
|
|
47
|
+
* @returns Pyth contract
|
|
48
|
+
*/
|
|
49
|
+
createPythContract(): Contract;
|
|
50
|
+
hasWebsocketProvider(): boolean;
|
|
51
|
+
createWeb3Provider(): import("web3-core").HttpProvider | import("web3-core").WebsocketProvider;
|
|
52
|
+
createWeb3PayerProvider(): HDWalletProvider;
|
|
53
|
+
}
|