@pythnetwork/pyth-sui-js 2.3.0 → 3.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.
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "SuiPriceServiceConnection", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return SuiPriceServiceConnection;
9
+ }
10
+ });
11
+ const _nodebuffer = require("node:buffer");
12
+ const _hermesclient = require("@pythnetwork/hermes-client");
13
+ class SuiPriceServiceConnection extends _hermesclient.HermesClient {
14
+ /**
15
+ * Gets price update data (either batch price attestation VAAs or accumulator messages, depending on the chosen endpoint), which then
16
+ * can be submitted to the Pyth contract to update the prices. This will throw an axios error if there is a network problem or
17
+ * the price service returns a non-ok response (e.g: Invalid price ids)
18
+ *
19
+ * @param priceIds - Array of hex-encoded price ids.
20
+ * @returns Array of buffers containing the price update data.
21
+ */ async getPriceFeedsUpdateData(priceIds) {
22
+ // Fetch the latest price feed update VAAs from the price service
23
+ const updateData = await this.getLatestPriceUpdates(priceIds, {
24
+ encoding: "base64",
25
+ parsed: false
26
+ });
27
+ return updateData.binary.data.map((update)=>_nodebuffer.Buffer.from(update, "base64"));
28
+ }
29
+ }
@@ -1,14 +1,14 @@
1
- import { HermesClient, HexString } from "@pythnetwork/hermes-client";
2
- import { Buffer } from "buffer";
1
+ import { Buffer } from "node:buffer";
2
+ import type { HexString } from "@pythnetwork/hermes-client";
3
+ import { HermesClient } from "@pythnetwork/hermes-client";
3
4
  export declare class SuiPriceServiceConnection extends HermesClient {
4
5
  /**
5
6
  * Gets price update data (either batch price attestation VAAs or accumulator messages, depending on the chosen endpoint), which then
6
7
  * can be submitted to the Pyth contract to update the prices. This will throw an axios error if there is a network problem or
7
8
  * the price service returns a non-ok response (e.g: Invalid price ids)
8
9
  *
9
- * @param priceIds Array of hex-encoded price ids.
10
+ * @param priceIds - Array of hex-encoded price ids.
10
11
  * @returns Array of buffers containing the price update data.
11
12
  */
12
13
  getPriceFeedsUpdateData(priceIds: HexString[]): Promise<Buffer[]>;
13
14
  }
