Skip to content

Commit

Permalink
feat: support closing vaas (#1460)
Browse files Browse the repository at this point in the history
* feat: support closing vaas

* Go

* Max out

* Cleanup

* Refactor, add comments

* Add max

* Remove script

* bump solana utils

* Revert "Fix: guardian set (#1459)"

This reverts commit d9c85d8.

* Update compute budget

* Go

* Restore

* Bump
  • Loading branch information
guibescos authored Apr 17, 2024
1 parent c12a58e commit 8d92ad9
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 157 deletions.
20 changes: 11 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion price_pusher/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pythnetwork/price-pusher",
"version": "6.5.0",
"version": "6.6.0",
"description": "Pyth Price Pusher",
"homepage": "https://pyth.network",
"main": "lib/index.js",
Expand Down
1 change: 1 addition & 0 deletions price_pusher/src/solana/solana.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export class SolanaPricePusherJito implements IPricePusher {
priceFeedUpdateData,
this.shardId
);
await transactionBuilder.addClosePreviousEncodedVaasInstructions();

const transactions = await transactionBuilder.buildVersionedTransactions({
jitoTipLamports: this.jitoTipLamports,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pythnetwork/pyth-solana-receiver",
"version": "0.6.0",
"version": "0.7.0",
"description": "Pyth solana receiver SDK",
"homepage": "https://pyth.network",
"main": "lib/index.js",
Expand Down Expand Up @@ -43,6 +43,7 @@
},
"dependencies": {
"@coral-xyz/anchor": "^0.29.0",
"@noble/hashes": "^1.4.0",
"@pythnetwork/price-service-sdk": ">=1.6.0",
"@pythnetwork/solana-utils": "*",
"@solana/web3.js": "^1.90.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
parsePriceFeedMessage,
} from "@pythnetwork/price-service-sdk";
import {
CLOSE_ENCODED_VAA_COMPUTE_BUDGET,
INIT_ENCODED_VAA_COMPUTE_BUDGET,
POST_UPDATE_ATOMIC_COMPUTE_BUDGET,
POST_UPDATE_COMPUTE_BUDGET,
Expand All @@ -38,8 +39,8 @@ import { Wallet } from "@coral-xyz/anchor";
import {
buildEncodedVaaCreateInstruction,
buildWriteEncodedVaaWithSplitInstructions,
findEncodedVaaAccountsByWriteAuthority,
getGuardianSetIndex,
overrideGuardianSet,
trimSignatures,
} from "./vaa";
import {
Expand Down Expand Up @@ -263,6 +264,18 @@ export class PythTransactionBuilder extends TransactionBuilder {
);
}

/** Add instructions to close encoded VAA accounts from previous actions.
* If you have previously used the PythTransactionBuilder with closeUpdateAccounts set to false or if you posted encoded VAAs but the transaction to close them did not land on-chain, your wallet might own many encoded VAA accounts.
* The rent cost for these accounts is 0.008 SOL per encoded VAA account. You can recover this rent calling this function when building a set of transactions.
*/
async addClosePreviousEncodedVaasInstructions(maxInstructions = 40) {
this.addInstructions(
await this.pythSolanaReceiver.buildClosePreviousEncodedVaasInstructions(
maxInstructions
)
);
}

/**
* Returns all the added instructions batched into versioned transactions, plus for each transaction the ephemeral signers that need to sign it
*/
Expand Down Expand Up @@ -447,7 +460,6 @@ export class PythSolanaReceiver {
encodedVaaAddress: PublicKey;
closeInstructions: InstructionWithEphemeralSigners[];
}> {
vaa = overrideGuardianSet(vaa); // Short term fix Wormhole officially server guardian set 4 vaas
const postInstructions: InstructionWithEphemeralSigners[] = [];
const closeInstructions: InstructionWithEphemeralSigners[] = [];
const encodedVaaKeypair = new Keypair();
Expand Down Expand Up @@ -664,7 +676,25 @@ export class PythSolanaReceiver {
.closeEncodedVaa()
.accounts({ encodedVaa })
.instruction();
return { instruction, signers: [] };
return {
instruction,
signers: [],
computeUnits: CLOSE_ENCODED_VAA_COMPUTE_BUDGET,
};
}

/**
* Build aset of instructions to close all the existing encoded VAA accounts owned by this PythSolanaReceiver's wallet
*/
async buildClosePreviousEncodedVaasInstructions(
maxInstructions: number
): Promise<InstructionWithEphemeralSigners[]> {
const encodedVaas = await this.findOwnedEncodedVaaAccounts();
const instructions = [];
for (const encodedVaa of encodedVaas) {
instructions.push(await this.buildCloseEncodedVaaInstruction(encodedVaa));
}
return instructions.slice(0, maxInstructions);
}

/**
Expand Down Expand Up @@ -739,6 +769,18 @@ export class PythSolanaReceiver {
this.pushOracle.programId
);
}

/**
* Find all the encoded VAA accounts owned by this PythSolanaReceiver's wallet
* @returns a list of the public keys of the encoded VAA accounts
*/
async findOwnedEncodedVaaAccounts() {
return await findEncodedVaaAccountsByWriteAuthority(
this.receiver.provider.connection,
this.wallet.publicKey,
this.wormhole.programId
);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ export const INIT_ENCODED_VAA_COMPUTE_BUDGET = 3000;
* A hard-coded budget for the compute units required for the `writeEncodedVaa` instruction in the Wormhole program.
*/
export const WRITE_ENCODED_VAA_COMPUTE_BUDGET = 3000;
/**
* A hard-coded budget for the compute units required for the `closeEncodedVaa` instruction in the Wormhole program.
*/
export const CLOSE_ENCODED_VAA_COMPUTE_BUDGET = 30000;
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ export {
TransactionBuilder,
InstructionWithEphemeralSigners,
} from "@pythnetwork/solana-utils";

export {
getConfigPda,
DEFAULT_RECEIVER_PROGRAM_ID,
Expand Down
49 changes: 34 additions & 15 deletions target_chains/solana/sdk/js/pyth_solana_receiver/src/vaa.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Keypair, PublicKey } from "@solana/web3.js";
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import { WormholeCoreBridgeSolana } from "./idl/wormhole_core_bridge_solana";
import { Program } from "@coral-xyz/anchor";
import { InstructionWithEphemeralSigners } from "@pythnetwork/solana-utils";
import { WRITE_ENCODED_VAA_COMPUTE_BUDGET } from "./compute_budget";

import { sha256 } from "@noble/hashes/sha256";
import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes";
/**
* Get the index of the guardian set that signed a VAA
*/
Expand Down Expand Up @@ -52,18 +53,6 @@ export function trimSignatures(
return trimmedVaa;
}

export const PREVIOUS_GUARDIAN_SET_INDEX = 4;
export const CURRENT_GUARDIAN_SET_INDEX = 4;
export function overrideGuardianSet(vaa: Buffer): Buffer {
const guardianSetIndex = getGuardianSetIndex(vaa);

if (guardianSetIndex <= 3) {
vaa.writeUint32BE(CURRENT_GUARDIAN_SET_INDEX, 1);
}

return vaa;
}

/**
* The start of the VAA bytes in an encoded VAA account. Before this offset, the account contains a header.
*/
Expand Down Expand Up @@ -97,7 +86,7 @@ export async function buildEncodedVaaCreateInstruction(
* This number was chosen as the biggest number such that one can still call `createInstruction`, `initEncodedVaa` and `writeEncodedVaa` in a single Solana transaction.
* This way, the packing of the instructions to post an encoded vaa is more efficient.
*/
export const VAA_SPLIT_INDEX = 792;
export const VAA_SPLIT_INDEX = 755;

/**
* Build a set of instructions to write a VAA to an encoded VAA account
Expand Down Expand Up @@ -141,3 +130,33 @@ export async function buildWriteEncodedVaaWithSplitInstructions(
},
];
}

/**
* Find all the encoded VAA accounts that have a given write authority
* @returns a list of the public keys of the encoded VAA accounts
*/
export async function findEncodedVaaAccountsByWriteAuthority(
connection: Connection,
writeAuthority: PublicKey,
wormholeProgramId: PublicKey
): Promise<PublicKey[]> {
const result = await connection.getProgramAccounts(wormholeProgramId, {
filters: [
{
memcmp: {
offset: 0,
bytes: bs58.encode(
Buffer.from(sha256("account:EncodedVaa").slice(0, 8))
),
},
},
{
memcmp: {
offset: 8 + 1,
bytes: bs58.encode(writeAuthority.toBuffer()),
},
},
],
});
return result.map((account) => new PublicKey(account.pubkey));
}

This file was deleted.

2 changes: 1 addition & 1 deletion target_chains/solana/sdk/js/solana_utils/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pythnetwork/solana-utils",
"version": "0.3.0",
"version": "0.4.0",
"description": "Utility functions for Solana",
"homepage": "https://pyth.network",
"main": "lib/index.js",
Expand Down
Loading

0 comments on commit 8d92ad9

Please sign in to comment.