@pythnetwork/price-pusher 6.8.0 → 7.0.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.
Files changed (56) hide show
  1. package/README.md +26 -14
  2. package/lib/aptos/aptos.d.ts +5 -2
  3. package/lib/aptos/aptos.d.ts.map +1 -1
  4. package/lib/aptos/aptos.js +31 -31
  5. package/lib/aptos/command.d.ts +3 -0
  6. package/lib/aptos/command.d.ts.map +1 -1
  7. package/lib/aptos/command.js +12 -14
  8. package/lib/controller.d.ts +3 -1
  9. package/lib/controller.d.ts.map +1 -1
  10. package/lib/controller.js +11 -4
  11. package/lib/evm/command.d.ts +3 -0
  12. package/lib/evm/command.d.ts.map +1 -1
  13. package/lib/evm/command.js +14 -16
  14. package/lib/evm/custom-gas-station.d.ts +4 -2
  15. package/lib/evm/custom-gas-station.d.ts.map +1 -1
  16. package/lib/evm/custom-gas-station.js +7 -6
  17. package/lib/evm/evm.d.ts +7 -3
  18. package/lib/evm/evm.d.ts.map +1 -1
  19. package/lib/evm/evm.js +25 -24
  20. package/lib/injective/command.d.ts +3 -0
  21. package/lib/injective/command.d.ts.map +1 -1
  22. package/lib/injective/command.js +11 -13
  23. package/lib/injective/injective.d.ts +5 -2
  24. package/lib/injective/injective.d.ts.map +1 -1
  25. package/lib/injective/injective.js +24 -23
  26. package/lib/interface.d.ts +1 -2
  27. package/lib/interface.d.ts.map +1 -1
  28. package/lib/interface.js +1 -4
  29. package/lib/near/command.d.ts +3 -0
  30. package/lib/near/command.d.ts.map +1 -1
  31. package/lib/near/command.js +14 -13
  32. package/lib/near/near.d.ts +5 -2
  33. package/lib/near/near.d.ts.map +1 -1
  34. package/lib/near/near.js +19 -17
  35. package/lib/options.d.ts +9 -0
  36. package/lib/options.d.ts.map +1 -1
  37. package/lib/options.js +28 -1
  38. package/lib/price-config.d.ts +2 -1
  39. package/lib/price-config.d.ts.map +1 -1
  40. package/lib/price-config.js +4 -6
  41. package/lib/pyth-price-listener.d.ts +4 -1
  42. package/lib/pyth-price-listener.d.ts.map +1 -1
  43. package/lib/pyth-price-listener.js +14 -2
  44. package/lib/solana/command.d.ts +5 -1
  45. package/lib/solana/command.d.ts.map +1 -1
  46. package/lib/solana/command.js +16 -18
  47. package/lib/solana/solana.d.ts +11 -5
  48. package/lib/solana/solana.d.ts.map +1 -1
  49. package/lib/solana/solana.js +41 -18
  50. package/lib/sui/command.d.ts +3 -0
  51. package/lib/sui/command.d.ts.map +1 -1
  52. package/lib/sui/command.js +12 -14
  53. package/lib/sui/sui.d.ts +6 -7
  54. package/lib/sui/sui.d.ts.map +1 -1
  55. package/lib/sui/sui.js +42 -63
  56. 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
