Skip to content

Commit 6fc2f26

Browse files
committed
guardian mock
1 parent 655faa4 commit 6fc2f26

File tree

6 files changed

+126
-2
lines changed

6 files changed

+126
-2
lines changed

bun.lock

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
"name": "example-executor-ci-test",
66
"dependencies": {
77
"@types/express": "^5.0.3",
8+
"@wormhole-foundation/sdk-base": "^2.4.0",
9+
"@wormhole-foundation/sdk-definitions": "^2.4.0",
810
"express": "^5.1.0",
911
"viem": "^2.31.7",
1012
},
@@ -57,10 +59,16 @@
5759

5860
"@types/serve-static": ["@types/[email protected]", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "*" } }, "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg=="],
5961

62+
"@wormhole-foundation/sdk-base": ["@wormhole-foundation/[email protected]", "", { "dependencies": { "@scure/base": "^1.1.3", "binary-layout": "^1.0.3" } }, "sha512-8LbhBMeiDgykZSYc3hkV48bUbasYppCTt3CBQltqBGNUO56sr08HLLCde7R1y9/15qmgQv4cijjp0i/0fNu5hA=="],
63+
64+
"@wormhole-foundation/sdk-definitions": ["@wormhole-foundation/[email protected]", "", { "dependencies": { "@noble/curves": "^1.4.0", "@noble/hashes": "^1.3.1", "@wormhole-foundation/sdk-base": "2.4.0" } }, "sha512-Aqx3/XLaBzbt5kt70N0lnVj3acGe/DYN66R4lG7AVv7VvDTSj2PKC0qOdbKgMh+bzFbjKK03fJkpUzl/d6eo+A=="],
65+
6066
"abitype": ["[email protected]", "", { "peerDependencies": { "typescript": ">=5.0.4", "zod": "^3 >=3.22.0" }, "optionalPeers": ["typescript", "zod"] }, "sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg=="],
6167

