clients/js: formatting only change (prettier)

Change-Id: I0b8805e0a577f0ef8757a5468c43fcb1083c0825
This commit is contained in:
Paul Noel 2022-08-18 14:42:11 +00:00 committed by Paul Noel
parent a6f75f1aef
commit 338e6f2648
1 changed files with 331 additions and 234 deletions

View File

@ -4,9 +4,20 @@ import yargs from "yargs";
import { hideBin } from "yargs/helpers"; import { hideBin } from "yargs/helpers";
import { Bech32, fromBech32, toHex } from "@cosmjs/encoding"; import { Bech32, fromBech32, toHex } from "@cosmjs/encoding";
import { isTerraChain, assertEVMChain, CONTRACTS, setDefaultWasm } from "@certusone/wormhole-sdk"; import {
isTerraChain,
assertEVMChain,
CONTRACTS,
setDefaultWasm,
} from "@certusone/wormhole-sdk";
import { execute_solana } from "./solana"; import { execute_solana } from "./solana";
import { execute_evm, getImplementation, hijack_evm, query_contract_evm, setStorageAt } from "./evm"; import {
execute_evm,
getImplementation,
hijack_evm,
query_contract_evm,
setStorageAt,
} from "./evm";
import { execute_terra } from "./terra"; import { execute_terra } from "./terra";
import * as vaa from "./vaa"; import * as vaa from "./vaa";
import { impossible, Payload, serialiseVAA, VAA } from "./vaa"; import { impossible, Payload, serialiseVAA, VAA } from "./vaa";
@ -100,7 +111,10 @@ yargs(hideBin(process.argv))
type: "RegisterChain", type: "RegisterChain",
chain: 0, chain: 0,
emitterChain: toChainId(argv["chain"]), emitterChain: toChainId(argv["chain"]),
emitterAddress: parseAddress(argv["chain"], argv["contract-address"]), emitterAddress: parseAddress(
argv["chain"],
argv["contract-address"]
),
}; };
let v = makeVAA( let v = makeVAA(
GOVERNANCE_CHAIN, GOVERNANCE_CHAIN,
@ -148,7 +162,10 @@ yargs(hideBin(process.argv))
module, module,
type: "ContractUpgrade", type: "ContractUpgrade",
chain: toChainId(argv["chain"]), chain: toChainId(argv["chain"]),
address: parseCodeAddress(argv["chain"], argv["contract-address"]), address: parseCodeAddress(
argv["chain"],
argv["contract-address"]
),
}; };
let v = makeVAA( let v = makeVAA(
GOVERNANCE_CHAIN, GOVERNANCE_CHAIN,
@ -179,233 +196,305 @@ yargs(hideBin(process.argv))
async (argv) => { async (argv) => {
let buf: Buffer; let buf: Buffer;
try { try {
buf = Buffer.from(String(argv.vaa), "hex") buf = Buffer.from(String(argv.vaa), "hex");
if (buf.length == 0) { if (buf.length == 0) {
throw Error("Couldn't parse VAA as hex") throw Error("Couldn't parse VAA as hex");
} }
} catch (e) { } catch (e) {
buf = Buffer.from(String(argv.vaa), "base64") buf = Buffer.from(String(argv.vaa), "base64");
if (buf.length == 0) { if (buf.length == 0) {
throw Error("Couldn't parse VAA as base64 or hex") throw Error("Couldn't parse VAA as base64 or hex");
} }
} }
const parsed_vaa = vaa.parse(buf); const parsed_vaa = vaa.parse(buf);
let parsed_vaa_with_digest = parsed_vaa; let parsed_vaa_with_digest = parsed_vaa;
parsed_vaa_with_digest['digest'] = vaa.vaaDigest(parsed_vaa); parsed_vaa_with_digest["digest"] = vaa.vaaDigest(parsed_vaa);
console.log(parsed_vaa_with_digest); console.log(parsed_vaa_with_digest);
})
.command("recover <digest> <signature>", "Recover an address from a signature", (yargs) => {
return yargs
.positional("digest", {
describe: "digest",
type: "string"
})
.positional("signature", {
describe: "signature",
type: "string"
});
}, async (argv) => {
console.log(ethers.utils.recoverAddress(hex(argv["digest"]), hex(argv["signature"])))
})
.command("contract <network> <chain> <module>", "Print contract address", (yargs) => {
return yargs
.positional("network", {
describe: "network",
type: "string",
choices: ["mainnet", "testnet", "devnet"],
})
.positional("chain", {
describe: "Chain to query",
type: "string",
choices: Object.keys(CHAINS),
})
.positional("module", {
describe: "Module to query",
type: "string",
choices: ["Core", "NFTBridge", "TokenBridge"],
})
}, 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" .command(
| "NFTBridge" "recover <digest> <signature>",
| "TokenBridge"; "Recover an address from a signature",
switch (module) { (yargs) => {
case "Core": return yargs
console.log(CONTRACTS[network][argv["chain"]]["core"]) .positional("digest", {
break; describe: "digest",
case "NFTBridge": type: "string",
console.log(CONTRACTS[network][argv["chain"]]["nft_bridge"]) })
break; .positional("signature", {
case "TokenBridge": describe: "signature",
console.log(CONTRACTS[network][argv["chain"]]["token_bridge"]) type: "string",
break; });
default: },
impossible(module) async (argv) => {
console.log(
ethers.utils.recoverAddress(hex(argv["digest"]), hex(argv["signature"]))
);
} }
}) )
.command("rpc <network> <chain>", "Print RPC address", (yargs) => { .command(
return yargs "contract <network> <chain> <module>",
.positional("network", { "Print contract address",
describe: "network", (yargs) => {
type: "string", return yargs
choices: ["mainnet", "testnet", "devnet"], .positional("network", {
}) describe: "network",
.positional("chain", { type: "string",
describe: "Chain to query", choices: ["mainnet", "testnet", "devnet"],
type: "string", })
choices: Object.keys(CHAINS), .positional("chain", {
}) describe: "Chain to query",
}, async (argv) => { type: "string",
assertChain(argv["chain"]) choices: Object.keys(CHAINS),
assertEVMChain(argv["chain"]) })
const network = argv.network.toUpperCase(); .positional("module", {
if ( describe: "Module to query",
network !== "MAINNET" && type: "string",
network !== "TESTNET" && choices: ["Core", "NFTBridge", "TokenBridge"],
network !== "DEVNET" });
) { },
throw Error(`Unknown network: ${network}`); 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";
switch (module) {
case "Core":
console.log(CONTRACTS[network][argv["chain"]]["core"]);
break;
case "NFTBridge":
console.log(CONTRACTS[network][argv["chain"]]["nft_bridge"]);
break;
case "TokenBridge":
console.log(CONTRACTS[network][argv["chain"]]["token_bridge"]);
break;
default:
impossible(module);
}
} }
console.log(NETWORKS[network][argv["chain"]].rpc) )
}) .command(
"rpc <network> <chain>",
"Print RPC address",
(yargs) => {
return yargs
.positional("network", {
describe: "network",
type: "string",
choices: ["mainnet", "testnet", "devnet"],
})
.positional("chain", {
describe: "Chain to query",
type: "string",
choices: Object.keys(CHAINS),
});
},
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}`);
}
console.log(NETWORKS[network][argv["chain"]].rpc);
}
)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Evm utilities // Evm utilities
.command("evm", "EVM utilites", (yargs) => { .command(
return yargs "evm",
.option("rpc", { "EVM utilites",
describe: "RPC endpoint", (yargs) => {
type: "string", return yargs
required: false .option("rpc", {
}) describe: "RPC endpoint",
.command("address-from-secret <secret>", "Compute a 20 byte eth address from a 32 byte private key", (yargs) => { type: "string",
return yargs required: false,
.positional("secret", { type: "string", describe: "Secret key (32 bytes)" }) })
}, (argv) => { .command(
console.log(ethers.utils.computeAddress(argv["secret"])) "address-from-secret <secret>",
}) "Compute a 20 byte eth address from a 32 byte private key",
.command("storage-update", "Update a storage slot on an EVM fork during testing (anvil or hardhat)", (yargs) => { (yargs) => {
return yargs return yargs.positional("secret", {
.option("contract-address", { type: "string",
alias: "a", describe: "Secret key (32 bytes)",
describe: "Contract address", });
type: "string", },
required: true, (argv) => {
}) console.log(ethers.utils.computeAddress(argv["secret"]));
.option("storage-slot", { }
alias: "k", )
describe: "Storage slot to modify", .command(
type: "string", "storage-update",
required: true, "Update a storage slot on an EVM fork during testing (anvil or hardhat)",
}) (yargs) => {
.option("value", { return yargs
alias: "v", .option("contract-address", {
describe: "Value to write into the slot (32 bytes)", alias: "a",
type: "string", describe: "Contract address",
required: true, type: "string",
}); required: true,
}, async (argv) => { })
const result = await setStorageAt(argv["rpc"], evm_address(argv["contract-address"]), argv["storage-slot"], ["uint256"], [argv["value"]]); .option("storage-slot", {
console.log(result); alias: "k",
}) describe: "Storage slot to modify",
.command("chains", "Return all EVM chains", type: "string",
async (_) => { required: true,
console.log(Object.values(CHAINS).map(id => toChainName(id)).filter(name => isEVMChain(name)).join(" ")) })
} .option("value", {
) alias: "v",
.command("info", "Query info about the on-chain state of the contract", (yargs) => { describe: "Value to write into the slot (32 bytes)",
return yargs type: "string",
.option("chain", { required: true,
alias: "c", });
describe: "Chain to query", },
type: "string", async (argv) => {
choices: Object.keys(CHAINS), const result = await setStorageAt(
required: true, argv["rpc"],
}) evm_address(argv["contract-address"]),
.option("module", { argv["storage-slot"],
alias: "m", ["uint256"],
describe: "Module to query", [argv["value"]]
type: "string", );
choices: ["Core", "NFTBridge", "TokenBridge"], console.log(result);
required: true, }
}) )
.option("network", { .command("chains", "Return all EVM chains", async (_) => {
alias: "n", console.log(
describe: "network", Object.values(CHAINS)
type: "string", .map((id) => toChainName(id))
choices: ["mainnet", "testnet", "devnet"], .filter((name) => isEVMChain(name))
required: true, .join(" ")
}) );
.option("contract-address", { })
alias: "a", .command(
describe: "Contract to query (override config)", "info",
type: "string", "Query info about the on-chain state of the contract",
required: false, (yargs) => {
}) return yargs
.option("implementation-only", { .option("chain", {
alias: "i", alias: "c",
describe: "Only query implementation (faster)", describe: "Chain to query",
type: "boolean", type: "string",
default: false, choices: Object.keys(CHAINS),
required: false, required: true,
}); })
}, async (argv) => { .option("module", {
assertChain(argv["chain"]) alias: "m",
assertEVMChain(argv["chain"]) describe: "Module to query",
const network = argv.network.toUpperCase(); type: "string",
if ( choices: ["Core", "NFTBridge", "TokenBridge"],
network !== "MAINNET" && required: true,
network !== "TESTNET" && })
network !== "DEVNET" .option("network", {
) { alias: "n",
throw Error(`Unknown network: ${network}`); describe: "network",
} type: "string",
let module = argv["module"] as choices: ["mainnet", "testnet", "devnet"],
| "Core" required: true,
| "NFTBridge" })
| "TokenBridge"; .option("contract-address", {
let rpc = argv["rpc"] ?? NETWORKS[network][argv["chain"]].rpc alias: "a",
if (argv["implementation-only"]) { describe: "Contract to query (override config)",
console.log(await getImplementation(network, argv["chain"], module, argv["contract-address"], rpc)) type: "string",
} else { required: false,
console.log(JSON.stringify(await query_contract_evm(network, argv["chain"], module, argv["contract-address"], rpc), null, 2)) })
} .option("implementation-only", {
}) alias: "i",
.command("hijack", "Override the guardian set of the core bridge contract during testing (anvil or hardhat)", (yargs) => { describe: "Only query implementation (faster)",
return yargs type: "boolean",
.option("core-contract-address", { default: false,
alias: "a", required: false,
describe: "Core contract address", });
type: "string", },
default: CONTRACTS.MAINNET.ethereum.core, async (argv) => {
}) assertChain(argv["chain"]);
.option("guardian-address", { assertEVMChain(argv["chain"]);
alias: "g", const network = argv.network.toUpperCase();
required: true, if (
describe: "Guardians' public addresses (CSV)", network !== "MAINNET" &&
type: "string", network !== "TESTNET" &&
}) network !== "DEVNET"
.option("guardian-set-index", { ) {
alias: "i", throw Error(`Unknown network: ${network}`);
required: false, }
describe: "New guardian set index (if unspecified, default to overriding the current index)", let module = argv["module"] as "Core" | "NFTBridge" | "TokenBridge";
type: "number" let rpc = argv["rpc"] ?? NETWORKS[network][argv["chain"]].rpc;
}); if (argv["implementation-only"]) {
}, async (argv) => { console.log(
const guardian_addresses = argv["guardian-address"].split(",") await getImplementation(
let rpc = argv["rpc"] ?? NETWORKS.DEVNET.ethereum.rpc network,
await hijack_evm(rpc, argv["core-contract-address"], guardian_addresses, argv["guardian-set-index"]) 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
.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 hijack_evm(
rpc,
argv["core-contract-address"],
guardian_addresses,
argv["guardian-set-index"]
);
}
);
},
(_) => { (_) => {
yargs.showHelp(); yargs.showHelp();
} }
@ -445,9 +534,10 @@ yargs(hideBin(process.argv))
.option("rpc", { .option("rpc", {
describe: "RPC endpoint", describe: "RPC endpoint",
type: "string", type: "string",
required: false required: false,
}) });
}, async (argv) => { },
async (argv) => {
const vaa_hex = String(argv.vaa); const vaa_hex = String(argv.vaa);
const buf = Buffer.from(vaa_hex, "hex"); const buf = Buffer.from(vaa_hex, "hex");
const parsed_vaa = vaa.parse(buf); const parsed_vaa = vaa.parse(buf);
@ -504,7 +594,14 @@ yargs(hideBin(process.argv))
"This VAA does not specify the target chain, please provide it by hand using the '--chain' flag." "This VAA does not specify the target chain, please provide it by hand using the '--chain' flag."
); );
} else if (isEVMChain(chain)) { } else if (isEVMChain(chain)) {
await execute_evm(parsed_vaa.payload, buf, network, chain, argv["contract-address"], argv["rpc"]); await execute_evm(
parsed_vaa.payload,
buf,
network,
chain,
argv["contract-address"],
argv["rpc"]
);
} else if (isTerraChain(chain)) { } else if (isTerraChain(chain)) {
await execute_terra(parsed_vaa.payload, buf, network, chain); await execute_terra(parsed_vaa.payload, buf, network, chain);
} else if (chain === "solana") { } else if (chain === "solana") {
@ -530,44 +627,44 @@ yargs(hideBin(process.argv))
).argv; ).argv;
function hex(x: string): string { function hex(x: string): string {
return ethers.utils.hexlify(x, { allowMissingPrefix: true }) return ethers.utils.hexlify(x, { allowMissingPrefix: true });
} }
function evm_address(x: string): string { function evm_address(x: string): string {
return hex(x).substring(2).padStart(64, "0") return hex(x).substring(2).padStart(64, "0");
} }
function parseAddress(chain: ChainName, address: string): string { function parseAddress(chain: ChainName, address: string): string {
if (chain === "unset") { if (chain === "unset") {
throw Error("Chain unset") throw Error("Chain unset");
} else if (isEVMChain(chain)) { } else if (isEVMChain(chain)) {
return "0x" + evm_address(address) return "0x" + evm_address(address);
} else if (isTerraChain(chain)) { } else if (isTerraChain(chain)) {
return "0x" + toHex(fromBech32(address).data).padStart(64, "0") return "0x" + toHex(fromBech32(address).data).padStart(64, "0");
} else if (chain === "solana") { } else if (chain === "solana") {
return "0x" + toHex(base58.decode(address)).padStart(64, "0") return "0x" + toHex(base58.decode(address)).padStart(64, "0");
} else if (chain === "algorand") { } else if (chain === "algorand") {
// TODO: is there a better native format for algorand? // TODO: is there a better native format for algorand?
return "0x" + evm_address(address) return "0x" + evm_address(address);
} else if (chain === "near") { } else if (chain === "near") {
throw Error("NEAR is not supported yet") throw Error("NEAR is not supported yet");
} else if (chain === "injective") { } else if (chain === "injective") {
throw Error("INJECTIVE is not supported yet"); throw Error("INJECTIVE is not supported yet");
} else if (chain === "osmosis") { } else if (chain === "osmosis") {
throw Error("OSMOSIS is not supported yet"); throw Error("OSMOSIS is not supported yet");
} else if (chain === "sui") { } else if (chain === "sui") {
throw Error("SUI is not supported yet") throw Error("SUI is not supported yet");
} else if (chain === "aptos") { } else if (chain === "aptos") {
throw Error("APTOS is not supported yet") throw Error("APTOS is not supported yet");
} else { } else {
impossible(chain) impossible(chain);
} }
} }
function parseCodeAddress(chain: ChainName, address: string): string { function parseCodeAddress(chain: ChainName, address: string): string {
if (isTerraChain(chain)) { if (isTerraChain(chain)) {
return "0x" + parseInt(address, 10).toString(16).padStart(64, "0") return "0x" + parseInt(address, 10).toString(16).padStart(64, "0");
} else { } else {
return parseAddress(chain, address) return parseAddress(chain, address);
} }
} }