diff --git a/clients/js/Makefile b/clients/js/Makefile index 0c0da1ff9..98bb6ed9b 100644 --- a/clients/js/Makefile +++ b/clients/js/Makefile @@ -15,8 +15,8 @@ dependencies: node_modules build: node_modules $(SOURCE_FILES) @mkdir -p build - @touch -m build npm run build + @touch -m build install: build @echo Linking binaries diff --git a/clients/js/evm.ts b/clients/js/evm.ts index a831a32da..c88b82629 100644 --- a/clients/js/evm.ts +++ b/clients/js/evm.ts @@ -104,6 +104,38 @@ export async function query_contract_evm( return result } +export async function getImplementation( + network: "MAINNET" | "TESTNET" | "DEVNET", + chain: EVMChainName, + module: "Core" | "NFTBridge" | "TokenBridge", + contract_address: string | undefined, + _rpc: string | undefined +): Promise { + let n = NETWORKS[network][chain] + let rpc: string | undefined = _rpc ?? n.rpc; + if (rpc === undefined) { + throw Error(`No ${network} rpc defined for ${chain} (see networks.ts)`) + } + + let contracts: Contracts = CONTRACTS[network][chain] + + switch (module) { + case "Core": + contract_address = contract_address ? contract_address : contracts.core; + break + case "TokenBridge": + contract_address = contract_address ? contract_address : contracts.token_bridge; + break + case "NFTBridge": + contract_address = contract_address ? contract_address : contracts.nft_bridge; + break + default: + impossible(module) + } + + return (await getStorageAt(rpc, contract_address, _IMPLEMENTATION_SLOT, ["address"]))[0] +} + export async function execute_governance_evm( payload: Payload, vaa: Buffer, diff --git a/clients/js/main.ts b/clients/js/main.ts index 6aa9e1034..4eda9b40b 100644 --- a/clients/js/main.ts +++ b/clients/js/main.ts @@ -5,7 +5,7 @@ import { hideBin } from "yargs/helpers"; import { isTerraChain, assertEVMChain, CONTRACTS, setDefaultWasm } from "@certusone/wormhole-sdk"; import { execute_governance_solana } from "./solana"; -import { execute_governance_evm, hijack_evm, query_contract_evm, setStorageAt } from "./evm"; +import { execute_governance_evm, getImplementation, hijack_evm, query_contract_evm, setStorageAt } from "./evm"; import { execute_governance_terra } from "./terra"; import * as vaa from "./vaa"; import { impossible, Payload, serialiseVAA, VAA } from "./vaa"; @@ -309,6 +309,11 @@ yargs(hideBin(process.argv)) const result = await setStorageAt(argv["rpc"], evm_address(argv["contract-address"]), argv["storage-slot"], ["uint256"], [argv["value"]]); console.log(result); }) + .command("chains", "Return all EVM chains", + async (_) => { + console.log(Object.values(CHAINS).map(id => toChainName(id)).filter(name => isEVMChain(name)).join(" ")) + } + ) .command("info", "Query info about the on-chain state of the contract", (yargs) => { return yargs .option("chain", { @@ -337,6 +342,13 @@ yargs(hideBin(process.argv)) describe: "Contract to query (override config)", type: "string", required: false, + }) + .option("implementation-only", { + alias: "i", + describe: "Only query implementation (faster)", + type: "boolean", + default: false, + required: false, }); }, async (argv) => { assertChain(argv["chain"]) @@ -354,7 +366,11 @@ yargs(hideBin(process.argv)) | "NFTBridge" | "TokenBridge"; let rpc = argv["rpc"] ?? NETWORKS[network][argv["chain"]].rpc - console.log(JSON.stringify(await query_contract_evm(network, argv["chain"], module, argv["contract-address"], rpc), null, 2)) + if (argv["implementation-only"]) { + console.log(await getImplementation(network, argv["chain"], module, argv["contract-address"], rpc)) + } else { + console.log(JSON.stringify(await query_contract_evm(network, argv["chain"], module, argv["contract-address"], rpc), null, 2)) + } }) .command("hijack", "Override the guardian set of the core bridge contract during testing (anvil or hardhat)", (yargs) => { return yargs