Skip to content

Commit 8d92ad9

Browse files
authored
feat: support closing vaas (#1460)
* 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
1 parent c12a58e commit 8d92ad9

File tree

12 files changed

+145
-157
lines changed

12 files changed

+145
-157
lines changed

package-lock.json

Lines changed: 11 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

price_pusher/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pythnetwork/price-pusher",
3-
"version": "6.5.0",
3+
"version": "6.6.0",
44
"description": "Pyth Price Pusher",
55
"homepage": "https://pyth.network",
66
"main": "lib/index.js",

price_pusher/src/solana/solana.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ export class SolanaPricePusherJito implements IPricePusher {
146146
priceFeedUpdateData,
147147
this.shardId
148148
);
149+
await transactionBuilder.addClosePreviousEncodedVaasInstructions();
149150

150151
const transactions = await transactionBuilder.buildVersionedTransactions({
151152
jitoTipLamports: this.jitoTipLamports,

target_chains/solana/sdk/js/pyth_solana_receiver/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pythnetwork/pyth-solana-receiver",
3-
"version": "0.6.0",
3+
"version": "0.7.0",
44
"description": "Pyth solana receiver SDK",
55
"homepage": "https://pyth.network",
66
"main": "lib/index.js",
@@ -43,6 +43,7 @@
4343
},
4444
"dependencies": {
4545
"@coral-xyz/anchor": "^0.29.0",
46+
"@noble/hashes": "^1.4.0",
4647
"@pythnetwork/price-service-sdk": ">=1.6.0",
4748
"@pythnetwork/solana-utils": "*",
4849
"@solana/web3.js": "^1.90.0"

target_chains/solana/sdk/js/pyth_solana_receiver/src/PythSolanaReceiver.ts

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
parsePriceFeedMessage,
2929
} from "@pythnetwork/price-service-sdk";
3030
import {
31+
CLOSE_ENCODED_VAA_COMPUTE_BUDGET,
3132
INIT_ENCODED_VAA_COMPUTE_BUDGET,
3233
POST_UPDATE_ATOMIC_COMPUTE_BUDGET,
3334
POST_UPDATE_COMPUTE_BUDGET,
@@ -38,8 +39,8 @@ import { Wallet } from "@coral-xyz/anchor";
3839
import {
3940
buildEncodedVaaCreateInstruction,
4041
buildWriteEncodedVaaWithSplitInstructions,
42+
findEncodedVaaAccountsByWriteAuthority,
4143
getGuardianSetIndex,
42-
overrideGuardianSet,
4344
trimSignatures,
4445
} from "./vaa";
4546
import {
@@ -263,6 +264,18 @@ export class PythTransactionBuilder extends TransactionBuilder {
263264
);
264265
}
265266

267+
/** Add instructions to close encoded VAA accounts from previous actions.
268+
* 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.
269+
* 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.
270+
*/
271+
async addClosePreviousEncodedVaasInstructions(maxInstructions = 40) {
272+
this.addInstructions(
273+
await this.pythSolanaReceiver.buildClosePreviousEncodedVaasInstructions(
274+
maxInstructions
275+
)
276+
);
277+
}
278+
266279
/**
267280
* Returns all the added instructions batched into versioned transactions, plus for each transaction the ephemeral signers that need to sign it
268281
*/
@@ -447,7 +460,6 @@ export class PythSolanaReceiver {
447460
encodedVaaAddress: PublicKey;
448461
closeInstructions: InstructionWithEphemeralSigners[];
449462
}> {
450-
vaa = overrideGuardianSet(vaa); // Short term fix Wormhole officially server guardian set 4 vaas
451463
const postInstructions: InstructionWithEphemeralSigners[] = [];
452464
const closeInstructions: InstructionWithEphemeralSigners[] = [];
453465
const encodedVaaKeypair = new Keypair();
@@ -664,7 +676,25 @@ export class PythSolanaReceiver {
664676
.closeEncodedVaa()
665677
.accounts({ encodedVaa })
666678
.instruction();
667-
return { instruction, signers: [] };
679+
return {
680+
instruction,
681+
signers: [],
682+
computeUnits: CLOSE_ENCODED_VAA_COMPUTE_BUDGET,
683+
};
684+
}
685+
686+
/**
687+
* Build aset of instructions to close all the existing encoded VAA accounts owned by this PythSolanaReceiver's wallet
688+
*/
689+
async buildClosePreviousEncodedVaasInstructions(
690+
maxInstructions: number
691+
): Promise<InstructionWithEphemeralSigners[]> {
692+
const encodedVaas = await this.findOwnedEncodedVaaAccounts();
693+
const instructions = [];
694+
for (const encodedVaa of encodedVaas) {
695+
instructions.push(await this.buildCloseEncodedVaaInstruction(encodedVaa));
696+
}
697+
return instructions.slice(0, maxInstructions);
668698
}
669699

670700
/**
@@ -739,6 +769,18 @@ export class PythSolanaReceiver {
739769
this.pushOracle.programId
740770
);
741771
}
772+
773+
/**
774+
* Find all the encoded VAA accounts owned by this PythSolanaReceiver's wallet
775+
* @returns a list of the public keys of the encoded VAA accounts
776+
*/
777+
async findOwnedEncodedVaaAccounts() {
778+
return await findEncodedVaaAccountsByWriteAuthority(
779+
this.receiver.provider.connection,
780+
this.wallet.publicKey,
781+
this.wormhole.programId
782+
);
783+
}
742784
}
743785

744786
/**

target_chains/solana/sdk/js/pyth_solana_receiver/src/compute_budget.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,7 @@ export const INIT_ENCODED_VAA_COMPUTE_BUDGET = 3000;
2222
* A hard-coded budget for the compute units required for the `writeEncodedVaa` instruction in the Wormhole program.
2323
*/
2424
export const WRITE_ENCODED_VAA_COMPUTE_BUDGET = 3000;
25+
/**
26+
* A hard-coded budget for the compute units required for the `closeEncodedVaa` instruction in the Wormhole program.
27+
*/
28+
export const CLOSE_ENCODED_VAA_COMPUTE_BUDGET = 30000;

target_chains/solana/sdk/js/pyth_solana_receiver/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ export {
66
TransactionBuilder,
77
InstructionWithEphemeralSigners,
88
} from "@pythnetwork/solana-utils";
9-
109
export {
1110
getConfigPda,
1211
DEFAULT_RECEIVER_PROGRAM_ID,

target_chains/solana/sdk/js/pyth_solana_receiver/src/vaa.ts

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { Keypair, PublicKey } from "@solana/web3.js";
1+
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
22
import { WormholeCoreBridgeSolana } from "./idl/wormhole_core_bridge_solana";
33
import { Program } from "@coral-xyz/anchor";
44
import { InstructionWithEphemeralSigners } from "@pythnetwork/solana-utils";
55
import { WRITE_ENCODED_VAA_COMPUTE_BUDGET } from "./compute_budget";
6-
6+
import { sha256 } from "@noble/hashes/sha256";
7+
import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes";
78
/**
89
* Get the index of the guardian set that signed a VAA
910
*/
@@ -52,18 +53,6 @@ export function trimSignatures(
5253
return trimmedVaa;
5354
}
5455

55-
export const PREVIOUS_GUARDIAN_SET_INDEX = 4;
56-
export const CURRENT_GUARDIAN_SET_INDEX = 4;
57-
export function overrideGuardianSet(vaa: Buffer): Buffer {
58-
const guardianSetIndex = getGuardianSetIndex(vaa);
59-
60-
if (guardianSetIndex <= 3) {
61-
vaa.writeUint32BE(CURRENT_GUARDIAN_SET_INDEX, 1);
62-
}
63-
64-
return vaa;
65-
}
66-
6756
/**
6857
* The start of the VAA bytes in an encoded VAA account. Before this offset, the account contains a header.
6958
*/
@@ -97,7 +86,7 @@ export async function buildEncodedVaaCreateInstruction(
9786
* This number was chosen as the biggest number such that one can still call `createInstruction`, `initEncodedVaa` and `writeEncodedVaa` in a single Solana transaction.
9887
* This way, the packing of the instructions to post an encoded vaa is more efficient.
9988
*/
100-
export const VAA_SPLIT_INDEX = 792;
89+
export const VAA_SPLIT_INDEX = 755;
10190

10291
/**
10392
* Build a set of instructions to write a VAA to an encoded VAA account
@@ -141,3 +130,33 @@ export async function buildWriteEncodedVaaWithSplitInstructions(
141130
},
142131
];
143132
}
133+
134+
/**
135+
* Find all the encoded VAA accounts that have a given write authority
136+
* @returns a list of the public keys of the encoded VAA accounts
137+
*/
138+
export async function findEncodedVaaAccountsByWriteAuthority(
139+
connection: Connection,
140+
writeAuthority: PublicKey,
141+
wormholeProgramId: PublicKey
142+
): Promise<PublicKey[]> {
143+
const result = await connection.getProgramAccounts(wormholeProgramId, {
144+
filters: [
145+
{
146+
memcmp: {
147+
offset: 0,
148+
bytes: bs58.encode(
149+
Buffer.from(sha256("account:EncodedVaa").slice(0, 8))
150+
),
151+
},
152+
},
153+
{
154+
memcmp: {
155+
offset: 8 + 1,
156+
bytes: bs58.encode(writeAuthority.toBuffer()),
157+
},
158+
},
159+
],
160+
});
161+
return result.map((account) => new PublicKey(account.pubkey));
162+
}

target_chains/solana/sdk/js/solana_utils/benchmarks/jito_benchmark.ts

Lines changed: 0 additions & 86 deletions
This file was deleted.

target_chains/solana/sdk/js/solana_utils/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pythnetwork/solana-utils",
3-
"version": "0.3.0",
3+
"version": "0.4.0",
44
"description": "Utility functions for Solana",
55
"homepage": "https://pyth.network",
66
"main": "lib/index.js",

0 commit comments

Comments
 (0)