wormhole/sdk/js/src/solana/sendAndConfirmPostVaa.ts

172 lines
4.4 KiB
TypeScript

import {
Commitment,
ConfirmOptions,
Connection,
Keypair,
PublicKeyInitData,
Transaction,
} from "@solana/web3.js";
import {
signSendAndConfirmTransaction,
SignTransaction,
sendAndConfirmTransactionsWithRetry,
modifySignTransaction,
TransactionSignatureAndResponse,
PreparedTransactions,
} from "./utils";
import {
createPostVaaInstruction,
createVerifySignaturesInstructions,
} from "./wormhole";
import { isBytes, ParsedVaa, parseVaa, SignedVaa } from "../vaa/wormhole";
export async function postVaaWithRetry(
connection: Connection,
signTransaction: SignTransaction,
wormholeProgramId: PublicKeyInitData,
payer: PublicKeyInitData,
vaa: Buffer,
maxRetries?: number,
commitment?: Commitment
): Promise<TransactionSignatureAndResponse[]> {
const { unsignedTransactions, signers } =
await createPostSignedVaaTransactions(
connection,
wormholeProgramId,
payer,
vaa,
commitment
);
const postVaaTransaction = unsignedTransactions.pop()!;
const responses = await sendAndConfirmTransactionsWithRetry(
connection,
modifySignTransaction(signTransaction, ...signers),
payer.toString(),
unsignedTransactions,
maxRetries
);
//While the signature_set is used to create the final instruction, it doesn't need to sign it.
responses.push(
...(await sendAndConfirmTransactionsWithRetry(
connection,
signTransaction,
payer.toString(),
[postVaaTransaction],
maxRetries
))
);
return responses;
}
export async function postVaa(
connection: Connection,
signTransaction: SignTransaction,
wormholeProgramId: PublicKeyInitData,
payer: PublicKeyInitData,
vaa: Buffer,
options?: ConfirmOptions,
asyncVerifySignatures: boolean = true
): Promise<TransactionSignatureAndResponse[]> {
const { unsignedTransactions, signers } =
await createPostSignedVaaTransactions(
connection,
wormholeProgramId,
payer,
vaa,
options?.commitment
);
const postVaaTransaction = unsignedTransactions.pop()!;
const verifySignatures = async (transaction: Transaction) =>
signSendAndConfirmTransaction(
connection,
payer,
modifySignTransaction(signTransaction, ...signers),
transaction,
options
);
const output: TransactionSignatureAndResponse[] = [];
if (asyncVerifySignatures) {
const verified = await Promise.all(
unsignedTransactions.map(async (transaction) =>
verifySignatures(transaction)
)
);
output.push(...verified);
} else {
for (const transaction of unsignedTransactions) {
output.push(await verifySignatures(transaction));
}
}
output.push(
await signSendAndConfirmTransaction(
connection,
payer,
signTransaction,
postVaaTransaction,
options
)
);
return output;
}
/** Send transactions for `verify_signatures` and `post_vaa` instructions.
*
* Using a signed VAA, execute transactions generated by {@link verifySignatures} and
* {@link postVaa}. At most 4 transactions are sent (up to 3 from signature verification
* and 1 to post VAA data to an account).
*
* @param {Connection} connection - Solana web3 connection
* @param {PublicKeyInitData} wormholeProgramId - wormhole program address
* @param {web3.Keypair} payer - transaction signer address
* @param {Buffer} signedVaa - bytes of signed VAA
* @param {Commitment} [options] - Solana commitment
*
*/
export async function createPostSignedVaaTransactions(
connection: Connection,
wormholeProgramId: PublicKeyInitData,
payer: PublicKeyInitData,
vaa: SignedVaa | ParsedVaa,
commitment?: Commitment
): Promise<PreparedTransactions> {
const parsed = isBytes(vaa) ? parseVaa(vaa) : vaa;
const signatureSet = Keypair.generate();
const verifySignaturesInstructions = await createVerifySignaturesInstructions(
connection,
wormholeProgramId,
payer,
parsed,
signatureSet.publicKey,
commitment
);
const unsignedTransactions: Transaction[] = [];
for (let i = 0; i < verifySignaturesInstructions.length; i += 2) {
unsignedTransactions.push(
new Transaction().add(...verifySignaturesInstructions.slice(i, i + 2))
);
}
unsignedTransactions.push(
new Transaction().add(
createPostVaaInstruction(
wormholeProgramId,
payer,
parsed,
signatureSet.publicKey
)
)
);
return {
unsignedTransactions,
signers: [signatureSet],
};
}