diff --git a/Tiltfile b/Tiltfile index 83b05bc..d908616 100644 --- a/Tiltfile +++ b/Tiltfile @@ -1,8 +1,8 @@ analytics_settings(False) update_settings(max_parallel_updates=10) -k8s_yaml("tilt/anvil-base-sepolia.yaml") -k8s_yaml("tilt/anvil-eth-sepolia.yaml") +k8s_yaml("k8s/anvil-base-sepolia.yaml") +k8s_yaml("k8s/anvil-eth-sepolia.yaml") k8s_resource( "anvil-eth-sepolia", @@ -29,7 +29,7 @@ docker_build( ] ) -k8s_yaml("tilt/executor.yaml") +k8s_yaml("k8s/executor.yaml") k8s_resource( "executor", port_forwards = [ diff --git a/bun.lock b/bun.lock index 6e0d81f..94d1fa0 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,7 @@ "dependencies": { "@types/express": "^5.0.3", "express": "^5.1.0", + "viem": "^2.31.7", }, "devDependencies": { "@types/bun": "latest", @@ -16,6 +17,20 @@ }, }, "packages": { + "@adraffy/ens-normalize": ["@adraffy/ens-normalize@1.11.0", "", {}, "sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg=="], + + "@noble/ciphers": ["@noble/ciphers@1.3.0", "", {}, "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw=="], + + "@noble/curves": ["@noble/curves@1.9.2", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g=="], + + "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + + "@scure/base": ["@scure/base@1.2.6", "", {}, "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg=="], + + "@scure/bip32": ["@scure/bip32@1.7.0", "", { "dependencies": { "@noble/curves": "~1.9.0", "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw=="], + + "@scure/bip39": ["@scure/bip39@1.6.0", "", { "dependencies": { "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A=="], + "@types/body-parser": ["@types/body-parser@1.19.6", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g=="], "@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="], @@ -42,6 +57,8 @@ "@types/serve-static": ["@types/serve-static@1.15.8", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "*" } }, "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg=="], + "abitype": ["abitype@1.0.8", "", { "peerDependencies": { "typescript": ">=5.0.4", "zod": "^3 >=3.22.0" }, "optionalPeers": ["typescript", "zod"] }, "sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg=="], + "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], "body-parser": ["body-parser@2.2.0", "", { "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=="], @@ -84,6 +101,8 @@ "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], + "eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], + "express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="], "finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="], @@ -114,6 +133,8 @@ "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], + "isows": ["isows@1.0.7", "", { "peerDependencies": { "ws": "*" } }, "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], @@ -134,6 +155,8 @@ "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + "ox": ["ox@0.8.1", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "^1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.0.8", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-e+z5epnzV+Zuz91YYujecW8cF01mzmrUtWotJ0oEPym/G82uccs7q0WDHTYL3eiONbTUEvcZrptAKLgTBD3u2A=="], + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], "path-to-regexp": ["path-to-regexp@8.2.0", "", {}, "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ=="], @@ -180,8 +203,12 @@ "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + "viem": ["viem@2.31.7", "", { "dependencies": { "@noble/curves": "1.9.2", "@noble/hashes": "1.8.0", "@scure/bip32": "1.7.0", "@scure/bip39": "1.6.0", "abitype": "1.0.8", "isows": "1.0.7", "ox": "0.8.1", "ws": "8.18.2" }, "peerDependencies": { "typescript": ">=5.0.4" }, "optionalPeers": ["typescript"] }, "sha512-mpB8Hp6xK77E/b/yJmpAIQcxcOfpbrwWNItjnXaIA8lxZYt4JS433Pge2gg6Hp3PwyFtaUMh01j5L8EXnLTjQQ=="], + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + "ws": ["ws@8.18.2", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ=="], + "http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], } } diff --git a/tilt/anvil-base-sepolia.yaml b/k8s/anvil-base-sepolia.yaml similarity index 100% rename from tilt/anvil-base-sepolia.yaml rename to k8s/anvil-base-sepolia.yaml diff --git a/tilt/anvil-eth-sepolia.yaml b/k8s/anvil-eth-sepolia.yaml similarity index 100% rename from tilt/anvil-eth-sepolia.yaml rename to k8s/anvil-eth-sepolia.yaml diff --git a/tilt/executor.yaml b/k8s/executor.yaml similarity index 100% rename from tilt/executor.yaml rename to k8s/executor.yaml diff --git a/package.json b/package.json index 17ee3c1..e27eeca 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ }, "dependencies": { "@types/express": "^5.0.3", - "express": "^5.1.0" + "express": "^5.1.0", + "viem": "^2.31.7" } } diff --git a/src/abis/core.ts b/src/abis/core.ts new file mode 100644 index 0000000..3671a59 --- /dev/null +++ b/src/abis/core.ts @@ -0,0 +1,56 @@ +// partial ABI from the Wormhole Core contract +// https://etherscan.io/address/0x3c3d457f1522d3540ab3325aa5f1864e34cba9d0#code + +export const CORE_ABI = [ + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "sender", + type: "address", + }, + { + indexed: false, + internalType: "uint64", + name: "sequence", + type: "uint64", + }, + { indexed: false, internalType: "uint32", name: "nonce", type: "uint32" }, + { indexed: false, internalType: "bytes", name: "payload", type: "bytes" }, + { + indexed: false, + internalType: "uint8", + name: "consistencyLevel", + type: "uint8", + }, + ], + name: "LogMessagePublished", + type: "event", + }, + { + inputs: [], + name: "getCurrentGuardianSetIndex", + outputs: [{ internalType: "uint32", name: "", type: "uint32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint32", name: "index", type: "uint32" }], + name: "getGuardianSet", + outputs: [ + { + components: [ + { internalType: "address[]", name: "keys", type: "address[]" }, + { internalType: "uint32", name: "expirationTime", type: "uint32" }, + ], + internalType: "struct Structs.GuardianSet", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, +] as const; diff --git a/src/index.ts b/src/index.ts index 5fd9569..1acdac2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,14 @@ import express, { type Request, type Response } from "express"; +import { overrideGuardianSet } from "./overrideGuardianSet"; + +await overrideGuardianSet( + "http://anvil-eth-sepolia:8545", + "0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78" +); +await overrideGuardianSet( + "http://anvil-base-sepolia:8545", + "0x79A1027a6A159502049F10906D333EC57E95F083" +); const app = express(); app.use(express.json()); diff --git a/src/overrideGuardianSet.ts b/src/overrideGuardianSet.ts new file mode 100644 index 0000000..beae39b --- /dev/null +++ b/src/overrideGuardianSet.ts @@ -0,0 +1,66 @@ +import { + createPublicClient, + createTestClient, + encodeAbiParameters, + getContract, + http, + keccak256, + padHex, + parseAbiParameters, + toHex, + type Hex, +} from "viem"; +import { anvil } from "viem/chains"; +import { CORE_ABI } from "./abis/core"; + +export async function overrideGuardianSet( + anvilRpcUrl: string, + coreContractAddress: Hex +) { + const transport = http(anvilRpcUrl); + const publicClient = createPublicClient({ + chain: anvil, + transport, + }); + const coreContract = getContract({ + address: coreContractAddress, + abi: CORE_ABI, + client: publicClient, + }); + const guardianSetIndex = await coreContract.read.getCurrentGuardianSetIndex(); + const anvilClient = createTestClient({ + chain: anvil, + mode: "anvil", + transport, + }); + const GUARDIAN_SETS_SLOT = padHex("0x02", { dir: "left", size: 32 }); + const addressesStorageSlot = keccak256( + encodeAbiParameters(parseAbiParameters("uint32, bytes32"), [ + guardianSetIndex, + GUARDIAN_SETS_SLOT, + ]) + ); + const firstIndexStorageSlot = BigInt(keccak256(addressesStorageSlot)); + await anvilClient.setStorageAt({ + address: coreContractAddress, + index: addressesStorageSlot, + value: padHex("0x01", { dir: "left", size: 32 }), + }); + await anvilClient.setStorageAt({ + address: coreContractAddress, + index: toHex(firstIndexStorageSlot), + // devnet guardian https://github.com/wormhole-foundation/wormhole/blob/b9d34bef10ec74c345fa4b406559cf44e3d70095/scripts/devnet-consts.json#L323 + value: padHex("0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe", { + dir: "left", + size: 32, + }), + }); + const guardianSet = await coreContract.read.getGuardianSet([ + guardianSetIndex, + ]); + console.log( + `Overrode guardian set ${guardianSetIndex} of ${anvilRpcUrl} contract ${coreContractAddress} to ${guardianSet.keys.join( + ", " + )}` + ); +}