|
|
@@ -0,0 +1,365 @@
|
|
|
+import { ChainName } from "@certusone/wormhole-sdk";
|
|
|
+import { createWormholeProgramInterface } from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole";
|
|
|
+import { AnchorProvider, Wallet } from "@project-serum/anchor";
|
|
|
+import {
|
|
|
+ getPythClusterApiUrl,
|
|
|
+ PythCluster,
|
|
|
+} from "@pythnetwork/client/lib/cluster";
|
|
|
+import {
|
|
|
+ Connection,
|
|
|
+ Keypair,
|
|
|
+ PublicKey,
|
|
|
+ SystemProgram,
|
|
|
+ TransactionInstruction,
|
|
|
+} from "@solana/web3.js";
|
|
|
+import {
|
|
|
+ MultisigInstructionProgram,
|
|
|
+ MultisigParser,
|
|
|
+ WORMHOLE_ADDRESS,
|
|
|
+} from "..";
|
|
|
+import {
|
|
|
+ encodeExecutePostedVaa,
|
|
|
+ ExecutePostedVaaArgs,
|
|
|
+} from "../governance_payload/ExecutePostedVaa";
|
|
|
+import { WormholeMultisigInstruction } from "../multisig_transaction/WormholeMultisigInstruction";
|
|
|
+
|
|
|
+test("Wormhole multisig instruction parse: send message without governance payload", (done) => {
|
|
|
+ jest.setTimeout(60000);
|
|
|
+
|
|
|
+ const cluster: PythCluster = "devnet";
|
|
|
+ const wormholeProgram = createWormholeProgramInterface(
|
|
|
+ WORMHOLE_ADDRESS[cluster]!,
|
|
|
+ new AnchorProvider(
|
|
|
+ new Connection(getPythClusterApiUrl(cluster)),
|
|
|
+ new Wallet(new Keypair()),
|
|
|
+ AnchorProvider.defaultOptions()
|
|
|
+ )
|
|
|
+ );
|
|
|
+ const parser = new MultisigParser(cluster);
|
|
|
+
|
|
|
+ wormholeProgram.methods
|
|
|
+ .postMessage(1, Buffer.from([0]), 1)
|
|
|
+ .accounts({
|
|
|
+ bridge: PublicKey.unique(),
|
|
|
+ message: PublicKey.unique(),
|
|
|
+ emitter: PublicKey.unique(),
|
|
|
+ sequence: PublicKey.unique(),
|
|
|
+ feeCollector: PublicKey.unique(),
|
|
|
+ clock: PublicKey.unique(),
|
|
|
+ })
|
|
|
+ .instruction()
|
|
|
+ .then((instruction) => {
|
|
|
+ const parsedInstruction = parser.parseInstruction(instruction);
|
|
|
+ expect(
|
|
|
+ parsedInstruction instanceof WormholeMultisigInstruction
|
|
|
+ ).toBeTruthy();
|
|
|
+ if (parsedInstruction instanceof WormholeMultisigInstruction) {
|
|
|
+ expect(parsedInstruction.program).toBe(
|
|
|
+ MultisigInstructionProgram.WormholeBridge
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.name).toBe("postMessage");
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["bridge"].pubkey.equals(
|
|
|
+ instruction.keys[0].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["bridge"].isSigner).toBe(
|
|
|
+ instruction.keys[0].isSigner
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.accounts.named["bridge"].isWritable).toBe(
|
|
|
+ instruction.keys[0].isWritable
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["message"].pubkey.equals(
|
|
|
+ instruction.keys[1].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["message"].isSigner).toBe(
|
|
|
+ instruction.keys[1].isSigner
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.accounts.named["message"].isWritable).toBe(
|
|
|
+ instruction.keys[1].isWritable
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["emitter"].pubkey.equals(
|
|
|
+ instruction.keys[2].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["emitter"].isSigner).toBe(
|
|
|
+ instruction.keys[2].isSigner
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.accounts.named["emitter"].isWritable).toBe(
|
|
|
+ instruction.keys[2].isWritable
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["sequence"].pubkey.equals(
|
|
|
+ instruction.keys[3].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["sequence"].isSigner).toBe(
|
|
|
+ instruction.keys[3].isSigner
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.accounts.named["sequence"].isWritable).toBe(
|
|
|
+ instruction.keys[3].isWritable
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["payer"].pubkey.equals(
|
|
|
+ instruction.keys[4].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["payer"].isSigner).toBe(
|
|
|
+ instruction.keys[4].isSigner
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.accounts.named["payer"].isWritable).toBe(
|
|
|
+ instruction.keys[4].isWritable
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["feeCollector"].pubkey.equals(
|
|
|
+ instruction.keys[5].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["feeCollector"].isSigner).toBe(
|
|
|
+ instruction.keys[5].isSigner
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["feeCollector"].isWritable
|
|
|
+ ).toBe(instruction.keys[5].isWritable);
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["clock"].pubkey.equals(
|
|
|
+ instruction.keys[6].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["clock"].isSigner).toBe(
|
|
|
+ instruction.keys[6].isSigner
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.accounts.named["clock"].isWritable).toBe(
|
|
|
+ instruction.keys[6].isWritable
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["rent"].pubkey.equals(
|
|
|
+ instruction.keys[7].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["rent"].isSigner).toBe(
|
|
|
+ instruction.keys[7].isSigner
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.accounts.named["rent"].isWritable).toBe(
|
|
|
+ instruction.keys[7].isWritable
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["systemProgram"].pubkey.equals(
|
|
|
+ instruction.keys[8].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["systemProgram"].isSigner).toBe(
|
|
|
+ instruction.keys[8].isSigner
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["systemProgram"].isWritable
|
|
|
+ ).toBe(instruction.keys[8].isWritable);
|
|
|
+ expect(parsedInstruction.accounts.remaining.length).toBe(0);
|
|
|
+
|
|
|
+ expect(parsedInstruction.args.nonce).toBe(1);
|
|
|
+ expect(parsedInstruction.args.payload.equals(Buffer.from([0])));
|
|
|
+ expect(parsedInstruction.args.consistencyLevel).toBe(1);
|
|
|
+ expect(parsedInstruction.args.targetChain).toBeUndefined();
|
|
|
+ done();
|
|
|
+ } else {
|
|
|
+ done("Not instance of WormholeInstruction");
|
|
|
+ }
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
+test("Wormhole multisig instruction parse: send message with governance payload", (done) => {
|
|
|
+ jest.setTimeout(60000);
|
|
|
+
|
|
|
+ const cluster: PythCluster = "devnet";
|
|
|
+ const wormholeProgram = createWormholeProgramInterface(
|
|
|
+ WORMHOLE_ADDRESS[cluster]!,
|
|
|
+ new AnchorProvider(
|
|
|
+ new Connection(getPythClusterApiUrl(cluster)),
|
|
|
+ new Wallet(new Keypair()),
|
|
|
+ AnchorProvider.defaultOptions()
|
|
|
+ )
|
|
|
+ );
|
|
|
+ const parser = new MultisigParser(cluster);
|
|
|
+
|
|
|
+ const executePostedVaaArgs: ExecutePostedVaaArgs = {
|
|
|
+ targetChainId: "pythnet" as ChainName,
|
|
|
+ instructions: [
|
|
|
+ SystemProgram.transfer({
|
|
|
+ fromPubkey: PublicKey.unique(),
|
|
|
+ toPubkey: PublicKey.unique(),
|
|
|
+ lamports: 890880,
|
|
|
+ }),
|
|
|
+ ],
|
|
|
+ };
|
|
|
+
|
|
|
+ wormholeProgram.methods
|
|
|
+ .postMessage(0, encodeExecutePostedVaa(executePostedVaaArgs), 0)
|
|
|
+ .accounts({
|
|
|
+ bridge: PublicKey.unique(),
|
|
|
+ message: PublicKey.unique(),
|
|
|
+ emitter: PublicKey.unique(),
|
|
|
+ sequence: PublicKey.unique(),
|
|
|
+ feeCollector: PublicKey.unique(),
|
|
|
+ clock: PublicKey.unique(),
|
|
|
+ })
|
|
|
+ .instruction()
|
|
|
+ .then((instruction) => {
|
|
|
+ const parsedInstruction = parser.parseInstruction(instruction);
|
|
|
+ if (parsedInstruction instanceof WormholeMultisigInstruction) {
|
|
|
+ expect(
|
|
|
+ parsedInstruction instanceof WormholeMultisigInstruction
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.program).toBe(
|
|
|
+ MultisigInstructionProgram.WormholeBridge
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.name).toBe("postMessage");
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["bridge"].pubkey.equals(
|
|
|
+ instruction.keys[0].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["bridge"].isSigner).toBe(
|
|
|
+ instruction.keys[0].isSigner
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.accounts.named["bridge"].isWritable).toBe(
|
|
|
+ instruction.keys[0].isWritable
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["message"].pubkey.equals(
|
|
|
+ instruction.keys[1].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["message"].isSigner).toBe(
|
|
|
+ instruction.keys[1].isSigner
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.accounts.named["message"].isWritable).toBe(
|
|
|
+ instruction.keys[1].isWritable
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["emitter"].pubkey.equals(
|
|
|
+ instruction.keys[2].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["emitter"].isSigner).toBe(
|
|
|
+ instruction.keys[2].isSigner
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.accounts.named["emitter"].isWritable).toBe(
|
|
|
+ instruction.keys[2].isWritable
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["sequence"].pubkey.equals(
|
|
|
+ instruction.keys[3].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["sequence"].isSigner).toBe(
|
|
|
+ instruction.keys[3].isSigner
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.accounts.named["sequence"].isWritable).toBe(
|
|
|
+ instruction.keys[3].isWritable
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["payer"].pubkey.equals(
|
|
|
+ instruction.keys[4].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["payer"].isSigner).toBe(
|
|
|
+ instruction.keys[4].isSigner
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.accounts.named["payer"].isWritable).toBe(
|
|
|
+ instruction.keys[4].isWritable
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["feeCollector"].pubkey.equals(
|
|
|
+ instruction.keys[5].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["feeCollector"].isSigner).toBe(
|
|
|
+ instruction.keys[5].isSigner
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["feeCollector"].isWritable
|
|
|
+ ).toBe(instruction.keys[5].isWritable);
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["clock"].pubkey.equals(
|
|
|
+ instruction.keys[6].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["clock"].isSigner).toBe(
|
|
|
+ instruction.keys[6].isSigner
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.accounts.named["clock"].isWritable).toBe(
|
|
|
+ instruction.keys[6].isWritable
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["rent"].pubkey.equals(
|
|
|
+ instruction.keys[7].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["rent"].isSigner).toBe(
|
|
|
+ instruction.keys[7].isSigner
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.accounts.named["rent"].isWritable).toBe(
|
|
|
+ instruction.keys[7].isWritable
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["systemProgram"].pubkey.equals(
|
|
|
+ instruction.keys[8].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(parsedInstruction.accounts.named["systemProgram"].isSigner).toBe(
|
|
|
+ instruction.keys[8].isSigner
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ parsedInstruction.accounts.named["systemProgram"].isWritable
|
|
|
+ ).toBe(instruction.keys[8].isWritable);
|
|
|
+ expect(parsedInstruction.accounts.remaining.length).toBe(0);
|
|
|
+
|
|
|
+ expect(parsedInstruction.args.nonce).toBe(0);
|
|
|
+ expect(
|
|
|
+ parsedInstruction.args.payload.equals(
|
|
|
+ encodeExecutePostedVaa(executePostedVaaArgs)
|
|
|
+ )
|
|
|
+ );
|
|
|
+ expect(parsedInstruction.args.consistencyLevel).toBe(0);
|
|
|
+
|
|
|
+ expect(parsedInstruction.args.governanceName).toBe("ExecutePostedVaa");
|
|
|
+
|
|
|
+ expect(parsedInstruction.args.governanceArgs.targetChainId).toBe(
|
|
|
+ "pythnet"
|
|
|
+ );
|
|
|
+
|
|
|
+ (
|
|
|
+ parsedInstruction.args.governanceArgs
|
|
|
+ .instructions as TransactionInstruction[]
|
|
|
+ ).forEach((instruction, i) => {
|
|
|
+ expect(
|
|
|
+ instruction.programId.equals(
|
|
|
+ executePostedVaaArgs.instructions[i].programId
|
|
|
+ )
|
|
|
+ );
|
|
|
+ expect(
|
|
|
+ instruction.data.equals(executePostedVaaArgs.instructions[i].data)
|
|
|
+ );
|
|
|
+ instruction.keys.forEach((account, j) => {
|
|
|
+ expect(
|
|
|
+ account.pubkey.equals(
|
|
|
+ executePostedVaaArgs.instructions[i].keys[j].pubkey
|
|
|
+ )
|
|
|
+ ).toBeTruthy();
|
|
|
+ expect(account.isSigner).toBe(
|
|
|
+ executePostedVaaArgs.instructions[i].keys[j].isSigner
|
|
|
+ );
|
|
|
+ expect(account.isWritable).toBe(
|
|
|
+ executePostedVaaArgs.instructions[i].keys[j].isWritable
|
|
|
+ );
|
|
|
+ });
|
|
|
+ });
|
|
|
+ done();
|
|
|
+ } else {
|
|
|
+ done("Not instance of WormholeInstruction");
|
|
|
+ }
|
|
|
+ });
|
|
|
+});
|