14
- //# sourceMappingURL=SuiPriceServiceConnection.d.ts.map
@@ -0,0 +1,284 @@
1
+ /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable no-console */ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "SuiPythClient", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return SuiPythClient;
9
+ }
10
+ });
11
+ const _nodebuffer = require("node:buffer");
12
+ const _bcs = require("@mysten/sui/bcs");
13
+ const _utils = require("@mysten/sui/utils");
14
+ const MAX_ARGUMENT_SIZE = 16 * 1024;
15
+ class SuiPythClient {
16
+ provider;
17
+ pythStateId;
18
+ wormholeStateId;
19
+ pythPackageId;
20
+ wormholePackageId;
21
+ priceTableInfo;
22
+ priceFeedObjectIdCache = new Map();
23
+ baseUpdateFee;
24
+ constructor(provider, pythStateId, wormholeStateId){
25
+ this.provider = provider;
26
+ this.pythStateId = pythStateId;
27
+ this.wormholeStateId = wormholeStateId;
28
+ this.pythPackageId = undefined;
29
+ this.wormholePackageId = undefined;
30
+ }
31
+ async getBaseUpdateFee() {
32
+ if (this.baseUpdateFee === undefined) {
33
+ const result = await this.provider.getObject({
34
+ id: this.pythStateId,
35
+ options: {
36
+ showContent: true
37
+ }
38
+ });
39
+ if (!result.data?.content || result.data.content.dataType !== "moveObject") throw new Error("Unable to fetch pyth state object");
40
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
41
+ // @ts-ignore
42
+ this.baseUpdateFee = result.data.content.fields.base_update_fee;
43
+ }
44
+ return this.baseUpdateFee;
45
+ }
46
+ /**
47
+ * getPackageId returns the latest package id that the object belongs to. Use this to
48
+ * fetch the latest package id for a given object id and handle package upgrades automatically.
49
+ * @param objectId - the object id
50
+ * @returns package id
51
+ */ async getPackageId(objectId) {
52
+ const state = await this.provider.getObject({
53
+ id: objectId,
54
+ options: {
55
+ showContent: true
56
+ }
57
+ }).then((result)=>{
58
+ if (result.data?.content?.dataType == "moveObject") {
59
+ return result.data.content.fields;
60
+ }
61
+ console.log(result.data?.content);
62
+ throw new Error(`Cannot fetch package id for object ${objectId}`);
63
+ });
64
+ if ("upgrade_cap" in state) {
65
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
66
+ // @ts-ignore
67
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
68
+ return state.upgrade_cap.fields.package;
69
+ }
70
+ throw new Error("upgrade_cap not found");
71
+ }
72
+ /**
73
+ * Adds the commands for calling wormhole and verifying the vaas and returns the verified vaas.
74
+ * @param vaas - array of vaas to verify
75
+ * @param tx - transaction block to add commands to
76
+ */ async verifyVaas(vaas, tx) {
77
+ const wormholePackageId = await this.getWormholePackageId();
78
+ const verifiedVaas = [];
79
+ for (const vaa of vaas){
80
+ const [verifiedVaa] = tx.moveCall({
81
+ target: `${wormholePackageId}::vaa::parse_and_verify`,
82
+ arguments: [
83
+ tx.object(this.wormholeStateId),
84
+ tx.pure(_bcs.bcs.vector(_bcs.bcs.U8).serialize([
85
+ ...vaa
86
+ ], {
87
+ maxSize: MAX_ARGUMENT_SIZE
88
+ }).toBytes()),
89
+ tx.object(_utils.SUI_CLOCK_OBJECT_ID)
90
+ ]
91
+ });
92
+ verifiedVaas.push(verifiedVaa);
93
+ }
94
+ return verifiedVaas;
95
+ }
96
+ async verifyVaasAndGetHotPotato(tx, updates, packageId) {
97
+ if (updates.length > 1) {
98
+ throw new Error("SDK does not support sending multiple accumulator messages in a single transaction");
99
+ }
100
+ const vaa = this.extractVaaBytesFromAccumulatorMessage(updates[0]);
101
+ const verifiedVaas = await this.verifyVaas([
102
+ vaa
103
+ ], tx);
104
+ const [priceUpdatesHotPotato] = tx.moveCall({
105
+ target: `${packageId}::pyth::create_authenticated_price_infos_using_accumulator`,
106
+ arguments: [
107
+ tx.object(this.pythStateId),
108
+ tx.pure(_bcs.bcs.vector(_bcs.bcs.U8).serialize([
109
+ ...updates[0]
110
+ ], {
111
+ maxSize: MAX_ARGUMENT_SIZE
112
+ }).toBytes()),
113
+ verifiedVaas[0],
114
+ tx.object(_utils.SUI_CLOCK_OBJECT_ID)
115
+ ]
116
+ });
117
+ return priceUpdatesHotPotato;
118
+ }
119
+ async executePriceFeedUpdates(tx, packageId, feedIds, // eslint-disable-next-line @typescript-eslint/no-explicit-any
120
+ priceUpdatesHotPotato, coins) {
121
+ const priceInfoObjects = [];
122
+ let coinId = 0;
123
+ for (const feedId of feedIds){
124
+ const priceInfoObjectId = await this.getPriceFeedObjectId(feedId);
125
+ if (!priceInfoObjectId) {
126
+ throw new Error(`Price feed ${feedId} not found, please create it first`);
127
+ }
128
+ priceInfoObjects.push(priceInfoObjectId);
129
+ [priceUpdatesHotPotato] = tx.moveCall({
130
+ target: `${packageId}::pyth::update_single_price_feed`,
131
+ arguments: [
132
+ tx.object(this.pythStateId),
133
+ priceUpdatesHotPotato,
134
+ tx.object(priceInfoObjectId),
135
+ coins[coinId],
136
+ tx.object(_utils.SUI_CLOCK_OBJECT_ID)
137
+ ]
138
+ });
139
+ coinId++;
140
+ }
141
+ tx.moveCall({
142
+ target: `${packageId}::hot_potato_vector::destroy`,
143
+ arguments: [
144
+ priceUpdatesHotPotato
145
+ ],
146
+ typeArguments: [
147
+ `${packageId}::price_info::PriceInfo`
148
+ ]
149
+ });
150
+ return priceInfoObjects;
151
+ }
152
+ /**
153
+ * Adds the necessary commands for updating the pyth price feeds to the transaction block.
154
+ * @param tx - transaction block to add commands to
155
+ * @param updates - array of price feed updates received from the price service
156
+ * @param feedIds - array of feed ids to update (in hex format)
157
+ */ async updatePriceFeeds(tx, updates, feedIds) {
158
+ const packageId = await this.getPythPackageId();
159
+ const priceUpdatesHotPotato = await this.verifyVaasAndGetHotPotato(tx, updates, packageId);
160
+ const baseUpdateFee = await this.getBaseUpdateFee();
161
+ const coins = tx.splitCoins(tx.gas, feedIds.map(()=>tx.pure.u64(baseUpdateFee)));
162
+ return await this.executePriceFeedUpdates(tx, packageId, feedIds, priceUpdatesHotPotato, coins);
163
+ }
164
+ /**
165
+ * Updates price feeds using the coin input for payment. Coins can be generated by calling splitCoin on tx.gas.
166
+ * @param tx - transaction block to add commands to
167
+ * @param updates - array of price feed updates received from the price service
168
+ * @param feedIds - array of feed ids to update (in hex format)
169
+ * @param coins - array of Coins for payment of update operations
170
+ */ async updatePriceFeedsWithCoins(tx, updates, feedIds, coins) {
171
+ const packageId = await this.getPythPackageId();
172
+ const priceUpdatesHotPotato = await this.verifyVaasAndGetHotPotato(tx, updates, packageId);
173
+ return await this.executePriceFeedUpdates(tx, packageId, feedIds, priceUpdatesHotPotato, coins);
174
+ }
175
+ async createPriceFeed(tx, updates) {
176
+ const packageId = await this.getPythPackageId();
177
+ if (updates.length > 1) {
178
+ throw new Error("SDK does not support sending multiple accumulator messages in a single transaction");
179
+ }
180
+ const vaa = this.extractVaaBytesFromAccumulatorMessage(updates[0]);
181
+ const verifiedVaas = await this.verifyVaas([
182
+ vaa
183
+ ], tx);
184
+ tx.moveCall({
185
+ target: `${packageId}::pyth::create_price_feeds_using_accumulator`,
186
+ arguments: [
187
+ tx.object(this.pythStateId),
188
+ tx.pure(_bcs.bcs.vector(_bcs.bcs.U8).serialize([
189
+ ...updates[0]
190
+ ], {
191
+ maxSize: MAX_ARGUMENT_SIZE
192
+ }).toBytes()),
193
+ verifiedVaas[0],
194
+ tx.object(_utils.SUI_CLOCK_OBJECT_ID)
195
+ ]
196
+ });
197
+ }
198
+ /**
199
+ * Get the packageId for the wormhole package if not already cached
200
+ */ async getWormholePackageId() {
201
+ if (!this.wormholePackageId) {
202
+ this.wormholePackageId = await this.getPackageId(this.wormholeStateId);
203
+ }
204
+ return this.wormholePackageId;
205
+ }
206
+ /**
207
+ * Get the packageId for the pyth package if not already cached
208
+ */ async getPythPackageId() {
209
+ if (!this.pythPackageId) {
210
+ this.pythPackageId = await this.getPackageId(this.pythStateId);
211
+ }
212
+ return this.pythPackageId;
213
+ }
214
+ /**
215
+ * Get the priceFeedObjectId for a given feedId if not already cached
216
+ * @param feedId - the feed id
217
+ */ async getPriceFeedObjectId(feedId) {
218
+ const normalizedFeedId = feedId.replace("0x", "");
219
+ if (!this.priceFeedObjectIdCache.has(normalizedFeedId)) {
220
+ const { id: tableId, fieldType } = await this.getPriceTableInfo();
221
+ const result = await this.provider.getDynamicFieldObject({
222
+ parentId: tableId,
223
+ name: {
224
+ type: `${fieldType}::price_identifier::PriceIdentifier`,
225
+ value: {
226
+ bytes: [
227
+ ..._nodebuffer.Buffer.from(normalizedFeedId, "hex")
228
+ ]
229
+ }
230
+ }
231
+ });
232
+ if (!result.data?.content) {
233
+ return undefined;
234
+ }
235
+ if (result.data.content.dataType !== "moveObject") {
236
+ throw new Error("Price feed type mismatch");
237
+ }
238
+ this.priceFeedObjectIdCache.set(normalizedFeedId, // eslint-disable-next-line @typescript-eslint/ban-ts-comment
239
+ // @ts-ignore
240
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
241
+ result.data.content.fields.value);
242
+ }
243
+ return this.priceFeedObjectIdCache.get(normalizedFeedId);
244
+ }
245
+ /**
246
+ * Fetches the price table object id for the current state id if not cached
247
+ * @returns price table object id
248
+ */ async getPriceTableInfo() {
249
+ if (this.priceTableInfo === undefined) {
250
+ const result = await this.provider.getDynamicFieldObject({
251
+ parentId: this.pythStateId,
252
+ name: {
253
+ type: "vector<u8>",
254
+ value: "price_info"
255
+ }
256
+ });
257
+ if (!result.data?.type) {
258
+ throw new Error("Price Table not found, contract may not be initialized");
259
+ }
260
+ let type = result.data.type.replace("0x2::table::Table<", "");
261
+ type = type.replace("::price_identifier::PriceIdentifier, 0x2::object::ID>", "");
262
+ this.priceTableInfo = {
263
+ id: result.data.objectId,
264
+ fieldType: type
265
+ };
266
+ }
267
+ return this.priceTableInfo;
268
+ }
269
+ /**
270
+ * Obtains the vaa bytes embedded in an accumulator message.
271
+ * @param accumulatorMessage - the accumulator price update message
272
+ * @returns vaa bytes as a uint8 array
273
+ */ extractVaaBytesFromAccumulatorMessage(accumulatorMessage) {
274
+ // the first 6 bytes in the accumulator message encode the header, major, and minor bytes
275
+ // we ignore them, since we are only interested in the VAA bytes
276
+ const trailingPayloadSize = accumulatorMessage.readUint8(6);
277
+ const vaaSizeOffset = 7 + // header bytes (header(4) + major(1) + minor(1) + trailing payload size(1))
278
+ trailingPayloadSize + // trailing payload (variable number of bytes)
279
+ 1; // proof_type (1 byte)
280
+ const vaaSize = accumulatorMessage.readUint16BE(vaaSizeOffset);
281
+ const vaaOffset = vaaSizeOffset + 2;
282
+ return accumulatorMessage.subarray(vaaOffset, vaaOffset + vaaSize);
283
+ }
284
+ }
@@ -1,7 +1,7 @@
1
+ import { Buffer } from "node:buffer";
1
2
  import { SuiClient } from "@mysten/sui/client";
