@pythnetwork/price-pusher 10.3.1 → 11.3.0
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 +28 -7
- package/dist/aptos/aptos.cjs +7 -7
- package/dist/aptos/aptos.d.ts +1 -1
- package/dist/aptos/balance-tracker.cjs +7 -7
- package/dist/aptos/balance-tracker.d.ts +1 -1
- package/dist/aptos/command.cjs +20 -17
- package/dist/aptos/command.d.ts +3 -2
- package/dist/common.cjs +0 -3
- package/dist/common.d.ts +0 -4
- package/dist/controller.cjs +12 -7
- package/dist/controller.d.ts +1 -1
- package/dist/evm/balance-tracker.cjs +4 -4
- package/dist/evm/balance-tracker.d.ts +2 -2
- package/dist/evm/command.cjs +89 -40
- package/dist/evm/command.d.ts +12 -6
- package/dist/evm/evm.cjs +162 -58
- package/dist/evm/evm.d.ts +13 -8
- package/dist/evm/gas-price.cjs +114 -0
- package/dist/evm/gas-price.d.ts +33 -0
- package/dist/evm/pyth-contract.cjs +2 -2
- package/dist/evm/super-wallet.cjs +4 -4
- package/dist/evm/super-wallet.d.ts +1 -1
- package/dist/fuel/command.cjs +17 -14
- package/dist/fuel/command.d.ts +3 -2
- package/dist/fuel/fuel.d.ts +2 -2
- package/dist/injective/command.cjs +26 -23
- package/dist/injective/command.d.ts +5 -4
- package/dist/injective/injective.cjs +11 -11
- package/dist/injective/injective.d.ts +2 -3
- package/dist/interface.d.ts +1 -1
- package/dist/metrics.cjs +57 -35
- package/dist/metrics.d.ts +10 -5
- package/dist/near/command.cjs +22 -19
- package/dist/near/command.d.ts +5 -4
- package/dist/near/near.cjs +17 -16
- package/dist/near/near.d.ts +1 -1
- package/dist/options.cjs +36 -26
- package/dist/options.d.ts +3 -0
- package/dist/price-config.cjs +15 -15
- package/dist/pyth-price-listener.cjs +5 -3
- package/dist/pyth-price-listener.d.ts +2 -3
- package/dist/solana/balance-tracker.cjs +5 -5
- package/dist/solana/balance-tracker.d.ts +2 -2
- package/dist/solana/command.cjs +75 -60
- package/dist/solana/command.d.ts +13 -10
- package/dist/solana/solana.cjs +5 -5
- package/dist/solana/solana.d.ts +4 -4
- package/dist/sui/balance-tracker.cjs +6 -6
- package/dist/sui/balance-tracker.d.ts +5 -5
- package/dist/sui/command.cjs +84 -47
- package/dist/sui/command.d.ts +10 -6
- package/dist/sui/sui.cjs +159 -106
- package/dist/sui/sui.d.ts +31 -14
- package/dist/ton/command.cjs +17 -14
- package/dist/ton/command.d.ts +3 -2
- package/dist/ton/ton.d.ts +2 -3
- package/dist/utils.d.ts +1 -2
- package/package.json +127 -131
package/dist/fuel/command.d.ts
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import type { Options } from "yargs";
|
|
2
2
|
declare const _default: {
|
|
3
|
-
command: string;
|
|
4
|
-
describe: string;
|
|
5
3
|
builder: {
|
|
6
4
|
"controller-log-level": Options;
|
|
7
5
|
"log-level": Options;
|
|
8
6
|
"polling-frequency": Options;
|
|
9
7
|
"pushing-frequency": Options;
|
|
8
|
+
"hermes-access-token": Options;
|
|
10
9
|
"price-service-endpoint": Options;
|
|
11
10
|
"price-config-file": Options;
|
|
12
11
|
endpoint: Options;
|
|
13
12
|
"private-key-file": Options;
|
|
14
13
|
"pyth-contract-address": Options;
|
|
15
14
|
};
|
|
15
|
+
command: string;
|
|
16
|
+
describe: string;
|
|
16
17
|
handler: (argv: any) => Promise<void>;
|
|
17
18
|
};
|
|
18
19
|
export default _default;
|
package/dist/fuel/fuel.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { HermesClient } from "@pythnetwork/hermes-client";
|
|
2
|
-
import { Provider, Wallet } from "fuels";
|
|
1
|
+
import type { HermesClient } from "@pythnetwork/hermes-client";
|
|
2
|
+
import type { Provider, Wallet } from "fuels";
|
|
3
3
|
import type { Logger } from "pino";
|
|
4
4
|
import type { IPricePusher, PriceInfo, PriceItem } from "../interface.js";
|
|
5
5
|
import { ChainPriceListener } from "../interface.js";
|
|
@@ -12,12 +12,12 @@ const _nodefs = /*#__PURE__*/ _interop_require_default(require("node:fs"));
|
|
|
12
12
|
const _networks = require("@injectivelabs/networks");
|
|
13
13
|
const _hermesclient = require("@pythnetwork/hermes-client");
|
|
14
14
|
const _pino = require("pino");
|
|
15
|
+
const _controller = require("../controller.cjs");
|
|
15
16
|
const _options = /*#__PURE__*/ _interop_require_wildcard(require("../options.cjs"));
|
|
16
17
|
const _priceconfig = require("../price-config.cjs");
|
|
17
|
-
const _injective = require("./injective.cjs");
|
|
18
|
-
const _controller = require("../controller.cjs");
|
|
19
18
|
const _pythpricelistener = require("../pyth-price-listener.cjs");
|
|
20
19
|
const _utils = require("../utils.cjs");
|
|
20
|
+
const _injective = require("./injective.cjs");
|
|
21
21
|
function _interop_require_default(obj) {
|
|
22
22
|
return obj && obj.__esModule ? obj : {
|
|
23
23
|
default: obj
|
|
@@ -65,34 +65,33 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
65
65
|
return newObj;
|
|
66
66
|
}
|
|
67
67
|
const _default = {
|
|
68
|
-
command: "injective",
|
|
69
|
-
describe: "run price pusher for injective",
|
|
70
68
|
builder: {
|
|
71
|
-
"
|
|
72
|
-
description: "
|
|
73
|
-
type: "
|
|
74
|
-
required: true
|
|
75
|
-
},
|
|
76
|
-
network: {
|
|
77
|
-
description: "testnet or mainnet",
|
|
78
|
-
type: "string",
|
|
79
|
-
required: true
|
|
69
|
+
"gas-multiplier": {
|
|
70
|
+
description: "Gas multiplier to be used for each transaction",
|
|
71
|
+
type: "number"
|
|
80
72
|
},
|
|
81
73
|
"gas-price": {
|
|
82
74
|
description: "Gas price to be used for each transaction",
|
|
83
75
|
type: "number"
|
|
84
76
|
},
|
|
85
|
-
"
|
|
86
|
-
description: "
|
|
87
|
-
|
|
77
|
+
"grpc-endpoint": {
|
|
78
|
+
description: "gRPC endpoint URL for injective. The pusher will periodically" + "poll for updates. The polling interval is configurable via the " + "`polling-frequency` command-line argument.",
|
|
79
|
+
required: true,
|
|
80
|
+
type: "string"
|
|
81
|
+
},
|
|
82
|
+
network: {
|
|
83
|
+
description: "testnet or mainnet",
|
|
84
|
+
required: true,
|
|
85
|
+
type: "string"
|
|
88
86
|
},
|
|
89
87
|
"price-ids-process-chunk-size": {
|
|
90
88
|
description: "Set in case we wanna split price feeds updates into chunks to have smaller transactions. Set to -1 to disable chunking.",
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
required: false,
|
|
90
|
+
type: "number"
|
|
93
91
|
},
|
|
94
92
|
..._options.priceConfigFile,
|
|
95
93
|
..._options.priceServiceEndpoint,
|
|
94
|
+
..._options.hermesAccessToken,
|
|
96
95
|
..._options.mnemonicFile,
|
|
97
96
|
..._options.pythContractAddress,
|
|
98
97
|
..._options.pollingFrequency,
|
|
@@ -100,9 +99,11 @@ const _default = {
|
|
|
100
99
|
..._options.logLevel,
|
|
101
100
|
..._options.controllerLogLevel
|
|
102
101
|
},
|
|
102
|
+
command: "injective",
|
|
103
|
+
describe: "run price pusher for injective",
|
|
103
104
|
handler: async function(argv) {
|
|
104
105
|
// FIXME: type checks for this
|
|
105
|
-
const { network, logLevel, gasPrice, grpcEndpoint, mnemonicFile, gasMultiplier, priceConfigFile, pollingFrequency, pushingFrequency, controllerLogLevel, pythContractAddress, priceServiceEndpoint, priceIdsProcessChunkSize } = argv;
|
|
106
|
+
const { network, logLevel, gasPrice, grpcEndpoint, mnemonicFile, gasMultiplier, priceConfigFile, pollingFrequency, pushingFrequency, controllerLogLevel, pythContractAddress, priceServiceEndpoint, hermesAccessToken, priceIdsProcessChunkSize } = argv;
|
|
106
107
|
const logger = (0, _pino.pino)({
|
|
107
108
|
level: logLevel
|
|
108
109
|
});
|
|
@@ -110,11 +111,13 @@ const _default = {
|
|
|
110
111
|
throw new Error("Please specify network. One of [testnet, mainnet]");
|
|
111
112
|
}
|
|
112
113
|
const priceConfigs = (0, _priceconfig.readPriceConfigFile)(priceConfigFile);
|
|
113
|
-
const hermesClient = new _hermesclient.HermesClient(priceServiceEndpoint
|
|
114
|
+
const hermesClient = new _hermesclient.HermesClient(priceServiceEndpoint, {
|
|
115
|
+
accessToken: hermesAccessToken
|
|
116
|
+
});
|
|
114
117
|
const mnemonic = _nodefs.default.readFileSync(mnemonicFile, "utf8").trim();
|
|
115
118
|
let priceItems = priceConfigs.map(({ id, alias })=>({
|
|
116
|
-
|
|
117
|
-
|
|
119
|
+
alias,
|
|
120
|
+
id
|
|
118
121
|
}));
|
|
119
122
|
// Better to filter out invalid price items before creating the pyth listener
|
|
120
123
|
const { existingPriceItems, invalidPriceItems } = await (0, _utils.filterInvalidPriceItems)(hermesClient, priceItems);
|
|
@@ -134,8 +137,8 @@ const _default = {
|
|
|
134
137
|
module: "InjectivePricePusher"
|
|
135
138
|
}), mnemonic, {
|
|
136
139
|
chainId: (0, _networks.getNetworkInfo)(network).chainId,
|
|
137
|
-
gasPrice,
|
|
138
140
|
gasMultiplier,
|
|
141
|
+
gasPrice,
|
|
139
142
|
priceIdsProcessChunkSize
|
|
140
143
|
});
|
|
141
144
|
const controller = new _controller.Controller(priceConfigs, pythListener, injectiveListener, injectivePusher, logger.child({
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { Options } from "yargs";
|
|
2
2
|
declare const _default: {
|
|
3
|
-
command: string;
|
|
4
|
-
describe: string;
|
|
5
3
|
builder: {
|
|
6
4
|
"controller-log-level": Options;
|
|
7
5
|
"log-level": Options;
|
|
@@ -9,14 +7,17 @@ declare const _default: {
|
|
|
9
7
|
"polling-frequency": Options;
|
|
10
8
|
"pyth-contract-address": Options;
|
|
11
9
|
"mnemonic-file": Options;
|
|
10
|
+
"hermes-access-token": Options;
|
|
12
11
|
"price-service-endpoint": Options;
|
|
13
12
|
"price-config-file": Options;
|
|
13
|
+
"gas-multiplier": Options;
|
|
14
|
+
"gas-price": Options;
|
|
14
15
|
"grpc-endpoint": Options;
|
|
15
16
|
network: Options;
|
|
16
|
-
"gas-price": Options;
|
|
17
|
-
"gas-multiplier": Options;
|
|
18
17
|
"price-ids-process-chunk-size": Options;
|
|
19
18
|
};
|
|
19
|
+
command: string;
|
|
20
|
+
describe: string;
|
|
20
21
|
handler: (argv: any) => Promise<void>;
|
|
21
22
|
};
|
|
22
23
|
export default _default;
|
|
@@ -85,12 +85,12 @@ class InjectivePricePusher {
|
|
|
85
85
|
const account = this.accounts[injectiveAddress];
|
|
86
86
|
try {
|
|
87
87
|
const { signBytes, txRaw } = (0, _sdkts.createTransactionFromMsg)({
|
|
88
|
-
sequence: account.baseAccount.sequence,
|
|
89
88
|
accountNumber: account.baseAccount.accountNumber,
|
|
90
|
-
message: msg,
|
|
91
89
|
chainId: this.chainConfig.chainId,
|
|
92
90
|
fee: await this.getStdFee(msg, index),
|
|
93
|
-
|
|
91
|
+
message: msg,
|
|
92
|
+
pubKey: wallet.toPublicKey().toBase64(),
|
|
93
|
+
sequence: account.baseAccount.sequence
|
|
94
94
|
});
|
|
95
95
|
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
96
96
|
const sig = await wallet.sign(Buffer.from(signBytes));
|
|
@@ -128,12 +128,12 @@ class InjectivePricePusher {
|
|
|
128
128
|
const updateFeeQueryResponse = await this.getUpdateFee(priceFeedUpdateObject.update_price_feeds.data);
|
|
129
129
|
const wallet = this.getWallet(chunkIndex);
|
|
130
130
|
const msg = _sdkts.MsgExecuteContract.fromJSON({
|
|
131
|
-
sender: wallet.toAddress().toBech32(),
|
|
132
131
|
contractAddress: this.pythContractAddress,
|
|
133
|
-
msg: priceFeedUpdateObject,
|
|
134
132
|
funds: [
|
|
135
133
|
updateFeeQueryResponse
|
|
136
|
-
]
|
|
134
|
+
],
|
|
135
|
+
msg: priceFeedUpdateObject,
|
|
136
|
+
sender: wallet.toAddress().toBech32()
|
|
137
137
|
});
|
|
138
138
|
const rs = await this.signAndBroadcastMsg(msg, chunkIndex);
|
|
139
139
|
this.logger.info({
|
|
@@ -164,11 +164,11 @@ class InjectivePricePusher {
|
|
|
164
164
|
throw new Error("Account not found");
|
|
165
165
|
}
|
|
166
166
|
const { txRaw: simulateTxRaw } = (0, _sdkts.createTransactionFromMsg)({
|
|
167
|
-
sequence: account.baseAccount.sequence,
|
|
168
167
|
accountNumber: account.baseAccount.accountNumber,
|
|
169
|
-
message: msg,
|
|
170
168
|
chainId: this.chainConfig.chainId,
|
|
171
|
-
|
|
169
|
+
message: msg,
|
|
170
|
+
pubKey: wallet.toPublicKey().toBase64(),
|
|
171
|
+
sequence: account.baseAccount.sequence
|
|
172
172
|
});
|
|
173
173
|
try {
|
|
174
174
|
const result = await new _sdkts.TxGrpcApi(this.grpcEndpoint).simulate(simulateTxRaw);
|
|
@@ -176,8 +176,8 @@ class InjectivePricePusher {
|
|
|
176
176
|
const fee = {
|
|
177
177
|
amount: [
|
|
178
178
|
{
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
amount: (Number(gas) * this.chainConfig.gasPrice).toFixed(0),
|
|
180
|
+
denom: "inj"
|
|
181
181
|
}
|
|
182
182
|
],
|
|
183
183
|
gas
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type { HexString } from "@pythnetwork/hermes-client";
|
|
2
|
-
import { HermesClient } from "@pythnetwork/hermes-client";
|
|
1
|
+
import type { HermesClient, HexString } from "@pythnetwork/hermes-client";
|
|
3
2
|
import type { Logger } from "pino";
|
|
4
|
-
import type {
|
|
3
|
+
import type { IPricePusher, PriceInfo, PriceItem } from "../interface.js";
|
|
5
4
|
import { ChainPriceListener } from "../interface.js";
|
|
6
5
|
import type { DurationInSeconds } from "../utils.js";
|
|
7
6
|
type InjectiveConfig = {
|
package/dist/interface.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { HexString, UnixTimestamp } from "@pythnetwork/hermes-client";
|
|
2
2
|
import type { Logger } from "pino";
|
|
3
|
-
import { PricePusherMetrics } from "./metrics.js";
|
|
3
|
+
import type { PricePusherMetrics } from "./metrics.js";
|
|
4
4
|
import type { DurationInSeconds } from "./utils.js";
|
|
5
5
|
export type PriceItem = {
|
|
6
6
|
id: HexString;
|
package/dist/metrics.cjs
CHANGED
|
@@ -30,6 +30,11 @@ class PricePusherMetrics {
|
|
|
30
30
|
targetPriceValue;
|
|
31
31
|
// Wallet metrics
|
|
32
32
|
walletBalance;
|
|
33
|
+
// Liveness heartbeat
|
|
34
|
+
loopIterations;
|
|
35
|
+
// Liveness state for the /live endpoint (threshold set by the controller)
|
|
36
|
+
lastLoopIterationAt;
|
|
37
|
+
livenessThresholdMs = 60_000;
|
|
33
38
|
constructor(logger){
|
|
34
39
|
this.logger = logger;
|
|
35
40
|
this.registry = new _promclient.Registry();
|
|
@@ -40,88 +45,91 @@ class PricePusherMetrics {
|
|
|
40
45
|
});
|
|
41
46
|
// Create metrics
|
|
42
47
|
this.lastPublishedTime = new _promclient.Gauge({
|
|
43
|
-
name: "pyth_price_last_published_time",
|
|
44
48
|
help: "The last published time of a price feed in unix timestamp",
|
|
45
49
|
labelNames: [
|
|
46
|
-
"price_id",
|
|
47
50
|
"alias"
|
|
48
51
|
],
|
|
52
|
+
name: "pyth_price_last_published_time",
|
|
49
53
|
registers: [
|
|
50
54
|
this.registry
|
|
51
55
|
]
|
|
52
56
|
});
|
|
53
57
|
this.priceUpdateAttempts = new _promclient.Counter({
|
|
54
|
-
name: "pyth_price_update_attempts_total",
|
|
55
58
|
help: "Total number of price update attempts with their trigger condition and status",
|
|
56
59
|
labelNames: [
|
|
57
|
-
"price_id",
|
|
58
60
|
"alias",
|
|
59
61
|
"trigger",
|
|
60
62
|
"status"
|
|
61
63
|
],
|
|
64
|
+
name: "pyth_price_update_attempts_total",
|
|
62
65
|
registers: [
|
|
63
66
|
this.registry
|
|
64
67
|
]
|
|
65
68
|
});
|
|
66
69
|
this.priceFeedsTotal = new _promclient.Gauge({
|
|
67
|
-
name: "pyth_price_feeds_total",
|
|
68
70
|
help: "Total number of price feeds being monitored",
|
|
71
|
+
name: "pyth_price_feeds_total",
|
|
69
72
|
registers: [
|
|
70
73
|
this.registry
|
|
71
74
|
]
|
|
72
75
|
});
|
|
73
76
|
this.sourceTimestamp = new _promclient.Gauge({
|
|
74
|
-
name: "pyth_source_timestamp",
|
|
75
77
|
help: "Latest source chain price publish timestamp",
|
|
76
78
|
labelNames: [
|
|
77
|
-
"price_id",
|
|
78
79
|
"alias"
|
|
79
80
|
],
|
|
81
|
+
name: "pyth_source_timestamp",
|
|
80
82
|
registers: [
|
|
81
83
|
this.registry
|
|
82
84
|
]
|
|
83
85
|
});
|
|
84
86
|
this.configuredTimeDifference = new _promclient.Gauge({
|
|
85
|
-
name: "pyth_configured_time_difference",
|
|
86
87
|
help: "Configured time difference threshold between source and target chains",
|
|
87
88
|
labelNames: [
|
|
88
|
-
"price_id",
|
|
89
89
|
"alias"
|
|
90
90
|
],
|
|
91
|
+
name: "pyth_configured_time_difference",
|
|
91
92
|
registers: [
|
|
92
93
|
this.registry
|
|
93
94
|
]
|
|
94
95
|
});
|
|
95
96
|
this.sourcePriceValue = new _promclient.Gauge({
|
|
96
|
-
name: "pyth_source_price",
|
|
97
97
|
help: "Latest price value from Pyth source",
|
|
98
98
|
labelNames: [
|
|
99
|
-
"price_id",
|
|
100
99
|
"alias"
|
|
101
100
|
],
|
|
101
|
+
name: "pyth_source_price",
|
|
102
102
|
registers: [
|
|
103
103
|
this.registry
|
|
104
104
|
]
|
|
105
105
|
});
|
|
106
106
|
this.targetPriceValue = new _promclient.Gauge({
|
|
107
|
-
name: "pyth_target_price",
|
|
108
107
|
help: "Latest price value from target chain",
|
|
109
108
|
labelNames: [
|
|
110
|
-
"price_id",
|
|
111
109
|
"alias"
|
|
112
110
|
],
|
|
111
|
+
name: "pyth_target_price",
|
|
113
112
|
registers: [
|
|
114
113
|
this.registry
|
|
115
114
|
]
|
|
116
115
|
});
|
|
117
116
|
// Wallet balance metric
|
|
118
117
|
this.walletBalance = new _promclient.Gauge({
|
|
119
|
-
name: "pyth_wallet_balance",
|
|
120
118
|
help: "Current wallet balance of the price pusher in native token units",
|
|
121
119
|
labelNames: [
|
|
122
120
|
"wallet_address",
|
|
123
121
|
"network"
|
|
124
122
|
],
|
|
123
|
+
name: "pyth_wallet_balance",
|
|
124
|
+
registers: [
|
|
125
|
+
this.registry
|
|
126
|
+
]
|
|
127
|
+
});
|
|
128
|
+
// Liveness heartbeat: increments once per controller loop iteration so a
|
|
129
|
+
// hung (but not crashed) process is detectable via the metric going flat.
|
|
130
|
+
this.loopIterations = new _promclient.Counter({
|
|
131
|
+
help: "Total number of controller loop iterations completed (liveness heartbeat)",
|
|
132
|
+
name: "pyth_pusher_loop_iterations_total",
|
|
125
133
|
registers: [
|
|
126
134
|
this.registry
|
|
127
135
|
]
|
|
@@ -131,6 +139,18 @@ class PricePusherMetrics {
|
|
|
131
139
|
res.set("Content-Type", this.registry.contentType);
|
|
132
140
|
res.end(await this.registry.metrics());
|
|
133
141
|
});
|
|
142
|
+
// Liveness endpoint for the k8s livenessProbe: 200 while the control loop is
|
|
143
|
+
// progressing, 503 once no iteration has completed within the threshold (hung),
|
|
144
|
+
// so Kubernetes restarts a hung-but-not-crashed pod.
|
|
145
|
+
this.server.get("/live", (_, res)=>{
|
|
146
|
+
const last = this.lastLoopIterationAt;
|
|
147
|
+
const healthy = last !== undefined && Date.now() - last <= this.livenessThresholdMs;
|
|
148
|
+
res.status(healthy ? 200 : 503).json({
|
|
149
|
+
lastLoopIterationAt: last ?? null,
|
|
150
|
+
status: healthy ? "ok" : "stale",
|
|
151
|
+
thresholdMs: this.livenessThresholdMs
|
|
152
|
+
});
|
|
153
|
+
});
|
|
134
154
|
}
|
|
135
155
|
// Start the metrics server
|
|
136
156
|
start(port) {
|
|
@@ -139,68 +159,70 @@ class PricePusherMetrics {
|
|
|
139
159
|
});
|
|
140
160
|
}
|
|
141
161
|
// Record a successful price update
|
|
142
|
-
recordPriceUpdate(
|
|
162
|
+
recordPriceUpdate(alias, trigger = "yes") {
|
|
143
163
|
this.priceUpdateAttempts.inc({
|
|
144
|
-
price_id: priceId,
|
|
145
164
|
alias,
|
|
146
|
-
|
|
147
|
-
|
|
165
|
+
status: "success",
|
|
166
|
+
trigger: trigger.toLowerCase()
|
|
148
167
|
});
|
|
149
168
|
}
|
|
150
169
|
// Record update condition status (YES/NO/EARLY)
|
|
151
|
-
recordUpdateCondition(
|
|
170
|
+
recordUpdateCondition(alias, condition) {
|
|
152
171
|
const triggerLabel = _priceconfig.UpdateCondition[condition].toLowerCase();
|
|
153
172
|
// Only record as 'skipped' when the condition is NO
|
|
154
173
|
if (condition === _priceconfig.UpdateCondition.NO) {
|
|
155
174
|
this.priceUpdateAttempts.inc({
|
|
156
|
-
price_id: priceId,
|
|
157
175
|
alias,
|
|
158
|
-
|
|
159
|
-
|
|
176
|
+
status: "skipped",
|
|
177
|
+
trigger: triggerLabel
|
|
160
178
|
});
|
|
161
179
|
}
|
|
162
180
|
// YES and EARLY don't increment the counter here - they'll be counted
|
|
163
181
|
// when recordPriceUpdate or recordPriceUpdateError is called
|
|
164
182
|
}
|
|
165
183
|
// Record a price update error
|
|
166
|
-
recordPriceUpdateError(
|
|
184
|
+
recordPriceUpdateError(alias, trigger = "yes") {
|
|
167
185
|
this.priceUpdateAttempts.inc({
|
|
168
|
-
price_id: priceId,
|
|
169
186
|
alias,
|
|
170
|
-
|
|
171
|
-
|
|
187
|
+
status: "error",
|
|
188
|
+
trigger: trigger.toLowerCase()
|
|
172
189
|
});
|
|
173
190
|
}
|
|
174
191
|
// Set the number of price feeds
|
|
175
192
|
setPriceFeedsTotal(count) {
|
|
176
193
|
this.priceFeedsTotal.set(count);
|
|
177
194
|
}
|
|
195
|
+
// Record a completed controller loop iteration (liveness heartbeat)
|
|
196
|
+
recordLoopIteration() {
|
|
197
|
+
this.lastLoopIterationAt = Date.now();
|
|
198
|
+
this.loopIterations.inc();
|
|
199
|
+
}
|
|
200
|
+
// Configure how long without a completed loop iteration before /live reports
|
|
201
|
+
// unhealthy (used by the k8s livenessProbe to restart a hung pod).
|
|
202
|
+
setLivenessThresholdSeconds(seconds) {
|
|
203
|
+
this.livenessThresholdMs = seconds * 1000;
|
|
204
|
+
}
|
|
178
205
|
// Update source, target and configured time difference timestamps
|
|
179
|
-
updateTimestamps(
|
|
206
|
+
updateTimestamps(alias, targetLatestPricePublishTime, sourceLatestPricePublishTime, priceConfigTimeDifference) {
|
|
180
207
|
this.sourceTimestamp.set({
|
|
181
|
-
price_id: priceId,
|
|
182
208
|
alias
|
|
183
209
|
}, sourceLatestPricePublishTime);
|
|
184
210
|
this.lastPublishedTime.set({
|
|
185
|
-
price_id: priceId,
|
|
186
211
|
alias
|
|
187
212
|
}, targetLatestPricePublishTime);
|
|
188
213
|
this.configuredTimeDifference.set({
|
|
189
|
-
price_id: priceId,
|
|
190
214
|
alias
|
|
191
215
|
}, priceConfigTimeDifference);
|
|
192
216
|
}
|
|
193
217
|
// Update price values
|
|
194
|
-
updatePriceValues(
|
|
218
|
+
updatePriceValues(alias, sourcePrice, targetPrice) {
|
|
195
219
|
if (sourcePrice !== undefined) {
|
|
196
220
|
this.sourcePriceValue.set({
|
|
197
|
-
price_id: priceId,
|
|
198
221
|
alias
|
|
199
222
|
}, Number(sourcePrice));
|
|
200
223
|
}
|
|
201
224
|
if (targetPrice !== undefined) {
|
|
202
225
|
this.targetPriceValue.set({
|
|
203
|
-
price_id: priceId,
|
|
204
226
|
alias
|
|
205
227
|
}, Number(targetPrice));
|
|
206
228
|
}
|
|
@@ -210,8 +232,8 @@ class PricePusherMetrics {
|
|
|
210
232
|
// Convert to number for compatibility with prometheus
|
|
211
233
|
const balanceNum = typeof balance === "bigint" ? Number(balance) / 1e18 : balance;
|
|
212
234
|
this.walletBalance.set({
|
|
213
|
-
|
|
214
|
-
|
|
235
|
+
network,
|
|
236
|
+
wallet_address: walletAddress
|
|
215
237
|
}, balanceNum);
|
|
216
238
|
this.logger.debug(`Updated wallet balance metric: ${walletAddress} = ${balanceNum}`);
|
|
217
239
|
}
|
package/dist/metrics.d.ts
CHANGED
|
@@ -13,13 +13,18 @@ export declare class PricePusherMetrics {
|
|
|
13
13
|
sourcePriceValue: Gauge;
|
|
14
14
|
targetPriceValue: Gauge;
|
|
15
15
|
walletBalance: Gauge;
|
|
16
|
+
loopIterations: Counter;
|
|
17
|
+
private lastLoopIterationAt;
|
|
18
|
+
private livenessThresholdMs;
|
|
16
19
|
constructor(logger: Logger);
|
|
17
20
|
start(port: number): void;
|
|
18
|
-
recordPriceUpdate(
|
|
19
|
-
recordUpdateCondition(
|
|
20
|
-
recordPriceUpdateError(
|
|
21
|
+
recordPriceUpdate(alias: string, trigger?: string): void;
|
|
22
|
+
recordUpdateCondition(alias: string, condition: UpdateCondition): void;
|
|
23
|
+
recordPriceUpdateError(alias: string, trigger?: string): void;
|
|
21
24
|
setPriceFeedsTotal(count: number): void;
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
recordLoopIteration(): void;
|
|
26
|
+
setLivenessThresholdSeconds(seconds: number): void;
|
|
27
|
+
updateTimestamps(alias: string, targetLatestPricePublishTime: number, sourceLatestPricePublishTime: number, priceConfigTimeDifference: number): void;
|
|
28
|
+
updatePriceValues(alias: string, sourcePrice: string | undefined, targetPrice: string | undefined): void;
|
|
24
29
|
updateWalletBalance(walletAddress: string, network: string, balance: bigint | number): void;
|
|
25
30
|
}
|
package/dist/near/command.cjs
CHANGED
|
@@ -14,8 +14,8 @@ const _controller = require("../controller.cjs");
|
|
|
14
14
|
const _options = /*#__PURE__*/ _interop_require_wildcard(require("../options.cjs"));
|
|
15
15
|
const _priceconfig = require("../price-config.cjs");
|
|
16
16
|
const _pythpricelistener = require("../pyth-price-listener.cjs");
|
|
17
|
-
const _near = require("./near.cjs");
|
|
18
17
|
const _utils = require("../utils.cjs");
|
|
18
|
+
const _near = require("./near.cjs");
|
|
19
19
|
function _getRequireWildcardCache(nodeInterop) {
|
|
20
20
|
if (typeof WeakMap !== "function") return null;
|
|
21
21
|
var cacheBabelInterop = new WeakMap();
|
|
@@ -58,48 +58,51 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
58
58
|
return newObj;
|
|
59
59
|
}
|
|
60
60
|
const _default = {
|
|
61
|
-
command: "near",
|
|
62
|
-
describe: "run price pusher for near",
|
|
63
61
|
builder: {
|
|
64
|
-
"
|
|
65
|
-
description: "
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
"account-id": {
|
|
63
|
+
description: "payer account identifier.",
|
|
64
|
+
required: true,
|
|
65
|
+
type: "string"
|
|
68
66
|
},
|
|
69
67
|
network: {
|
|
70
68
|
description: "testnet or mainnet.",
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
required: true,
|
|
70
|
+
type: "string"
|
|
73
71
|
},
|
|
74
|
-
"
|
|
75
|
-
description: "
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
"node-url": {
|
|
73
|
+
description: "NEAR RPC API url. used to make JSON RPC calls to interact with NEAR.",
|
|
74
|
+
required: true,
|
|
75
|
+
type: "string"
|
|
78
76
|
},
|
|
79
77
|
"private-key-path": {
|
|
80
78
|
description: "path to payer private key file.",
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
required: false,
|
|
80
|
+
type: "string"
|
|
83
81
|
},
|
|
84
82
|
..._options.priceConfigFile,
|
|
85
83
|
..._options.priceServiceEndpoint,
|
|
84
|
+
..._options.hermesAccessToken,
|
|
86
85
|
..._options.pythContractAddress,
|
|
87
86
|
..._options.pollingFrequency,
|
|
88
87
|
..._options.pushingFrequency,
|
|
89
88
|
..._options.logLevel,
|
|
90
89
|
..._options.controllerLogLevel
|
|
91
90
|
},
|
|
91
|
+
command: "near",
|
|
92
|
+
describe: "run price pusher for near",
|
|
92
93
|
handler: async function(argv) {
|
|
93
94
|
// FIXME: type checks for this
|
|
94
|
-
const { nodeUrl, network, accountId, privateKeyPath, priceConfigFile, priceServiceEndpoint, pythContractAddress, pushingFrequency, pollingFrequency, logLevel, controllerLogLevel } = argv;
|
|
95
|
+
const { nodeUrl, network, accountId, privateKeyPath, priceConfigFile, priceServiceEndpoint, hermesAccessToken, pythContractAddress, pushingFrequency, pollingFrequency, logLevel, controllerLogLevel } = argv;
|
|
95
96
|
const logger = (0, _pino.pino)({
|
|
96
97
|
level: logLevel
|
|
97
98
|
});
|
|
98
99
|
const priceConfigs = (0, _priceconfig.readPriceConfigFile)(priceConfigFile);
|
|
99
|
-
const hermesClient = new _hermesclient.HermesClient(priceServiceEndpoint
|
|
100
|
+
const hermesClient = new _hermesclient.HermesClient(priceServiceEndpoint, {
|
|
101
|
+
accessToken: hermesAccessToken
|
|
102
|
+
});
|
|
100
103
|
let priceItems = priceConfigs.map(({ id, alias })=>({
|
|
101
|
-
|
|
102
|
-
|
|
104
|
+
alias,
|
|
105
|
+
id
|
|
103
106
|
}));
|
|
104
107
|
// Better to filter out invalid price items before creating the pyth listener
|
|
105
108
|
const { existingPriceItems, invalidPriceItems } = await (0, _utils.filterInvalidPriceItems)(hermesClient, priceItems);
|
package/dist/near/command.d.ts
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import type { Options } from "yargs";
|
|
2
2
|
declare const _default: {
|
|
3
|
-
command: string;
|
|
4
|
-
describe: string;
|
|
5
3
|
builder: {
|
|
6
4
|
"controller-log-level": Options;
|
|
7
5
|
"log-level": Options;
|
|
8
6
|
"pushing-frequency": Options;
|
|
9
7
|
"polling-frequency": Options;
|
|
10
8
|
"pyth-contract-address": Options;
|
|
9
|
+
"hermes-access-token": Options;
|
|
11
10
|
"price-service-endpoint": Options;
|
|
12
11
|
"price-config-file": Options;
|
|
13
|
-
"node-url": Options;
|
|
14
|
-
network: Options;
|
|
15
12
|
"account-id": Options;
|
|
13
|
+
network: Options;
|
|
14
|
+
"node-url": Options;
|
|
16
15
|
"private-key-path": Options;
|
|
17
16
|
};
|
|
17
|
+
command: string;
|
|
18
|
+
describe: string;
|
|
18
19
|
handler: (argv: any) => Promise<void>;
|
|
19
20
|
};
|
|
20
21
|
export default _default;
|