- constructor(pythStateId, wormholeStateId, endpoint, priceItems, config) {
16
- super("sui", config.pollingFrequency, priceItems);
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 (e) {
50
- console.error(`Polling Sui on-chain price for ${priceId} failed. Error:`);
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,22 +72,16 @@ exports.SuiPriceListener = SuiPriceListener;
71
72
  class SuiPricePusher {
72
73
  signer;
73
74
  provider;
75
+ logger;
74
76
  priceServiceConnection;
75
- pythPackageId;
76
- pythStateId;
77
- wormholePackageId;
78
- wormholeStateId;
79
77
  gasBudget;
80
78
  gasPool;
81
79
  pythClient;
82
- constructor(signer, provider, priceServiceConnection, pythPackageId, pythStateId, wormholePackageId, wormholeStateId, endpoint, keypair, gasBudget, gasPool, pythClient) {
80
+ constructor(signer, provider, logger, priceServiceConnection, gasBudget, gasPool, pythClient) {
83
81
  this.signer = signer;
84
82
  this.provider = provider;
83
+ this.logger = logger;
85
84
  this.priceServiceConnection = priceServiceConnection;
86
- this.pythPackageId = pythPackageId;
87
- this.pythStateId = pythStateId;
88
- this.wormholePackageId = wormholePackageId;
89
- this.wormholeStateId = wormholeStateId;
90
85
  this.gasBudget = gasBudget;
91
86
  this.gasPool = gasPool;
92
87
  this.pythClient = pythClient;
@@ -123,16 +118,14 @@ class SuiPricePusher {
123
118
  * Create a price pusher with a pool of `numGasObjects` gas coins that will be used to send transactions.
124
119
  * The gas coins of the wallet for the provided keypair will be merged and then evenly split into `numGasObjects`.
125
120
  */
126
- static async createWithAutomaticGasPool(priceServiceConnection, pythStateId, wormholeStateId, endpoint, keypair, gasBudget, numGasObjects, ignoreGasObjects) {
121
+ static async createWithAutomaticGasPool(priceServiceConnection, logger, pythStateId, wormholeStateId, endpoint, keypair, gasBudget, numGasObjects, ignoreGasObjects) {
127
122
  if (numGasObjects > MAX_NUM_OBJECTS_IN_ARGUMENT) {
128
123
  throw new Error(`numGasObjects cannot be greater than ${MAX_NUM_OBJECTS_IN_ARGUMENT} until we implement split chunking`);
129
124
  }
130
125
  const provider = new client_1.SuiClient({ url: endpoint });
131
- const pythPackageId = await SuiPricePusher.getPackageId(provider, pythStateId);
132
- const wormholePackageId = await SuiPricePusher.getPackageId(provider, wormholeStateId);
133
- const gasPool = await SuiPricePusher.initializeGasPool(keypair, provider, numGasObjects, ignoreGasObjects);
126
+ const gasPool = await SuiPricePusher.initializeGasPool(keypair, provider, numGasObjects, ignoreGasObjects, logger);
134
127
  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);
128
+ return new SuiPricePusher(keypair, provider, logger, priceServiceConnection, gasBudget, gasPool, pythClient);
136
129
  }
137
130
  async updatePriceFeed(priceIds, pubTimesToPush) {
138
131
  if (priceIds.length === 0) {
@@ -141,7 +134,7 @@ class SuiPricePusher {
141
134
  if (priceIds.length !== pubTimesToPush.length)
142
135
  throw new Error("Invalid arguments");
143
136
  if (this.gasPool.length === 0) {
144
- console.warn("Skipping update: no available gas coin.");
137
+ this.logger.warn("Skipping update: no available gas coin.");
145
138
  return;
146
139
  }
147
140
  // 3 price feeds per transaction is the optimal number for gas cost.
@@ -167,7 +160,7 @@ class SuiPricePusher {
167
160
  async sendTransactionBlock(tx) {
168
161
  const gasObject = this.gasPool.shift();
169
162
  if (gasObject === undefined) {
170
- console.warn("No available gas coin. Skipping push.");
163
+ this.logger.warn("No available gas coin. Skipping push.");
171
164
  return;
172
165
  }
173
166
  let nextGasObject = undefined;
@@ -184,24 +177,20 @@ class SuiPricePusher {
184
177
  nextGasObject = result.effects?.mutated
185
178
  ?.map((obj) => obj.reference)
186
179
  .find((ref) => ref.objectId === gasObject.objectId);
187
- console.log("Successfully updated price with transaction digest ", result.digest);
180
+ this.logger.info({ hash: result.digest }, "Successfully updated price with transaction digest");
188
181
  }
189
- catch (e) {
190
- console.log("Error when signAndExecuteTransactionBlock");
191
- if (String(e).includes("Balance of gas object") ||
192
- String(e).includes("GasBalanceTooLow")) {
182
+ catch (err) {
183
+ if (String(err).includes("Balance of gas object") ||
184
+ String(err).includes("GasBalanceTooLow")) {
185
+ this.logger.error(err, "Insufficient gas balance");
193
186
  // If the error is caused by insufficient gas, we should panic
194
- throw e;
187
+ throw err;
195
188
  }
196
189
  else {
190
+ this.logger.error(err, "Failed to update price. Trying to refresh gas object references.");
197
191
  // Refresh the coin object here in case the error is caused by an object version mismatch.
198
192
  nextGasObject = await SuiPricePusher.tryRefreshObjectReference(this.provider, gasObject);
199
193
  }
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
194
  }
206
195
  if (nextGasObject !== undefined) {
207
196
  this.gasPool.push(nextGasObject);
@@ -211,13 +200,12 @@ class SuiPricePusher {
211
200
  // split them equally into numGasObjects.
212
201
  // ignoreGasObjects is a list of gas objects that will be ignored during the
213
202
  // merging -- use this to store any locked objects on initialization.
214
- static async initializeGasPool(signer, provider, numGasObjects, ignoreGasObjects) {
215
- const signerAddress = await signer.toSuiAddress();
203
+ static async initializeGasPool(signer, provider, numGasObjects, ignoreGasObjects, logger) {
204
+ const signerAddress = signer.toSuiAddress();
216
205
  if (ignoreGasObjects.length > 0) {
217
- console.log("Ignoring some gas objects for coin merging:");
218
- console.log(ignoreGasObjects);
206
+ logger.info({ ignoreGasObjects }, "Ignoring some gas objects for coin merging");
219
207
  }
220
- const consolidatedCoin = await SuiPricePusher.mergeGasCoinsIntoOne(signer, provider, signerAddress, ignoreGasObjects);
208
+ const consolidatedCoin = await SuiPricePusher.mergeGasCoinsIntoOne(signer, provider, signerAddress, ignoreGasObjects, logger);
221
209
  const coinResult = await provider.getObject({
222
210
  id: consolidatedCoin.objectId,
223
211
  options: { showContent: true },
@@ -234,28 +222,22 @@ class SuiPricePusher {
234
222
  throw new Error("Bad coin object");
235
223
  const splitAmount = (BigInt(balance) - BigInt(GAS_FEE_FOR_SPLIT)) / BigInt(numGasObjects);
236
224
  const gasPool = await SuiPricePusher.splitGasCoinEqually(signer, provider, signerAddress, Number(splitAmount), numGasObjects, consolidatedCoin);
237
- console.log("Gas pool is filled with coins: ", gasPool);
225
+ logger.info({ gasPool }, "Gas pool is filled with coins");
238
226
  return gasPool;
239
227
  }
240
228
  // Attempt to refresh the version of the provided object reference to point to the current version
241
- // of the object. Return the provided object reference if an error occurs or the object could not
242
- // be retrieved.
229
+ // of the object. Throws an error if the object cannot be refreshed.
243
230
  static async tryRefreshObjectReference(provider, ref) {
244
- try {
245
- const objectResponse = await provider.getObject({ id: ref.objectId });
246
- if (objectResponse.data !== undefined) {
247
- return {
248
- digest: objectResponse.data.digest,
249
- objectId: objectResponse.data.objectId,
250
- version: objectResponse.data.version,
251
- };
252
- }
253
- else {
254
- return ref;
255
- }
231
+ const objectResponse = await provider.getObject({ id: ref.objectId });
232
+ if (objectResponse.data !== undefined) {
233
+ return {
234
+ digest: objectResponse.data.digest,
235
+ objectId: objectResponse.data.objectId,
236
+ version: objectResponse.data.version,
237
+ };
256
238
  }
257
- catch (error) {
258
- return ref;
239
+ else {
240
+ throw new Error("Failed to refresh object reference");
259
241
  }
260
242
  }
261
243
  static async getAllGasCoins(provider, owner) {
@@ -303,7 +285,7 @@ class SuiPricePusher {
303
285
  }
304
286
  return newCoins;
305
287
  }
306
- static async mergeGasCoinsIntoOne(signer, provider, owner, initialLockedAddresses) {
288
+ static async mergeGasCoinsIntoOne(signer, provider, owner, initialLockedAddresses, logger) {
307
289
  const gasCoins = await SuiPricePusher.getAllGasCoins(provider, owner);
308
290
  // skip merging if there is only one coin
309
291
  if (gasCoins.length === 1) {
@@ -329,13 +311,10 @@ class SuiPricePusher {
329
311
  options: { showEffects: true },
330
312
  });
331
313
  }
332
- catch (e) {
333
- console.log("Merge transaction failed with error:");
334
- console.log(e);
335
- console.log(e.data);
336
- console.log(JSON.stringify(e));
337
- if (String(e).includes("quorum of validators because of locked objects. Retried a conflicting transaction")) {
338
- Object.values(e.data).forEach((lockedObjects) => {
314
+ catch (err) {
315
+ logger.error(err, "Merge transaction failed with error");
316
+ if (String(err).includes("quorum of validators because of locked objects. Retried a conflicting transaction")) {
317
+ Object.values(err.data).forEach((lockedObjects) => {
339
318
  lockedObjects.forEach((lockedObject) => {
340
319
  lockedAddresses.add(lockedObject[0]);
341
320
  });
@@ -344,7 +323,7 @@ class SuiPricePusher {
344
323
  i--;
345
324
  continue;
346
325
  }
347
- throw e;
326
+ throw err;
348
327
  }
349
328
  const error = mergeResult?.effects?.status.error;
350
329
  if (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pythnetwork/price-pusher",
3
- "version": "6.8.0",
3
+ "version": "7.0.0",
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": "npm run build && npm test && npm run lint",
30
- "preversion": "npm run lint",
31
- "version": "npm run format && git add -A src"
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": "^5.20.0",
46
- "@typescript-eslint/parser": "^5.20.0",
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/pyth-sdk-solidity": "*",
58
- "@pythnetwork/pyth-solana-receiver": "*",
59
- "@pythnetwork/pyth-sui-js": "*",
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": "641a4bdd6306ccb62ece63b800f9727f54f816df"
80
+ "gitHead": "05dc9c8e06b9643bb365db494e67cac843d7b90a"
71
81
  }