import crypto from "crypto"; // @ts-expect-error globalThis.crypto = crypto; import { createWormholeProgramInterface } from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole"; import { AnchorProvider, Wallet } from "@coral-xyz/anchor"; import { getPythClusterApiUrl, PythCluster, } from "@pythnetwork/client/lib/cluster"; import { Connection, Keypair, PublicKey, SystemProgram, TransactionInstruction, } from "@solana/web3.js"; import { MultisigInstructionProgram, MultisigParser, WORMHOLE_ADDRESS, ExecutePostedVaa, } from ".."; 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 = MultisigParser.fromCluster(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); 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 WormholeMultisigInstruction"); } }); }); 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 = MultisigParser.fromCluster(cluster); const executePostedVaa: ExecutePostedVaa = new ExecutePostedVaa("pythnet", [ SystemProgram.transfer({ fromPubkey: PublicKey.unique(), toPubkey: PublicKey.unique(), lamports: 890880, }), ]); wormholeProgram.methods .postMessage(0, executePostedVaa.encode(), 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.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(executePostedVaa.encode()) ); expect(parsedInstruction.args.consistencyLevel).toBe(0); if (parsedInstruction.governanceAction instanceof ExecutePostedVaa) { expect(parsedInstruction.governanceAction.targetChainId).toBe( "pythnet" ); ( parsedInstruction.governanceAction .instructions as TransactionInstruction[] ).forEach((instruction, i) => { expect( instruction.programId.equals( executePostedVaa.instructions[i].programId ) ); expect( instruction.data.equals(executePostedVaa.instructions[i].data) ); instruction.keys.forEach((account, j) => { expect( account.pubkey.equals( executePostedVaa.instructions[i].keys[j].pubkey ) ).toBeTruthy(); expect(account.isSigner).toBe( executePostedVaa.instructions[i].keys[j].isSigner ); expect(account.isWritable).toBe( executePostedVaa.instructions[i].keys[j].isWritable ); }); }); done(); } else { done("Not instance of ExecutePostedVaa"); } } else { done("Not instance of WormholeMultisigInstruction"); } }); });