Skip to content

feat: Support Sui Price Update with Coin Input #2861

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions target_chains/sui/sdk/js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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)}`,
);
});

Expand Down
2 changes: 1 addition & 1 deletion target_chains/sui/sdk/js/package.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down
98 changes: 80 additions & 18 deletions target_chains/sui/sdk/js/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import { HexString } from "@pythnetwork/price-service-client";
import { Buffer } from "buffer";

const MAX_ARGUMENT_SIZE = 16 * 1024;
type Coin = {
$kind: "NestedResult";
NestedResult: [number, number];
};
export type ObjectId = string;

export class SuiPythClient {
Expand Down Expand Up @@ -104,28 +108,19 @@ 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<any> {
if (updates.length > 1) {
throw new Error(
"SDK does not support sending multiple accumulator messages in a single transaction",
);
}
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),
Expand All @@ -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: Coin[],
) {
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);
Expand Down Expand Up @@ -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: Coin[],
): 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) {
Expand Down
Loading