|
| 1 | +import { ParsedVaa } from "@certusone/wormhole-sdk"; |
| 2 | +import { GuardianSet } from "@certusone/wormhole-spydk/lib/cjs/proto/publicrpc/v1/publicrpc"; |
| 3 | +import { ethers } from "ethers"; |
| 4 | + |
| 5 | +const WormholeClusters = ["localnet", "testnet", "mainnet"] as const; |
| 6 | +export type WormholeCluster = typeof WormholeClusters[number]; |
| 7 | + |
| 8 | +export function wormholeClusterFromString(s: string): WormholeCluster { |
| 9 | + if (WormholeClusters.includes(s as WormholeCluster)) { |
| 10 | + return s as WormholeCluster; |
| 11 | + } |
| 12 | + throw new Error(`Invalid wormhole cluster: ${s}`); |
| 13 | +} |
| 14 | + |
| 15 | +const guardianSets: Record<WormholeCluster, GuardianSet> = { |
| 16 | + localnet: { |
| 17 | + index: 0, |
| 18 | + addresses: ["0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe"], |
| 19 | + }, |
| 20 | + testnet: { |
| 21 | + index: 0, |
| 22 | + addresses: ["0x13947Bd48b18E53fdAeEe77F3473391aC727C638"], |
| 23 | + }, |
| 24 | + mainnet: { |
| 25 | + index: 3, |
| 26 | + addresses: [ |
| 27 | + "0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5", |
| 28 | + "0xfF6CB952589BDE862c25Ef4392132fb9D4A42157", |
| 29 | + "0x114De8460193bdf3A2fCf81f86a09765F4762fD1", |
| 30 | + "0x107A0086b32d7A0977926A205131d8731D39cbEB", |
| 31 | + "0x8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2", |
| 32 | + "0x11b39756C042441BE6D8650b69b54EbE715E2343", |
| 33 | + "0x54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd", |
| 34 | + "0x15e7cAF07C4e3DC8e7C469f92C8Cd88FB8005a20", |
| 35 | + "0x74a3bf913953D695260D88BC1aA25A4eeE363ef0", |
| 36 | + "0x000aC0076727b35FBea2dAc28fEE5cCB0fEA768e", |
| 37 | + "0xAF45Ced136b9D9e24903464AE889F5C8a723FC14", |
| 38 | + "0xf93124b7c738843CBB89E864c862c38cddCccF95", |
| 39 | + "0xD2CC37A4dc036a8D232b48f62cDD4731412f4890", |
| 40 | + "0xDA798F6896A3331F64b48c12D1D57Fd9cbe70811", |
| 41 | + "0x71AA1BE1D36CaFE3867910F99C09e347899C19C3", |
| 42 | + "0x8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf", |
| 43 | + "0x178e21ad2E77AE06711549CFBB1f9c7a9d8096e8", |
| 44 | + "0x5E1487F35515d02A92753504a8D75471b9f49EdB", |
| 45 | + "0x6FbEBc898F403E4773E95feB15E80C9A99c8348d", |
| 46 | + ], |
| 47 | + }, |
| 48 | +}; |
| 49 | + |
| 50 | +export function isValidVaa(vaa: ParsedVaa, cluster: WormholeCluster): boolean { |
| 51 | + const currentGuardianSet = guardianSets[cluster]; |
| 52 | + if (vaa.guardianSetIndex !== currentGuardianSet.index) { |
| 53 | + return false; |
| 54 | + } |
| 55 | + |
| 56 | + const threshold = Math.ceil((currentGuardianSet.addresses.length * 2) / 3); |
| 57 | + if (vaa.guardianSignatures.length < threshold) { |
| 58 | + return false; |
| 59 | + } |
| 60 | + |
| 61 | + const digest = ethers.utils.keccak256(vaa.hash); |
| 62 | + |
| 63 | + let validVaa = true; |
| 64 | + vaa.guardianSignatures.forEach((sig) => { |
| 65 | + if ( |
| 66 | + ethers.utils.recoverAddress(digest, sig.signature) !== |
| 67 | + currentGuardianSet.addresses[sig.index] |
| 68 | + ) |
| 69 | + validVaa = false; |
| 70 | + }); |
| 71 | + |
| 72 | + return validVaa; |
| 73 | +} |
0 commit comments