Bläddra i källkod

feat: Support Sui Price Update with Coin Input (#2861)

* add update price feeds function for sui which takes coin input

* lint

* fix prettier issues

* prettier on fuel

* fix eslint

* use explicit types
Darun Seethammagari 4 månader sedan
förälder
incheckning
29b964468e

+ 5 - 4
target_chains/sui/sdk/js/README.md

@@ -22,7 +22,7 @@ Pyth prices and submit them to the network:
 
 ```typescript
 const connection = new SuiPriceServiceConnection(
-  "https://hermes-beta.pyth.network"
+  "https://hermes-beta.pyth.network",
 ); // See Hermes endpoints section below for other endpoints
 
 const priceIds = [
@@ -104,8 +104,9 @@ You can run this example with `pnpm turbo --filter @pythnetwork/pyth-sui-js run
 
 ```bash
 export SUI_KEY=YOUR_PRIV_KEY;
-pnpm turbo --filter @pythnetwork/pyth-sui-js run example-relay -- --feed-id "5a035d5440f5c163069af66062bac6c79377bf88396fa27e6067bfca8096d280" \
---price-service "https://hermes-beta.pyth.network" \
+pnpm turbo run example-relay --filter @pythnetwork/pyth-sui-js -- \
+--feed-id "5a035d5440f5c163069af66062bac6c79377bf88396fa27e6067bfca8096d280" \
+--hermes "https://hermes-beta.pyth.network" \
 --full-node "https://fullnode.testnet.sui.io:443" \
 --pyth-state-id "0xd3e79c2c083b934e78b3bd58a490ec6b092561954da6e7322e1e2b3c8abfddc0" \
 --wormhole-state-id "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790"
@@ -136,7 +137,7 @@ This method is useful if you want to show continuously updating real-time prices
 // gets a price update.
 connection.subscribePriceFeedUpdates(priceIds, (priceFeed) => {
   console.log(
-    `Received update for ${priceFeed.id}: ${priceFeed.getPriceNoOlderThan(60)}`
+    `Received update for ${priceFeed.id}: ${priceFeed.getPriceNoOlderThan(60)}`,
   );
 });
 

+ 1 - 1
target_chains/sui/sdk/js/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@pythnetwork/pyth-sui-js",
-  "version": "2.1.0",
+  "version": "2.2.0",
   "description": "Pyth Network Sui Utilities",
   "homepage": "https://pyth.network",
   "author": {

+ 80 - 18
target_chains/sui/sdk/js/src/client.ts

@@ -6,6 +6,10 @@ import { HexString } from "@pythnetwork/price-service-client";
 import { Buffer } from "buffer";
 
 const MAX_ARGUMENT_SIZE = 16 * 1024;
+type NestedTransactionResult = {
+  $kind: "NestedResult";
+  NestedResult: [number, number];
+};
 export type ObjectId = string;
 
 export class SuiPythClient {
@@ -104,20 +108,11 @@ export class SuiPythClient {
     return verifiedVaas;
   }
 
-  /**
-   * Adds the necessary commands for updating the pyth price feeds to the transaction block.
-   * @param tx transaction block to add commands to
-   * @param updates array of price feed updates received from the price service
-   * @param feedIds array of feed ids to update (in hex format)
-   */
-  async updatePriceFeeds(
+  async verifyVaasAndGetHotPotato(
     tx: Transaction,
     updates: Buffer[],
-    feedIds: HexString[],
-  ): Promise<ObjectId[]> {
-    const packageId = await this.getPythPackageId();
-
-    let priceUpdatesHotPotato;
+    packageId: string,
+  ): Promise<NestedTransactionResult> {
     if (updates.length > 1) {
       throw new Error(
         "SDK does not support sending multiple accumulator messages in a single transaction",
@@ -125,7 +120,7 @@ export class SuiPythClient {
     }
     const vaa = this.extractVaaBytesFromAccumulatorMessage(updates[0]);
     const verifiedVaas = await this.verifyVaas([vaa], tx);
-    [priceUpdatesHotPotato] = tx.moveCall({
+    const [priceUpdatesHotPotato] = tx.moveCall({
       target: `${packageId}::pyth::create_authenticated_price_infos_using_accumulator`,
       arguments: [
         tx.object(this.pythStateId),
@@ -141,13 +136,17 @@ export class SuiPythClient {
         tx.object(SUI_CLOCK_OBJECT_ID),
       ],
     });
+    return priceUpdatesHotPotato;
+  }
 
+  async executePriceFeedUpdates(
+    tx: Transaction,
+    packageId: string,
+    feedIds: HexString[],
+    priceUpdatesHotPotato: any,
+    coins: NestedTransactionResult[],
+  ) {
     const priceInfoObjects: ObjectId[] = [];
-    const baseUpdateFee = await this.getBaseUpdateFee();
-    const coins = tx.splitCoins(
-      tx.gas,
-      feedIds.map(() => tx.pure.u64(baseUpdateFee)),
-    );
     let coinId = 0;
     for (const feedId of feedIds) {
       const priceInfoObjectId = await this.getPriceFeedObjectId(feedId);
@@ -176,6 +175,69 @@ export class SuiPythClient {
     });
     return priceInfoObjects;
   }
+
+  /**
+   * Adds the necessary commands for updating the pyth price feeds to the transaction block.
+   * @param tx transaction block to add commands to
+   * @param updates array of price feed updates received from the price service
+   * @param feedIds array of feed ids to update (in hex format)
+   */
+  async updatePriceFeeds(
+    tx: Transaction,
+    updates: Buffer[],
+    feedIds: HexString[],
+  ): Promise<ObjectId[]> {
+    const packageId = await this.getPythPackageId();
+    const priceUpdatesHotPotato = await this.verifyVaasAndGetHotPotato(
+      tx,
+      updates,
+      packageId,
+    );
+
+    const baseUpdateFee = await this.getBaseUpdateFee();
+    const coins = tx.splitCoins(
+      tx.gas,
+      feedIds.map(() => tx.pure.u64(baseUpdateFee)),
+    );
+
+    return await this.executePriceFeedUpdates(
+      tx,
+      packageId,
+      feedIds,
+      priceUpdatesHotPotato,
+      coins,
+    );
+  }
+
+  /**
+   * Updates price feeds using the coin input for payment. Coins can be generated by calling splitCoin on tx.gas.
+   * @param tx transaction block to add commands to
+   * @param updates array of price feed updates received from the price service
+   * @param feedIds array of feed ids to update (in hex format)
+   * @param coins array of Coins for payment of update operations
+   */
+  async updatePriceFeedsWithCoins(
+    tx: Transaction,
+    updates: Buffer[],
+    feedIds: HexString[],
+    coins: NestedTransactionResult[],
+  ): Promise<ObjectId[]> {
+    const packageId = await this.getPythPackageId();
+    const priceUpdatesHotPotato = await this.verifyVaasAndGetHotPotato(
+      tx,
+      updates,
+      packageId,
+    );
+
+    return await this.executePriceFeedUpdates(
+      tx,
+      packageId,
+      feedIds,
+      priceUpdatesHotPotato,
+      coins,
+    );
+  }
+
   async createPriceFeed(tx: Transaction, updates: Buffer[]) {
     const packageId = await this.getPythPackageId();
     if (updates.length > 1) {