2
3
  import { Transaction } from "@mysten/sui/transactions";
3
- import { HexString } from "@pythnetwork/hermes-client";
4
- import { Buffer } from "buffer";
4
+ import type { HexString } from "@pythnetwork/hermes-client";
5
5
  type NestedTransactionResult = {
6
6
  $kind: "NestedResult";
7
7
  NestedResult: [number, number];
@@ -21,34 +21,34 @@ export declare class SuiPythClient {
21
21
  /**
22
22
  * getPackageId returns the latest package id that the object belongs to. Use this to
23
23
  * fetch the latest package id for a given object id and handle package upgrades automatically.
24
- * @param objectId
24
+ * @param objectId - the object id
25
25
  * @returns package id
26
26
  */
27
27
  getPackageId(objectId: ObjectId): Promise<ObjectId>;
28
28
  /**
29
29
  * Adds the commands for calling wormhole and verifying the vaas and returns the verified vaas.
30
- * @param vaas array of vaas to verify
31
- * @param tx transaction block to add commands to
30
+ * @param vaas - array of vaas to verify
31
+ * @param tx - transaction block to add commands to
32
32
  */
33
- verifyVaas(vaas: Buffer[], tx: Transaction): Promise<{
33
+ verifyVaas(vaas: Buffer[], tx: Transaction): Promise<({
34
34
  $kind: "NestedResult";
35
35
  NestedResult: [number, number];
36
- }[]>;
36
+ } | undefined)[]>;
37
37
  verifyVaasAndGetHotPotato(tx: Transaction, updates: Buffer[], packageId: string): Promise<NestedTransactionResult>;
38
38
  executePriceFeedUpdates(tx: Transaction, packageId: string, feedIds: HexString[], priceUpdatesHotPotato: any, coins: NestedTransactionResult[]): Promise<string[]>;
39
39
  /**
40
40
  * Adds the necessary commands for updating the pyth price feeds to the transaction block.
41
- * @param tx transaction block to add commands to
42
- * @param updates array of price feed updates received from the price service
43
- * @param feedIds array of feed ids to update (in hex format)
41
+ * @param tx - transaction block to add commands to
42
+ * @param updates - array of price feed updates received from the price service
43
+ * @param feedIds - array of feed ids to update (in hex format)
44
44
  */
45
45
  updatePriceFeeds(tx: Transaction, updates: Buffer[], feedIds: HexString[]): Promise<ObjectId[]>;
46
46
  /**
47
47
  * Updates price feeds using the coin input for payment. Coins can be generated by calling splitCoin on tx.gas.
48
- * @param tx transaction block to add commands to
49
- * @param updates array of price feed updates received from the price service
50
- * @param feedIds array of feed ids to update (in hex format)
51
- * @param coins array of Coins for payment of update operations
48
+ * @param tx - transaction block to add commands to
49
+ * @param updates - array of price feed updates received from the price service
50
+ * @param feedIds - array of feed ids to update (in hex format)
51
+ * @param coins - array of Coins for payment of update operations
52
52
  */
53
53
  updatePriceFeedsWithCoins(tx: Transaction, updates: Buffer[], feedIds: HexString[], coins: NestedTransactionResult[]): Promise<ObjectId[]>;
54
54
  createPriceFeed(tx: Transaction, updates: Buffer[]): Promise<void>;
@@ -62,7 +62,7 @@ export declare class SuiPythClient {
62
62
  getPythPackageId(): Promise<string>;
63
63
  /**
64
64
  * Get the priceFeedObjectId for a given feedId if not already cached
65
- * @param feedId
65
+ * @param feedId - the feed id
66
66
  */
67
67
  getPriceFeedObjectId(feedId: HexString): Promise<ObjectId | undefined>;
68
68
  /**
@@ -81,4 +81,3 @@ export declare class SuiPythClient {
81
81
  extractVaaBytesFromAccumulatorMessage(accumulatorMessage: Buffer): Buffer;
82
82
  }
83
83
  export {};
84
- //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get SuiPriceServiceConnection () {
13
+ return _SuiPriceServiceConnection.SuiPriceServiceConnection;
14
+ },
15
+ get SuiPythClient () {
16
+ return _client.SuiPythClient;
17
+ }
18
+ });
19
+ const _SuiPriceServiceConnection = require("./SuiPriceServiceConnection.cjs");
20
+ const _client = require("./client.cjs");
@@ -0,0 +1,3 @@
1
+ export { SuiPriceServiceConnection } from "./SuiPriceServiceConnection.js";
2
+ export { SuiPythClient } from "./client.js";
3
+ export type { AssetType, BinaryPriceUpdate, DurationInMs, DurationInSeconds, EncodingType, HermesClientConfig, HexString, PriceFeedMetadata, PriceIdInput, PriceUpdate, PublisherCaps, UnixTimestamp, } from "@pythnetwork/hermes-client";
@@ -0,0 +1 @@
1
+ { "type": "commonjs" }
@@ -0,0 +1,14 @@
1
+ import { Buffer } from "node:buffer";
2
+ import type { HexString } from "@pythnetwork/hermes-client";
3
+ import { HermesClient } from "@pythnetwork/hermes-client";
4
+ export declare class SuiPriceServiceConnection extends HermesClient {
5
+ /**
6
+ * Gets price update data (either batch price attestation VAAs or accumulator messages, depending on the chosen endpoint), which then
7
+ * can be submitted to the Pyth contract to update the prices. This will throw an axios error if there is a network problem or
8
+ * the price service returns a non-ok response (e.g: Invalid price ids)
9
+ *
10
+ * @param priceIds - Array of hex-encoded price ids.
11
+ * @returns Array of buffers containing the price update data.
12
+ */
13
+ getPriceFeedsUpdateData(priceIds: HexString[]): Promise<Buffer[]>;
14
+ }
@@ -0,0 +1,19 @@
1
+ import { Buffer } from "node:buffer";
2
+ import { HermesClient } from "@pythnetwork/hermes-client";
3
+ export class SuiPriceServiceConnection extends HermesClient {
4
+ /**
5
+ * Gets price update data (either batch price attestation VAAs or accumulator messages, depending on the chosen endpoint), which then
6
+ * can be submitted to the Pyth contract to update the prices. This will throw an axios error if there is a network problem or
7
+ * the price service returns a non-ok response (e.g: Invalid price ids)
8
+ *
9
+ * @param priceIds - Array of hex-encoded price ids.
10
+ * @returns Array of buffers containing the price update data.
11
+ */ async getPriceFeedsUpdateData(priceIds) {
12
+ // Fetch the latest price feed update VAAs from the price service
13
+ const updateData = await this.getLatestPriceUpdates(priceIds, {
14
+ encoding: "base64",
15
+ parsed: false
16
+ });
17
+ return updateData.binary.data.map((update)=>Buffer.from(update, "base64"));
18
+ }
19
+ }
@@ -0,0 +1,83 @@
1
+ import { Buffer } from "node:buffer";
2
+ import { SuiClient } from "@mysten/sui/client";
3
+ import { Transaction } from "@mysten/sui/transactions";
4
+ import type { HexString } from "@pythnetwork/hermes-client";
5
+ type NestedTransactionResult = {
6
+ $kind: "NestedResult";
7
+ NestedResult: [number, number];
8
+ };
9
+ export type ObjectId = string;
10
+ export declare class SuiPythClient {
11
+ provider: SuiClient;
12
+ pythStateId: ObjectId;
13
+ wormholeStateId: ObjectId;
14
+ private pythPackageId;
15
+ private wormholePackageId;
16
+ private priceTableInfo;
17
+ private priceFeedObjectIdCache;
18
+ private baseUpdateFee;
19
+ constructor(provider: SuiClient, pythStateId: ObjectId, wormholeStateId: ObjectId);
20
+ getBaseUpdateFee(): Promise<number>;
21
+ /**
22
+ * getPackageId returns the latest package id that the object belongs to. Use this to
23
+ * fetch the latest package id for a given object id and handle package upgrades automatically.
24
+ * @param objectId - the object id
25
+ * @returns package id
26
+ */
27
+ getPackageId(objectId: ObjectId): Promise<ObjectId>;
28
+ /**
29
+ * Adds the commands for calling wormhole and verifying the vaas and returns the verified vaas.
30
+ * @param vaas - array of vaas to verify
31
+ * @param tx - transaction block to add commands to
32
+ */
33
+ verifyVaas(vaas: Buffer[], tx: Transaction): Promise<({
34
+ $kind: "NestedResult";
35
+ NestedResult: [number, number];
36
+ } | undefined)[]>;
37
+ verifyVaasAndGetHotPotato(tx: Transaction, updates: Buffer[], packageId: string): Promise<NestedTransactionResult>;
38
+ executePriceFeedUpdates(tx: Transaction, packageId: string, feedIds: HexString[], priceUpdatesHotPotato: any, coins: NestedTransactionResult[]): Promise<string[]>;
39
+ /**
40
+ * Adds the necessary commands for updating the pyth price feeds to the transaction block.
41
+ * @param tx - transaction block to add commands to
42
+ * @param updates - array of price feed updates received from the price service
43
+ * @param feedIds - array of feed ids to update (in hex format)
44
+ */
45
+ updatePriceFeeds(tx: Transaction, updates: Buffer[], feedIds: HexString[]): Promise<ObjectId[]>;
46
+ /**
47
+ * Updates price feeds using the coin input for payment. Coins can be generated by calling splitCoin on tx.gas.
48
+ * @param tx - transaction block to add commands to
49
+ * @param updates - array of price feed updates received from the price service
50
+ * @param feedIds - array of feed ids to update (in hex format)
51
+ * @param coins - array of Coins for payment of update operations
52
+ */
53
+ updatePriceFeedsWithCoins(tx: Transaction, updates: Buffer[], feedIds: HexString[], coins: NestedTransactionResult[]): Promise<ObjectId[]>;
54
+ createPriceFeed(tx: Transaction, updates: Buffer[]): Promise<void>;
55
+ /**
56
+ * Get the packageId for the wormhole package if not already cached
57
+ */
58
+ getWormholePackageId(): Promise<string>;
59
+ /**
60
+ * Get the packageId for the pyth package if not already cached
61
+ */
62
+ getPythPackageId(): Promise<string>;
63
+ /**
64
+ * Get the priceFeedObjectId for a given feedId if not already cached
65
+ * @param feedId - the feed id
66
+ */
67
+ getPriceFeedObjectId(feedId: HexString): Promise<ObjectId | undefined>;
68
+ /**
69
+ * Fetches the price table object id for the current state id if not cached
70
+ * @returns price table object id
71
+ */
72
+ getPriceTableInfo(): Promise<{
73
+ id: ObjectId;
74
+ fieldType: ObjectId;
75
+ }>;
76
+ /**
77
+ * Obtains the vaa bytes embedded in an accumulator message.
78
+ * @param accumulatorMessage - the accumulator price update message
79
+ * @returns vaa bytes as a uint8 array
80
+ */
81
+ extractVaaBytesFromAccumulatorMessage(accumulatorMessage: Buffer): Buffer;
82
+ }
83
+ export {};
@@ -1,11 +1,8 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SuiPythClient = void 0;
4
- const utils_1 = require("@mysten/sui/utils");
5
- const bcs_1 = require("@mysten/sui/bcs");
6
- const buffer_1 = require("buffer");
1
+ /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable no-console */ import { Buffer } from "node:buffer";
2
+ import { bcs } from "@mysten/sui/bcs";
3
+ import { SUI_CLOCK_OBJECT_ID } from "@mysten/sui/utils";
7
4
  const MAX_ARGUMENT_SIZE = 16 * 1024;
8
- class SuiPythClient {
5
+ export class SuiPythClient {
9
6
  provider;
10
7
  pythStateId;
11
8
  wormholeStateId;
@@ -14,7 +11,7 @@ class SuiPythClient {
14
11
  priceTableInfo;
15
12
  priceFeedObjectIdCache = new Map();
16
13
  baseUpdateFee;
17
- constructor(provider, pythStateId, wormholeStateId) {
14
+ constructor(provider, pythStateId, wormholeStateId){
18
15
  this.provider = provider;
19
16
  this.pythStateId = pythStateId;
20
17
  this.wormholeStateId = wormholeStateId;
@@ -25,12 +22,11 @@ class SuiPythClient {
25
22
  if (this.baseUpdateFee === undefined) {
26
23
  const result = await this.provider.getObject({
27
24
  id: this.pythStateId,
28
- options: { showContent: true },
25
+ options: {
26
+ showContent: true
27
+ }
29
28
  });
30
- if (!result.data ||
31
- !result.data.content ||
32
- result.data.content.dataType !== "moveObject")
33
- throw new Error("Unable to fetch pyth state object");
29
+ if (!result.data?.content || result.data.content.dataType !== "moveObject") throw new Error("Unable to fetch pyth state object");
34
30
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
35
31
  // @ts-ignore
36
32
  this.baseUpdateFee = result.data.content.fields.base_update_fee;
@@ -38,20 +34,17 @@ class SuiPythClient {
38
34
  return this.baseUpdateFee;
39
35
  }
40
36
  /**
41
- * getPackageId returns the latest package id that the object belongs to. Use this to
42
- * fetch the latest package id for a given object id and handle package upgrades automatically.
43
- * @param objectId
44
- * @returns package id
45
- */
46
- async getPackageId(objectId) {
47
- const state = await this.provider
48
- .getObject({
37
+ * getPackageId returns the latest package id that the object belongs to. Use this to
38
+ * fetch the latest package id for a given object id and handle package upgrades automatically.
39
+ * @param objectId - the object id
40
+ * @returns package id
41
+ */ async getPackageId(objectId) {
42
+ const state = await this.provider.getObject({
49
43
  id: objectId,
50
44
  options: {
51
- showContent: true,
52
- },
53
- })
54
- .then((result) => {
45
+ showContent: true
46
+ }
47
+ }).then((result)=>{
55
48
  if (result.data?.content?.dataType == "moveObject") {
56
49
  return result.data.content.fields;
57
50
  }
@@ -61,31 +54,30 @@ class SuiPythClient {
61
54
  if ("upgrade_cap" in state) {
62
55
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
63
56
  // @ts-ignore
57
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
64
58
  return state.upgrade_cap.fields.package;
65
59
  }
66
60
  throw new Error("upgrade_cap not found");
67
61
  }
68
62
  /**
69
- * Adds the commands for calling wormhole and verifying the vaas and returns the verified vaas.
70
- * @param vaas array of vaas to verify
71
- * @param tx transaction block to add commands to
72
- */
73
- async verifyVaas(vaas, tx) {
63
+ * Adds the commands for calling wormhole and verifying the vaas and returns the verified vaas.
64
+ * @param vaas - array of vaas to verify
65
+ * @param tx - transaction block to add commands to
66
+ */ async verifyVaas(vaas, tx) {
74
67
  const wormholePackageId = await this.getWormholePackageId();
75
68
  const verifiedVaas = [];
76
- for (const vaa of vaas) {
69
+ for (const vaa of vaas){
77
70
  const [verifiedVaa] = tx.moveCall({
78
71
  target: `${wormholePackageId}::vaa::parse_and_verify`,
79
72
  arguments: [
80
73
  tx.object(this.wormholeStateId),
81
- tx.pure(bcs_1.bcs
82
- .vector(bcs_1.bcs.U8)
83
- .serialize(Array.from(vaa), {
84
- maxSize: MAX_ARGUMENT_SIZE,
85
- })
86
- .toBytes()),
87
- tx.object(utils_1.SUI_CLOCK_OBJECT_ID),
88
- ],
74
+ tx.pure(bcs.vector(bcs.U8).serialize([
75
+ ...vaa
76
+ ], {
77
+ maxSize: MAX_ARGUMENT_SIZE
78
+ }).toBytes()),
79
+ tx.object(SUI_CLOCK_OBJECT_ID)
80
+ ]
89
81
  });
90
82
  verifiedVaas.push(verifiedVaa);
91
83
  }
@@ -96,27 +88,29 @@ class SuiPythClient {
96
88
  throw new Error("SDK does not support sending multiple accumulator messages in a single transaction");
97
89
  }
98
90
  const vaa = this.extractVaaBytesFromAccumulatorMessage(updates[0]);
99
- const verifiedVaas = await this.verifyVaas([vaa], tx);
91
+ const verifiedVaas = await this.verifyVaas([
92
+ vaa
93
+ ], tx);
100
94
  const [priceUpdatesHotPotato] = tx.moveCall({
101
95
  target: `${packageId}::pyth::create_authenticated_price_infos_using_accumulator`,
102
96
  arguments: [
103
97
  tx.object(this.pythStateId),
104
- tx.pure(bcs_1.bcs
105
- .vector(bcs_1.bcs.U8)
106
- .serialize(Array.from(updates[0]), {
107
- maxSize: MAX_ARGUMENT_SIZE,
108
- })
109
- .toBytes()),
98
+ tx.pure(bcs.vector(bcs.U8).serialize([
99
+ ...updates[0]
100
+ ], {
101
+ maxSize: MAX_ARGUMENT_SIZE
102
+ }).toBytes()),
110
103
  verifiedVaas[0],
111
- tx.object(utils_1.SUI_CLOCK_OBJECT_ID),
112
- ],
104
+ tx.object(SUI_CLOCK_OBJECT_ID)
105
+ ]
113
106
  });
114
107
  return priceUpdatesHotPotato;
115
108
  }
116
- async executePriceFeedUpdates(tx, packageId, feedIds, priceUpdatesHotPotato, coins) {
109
+ async executePriceFeedUpdates(tx, packageId, feedIds, // eslint-disable-next-line @typescript-eslint/no-explicit-any
110
+ priceUpdatesHotPotato, coins) {
117
111
  const priceInfoObjects = [];
118
112
  let coinId = 0;
119
- for (const feedId of feedIds) {
113
+ for (const feedId of feedIds){
120
114
  const priceInfoObjectId = await this.getPriceFeedObjectId(feedId);
121
115
  if (!priceInfoObjectId) {
122
116
  throw new Error(`Price feed ${feedId} not found, please create it first`);
@@ -129,39 +123,41 @@ class SuiPythClient {
129
123
  priceUpdatesHotPotato,
130
124
  tx.object(priceInfoObjectId),
131
125
  coins[coinId],
132
- tx.object(utils_1.SUI_CLOCK_OBJECT_ID),
133
- ],
126
+ tx.object(SUI_CLOCK_OBJECT_ID)
127
+ ]
134
128
  });
135
129
  coinId++;
136
130
  }
137
131
  tx.moveCall({
138
132
  target: `${packageId}::hot_potato_vector::destroy`,
139
- arguments: [priceUpdatesHotPotato],
140
- typeArguments: [`${packageId}::price_info::PriceInfo`],
133
+ arguments: [
134
+ priceUpdatesHotPotato
135
+ ],
136
+ typeArguments: [
137
+ `${packageId}::price_info::PriceInfo`
138
+ ]
141
139
  });
142
140
  return priceInfoObjects;
143
141
  }
144
142
  /**
145
- * Adds the necessary commands for updating the pyth price feeds to the transaction block.
146
- * @param tx transaction block to add commands to
147
- * @param updates array of price feed updates received from the price service
148
- * @param feedIds array of feed ids to update (in hex format)
149
- */
150
- async updatePriceFeeds(tx, updates, feedIds) {
143
+ * Adds the necessary commands for updating the pyth price feeds to the transaction block.
144
+ * @param tx - transaction block to add commands to
145
+ * @param updates - array of price feed updates received from the price service
146
+ * @param feedIds - array of feed ids to update (in hex format)
147
+ */ async updatePriceFeeds(tx, updates, feedIds) {
151
148
  const packageId = await this.getPythPackageId();
152
149
  const priceUpdatesHotPotato = await this.verifyVaasAndGetHotPotato(tx, updates, packageId);
153
150
  const baseUpdateFee = await this.getBaseUpdateFee();
154
- const coins = tx.splitCoins(tx.gas, feedIds.map(() => tx.pure.u64(baseUpdateFee)));
151
+ const coins = tx.splitCoins(tx.gas, feedIds.map(()=>tx.pure.u64(baseUpdateFee)));
155
152
  return await this.executePriceFeedUpdates(tx, packageId, feedIds, priceUpdatesHotPotato, coins);
156
153
  }
157
154
  /**
158
- * Updates price feeds using the coin input for payment. Coins can be generated by calling splitCoin on tx.gas.
159
- * @param tx transaction block to add commands to
160
- * @param updates array of price feed updates received from the price service
161
- * @param feedIds array of feed ids to update (in hex format)
162
- * @param coins array of Coins for payment of update operations
163
- */
164
- async updatePriceFeedsWithCoins(tx, updates, feedIds, coins) {
155
+ * Updates price feeds using the coin input for payment. Coins can be generated by calling splitCoin on tx.gas.
156
+ * @param tx - transaction block to add commands to
157
+ * @param updates - array of price feed updates received from the price service
158
+ * @param feedIds - array of feed ids to update (in hex format)
159
+ * @param coins - array of Coins for payment of update operations
160
+ */ async updatePriceFeedsWithCoins(tx, updates, feedIds, coins) {
165
161
  const packageId = await this.getPythPackageId();
166
162
  const priceUpdatesHotPotato = await this.verifyVaasAndGetHotPotato(tx, updates, packageId);
167
163
  return await this.executePriceFeedUpdates(tx, packageId, feedIds, priceUpdatesHotPotato, coins);
@@ -172,45 +168,43 @@ class SuiPythClient {
172
168
  throw new Error("SDK does not support sending multiple accumulator messages in a single transaction");
173
169
  }
174
170
  const vaa = this.extractVaaBytesFromAccumulatorMessage(updates[0]);
175
- const verifiedVaas = await this.verifyVaas([vaa], tx);
171
+ const verifiedVaas = await this.verifyVaas([
172
+ vaa
173
+ ], tx);
176
174
  tx.moveCall({
177
175
  target: `${packageId}::pyth::create_price_feeds_using_accumulator`,
178
176
  arguments: [
179
177
  tx.object(this.pythStateId),
180
- tx.pure(bcs_1.bcs
181
- .vector(bcs_1.bcs.U8)
182
- .serialize(Array.from(updates[0]), {
183
- maxSize: MAX_ARGUMENT_SIZE,
184
- })
185
- .toBytes()),
178
+ tx.pure(bcs.vector(bcs.U8).serialize([
179
+ ...updates[0]
180
+ ], {
181
+ maxSize: MAX_ARGUMENT_SIZE
182
+ }).toBytes()),
186
183
  verifiedVaas[0],
187
- tx.object(utils_1.SUI_CLOCK_OBJECT_ID),
188
- ],
184
+ tx.object(SUI_CLOCK_OBJECT_ID)
185
+ ]
189
186
  });
190
187
  }
191
188
  /**
192
- * Get the packageId for the wormhole package if not already cached
193
- */
194
- async getWormholePackageId() {
189
+ * Get the packageId for the wormhole package if not already cached
190
+ */ async getWormholePackageId() {
195
191
  if (!this.wormholePackageId) {
196
192
  this.wormholePackageId = await this.getPackageId(this.wormholeStateId);
197
193
  }
198
194
  return this.wormholePackageId;
199
195
  }
200
196
  /**
201
- * Get the packageId for the pyth package if not already cached
202
- */
203
- async getPythPackageId() {
197
+ * Get the packageId for the pyth package if not already cached
198
+ */ async getPythPackageId() {
204
199
  if (!this.pythPackageId) {
205
200
  this.pythPackageId = await this.getPackageId(this.pythStateId);
206
201
  }
207
202
  return this.pythPackageId;
208
203
  }
209
204
  /**
210
- * Get the priceFeedObjectId for a given feedId if not already cached
211
- * @param feedId
212
- */
213
- async getPriceFeedObjectId(feedId) {
205
+ * Get the priceFeedObjectId for a given feedId if not already cached
206
+ * @param feedId - the feed id
207
+ */ async getPriceFeedObjectId(feedId) {
214
208
  const normalizedFeedId = feedId.replace("0x", "");
215
209
  if (!this.priceFeedObjectIdCache.has(normalizedFeedId)) {
216
210
  const { id: tableId, fieldType } = await this.getPriceTableInfo();
@@ -219,60 +213,62 @@ class SuiPythClient {
219
213
  name: {
220
214
  type: `${fieldType}::price_identifier::PriceIdentifier`,
221
215
  value: {
222
- bytes: Array.from(buffer_1.Buffer.from(normalizedFeedId, "hex")),
223
- },
224
- },
216
+ bytes: [
217
+ ...Buffer.from(normalizedFeedId, "hex")
218
+ ]
219
+ }
220
+ }
225
221
  });
226
- if (!result.data || !result.data.content) {
222
+ if (!result.data?.content) {
227
223
  return undefined;
228
224
  }
229
225
  if (result.data.content.dataType !== "moveObject") {
230
226
  throw new Error("Price feed type mismatch");
231
227
  }
232
- this.priceFeedObjectIdCache.set(normalizedFeedId,
233
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
228
+ this.priceFeedObjectIdCache.set(normalizedFeedId, // eslint-disable-next-line @typescript-eslint/ban-ts-comment
234
229
  // @ts-ignore
230
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
235
231
  result.data.content.fields.value);
236
232
  }
237
233
  return this.priceFeedObjectIdCache.get(normalizedFeedId);
238
234
  }
239
235
  /**
240
- * Fetches the price table object id for the current state id if not cached
241
- * @returns price table object id
242
- */
243
- async getPriceTableInfo() {
236
+ * Fetches the price table object id for the current state id if not cached
237
+ * @returns price table object id
238
+ */ async getPriceTableInfo() {
244
239
  if (this.priceTableInfo === undefined) {
245
240
  const result = await this.provider.getDynamicFieldObject({
246
241
  parentId: this.pythStateId,
247
242
  name: {
248
243
  type: "vector<u8>",
249
- value: "price_info",
250
- },
244
+ value: "price_info"
245
+ }
251
246
  });
252
- if (!result.data || !result.data.type) {
247
+ if (!result.data?.type) {
253
248
  throw new Error("Price Table not found, contract may not be initialized");
254
249
  }
255
250
  let type = result.data.type.replace("0x2::table::Table<", "");
256
251
  type = type.replace("::price_identifier::PriceIdentifier, 0x2::object::ID>", "");
257
- this.priceTableInfo = { id: result.data.objectId, fieldType: type };
252
+ this.priceTableInfo = {
253
+ id: result.data.objectId,
254
+ fieldType: type
255
+ };
258
256
  }
259
257
  return this.priceTableInfo;
260
258
  }
261
259
  /**
262
- * Obtains the vaa bytes embedded in an accumulator message.
263
- * @param accumulatorMessage - the accumulator price update message
264
- * @returns vaa bytes as a uint8 array
265
- */
266
- extractVaaBytesFromAccumulatorMessage(accumulatorMessage) {
260
+ * Obtains the vaa bytes embedded in an accumulator message.
261
+ * @param accumulatorMessage - the accumulator price update message
262
+ * @returns vaa bytes as a uint8 array
263
+ */ extractVaaBytesFromAccumulatorMessage(accumulatorMessage) {
267
264
  // the first 6 bytes in the accumulator message encode the header, major, and minor bytes
268
265
  // we ignore them, since we are only interested in the VAA bytes
269
266
  const trailingPayloadSize = accumulatorMessage.readUint8(6);
270
267
  const vaaSizeOffset = 7 + // header bytes (header(4) + major(1) + minor(1) + trailing payload size(1))
271
- trailingPayloadSize + // trailing payload (variable number of bytes)
272
- 1; // proof_type (1 byte)
268
+ trailingPayloadSize + // trailing payload (variable number of bytes)
269
+ 1; // proof_type (1 byte)
273
270
  const vaaSize = accumulatorMessage.readUint16BE(vaaSizeOffset);
274
271
  const vaaOffset = vaaSizeOffset + 2;
275
272
  return accumulatorMessage.subarray(vaaOffset, vaaOffset + vaaSize);
276
273
  }
277
274
  }
278
- exports.SuiPythClient = SuiPythClient;
@@ -0,0 +1,3 @@
1
+ export { SuiPriceServiceConnection } from "./SuiPriceServiceConnection.js";
2
+ export { SuiPythClient } from "./client.js";
3
+ export type { AssetType, BinaryPriceUpdate, DurationInMs, DurationInSeconds, EncodingType, HermesClientConfig, HexString, PriceFeedMetadata, PriceIdInput, PriceUpdate, PublisherCaps, UnixTimestamp, } from "@pythnetwork/hermes-client";
@@ -0,0 +1,2 @@
1
+ export { SuiPriceServiceConnection } from "./SuiPriceServiceConnection.mjs";
2
+ export { SuiPythClient } from "./client.mjs";
@@ -0,0 +1 @@
1
+ { "type": "module" }
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "@pythnetwork/pyth-sui-js",
3
- "version": "2.3.0",
3
+ "version": "3.0.0",
4
4
  "description": "Pyth Network Sui Utilities",
5
5
  "homepage": "https://pyth.network",
6
6
  "author": {
7
7
  "name": "Pyth Data Association"
8
8
  },
9
- "main": "lib/index.js",
10
- "types": "lib/index.d.ts",
9
+ "main": "./dist/cjs/index.cjs",
10
+ "types": "./dist/cjs/index.d.ts",
11
+ "type": "module",
11
12
  "files": [
12
- "lib/**/*"
13
+ "dist/**/*"
13
14
  ],
14
15
  "repository": {
15
16
  "type": "git",
@@ -26,6 +27,8 @@
26
27
  ],
27
28
  "license": "Apache-2.0",
28
29
  "devDependencies": {
30
+ "@cprussin/eslint-config": "^4.0.2",
31
+ "@pythnetwork/jest-config": "",
29
32
  "@truffle/hdwallet-provider": "^2.1.5",
30
33
  "@types/ethereum-protocol": "^1.0.2",
31
34
  "@types/jest": "^29.4.0",
@@ -34,27 +37,63 @@
34
37
  "@types/yargs": "^17.0.20",
35
38
  "@typescript-eslint/eslint-plugin": "^6.0.0",
36
39
  "@typescript-eslint/parser": "^6.0.0",
37
- "eslint": "^8.14.0",
40
+ "eslint": "^9.23.0",
38
41
  "jest": "^29.4.1",
39
42
  "prettier": "^3.5.3",
40
- "ts-jest": "^29.0.5",
41
- "typescript": "^5.3.3",
42
43
  "web3": "^1.8.2",
43
44
  "yargs": "^17.0.20"
44
45
  },
45
46
  "dependencies": {
46
47
  "@mysten/sui": "^1.3.0",
47
48
  "buffer": "^6.0.3",
48
- "@pythnetwork/hermes-client": "2.0.0"
49
+ "@pythnetwork/hermes-client": "3.1.0"
49
50
  },
51
+ "engines": {
52
+ "node": "^24.0.0"
53
+ },
54
+ "exports": {
55
+ "./SuiPriceServiceConnection": {
56
+ "require": {
57
+ "types": "./dist/cjs/SuiPriceServiceConnection.d.ts",
58
+ "default": "./dist/cjs/SuiPriceServiceConnection.cjs"
59
+ },
60
+ "import": {
61
+ "types": "./dist/esm/SuiPriceServiceConnection.d.ts",
62
+ "default": "./dist/esm/SuiPriceServiceConnection.mjs"
63
+ }
64
+ },
65
+ "./client": {
66
+ "require": {
67
+ "types": "./dist/cjs/client.d.ts",
68
+ "default": "./dist/cjs/client.cjs"
69
+ },
70
+ "import": {
71
+ "types": "./dist/esm/client.d.ts",
72
+ "default": "./dist/esm/client.mjs"
73
+ }
74
+ },
75
+ ".": {
76
+ "require": {
77
+ "types": "./dist/cjs/index.d.ts",
78
+ "default": "./dist/cjs/index.cjs"
79
+ },
80
+ "import": {
81
+ "types": "./dist/esm/index.d.ts",
82
+ "default": "./dist/esm/index.mjs"
83
+ }
84
+ },
85
+ "./package.json": "./package.json"
86
+ },
87
+ "module": "./dist/esm/index.mjs",
50
88
  "scripts": {
51
- "build": "tsc",
89
+ "build": "ts-duality",
52
90
  "example-relay": "node lib/examples/SuiRelay.js",
53
91
  "test:lint": "eslint src/ --max-warnings 0",
54
92
  "test:format": "prettier --check \"src/**/*.ts\"",
55
93
  "fix:lint": "eslint src/ --fix --max-warnings 0",
56
94
  "fix:format": "prettier --write \"src/**/*.ts\"",
57
95
  "preversion": "pnpm run test:lint",
58
- "version": "pnpm run format && git add -A src"
96
+ "version": "pnpm run format && git add -A src",
97
+ "clean": "rm -rf ./dist"
59
98
  }
60
99
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"SuiPriceServiceConnection.d.ts","sourceRoot":"","sources":["../src/SuiPriceServiceConnection.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,SAAS,EAEV,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,qBAAa,yBAA0B,SAAQ,YAAY;IACzD;;;;;;;OAOG;IACG,uBAAuB,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAUxE"}
@@ -1,24 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SuiPriceServiceConnection = void 0;
4
- const hermes_client_1 = require("@pythnetwork/hermes-client");
5
- const buffer_1 = require("buffer");
6
- class SuiPriceServiceConnection extends hermes_client_1.HermesClient {
7
- /**
8
- * Gets price update data (either batch price attestation VAAs or accumulator messages, depending on the chosen endpoint), which then
9
- * can be submitted to the Pyth contract to update the prices. This will throw an axios error if there is a network problem or
10
- * the price service returns a non-ok response (e.g: Invalid price ids)
11
- *
12
- * @param priceIds Array of hex-encoded price ids.
13
- * @returns Array of buffers containing the price update data.
14
- */
15
- async getPriceFeedsUpdateData(priceIds) {
16
- // Fetch the latest price feed update VAAs from the price service
17
- const updateData = await this.getLatestPriceUpdates(priceIds, {
18
- encoding: "base64",
19
- parsed: false,
20
- });
21
- return updateData.binary.data.map((update) => buffer_1.Buffer.from(update, "base64"));
22
- }
23
- }
24
- exports.SuiPriceServiceConnection = SuiPriceServiceConnection;
@@ -1 +0,0 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,KAAK,uBAAuB,GAAG;IAC7B,KAAK,EAAE,cAAc,CAAC;IACtB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC,CAAC;AACF,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAE9B,qBAAa,aAAa;IAOf,QAAQ,EAAE,SAAS;IACnB,WAAW,EAAE,QAAQ;IACrB,eAAe,EAAE,QAAQ;IARlC,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,cAAc,CAAoD;IAC1E,OAAO,CAAC,sBAAsB,CAAuC;IACrE,OAAO,CAAC,aAAa,CAAqB;gBAEjC,QAAQ,EAAE,SAAS,EACnB,WAAW,EAAE,QAAQ,EACrB,eAAe,EAAE,QAAQ;IAM5B,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;IAoBzC;;;;;OAKG;IACG,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IA0BzD;;;;OAIG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,WAAW;;;;IAwB1C,yBAAyB,CAC7B,EAAE,EAAE,WAAW,EACf,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,uBAAuB,CAAC;IA2B7B,uBAAuB,CAC3B,EAAE,EAAE,WAAW,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,SAAS,EAAE,EACpB,qBAAqB,EAAE,GAAG,EAC1B,KAAK,EAAE,uBAAuB,EAAE;IAgClC;;;;;OAKG;IACG,gBAAgB,CACpB,EAAE,EAAE,WAAW,EACf,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE,SAAS,EAAE,GACnB,OAAO,CAAC,QAAQ,EAAE,CAAC;IAuBtB;;;;;;OAMG;IACG,yBAAyB,CAC7B,EAAE,EAAE,WAAW,EACf,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE,SAAS,EAAE,EACpB,KAAK,EAAE,uBAAuB,EAAE,GAC/B,OAAO,CAAC,QAAQ,EAAE,CAAC;IAiBhB,eAAe,CAAC,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE;IA2BxD;;OAEG;IACG,oBAAoB;IAO1B;;OAEG;IACG,gBAAgB;IAOtB;;;OAGG;IACG,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IA6B5E;;;OAGG;IACG,iBAAiB,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,QAAQ,CAAC;QAAC,SAAS,EAAE,QAAQ,CAAA;KAAE,CAAC;IAwBzE;;;;OAIG;IACH,qCAAqC,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM;CAY1E"}
@@ -1,3 +0,0 @@
1
- import { SuiClient } from "@mysten/sui/client";
2
- export declare function getProvider(url: string): SuiClient;
3
- //# sourceMappingURL=SuiRelay.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SuiRelay.d.ts","sourceRoot":"","sources":["../../src/examples/SuiRelay.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAsC/C,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,aAEtC"}
@@ -1,98 +0,0 @@
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.getProvider = getProvider;
7
- const yargs_1 = __importDefault(require("yargs"));
8
- const helpers_1 = require("yargs/helpers");
9
- const client_1 = require("@mysten/sui/client");
10
- const transactions_1 = require("@mysten/sui/transactions");
11
- const ed25519_1 = require("@mysten/sui/keypairs/ed25519");
12
- const buffer_1 = require("buffer");
13
- const client_2 = require("../client");
14
- const index_1 = require("../index");
15
- const argvPromise = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
16
- .option("feed-id", {
17
- description: "Price feed ids to update without the leading 0x (e.g f9c0172ba10dfa4d19088d94f5bf61d3b54d5bd7483a322a982e1373ee8ea31b). Can be provided multiple times for multiple feed updates",
18
- string: true,
19
- type: "array",
20
- demandOption: true,
21
- })
22
- .option("hermes", {
23
- description: "Endpoint URL for Hermes. e.g: https://hermes.pyth.network",
24
- type: "string",
25
- demandOption: true,
26
- })
27
- .option("full-node", {
28
- description: "URL of the full Sui node RPC endpoint. e.g: https://fullnode.testnet.sui.io:443",
29
- type: "string",
30
- demandOption: true,
31
- })
32
- .option("pyth-state-id", {
33
- description: "Pyth state object id.",
34
- type: "string",
35
- demandOption: true,
36
- })
37
- .option("wormhole-state-id", {
38
- description: "Wormhole state object id.",
39
- type: "string",
40
- demandOption: true,
41
- }).argv;
42
- function getProvider(url) {
43
- return new client_1.SuiClient({ url });
44
- }
45
- async function run() {
46
- if (process.env.SUI_KEY === undefined) {
47
- throw new Error(`SUI_KEY environment variable should be set.`);
48
- }
49
- const argv = await argvPromise;
50
- // Fetch the latest price feed update data from the Price Service
51
- const connection = new index_1.SuiPriceServiceConnection(argv["hermes"]);
52
- const feeds = argv["feed-id"];
53
- if (!Array.isArray(feeds)) {
54
- throw new Error("Not a valid input!");
55
- }
56
- const provider = getProvider(argv["full-node"]);
57
- const wormholeStateId = argv["wormhole-state-id"];
58
- const pythStateId = argv["pyth-state-id"];
59
- const client = new client_2.SuiPythClient(provider, pythStateId, wormholeStateId);
60
- const newFeeds = [];
61
- const existingFeeds = [];
62
- for (const feed of feeds) {
63
- if (typeof feed !== "string") {
64
- throw new Error(`Not a valid string input ${feed}`);
65
- }
66
- if ((await client.getPriceFeedObjectId(feed)) == undefined) {
67
- newFeeds.push(feed);
68
- }
69
- else {
70
- existingFeeds.push(feed);
71
- }
72
- }
73
- console.log({
74
- newFeeds,
75
- existingFeeds,
76
- });
77
- const tx = new transactions_1.Transaction();
78
- if (existingFeeds.length > 0) {
79
- const updateData = await connection.getPriceFeedsUpdateData(existingFeeds);
80
- await client.updatePriceFeeds(tx, updateData, existingFeeds);
81
- }
82
- if (newFeeds.length > 0) {
83
- const updateData = await connection.getPriceFeedsUpdateData(newFeeds);
84
- await client.createPriceFeed(tx, updateData);
85
- }
86
- const wallet = ed25519_1.Ed25519Keypair.fromSecretKey(buffer_1.Buffer.from(process.env.SUI_KEY, "hex"));
87
- tx.setGasBudget(1000000);
88
- const result = await provider.signAndExecuteTransaction({
89
- signer: wallet,
90
- transaction: tx,
91
- options: {
92
- showEffects: true,
93
- showEvents: true,
94
- },
95
- });
96
- console.dir(result, { depth: null });
97
- }
98
- run();
package/lib/index.d.ts DELETED
@@ -1,4 +0,0 @@
1
- export { SuiPriceServiceConnection } from "./SuiPriceServiceConnection";
2
- export { SuiPythClient } from "./client";
3
- export { AssetType, BinaryPriceUpdate, DurationInMs, DurationInSeconds, EncodingType, HermesClientConfig, HexString, PriceFeedMetadata, PriceIdInput, PriceUpdate, PublisherCaps, TwapsResponse, UnixTimestamp, } from "@pythnetwork/hermes-client";
4
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,EAClB,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,aAAa,EACb,aAAa,EACb,aAAa,GACd,MAAM,4BAA4B,CAAC"}
package/lib/index.js DELETED
@@ -1,7 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SuiPythClient = exports.SuiPriceServiceConnection = void 0;
4
- var SuiPriceServiceConnection_1 = require("./SuiPriceServiceConnection");
5
- Object.defineProperty(exports, "SuiPriceServiceConnection", { enumerable: true, get: function () { return SuiPriceServiceConnection_1.SuiPriceServiceConnection; } });
6
- var client_1 = require("./client");
7
- Object.defineProperty(exports, "SuiPythClient", { enumerable: true, get: function () { return client_1.SuiPythClient; } });