6268
"accepts": ["[email protected]", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
6369

70+
"binary-layout": ["[email protected]", "", {}, "sha512-jDJ6rLgjjQ9q8NP5eIumdvsegbbMsNplJ7GHMuVnMWi0Qw59o8kIOw+ew4fLAryPL3LgIp5KrjfdAMoSpmpO8w=="],
71+
6472
"body-parser": ["[email protected]", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],
6573

6674
"bun-types": ["[email protected]", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="],

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
},
1515
"dependencies": {
1616
"@types/express": "^5.0.3",
17+
"@wormhole-foundation/sdk-base": "^2.4.0",
18+
"@wormhole-foundation/sdk-definitions": "^2.4.0",
1719
"express": "^5.1.0",
1820
"viem": "^2.31.7"
1921
}

src/abis/core.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// partial ABI from the Wormhole Core contract
1+
// partial ABI from the Wormhole Core contract's implementation
22
// https://etherscan.io/address/0x3c3d457f1522d3540ab3325aa5f1864e34cba9d0#code
33

44
export const CORE_ABI = [
@@ -29,6 +29,13 @@ export const CORE_ABI = [
2929
name: "LogMessagePublished",
3030
type: "event",
3131
},
32+
{
33+
inputs: [],
34+
name: "chainId",
35+
outputs: [{ internalType: "uint16", name: "", type: "uint16" }],
36+
stateMutability: "view",
37+
type: "function",
38+
},
3239
{
3340
inputs: [],
3441
name: "getCurrentGuardianSetIndex",

src/consts.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { toHex } from "viem";
2+
import { mnemonicToAccount } from "viem/accounts";
3+
4+
const account = mnemonicToAccount(
5+
"test test test test test test test test test test test junk",
6+
{ addressIndex: 9 }
7+
);
8+
9+
export const EVM_PUBLIC_KEY = account.address;
10+
export const EVM_PRIVATE_KEY = toHex(account.getHdKey().privateKey || "0x");

src/mockGuardian.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import { toChain } from "@wormhole-foundation/sdk-base";
2+
import {
3+
createVAA,
4+
serialize,
5+
UniversalAddress,
6+
type VAA,
7+
} from "@wormhole-foundation/sdk-definitions";
8+
import { mocks } from "@wormhole-foundation/sdk-definitions/testing";
9+
import {
10+
createPublicClient,
11+
getContract,
12+
http,
13+
isAddressEqual,
14+
padHex,
15+
parseEventLogs,
16+
toBytes,
17+
type Hex,
18+
} from "viem";
19+
import { anvil } from "viem/chains";
20+
import { CORE_ABI } from "./abis/core";
21+
import { EVM_PRIVATE_KEY } from "./consts";
22+
23+
async function getWormholeMessage(
24+
rpc: string,
25+
txHash: Hex,
26+
coreContractAddress: Hex
27+
): Promise<VAA<"Uint8Array"> | undefined> {
28+
console.log(`Mocking guardian signatures for ${rpc} ${txHash}`);
29+
const transport = http(rpc);
30+
const client = createPublicClient({
31+
chain: anvil,
32+
transport,
33+
});
34+
const transaction = await client.getTransactionReceipt({
35+
hash: txHash,
36+
});
37+
const coreContract = getContract({
38+
address: coreContractAddress,
39+
abi: CORE_ABI,
40+
client,
41+
});
42+
const chainId = await coreContract.read.chainId();
43+
const guardianSetIndex = await coreContract.read.getCurrentGuardianSetIndex();
44+
const topics = parseEventLogs({
45+
eventName: "LogMessagePublished",
46+
abi: CORE_ABI,
47+
logs: transaction.logs,
48+
});
49+
for (const topic of topics) {
50+
if (
51+
topic.removed === false &&
52+
isAddressEqual(topic.address, coreContractAddress)
53+
) {
54+
const emitter = topic.args.sender;
55+
return createVAA("Uint8Array", {
56+
guardianSet: guardianSetIndex,
57+
timestamp: Number(
58+
(
59+
await client.getBlock({
60+
blockHash: transaction.blockHash,
61+
includeTransactions: false,
62+
})
63+
).timestamp
64+
),
65+
// NOTE: the Wormhole SDK requires this be a known chain, though that is not strictly necessary for our use case.
66+
emitterChain: toChain(chainId),
67+
emitterAddress: new UniversalAddress(
68+
toBytes(padHex(emitter, { dir: "left", size: 32 }))
69+
),
70+
consistencyLevel: topic.args.consistencyLevel,
71+
sequence: topic.args.sequence,
72+
nonce: topic.args.nonce,
73+
signatures: [],
74+
payload: toBytes(topic.args.payload),
75+
});
76+
}
77+
}
78+
}
79+
80+
/**
81+
* returns a base64 string like a guardian /v1/signed_vaa/
82+
*/
83+
export async function mockWormhole(
84+
rpc: string,
85+
txHash: Hex,
86+
coreContractAddress: Hex
87+
): Promise<string> {
88+
const vaa = await getWormholeMessage(rpc, txHash, coreContractAddress);
89+
if (vaa) {
90+
const guardianSet = new mocks.MockGuardians(0, [EVM_PRIVATE_KEY]);
91+
const signedVaa = guardianSet.addSignatures(vaa);
92+
const base64 = Buffer.from(serialize(signedVaa)).toString("base64");
93+
return base64;
94+
}
95+
return "";
96+
}

src/overrideGuardianSet.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
} from "viem";
1313
import { anvil } from "viem/chains";
1414
import { CORE_ABI } from "./abis/core";
15+
import { EVM_PUBLIC_KEY } from "./consts";
1516

1617
export async function overrideGuardianSet(
1718
anvilRpcUrl: string,
@@ -50,7 +51,7 @@ export async function overrideGuardianSet(
5051
address: coreContractAddress,
5152
index: toHex(firstIndexStorageSlot),
5253
// devnet guardian https://github.com/wormhole-foundation/wormhole/blob/b9d34bef10ec74c345fa4b406559cf44e3d70095/scripts/devnet-consts.json#L323
53-
value: padHex("0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe", {
54+
value: padHex(EVM_PUBLIC_KEY, {
5455
dir: "left",
5556
size: 32,
5657
}),

0 commit comments

Comments
 (0)