@pythnetwork/pyth-sui-js 2.1.0 → 2.2.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.
package/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2024 Pyth Data Association.
1
+ Copyright 2025 Pyth Data Association.
2
2
 
3
3
  Licensed under the Apache License, Version 2.0 (the "License");
4
4
  you may not use this file except in compliance with the License.
package/README.md CHANGED
@@ -4,16 +4,11 @@
4
4
 
5
5
  ## Installation
6
6
 
7
- ### npm
7
+ ### pnpm
8
8
 
9
9
  ```
10
- $ npm install --save @pythnetwork/pyth-sui-js
11
- ```
12
-
13
- ### Yarn
14
-
15
- ```
16
- $ yarn add @pythnetwork/pyth-sui-js
10
+ cd to crosschain root
11
+ $ pnpm install
17
12
  ```
18
13
 
19
14
  ## Quickstart
@@ -27,7 +22,7 @@ Pyth prices and submit them to the network:
27
22
 
28
23
  ```typescript
29
24
  const connection = new SuiPriceServiceConnection(
30
- "https://hermes-beta.pyth.network"
25
+ "https://hermes-beta.pyth.network",
31
26
  ); // See Hermes endpoints section below for other endpoints
32
27
 
33
28
  const priceIds = [
@@ -103,12 +98,15 @@ Now in your contract you can consume the price by calling `pyth::get_price` or o
103
98
  1. Fetches update data from Hermes for the given price feeds.
104
99
  2. Calls the Pyth Sui contract with the update data.
105
100
 
106
- You can run this example with `npm run example-relay`. A full command that updates prices on Sui testnet looks like:
101
+ In order to run the commands, a SUI private key is needed. The commands expects the key to be in the form of hex. You can use `sui keytool convert` to get the hex version of the key, to be used below, if your private key is in the form "suiprivkey...".
102
+
103
+ You can run this example with `pnpm turbo --filter @pythnetwork/pyth-sui-js run example-relay` from the root of crosschain. Turbo will automatically build any detected dependencies including local ones, and filter is needed to tell it which sub-package to use (Such as this one). A full command that updates prices on Sui testnet looks like:
107
104
 
108
105
  ```bash
109
106
  export SUI_KEY=YOUR_PRIV_KEY;
110
- npm run example-relay -- --feed-id "5a035d5440f5c163069af66062bac6c79377bf88396fa27e6067bfca8096d280" \
111
- --price-service "https://hermes-beta.pyth.network" \
107
+ pnpm turbo run example-relay --filter @pythnetwork/pyth-sui-js -- \
108
+ --feed-id "5a035d5440f5c163069af66062bac6c79377bf88396fa27e6067bfca8096d280" \
109
+ --hermes "https://hermes-beta.pyth.network" \
112
110
  --full-node "https://fullnode.testnet.sui.io:443" \
113
111
  --pyth-state-id "0xd3e79c2c083b934e78b3bd58a490ec6b092561954da6e7322e1e2b3c8abfddc0" \
114
112
  --wormhole-state-id "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790"
@@ -139,7 +137,7 @@ This method is useful if you want to show continuously updating real-time prices
139
137
  // gets a price update.
140
138
  connection.subscribePriceFeedUpdates(priceIds, (priceFeed) => {
141
139
  console.log(
142
- `Received update for ${priceFeed.id}: ${priceFeed.getPriceNoOlderThan(60)}`
140
+ `Received update for ${priceFeed.id}: ${priceFeed.getPriceNoOlderThan(60)}`,
143
141
  );
144
142
  });
145
143
 
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { PriceServiceConnection, HexString } from "@pythnetwork/price-service-client";
3
2
  import { Buffer } from "buffer";
