@pythnetwork/price-pusher 6.1.0 → 6.4.2
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 +16 -4
- package/lib/evm/evm.d.ts.map +1 -1
- package/lib/evm/evm.js +3 -2
- package/lib/index.js +4 -0
- package/lib/near/command.d.ts +19 -0
- package/lib/near/command.d.ts.map +1 -0
- package/lib/near/command.js +86 -0
- package/lib/near/near.d.ts +28 -0
- package/lib/near/near.d.ts.map +1 -0
- package/lib/near/near.js +163 -0
- package/lib/price-config.js +1 -1
- package/lib/solana/command.d.ts +19 -0
- package/lib/solana/command.d.ts.map +1 -0
- package/lib/solana/command.js +96 -0
- package/lib/solana/solana.d.ts +21 -0
- package/lib/solana/solana.d.ts.map +1 -0
- package/lib/solana/solana.js +75 -0
- package/lib/sui/command.js +2 -2
- package/lib/sui/sui.d.ts +7 -3
- package/lib/sui/sui.d.ts.map +1 -1
- package/lib/sui/sui.js +46 -36
- package/package.json +8 -6
package/README.md
CHANGED
|
@@ -133,6 +133,18 @@ npm run start -- sui \
|
|
|
133
133
|
[--polling-frequency 5] \
|
|
134
134
|
[--num-gas-objects 30]
|
|
135
135
|
|
|
136
|
+
# For Near
|
|
137
|
+
npm run start -- near \
|
|
138
|
+
--node-url https://rpc.testnet.near.org \
|
|
139
|
+
--network testnet \
|
|
140
|
+
--account-id payer.testnet \
|
|
141
|
+
--pyth-contract-address pyth-oracle.testnet \
|
|
142
|
+
--price-service-endpoint "https://hermes-beta.pyth.network" \
|
|
143
|
+
--price-config-file ./price-config.beta.sample.yaml \
|
|
144
|
+
[--private-key-path ./payer.testnet.json] \
|
|
145
|
+
[--pushing-frequency 10] \
|
|
146
|
+
[--polling-frequency 5]
|
|
147
|
+
|
|
136
148
|
|
|
137
149
|
# Or, run the price pusher docker image instead of building from the source
|
|
138
150
|
docker run public.ecr.aws/pyth-network/xc-price-pusher:v<version> -- <above-arguments>
|
|
@@ -195,9 +207,9 @@ It will take a few minutes until all the services are up and running.
|
|
|
195
207
|
## Reliability
|
|
196
208
|
|
|
197
209
|
You can run multiple instances of the price pusher to increase the reliability. It is better to use
|
|
198
|
-
|
|
210
|
+
different RPCs to get better reliability in case an RPC goes down. **If you use the same payer account
|
|
199
211
|
in different pushers, then due to blockchains nonce or sequence for accounts, a transaction won't be
|
|
200
|
-
pushed
|
|
201
|
-
|
|
202
|
-
transactions land on-chain. You can reduce the chances of additional cost overhead by reducing the
|
|
212
|
+
pushed twice and you won't pay additional costs most of the time.** However, there might be some race
|
|
213
|
+
conditions in the RPCs because they are often behind a load balancer which can sometimes cause rejected
|
|
214
|
+
transactions to land on-chain. You can reduce the chances of additional cost overhead by reducing the
|
|
203
215
|
pushing frequency.
|
package/lib/evm/evm.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evm.d.ts","sourceRoot":"","sources":["../../src/evm/evm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAa,MAAM,mBAAmB,CAAC;AACxD,OAAO,EACL,YAAY,EACZ,SAAS,EACT,kBAAkB,EAClB,SAAS,EACV,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAgB,iBAAiB,EAAmB,MAAM,UAAU,CAAC;AAE5E,OAAO,gBAAgB,MAAM,4BAA4B,CAAC;AAG1D,OAAO,EACL,sBAAsB,EACtB,SAAS,EACT,aAAa,EACd,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAIxD,qBAAa,gBAAiB,SAAQ,kBAAkB;IACtD,OAAO,CAAC,mBAAmB,CAAsB;IACjD,OAAO,CAAC,YAAY,CAAW;gBAG7B,mBAAmB,EAAE,mBAAmB,EACxC,UAAU,EAAE,SAAS,EAAE,EACvB,MAAM,EAAE;QACN,gBAAgB,EAAE,iBAAiB,CAAC;KACrC;IAUG,KAAK;YAeG,iBAAiB;IAc/B,OAAO,CAAC,iBAAiB;IAsBnB,mBAAmB,CACvB,OAAO,EAAE,SAAS,GACjB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CAwBlC;AAED,qBAAa,cAAe,YAAW,YAAY;IAQ/C,OAAO,CAAC,UAAU;IAElB,OAAO,CAAC,0BAA0B;IAClC,OAAO,CAAC,6BAA6B;IAVvC,OAAO,CAAC,gBAAgB,CAAC,CAAmB;IAC5C,OAAO,CAAC,YAAY,CAAW;IAC/B,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,eAAe,CAA0B;gBAGvC,UAAU,EAAE,sBAAsB,EAC1C,mBAAmB,EAAE,mBAAmB,EAChC,0BAA0B,EAAE,MAAM,EAClC,6BAA6B,EAAE,MAAM,EAC7C,gBAAgB,CAAC,EAAE,gBAAgB;IAa/B,eAAe,CACnB,QAAQ,EAAE,MAAM,EAAE,EAClB,cAAc,EAAE,aAAa,EAAE,GAC9B,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"evm.d.ts","sourceRoot":"","sources":["../../src/evm/evm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAa,MAAM,mBAAmB,CAAC;AACxD,OAAO,EACL,YAAY,EACZ,SAAS,EACT,kBAAkB,EAClB,SAAS,EACV,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAgB,iBAAiB,EAAmB,MAAM,UAAU,CAAC;AAE5E,OAAO,gBAAgB,MAAM,4BAA4B,CAAC;AAG1D,OAAO,EACL,sBAAsB,EACtB,SAAS,EACT,aAAa,EACd,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAIxD,qBAAa,gBAAiB,SAAQ,kBAAkB;IACtD,OAAO,CAAC,mBAAmB,CAAsB;IACjD,OAAO,CAAC,YAAY,CAAW;gBAG7B,mBAAmB,EAAE,mBAAmB,EACxC,UAAU,EAAE,SAAS,EAAE,EACvB,MAAM,EAAE;QACN,gBAAgB,EAAE,iBAAiB,CAAC;KACrC;IAUG,KAAK;YAeG,iBAAiB;IAc/B,OAAO,CAAC,iBAAiB;IAsBnB,mBAAmB,CACvB,OAAO,EAAE,SAAS,GACjB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CAwBlC;AAED,qBAAa,cAAe,YAAW,YAAY;IAQ/C,OAAO,CAAC,UAAU;IAElB,OAAO,CAAC,0BAA0B;IAClC,OAAO,CAAC,6BAA6B;IAVvC,OAAO,CAAC,gBAAgB,CAAC,CAAmB;IAC5C,OAAO,CAAC,YAAY,CAAW;IAC/B,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,eAAe,CAA0B;gBAGvC,UAAU,EAAE,sBAAsB,EAC1C,mBAAmB,EAAE,mBAAmB,EAChC,0BAA0B,EAAE,MAAM,EAClC,6BAA6B,EAAE,MAAM,EAC7C,gBAAgB,CAAC,EAAE,gBAAgB;IAa/B,eAAe,CACnB,QAAQ,EAAE,MAAM,EAAE,EAClB,cAAc,EAAE,aAAa,EAAE,GAC9B,OAAO,CAAC,IAAI,CAAC;YAiJF,uBAAuB;CAQtC;AAED,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,mBAAmB;gBAFnB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,mBAAmB,EAAE,MAAM;IAGrC;;;;;;OAMG;IACH,2BAA2B,IAAI,QAAQ;IAcvC;;;;;OAKG;IACH,kBAAkB,IAAI,QAAQ;IAS9B,oBAAoB,IAAI,OAAO;IAI/B,kBAAkB;IA0BlB,uBAAuB;CAQxB"}
|
package/lib/evm/evm.js
CHANGED
|
@@ -158,8 +158,9 @@ class EvmPricePusher {
|
|
|
158
158
|
return;
|
|
159
159
|
}
|
|
160
160
|
if (err.message.includes("the tx doesn't have the correct nonce.") ||
|
|
161
|
-
err.message.includes("nonce too low")
|
|
162
|
-
|
|
161
|
+
err.message.includes("nonce too low") ||
|
|
162
|
+
err.message.includes("invalid nonce")) {
|
|
163
|
+
console.log("The nonce is incorrect (are multiple users using this account?). Skipping this push.");
|
|
163
164
|
return;
|
|
164
165
|
}
|
|
165
166
|
if (err.message.includes("max fee per gas less than block base fee")) {
|
package/lib/index.js
CHANGED
|
@@ -10,6 +10,8 @@ const command_1 = __importDefault(require("./injective/command"));
|
|
|
10
10
|
const command_2 = __importDefault(require("./evm/command"));
|
|
11
11
|
const command_3 = __importDefault(require("./aptos/command"));
|
|
12
12
|
const command_4 = __importDefault(require("./sui/command"));
|
|
13
|
+
const command_5 = __importDefault(require("./near/command"));
|
|
14
|
+
const command_6 = __importDefault(require("./solana/command"));
|
|
13
15
|
(0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
|
|
14
16
|
.config("config")
|
|
15
17
|
.global("config")
|
|
@@ -17,4 +19,6 @@ const command_4 = __importDefault(require("./sui/command"));
|
|
|
17
19
|
.command(command_1.default)
|
|
18
20
|
.command(command_3.default)
|
|
19
21
|
.command(command_4.default)
|
|
22
|
+
.command(command_5.default)
|
|
23
|
+
.command(command_6.default)
|
|
20
24
|
.help().argv;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Options } from "yargs";
|
|
2
|
+
declare const _default: {
|
|
3
|
+
command: string;
|
|
4
|
+
describe: string;
|
|
5
|
+
builder: {
|
|
6
|
+
"pushing-frequency": Options;
|
|
7
|
+
"polling-frequency": Options;
|
|
8
|
+
"pyth-contract-address": Options;
|
|
9
|
+
"price-service-endpoint": Options;
|
|
10
|
+
"price-config-file": Options;
|
|
11
|
+
"node-url": Options;
|
|
12
|
+
network: Options;
|
|
13
|
+
"account-id": Options;
|
|
14
|
+
"private-key-path": Options;
|
|
15
|
+
};
|
|
16
|
+
handler: (argv: any) => void;
|
|
17
|
+
};
|
|
18
|
+
export default _default;
|
|
19
|
+
//# sourceMappingURL=command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/near/command.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;;;;;;;;;;;;;;;oBAkCL,GAAG;;AA/B9B,wBA2FE"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
const price_service_client_1 = require("@pythnetwork/price-service-client");
|
|
27
|
+
const options = __importStar(require("../options"));
|
|
28
|
+
const price_config_1 = require("../price-config");
|
|
29
|
+
const pyth_price_listener_1 = require("../pyth-price-listener");
|
|
30
|
+
const controller_1 = require("../controller");
|
|
31
|
+
const near_1 = require("./near");
|
|
32
|
+
exports.default = {
|
|
33
|
+
command: "near",
|
|
34
|
+
describe: "run price pusher for near",
|
|
35
|
+
builder: {
|
|
36
|
+
"node-url": {
|
|
37
|
+
description: "NEAR RPC API url. used to make JSON RPC calls to interact with NEAR.",
|
|
38
|
+
type: "string",
|
|
39
|
+
required: true,
|
|
40
|
+
},
|
|
41
|
+
network: {
|
|
42
|
+
description: "testnet or mainnet.",
|
|
43
|
+
type: "string",
|
|
44
|
+
required: true,
|
|
45
|
+
},
|
|
46
|
+
"account-id": {
|
|
47
|
+
description: "payer account identifier.",
|
|
48
|
+
type: "string",
|
|
49
|
+
required: true,
|
|
50
|
+
},
|
|
51
|
+
"private-key-path": {
|
|
52
|
+
description: "path to payer private key file.",
|
|
53
|
+
type: "string",
|
|
54
|
+
required: false,
|
|
55
|
+
},
|
|
56
|
+
...options.priceConfigFile,
|
|
57
|
+
...options.priceServiceEndpoint,
|
|
58
|
+
...options.pythContractAddress,
|
|
59
|
+
...options.pollingFrequency,
|
|
60
|
+
...options.pushingFrequency,
|
|
61
|
+
},
|
|
62
|
+
handler: function (argv) {
|
|
63
|
+
// FIXME: type checks for this
|
|
64
|
+
const { nodeUrl, network, accountId, privateKeyPath, priceConfigFile, priceServiceEndpoint, pythContractAddress, pushingFrequency, pollingFrequency, } = argv;
|
|
65
|
+
const priceConfigs = (0, price_config_1.readPriceConfigFile)(priceConfigFile);
|
|
66
|
+
const priceServiceConnection = new price_service_client_1.PriceServiceConnection(priceServiceEndpoint, {
|
|
67
|
+
logger: {
|
|
68
|
+
// Log only warnings and errors from the price service client
|
|
69
|
+
info: () => undefined,
|
|
70
|
+
warn: console.warn,
|
|
71
|
+
error: console.error,
|
|
72
|
+
debug: () => undefined,
|
|
73
|
+
trace: () => undefined,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
const priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
|
|
77
|
+
const pythListener = new pyth_price_listener_1.PythPriceListener(priceServiceConnection, priceItems);
|
|
78
|
+
const nearAccount = new near_1.NearAccount(network, accountId, nodeUrl, privateKeyPath, pythContractAddress);
|
|
79
|
+
const nearListener = new near_1.NearPriceListener(nearAccount, priceItems, {
|
|
80
|
+
pollingFrequency,
|
|
81
|
+
});
|
|
82
|
+
const nearPusher = new near_1.NearPricePusher(nearAccount, priceServiceConnection);
|
|
83
|
+
const controller = new controller_1.Controller(priceConfigs, pythListener, nearListener, nearPusher, { pushingFrequency });
|
|
84
|
+
controller.start();
|
|
85
|
+
},
|
|
86
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { IPricePusher, PriceInfo, ChainPriceListener, PriceItem } from "../interface";
|
|
2
|
+
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
|
|
3
|
+
import { DurationInSeconds } from "../utils";
|
|
4
|
+
import { FinalExecutionOutcome } from "near-api-js/lib/providers/provider";
|
|
5
|
+
export declare class NearPriceListener extends ChainPriceListener {
|
|
6
|
+
private account;
|
|
7
|
+
constructor(account: NearAccount, priceItems: PriceItem[], config: {
|
|
8
|
+
pollingFrequency: DurationInSeconds;
|
|
9
|
+
});
|
|
10
|
+
getOnChainPriceInfo(priceId: string): Promise<PriceInfo | undefined>;
|
|
11
|
+
}
|
|
12
|
+
export declare class NearPricePusher implements IPricePusher {
|
|
13
|
+
private account;
|
|
14
|
+
private connection;
|
|
15
|
+
constructor(account: NearAccount, connection: PriceServiceConnection);
|
|
16
|
+
updatePriceFeed(priceIds: string[], pubTimesToPush: number[]): Promise<void>;
|
|
17
|
+
private getPriceFeedsUpdateData;
|
|
18
|
+
}
|
|
19
|
+
export declare class NearAccount {
|
|
20
|
+
private pythAccountId;
|
|
21
|
+
private account;
|
|
22
|
+
constructor(network: string, accountId: string, nodeUrl: string, privateKeyPath: string | undefined, pythAccountId: string);
|
|
23
|
+
getPriceUnsafe(priceId: string): Promise<any>;
|
|
24
|
+
getUpdateFeeEstimate(data: string): Promise<any>;
|
|
25
|
+
updatePriceFeeds(data: string, updateFee: any): Promise<FinalExecutionOutcome>;
|
|
26
|
+
private getConnection;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=near.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"near.d.ts","sourceRoot":"","sources":["../../src/near/near.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,YAAY,EACZ,SAAS,EACT,kBAAkB,EAClB,SAAS,EACV,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,sBAAsB,EAEvB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAG7C,OAAO,EAGL,qBAAqB,EACtB,MAAM,oCAAoC,CAAC;AAG5C,qBAAa,iBAAkB,SAAQ,kBAAkB;IAErD,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,WAAW,EAC5B,UAAU,EAAE,SAAS,EAAE,EACvB,MAAM,EAAE;QACN,gBAAgB,EAAE,iBAAiB,CAAC;KACrC;IAKG,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CAyB3E;AAED,qBAAa,eAAgB,YAAW,YAAY;IAEhD,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,UAAU;gBADV,OAAO,EAAE,WAAW,EACpB,UAAU,EAAE,sBAAsB;IAGtC,eAAe,CACnB,QAAQ,EAAE,MAAM,EAAE,EAClB,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,IAAI,CAAC;YAiEF,uBAAuB;CAMtC;AAED,qBAAa,WAAW;IAQpB,OAAO,CAAC,aAAa;IAPvB,OAAO,CAAC,OAAO,CAAU;gBAGvB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,MAAM,GAAG,SAAS,EAC1B,aAAa,EAAE,MAAM;IAWzB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAU7C,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAUhD,gBAAgB,CACpB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,GAAG,GACb,OAAO,CAAC,qBAAqB,CAAC;IAYjC,OAAO,CAAC,aAAa;CAkCtB"}
|
package/lib/near/near.js
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.NearAccount = exports.NearPricePusher = exports.NearPriceListener = void 0;
|
|
7
|
+
const os_1 = __importDefault(require("os"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const interface_1 = require("../interface");
|
|
11
|
+
const near_api_js_1 = require("near-api-js");
|
|
12
|
+
const key_stores_1 = require("near-api-js/lib/key_stores");
|
|
13
|
+
class NearPriceListener extends interface_1.ChainPriceListener {
|
|
14
|
+
account;
|
|
15
|
+
constructor(account, priceItems, config) {
|
|
16
|
+
super("near", config.pollingFrequency, priceItems);
|
|
17
|
+
this.account = account;
|
|
18
|
+
}
|
|
19
|
+
async getOnChainPriceInfo(priceId) {
|
|
20
|
+
try {
|
|
21
|
+
const priceRaw = await this.account.getPriceUnsafe(priceId);
|
|
22
|
+
console.log(`Polled a NEAR on chain price for feed ${this.priceIdToAlias.get(priceId)} (${priceId}) ${JSON.stringify(priceRaw)}.`);
|
|
23
|
+
if (priceRaw) {
|
|
24
|
+
return {
|
|
25
|
+
conf: priceRaw.conf,
|
|
26
|
+
price: priceRaw.price,
|
|
27
|
+
publishTime: priceRaw.publish_time,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
console.error(`Polling on-chain price for ${priceId} failed. Error:`);
|
|
36
|
+
console.error(e);
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.NearPriceListener = NearPriceListener;
|
|
42
|
+
class NearPricePusher {
|
|
43
|
+
account;
|
|
44
|
+
connection;
|
|
45
|
+
constructor(account, connection) {
|
|
46
|
+
this.account = account;
|
|
47
|
+
this.connection = connection;
|
|
48
|
+
}
|
|
49
|
+
async updatePriceFeed(priceIds, pubTimesToPush) {
|
|
50
|
+
if (priceIds.length === 0) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (priceIds.length !== pubTimesToPush.length)
|
|
54
|
+
throw new Error("Invalid arguments");
|
|
55
|
+
let priceFeedUpdateData;
|
|
56
|
+
try {
|
|
57
|
+
priceFeedUpdateData = await this.getPriceFeedsUpdateData(priceIds);
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
console.error(new Date(), "getPriceFeedsUpdateData failed:", e);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
console.log("Pushing ", priceIds);
|
|
64
|
+
for (const data of priceFeedUpdateData) {
|
|
65
|
+
let updateFee;
|
|
66
|
+
try {
|
|
67
|
+
updateFee = await this.account.getUpdateFeeEstimate(data);
|
|
68
|
+
console.log(`Update fee: ${updateFee}`);
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
console.error(new Date(), "getUpdateFeeEstimate failed:", e);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const outcome = await this.account.updatePriceFeeds(data, updateFee);
|
|
76
|
+
const failureMessages = [];
|
|
77
|
+
const is_success = Object.values(outcome["receipts_outcome"]).reduce((is_success, receipt) => {
|
|
78
|
+
if (Object.prototype.hasOwnProperty.call(receipt["outcome"]["status"], "Failure")) {
|
|
79
|
+
failureMessages.push(receipt["outcome"]["status"]);
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
return is_success;
|
|
83
|
+
}, true);
|
|
84
|
+
if (is_success) {
|
|
85
|
+
console.log(new Date(), "updatePriceFeeds successful. Tx hash: ", outcome["transaction"]["hash"]);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
console.error(new Date(), "updatePriceFeeds failed:", JSON.stringify(failureMessages, undefined, 2));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
console.error(new Date(), "updatePriceFeeds failed:", e);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async getPriceFeedsUpdateData(priceIds) {
|
|
97
|
+
const latestVaas = await this.connection.getLatestVaas(priceIds);
|
|
98
|
+
return latestVaas.map((vaa) => Buffer.from(vaa, "base64").toString("hex"));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
exports.NearPricePusher = NearPricePusher;
|
|
102
|
+
class NearAccount {
|
|
103
|
+
pythAccountId;
|
|
104
|
+
account;
|
|
105
|
+
constructor(network, accountId, nodeUrl, privateKeyPath, pythAccountId) {
|
|
106
|
+
this.pythAccountId = pythAccountId;
|
|
107
|
+
const connection = this.getConnection(network, accountId, nodeUrl, privateKeyPath);
|
|
108
|
+
this.account = new near_api_js_1.Account(connection, accountId);
|
|
109
|
+
}
|
|
110
|
+
async getPriceUnsafe(priceId) {
|
|
111
|
+
return await this.account.viewFunction({
|
|
112
|
+
contractId: this.pythAccountId,
|
|
113
|
+
methodName: "get_price_unsafe",
|
|
114
|
+
args: {
|
|
115
|
+
price_identifier: priceId,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
async getUpdateFeeEstimate(data) {
|
|
120
|
+
return await this.account.viewFunction({
|
|
121
|
+
contractId: this.pythAccountId,
|
|
122
|
+
methodName: "get_update_fee_estimate",
|
|
123
|
+
args: {
|
|
124
|
+
data,
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
async updatePriceFeeds(data, updateFee) {
|
|
129
|
+
return await this.account.functionCall({
|
|
130
|
+
contractId: this.pythAccountId,
|
|
131
|
+
methodName: "update_price_feeds",
|
|
132
|
+
args: {
|
|
133
|
+
data,
|
|
134
|
+
},
|
|
135
|
+
gas: "300000000000000",
|
|
136
|
+
attachedDeposit: updateFee,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
getConnection(network, accountId, nodeUrl, privateKeyPath) {
|
|
140
|
+
const content = fs_1.default.readFileSync(privateKeyPath ||
|
|
141
|
+
path_1.default.join(os_1.default.homedir(), ".near-credentials", network, accountId + ".json"));
|
|
142
|
+
const accountInfo = JSON.parse(content.toString());
|
|
143
|
+
let privateKey = accountInfo.private_key;
|
|
144
|
+
if (!privateKey && accountInfo.secret_key) {
|
|
145
|
+
privateKey = accountInfo.secret_key;
|
|
146
|
+
}
|
|
147
|
+
if (accountInfo.account_id && privateKey) {
|
|
148
|
+
const keyPair = near_api_js_1.KeyPair.fromString(privateKey);
|
|
149
|
+
const keyStore = new key_stores_1.InMemoryKeyStore();
|
|
150
|
+
keyStore.setKey(network, accountInfo.account_id, keyPair);
|
|
151
|
+
return near_api_js_1.Connection.fromConfig({
|
|
152
|
+
networkId: network,
|
|
153
|
+
provider: { type: "JsonRpcProvider", args: { url: nodeUrl } },
|
|
154
|
+
signer: { type: "InMemorySigner", keyStore },
|
|
155
|
+
jsvmAccountId: `jsvm.${network}`,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
throw new Error("Invalid key file!");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
exports.NearAccount = NearAccount;
|
package/lib/price-config.js
CHANGED
|
@@ -56,7 +56,7 @@ var UpdateCondition;
|
|
|
56
56
|
UpdateCondition[UpdateCondition["EARLY"] = 1] = "EARLY";
|
|
57
57
|
// This price feed shouldn't be updated
|
|
58
58
|
UpdateCondition[UpdateCondition["NO"] = 2] = "NO";
|
|
59
|
-
})(UpdateCondition
|
|
59
|
+
})(UpdateCondition || (exports.UpdateCondition = UpdateCondition = {}));
|
|
60
60
|
/**
|
|
61
61
|
* Checks whether on-chain price needs to be updated with the latest pyth price information.
|
|
62
62
|
*
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Options } from "yargs";
|
|
2
|
+
declare const _default: {
|
|
3
|
+
command: string;
|
|
4
|
+
describe: string;
|
|
5
|
+
builder: {
|
|
6
|
+
"pushing-frequency": Options;
|
|
7
|
+
"polling-frequency": Options;
|
|
8
|
+
"pyth-contract-address": Options;
|
|
9
|
+
"price-service-endpoint": Options;
|
|
10
|
+
"price-config-file": Options;
|
|
11
|
+
endpoint: Options;
|
|
12
|
+
"keypair-file": Options;
|
|
13
|
+
"shard-id": Options;
|
|
14
|
+
"compute-unit-price-micro-lamports": Options;
|
|
15
|
+
};
|
|
16
|
+
handler: (argv: any) => void;
|
|
17
|
+
};
|
|
18
|
+
export default _default;
|
|
19
|
+
//# sourceMappingURL=command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/solana/command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;;;;;;;;;;;;;;;oBA2CL,GAAG;;AA9B9B,wBAqGE"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
const options = __importStar(require("../options"));
|
|
30
|
+
const price_config_1 = require("../price-config");
|
|
31
|
+
const price_service_client_1 = require("@pythnetwork/price-service-client");
|
|
32
|
+
const pyth_price_listener_1 = require("../pyth-price-listener");
|
|
33
|
+
const solana_1 = require("./solana");
|
|
34
|
+
const controller_1 = require("../controller");
|
|
35
|
+
const pyth_solana_receiver_1 = require("@pythnetwork/pyth-solana-receiver");
|
|
36
|
+
const nodewallet_1 = __importDefault(require("@coral-xyz/anchor/dist/cjs/nodewallet"));
|
|
37
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
38
|
+
const fs_1 = __importDefault(require("fs"));
|
|
39
|
+
const web3_js_2 = require("@solana/web3.js");
|
|
40
|
+
exports.default = {
|
|
41
|
+
command: "solana",
|
|
42
|
+
describe: "run price pusher for solana",
|
|
43
|
+
builder: {
|
|
44
|
+
endpoint: {
|
|
45
|
+
description: "Solana RPC API endpoint",
|
|
46
|
+
type: "string",
|
|
47
|
+
required: true,
|
|
48
|
+
},
|
|
49
|
+
"keypair-file": {
|
|
50
|
+
description: "Path to a keypair file",
|
|
51
|
+
type: "string",
|
|
52
|
+
required: true,
|
|
53
|
+
},
|
|
54
|
+
"shard-id": {
|
|
55
|
+
description: "Shard ID",
|
|
56
|
+
type: "number",
|
|
57
|
+
required: true,
|
|
58
|
+
},
|
|
59
|
+
"compute-unit-price-micro-lamports": {
|
|
60
|
+
description: "Priority fee per compute unit",
|
|
61
|
+
type: "number",
|
|
62
|
+
default: 50000,
|
|
63
|
+
},
|
|
64
|
+
...options.priceConfigFile,
|
|
65
|
+
...options.priceServiceEndpoint,
|
|
66
|
+
...options.pythContractAddress,
|
|
67
|
+
...options.pollingFrequency,
|
|
68
|
+
...options.pushingFrequency,
|
|
69
|
+
},
|
|
70
|
+
handler: function (argv) {
|
|
71
|
+
const { endpoint, keypairFile, shardId, computeUnitPriceMicroLamports, priceConfigFile, priceServiceEndpoint, pythContractAddress, pushingFrequency, pollingFrequency, } = argv;
|
|
72
|
+
const priceConfigs = (0, price_config_1.readPriceConfigFile)(priceConfigFile);
|
|
73
|
+
const priceServiceConnection = new price_service_client_1.PriceServiceConnection(priceServiceEndpoint, {
|
|
74
|
+
logger: {
|
|
75
|
+
// Log only warnings and errors from the price service client
|
|
76
|
+
info: () => undefined,
|
|
77
|
+
warn: console.warn,
|
|
78
|
+
error: console.error,
|
|
79
|
+
debug: () => undefined,
|
|
80
|
+
trace: () => undefined,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
const priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
|
|
84
|
+
const pythListener = new pyth_price_listener_1.PythPriceListener(priceServiceConnection, priceItems);
|
|
85
|
+
const wallet = new nodewallet_1.default(web3_js_1.Keypair.fromSecretKey(Uint8Array.from(JSON.parse(fs_1.default.readFileSync(keypairFile, "ascii")))));
|
|
86
|
+
const pythSolanaReceiver = new pyth_solana_receiver_1.PythSolanaReceiver({
|
|
87
|
+
connection: new web3_js_1.Connection(endpoint),
|
|
88
|
+
wallet,
|
|
89
|
+
pushOracleProgramId: new web3_js_2.PublicKey(pythContractAddress),
|
|
90
|
+
});
|
|
91
|
+
const solanaPricePusher = new solana_1.SolanaPricePusher(pythSolanaReceiver, priceServiceConnection, shardId, computeUnitPriceMicroLamports);
|
|
92
|
+
const solanaPriceListener = new solana_1.SolanaPriceListener(pythSolanaReceiver, shardId, priceItems, { pollingFrequency });
|
|
93
|
+
const controller = new controller_1.Controller(priceConfigs, pythListener, solanaPriceListener, solanaPricePusher, { pushingFrequency });
|
|
94
|
+
controller.start();
|
|
95
|
+
},
|
|
96
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { PythSolanaReceiver } from "@pythnetwork/pyth-solana-receiver";
|
|
2
|
+
import { ChainPriceListener, IPricePusher, PriceInfo, PriceItem } from "../interface";
|
|
3
|
+
import { DurationInSeconds } from "../utils";
|
|
4
|
+
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
|
|
5
|
+
export declare class SolanaPriceListener extends ChainPriceListener {
|
|
6
|
+
private pythSolanaReceiver;
|
|
7
|
+
private shardId;
|
|
8
|
+
constructor(pythSolanaReceiver: PythSolanaReceiver, shardId: number, priceItems: PriceItem[], config: {
|
|
9
|
+
pollingFrequency: DurationInSeconds;
|
|
10
|
+
});
|
|
11
|
+
getOnChainPriceInfo(priceId: string): Promise<PriceInfo | undefined>;
|
|
12
|
+
}
|
|
13
|
+
export declare class SolanaPricePusher implements IPricePusher {
|
|
14
|
+
private pythSolanaReceiver;
|
|
15
|
+
private priceServiceConnection;
|
|
16
|
+
private shardId;
|
|
17
|
+
private computeUnitPriceMicroLamports;
|
|
18
|
+
constructor(pythSolanaReceiver: PythSolanaReceiver, priceServiceConnection: PriceServiceConnection, shardId: number, computeUnitPriceMicroLamports: number);
|
|
19
|
+
updatePriceFeed(priceIds: string[], pubTimesToPush: number[]): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=solana.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solana.d.ts","sourceRoot":"","sources":["../../src/solana/solana.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,SAAS,EACV,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAE3E,qBAAa,mBAAoB,SAAQ,kBAAkB;IAEvD,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,OAAO;gBADP,kBAAkB,EAAE,kBAAkB,EACtC,OAAO,EAAE,MAAM,EACvB,UAAU,EAAE,SAAS,EAAE,EACvB,MAAM,EAAE;QACN,gBAAgB,EAAE,iBAAiB,CAAC;KACrC;IAKG,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CA2B3E;AAED,qBAAa,iBAAkB,YAAW,YAAY;IAElD,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,sBAAsB;IAC9B,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,6BAA6B;gBAH7B,kBAAkB,EAAE,kBAAkB,EACtC,sBAAsB,EAAE,sBAAsB,EAC9C,OAAO,EAAE,MAAM,EACf,6BAA6B,EAAE,MAAM;IAGzC,eAAe,CACnB,QAAQ,EAAE,MAAM,EAAE,EAClB,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,IAAI,CAAC;CAoCjB"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SolanaPricePusher = exports.SolanaPriceListener = void 0;
|
|
4
|
+
const interface_1 = require("../interface");
|
|
5
|
+
class SolanaPriceListener extends interface_1.ChainPriceListener {
|
|
6
|
+
pythSolanaReceiver;
|
|
7
|
+
shardId;
|
|
8
|
+
constructor(pythSolanaReceiver, shardId, priceItems, config) {
|
|
9
|
+
super("solana", config.pollingFrequency, priceItems);
|
|
10
|
+
this.pythSolanaReceiver = pythSolanaReceiver;
|
|
11
|
+
this.shardId = shardId;
|
|
12
|
+
}
|
|
13
|
+
async getOnChainPriceInfo(priceId) {
|
|
14
|
+
try {
|
|
15
|
+
const priceFeedAccount = await this.pythSolanaReceiver.fetchPriceFeedAccount(this.shardId, Buffer.from(priceId, "hex"));
|
|
16
|
+
console.log(`Polled a Solana on chain price for feed ${this.priceIdToAlias.get(priceId)} (${priceId}).`);
|
|
17
|
+
if (priceFeedAccount) {
|
|
18
|
+
return {
|
|
19
|
+
conf: priceFeedAccount.priceMessage.conf.toString(),
|
|
20
|
+
price: priceFeedAccount.priceMessage.price.toString(),
|
|
21
|
+
publishTime: priceFeedAccount.priceMessage.publishTime.toNumber(),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
console.error(`Polling on-chain price for ${priceId} failed. Error:`);
|
|
30
|
+
console.error(e);
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.SolanaPriceListener = SolanaPriceListener;
|
|
36
|
+
class SolanaPricePusher {
|
|
37
|
+
pythSolanaReceiver;
|
|
38
|
+
priceServiceConnection;
|
|
39
|
+
shardId;
|
|
40
|
+
computeUnitPriceMicroLamports;
|
|
41
|
+
constructor(pythSolanaReceiver, priceServiceConnection, shardId, computeUnitPriceMicroLamports) {
|
|
42
|
+
this.pythSolanaReceiver = pythSolanaReceiver;
|
|
43
|
+
this.priceServiceConnection = priceServiceConnection;
|
|
44
|
+
this.shardId = shardId;
|
|
45
|
+
this.computeUnitPriceMicroLamports = computeUnitPriceMicroLamports;
|
|
46
|
+
}
|
|
47
|
+
async updatePriceFeed(priceIds, pubTimesToPush) {
|
|
48
|
+
if (priceIds.length === 0) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
let priceFeedUpdateData;
|
|
52
|
+
try {
|
|
53
|
+
priceFeedUpdateData = await this.priceServiceConnection.getLatestVaas(priceIds);
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
console.error(new Date(), "getPriceFeedsUpdateData failed:", e);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const transactionBuilder = this.pythSolanaReceiver.newTransactionBuilder({
|
|
60
|
+
closeUpdateAccounts: true,
|
|
61
|
+
});
|
|
62
|
+
await transactionBuilder.addUpdatePriceFeed(priceFeedUpdateData, this.shardId);
|
|
63
|
+
try {
|
|
64
|
+
await this.pythSolanaReceiver.provider.sendAll(await transactionBuilder.buildVersionedTransactions({
|
|
65
|
+
computeUnitPriceMicroLamports: this.computeUnitPriceMicroLamports,
|
|
66
|
+
}), { skipPreflight: true });
|
|
67
|
+
console.log(new Date(), "updatePriceFeed successful");
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
console.error(new Date(), "updatePriceFeed failed", e);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
exports.SolanaPricePusher = SolanaPricePusher;
|
package/lib/sui/command.js
CHANGED
|
@@ -33,7 +33,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
33
33
|
const pyth_price_listener_1 = require("../pyth-price-listener");
|
|
34
34
|
const controller_1 = require("../controller");
|
|
35
35
|
const sui_1 = require("./sui");
|
|
36
|
-
const
|
|
36
|
+
const ed25519_1 = require("@mysten/sui.js/keypairs/ed25519");
|
|
37
37
|
exports.default = {
|
|
38
38
|
command: "sui",
|
|
39
39
|
describe: "Run price pusher for sui. Most of the arguments below are" +
|
|
@@ -101,7 +101,7 @@ exports.default = {
|
|
|
101
101
|
},
|
|
102
102
|
});
|
|
103
103
|
const mnemonic = fs_1.default.readFileSync(mnemonicFile, "utf-8").trim();
|
|
104
|
-
const keypair =
|
|
104
|
+
const keypair = ed25519_1.Ed25519Keypair.deriveKeypair(mnemonic, `m/44'/784'/${accountIndex}'/0'/0'`);
|
|
105
105
|
console.log(`Pushing updates from wallet address: ${keypair
|
|
106
106
|
.getPublicKey()
|
|
107
107
|
.toSuiAddress()}`);
|
package/lib/sui/sui.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { ChainPriceListener, IPricePusher, PriceInfo, PriceItem } from "../interface";
|
|
2
2
|
import { DurationInSeconds } from "../utils";
|
|
3
3
|
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
|
|
4
|
-
import { JsonRpcProvider, Ed25519Keypair, RawSigner, SuiObjectRef, ObjectId } from "@mysten/sui.js";
|
|
5
4
|
import { SuiPythClient } from "@pythnetwork/pyth-sui-js";
|
|
5
|
+
import { Ed25519Keypair } from "@mysten/sui.js/keypairs/ed25519";
|
|
6
|
+
import { SuiClient, SuiObjectRef } from "@mysten/sui.js/client";
|
|
7
|
+
type ObjectId = string;
|
|
6
8
|
export declare class SuiPriceListener extends ChainPriceListener {
|
|
7
9
|
private pythClient;
|
|
8
10
|
private provider;
|
|
@@ -27,6 +29,7 @@ export declare class SuiPriceListener extends ChainPriceListener {
|
|
|
27
29
|
*/
|
|
28
30
|
export declare class SuiPricePusher implements IPricePusher {
|
|
29
31
|
private readonly signer;
|
|
32
|
+
private readonly provider;
|
|
30
33
|
private priceServiceConnection;
|
|
31
34
|
private pythPackageId;
|
|
32
35
|
private pythStateId;
|
|
@@ -35,7 +38,7 @@ export declare class SuiPricePusher implements IPricePusher {
|
|
|
35
38
|
private gasBudget;
|
|
36
39
|
private gasPool;
|
|
37
40
|
private pythClient;
|
|
38
|
-
constructor(signer:
|
|
41
|
+
constructor(signer: Ed25519Keypair, provider: SuiClient, priceServiceConnection: PriceServiceConnection, pythPackageId: string, pythStateId: string, wormholePackageId: string, wormholeStateId: string, endpoint: string, keypair: Ed25519Keypair, gasBudget: number, gasPool: SuiObjectRef[], pythClient: SuiPythClient);
|
|
39
42
|
/**
|
|
40
43
|
* getPackageId returns the latest package id that the object belongs to. Use this to
|
|
41
44
|
* fetch the latest package id for a given object id and handle package upgrades automatically.
|
|
@@ -43,7 +46,7 @@ export declare class SuiPricePusher implements IPricePusher {
|
|
|
43
46
|
* @param objectId
|
|
44
47
|
* @returns package id
|
|
45
48
|
*/
|
|
46
|
-
static getPackageId(provider:
|
|
49
|
+
static getPackageId(provider: SuiClient, objectId: ObjectId): Promise<ObjectId>;
|
|
47
50
|
/**
|
|
48
51
|
* Create a price pusher with a pool of `numGasObjects` gas coins that will be used to send transactions.
|
|
49
52
|
* The gas coins of the wallet for the provided keypair will be merged and then evenly split into `numGasObjects`.
|
|
@@ -60,4 +63,5 @@ export declare class SuiPricePusher implements IPricePusher {
|
|
|
60
63
|
private static splitGasCoinEqually;
|
|
61
64
|
private static mergeGasCoinsIntoOne;
|
|
62
65
|
}
|
|
66
|
+
export {};
|
|
63
67
|
//# sourceMappingURL=sui.d.ts.map
|
package/lib/sui/sui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sui.d.ts","sourceRoot":"","sources":["../../src/sui/sui.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,SAAS,EACV,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,
|
|
1
|
+
{"version":3,"file":"sui.d.ts","sourceRoot":"","sources":["../../src/sui/sui.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,SAAS,EACV,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAkB,MAAM,uBAAuB,CAAC;AAOhF,KAAK,QAAQ,GAAG,MAAM,CAAC;AAGvB,qBAAa,gBAAiB,SAAQ,kBAAkB;IACtD,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,QAAQ,CAAY;gBAG1B,WAAW,EAAE,QAAQ,EACrB,eAAe,EAAE,QAAQ,EACzB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,SAAS,EAAE,EACvB,MAAM,EAAE;QACN,gBAAgB,EAAE,iBAAiB,CAAC;KACrC;IAWG,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CA2C3E;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,cAAe,YAAW,YAAY;IAE/C,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,sBAAsB;IAC9B,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,iBAAiB;IACzB,OAAO,CAAC,eAAe;IAGvB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,UAAU;gBAXD,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,SAAS,EAC5B,sBAAsB,EAAE,sBAAsB,EAC9C,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,iBAAiB,EAAE,MAAM,EACzB,eAAe,EAAE,MAAM,EAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,YAAY,EAAE,EACvB,UAAU,EAAE,aAAa;IAGnC;;;;;;OAMG;WACU,YAAY,CACvB,QAAQ,EAAE,SAAS,EACnB,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,QAAQ,CAAC;IAyBpB;;;OAGG;WACU,0BAA0B,CACrC,sBAAsB,EAAE,sBAAsB,EAC9C,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,cAAc,CAAC;IA6CpB,eAAe,CACnB,QAAQ,EAAE,MAAM,EAAE,EAClB,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,IAAI,CAAC;IA0ChB,iGAAiG;YACnF,qBAAqB;IAMnC,sEAAsE;YACxD,oBAAoB;mBAyDb,iBAAiB;mBA4CjB,yBAAyB;mBAoBzB,cAAc;mBAiCd,mBAAmB;mBAwCnB,oBAAoB;CA4D1C"}
|
package/lib/sui/sui.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SuiPricePusher = exports.SuiPriceListener = void 0;
|
|
4
4
|
const interface_1 = require("../interface");
|
|
5
|
-
const sui_js_1 = require("@mysten/sui.js");
|
|
6
5
|
const pyth_sui_js_1 = require("@pythnetwork/pyth-sui-js");
|
|
6
|
+
const transactions_1 = require("@mysten/sui.js/transactions");
|
|
7
|
+
const client_1 = require("@mysten/sui.js/client");
|
|
7
8
|
const GAS_FEE_FOR_SPLIT = 2_000_000_000;
|
|
8
9
|
// TODO: read this from on chain config
|
|
9
10
|
const MAX_NUM_GAS_OBJECTS_IN_PTB = 256;
|
|
@@ -13,7 +14,7 @@ class SuiPriceListener extends interface_1.ChainPriceListener {
|
|
|
13
14
|
provider;
|
|
14
15
|
constructor(pythStateId, wormholeStateId, endpoint, priceItems, config) {
|
|
15
16
|
super("sui", config.pollingFrequency, priceItems);
|
|
16
|
-
this.provider = new
|
|
17
|
+
this.provider = new client_1.SuiClient({ url: endpoint });
|
|
17
18
|
this.pythClient = new pyth_sui_js_1.SuiPythClient(this.provider, pythStateId, wormholeStateId);
|
|
18
19
|
}
|
|
19
20
|
async getOnChainPriceInfo(priceId) {
|
|
@@ -27,17 +28,18 @@ class SuiPriceListener extends interface_1.ChainPriceListener {
|
|
|
27
28
|
id: priceInfoObjectId,
|
|
28
29
|
options: { showContent: true },
|
|
29
30
|
});
|
|
30
|
-
if (priceInfoObject.data
|
|
31
|
-
priceInfoObject.data.content === undefined)
|
|
31
|
+
if (!priceInfoObject.data || !priceInfoObject.data.content)
|
|
32
32
|
throw new Error("Price not found on chain for price id " + priceId);
|
|
33
33
|
if (priceInfoObject.data.content.dataType !== "moveObject")
|
|
34
34
|
throw new Error("fetched object datatype should be moveObject");
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
const priceInfo =
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
priceInfoObject.data.content.fields.price_info.fields.price_feed.fields
|
|
39
|
+
.price.fields;
|
|
40
|
+
const { magnitude, negative } = priceInfo.price.fields;
|
|
41
|
+
const conf = priceInfo.conf;
|
|
42
|
+
const timestamp = priceInfo.timestamp;
|
|
41
43
|
return {
|
|
42
44
|
price: negative ? "-" + magnitude : magnitude,
|
|
43
45
|
conf,
|
|
@@ -68,6 +70,7 @@ exports.SuiPriceListener = SuiPriceListener;
|
|
|
68
70
|
*/
|
|
69
71
|
class SuiPricePusher {
|
|
70
72
|
signer;
|
|
73
|
+
provider;
|
|
71
74
|
priceServiceConnection;
|
|
72
75
|
pythPackageId;
|
|
73
76
|
pythStateId;
|
|
@@ -76,8 +79,9 @@ class SuiPricePusher {
|
|
|
76
79
|
gasBudget;
|
|
77
80
|
gasPool;
|
|
78
81
|
pythClient;
|
|
79
|
-
constructor(signer, priceServiceConnection, pythPackageId, pythStateId, wormholePackageId, wormholeStateId, endpoint, keypair, gasBudget, gasPool, pythClient) {
|
|
82
|
+
constructor(signer, provider, priceServiceConnection, pythPackageId, pythStateId, wormholePackageId, wormholeStateId, endpoint, keypair, gasBudget, gasPool, pythClient) {
|
|
80
83
|
this.signer = signer;
|
|
84
|
+
this.provider = provider;
|
|
81
85
|
this.priceServiceConnection = priceServiceConnection;
|
|
82
86
|
this.pythPackageId = pythPackageId;
|
|
83
87
|
this.pythStateId = pythStateId;
|
|
@@ -109,6 +113,8 @@ class SuiPricePusher {
|
|
|
109
113
|
throw new Error("not move object");
|
|
110
114
|
});
|
|
111
115
|
if ("upgrade_cap" in state) {
|
|
116
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
117
|
+
// @ts-ignore
|
|
112
118
|
return state.upgrade_cap.fields.package;
|
|
113
119
|
}
|
|
114
120
|
throw new Error("upgrade_cap not found");
|
|
@@ -121,13 +127,12 @@ class SuiPricePusher {
|
|
|
121
127
|
if (numGasObjects > MAX_NUM_OBJECTS_IN_ARGUMENT) {
|
|
122
128
|
throw new Error(`numGasObjects cannot be greater than ${MAX_NUM_OBJECTS_IN_ARGUMENT} until we implement split chunking`);
|
|
123
129
|
}
|
|
124
|
-
const provider = new
|
|
125
|
-
const signer = new sui_js_1.RawSigner(keypair, provider);
|
|
130
|
+
const provider = new client_1.SuiClient({ url: endpoint });
|
|
126
131
|
const pythPackageId = await SuiPricePusher.getPackageId(provider, pythStateId);
|
|
127
132
|
const wormholePackageId = await SuiPricePusher.getPackageId(provider, wormholeStateId);
|
|
128
|
-
const gasPool = await SuiPricePusher.initializeGasPool(
|
|
133
|
+
const gasPool = await SuiPricePusher.initializeGasPool(keypair, provider, numGasObjects);
|
|
129
134
|
const pythClient = new pyth_sui_js_1.SuiPythClient(provider, pythStateId, wormholeStateId);
|
|
130
|
-
return new SuiPricePusher(
|
|
135
|
+
return new SuiPricePusher(keypair, provider, priceServiceConnection, pythPackageId, pythStateId, wormholePackageId, wormholeStateId, endpoint, keypair, gasBudget, gasPool, pythClient);
|
|
131
136
|
}
|
|
132
137
|
async updatePriceFeed(priceIds, pubTimesToPush) {
|
|
133
138
|
if (priceIds.length === 0) {
|
|
@@ -148,7 +153,7 @@ class SuiPricePusher {
|
|
|
148
153
|
throw new Error(`Expected a single VAA for all priceIds ${priceIdChunk} but received ${vaas.length} VAAs: ${vaas}`);
|
|
149
154
|
}
|
|
150
155
|
const vaa = vaas[0];
|
|
151
|
-
const tx = new
|
|
156
|
+
const tx = new transactions_1.TransactionBlock();
|
|
152
157
|
await this.pythClient.updatePriceFeeds(tx, [Buffer.from(vaa, "base64")], priceIdChunk);
|
|
153
158
|
txBlocks.push(tx);
|
|
154
159
|
}));
|
|
@@ -169,14 +174,15 @@ class SuiPricePusher {
|
|
|
169
174
|
try {
|
|
170
175
|
tx.setGasPayment([gasObject]);
|
|
171
176
|
tx.setGasBudget(this.gasBudget);
|
|
172
|
-
const result = await this.
|
|
177
|
+
const result = await this.provider.signAndExecuteTransactionBlock({
|
|
178
|
+
signer: this.signer,
|
|
173
179
|
transactionBlock: tx,
|
|
174
180
|
options: {
|
|
175
181
|
showEffects: true,
|
|
176
182
|
},
|
|
177
183
|
});
|
|
178
|
-
nextGasObject =
|
|
179
|
-
?.
|
|
184
|
+
nextGasObject = result.effects?.mutated
|
|
185
|
+
?.map((obj) => obj.reference)
|
|
180
186
|
.find((ref) => ref.objectId === gasObject.objectId);
|
|
181
187
|
console.log("Successfully updated price with transaction digest ", result.digest);
|
|
182
188
|
}
|
|
@@ -189,7 +195,7 @@ class SuiPricePusher {
|
|
|
189
195
|
}
|
|
190
196
|
else {
|
|
191
197
|
// Refresh the coin object here in case the error is caused by an object version mismatch.
|
|
192
|
-
nextGasObject = await SuiPricePusher.tryRefreshObjectReference(this.
|
|
198
|
+
nextGasObject = await SuiPricePusher.tryRefreshObjectReference(this.provider, gasObject);
|
|
193
199
|
}
|
|
194
200
|
console.error(e);
|
|
195
201
|
if ("data" in e) {
|
|
@@ -203,10 +209,10 @@ class SuiPricePusher {
|
|
|
203
209
|
}
|
|
204
210
|
// This function will smash all coins owned by the signer into one, and then
|
|
205
211
|
// split them equally into numGasObjects.
|
|
206
|
-
static async initializeGasPool(signer, numGasObjects) {
|
|
207
|
-
const signerAddress = await signer.
|
|
208
|
-
const consolidatedCoin = await SuiPricePusher.mergeGasCoinsIntoOne(signer, signerAddress);
|
|
209
|
-
const coinResult = await
|
|
212
|
+
static async initializeGasPool(signer, provider, numGasObjects) {
|
|
213
|
+
const signerAddress = await signer.toSuiAddress();
|
|
214
|
+
const consolidatedCoin = await SuiPricePusher.mergeGasCoinsIntoOne(signer, provider, signerAddress);
|
|
215
|
+
const coinResult = await provider.getObject({
|
|
210
216
|
id: consolidatedCoin.objectId,
|
|
211
217
|
options: { showContent: true },
|
|
212
218
|
});
|
|
@@ -214,12 +220,14 @@ class SuiPricePusher {
|
|
|
214
220
|
if (coinResult.data &&
|
|
215
221
|
coinResult.data.content &&
|
|
216
222
|
coinResult.data.content.dataType == "moveObject") {
|
|
223
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
224
|
+
// @ts-ignore
|
|
217
225
|
balance = coinResult.data.content.fields.balance;
|
|
218
226
|
}
|
|
219
227
|
else
|
|
220
228
|
throw new Error("Bad coin object");
|
|
221
229
|
const splitAmount = (BigInt(balance) - BigInt(GAS_FEE_FOR_SPLIT)) / BigInt(numGasObjects);
|
|
222
|
-
const gasPool = await SuiPricePusher.splitGasCoinEqually(signer, signerAddress, Number(splitAmount), numGasObjects, consolidatedCoin);
|
|
230
|
+
const gasPool = await SuiPricePusher.splitGasCoinEqually(signer, provider, signerAddress, Number(splitAmount), numGasObjects, consolidatedCoin);
|
|
223
231
|
console.log("Gas pool is filled with coins: ", gasPool);
|
|
224
232
|
return gasPool;
|
|
225
233
|
}
|
|
@@ -268,28 +276,29 @@ class SuiPricePusher {
|
|
|
268
276
|
}
|
|
269
277
|
return [...coins].map((item) => JSON.parse(item));
|
|
270
278
|
}
|
|
271
|
-
static async splitGasCoinEqually(signer, signerAddress, splitAmount, numGasObjects, gasCoin) {
|
|
279
|
+
static async splitGasCoinEqually(signer, provider, signerAddress, splitAmount, numGasObjects, gasCoin) {
|
|
272
280
|
// TODO: implement chunking if numGasObjects exceeds MAX_NUM_CREATED_OBJECTS
|
|
273
|
-
const tx = new
|
|
281
|
+
const tx = new transactions_1.TransactionBlock();
|
|
274
282
|
const coins = tx.splitCoins(tx.gas, Array.from({ length: numGasObjects }, () => tx.pure(splitAmount)));
|
|
275
283
|
tx.transferObjects(Array.from({ length: numGasObjects }, (_, i) => coins[i]), tx.pure(signerAddress));
|
|
276
284
|
tx.setGasPayment([gasCoin]);
|
|
277
|
-
const result = await
|
|
285
|
+
const result = await provider.signAndExecuteTransactionBlock({
|
|
286
|
+
signer,
|
|
278
287
|
transactionBlock: tx,
|
|
279
288
|
options: { showEffects: true },
|
|
280
289
|
});
|
|
281
|
-
const error =
|
|
290
|
+
const error = result?.effects?.status.error;
|
|
282
291
|
if (error) {
|
|
283
292
|
throw new Error(`Failed to initialize gas pool: ${error}. Try re-running the script`);
|
|
284
293
|
}
|
|
285
|
-
const newCoins =
|
|
294
|
+
const newCoins = result.effects.created.map((obj) => obj.reference);
|
|
286
295
|
if (newCoins.length !== numGasObjects) {
|
|
287
296
|
throw new Error(`Failed to initialize gas pool. Expected ${numGasObjects}, got: ${newCoins}`);
|
|
288
297
|
}
|
|
289
298
|
return newCoins;
|
|
290
299
|
}
|
|
291
|
-
static async mergeGasCoinsIntoOne(signer, owner) {
|
|
292
|
-
const gasCoins = await SuiPricePusher.getAllGasCoins(
|
|
300
|
+
static async mergeGasCoinsIntoOne(signer, provider, owner) {
|
|
301
|
+
const gasCoins = await SuiPricePusher.getAllGasCoins(provider, owner);
|
|
293
302
|
// skip merging if there is only one coin
|
|
294
303
|
if (gasCoins.length === 1) {
|
|
295
304
|
return gasCoins[0];
|
|
@@ -298,7 +307,7 @@ class SuiPricePusher {
|
|
|
298
307
|
let finalCoin;
|
|
299
308
|
const lockedAddresses = new Set();
|
|
300
309
|
for (let i = 0; i < gasCoinsChunks.length; i++) {
|
|
301
|
-
const mergeTx = new
|
|
310
|
+
const mergeTx = new transactions_1.TransactionBlock();
|
|
302
311
|
let coins = gasCoinsChunks[i];
|
|
303
312
|
coins = coins.filter((coin) => !lockedAddresses.has(coin.objectId));
|
|
304
313
|
if (finalCoin) {
|
|
@@ -307,7 +316,8 @@ class SuiPricePusher {
|
|
|
307
316
|
mergeTx.setGasPayment(coins);
|
|
308
317
|
let mergeResult;
|
|
309
318
|
try {
|
|
310
|
-
mergeResult = await
|
|
319
|
+
mergeResult = await provider.signAndExecuteTransactionBlock({
|
|
320
|
+
signer,
|
|
311
321
|
transactionBlock: mergeTx,
|
|
312
322
|
options: { showEffects: true },
|
|
313
323
|
});
|
|
@@ -325,11 +335,11 @@ class SuiPricePusher {
|
|
|
325
335
|
}
|
|
326
336
|
throw e;
|
|
327
337
|
}
|
|
328
|
-
const error =
|
|
338
|
+
const error = mergeResult?.effects?.status.error;
|
|
329
339
|
if (error) {
|
|
330
340
|
throw new Error(`Failed to merge coins when initializing gas pool: ${error}. Try re-running the script`);
|
|
331
341
|
}
|
|
332
|
-
finalCoin =
|
|
342
|
+
finalCoin = mergeResult.effects.mutated.map((obj) => obj.reference)[0];
|
|
333
343
|
}
|
|
334
344
|
return finalCoin;
|
|
335
345
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pythnetwork/price-pusher",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.4.2",
|
|
4
4
|
"description": "Pyth Price Pusher",
|
|
5
5
|
"homepage": "https://pyth.network",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -45,24 +45,26 @@
|
|
|
45
45
|
"@typescript-eslint/eslint-plugin": "^5.20.0",
|
|
46
46
|
"@typescript-eslint/parser": "^5.20.0",
|
|
47
47
|
"eslint": "^8.13.0",
|
|
48
|
-
"jest": "^
|
|
48
|
+
"jest": "^29.7.0",
|
|
49
49
|
"prettier": "^2.6.2",
|
|
50
|
-
"ts-jest": "^
|
|
51
|
-
"typescript": "^
|
|
50
|
+
"ts-jest": "^29.1.1",
|
|
51
|
+
"typescript": "^5.3.3"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@injectivelabs/sdk-ts": "1.10.72",
|
|
55
|
-
"@mysten/sui.js": "^0.
|
|
55
|
+
"@mysten/sui.js": "^0.49.1",
|
|
56
56
|
"@pythnetwork/price-service-client": "*",
|
|
57
57
|
"@pythnetwork/pyth-sdk-solidity": "*",
|
|
58
|
+
"@pythnetwork/pyth-solana-receiver": "*",
|
|
58
59
|
"@pythnetwork/pyth-sui-js": "*",
|
|
59
60
|
"@truffle/hdwallet-provider": "^2.1.3",
|
|
60
61
|
"aptos": "^1.8.5",
|
|
61
62
|
"joi": "^17.6.0",
|
|
63
|
+
"near-api-js": "^3.0.2",
|
|
62
64
|
"web3": "^1.8.1",
|
|
63
65
|
"web3-eth-contract": "^1.8.1",
|
|
64
66
|
"yaml": "^2.1.1",
|
|
65
67
|
"yargs": "^17.5.1"
|
|
66
68
|
},
|
|
67
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "62d189e3b5e3cdbbfba04c1ebd677b28f4a6f693"
|
|
68
70
|
}
|