@pythnetwork/price-pusher 6.8.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/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 +27 -18
- package/lib/sui/command.d.ts +3 -0
- package/lib/sui/command.d.ts.map +1 -1
- package/lib/sui/command.js +12 -14
- package/lib/sui/sui.d.ts +6 -3
- package/lib/sui/sui.d.ts.map +1 -1
- package/lib/sui/sui.js +31 -36
- 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, ignoreGasObjects) {
|
|
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, ignoreGasObjects);
|
|
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);
|
|
@@ -211,13 +210,12 @@ class SuiPricePusher {
|
|
|
211
210
|
// split them equally into numGasObjects.
|
|
212
211
|
// ignoreGasObjects is a list of gas objects that will be ignored during the
|
|
213
212
|
// merging -- use this to store any locked objects on initialization.
|
|
214
|
-
static async initializeGasPool(signer, provider, numGasObjects, ignoreGasObjects) {
|
|
213
|
+
static async initializeGasPool(signer, provider, numGasObjects, ignoreGasObjects, logger) {
|
|
215
214
|
const signerAddress = await signer.toSuiAddress();
|
|
216
215
|
if (ignoreGasObjects.length > 0) {
|
|
217
|
-
|
|
218
|
-
console.log(ignoreGasObjects);
|
|
216
|
+
logger.info({ ignoreGasObjects }, "Ignoring some gas objects for coin merging");
|
|
219
217
|
}
|
|
220
|
-
const consolidatedCoin = await SuiPricePusher.mergeGasCoinsIntoOne(signer, provider, signerAddress, ignoreGasObjects);
|
|
218
|
+
const consolidatedCoin = await SuiPricePusher.mergeGasCoinsIntoOne(signer, provider, signerAddress, ignoreGasObjects, logger);
|
|
221
219
|
const coinResult = await provider.getObject({
|
|
222
220
|
id: consolidatedCoin.objectId,
|
|
223
221
|
options: { showContent: true },
|
|
@@ -234,7 +232,7 @@ class SuiPricePusher {
|
|
|
234
232
|
throw new Error("Bad coin object");
|
|
235
233
|
const splitAmount = (BigInt(balance) - BigInt(GAS_FEE_FOR_SPLIT)) / BigInt(numGasObjects);
|
|
236
234
|
const gasPool = await SuiPricePusher.splitGasCoinEqually(signer, provider, signerAddress, Number(splitAmount), numGasObjects, consolidatedCoin);
|
|
237
|
-
|
|
235
|
+
logger.info({ gasPool }, "Gas pool is filled with coins");
|
|
238
236
|
return gasPool;
|
|
239
237
|
}
|
|
240
238
|
// Attempt to refresh the version of the provided object reference to point to the current version
|
|
@@ -303,7 +301,7 @@ class SuiPricePusher {
|
|
|
303
301
|
}
|
|
304
302
|
return newCoins;
|
|
305
303
|
}
|
|
306
|
-
static async mergeGasCoinsIntoOne(signer, provider, owner, initialLockedAddresses) {
|
|
304
|
+
static async mergeGasCoinsIntoOne(signer, provider, owner, initialLockedAddresses, logger) {
|
|
307
305
|
const gasCoins = await SuiPricePusher.getAllGasCoins(provider, owner);
|
|
308
306
|
// skip merging if there is only one coin
|
|
309
307
|
if (gasCoins.length === 1) {
|
|
@@ -329,13 +327,10 @@ class SuiPricePusher {
|
|
|
329
327
|
options: { showEffects: true },
|
|
330
328
|
});
|
|
331
329
|
}
|
|
332
|
-
catch (
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
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) => {
|
|
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) => {
|
|
339
334
|
lockedObjects.forEach((lockedObject) => {
|
|
340
335
|
lockedAddresses.add(lockedObject[0]);
|
|
341
336
|
});
|
|
@@ -344,7 +339,7 @@ class SuiPricePusher {
|
|
|
344
339
|
i--;
|
|
345
340
|
continue;
|
|
346
341
|
}
|
|
347
|
-
throw
|
|
342
|
+
throw err;
|
|
348
343
|
}
|
|
349
344
|
const error = mergeResult?.effects?.status.error;
|
|
350
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
|
}
|