verify_vaa_shim_test.ts 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import { keccak256 } from "@certusone/wormhole-sdk/lib/cjs/utils/keccak";
  2. import { parseVaa } from "@certusone/wormhole-sdk/lib/cjs/vaa";
  3. import {
  4. AnchorProvider,
  5. Program,
  6. setProvider,
  7. Wallet,
  8. web3,
  9. } from "@coral-xyz/anchor";
  10. import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes";
  11. import { WormholeVerifyVaaShim } from "../../svm/wormhole-core-shims/anchor/idls/wormhole_verify_vaa_shim";
  12. import WormholeVerifyVaaShimIdl from "../../svm/wormhole-core-shims/anchor/idls/wormhole_verify_vaa_shim.json";
  13. // Usage:
  14. // RPC_URL="https://api.devnet.solana.com" CORE_BRIDGE_PROGRAM_ID=3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 SOLANA_KEY="<full_path>.json" VAA="<base64 VAA from wormholescan>" npx tsx post_message.ts
  15. const GUARDIAN_SET_SEED = "GuardianSet";
  16. (async () => {
  17. const RPC_URL = process.env.RPC_URL;
  18. if (!RPC_URL) {
  19. throw new Error("RPC_URL is required");
  20. }
  21. const CORE_BRIDGE_PROGRAM_ID = process.env.CORE_BRIDGE_PROGRAM_ID;
  22. if (!CORE_BRIDGE_PROGRAM_ID) {
  23. throw new Error("CORE_BRIDGE_PROGRAM_ID is required");
  24. }
  25. const coreBridgeAddress = new web3.PublicKey(CORE_BRIDGE_PROGRAM_ID);
  26. const VAA = process.env.VAA;
  27. if (!VAA) {
  28. throw new Error("VAA is required");
  29. }
  30. const connection = new web3.Connection(RPC_URL, "confirmed");
  31. const key = process.env.SOLANA_KEY;
  32. if (!key) {
  33. throw new Error("SOLANA_KEY is required");
  34. }
  35. const payer = web3.Keypair.fromSecretKey(
  36. key.endsWith(".json") ? new Uint8Array(require(key)) : bs58.decode(key)
  37. );
  38. const provider = new AnchorProvider(connection, new Wallet(payer));
  39. setProvider(provider);
  40. const program = new Program<WormholeVerifyVaaShim>(
  41. WormholeVerifyVaaShimIdl as WormholeVerifyVaaShim
  42. );
  43. const signatureKeypair = web3.Keypair.generate();
  44. console.log(`signature public key: ${signatureKeypair.publicKey.toString()}`);
  45. const buf = Buffer.from(VAA, "base64");
  46. const vaa = parseVaa(buf);
  47. const tx = await program.methods
  48. .postSignatures(
  49. vaa.guardianSetIndex,
  50. vaa.guardianSignatures.length,
  51. vaa.guardianSignatures.map((s) => [s.index, ...s.signature])
  52. )
  53. .accounts({ guardianSignatures: signatureKeypair.publicKey })
  54. .signers([signatureKeypair])
  55. .rpc();
  56. console.log(`verify tx1: ${tx}`);
  57. // Convert guardian_set_index to big-endian bytes
  58. const guardianSetIndex = vaa.guardianSetIndex;
  59. const indexBuffer = Buffer.alloc(4); // guardian_set_index is a u32
  60. indexBuffer.writeUInt32BE(guardianSetIndex);
  61. const [guardianSet, guardianSetBump] = web3.PublicKey.findProgramAddressSync(
  62. [Buffer.from(GUARDIAN_SET_SEED), indexBuffer],
  63. coreBridgeAddress
  64. );
  65. const tx2 = await program.methods
  66. .verifyHash(guardianSetBump, [...keccak256(vaa.hash)])
  67. .accounts({
  68. guardianSet,
  69. guardianSignatures: signatureKeypair.publicKey,
  70. })
  71. .preInstructions([
  72. web3.ComputeBudgetProgram.setComputeUnitLimit({
  73. units: 420_000,
  74. }),
  75. ])
  76. .postInstructions([
  77. await program.methods
  78. .closeSignatures()
  79. .accounts({ guardianSignatures: signatureKeypair.publicKey })
  80. .instruction(),
  81. ])
  82. .rpc();
  83. console.log(`verify tx2: ${tx2}`);
  84. })();