@pythnetwork/price-pusher 10.0.0 → 10.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 +31 -3
- package/{lib/aptos/aptos.js → dist/aptos/aptos.cjs} +80 -76
- package/{lib → dist}/aptos/aptos.d.ts +5 -5
- package/{lib/aptos/balance-tracker.js → dist/aptos/balance-tracker.cjs} +37 -25
- package/{lib → dist}/aptos/balance-tracker.d.ts +9 -9
- package/dist/aptos/command.cjs +161 -0
- package/{lib → dist}/aptos/command.d.ts +1 -2
- package/dist/common.cjs +4 -0
- package/{lib → dist}/common.d.ts +0 -1
- package/{lib/controller.js → dist/controller.cjs} +36 -33
- package/{lib → dist}/controller.d.ts +5 -6
- package/dist/evm/balance-tracker.cjs +58 -0
- package/{lib → dist}/evm/balance-tracker.d.ts +10 -10
- package/dist/evm/command.cjs +205 -0
- package/{lib → dist}/evm/command.d.ts +1 -2
- package/dist/evm/custom-gas-station.cjs +54 -0
- package/{lib → dist}/evm/custom-gas-station.d.ts +1 -2
- package/dist/evm/evm.cjs +287 -0
- package/{lib → dist}/evm/evm.d.ts +8 -7
- package/{lib/evm/pyth-abi.js → dist/evm/pyth-abi.cjs} +181 -160
- package/{lib → dist}/evm/pyth-abi.d.ts +0 -1
- package/dist/evm/pyth-contract.cjs +17 -0
- package/{lib → dist}/evm/pyth-contract.d.ts +3 -4
- package/dist/evm/super-wallet.cjs +90 -0
- package/{lib → dist}/evm/super-wallet.d.ts +1 -2
- package/dist/fuel/command.cjs +135 -0
- package/{lib → dist}/fuel/command.d.ts +1 -2
- package/dist/fuel/fuel.cjs +108 -0
- package/{lib → dist}/fuel/fuel.d.ts +5 -5
- package/dist/index.cjs +25 -0
- package/dist/index.d.ts +1 -0
- package/dist/injective/command.cjs +150 -0
- package/{lib → dist}/injective/command.d.ts +1 -2
- package/{lib/injective/injective.js → dist/injective/injective.cjs} +100 -98
- package/{lib → dist}/injective/injective.d.ts +7 -6
- package/dist/interface.cjs +142 -0
- package/{lib → dist}/interface.d.ts +12 -13
- package/dist/metrics.cjs +218 -0
- package/{lib → dist}/metrics.d.ts +11 -9
- package/dist/near/command.cjs +129 -0
- package/{lib → dist}/near/command.d.ts +1 -2
- package/dist/near/near.cjs +183 -0
- package/{lib → dist}/near/near.d.ts +5 -5
- package/dist/options.cjs +132 -0
- package/{lib → dist}/options.d.ts +1 -2
- package/dist/package.json +1 -0
- package/dist/price-config.cjs +104 -0
- package/{lib → dist}/price-config.d.ts +5 -6
- package/{lib/pyth-price-listener.js → dist/pyth-price-listener.cjs} +30 -24
- package/{lib → dist}/pyth-price-listener.d.ts +4 -4
- package/dist/solana/balance-tracker.cjs +60 -0
- package/{lib → dist}/solana/balance-tracker.d.ts +9 -9
- package/dist/solana/command.cjs +259 -0
- package/{lib → dist}/solana/command.d.ts +2 -3
- package/{lib/solana/solana.js → dist/solana/solana.cjs} +90 -78
- package/{lib → dist}/solana/solana.d.ts +6 -6
- package/dist/sui/balance-tracker.cjs +58 -0
- package/{lib → dist}/sui/balance-tracker.d.ts +9 -9
- package/dist/sui/command.cjs +190 -0
- package/{lib → dist}/sui/command.d.ts +1 -2
- package/{lib/sui/sui.js → dist/sui/sui.cjs} +145 -133
- package/{lib → dist}/sui/sui.d.ts +7 -8
- package/dist/ton/command.cjs +137 -0
- package/{lib → dist}/ton/command.d.ts +1 -2
- package/dist/ton/ton.cjs +103 -0
- package/{lib → dist}/ton/ton.d.ts +7 -6
- package/dist/utils.cjs +102 -0
- package/{lib → dist}/utils.d.ts +4 -4
- package/package.json +161 -20
- package/lib/aptos/aptos.d.ts.map +0 -1
- package/lib/aptos/balance-tracker.d.ts.map +0 -1
- package/lib/aptos/command.d.ts.map +0 -1
- package/lib/aptos/command.js +0 -126
- package/lib/common.d.ts.map +0 -1
- package/lib/common.js +0 -2
- package/lib/controller.d.ts.map +0 -1
- package/lib/evm/balance-tracker.d.ts.map +0 -1
- package/lib/evm/balance-tracker.js +0 -49
- package/lib/evm/command.d.ts.map +0 -1
- package/lib/evm/command.js +0 -178
- package/lib/evm/custom-gas-station.d.ts.map +0 -1
- package/lib/evm/custom-gas-station.js +0 -40
- package/lib/evm/evm.d.ts.map +0 -1
- package/lib/evm/evm.js +0 -270
- package/lib/evm/pyth-abi.d.ts.map +0 -1
- package/lib/evm/pyth-contract.d.ts.map +0 -1
- package/lib/evm/pyth-contract.js +0 -11
- package/lib/evm/super-wallet.d.ts.map +0 -1
- package/lib/evm/super-wallet.js +0 -73
- package/lib/fuel/command.d.ts.map +0 -1
- package/lib/fuel/command.js +0 -98
- package/lib/fuel/fuel.d.ts.map +0 -1
- package/lib/fuel/fuel.js +0 -101
- package/lib/index.d.ts +0 -3
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js +0 -34
- package/lib/injective/command.d.ts.map +0 -1
- package/lib/injective/command.js +0 -119
- package/lib/injective/injective.d.ts.map +0 -1
- package/lib/interface.d.ts.map +0 -1
- package/lib/interface.js +0 -122
- package/lib/metrics.d.ts.map +0 -1
- package/lib/metrics.js +0 -129
- package/lib/near/command.d.ts.map +0 -1
- package/lib/near/command.js +0 -103
- package/lib/near/near.d.ts.map +0 -1
- package/lib/near/near.js +0 -168
- package/lib/options.d.ts.map +0 -1
- package/lib/options.js +0 -84
- package/lib/price-config.d.ts.map +0 -1
- package/lib/price-config.js +0 -114
- package/lib/pyth-price-listener.d.ts.map +0 -1
- package/lib/solana/balance-tracker.d.ts.map +0 -1
- package/lib/solana/balance-tracker.js +0 -51
- package/lib/solana/command.d.ts.map +0 -1
- package/lib/solana/command.js +0 -218
- package/lib/solana/solana.d.ts.map +0 -1
- package/lib/sui/balance-tracker.d.ts.map +0 -1
- package/lib/sui/balance-tracker.js +0 -49
- package/lib/sui/command.d.ts.map +0 -1
- package/lib/sui/command.js +0 -160
- package/lib/sui/sui.d.ts.map +0 -1
- package/lib/ton/command.d.ts.map +0 -1
- package/lib/ton/command.js +0 -99
- package/lib/ton/ton.d.ts.map +0 -1
- package/lib/ton/ton.js +0 -97
- package/lib/utils.d.ts.map +0 -1
- package/lib/utils.js +0 -61
package/dist/options.cjs
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get controllerLogLevel () {
|
|
13
|
+
return controllerLogLevel;
|
|
14
|
+
},
|
|
15
|
+
get enableMetrics () {
|
|
16
|
+
return enableMetrics;
|
|
17
|
+
},
|
|
18
|
+
get logLevel () {
|
|
19
|
+
return logLevel;
|
|
20
|
+
},
|
|
21
|
+
get metricsPort () {
|
|
22
|
+
return metricsPort;
|
|
23
|
+
},
|
|
24
|
+
get mnemonicFile () {
|
|
25
|
+
return mnemonicFile;
|
|
26
|
+
},
|
|
27
|
+
get pollingFrequency () {
|
|
28
|
+
return pollingFrequency;
|
|
29
|
+
},
|
|
30
|
+
get priceConfigFile () {
|
|
31
|
+
return priceConfigFile;
|
|
32
|
+
},
|
|
33
|
+
get priceServiceEndpoint () {
|
|
34
|
+
return priceServiceEndpoint;
|
|
35
|
+
},
|
|
36
|
+
get pushingFrequency () {
|
|
37
|
+
return pushingFrequency;
|
|
38
|
+
},
|
|
39
|
+
get pythContractAddress () {
|
|
40
|
+
return pythContractAddress;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
const priceServiceEndpoint = {
|
|
44
|
+
"price-service-endpoint": {
|
|
45
|
+
description: "Endpoint URL for the hermes client. e.g: https://endpoint/example",
|
|
46
|
+
type: "string",
|
|
47
|
+
required: true
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const pythContractAddress = {
|
|
51
|
+
"pyth-contract-address": {
|
|
52
|
+
description: "Pyth contract address. Provide the network name on which Pyth is deployed " + "or the Pyth contract address if you use a local network.",
|
|
53
|
+
type: "string",
|
|
54
|
+
required: true
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const priceConfigFile = {
|
|
58
|
+
"price-config-file": {
|
|
59
|
+
description: "Path to price configuration YAML file.",
|
|
60
|
+
type: "string",
|
|
61
|
+
required: true
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const pollingFrequency = {
|
|
65
|
+
"polling-frequency": {
|
|
66
|
+
description: "The frequency to poll price info data from the network if the RPC is not a websocket.",
|
|
67
|
+
type: "number",
|
|
68
|
+
required: false,
|
|
69
|
+
default: 5
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const pushingFrequency = {
|
|
73
|
+
"pushing-frequency": {
|
|
74
|
+
description: "The frequency to push prices to the RPC. " + "It is better that the value be greater than the block time of the network, so this program confirms " + "it is updated and does not push it twice.",
|
|
75
|
+
type: "number",
|
|
76
|
+
required: false,
|
|
77
|
+
default: 10
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const mnemonicFile = {
|
|
81
|
+
"mnemonic-file": {
|
|
82
|
+
description: "Path to payer mnemonic (private key) file.",
|
|
83
|
+
type: "string",
|
|
84
|
+
required: true
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const logLevel = {
|
|
88
|
+
"log-level": {
|
|
89
|
+
description: "Log level",
|
|
90
|
+
type: "string",
|
|
91
|
+
required: false,
|
|
92
|
+
default: "info",
|
|
93
|
+
choices: [
|
|
94
|
+
"trace",
|
|
95
|
+
"debug",
|
|
96
|
+
"info",
|
|
97
|
+
"warn",
|
|
98
|
+
"error"
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const controllerLogLevel = {
|
|
103
|
+
"controller-log-level": {
|
|
104
|
+
description: "Log level for the controller.",
|
|
105
|
+
type: "string",
|
|
106
|
+
required: false,
|
|
107
|
+
default: "info",
|
|
108
|
+
choices: [
|
|
109
|
+
"trace",
|
|
110
|
+
"debug",
|
|
111
|
+
"info",
|
|
112
|
+
"warn",
|
|
113
|
+
"error"
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
const enableMetrics = {
|
|
118
|
+
"enable-metrics": {
|
|
119
|
+
description: "Enable Prometheus metrics server",
|
|
120
|
+
type: "boolean",
|
|
121
|
+
required: false,
|
|
122
|
+
default: true
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
const metricsPort = {
|
|
126
|
+
"metrics-port": {
|
|
127
|
+
description: "Port for the Prometheus metrics server",
|
|
128
|
+
type: "number",
|
|
129
|
+
required: false,
|
|
130
|
+
default: 9090
|
|
131
|
+
}
|
|
132
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Options } from "yargs";
|
|
1
|
+
import type { Options } from "yargs";
|
|
2
2
|
export declare const priceServiceEndpoint: {
|
|
3
3
|
"price-service-endpoint": Options;
|
|
4
4
|
};
|
|
@@ -29,4 +29,3 @@ export declare const enableMetrics: {
|
|
|
29
29
|
export declare const metricsPort: {
|
|
30
30
|
"metrics-port": Options;
|
|
31
31
|
};
|
|
32
|
-
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "type": "commonjs" }
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/restrict-template-expressions */ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ "use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get UpdateCondition () {
|
|
13
|
+
return UpdateCondition;
|
|
14
|
+
},
|
|
15
|
+
get readPriceConfigFile () {
|
|
16
|
+
return readPriceConfigFile;
|
|
17
|
+
},
|
|
18
|
+
get shouldUpdate () {
|
|
19
|
+
return shouldUpdate;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const _nodefs = /*#__PURE__*/ _interop_require_default(require("node:fs"));
|
|
23
|
+
const _joi = /*#__PURE__*/ _interop_require_default(require("joi"));
|
|
24
|
+
const _yaml = /*#__PURE__*/ _interop_require_default(require("yaml"));
|
|
25
|
+
const _utils = require("./utils.cjs");
|
|
26
|
+
function _interop_require_default(obj) {
|
|
27
|
+
return obj && obj.__esModule ? obj : {
|
|
28
|
+
default: obj
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const PriceConfigFileSchema = _joi.default.array().items(_joi.default.object({
|
|
32
|
+
alias: _joi.default.string().required(),
|
|
33
|
+
id: _joi.default.string().regex(/^(0x)?[a-f0-9]{64}$/).required(),
|
|
34
|
+
time_difference: _joi.default.number().required(),
|
|
35
|
+
price_deviation: _joi.default.number().required(),
|
|
36
|
+
confidence_ratio: _joi.default.number().required(),
|
|
37
|
+
early_update: _joi.default.object({
|
|
38
|
+
time_difference: _joi.default.number().optional(),
|
|
39
|
+
price_deviation: _joi.default.number().optional(),
|
|
40
|
+
confidence_ratio: _joi.default.number().optional()
|
|
41
|
+
}).optional()
|
|
42
|
+
})).unique("id").unique("alias").required();
|
|
43
|
+
function readPriceConfigFile(path) {
|
|
44
|
+
const priceConfigs = _yaml.default.parse(_nodefs.default.readFileSync(path, "utf8"));
|
|
45
|
+
const validationResult = PriceConfigFileSchema.validate(priceConfigs);
|
|
46
|
+
if (validationResult.error !== undefined) {
|
|
47
|
+
throw validationResult.error;
|
|
48
|
+
}
|
|
49
|
+
return priceConfigs.map((priceConfigRaw)=>{
|
|
50
|
+
const priceConfig = {
|
|
51
|
+
alias: priceConfigRaw.alias,
|
|
52
|
+
id: (0, _utils.removeLeading0x)(priceConfigRaw.id),
|
|
53
|
+
timeDifference: priceConfigRaw.time_difference,
|
|
54
|
+
priceDeviation: priceConfigRaw.price_deviation,
|
|
55
|
+
confidenceRatio: priceConfigRaw.confidence_ratio,
|
|
56
|
+
customEarlyUpdate: priceConfigRaw.early_update !== undefined,
|
|
57
|
+
earlyUpdateTimeDifference: priceConfigRaw.early_update?.time_difference,
|
|
58
|
+
earlyUpdatePriceDeviation: priceConfigRaw.early_update?.price_deviation,
|
|
59
|
+
earlyUpdateConfidenceRatio: priceConfigRaw.early_update?.confidence_ratio
|
|
60
|
+
};
|
|
61
|
+
return priceConfig;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
var UpdateCondition = /*#__PURE__*/ function(UpdateCondition) {
|
|
65
|
+
// This price feed must be updated
|
|
66
|
+
UpdateCondition[UpdateCondition["YES"] = 0] = "YES";
|
|
67
|
+
// This price feed may be updated as part of a larger batch
|
|
68
|
+
UpdateCondition[UpdateCondition["EARLY"] = 1] = "EARLY";
|
|
69
|
+
// This price feed shouldn't be updated
|
|
70
|
+
UpdateCondition[UpdateCondition["NO"] = 2] = "NO";
|
|
71
|
+
return UpdateCondition;
|
|
72
|
+
}({});
|
|
73
|
+
function shouldUpdate(priceConfig, sourceLatestPrice, targetLatestPrice, logger) {
|
|
74
|
+
const priceId = priceConfig.id;
|
|
75
|
+
// There is no price to update the target with. So we should not update it.
|
|
76
|
+
if (sourceLatestPrice === undefined) {
|
|
77
|
+
logger.info(`${priceConfig.alias} (${priceId}) is not available on the source network. Ignoring it.`);
|
|
78
|
+
return 2;
|
|
79
|
+
}
|
|
80
|
+
// It means that price never existed there. So we should push the latest price feed.
|
|
81
|
+
if (targetLatestPrice === undefined) {
|
|
82
|
+
logger.info(`${priceConfig.alias} (${priceId}) is not available on the target network. Pushing the price.`);
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
// The current price is not newer than the price onchain
|
|
86
|
+
if (sourceLatestPrice.publishTime < targetLatestPrice.publishTime) {
|
|
87
|
+
return 2;
|
|
88
|
+
}
|
|
89
|
+
const timeDifference = sourceLatestPrice.publishTime - targetLatestPrice.publishTime;
|
|
90
|
+
const priceDeviationPct = Math.abs(Number(sourceLatestPrice.price) - Number(targetLatestPrice.price)) / Number(targetLatestPrice.price) * 100;
|
|
91
|
+
const confidenceRatioPct = Math.abs(Number(sourceLatestPrice.conf) / Number(sourceLatestPrice.price) * 100);
|
|
92
|
+
logger.info({
|
|
93
|
+
sourcePrice: sourceLatestPrice,
|
|
94
|
+
targetPrice: targetLatestPrice,
|
|
95
|
+
symbol: priceConfig.alias
|
|
96
|
+
}, `Analyzing price ${priceConfig.alias} (${priceId}). ` + `Time difference: ${timeDifference} (< ${priceConfig.timeDifference}? / early: < ${priceConfig.earlyUpdateTimeDifference}) OR ` + `Price deviation: ${priceDeviationPct.toFixed(5)}% (< ${priceConfig.priceDeviation}%? / early: < ${priceConfig.earlyUpdatePriceDeviation}%?) OR ` + `Confidence ratio: ${confidenceRatioPct.toFixed(5)}% (< ${priceConfig.confidenceRatio}%? / early: < ${priceConfig.earlyUpdateConfidenceRatio}%?)`);
|
|
97
|
+
if (timeDifference >= priceConfig.timeDifference || priceDeviationPct >= priceConfig.priceDeviation || confidenceRatioPct >= priceConfig.confidenceRatio) {
|
|
98
|
+
return 0;
|
|
99
|
+
} else if (priceConfig.customEarlyUpdate === undefined || !priceConfig.customEarlyUpdate || priceConfig.earlyUpdateTimeDifference !== undefined && timeDifference >= priceConfig.earlyUpdateTimeDifference || priceConfig.earlyUpdatePriceDeviation !== undefined && priceDeviationPct >= priceConfig.earlyUpdatePriceDeviation || priceConfig.earlyUpdateConfidenceRatio !== undefined && confidenceRatioPct >= priceConfig.earlyUpdateConfidenceRatio) {
|
|
100
|
+
return 1;
|
|
101
|
+
} else {
|
|
102
|
+
return 2;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { HexString } from "@pythnetwork/hermes-client";
|
|
2
|
-
import { Logger } from "pino";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import type { HexString } from "@pythnetwork/hermes-client";
|
|
2
|
+
import type { Logger } from "pino";
|
|
3
|
+
import type { PriceInfo } from "./interface.js";
|
|
4
|
+
import type { DurationInSeconds, PctNumber } from "./utils.js";
|
|
5
5
|
export type PriceConfig = {
|
|
6
6
|
alias: string;
|
|
7
7
|
id: HexString;
|
|
@@ -22,8 +22,7 @@ export declare enum UpdateCondition {
|
|
|
22
22
|
/**
|
|
23
23
|
* Checks whether on-chain price needs to be updated with the latest pyth price information.
|
|
24
24
|
*
|
|
25
|
-
* @param priceConfig Config of the price feed to check
|
|
25
|
+
* @param priceConfig - Config of the price feed to check
|
|
26
26
|
* @returns True if the on-chain price needs to be updated.
|
|
27
27
|
*/
|
|
28
28
|
export declare function shouldUpdate(priceConfig: PriceConfig, sourceLatestPrice: PriceInfo | undefined, targetLatestPrice: PriceInfo | undefined, logger: Logger): UpdateCondition;
|
|
29
|
-
//# sourceMappingURL=price-config.d.ts.map
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/* eslint-disable no-console */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable unicorn/prefer-add-event-listener */ /* eslint-disable @typescript-eslint/restrict-template-expressions */ "use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "PythPriceListener", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return PythPriceListener;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _utils = require("./utils.cjs");
|
|
5
12
|
class PythPriceListener {
|
|
6
13
|
hermesClient;
|
|
7
14
|
priceIds;
|
|
@@ -10,21 +17,23 @@ class PythPriceListener {
|
|
|
10
17
|
logger;
|
|
11
18
|
lastUpdated;
|
|
12
19
|
healthCheckInterval;
|
|
13
|
-
constructor(hermesClient, priceItems, logger)
|
|
20
|
+
constructor(hermesClient, priceItems, logger){
|
|
14
21
|
this.hermesClient = hermesClient;
|
|
15
|
-
this.priceIds = priceItems.map((priceItem)
|
|
16
|
-
this.priceIdToAlias = new Map(priceItems.map((priceItem)
|
|
22
|
+
this.priceIds = priceItems.map((priceItem)=>priceItem.id);
|
|
23
|
+
this.priceIdToAlias = new Map(priceItems.map((priceItem)=>[
|
|
24
|
+
priceItem.id,
|
|
25
|
+
priceItem.alias
|
|
26
|
+
]));
|
|
17
27
|
this.latestPriceInfo = new Map();
|
|
18
28
|
this.logger = logger;
|
|
19
29
|
}
|
|
20
30
|
// This method should be awaited on and once it finishes it has the latest value
|
|
21
31
|
// for the given price feeds (if they exist).
|
|
22
32
|
async start() {
|
|
23
|
-
this.startListening();
|
|
33
|
+
await this.startListening();
|
|
24
34
|
// Store health check interval reference
|
|
25
|
-
this.healthCheckInterval = setInterval(()
|
|
26
|
-
if (this.lastUpdated === undefined ||
|
|
27
|
-
this.lastUpdated < Date.now() - 30 * 1000) {
|
|
35
|
+
this.healthCheckInterval = setInterval(()=>{
|
|
36
|
+
if (this.lastUpdated === undefined || this.lastUpdated < Date.now() - 30 * 1000) {
|
|
28
37
|
throw new Error("Hermes Price feeds are not updating.");
|
|
29
38
|
}
|
|
30
39
|
}, 5000);
|
|
@@ -33,34 +42,32 @@ class PythPriceListener {
|
|
|
33
42
|
this.logger.info(`Starting to listen for price updates from Hermes for ${this.priceIds.length} price feeds.`);
|
|
34
43
|
const eventSource = await this.hermesClient.getPriceUpdatesStream(this.priceIds, {
|
|
35
44
|
parsed: true,
|
|
36
|
-
ignoreInvalidPriceIds: true
|
|
45
|
+
ignoreInvalidPriceIds: true
|
|
37
46
|
});
|
|
38
|
-
eventSource.onmessage = (event)
|
|
47
|
+
eventSource.onmessage = (event)=>{
|
|
39
48
|
const priceUpdates = JSON.parse(event.data);
|
|
40
|
-
priceUpdates.parsed
|
|
49
|
+
if (priceUpdates.parsed) for (const priceUpdate of priceUpdates.parsed){
|
|
41
50
|
this.logger.debug(`Received new price feed update from Pyth price service: ${this.priceIdToAlias.get(priceUpdate.id)} ${priceUpdate.id}`);
|
|
42
51
|
// Consider price to be currently available if it is not older than 60s
|
|
43
|
-
const currentPrice = Date.now() / 1000 - priceUpdate.price.publish_time > 60
|
|
44
|
-
? undefined
|
|
45
|
-
: priceUpdate.price;
|
|
52
|
+
const currentPrice = Date.now() / 1000 - priceUpdate.price.publish_time > 60 ? undefined : priceUpdate.price;
|
|
46
53
|
if (currentPrice === undefined) {
|
|
47
54
|
this.logger.debug("Price is older than 60s, skipping");
|
|
48
|
-
|
|
55
|
+
continue;
|
|
49
56
|
}
|
|
50
57
|
const priceInfo = {
|
|
51
58
|
conf: currentPrice.conf,
|
|
52
59
|
price: currentPrice.price,
|
|
53
|
-
publishTime: currentPrice.publish_time
|
|
60
|
+
publishTime: currentPrice.publish_time
|
|
54
61
|
};
|
|
55
62
|
this.latestPriceInfo.set(priceUpdate.id, priceInfo);
|
|
56
63
|
this.lastUpdated = Date.now();
|
|
57
|
-
}
|
|
64
|
+
}
|
|
58
65
|
};
|
|
59
|
-
eventSource.onerror = async (error)
|
|
66
|
+
eventSource.onerror = async (error)=>{
|
|
60
67
|
console.error("Error receiving updates from Hermes:", error);
|
|
61
68
|
eventSource.close();
|
|
62
|
-
await (0,
|
|
63
|
-
this.startListening(); // Attempt to restart the listener
|
|
69
|
+
await (0, _utils.sleep)(5000); // Wait a bit before trying to reconnect
|
|
70
|
+
void this.startListening(); // Attempt to restart the listener
|
|
64
71
|
};
|
|
65
72
|
}
|
|
66
73
|
getLatestPriceInfo(priceId) {
|
|
@@ -72,4 +79,3 @@ class PythPriceListener {
|
|
|
72
79
|
}
|
|
73
80
|
}
|
|
74
81
|
}
|
|
75
|
-
exports.PythPriceListener = PythPriceListener;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { HexString
|
|
2
|
-
import {
|
|
3
|
-
import { Logger } from "pino";
|
|
1
|
+
import type { HexString } from "@pythnetwork/hermes-client";
|
|
2
|
+
import { HermesClient } from "@pythnetwork/hermes-client";
|
|
3
|
+
import type { Logger } from "pino";
|
|
4
|
+
import type { PriceInfo, IPriceListener, PriceItem } from "./interface.js";
|
|
4
5
|
export declare class PythPriceListener implements IPriceListener {
|
|
5
6
|
private hermesClient;
|
|
6
7
|
private priceIds;
|
|
@@ -15,4 +16,3 @@ export declare class PythPriceListener implements IPriceListener {
|
|
|
15
16
|
getLatestPriceInfo(priceId: HexString): PriceInfo | undefined;
|
|
16
17
|
cleanup(): void;
|
|
17
18
|
}
|
|
18
|
-
//# sourceMappingURL=pyth-price-listener.d.ts.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get SolanaBalanceTracker () {
|
|
13
|
+
return SolanaBalanceTracker;
|
|
14
|
+
},
|
|
15
|
+
get createSolanaBalanceTracker () {
|
|
16
|
+
return createSolanaBalanceTracker;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const _web3 = require("@solana/web3.js");
|
|
20
|
+
const _interface = require("../interface.cjs");
|
|
21
|
+
class SolanaBalanceTracker extends _interface.BaseBalanceTracker {
|
|
22
|
+
connection;
|
|
23
|
+
publicKey;
|
|
24
|
+
constructor(config){
|
|
25
|
+
super({
|
|
26
|
+
...config,
|
|
27
|
+
logger: config.logger.child({
|
|
28
|
+
module: "SolanaBalanceTracker"
|
|
29
|
+
})
|
|
30
|
+
});
|
|
31
|
+
this.connection = config.connection;
|
|
32
|
+
this.publicKey = config.publicKey;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Solana-specific implementation of balance update
|
|
36
|
+
*/ async updateBalance() {
|
|
37
|
+
try {
|
|
38
|
+
const balanceInLamports = await this.connection.getBalance(this.publicKey);
|
|
39
|
+
// Convert from lamports to SOL
|
|
40
|
+
const balanceInSol = balanceInLamports / _web3.LAMPORTS_PER_SOL;
|
|
41
|
+
this.metrics.updateWalletBalance(this.address, this.network, balanceInSol);
|
|
42
|
+
this.logger.debug(`Updated Solana wallet balance: ${this.address} = ${balanceInSol.toString()} SOL (${balanceInLamports.toString()} lamports)`);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
this.logger.error({
|
|
45
|
+
error
|
|
46
|
+
}, "Error fetching Solana wallet balance for metrics");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function createSolanaBalanceTracker(params) {
|
|
51
|
+
return new SolanaBalanceTracker({
|
|
52
|
+
connection: params.connection,
|
|
53
|
+
publicKey: params.publicKey,
|
|
54
|
+
address: params.publicKey.toString(),
|
|
55
|
+
network: params.network,
|
|
56
|
+
updateInterval: params.updateInterval,
|
|
57
|
+
metrics: params.metrics,
|
|
58
|
+
logger: params.logger
|
|
59
|
+
});
|
|
60
|
+
}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { Connection, PublicKey } from "@solana/web3.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import type { Logger } from "pino";
|
|
3
|
+
import type { BaseBalanceTrackerConfig, IBalanceTracker } from "../interface.js";
|
|
4
|
+
import { BaseBalanceTracker } from "../interface.js";
|
|
5
|
+
import { PricePusherMetrics } from "../metrics.js";
|
|
6
|
+
import type { DurationInSeconds } from "../utils.js";
|
|
6
7
|
/**
|
|
7
8
|
* Solana-specific configuration for balance tracker
|
|
8
9
|
*/
|
|
9
|
-
export
|
|
10
|
+
export type SolanaBalanceTrackerConfig = {
|
|
10
11
|
/** Solana connection instance */
|
|
11
12
|
connection: Connection;
|
|
12
13
|
/** Solana public key */
|
|
13
14
|
publicKey: PublicKey;
|
|
14
|
-
}
|
|
15
|
+
} & BaseBalanceTrackerConfig;
|
|
15
16
|
/**
|
|
16
17
|
* Solana-specific implementation of the balance tracker
|
|
17
18
|
*/
|
|
@@ -27,16 +28,15 @@ export declare class SolanaBalanceTracker extends BaseBalanceTracker {
|
|
|
27
28
|
/**
|
|
28
29
|
* Parameters for creating a Solana balance tracker
|
|
29
30
|
*/
|
|
30
|
-
export
|
|
31
|
+
export type CreateSolanaBalanceTrackerParams = {
|
|
31
32
|
connection: Connection;
|
|
32
33
|
publicKey: PublicKey;
|
|
33
34
|
network: string;
|
|
34
35
|
updateInterval: DurationInSeconds;
|
|
35
36
|
metrics: PricePusherMetrics;
|
|
36
37
|
logger: Logger;
|
|
37
|
-
}
|
|
38
|
+
};
|
|
38
39
|
/**
|
|
39
40
|
* Factory function to create a balance tracker for Solana
|
|
40
41
|
*/
|
|
41
42
|
export declare function createSolanaBalanceTracker(params: CreateSolanaBalanceTrackerParams): IBalanceTracker;
|
|
42
|
-
//# sourceMappingURL=balance-tracker.d.ts.map
|