4
3
  export declare class SuiPriceServiceConnection extends PriceServiceConnection {
@@ -1 +1 @@
1
- {"version":3,"file":"SuiPriceServiceConnection.d.ts","sourceRoot":"","sources":["../src/SuiPriceServiceConnection.ts"],"names":[],"mappings":";AAAA,OAAO,EACL,sBAAsB,EACtB,SAAS,EACV,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,qBAAa,yBAA0B,SAAQ,sBAAsB;IACnE;;;;;;;OAOG;IACG,uBAAuB,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAKxE"}
1
+ {"version":3,"file":"SuiPriceServiceConnection.d.ts","sourceRoot":"","sources":["../src/SuiPriceServiceConnection.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,SAAS,EACV,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,qBAAa,yBAA0B,SAAQ,sBAAsB;IACnE;;;;;;;OAOG;IACG,uBAAuB,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAKxE"}
package/lib/client.d.ts CHANGED
@@ -1,8 +1,11 @@
1
- /// <reference types="node" />
2
1
  import { SuiClient } from "@mysten/sui/client";
3
2
  import { Transaction } from "@mysten/sui/transactions";
4
3
  import { HexString } from "@pythnetwork/price-service-client";
5
4
  import { Buffer } from "buffer";
5
+ type NestedTransactionResult = {
6
+ $kind: "NestedResult";
7
+ NestedResult: [number, number];
8
+ };
6
9
  export type ObjectId = string;
7
10
  export declare class SuiPythClient {
8
11
  provider: SuiClient;
@@ -31,6 +34,8 @@ export declare class SuiPythClient {
31
34
  $kind: "NestedResult";
32
35
  NestedResult: [number, number];
33
36
  }[]>;
37
+ verifyVaasAndGetHotPotato(tx: Transaction, updates: Buffer[], packageId: string): Promise<NestedTransactionResult>;
38
+ executePriceFeedUpdates(tx: Transaction, packageId: string, feedIds: HexString[], priceUpdatesHotPotato: any, coins: NestedTransactionResult[]): Promise<string[]>;
34
39
  /**
35
40
  * Adds the necessary commands for updating the pyth price feeds to the transaction block.
36
41
  * @param tx transaction block to add commands to
@@ -38,6 +43,14 @@ export declare class SuiPythClient {
38
43
  * @param feedIds array of feed ids to update (in hex format)
39
44
  */
40
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[]>;
41
54
  createPriceFeed(tx: Transaction, updates: Buffer[]): Promise<void>;
42
55
  /**
43
56
  * Get the packageId for the wormhole package if not already cached
@@ -67,4 +80,5 @@ export declare class SuiPythClient {
67
80
  */
68
81
  extractVaaBytesFromAccumulatorMessage(accumulatorMessage: Buffer): Buffer;
69
82
  }
83
+ export {};
70
84
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
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,mCAAmC,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,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;;;;IAwBhD;;;;;OAKG;IACG,gBAAgB,CACpB,EAAE,EAAE,WAAW,EACf,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE,SAAS,EAAE,GACnB,OAAO,CAAC,QAAQ,EAAE,CAAC;IA8DhB,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
+ {"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,mCAAmC,CAAC;AAC9D,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"}
package/lib/client.js CHANGED
@@ -91,21 +91,13 @@ class SuiPythClient {
91
91
  }
92
92
  return verifiedVaas;
93
93
  }
94
- /**
95
- * Adds the necessary commands for updating the pyth price feeds to the transaction block.
96
- * @param tx transaction block to add commands to
97
- * @param updates array of price feed updates received from the price service
98
- * @param feedIds array of feed ids to update (in hex format)
99
- */
100
- async updatePriceFeeds(tx, updates, feedIds) {
101
- const packageId = await this.getPythPackageId();
102
- let priceUpdatesHotPotato;
94
+ async verifyVaasAndGetHotPotato(tx, updates, packageId) {
103
95
  if (updates.length > 1) {
104
96
  throw new Error("SDK does not support sending multiple accumulator messages in a single transaction");
105
97
  }
106
98
  const vaa = this.extractVaaBytesFromAccumulatorMessage(updates[0]);
107
99
  const verifiedVaas = await this.verifyVaas([vaa], tx);
108
- [priceUpdatesHotPotato] = tx.moveCall({
100
+ const [priceUpdatesHotPotato] = tx.moveCall({
109
101
  target: `${packageId}::pyth::create_authenticated_price_infos_using_accumulator`,
110
102
  arguments: [
111
103
  tx.object(this.pythStateId),
@@ -119,9 +111,10 @@ class SuiPythClient {
119
111
  tx.object(utils_1.SUI_CLOCK_OBJECT_ID),
120
112
  ],
121
113
  });
114
+ return priceUpdatesHotPotato;
115
+ }
116
+ async executePriceFeedUpdates(tx, packageId, feedIds, priceUpdatesHotPotato, coins) {
122
117
  const priceInfoObjects = [];
123
- const baseUpdateFee = await this.getBaseUpdateFee();
124
- const coins = tx.splitCoins(tx.gas, feedIds.map(() => tx.pure.u64(baseUpdateFee)));
125
118
  let coinId = 0;
126
119
  for (const feedId of feedIds) {
127
120
  const priceInfoObjectId = await this.getPriceFeedObjectId(feedId);
@@ -148,6 +141,31 @@ class SuiPythClient {
148
141
  });
149
142
  return priceInfoObjects;
150
143
  }
144
+ /**
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) {
151
+ const packageId = await this.getPythPackageId();
152
+ const priceUpdatesHotPotato = await this.verifyVaasAndGetHotPotato(tx, updates, packageId);
153
+ const baseUpdateFee = await this.getBaseUpdateFee();
154
+ const coins = tx.splitCoins(tx.gas, feedIds.map(() => tx.pure.u64(baseUpdateFee)));
155
+ return await this.executePriceFeedUpdates(tx, packageId, feedIds, priceUpdatesHotPotato, coins);
156
+ }
157
+ /**
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) {
165
+ const packageId = await this.getPythPackageId();
166
+ const priceUpdatesHotPotato = await this.verifyVaasAndGetHotPotato(tx, updates, packageId);
167
+ return await this.executePriceFeedUpdates(tx, packageId, feedIds, priceUpdatesHotPotato, coins);
168
+ }
151
169
  async createPriceFeed(tx, updates) {
152
170
  const packageId = await this.getPythPackageId();
153
171
  if (updates.length > 1) {
@@ -1 +1 @@
1
- {"version":3,"file":"SuiRelay.d.ts","sourceRoot":"","sources":["../../src/examples/SuiRelay.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAqC/C,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,aAEtC"}
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"}
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getProvider = void 0;
6
+ exports.getProvider = getProvider;
7
7
  const yargs_1 = __importDefault(require("yargs"));
8
8
  const helpers_1 = require("yargs/helpers");
9
9
  const client_1 = require("@mysten/sui/client");
@@ -15,6 +15,7 @@ const index_1 = require("../index");
15
15
  const argvPromise = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
16
16
  .option("feed-id", {
17
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,
18
19
  type: "array",
19
20
  demandOption: true,
20
21
  })
@@ -41,7 +42,6 @@ const argvPromise = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
41
42
  function getProvider(url) {
42
43
  return new client_1.SuiClient({ url });
43
44
  }
44
- exports.getProvider = getProvider;
45
45
  async function run() {
46
46
  if (process.env.SUI_KEY === undefined) {
47
47
  throw new Error(`SUI_KEY environment variable should be set.`);
@@ -50,6 +50,9 @@ async function run() {
50
50
  // Fetch the latest price feed update data from the Price Service
51
51
  const connection = new index_1.SuiPriceServiceConnection(argv["hermes"]);
52
52
  const feeds = argv["feed-id"];
53
+ if (!Array.isArray(feeds)) {
54
+ throw new Error("Not a valid input!");
55
+ }
53
56
  const provider = getProvider(argv["full-node"]);
54
57
  const wormholeStateId = argv["wormhole-state-id"];
55
58
  const pythStateId = argv["pyth-state-id"];
@@ -57,6 +60,9 @@ async function run() {
57
60
  const newFeeds = [];
58
61
  const existingFeeds = [];
59
62
  for (const feed of feeds) {
63
+ if (typeof feed !== "string") {
64
+ throw new Error(`Not a valid string input ${feed}`);
65
+ }
60
66
  if ((await client.getPriceFeedObjectId(feed)) == undefined) {
61
67
  newFeeds.push(feed);
62
68
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pythnetwork/pyth-sui-js",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Pyth Network Sui Utilities",
5
5
  "homepage": "https://pyth.network",
6
6
  "author": {
@@ -19,16 +19,6 @@
19
19
  "publishConfig": {
20
20
  "access": "public"
21
21
  },
22
- "scripts": {
23
- "test": "jest --passWithNoTests",
24
- "build": "tsc",
25
- "example-relay": "pnpm run build && node lib/examples/SuiRelay.js",
26
- "format": "prettier --write \"src/**/*.ts\"",
27
- "lint": "eslint src/",
28
- "prepublishOnly": "pnpm run build && pnpm test && pnpm run lint",
29
- "preversion": "pnpm run lint",
30
- "version": "pnpm run format && git add -A src"
31
- },
32
22
  "keywords": [
33
23
  "pyth",
34
24
  "oracle",
@@ -46,7 +36,7 @@
46
36
  "@typescript-eslint/parser": "^6.0.0",
47
37
  "eslint": "^8.14.0",
48
38
  "jest": "^29.4.1",
49
- "prettier": "^2.6.2",
39
+ "prettier": "^3.5.3",
50
40
  "ts-jest": "^29.0.5",
51
41
  "typescript": "^5.3.3",
52
42
  "web3": "^1.8.2",
@@ -54,8 +44,17 @@
54
44
  },
55
45
  "dependencies": {
56
46
  "@mysten/sui": "^1.3.0",
57
- "@pythnetwork/price-service-client": "1.9.0",
58
- "buffer": "^6.0.3"
47
+ "buffer": "^6.0.3",
48
+ "@pythnetwork/price-service-client": "1.9.0"
59
49
  },
60
- "gitHead": "9a31948be215682091abe580a68666909b976462"
61
- }
50
+ "scripts": {
51
+ "build": "tsc",
52
+ "example-relay": "node lib/examples/SuiRelay.js",
53
+ "test:lint": "eslint src/ --max-warnings 0",
54
+ "test:format": "prettier --check \"src/**/*.ts\"",
55
+ "fix:lint": "eslint src/ --fix --max-warnings 0",
56
+ "fix:format": "prettier --write \"src/**/*.ts\"",
57
+ "preversion": "pnpm run test:lint",
58
+ "version": "pnpm run format && git add -A src"
59
+ }
60
+ }