@pythnetwork/price-pusher 6.7.0 → 7.0.0-alpha
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 +26 -14
- package/lib/aptos/aptos.d.ts +5 -2
- package/lib/aptos/aptos.d.ts.map +1 -1
- package/lib/aptos/aptos.js +19 -19
- package/lib/aptos/command.d.ts +3 -0
- package/lib/aptos/command.d.ts.map +1 -1
- package/lib/aptos/command.js +12 -14
- package/lib/controller.d.ts +3 -1
- package/lib/controller.d.ts.map +1 -1
- package/lib/controller.js +11 -4
- package/lib/evm/command.d.ts +3 -0
- package/lib/evm/command.d.ts.map +1 -1
- package/lib/evm/command.js +14 -16
- package/lib/evm/custom-gas-station.d.ts +4 -2
- package/lib/evm/custom-gas-station.d.ts.map +1 -1
- package/lib/evm/custom-gas-station.js +7 -6
- package/lib/evm/evm.d.ts +7 -3
- package/lib/evm/evm.d.ts.map +1 -1
- package/lib/evm/evm.js +25 -24
- package/lib/index.js +3 -0
- package/lib/injective/command.d.ts +3 -0
- package/lib/injective/command.d.ts.map +1 -1
- package/lib/injective/command.js +11 -13
- package/lib/injective/injective.d.ts +5 -2
- package/lib/injective/injective.d.ts.map +1 -1
- package/lib/injective/injective.js +22 -22
- package/lib/interface.d.ts +1 -2
- package/lib/interface.d.ts.map +1 -1
- package/lib/interface.js +1 -4
- package/lib/near/command.d.ts +3 -0
- package/lib/near/command.d.ts.map +1 -1
- package/lib/near/command.js +14 -13
- package/lib/near/near.d.ts +5 -2
- package/lib/near/near.d.ts.map +1 -1
- package/lib/near/near.js +19 -17
- package/lib/options.d.ts +9 -0
- package/lib/options.d.ts.map +1 -1
- package/lib/options.js +28 -1
- package/lib/price-config.d.ts +2 -1
- package/lib/price-config.d.ts.map +1 -1
- package/lib/price-config.js +4 -6
- package/lib/pyth-price-listener.d.ts +3 -1
- package/lib/pyth-price-listener.d.ts.map +1 -1
- package/lib/pyth-price-listener.js +4 -2
- package/lib/solana/command.d.ts +5 -1
- package/lib/solana/command.d.ts.map +1 -1
- package/lib/solana/command.js +16 -18
- package/lib/solana/solana.d.ts +9 -5
- package/lib/solana/solana.d.ts.map +1 -1
- package/lib/solana/solana.js +42 -39
- package/lib/sui/command.d.ts +4 -0
- package/lib/sui/command.d.ts.map +1 -1
- package/lib/sui/command.js +18 -14
- package/lib/sui/sui.d.ts +6 -3
- package/lib/sui/sui.d.ts.map +1 -1
- package/lib/sui/sui.js +36 -30
- package/package.json +21 -11
package/lib/sui/sui.js
CHANGED
|
@@ -12,10 +12,12 @@ const MAX_NUM_OBJECTS_IN_ARGUMENT = 510;
|
|
|
12
12
|
class SuiPriceListener extends interface_1.ChainPriceListener {
|
|
13
13
|
pythClient;
|
|
14
14
|
provider;
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
logger;
|
|
16
|
+
constructor(pythStateId, wormholeStateId, endpoint, priceItems, logger, config) {
|
|
17
|
+
super(config.pollingFrequency, priceItems);
|
|
17
18
|
this.provider = new client_1.SuiClient({ url: endpoint });
|
|
18
19
|
this.pythClient = new pyth_sui_js_1.SuiPythClient(this.provider, pythStateId, wormholeStateId);
|
|
20
|
+
this.logger = logger;
|
|
19
21
|
}
|
|
20
22
|
async getOnChainPriceInfo(priceId) {
|
|
21
23
|
try {
|
|
@@ -46,9 +48,8 @@ class SuiPriceListener extends interface_1.ChainPriceListener {
|
|
|
46
48
|
publishTime: Number(timestamp),
|
|
47
49
|
};
|
|
48
50
|
}
|
|
49
|
-
catch (
|
|
50
|
-
|
|
51
|
-
console.error(e);
|
|
51
|
+
catch (err) {
|
|
52
|
+
this.logger.error(err, `Polling Sui on-chain price for ${priceId} failed.`);
|
|
52
53
|
return undefined;
|
|
53
54
|
}
|
|
54
55
|
}
|
|
@@ -71,6 +72,7 @@ exports.SuiPriceListener = SuiPriceListener;
|
|
|
71
72
|
class SuiPricePusher {
|
|
72
73
|
signer;
|
|
73
74
|
provider;
|
|
75
|
+
logger;
|
|
74
76
|
priceServiceConnection;
|
|
75
77
|
pythPackageId;
|
|
76
78
|
pythStateId;
|
|
@@ -79,9 +81,10 @@ class SuiPricePusher {
|
|
|
79
81
|
gasBudget;
|
|
80
82
|
gasPool;
|
|
81
83
|
pythClient;
|
|
82
|
-
constructor(signer, provider, priceServiceConnection, pythPackageId, pythStateId, wormholePackageId, wormholeStateId, endpoint, keypair, gasBudget, gasPool, pythClient) {
|
|
84
|
+
constructor(signer, provider, logger, priceServiceConnection, pythPackageId, pythStateId, wormholePackageId, wormholeStateId, endpoint, keypair, gasBudget, gasPool, pythClient) {
|
|
83
85
|
this.signer = signer;
|
|
84
86
|
this.provider = provider;
|
|
87
|
+
this.logger = logger;
|
|
85
88
|
this.priceServiceConnection = priceServiceConnection;
|
|
86
89
|
this.pythPackageId = pythPackageId;
|
|
87
90
|
this.pythStateId = pythStateId;
|
|
@@ -123,16 +126,16 @@ class SuiPricePusher {
|
|
|
123
126
|
* Create a price pusher with a pool of `numGasObjects` gas coins that will be used to send transactions.
|
|
124
127
|
* The gas coins of the wallet for the provided keypair will be merged and then evenly split into `numGasObjects`.
|
|
125
128
|
*/
|
|
126
|
-
static async createWithAutomaticGasPool(priceServiceConnection, pythStateId, wormholeStateId, endpoint, keypair, gasBudget, numGasObjects) {
|
|
129
|
+
static async createWithAutomaticGasPool(priceServiceConnection, logger, pythStateId, wormholeStateId, endpoint, keypair, gasBudget, numGasObjects, ignoreGasObjects) {
|
|
127
130
|
if (numGasObjects > MAX_NUM_OBJECTS_IN_ARGUMENT) {
|
|
128
131
|
throw new Error(`numGasObjects cannot be greater than ${MAX_NUM_OBJECTS_IN_ARGUMENT} until we implement split chunking`);
|
|
129
132
|
}
|
|
130
133
|
const provider = new client_1.SuiClient({ url: endpoint });
|
|
131
134
|
const pythPackageId = await SuiPricePusher.getPackageId(provider, pythStateId);
|
|
132
135
|
const wormholePackageId = await SuiPricePusher.getPackageId(provider, wormholeStateId);
|
|
133
|
-
const gasPool = await SuiPricePusher.initializeGasPool(keypair, provider, numGasObjects);
|
|
136
|
+
const gasPool = await SuiPricePusher.initializeGasPool(keypair, provider, numGasObjects, ignoreGasObjects, logger);
|
|
134
137
|
const pythClient = new pyth_sui_js_1.SuiPythClient(provider, pythStateId, wormholeStateId);
|
|
135
|
-
return new SuiPricePusher(keypair, provider, priceServiceConnection, pythPackageId, pythStateId, wormholePackageId, wormholeStateId, endpoint, keypair, gasBudget, gasPool, pythClient);
|
|
138
|
+
return new SuiPricePusher(keypair, provider, logger, priceServiceConnection, pythPackageId, pythStateId, wormholePackageId, wormholeStateId, endpoint, keypair, gasBudget, gasPool, pythClient);
|
|
136
139
|
}
|
|
137
140
|
async updatePriceFeed(priceIds, pubTimesToPush) {
|
|
138
141
|
if (priceIds.length === 0) {
|
|
@@ -141,7 +144,7 @@ class SuiPricePusher {
|
|
|
141
144
|
if (priceIds.length !== pubTimesToPush.length)
|
|
142
145
|
throw new Error("Invalid arguments");
|
|
143
146
|
if (this.gasPool.length === 0) {
|
|
144
|
-
|
|
147
|
+
this.logger.warn("Skipping update: no available gas coin.");
|
|
145
148
|
return;
|
|
146
149
|
}
|
|
147
150
|
// 3 price feeds per transaction is the optimal number for gas cost.
|
|
@@ -167,7 +170,7 @@ class SuiPricePusher {
|
|
|
167
170
|
async sendTransactionBlock(tx) {
|
|
168
171
|
const gasObject = this.gasPool.shift();
|
|
169
172
|
if (gasObject === undefined) {
|
|
170
|
-
|
|
173
|
+
this.logger.warn("No available gas coin. Skipping push.");
|
|
171
174
|
return;
|
|
172
175
|
}
|
|
173
176
|
let nextGasObject = undefined;
|
|
@@ -184,24 +187,20 @@ class SuiPricePusher {
|
|
|
184
187
|
nextGasObject = result.effects?.mutated
|
|
185
188
|
?.map((obj) => obj.reference)
|
|
186
189
|
.find((ref) => ref.objectId === gasObject.objectId);
|
|
187
|
-
|
|
190
|
+
this.logger.info({ hash: result.digest }, "Successfully updated price with transaction digest");
|
|
188
191
|
}
|
|
189
|
-
catch (
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
192
|
+
catch (err) {
|
|
193
|
+
if (String(err).includes("Balance of gas object") ||
|
|
194
|
+
String(err).includes("GasBalanceTooLow")) {
|
|
195
|
+
this.logger.error(err, "Insufficient gas balance");
|
|
193
196
|
// If the error is caused by insufficient gas, we should panic
|
|
194
|
-
throw
|
|
197
|
+
throw err;
|
|
195
198
|
}
|
|
196
199
|
else {
|
|
200
|
+
this.logger.error(err, "Failed to update price. Trying to refresh gas object references.");
|
|
197
201
|
// Refresh the coin object here in case the error is caused by an object version mismatch.
|
|
198
202
|
nextGasObject = await SuiPricePusher.tryRefreshObjectReference(this.provider, gasObject);
|
|
199
203
|
}
|
|
200
|
-
console.error(e);
|
|
201
|
-
if ("data" in e) {
|
|
202
|
-
console.error("Error has .data field:");
|
|
203
|
-
console.error(JSON.stringify(e.data));
|
|
204
|
-
}
|
|
205
204
|
}
|
|
206
205
|
if (nextGasObject !== undefined) {
|
|
207
206
|
this.gasPool.push(nextGasObject);
|
|
@@ -209,9 +208,14 @@ class SuiPricePusher {
|
|
|
209
208
|
}
|
|
210
209
|
// This function will smash all coins owned by the signer into one, and then
|
|
211
210
|
// split them equally into numGasObjects.
|
|
212
|
-
|
|
211
|
+
// ignoreGasObjects is a list of gas objects that will be ignored during the
|
|
212
|
+
// merging -- use this to store any locked objects on initialization.
|
|
213
|
+
static async initializeGasPool(signer, provider, numGasObjects, ignoreGasObjects, logger) {
|
|
213
214
|
const signerAddress = await signer.toSuiAddress();
|
|
214
|
-
|
|
215
|
+
if (ignoreGasObjects.length > 0) {
|
|
216
|
+
logger.info({ ignoreGasObjects }, "Ignoring some gas objects for coin merging");
|
|
217
|
+
}
|
|
218
|
+
const consolidatedCoin = await SuiPricePusher.mergeGasCoinsIntoOne(signer, provider, signerAddress, ignoreGasObjects, logger);
|
|
215
219
|
const coinResult = await provider.getObject({
|
|
216
220
|
id: consolidatedCoin.objectId,
|
|
217
221
|
options: { showContent: true },
|
|
@@ -228,7 +232,7 @@ class SuiPricePusher {
|
|
|
228
232
|
throw new Error("Bad coin object");
|
|
229
233
|
const splitAmount = (BigInt(balance) - BigInt(GAS_FEE_FOR_SPLIT)) / BigInt(numGasObjects);
|
|
230
234
|
const gasPool = await SuiPricePusher.splitGasCoinEqually(signer, provider, signerAddress, Number(splitAmount), numGasObjects, consolidatedCoin);
|
|
231
|
-
|
|
235
|
+
logger.info({ gasPool }, "Gas pool is filled with coins");
|
|
232
236
|
return gasPool;
|
|
233
237
|
}
|
|
234
238
|
// Attempt to refresh the version of the provided object reference to point to the current version
|
|
@@ -297,7 +301,7 @@ class SuiPricePusher {
|
|
|
297
301
|
}
|
|
298
302
|
return newCoins;
|
|
299
303
|
}
|
|
300
|
-
static async mergeGasCoinsIntoOne(signer, provider, owner) {
|
|
304
|
+
static async mergeGasCoinsIntoOne(signer, provider, owner, initialLockedAddresses, logger) {
|
|
301
305
|
const gasCoins = await SuiPricePusher.getAllGasCoins(provider, owner);
|
|
302
306
|
// skip merging if there is only one coin
|
|
303
307
|
if (gasCoins.length === 1) {
|
|
@@ -306,6 +310,7 @@ class SuiPricePusher {
|
|
|
306
310
|
const gasCoinsChunks = chunkArray(gasCoins, MAX_NUM_GAS_OBJECTS_IN_PTB - 2);
|
|
307
311
|
let finalCoin;
|
|
308
312
|
const lockedAddresses = new Set();
|
|
313
|
+
initialLockedAddresses.forEach((value) => lockedAddresses.add(value));
|
|
309
314
|
for (let i = 0; i < gasCoinsChunks.length; i++) {
|
|
310
315
|
const mergeTx = new transactions_1.TransactionBlock();
|
|
311
316
|
let coins = gasCoinsChunks[i];
|
|
@@ -322,9 +327,10 @@ class SuiPricePusher {
|
|
|
322
327
|
options: { showEffects: true },
|
|
323
328
|
});
|
|
324
329
|
}
|
|
325
|
-
catch (
|
|
326
|
-
|
|
327
|
-
|
|
330
|
+
catch (err) {
|
|
331
|
+
logger.error(err, "Merge transaction failed with error");
|
|
332
|
+
if (String(err).includes("quorum of validators because of locked objects. Retried a conflicting transaction")) {
|
|
333
|
+
Object.values(err.data).forEach((lockedObjects) => {
|
|
328
334
|
lockedObjects.forEach((lockedObject) => {
|
|
329
335
|
lockedAddresses.add(lockedObject[0]);
|
|
330
336
|
});
|
|
@@ -333,7 +339,7 @@ class SuiPricePusher {
|
|
|
333
339
|
i--;
|
|
334
340
|
continue;
|
|
335
341
|
}
|
|
336
|
-
throw
|
|
342
|
+
throw err;
|
|
337
343
|
}
|
|
338
344
|
const error = mergeResult?.effects?.status.error;
|
|
339
345
|
if (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pythnetwork/price-pusher",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0-alpha",
|
|
4
4
|
"description": "Pyth Price Pusher",
|
|
5
5
|
"homepage": "https://pyth.network",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
"lint": "eslint src/",
|
|
27
27
|
"start": "node lib/index.js",
|
|
28
28
|
"dev": "ts-node src/index.ts",
|
|
29
|
-
"prepublishOnly": "
|
|
30
|
-
"preversion": "
|
|
31
|
-
"version": "
|
|
29
|
+
"prepublishOnly": "pnpm run build && pnpm test && pnpm run lint",
|
|
30
|
+
"preversion": "pnpm run lint",
|
|
31
|
+
"version": "pnpm run format && git add -A src"
|
|
32
32
|
},
|
|
33
33
|
"keywords": [
|
|
34
34
|
"pyth",
|
|
@@ -42,30 +42,40 @@
|
|
|
42
42
|
"@types/ethereum-protocol": "^1.0.2",
|
|
43
43
|
"@types/jest": "^27.4.1",
|
|
44
44
|
"@types/yargs": "^17.0.10",
|
|
45
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
46
|
-
"@typescript-eslint/parser": "^
|
|
45
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
46
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
47
47
|
"eslint": "^8.13.0",
|
|
48
48
|
"jest": "^29.7.0",
|
|
49
|
+
"pino-pretty": "^11.2.1",
|
|
49
50
|
"prettier": "^2.6.2",
|
|
50
51
|
"ts-jest": "^29.1.1",
|
|
52
|
+
"ts-node": "^10.9.1",
|
|
51
53
|
"typescript": "^5.3.3"
|
|
52
54
|
},
|
|
53
55
|
"dependencies": {
|
|
56
|
+
"@coral-xyz/anchor": "^0.30.0",
|
|
57
|
+
"@injectivelabs/networks": "^1.14.6",
|
|
54
58
|
"@injectivelabs/sdk-ts": "1.10.72",
|
|
55
59
|
"@mysten/sui.js": "^0.49.1",
|
|
56
|
-
"@pythnetwork/price-service-client": "
|
|
57
|
-
"@pythnetwork/
|
|
58
|
-
"@pythnetwork/pyth-
|
|
59
|
-
"@pythnetwork/pyth-
|
|
60
|
+
"@pythnetwork/price-service-client": "1.9.0",
|
|
61
|
+
"@pythnetwork/price-service-sdk": "^1.7.1",
|
|
62
|
+
"@pythnetwork/pyth-sdk-solidity": "3.1.0",
|
|
63
|
+
"@pythnetwork/pyth-solana-receiver": "0.8.0",
|
|
64
|
+
"@pythnetwork/pyth-sui-js": "2.0.0",
|
|
65
|
+
"@pythnetwork/solana-utils": "0.4.1",
|
|
66
|
+
"@solana/web3.js": "^1.93.0",
|
|
60
67
|
"@truffle/hdwallet-provider": "^2.1.3",
|
|
68
|
+
"@types/pino": "^7.0.5",
|
|
61
69
|
"aptos": "^1.8.5",
|
|
62
70
|
"jito-ts": "^3.0.1",
|
|
63
71
|
"joi": "^17.6.0",
|
|
64
72
|
"near-api-js": "^3.0.2",
|
|
73
|
+
"pino": "^9.2.0",
|
|
65
74
|
"web3": "^1.8.1",
|
|
75
|
+
"web3-core": "^1.8.1",
|
|
66
76
|
"web3-eth-contract": "^1.8.1",
|
|
67
77
|
"yaml": "^2.1.1",
|
|
68
78
|
"yargs": "^17.5.1"
|
|
69
79
|
},
|
|
70
|
-
"gitHead": "
|
|
80
|
+
"gitHead": "40a63bf8f80d9f929eeddfb7c4e4f9d0e56d93fb"
|
|
71
81
|
}
|