@pythnetwork/price-pusher 4.1.2 → 5.4.2
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/README.md +36 -2
- package/lib/aptos/aptos.d.ts +31 -0
- package/lib/aptos/aptos.d.ts.map +1 -0
- package/lib/aptos/aptos.js +139 -0
- package/lib/aptos/command.d.ts +18 -0
- package/lib/aptos/command.d.ts.map +1 -0
- package/lib/aptos/command.js +82 -0
- package/lib/common.d.ts +5 -0
- package/lib/common.d.ts.map +1 -0
- package/lib/common.js +2 -0
- package/lib/controller.d.ts +2 -1
- package/lib/controller.d.ts.map +1 -0
- package/lib/controller.js +10 -2
- package/lib/evm/command.d.ts +1 -0
- package/lib/evm/command.d.ts.map +1 -0
- package/lib/evm/command.js +3 -0
- package/lib/evm/custom-gas-station.d.ts +1 -0
- package/lib/evm/custom-gas-station.d.ts.map +1 -0
- package/lib/evm/evm.d.ts +1 -0
- package/lib/evm/evm.d.ts.map +1 -0
- package/lib/evm/evm.js +9 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +4 -0
- package/lib/injective/command.d.ts +2 -0
- package/lib/injective/command.d.ts.map +1 -0
- package/lib/injective/command.js +13 -2
- package/lib/injective/injective.d.ts +2 -0
- package/lib/injective/injective.d.ts.map +1 -0
- package/lib/injective/injective.js +35 -34
- package/lib/interface.d.ts +1 -0
- package/lib/interface.d.ts.map +1 -0
- package/lib/options.d.ts +1 -0
- package/lib/options.d.ts.map +1 -0
- package/lib/price-config.d.ts +10 -1
- package/lib/price-config.d.ts.map +1 -0
- package/lib/price-config.js +39 -10
- package/lib/pyth-price-listener.d.ts +1 -0
- package/lib/pyth-price-listener.d.ts.map +1 -0
- package/lib/sui/command.d.ts +24 -0
- package/lib/sui/command.d.ts.map +1 -0
- package/lib/sui/command.js +132 -0
- package/lib/sui/sui.d.ts +42 -0
- package/lib/sui/sui.d.ts.map +1 -0
- package/lib/sui/sui.js +358 -0
- package/lib/utils.d.ts +1 -0
- package/lib/utils.d.ts.map +1 -0
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -37,9 +37,20 @@ The parameters above are configured per price feed in a price configuration YAML
|
|
|
37
37
|
time_difference: 60 # Time difference threshold (in seconds) to push a newer price feed.
|
|
38
38
|
price_deviation: 0.5 # The price deviation (%) threshold to push a newer price feed.
|
|
39
39
|
confidence_ratio: 1 # The confidence/price (%) threshold to push a newer price feed.
|
|
40
|
+
# Optional block to configure whether this feed can be early updated. If at least one feed meets the
|
|
41
|
+
# triggering conditions above, all other feeds who meet the early update conditions will be included in
|
|
42
|
+
# the submitted batch of prices. This logic takes advantage of the fact that adding a feed to a larger
|
|
43
|
+
# batch of updates incurs a minimal gas cost. All fields below are optional (and interpreted as infinity if omitted)
|
|
44
|
+
# and have the same semantics as the corresponding fields above.
|
|
45
|
+
early_update:
|
|
46
|
+
time_difference: 30
|
|
47
|
+
price_deviation: 0.1
|
|
48
|
+
confidence_ratio: 0.5
|
|
40
49
|
- ...
|
|
41
50
|
```
|
|
42
51
|
|
|
52
|
+
Two sample YAML configuration files are available in the root of this repo.
|
|
53
|
+
|
|
43
54
|
You can get the list of available price feeds from
|
|
44
55
|
[here](https://pyth.network/developers/price-feed-ids/).
|
|
45
56
|
|
|
@@ -57,7 +68,7 @@ cd price_pusher
|
|
|
57
68
|
npm run start -- evm --endpoint wss://example-rpc.com \
|
|
58
69
|
--pyth-contract-address 0xff1a0f4744e8582DF...... \
|
|
59
70
|
--price-service-endpoint https://example-pyth-price.com \
|
|
60
|
-
--price-config-file "path/to/price-config
|
|
71
|
+
--price-config-file "path/to/price-config.testnet.sample.yaml" \
|
|
61
72
|
--mnemonic-file "path/to/mnemonic.txt" \
|
|
62
73
|
[--pushing-frequency 10] \
|
|
63
74
|
[--polling-frequency 5] \
|
|
@@ -66,11 +77,34 @@ npm run start -- evm --endpoint wss://example-rpc.com \
|
|
|
66
77
|
# For Injective
|
|
67
78
|
npm run start -- injective --grpc-endpoint https://grpc-endpoint.com \
|
|
68
79
|
--pyth-contract-address inj1z60tg0... --price-service-endpoint "https://example-pyth-price.com" \
|
|
69
|
-
--price-config-file "path/to/price-config
|
|
80
|
+
--price-config-file "path/to/price-config.testnet.sample.yaml" \
|
|
81
|
+
--mnemonic-file "path/to/mnemonic.txt" \
|
|
82
|
+
[--pushing-frequency 10] \
|
|
83
|
+
[--polling-frequency 5] \
|
|
84
|
+
|
|
85
|
+
# For Aptos
|
|
86
|
+
npm run start -- aptos --endpoint https://fullnode.testnet.aptoslabs.com/v1 \
|
|
87
|
+
--pyth-contract-address 0x7e783b349d3e89cf5931af376ebeadbfab855b3fa239b7ada8f5a92fbea6b387 --price-service-endpoint "https://xc-testnet.pyth.network" \
|
|
88
|
+
--price-config-file "./price-config.testnet.sample.yaml" \
|
|
70
89
|
--mnemonic-file "path/to/mnemonic.txt" \
|
|
71
90
|
[--pushing-frequency 10] \
|
|
72
91
|
[--polling-frequency 5] \
|
|
73
92
|
|
|
93
|
+
# For Sui
|
|
94
|
+
npm run start -- sui \
|
|
95
|
+
--endpoint https://sui-testnet-rpc.allthatnode.com \
|
|
96
|
+
--pyth-package-id 0x975e063f398f720af4f33ec06a927f14ea76ca24f7f8dd544aa62ab9d5d15f44 \
|
|
97
|
+
--pyth-state-id 0xd8afde3a48b4ff7212bd6829a150f43f59043221200d63504d981f62bff2e27a \
|
|
98
|
+
--wormhole-package-id 0xcc029e2810f17f9f43f52262f40026a71fbdca40ed3803ad2884994361910b7e \
|
|
99
|
+
--wormhole-state-id 0xebba4cc4d614f7a7cdbe883acc76d1cc767922bc96778e7b68be0d15fce27c02 \
|
|
100
|
+
--price-feed-to-price-info-object-table-id 0xf8929174008c662266a1adde78e1e8e33016eb7ad37d379481e860b911e40ed5 \
|
|
101
|
+
--price-service-endpoint https://xc-testnet.pyth.network \
|
|
102
|
+
--mnemonic-file ./mnemonic \
|
|
103
|
+
--price-config-file ./price-config.testnet.sample.yaml \
|
|
104
|
+
[--pushing-frequency 10] \
|
|
105
|
+
[--polling-frequency 5] \
|
|
106
|
+
[--num-gas-objects 30]
|
|
107
|
+
|
|
74
108
|
|
|
75
109
|
# Or, run the price pusher docker image instead of building from the source
|
|
76
110
|
docker run public.ecr.aws/pyth-network/xc-price-pusher:v<version> -- <above-arguments>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ChainPriceListener, IPricePusher, PriceInfo, PriceItem } from "../interface";
|
|
2
|
+
import { DurationInSeconds } from "../utils";
|
|
3
|
+
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
|
|
4
|
+
export declare class AptosPriceListener extends ChainPriceListener {
|
|
5
|
+
private pythModule;
|
|
6
|
+
private endpoint;
|
|
7
|
+
constructor(pythModule: string, endpoint: string, priceItems: PriceItem[], config: {
|
|
8
|
+
pollingFrequency: DurationInSeconds;
|
|
9
|
+
});
|
|
10
|
+
getOnChainPriceInfo(priceId: string): Promise<PriceInfo | undefined>;
|
|
11
|
+
}
|
|
12
|
+
export declare class AptosPricePusher implements IPricePusher {
|
|
13
|
+
private priceServiceConnection;
|
|
14
|
+
private pythContractAddress;
|
|
15
|
+
private endpoint;
|
|
16
|
+
private mnemonic;
|
|
17
|
+
private overrideGasPriceMultiplier;
|
|
18
|
+
private lastPushAttempt;
|
|
19
|
+
private readonly accountHDPath;
|
|
20
|
+
constructor(priceServiceConnection: PriceServiceConnection, pythContractAddress: string, endpoint: string, mnemonic: string, overrideGasPriceMultiplier: number);
|
|
21
|
+
/**
|
|
22
|
+
* Gets price update data which then can be submitted to the Pyth contract to update the prices.
|
|
23
|
+
* This will throw an axios error if there is a network problem or the price service returns a non-ok response (e.g: Invalid price ids)
|
|
24
|
+
*
|
|
25
|
+
* @param priceIds Array of hex-encoded price ids.
|
|
26
|
+
* @returns Array of price update data.
|
|
27
|
+
*/
|
|
28
|
+
getPriceFeedsUpdateData(priceIds: string[]): Promise<number[][]>;
|
|
29
|
+
updatePriceFeed(priceIds: string[], pubTimesToPush: number[]): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=aptos.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aptos.d.ts","sourceRoot":"","sources":["../../src/aptos/aptos.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,SAAS,EACV,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAG3E,qBAAa,kBAAmB,SAAQ,kBAAkB;IAEtD,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,QAAQ;gBADR,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EACxB,UAAU,EAAE,SAAS,EAAE,EACvB,MAAM,EAAE;QACN,gBAAgB,EAAE,iBAAiB,CAAC;KACrC;IAKG,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CA6C3E;AAED,qBAAa,gBAAiB,YAAW,YAAY;IAKjD,OAAO,CAAC,sBAAsB;IAC9B,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,0BAA0B;IARpC,OAAO,CAAC,eAAe,CAA0B;IAEjD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAyB;gBAE7C,sBAAsB,EAAE,sBAAsB,EAC9C,mBAAmB,EAAE,MAAM,EAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,0BAA0B,EAAE,MAAM;IAG5C;;;;;;OAMG;IACG,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;IAQhE,eAAe,CACnB,QAAQ,EAAE,MAAM,EAAE,EAClB,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,IAAI,CAAC;CAyFjB"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AptosPricePusher = exports.AptosPriceListener = void 0;
|
|
4
|
+
const interface_1 = require("../interface");
|
|
5
|
+
const aptos_1 = require("aptos");
|
|
6
|
+
class AptosPriceListener extends interface_1.ChainPriceListener {
|
|
7
|
+
pythModule;
|
|
8
|
+
endpoint;
|
|
9
|
+
constructor(pythModule, endpoint, priceItems, config) {
|
|
10
|
+
super("aptos", config.pollingFrequency, priceItems);
|
|
11
|
+
this.pythModule = pythModule;
|
|
12
|
+
this.endpoint = endpoint;
|
|
13
|
+
}
|
|
14
|
+
async getOnChainPriceInfo(priceId) {
|
|
15
|
+
try {
|
|
16
|
+
const client = new aptos_1.AptosClient(this.endpoint);
|
|
17
|
+
const res = await client.getAccountResource(this.pythModule, `${this.pythModule}::state::LatestPriceInfo`);
|
|
18
|
+
// This depends upon the pyth contract storage on Aptos and should not be undefined.
|
|
19
|
+
// If undefined, there has been some change and we would need to update accordingly.
|
|
20
|
+
const handle = res.data.info.handle;
|
|
21
|
+
const priceItemRes = await client.getTableItem(handle, {
|
|
22
|
+
key_type: `${this.pythModule}::price_identifier::PriceIdentifier`,
|
|
23
|
+
value_type: `${this.pythModule}::price_info::PriceInfo`,
|
|
24
|
+
key: {
|
|
25
|
+
bytes: priceId,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
const multiplier = priceItemRes.price_feed.price.price.negative === true ? -1 : 1;
|
|
29
|
+
const price = multiplier * Number(priceItemRes.price_feed.price.price.magnitude);
|
|
30
|
+
console.log(`Polled an Aptos on-chain price for feed ${this.priceIdToAlias.get(priceId)} (${priceId}).`);
|
|
31
|
+
return {
|
|
32
|
+
price: price.toString(),
|
|
33
|
+
conf: priceItemRes.price_feed.price.conf,
|
|
34
|
+
publishTime: Number(priceItemRes.price_feed.price.timestamp),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
console.error(`Polling Aptos on-chain price for ${priceId} failed. Error:`);
|
|
39
|
+
console.error(e);
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.AptosPriceListener = AptosPriceListener;
|
|
45
|
+
class AptosPricePusher {
|
|
46
|
+
priceServiceConnection;
|
|
47
|
+
pythContractAddress;
|
|
48
|
+
endpoint;
|
|
49
|
+
mnemonic;
|
|
50
|
+
overrideGasPriceMultiplier;
|
|
51
|
+
lastPushAttempt;
|
|
52
|
+
accountHDPath = "m/44'/637'/0'/0'/0'";
|
|
53
|
+
constructor(priceServiceConnection, pythContractAddress, endpoint, mnemonic, overrideGasPriceMultiplier) {
|
|
54
|
+
this.priceServiceConnection = priceServiceConnection;
|
|
55
|
+
this.pythContractAddress = pythContractAddress;
|
|
56
|
+
this.endpoint = endpoint;
|
|
57
|
+
this.mnemonic = mnemonic;
|
|
58
|
+
this.overrideGasPriceMultiplier = overrideGasPriceMultiplier;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Gets price update data which then can be submitted to the Pyth contract to update the prices.
|
|
62
|
+
* This will throw an axios error if there is a network problem or the price service returns a non-ok response (e.g: Invalid price ids)
|
|
63
|
+
*
|
|
64
|
+
* @param priceIds Array of hex-encoded price ids.
|
|
65
|
+
* @returns Array of price update data.
|
|
66
|
+
*/
|
|
67
|
+
async getPriceFeedsUpdateData(priceIds) {
|
|
68
|
+
// Fetch the latest price feed update VAAs from the price service
|
|
69
|
+
const latestVaas = await this.priceServiceConnection.getLatestVaas(priceIds);
|
|
70
|
+
return latestVaas.map((vaa) => Array.from(Buffer.from(vaa, "base64")));
|
|
71
|
+
}
|
|
72
|
+
async updatePriceFeed(priceIds, pubTimesToPush) {
|
|
73
|
+
if (priceIds.length === 0) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (priceIds.length !== pubTimesToPush.length)
|
|
77
|
+
throw new Error("Invalid arguments");
|
|
78
|
+
let priceFeedUpdateData;
|
|
79
|
+
try {
|
|
80
|
+
// get the latest VAAs for updatePriceFeed and then push them
|
|
81
|
+
priceFeedUpdateData = await this.getPriceFeedsUpdateData(priceIds);
|
|
82
|
+
}
|
|
83
|
+
catch (e) {
|
|
84
|
+
console.error("Error fetching the latest vaas to push");
|
|
85
|
+
console.error(e);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const account = aptos_1.AptosAccount.fromDerivePath(this.accountHDPath, this.mnemonic);
|
|
90
|
+
const client = new aptos_1.AptosClient(this.endpoint);
|
|
91
|
+
const rawTx = await client.generateTransaction(account.address(), {
|
|
92
|
+
function: `${this.pythContractAddress}::pyth::update_price_feeds_if_fresh_with_funder`,
|
|
93
|
+
type_arguments: [],
|
|
94
|
+
arguments: [
|
|
95
|
+
priceFeedUpdateData,
|
|
96
|
+
priceIds.map((priceId) => Buffer.from(priceId, "hex")),
|
|
97
|
+
pubTimesToPush,
|
|
98
|
+
],
|
|
99
|
+
});
|
|
100
|
+
const simulation = await client.simulateTransaction(account, rawTx, {
|
|
101
|
+
estimateGasUnitPrice: true,
|
|
102
|
+
estimateMaxGasAmount: true,
|
|
103
|
+
estimatePrioritizedGasUnitPrice: true,
|
|
104
|
+
});
|
|
105
|
+
// Transactions on Aptos can be prioritized by paying a higher gas unit price.
|
|
106
|
+
// We are storing the gas unit price paid for the last transaction.
|
|
107
|
+
// If that transaction is not added to the block, we are increasing the gas unit price
|
|
108
|
+
// by multiplying the old gas unit price with `this.overrideGasPriceMultiplier`.
|
|
109
|
+
// After which we are sending a transaction with the same sequence number as the last
|
|
110
|
+
// transaction. Since they have the same sequence number only one of them will be added to
|
|
111
|
+
// the block and we won't be paying fees twice.
|
|
112
|
+
let gasUnitPrice = Number(simulation[0].gas_unit_price);
|
|
113
|
+
if (this.lastPushAttempt !== undefined &&
|
|
114
|
+
Number(simulation[0].sequence_number) === this.lastPushAttempt.nonce) {
|
|
115
|
+
const newGasUnitPrice = Number(this.lastPushAttempt.gasPrice * this.overrideGasPriceMultiplier);
|
|
116
|
+
if (gasUnitPrice < newGasUnitPrice)
|
|
117
|
+
gasUnitPrice = newGasUnitPrice;
|
|
118
|
+
}
|
|
119
|
+
const gasUsed = Number(simulation[0].gas_used) * 1.5;
|
|
120
|
+
const maxGasAmount = Number(gasUnitPrice * gasUsed);
|
|
121
|
+
const rawTxWithFee = new aptos_1.TxnBuilderTypes.RawTransaction(rawTx.sender, rawTx.sequence_number, rawTx.payload, BigInt(maxGasAmount.toFixed()), BigInt(gasUnitPrice.toFixed()), rawTx.expiration_timestamp_secs, rawTx.chain_id);
|
|
122
|
+
const signedTx = await client.signTransaction(account, rawTxWithFee);
|
|
123
|
+
const pendingTx = await client.submitTransaction(signedTx);
|
|
124
|
+
console.log("Succesfully broadcasted txHash:", pendingTx.hash);
|
|
125
|
+
// Update lastAttempt
|
|
126
|
+
this.lastPushAttempt = {
|
|
127
|
+
nonce: Number(pendingTx.sequence_number),
|
|
128
|
+
gasPrice: gasUnitPrice,
|
|
129
|
+
};
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
console.error("Error executing messages");
|
|
134
|
+
console.log(e);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
exports.AptosPricePusher = AptosPricePusher;
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
+
"override-gas-price-multiplier": Options;
|
|
14
|
+
};
|
|
15
|
+
handler: (argv: any) => void;
|
|
16
|
+
};
|
|
17
|
+
export default _default;
|
|
18
|
+
//# sourceMappingURL=command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/aptos/command.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;;;;;;;;;;;;;;oBA6BL,GAAG;;AA1B9B,wBAsFE"}
|
|
@@ -0,0 +1,82 @@
|
|
|
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 aptos_1 = require("./aptos");
|
|
36
|
+
exports.default = {
|
|
37
|
+
command: "aptos",
|
|
38
|
+
describe: "run price pusher for aptos",
|
|
39
|
+
builder: {
|
|
40
|
+
endpoint: {
|
|
41
|
+
description: "RPC endpoint endpoint URL for aptos. The pusher will periodically" +
|
|
42
|
+
"poll for updates. The polling interval is configurable via the " +
|
|
43
|
+
"`polling-frequency` command-line argument.",
|
|
44
|
+
type: "string",
|
|
45
|
+
required: true,
|
|
46
|
+
},
|
|
47
|
+
"override-gas-price-multiplier": {
|
|
48
|
+
description: "Multiply the gas price by this number if the transaction is not landing to override it. Default 2",
|
|
49
|
+
type: "number",
|
|
50
|
+
required: false,
|
|
51
|
+
default: 2,
|
|
52
|
+
},
|
|
53
|
+
...options.priceConfigFile,
|
|
54
|
+
...options.priceServiceEndpoint,
|
|
55
|
+
...options.mnemonicFile,
|
|
56
|
+
...options.pythContractAddress,
|
|
57
|
+
...options.pollingFrequency,
|
|
58
|
+
...options.pushingFrequency,
|
|
59
|
+
},
|
|
60
|
+
handler: function (argv) {
|
|
61
|
+
// FIXME: type checks for this
|
|
62
|
+
const { endpoint, priceConfigFile, priceServiceEndpoint, mnemonicFile, pythContractAddress, pushingFrequency, pollingFrequency, overrideGasPriceMultiplier, } = argv;
|
|
63
|
+
const priceConfigs = (0, price_config_1.readPriceConfigFile)(priceConfigFile);
|
|
64
|
+
const priceServiceConnection = new price_service_client_1.PriceServiceConnection(priceServiceEndpoint, {
|
|
65
|
+
logger: {
|
|
66
|
+
// Log only warnings and errors from the price service client
|
|
67
|
+
info: () => undefined,
|
|
68
|
+
warn: console.warn,
|
|
69
|
+
error: console.error,
|
|
70
|
+
debug: () => undefined,
|
|
71
|
+
trace: () => undefined,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
const mnemonic = fs_1.default.readFileSync(mnemonicFile, "utf-8").trim();
|
|
75
|
+
const priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
|
|
76
|
+
const pythListener = new pyth_price_listener_1.PythPriceListener(priceServiceConnection, priceItems);
|
|
77
|
+
const aptosListener = new aptos_1.AptosPriceListener(pythContractAddress, endpoint, priceItems, { pollingFrequency });
|
|
78
|
+
const aptosPusher = new aptos_1.AptosPricePusher(priceServiceConnection, pythContractAddress, endpoint, mnemonic, overrideGasPriceMultiplier);
|
|
79
|
+
const controller = new controller_1.Controller(priceConfigs, pythListener, aptosListener, aptosPusher, { pushingFrequency });
|
|
80
|
+
controller.start();
|
|
81
|
+
},
|
|
82
|
+
};
|
package/lib/common.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC"}
|
package/lib/common.js
ADDED
package/lib/controller.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DurationInSeconds } from "./utils";
|
|
2
|
-
import {
|
|
2
|
+
import { IPriceListener, IPricePusher } from "./interface";
|
|
3
3
|
import { PriceConfig } from "./price-config";
|
|
4
4
|
export declare class Controller {
|
|
5
5
|
private priceConfigs;
|
|
@@ -12,3 +12,4 @@ export declare class Controller {
|
|
|
12
12
|
});
|
|
13
13
|
start(): Promise<void>;
|
|
14
14
|
}
|
|
15
|
+
//# sourceMappingURL=controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../src/controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAS,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAiC,MAAM,gBAAgB,CAAC;AAE5E,qBAAa,UAAU;IAGnB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,sBAAsB;IALhC,OAAO,CAAC,gBAAgB,CAAoB;gBAElC,YAAY,EAAE,WAAW,EAAE,EAC3B,mBAAmB,EAAE,cAAc,EACnC,mBAAmB,EAAE,cAAc,EACnC,sBAAsB,EAAE,YAAY,EAC5C,MAAM,EAAE;QACN,gBAAgB,EAAE,iBAAiB,CAAC;KACrC;IAKG,KAAK;CA2DZ"}
|
package/lib/controller.js
CHANGED
|
@@ -25,18 +25,26 @@ class Controller {
|
|
|
25
25
|
// their might be a message sent before.
|
|
26
26
|
await (0, utils_1.sleep)(this.pushingFrequency * 1000);
|
|
27
27
|
for (;;) {
|
|
28
|
+
// We will push all prices whose update condition is YES or EARLY as long as there is
|
|
29
|
+
// at least one YES.
|
|
30
|
+
let pushThresholdMet = false;
|
|
28
31
|
const pricesToPush = [];
|
|
29
32
|
const pubTimesToPush = [];
|
|
30
33
|
for (const priceConfig of this.priceConfigs) {
|
|
31
34
|
const priceId = priceConfig.id;
|
|
32
35
|
const targetLatestPrice = this.targetPriceListener.getLatestPriceInfo(priceId);
|
|
33
36
|
const sourceLatestPrice = this.sourcePriceListener.getLatestPriceInfo(priceId);
|
|
34
|
-
|
|
37
|
+
const priceShouldUpdate = (0, price_config_1.shouldUpdate)(priceConfig, sourceLatestPrice, targetLatestPrice);
|
|
38
|
+
if (priceShouldUpdate == price_config_1.UpdateCondition.YES) {
|
|
39
|
+
pushThresholdMet = true;
|
|
40
|
+
}
|
|
41
|
+
if (priceShouldUpdate == price_config_1.UpdateCondition.YES ||
|
|
42
|
+
priceShouldUpdate == price_config_1.UpdateCondition.EARLY) {
|
|
35
43
|
pricesToPush.push(priceConfig);
|
|
36
44
|
pubTimesToPush.push((targetLatestPrice?.publishTime || 0) + 1);
|
|
37
45
|
}
|
|
38
46
|
}
|
|
39
|
-
if (
|
|
47
|
+
if (pushThresholdMet) {
|
|
40
48
|
console.log("Some of the above values passed the threshold. Will push the price.");
|
|
41
49
|
// note that the priceIds are without leading "0x"
|
|
42
50
|
const priceIds = pricesToPush.map((priceConfig) => priceConfig.id);
|
package/lib/evm/command.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/evm/command.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;;;;;;;;;;;;;;;;oBA4CL,GAAG;;AAxC9B,wBA+GE"}
|
package/lib/evm/command.js
CHANGED
|
@@ -88,6 +88,9 @@ exports.default = {
|
|
|
88
88
|
const priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
|
|
89
89
|
const pythListener = new pyth_price_listener_1.PythPriceListener(priceServiceConnection, priceItems);
|
|
90
90
|
const pythContractFactory = new evm_1.PythContractFactory(endpoint, mnemonic, pythContractAddress);
|
|
91
|
+
console.log(`Pushing updates from wallet address: ${pythContractFactory
|
|
92
|
+
.createWeb3PayerProvider()
|
|
93
|
+
.getAddress()}`);
|
|
91
94
|
const evmListener = new evm_1.EvmPriceListener(pythContractFactory, priceItems, {
|
|
92
95
|
pollingFrequency,
|
|
93
96
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-gas-station.d.ts","sourceRoot":"","sources":["../../src/evm/custom-gas-station.ts"],"names":[],"mappings":"AAWA,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,KAAK,CAAU;IACvB,OAAO,CAAC,YAAY,CAElB;gBACU,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAKlC,iBAAiB;YAIT,yBAAyB;CAexC;AAED,wBAAgB,mBAAmB,CACjC,gBAAgB,CAAC,EAAE,MAAM,EACzB,OAAO,CAAC,EAAE,MAAM,gCAKjB"}
|
package/lib/evm/evm.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evm.d.ts","sourceRoot":"","sources":["../../src/evm/evm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAa,MAAM,mBAAmB,CAAC;AACxD,OAAO,EACL,YAAY,EACZ,SAAS,EACT,kBAAkB,EAClB,SAAS,EACV,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAgB,iBAAiB,EAAmB,MAAM,UAAU,CAAC;AAE5E,OAAO,gBAAgB,MAAM,4BAA4B,CAAC;AAG1D,OAAO,EACL,sBAAsB,EACtB,SAAS,EACT,aAAa,EACd,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAIxD,qBAAa,gBAAiB,SAAQ,kBAAkB;IACtD,OAAO,CAAC,mBAAmB,CAAsB;IACjD,OAAO,CAAC,YAAY,CAAW;gBAG7B,mBAAmB,EAAE,mBAAmB,EACxC,UAAU,EAAE,SAAS,EAAE,EACvB,MAAM,EAAE;QACN,gBAAgB,EAAE,iBAAiB,CAAC;KACrC;IAUG,KAAK;YAeG,iBAAiB;IAc/B,OAAO,CAAC,iBAAiB;IAsBnB,mBAAmB,CACvB,OAAO,EAAE,SAAS,GACjB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CAwBlC;AAED,qBAAa,cAAe,YAAW,YAAY;IAQ/C,OAAO,CAAC,UAAU;IAElB,OAAO,CAAC,0BAA0B;IATpC,OAAO,CAAC,gBAAgB,CAAC,CAAmB;IAC5C,OAAO,CAAC,YAAY,CAAW;IAC/B,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,eAAe,CAA0B;gBAGvC,UAAU,EAAE,sBAAsB,EAC1C,mBAAmB,EAAE,mBAAmB,EAChC,0BAA0B,EAAE,MAAM,EAC1C,gBAAgB,CAAC,EAAE,gBAAgB;IAa/B,eAAe,CACnB,QAAQ,EAAE,MAAM,EAAE,EAClB,cAAc,EAAE,aAAa,EAAE,GAC9B,OAAO,CAAC,IAAI,CAAC;YA6IF,uBAAuB;CAQtC;AAED,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,mBAAmB;gBAFnB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,mBAAmB,EAAE,MAAM;IAGrC;;;;;;OAMG;IACH,2BAA2B,IAAI,QAAQ;IAcvC;;;;;OAKG;IACH,kBAAkB,IAAI,QAAQ;IAS9B,oBAAoB,IAAI,OAAO;IAI/B,kBAAkB;IA0BlB,uBAAuB;CAQxB"}
|
package/lib/evm/evm.js
CHANGED
|
@@ -151,7 +151,7 @@ class EvmPricePusher {
|
|
|
151
151
|
// doesn't return any information why the call has reverted. Assuming that
|
|
152
152
|
// the update data is valid there is no possible rejection cause other than
|
|
153
153
|
// the target chain price being already updated.
|
|
154
|
-
console.log("Execution reverted. With high
|
|
154
|
+
console.log("Execution reverted. With high probability, the target chain price " +
|
|
155
155
|
"has already updated, Skipping this push.");
|
|
156
156
|
return;
|
|
157
157
|
}
|
|
@@ -160,6 +160,14 @@ class EvmPricePusher {
|
|
|
160
160
|
console.log("Multiple users are using the same accounts and nonce is incorrect. Skipping this push.");
|
|
161
161
|
return;
|
|
162
162
|
}
|
|
163
|
+
if (err.message.includes("max fee per gas less than block base fee")) {
|
|
164
|
+
// We just have to handle this error and return.
|
|
165
|
+
// LastPushAttempt was stored with the class
|
|
166
|
+
// Next time the update will be executing, it will check the last attempt
|
|
167
|
+
// and increase the gas price accordingly.
|
|
168
|
+
console.log("The transaction failed with error: max fee per gas less than block base fee ");
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
163
171
|
if (err.message.includes("sender doesn't have enough funds to send tx.")) {
|
|
164
172
|
console.error("Payer is out of balance, please top it up.");
|
|
165
173
|
throw err;
|
package/lib/index.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/lib/index.js
CHANGED
|
@@ -8,9 +8,13 @@ const yargs_1 = __importDefault(require("yargs"));
|
|
|
8
8
|
const helpers_1 = require("yargs/helpers");
|
|
9
9
|
const command_1 = __importDefault(require("./injective/command"));
|
|
10
10
|
const command_2 = __importDefault(require("./evm/command"));
|
|
11
|
+
const command_3 = __importDefault(require("./aptos/command"));
|
|
12
|
+
const command_4 = __importDefault(require("./sui/command"));
|
|
11
13
|
(0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
|
|
12
14
|
.config("config")
|
|
13
15
|
.global("config")
|
|
14
16
|
.command(command_2.default)
|
|
15
17
|
.command(command_1.default)
|
|
18
|
+
.command(command_3.default)
|
|
19
|
+
.command(command_4.default)
|
|
16
20
|
.help().argv;
|
|
@@ -10,7 +10,9 @@ declare const _default: {
|
|
|
10
10
|
"price-service-endpoint": Options;
|
|
11
11
|
"price-config-file": Options;
|
|
12
12
|
"grpc-endpoint": Options;
|
|
13
|
+
network: Options;
|
|
13
14
|
};
|
|
14
15
|
handler: (argv: any) => void;
|
|
15
16
|
};
|
|
16
17
|
export default _default;
|
|
18
|
+
//# sourceMappingURL=command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/injective/command.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;;;;;;;;;;;;;;oBA2BL,GAAG;;AAxB9B,wBA4FE"}
|
package/lib/injective/command.js
CHANGED
|
@@ -33,6 +33,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
33
33
|
const injective_1 = require("./injective");
|
|
34
34
|
const pyth_price_listener_1 = require("../pyth-price-listener");
|
|
35
35
|
const controller_1 = require("../controller");
|
|
36
|
+
const networks_1 = require("@injectivelabs/networks");
|
|
36
37
|
exports.default = {
|
|
37
38
|
command: "injective",
|
|
38
39
|
describe: "run price pusher for injective",
|
|
@@ -44,6 +45,11 @@ exports.default = {
|
|
|
44
45
|
type: "string",
|
|
45
46
|
required: true,
|
|
46
47
|
},
|
|
48
|
+
network: {
|
|
49
|
+
description: "testnet or mainnet",
|
|
50
|
+
type: "string",
|
|
51
|
+
required: true,
|
|
52
|
+
},
|
|
47
53
|
...options.priceConfigFile,
|
|
48
54
|
...options.priceServiceEndpoint,
|
|
49
55
|
...options.mnemonicFile,
|
|
@@ -53,7 +59,10 @@ exports.default = {
|
|
|
53
59
|
},
|
|
54
60
|
handler: function (argv) {
|
|
55
61
|
// FIXME: type checks for this
|
|
56
|
-
const { grpcEndpoint, priceConfigFile, priceServiceEndpoint, mnemonicFile, pythContractAddress, pushingFrequency, pollingFrequency, } = argv;
|
|
62
|
+
const { grpcEndpoint, priceConfigFile, priceServiceEndpoint, mnemonicFile, pythContractAddress, pushingFrequency, pollingFrequency, network, } = argv;
|
|
63
|
+
if (network !== "testnet" && network !== "mainnet") {
|
|
64
|
+
throw new Error("Please specify network. One of [testnet, mainnet]");
|
|
65
|
+
}
|
|
57
66
|
const priceConfigs = (0, price_config_1.readPriceConfigFile)(priceConfigFile);
|
|
58
67
|
const priceServiceConnection = new price_service_client_1.PriceServiceConnection(priceServiceEndpoint, {
|
|
59
68
|
logger: {
|
|
@@ -71,7 +80,9 @@ exports.default = {
|
|
|
71
80
|
const injectiveListener = new injective_1.InjectivePriceListener(pythContractAddress, grpcEndpoint, priceItems, {
|
|
72
81
|
pollingFrequency,
|
|
73
82
|
});
|
|
74
|
-
const injectivePusher = new injective_1.InjectivePricePusher(priceServiceConnection, pythContractAddress, grpcEndpoint, mnemonic
|
|
83
|
+
const injectivePusher = new injective_1.InjectivePricePusher(priceServiceConnection, pythContractAddress, grpcEndpoint, mnemonic, {
|
|
84
|
+
chainId: (0, networks_1.getNetworkInfo)(network).chainId,
|
|
85
|
+
});
|
|
75
86
|
const controller = new controller_1.Controller(priceConfigs, pythListener, injectiveListener, injectivePusher, { pushingFrequency });
|
|
76
87
|
controller.start();
|
|
77
88
|
},
|
|
@@ -20,6 +20,7 @@ export declare class InjectivePricePusher implements IPricePusher {
|
|
|
20
20
|
private grpcEndpoint;
|
|
21
21
|
private wallet;
|
|
22
22
|
private chainConfig;
|
|
23
|
+
private account;
|
|
23
24
|
constructor(priceServiceConnection: PriceServiceConnection, pythContractAddress: string, grpcEndpoint: string, mnemonic: string, chainConfig?: Partial<InjectiveConfig>);
|
|
24
25
|
private injectiveAddress;
|
|
25
26
|
private signAndBroadcastMsg;
|
|
@@ -27,3 +28,4 @@ export declare class InjectivePricePusher implements IPricePusher {
|
|
|
27
28
|
updatePriceFeed(priceIds: string[], pubTimesToPush: number[]): Promise<void>;
|
|
28
29
|
}
|
|
29
30
|
export {};
|
|
31
|
+
//# sourceMappingURL=injective.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injective.d.ts","sourceRoot":"","sources":["../../src/injective/injective.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,sBAAsB,EACvB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,YAAY,EACZ,SAAS,EACT,kBAAkB,EAClB,SAAS,EACV,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAiC7C,qBAAa,sBAAuB,SAAQ,kBAAkB;IAE1D,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,YAAY;gBADZ,mBAAmB,EAAE,MAAM,EAC3B,YAAY,EAAE,MAAM,EAC5B,UAAU,EAAE,SAAS,EAAE,EACvB,MAAM,EAAE;QACN,gBAAgB,EAAE,iBAAiB,CAAC;KACrC;IAKG,mBAAmB,CACvB,OAAO,EAAE,SAAS,GACjB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CA6BlC;AAED,KAAK,eAAe,GAAG;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AACF,qBAAa,oBAAqB,YAAW,YAAY;IAMrD,OAAO,CAAC,sBAAsB;IAC9B,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,YAAY;IAPtB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,OAAO,CAAwB;gBAG7B,sBAAsB,EAAE,sBAAsB,EAC9C,mBAAmB,EAAE,MAAM,EAC3B,YAAY,EAAE,MAAM,EAC5B,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC;IAWxC,OAAO,CAAC,gBAAgB;YAIV,mBAAmB;IAkE3B,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;IAU1D,eAAe,CACnB,QAAQ,EAAE,MAAM,EAAE,EAClB,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,IAAI,CAAC;CAoDjB"}
|