209 lines
6.0 KiB
TypeScript
209 lines
6.0 KiB
TypeScript
import {
|
|
assertChain,
|
|
assertEVMChain,
|
|
CHAINS,
|
|
CONTRACTS,
|
|
isEVMChain,
|
|
toChainName,
|
|
} from "@certusone/wormhole-sdk/lib/cjs/utils/consts";
|
|
import { ethers } from "ethers";
|
|
import yargs from "yargs";
|
|
import { NETWORKS } from "../networks";
|
|
import { evm_address } from "../utils";
|
|
import { config } from '../config';
|
|
import { runCommand, validator_args } from '../start-validator';
|
|
|
|
exports.command = "evm";
|
|
exports.desc = "EVM utilities";
|
|
exports.builder = function (y: typeof yargs) {
|
|
const evm = require("../evm");
|
|
return y
|
|
.option("rpc", {
|
|
describe: "RPC endpoint",
|
|
type: "string",
|
|
required: false,
|
|
})
|
|
.command(
|
|
"address-from-secret <secret>",
|
|
"Compute a 20 byte eth address from a 32 byte private key",
|
|
(yargs) => {
|
|
return yargs.positional("secret", {
|
|
type: "string",
|
|
describe: "Secret key (32 bytes)",
|
|
});
|
|
},
|
|
(argv) => {
|
|
console.log(ethers.utils.computeAddress(argv["secret"]));
|
|
}
|
|
)
|
|
.command(
|
|
"storage-update",
|
|
"Update a storage slot on an EVM fork during testing (anvil or hardhat)",
|
|
(yargs) => {
|
|
return yargs
|
|
.option("contract-address", {
|
|
alias: "a",
|
|
describe: "Contract address",
|
|
type: "string",
|
|
required: true,
|
|
})
|
|
.option("storage-slot", {
|
|
alias: "k",
|
|
describe: "Storage slot to modify",
|
|
type: "string",
|
|
required: true,
|
|
})
|
|
.option("value", {
|
|
alias: "v",
|
|
describe: "Value to write into the slot (32 bytes)",
|
|
type: "string",
|
|
required: true,
|
|
});
|
|
},
|
|
async (argv) => {
|
|
const result = await evm.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", {
|
|
alias: "c",
|
|
describe: "Chain to query",
|
|
type: "string",
|
|
choices: Object.keys(CHAINS),
|
|
required: true,
|
|
})
|
|
.option("module", {
|
|
alias: "m",
|
|
describe: "Module to query",
|
|
type: "string",
|
|
choices: ["Core", "NFTBridge", "TokenBridge"],
|
|
required: true,
|
|
})
|
|
.option("network", {
|
|
alias: "n",
|
|
describe: "network",
|
|
type: "string",
|
|
choices: ["mainnet", "testnet", "devnet"],
|
|
required: true,
|
|
})
|
|
.option("contract-address", {
|
|
alias: "a",
|
|
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"]);
|
|
assertEVMChain(argv["chain"]);
|
|
const network = argv.network.toUpperCase();
|
|
if (
|
|
network !== "MAINNET" &&
|
|
network !== "TESTNET" &&
|
|
network !== "DEVNET"
|
|
) {
|
|
throw Error(`Unknown network: ${network}`);
|
|
}
|
|
let module = argv["module"] as "Core" | "NFTBridge" | "TokenBridge";
|
|
let rpc = argv["rpc"] ?? NETWORKS[network][argv["chain"]].rpc;
|
|
if (argv["implementation-only"]) {
|
|
console.log(
|
|
await evm.getImplementation(
|
|
network,
|
|
argv["chain"],
|
|
module,
|
|
argv["contract-address"],
|
|
rpc
|
|
)
|
|
);
|
|
} else {
|
|
console.log(
|
|
JSON.stringify(
|
|
await evm.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
|
|
.option("core-contract-address", {
|
|
alias: "a",
|
|
describe: "Core contract address",
|
|
type: "string",
|
|
default: CONTRACTS.MAINNET.ethereum.core,
|
|
})
|
|
.option("guardian-address", {
|
|
alias: "g",
|
|
required: true,
|
|
describe: "Guardians' public addresses (CSV)",
|
|
type: "string",
|
|
})
|
|
.option("guardian-set-index", {
|
|
alias: "i",
|
|
required: false,
|
|
describe:
|
|
"New guardian set index (if unspecified, default to overriding the current index)",
|
|
type: "number",
|
|
});
|
|
},
|
|
async (argv) => {
|
|
const guardian_addresses = argv["guardian-address"].split(",");
|
|
let rpc = argv["rpc"] ?? NETWORKS.DEVNET.ethereum.rpc;
|
|
await evm.hijack_evm(
|
|
rpc,
|
|
argv["core-contract-address"],
|
|
guardian_addresses,
|
|
argv["guardian-set-index"]
|
|
);
|
|
}
|
|
)
|
|
.command("start-validator", "Start a local EVM validator", (yargs) => {
|
|
return yargs
|
|
.option("validator-args", validator_args)
|
|
}, (argv) => {
|
|
const dir = `${config.wormholeDir}/ethereum`;
|
|
const cmd = `cd ${dir} && npx ganache-cli -e 10000 --deterministic --time="1970-01-01T00:00:00+00:00"`;
|
|
runCommand(cmd, argv['validator-args'])
|
|
})
|
|
.strict()
|
|
.demandCommand();
|
|
};
|