@pythnetwork/price-pusher 10.2.0 → 10.3.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/{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} +35 -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 +10 -11
- 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 -152
- 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 -223
- 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
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/restrict-template-expressions */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-explicit-any */ "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 default () {
|
|
13
|
+
return _default;
|
|
14
|
+
},
|
|
15
|
+
get onBundleResult () {
|
|
16
|
+
return onBundleResult;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const _nodefs = /*#__PURE__*/ _interop_require_default(require("node:fs"));
|
|
20
|
+
const _nodewallet = /*#__PURE__*/ _interop_require_default(require("@coral-xyz/anchor/dist/cjs/nodewallet.js"));
|
|
21
|
+
const _hermesclient = require("@pythnetwork/hermes-client");
|
|
22
|
+
const _pythsolanareceiver = require("@pythnetwork/pyth-solana-receiver");
|
|
23
|
+
const _web3 = require("@solana/web3.js");
|
|
24
|
+
const _searcher = require("jito-ts/dist/sdk/block-engine/searcher");
|
|
25
|
+
const _pino = require("pino");
|
|
26
|
+
const _options = /*#__PURE__*/ _interop_require_wildcard(require("../options.cjs"));
|
|
27
|
+
const _priceconfig = require("../price-config.cjs");
|
|
28
|
+
const _pythpricelistener = require("../pyth-price-listener.cjs");
|
|
29
|
+
const _solana = require("./solana.cjs");
|
|
30
|
+
const _controller = require("../controller.cjs");
|
|
31
|
+
const _metrics = require("../metrics.cjs");
|
|
32
|
+
const _utils = require("../utils.cjs");
|
|
33
|
+
const _balancetracker = require("./balance-tracker.cjs");
|
|
34
|
+
function _interop_require_default(obj) {
|
|
35
|
+
return obj && obj.__esModule ? obj : {
|
|
36
|
+
default: obj
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
40
|
+
if (typeof WeakMap !== "function") return null;
|
|
41
|
+
var cacheBabelInterop = new WeakMap();
|
|
42
|
+
var cacheNodeInterop = new WeakMap();
|
|
43
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
44
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
45
|
+
})(nodeInterop);
|
|
46
|
+
}
|
|
47
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
48
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
49
|
+
return obj;
|
|
50
|
+
}
|
|
51
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
52
|
+
return {
|
|
53
|
+
default: obj
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
57
|
+
if (cache && cache.has(obj)) {
|
|
58
|
+
return cache.get(obj);
|
|
59
|
+
}
|
|
60
|
+
var newObj = {
|
|
61
|
+
__proto__: null
|
|
62
|
+
};
|
|
63
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
64
|
+
for(var key in obj){
|
|
65
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
66
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
67
|
+
if (desc && (desc.get || desc.set)) {
|
|
68
|
+
Object.defineProperty(newObj, key, desc);
|
|
69
|
+
} else {
|
|
70
|
+
newObj[key] = obj[key];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
newObj.default = obj;
|
|
75
|
+
if (cache) {
|
|
76
|
+
cache.set(obj, newObj);
|
|
77
|
+
}
|
|
78
|
+
return newObj;
|
|
79
|
+
}
|
|
80
|
+
const _default = {
|
|
81
|
+
command: "solana",
|
|
82
|
+
describe: "run price pusher for solana",
|
|
83
|
+
builder: {
|
|
84
|
+
endpoint: {
|
|
85
|
+
description: "Solana RPC API endpoint",
|
|
86
|
+
type: "string",
|
|
87
|
+
required: true
|
|
88
|
+
},
|
|
89
|
+
"keypair-file": {
|
|
90
|
+
description: "Path to a keypair file",
|
|
91
|
+
type: "string",
|
|
92
|
+
required: true
|
|
93
|
+
},
|
|
94
|
+
"shard-id": {
|
|
95
|
+
description: "Shard ID",
|
|
96
|
+
type: "number",
|
|
97
|
+
required: true
|
|
98
|
+
},
|
|
99
|
+
"compute-unit-price-micro-lamports": {
|
|
100
|
+
description: "Priority fee per compute unit",
|
|
101
|
+
type: "number",
|
|
102
|
+
default: 50_000
|
|
103
|
+
},
|
|
104
|
+
"jito-endpoints": {
|
|
105
|
+
description: "Jito endpoint(s) - comma-separated list of endpoints",
|
|
106
|
+
type: "string",
|
|
107
|
+
optional: true
|
|
108
|
+
},
|
|
109
|
+
"jito-keypair-file": {
|
|
110
|
+
description: "Path to the jito keypair file (need for grpc authentication)",
|
|
111
|
+
type: "string",
|
|
112
|
+
optional: true
|
|
113
|
+
},
|
|
114
|
+
"jito-tip-lamports": {
|
|
115
|
+
description: "Lamports to tip the jito builder",
|
|
116
|
+
type: "number",
|
|
117
|
+
optional: true
|
|
118
|
+
},
|
|
119
|
+
"dynamic-jito-tips": {
|
|
120
|
+
description: "Use dynamic jito tips",
|
|
121
|
+
type: "boolean",
|
|
122
|
+
default: false
|
|
123
|
+
},
|
|
124
|
+
"max-jito-tip-lamports": {
|
|
125
|
+
description: "Maximum jito tip lamports",
|
|
126
|
+
type: "number",
|
|
127
|
+
default: _web3.LAMPORTS_PER_SOL / 100
|
|
128
|
+
},
|
|
129
|
+
"jito-bundle-size": {
|
|
130
|
+
description: "Number of transactions in each Jito bundle",
|
|
131
|
+
type: "number",
|
|
132
|
+
default: 5
|
|
133
|
+
},
|
|
134
|
+
"updates-per-jito-bundle": {
|
|
135
|
+
description: "Number of price updates in each Jito bundle",
|
|
136
|
+
type: "number",
|
|
137
|
+
default: 6
|
|
138
|
+
},
|
|
139
|
+
"address-lookup-table-account": {
|
|
140
|
+
description: "The pubkey of the ALT to use when updating price feeds",
|
|
141
|
+
type: "string",
|
|
142
|
+
optional: true
|
|
143
|
+
},
|
|
144
|
+
"treasury-id": {
|
|
145
|
+
description: "The treasuryId to use. Useful when the corresponding treasury account is indexed in the ALT passed to --address-lookup-table-account. This is a tx size optimization and is optional; if not set, a random treasury account will be used.",
|
|
146
|
+
type: "number",
|
|
147
|
+
optional: true
|
|
148
|
+
},
|
|
149
|
+
..._options.priceConfigFile,
|
|
150
|
+
..._options.priceServiceEndpoint,
|
|
151
|
+
..._options.pythContractAddress,
|
|
152
|
+
..._options.pollingFrequency,
|
|
153
|
+
..._options.pushingFrequency,
|
|
154
|
+
..._options.logLevel,
|
|
155
|
+
..._options.controllerLogLevel,
|
|
156
|
+
..._options.enableMetrics,
|
|
157
|
+
..._options.metricsPort
|
|
158
|
+
},
|
|
159
|
+
handler: async function(argv) {
|
|
160
|
+
const { endpoint, keypairFile, shardId, computeUnitPriceMicroLamports, priceConfigFile, priceServiceEndpoint, pythContractAddress, pushingFrequency, pollingFrequency, jitoEndpoints, jitoKeypairFile, jitoTipLamports, dynamicJitoTips, maxJitoTipLamports, updatesPerJitoBundle, addressLookupTableAccount, treasuryId, logLevel, controllerLogLevel, enableMetrics, metricsPort } = argv;
|
|
161
|
+
const logger = (0, _pino.pino)({
|
|
162
|
+
level: logLevel
|
|
163
|
+
});
|
|
164
|
+
const priceConfigs = (0, _priceconfig.readPriceConfigFile)(priceConfigFile);
|
|
165
|
+
const hermesClient = new _hermesclient.HermesClient(priceServiceEndpoint);
|
|
166
|
+
// Initialize metrics if enabled
|
|
167
|
+
let metrics;
|
|
168
|
+
if (enableMetrics) {
|
|
169
|
+
metrics = new _metrics.PricePusherMetrics(logger.child({
|
|
170
|
+
module: "Metrics"
|
|
171
|
+
}));
|
|
172
|
+
metrics.start(metricsPort);
|
|
173
|
+
logger.info(`Metrics server started on port ${metricsPort}`);
|
|
174
|
+
}
|
|
175
|
+
let priceItems = priceConfigs.map(({ id, alias })=>({
|
|
176
|
+
id,
|
|
177
|
+
alias
|
|
178
|
+
}));
|
|
179
|
+
// Better to filter out invalid price items before creating the pyth listener
|
|
180
|
+
const { existingPriceItems, invalidPriceItems } = await (0, _utils.filterInvalidPriceItems)(hermesClient, priceItems);
|
|
181
|
+
if (invalidPriceItems.length > 0) {
|
|
182
|
+
logger.error(`Invalid price id submitted for: ${invalidPriceItems.map(({ alias })=>alias).join(", ")}`);
|
|
183
|
+
}
|
|
184
|
+
priceItems = existingPriceItems;
|
|
185
|
+
const pythListener = new _pythpricelistener.PythPriceListener(hermesClient, priceItems, logger.child({
|
|
186
|
+
module: "PythPriceListener"
|
|
187
|
+
}));
|
|
188
|
+
const keypair = _web3.Keypair.fromSecretKey(Uint8Array.from(JSON.parse(_nodefs.default.readFileSync(keypairFile, "ascii"))));
|
|
189
|
+
const wallet = new _nodewallet.default(keypair);
|
|
190
|
+
const connection = new _web3.Connection(endpoint, "processed");
|
|
191
|
+
const pythSolanaReceiver = new _pythsolanareceiver.PythSolanaReceiver({
|
|
192
|
+
connection,
|
|
193
|
+
wallet,
|
|
194
|
+
pushOracleProgramId: new _web3.PublicKey(pythContractAddress),
|
|
195
|
+
treasuryId: treasuryId
|
|
196
|
+
});
|
|
197
|
+
// Create and start the balance tracker if metrics are enabled
|
|
198
|
+
if (metrics) {
|
|
199
|
+
const balanceTracker = (0, _balancetracker.createSolanaBalanceTracker)({
|
|
200
|
+
connection,
|
|
201
|
+
publicKey: keypair.publicKey,
|
|
202
|
+
network: "solana",
|
|
203
|
+
updateInterval: 60,
|
|
204
|
+
metrics,
|
|
205
|
+
logger
|
|
206
|
+
});
|
|
207
|
+
// Start the balance tracker
|
|
208
|
+
await balanceTracker.start();
|
|
209
|
+
}
|
|
210
|
+
// Fetch the account lookup table if provided
|
|
211
|
+
const lookupTableAccount = addressLookupTableAccount ? await connection.getAddressLookupTable(new _web3.PublicKey(addressLookupTableAccount)).then((result)=>result.value ?? undefined) : undefined;
|
|
212
|
+
let solanaPricePusher;
|
|
213
|
+
if (jitoTipLamports) {
|
|
214
|
+
const jitoKeypair = _web3.Keypair.fromSecretKey(Uint8Array.from(JSON.parse(_nodefs.default.readFileSync(jitoKeypairFile, "ascii"))));
|
|
215
|
+
const jitoEndpointsList = jitoEndpoints.split(",").map((endpoint)=>endpoint.trim());
|
|
216
|
+
const jitoClients = jitoEndpointsList.map((endpoint)=>{
|
|
217
|
+
logger.info(`Constructing Jito searcher client from endpoint ${endpoint}`);
|
|
218
|
+
return (0, _searcher.searcherClient)(endpoint, jitoKeypair);
|
|
219
|
+
});
|
|
220
|
+
solanaPricePusher = new _solana.SolanaPricePusherJito(pythSolanaReceiver, hermesClient, logger.child({
|
|
221
|
+
module: "SolanaPricePusherJito"
|
|
222
|
+
}), shardId, jitoTipLamports, dynamicJitoTips, maxJitoTipLamports, jitoClients, updatesPerJitoBundle, // Set max retry time to pushing frequency, since we want to stop retrying before the next push attempt
|
|
223
|
+
pushingFrequency * 1000, lookupTableAccount);
|
|
224
|
+
for (const [index, client] of jitoClients.entries()){
|
|
225
|
+
onBundleResult(client, logger.child({
|
|
226
|
+
module: `JitoClient-${index}`
|
|
227
|
+
}));
|
|
228
|
+
}
|
|
229
|
+
} else {
|
|
230
|
+
solanaPricePusher = new _solana.SolanaPricePusher(pythSolanaReceiver, hermesClient, logger.child({
|
|
231
|
+
module: "SolanaPricePusher"
|
|
232
|
+
}), shardId, computeUnitPriceMicroLamports, lookupTableAccount);
|
|
233
|
+
}
|
|
234
|
+
const solanaPriceListener = new _solana.SolanaPriceListener(pythSolanaReceiver, shardId, priceItems, logger.child({
|
|
235
|
+
module: "SolanaPriceListener"
|
|
236
|
+
}), {
|
|
237
|
+
pollingFrequency
|
|
238
|
+
});
|
|
239
|
+
const controller = new _controller.Controller(priceConfigs, pythListener, solanaPriceListener, solanaPricePusher, logger.child({
|
|
240
|
+
module: "Controller"
|
|
241
|
+
}, {
|
|
242
|
+
level: controllerLogLevel
|
|
243
|
+
}), {
|
|
244
|
+
pushingFrequency,
|
|
245
|
+
metrics: metrics
|
|
246
|
+
});
|
|
247
|
+
void controller.start();
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
const onBundleResult = (c, logger)=>{
|
|
251
|
+
try {
|
|
252
|
+
c.onBundleResult(// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
253
|
+
()=>{}, (err)=>{
|
|
254
|
+
logger.error(err, "Error in bundle result");
|
|
255
|
+
});
|
|
256
|
+
} catch (error) {
|
|
257
|
+
logger.error(error, "Exception in bundle result");
|
|
258
|
+
}
|
|
259
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Options } from "yargs";
|
|
2
1
|
import { SearcherClient } from "jito-ts/dist/sdk/block-engine/searcher";
|
|
3
|
-
import { Logger } from "pino";
|
|
2
|
+
import type { Logger } from "pino";
|
|
3
|
+
import type { Options } from "yargs";
|
|
4
4
|
declare const _default: {
|
|
5
5
|
command: string;
|
|
6
6
|
describe: string;
|
|
@@ -32,4 +32,3 @@ declare const _default: {
|
|
|
32
32
|
};
|
|
33
33
|
export default _default;
|
|
34
34
|
export declare const onBundleResult: (c: SearcherClient, logger: Logger) => void;
|
|
35
|
-
//# sourceMappingURL=command.d.ts.map
|
|
@@ -1,20 +1,35 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-explicit-any */ "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 SolanaPriceListener () {
|
|
13
|
+
return SolanaPriceListener;
|
|
14
|
+
},
|
|
15
|
+
get SolanaPricePusher () {
|
|
16
|
+
return SolanaPricePusher;
|
|
17
|
+
},
|
|
18
|
+
get SolanaPricePusherJito () {
|
|
19
|
+
return SolanaPricePusherJito;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const _priceservicesdk = require("@pythnetwork/price-service-sdk");
|
|
23
|
+
const _solanautils = require("@pythnetwork/solana-utils");
|
|
24
|
+
const _web3 = require("@solana/web3.js");
|
|
25
|
+
const _interface = require("../interface.cjs");
|
|
8
26
|
const HEALTH_CHECK_TIMEOUT_SECONDS = 60;
|
|
9
|
-
class SolanaPriceListener extends
|
|
27
|
+
class SolanaPriceListener extends _interface.ChainPriceListener {
|
|
10
28
|
pythSolanaReceiver;
|
|
11
29
|
shardId;
|
|
12
30
|
logger;
|
|
13
|
-
constructor(pythSolanaReceiver, shardId, priceItems, logger, config)
|
|
14
|
-
super(config.pollingFrequency, priceItems);
|
|
15
|
-
this.pythSolanaReceiver = pythSolanaReceiver;
|
|
16
|
-
this.shardId = shardId;
|
|
17
|
-
this.logger = logger;
|
|
31
|
+
constructor(pythSolanaReceiver, shardId, priceItems, logger, config){
|
|
32
|
+
super(config.pollingFrequency, priceItems), this.pythSolanaReceiver = pythSolanaReceiver, this.shardId = shardId, this.logger = logger;
|
|
18
33
|
}
|
|
19
34
|
// Checking the health of the Solana connection by checking the last block time
|
|
20
35
|
// and ensuring it is not older than 30 seconds.
|
|
@@ -22,44 +37,38 @@ class SolanaPriceListener extends interface_1.ChainPriceListener {
|
|
|
22
37
|
const slot = await this.pythSolanaReceiver.connection.getSlot("finalized");
|
|
23
38
|
try {
|
|
24
39
|
const blockTime = await this.pythSolanaReceiver.connection.getBlockTime(slot);
|
|
25
|
-
if (blockTime === null ||
|
|
26
|
-
|
|
27
|
-
if (blockTime !== null) {
|
|
28
|
-
this.logger.info(`Solana connection is behind by ${Date.now() / 1000 - blockTime} seconds`);
|
|
29
|
-
}
|
|
40
|
+
if ((blockTime === null || blockTime < Date.now() / 1000 - HEALTH_CHECK_TIMEOUT_SECONDS) && blockTime !== null) {
|
|
41
|
+
this.logger.info(`Solana connection is behind by ${(Date.now() / 1000 - blockTime).toString()} seconds`);
|
|
30
42
|
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
} catch (error) {
|
|
44
|
+
this.logger.error({
|
|
45
|
+
err: error
|
|
46
|
+
}, "checkHealth failed");
|
|
34
47
|
}
|
|
35
48
|
}
|
|
36
49
|
async start() {
|
|
37
50
|
// Frequently check the RPC connection to ensure it is healthy
|
|
38
|
-
setInterval(this.checkHealth
|
|
51
|
+
setInterval(()=>void this.checkHealth(), 5000);
|
|
39
52
|
await super.start();
|
|
40
53
|
}
|
|
41
54
|
async getOnChainPriceInfo(priceId) {
|
|
42
55
|
try {
|
|
43
56
|
const priceFeedAccount = await this.pythSolanaReceiver.fetchPriceFeedAccount(this.shardId, Buffer.from(priceId, "hex"));
|
|
44
|
-
this.logger.debug(`Polled a Solana on chain price for feed ${this.priceIdToAlias.get(priceId)} (${priceId}).`);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
catch (err) {
|
|
57
|
-
this.logger.error({ err, priceId }, `Polling on-chain price failed.`);
|
|
57
|
+
this.logger.debug(`Polled a Solana on chain price for feed ${this.priceIdToAlias.get(priceId)?.toString() ?? ""} (${priceId}).`);
|
|
58
|
+
return priceFeedAccount ? {
|
|
59
|
+
conf: priceFeedAccount.priceMessage.conf.toString(),
|
|
60
|
+
price: priceFeedAccount.priceMessage.price.toString(),
|
|
61
|
+
publishTime: priceFeedAccount.priceMessage.publishTime.toNumber()
|
|
62
|
+
} : undefined;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
this.logger.error({
|
|
65
|
+
err: error,
|
|
66
|
+
priceId
|
|
67
|
+
}, `Polling on-chain price failed.`);
|
|
58
68
|
return undefined;
|
|
59
69
|
}
|
|
60
70
|
}
|
|
61
71
|
}
|
|
62
|
-
exports.SolanaPriceListener = SolanaPriceListener;
|
|
63
72
|
class SolanaPricePusher {
|
|
64
73
|
pythSolanaReceiver;
|
|
65
74
|
hermesClient;
|
|
@@ -67,7 +76,7 @@ class SolanaPricePusher {
|
|
|
67
76
|
shardId;
|
|
68
77
|
computeUnitPriceMicroLamports;
|
|
69
78
|
addressLookupTableAccount;
|
|
70
|
-
constructor(pythSolanaReceiver, hermesClient, logger, shardId, computeUnitPriceMicroLamports, addressLookupTableAccount)
|
|
79
|
+
constructor(pythSolanaReceiver, hermesClient, logger, shardId, computeUnitPriceMicroLamports, addressLookupTableAccount){
|
|
71
80
|
this.pythSolanaReceiver = pythSolanaReceiver;
|
|
72
81
|
this.hermesClient = hermesClient;
|
|
73
82
|
this.logger = logger;
|
|
@@ -79,43 +88,42 @@ class SolanaPricePusher {
|
|
|
79
88
|
if (priceIds.length === 0) {
|
|
80
89
|
return;
|
|
81
90
|
}
|
|
82
|
-
const shuffledPriceIds = priceIds
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
const shuffledPriceIds = priceIds.map((x)=>{
|
|
92
|
+
return {
|
|
93
|
+
element: x,
|
|
94
|
+
key: Math.random()
|
|
95
|
+
};
|
|
96
|
+
}).sort((a, b)=>a.key - b.key).map((x)=>x.element);
|
|
88
97
|
let priceFeedUpdateData;
|
|
89
98
|
try {
|
|
90
99
|
const response = await this.hermesClient.getLatestPriceUpdates(shuffledPriceIds, {
|
|
91
100
|
encoding: "base64",
|
|
92
|
-
ignoreInvalidPriceIds: true
|
|
101
|
+
ignoreInvalidPriceIds: true
|
|
93
102
|
});
|
|
94
103
|
priceFeedUpdateData = response.binary.data;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
this.logger.error(err, "getPriceFeedsUpdateData failed:");
|
|
104
|
+
} catch (error) {
|
|
105
|
+
this.logger.error(error, "getPriceFeedsUpdateData failed:");
|
|
98
106
|
return;
|
|
99
107
|
}
|
|
100
108
|
const transactionBuilder = this.pythSolanaReceiver.newTransactionBuilder({
|
|
101
|
-
closeUpdateAccounts: true
|
|
109
|
+
closeUpdateAccounts: true
|
|
102
110
|
}, this.addressLookupTableAccount);
|
|
103
111
|
await transactionBuilder.addUpdatePriceFeed(priceFeedUpdateData, this.shardId);
|
|
104
112
|
const transactions = await transactionBuilder.buildVersionedTransactions({
|
|
105
113
|
computeUnitPriceMicroLamports: this.computeUnitPriceMicroLamports,
|
|
106
|
-
tightComputeBudget: true
|
|
114
|
+
tightComputeBudget: true
|
|
107
115
|
});
|
|
108
116
|
try {
|
|
109
|
-
const signatures = await (0,
|
|
110
|
-
this.logger.info({
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
117
|
+
const signatures = await (0, _solanautils.sendTransactions)(transactions, this.pythSolanaReceiver.connection, this.pythSolanaReceiver.wallet);
|
|
118
|
+
this.logger.info({
|
|
119
|
+
signatures
|
|
120
|
+
}, "updatePriceFeed successful");
|
|
121
|
+
} catch (error) {
|
|
122
|
+
this.logger.error(error, "updatePriceFeed failed");
|
|
114
123
|
return;
|
|
115
124
|
}
|
|
116
125
|
}
|
|
117
126
|
}
|
|
118
|
-
exports.SolanaPricePusher = SolanaPricePusher;
|
|
119
127
|
class SolanaPricePusherJito {
|
|
120
128
|
pythSolanaReceiver;
|
|
121
129
|
hermesClient;
|
|
@@ -128,7 +136,7 @@ class SolanaPricePusherJito {
|
|
|
128
136
|
updatesPerJitoBundle;
|
|
129
137
|
maxRetryTimeMs;
|
|
130
138
|
addressLookupTableAccount;
|
|
131
|
-
constructor(pythSolanaReceiver, hermesClient, logger, shardId, defaultJitoTipLamports, dynamicJitoTips, maxJitoTipLamports, searcherClients, updatesPerJitoBundle, maxRetryTimeMs, addressLookupTableAccount)
|
|
139
|
+
constructor(pythSolanaReceiver, hermesClient, logger, shardId, defaultJitoTipLamports, dynamicJitoTips, maxJitoTipLamports, searcherClients, updatesPerJitoBundle, maxRetryTimeMs, addressLookupTableAccount){
|
|
132
140
|
this.pythSolanaReceiver = pythSolanaReceiver;
|
|
133
141
|
this.hermesClient = hermesClient;
|
|
134
142
|
this.logger = logger;
|
|
@@ -145,50 +153,54 @@ class SolanaPricePusherJito {
|
|
|
145
153
|
try {
|
|
146
154
|
const response = await fetch("https://bundles.jito.wtf/api/v1/bundles/tip_floor");
|
|
147
155
|
if (!response.ok) {
|
|
148
|
-
this.logger.error({
|
|
156
|
+
this.logger.error({
|
|
157
|
+
status: response.status,
|
|
158
|
+
statusText: response.statusText
|
|
159
|
+
}, "getRecentJitoTips http request failed");
|
|
149
160
|
return undefined;
|
|
150
161
|
}
|
|
162
|
+
// TODO: fix this type here to be more specific
|
|
151
163
|
const data = await response.json();
|
|
152
|
-
return Math.floor(Number(data[0].landed_tips_50th_percentile) *
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
this.logger.error({
|
|
164
|
+
return Math.floor(Number(data[0].landed_tips_50th_percentile) * _web3.LAMPORTS_PER_SOL);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
167
|
+
this.logger.error({
|
|
168
|
+
err: error
|
|
169
|
+
}, "getRecentJitoTips failed");
|
|
156
170
|
return undefined;
|
|
157
171
|
}
|
|
158
172
|
}
|
|
159
173
|
async updatePriceFeed(priceIds) {
|
|
160
174
|
const recentJitoTip = await this.getRecentJitoTipLamports();
|
|
161
|
-
const jitoTip = this.dynamicJitoTips && recentJitoTip !== undefined
|
|
162
|
-
? Math.max(this.defaultJitoTipLamports, recentJitoTip)
|
|
163
|
-
: this.defaultJitoTipLamports;
|
|
175
|
+
const jitoTip = this.dynamicJitoTips && recentJitoTip !== undefined ? Math.max(this.defaultJitoTipLamports, recentJitoTip) : this.defaultJitoTipLamports;
|
|
164
176
|
const cappedJitoTip = Math.min(jitoTip, this.maxJitoTipLamports);
|
|
165
|
-
this.logger.info({
|
|
177
|
+
this.logger.info({
|
|
178
|
+
cappedJitoTip
|
|
179
|
+
}, "using jito tip of");
|
|
166
180
|
let priceFeedUpdateData;
|
|
167
181
|
try {
|
|
168
182
|
const response = await this.hermesClient.getLatestPriceUpdates(priceIds, {
|
|
169
|
-
encoding: "base64"
|
|
183
|
+
encoding: "base64"
|
|
170
184
|
});
|
|
171
185
|
priceFeedUpdateData = response.binary.data;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
this.logger.error(err, "getPriceFeedsUpdateData failed");
|
|
186
|
+
} catch (error) {
|
|
187
|
+
this.logger.error(error, "getPriceFeedsUpdateData failed");
|
|
175
188
|
return;
|
|
176
189
|
}
|
|
177
|
-
for
|
|
190
|
+
for(let i = 0; i < priceIds.length; i += this.updatesPerJitoBundle){
|
|
178
191
|
const transactionBuilder = this.pythSolanaReceiver.newTransactionBuilder({
|
|
179
|
-
closeUpdateAccounts: true
|
|
192
|
+
closeUpdateAccounts: true
|
|
180
193
|
}, this.addressLookupTableAccount);
|
|
181
|
-
await transactionBuilder.addUpdatePriceFeed(priceFeedUpdateData.map((x)
|
|
182
|
-
return (0,
|
|
194
|
+
await transactionBuilder.addUpdatePriceFeed(priceFeedUpdateData.map((x)=>{
|
|
195
|
+
return (0, _priceservicesdk.sliceAccumulatorUpdateData)(Buffer.from(x, "base64"), i, i + this.updatesPerJitoBundle).toString("base64");
|
|
183
196
|
}), this.shardId);
|
|
184
197
|
const transactions = await transactionBuilder.buildVersionedTransactions({
|
|
185
198
|
jitoTipLamports: cappedJitoTip,
|
|
186
|
-
tightComputeBudget: true
|
|
199
|
+
tightComputeBudget: true
|
|
187
200
|
});
|
|
188
|
-
await (0,
|
|
189
|
-
maxRetryTimeMs: this.maxRetryTimeMs
|
|
201
|
+
await (0, _solanautils.sendTransactionsJito)(transactions, this.searcherClients, this.pythSolanaReceiver.wallet, {
|
|
202
|
+
maxRetryTimeMs: this.maxRetryTimeMs
|
|
190
203
|
}, this.logger);
|
|
191
204
|
}
|
|
192
205
|
}
|
|
193
206
|
}
|
|
194
|
-
exports.SolanaPricePusherJito = SolanaPricePusherJito;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { PythSolanaReceiver } from "@pythnetwork/pyth-solana-receiver";
|
|
2
|
-
import { ChainPriceListener, IPricePusher, PriceInfo, PriceItem } from "../interface";
|
|
3
|
-
import { DurationInSeconds } from "../utils";
|
|
4
1
|
import { HermesClient } from "@pythnetwork/hermes-client";
|
|
5
|
-
import {
|
|
6
|
-
import { Logger } from "pino";
|
|
2
|
+
import { PythSolanaReceiver } from "@pythnetwork/pyth-solana-receiver";
|
|
7
3
|
import { AddressLookupTableAccount } from "@solana/web3.js";
|
|
4
|
+
import { SearcherClient } from "jito-ts/dist/sdk/block-engine/searcher";
|
|
5
|
+
import type { Logger } from "pino";
|
|
6
|
+
import type { IPricePusher, PriceInfo, PriceItem } from "../interface.js";
|
|
7
|
+
import { ChainPriceListener } from "../interface.js";
|
|
8
|
+
import type { DurationInSeconds } from "../utils.js";
|
|
8
9
|
export declare class SolanaPriceListener extends ChainPriceListener {
|
|
9
10
|
private pythSolanaReceiver;
|
|
10
11
|
private shardId;
|
|
@@ -42,4 +43,3 @@ export declare class SolanaPricePusherJito implements IPricePusher {
|
|
|
42
43
|
getRecentJitoTipLamports(): Promise<number | undefined>;
|
|
43
44
|
updatePriceFeed(priceIds: string[]): Promise<void>;
|
|
44
45
|
}
|
|
45
|
-
//# sourceMappingURL=solana.d.ts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
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 SuiBalanceTracker () {
|
|
13
|
+
return SuiBalanceTracker;
|
|
14
|
+
},
|
|
15
|
+
get createSuiBalanceTracker () {
|
|
16
|
+
return createSuiBalanceTracker;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const _interface = require("../interface.cjs");
|
|
20
|
+
class SuiBalanceTracker extends _interface.BaseBalanceTracker {
|
|
21
|
+
client;
|
|
22
|
+
constructor(config){
|
|
23
|
+
super({
|
|
24
|
+
...config,
|
|
25
|
+
logger: config.logger.child({
|
|
26
|
+
module: "SuiBalanceTracker"
|
|
27
|
+
})
|
|
28
|
+
});
|
|
29
|
+
this.client = config.client;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Sui-specific implementation of balance update
|
|
33
|
+
*/ async updateBalance() {
|
|
34
|
+
try {
|
|
35
|
+
const balance = await this.client.getBalance({
|
|
36
|
+
owner: this.address
|
|
37
|
+
});
|
|
38
|
+
// Convert to a normalized number for reporting (SUI has 9 decimals)
|
|
39
|
+
const normalizedBalance = Number(balance.totalBalance) / 1e9;
|
|
40
|
+
this.metrics.updateWalletBalance(this.address, this.network, normalizedBalance);
|
|
41
|
+
this.logger.debug(`Updated Sui wallet balance: ${this.address} = ${normalizedBalance.toString()} SUI`);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
this.logger.error({
|
|
44
|
+
error
|
|
45
|
+
}, "Error fetching Sui wallet balance for metrics");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function createSuiBalanceTracker(params) {
|
|
50
|
+
return new SuiBalanceTracker({
|
|
51
|
+
client: params.client,
|
|
52
|
+
address: params.address,
|
|
53
|
+
network: params.network,
|
|
54
|
+
updateInterval: params.updateInterval,
|
|
55
|
+
metrics: params.metrics,
|
|
56
|
+
logger: params.logger
|
|
57
|
+
});
|
|
58
|
+
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { SuiClient } from "@mysten/sui/client";
|
|
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
|
* Sui-specific configuration for balance tracker
|
|
8
9
|
*/
|
|
9
|
-
export
|
|
10
|
+
export type SuiBalanceTrackerConfig = {
|
|
10
11
|
/** Sui client instance */
|
|
11
12
|
client: SuiClient;
|
|
12
|
-
}
|
|
13
|
+
} & BaseBalanceTrackerConfig;
|
|
13
14
|
/**
|
|
14
15
|
* Sui-specific implementation of the balance tracker
|
|
15
16
|
*/
|
|
@@ -24,16 +25,15 @@ export declare class SuiBalanceTracker extends BaseBalanceTracker {
|
|
|
24
25
|
/**
|
|
25
26
|
* Parameters for creating a Sui balance tracker
|
|
26
27
|
*/
|
|
27
|
-
export
|
|
28
|
+
export type CreateSuiBalanceTrackerParams = {
|
|
28
29
|
client: SuiClient;
|
|
29
30
|
address: string;
|
|
30
31
|
network: string;
|
|
31
32
|
updateInterval: DurationInSeconds;
|
|
32
33
|
metrics: PricePusherMetrics;
|
|
33
34
|
logger: Logger;
|
|
34
|
-
}
|
|
35
|
+
};
|
|
35
36
|
/**
|
|
36
37
|
* Factory function to create a balance tracker for Sui chain
|
|
37
38
|
*/
|
|
38
39
|
export declare function createSuiBalanceTracker(params: CreateSuiBalanceTrackerParams): IBalanceTracker;
|
|
39
|
-
//# sourceMappingURL=balance-tracker.d.ts.map
|