clients/js: set strict = true in tsconfig
This commit is contained in:
parent
0cff646fed
commit
9d50254893
|
@ -45,6 +45,7 @@
|
|||
"@truffle/hdwallet-provider": "^2.0.15",
|
||||
"@types/bn.js": "^5.1.0",
|
||||
"@types/bs58": "^4.0.1",
|
||||
"@types/node-fetch": "^2.6.3",
|
||||
"@types/yargs": "^17.0.2",
|
||||
"copy-dir": "^1.3.0",
|
||||
"typescript": "^4.6"
|
||||
|
@ -3440,6 +3441,30 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz",
|
||||
"integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A=="
|
||||
},
|
||||
"node_modules/@types/node-fetch": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.3.tgz",
|
||||
"integrity": "sha512-ETTL1mOEdq/sxUtgtOhKjyB2Irra4cjxksvcMUR5Zr4n+PxVhsCD9WS46oPbHL3et9Zde7CNRr+WUNlcHvsX+w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"form-data": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node-fetch/node_modules/form-data": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
|
||||
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/pbkdf2": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz",
|
||||
|
@ -10753,6 +10778,29 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz",
|
||||
"integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A=="
|
||||
},
|
||||
"@types/node-fetch": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.3.tgz",
|
||||
"integrity": "sha512-ETTL1mOEdq/sxUtgtOhKjyB2Irra4cjxksvcMUR5Zr4n+PxVhsCD9WS46oPbHL3et9Zde7CNRr+WUNlcHvsX+w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"form-data": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"form-data": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
|
||||
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/pbkdf2": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz",
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
"@truffle/hdwallet-provider": "^2.0.15",
|
||||
"@types/bn.js": "^5.1.0",
|
||||
"@types/bs58": "^4.0.1",
|
||||
"@types/node-fetch": "^2.6.3",
|
||||
"@types/yargs": "^17.0.2",
|
||||
"copy-dir": "^1.3.0",
|
||||
"typescript": "^4.6"
|
||||
|
|
|
@ -1,40 +1,42 @@
|
|||
import { NETWORKS } from "./networks";
|
||||
import { impossible, Payload } from "./vaa";
|
||||
import { Account, Algodv2, mnemonicToSecretKey } from "algosdk";
|
||||
import {
|
||||
signSendAndConfirmAlgorand,
|
||||
_submitVAAAlgorand,
|
||||
signSendAndConfirmAlgorand,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/algorand";
|
||||
import { CONTRACTS } from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import { Account, Algodv2, mnemonicToSecretKey } from "algosdk";
|
||||
import { NETWORKS } from "./networks";
|
||||
import { Network } from "./utils";
|
||||
import { Payload, impossible } from "./vaa";
|
||||
|
||||
export async function execute_algorand(
|
||||
payload: Payload,
|
||||
vaa: Uint8Array,
|
||||
environment: "MAINNET" | "TESTNET" | "DEVNET"
|
||||
network: Network
|
||||
) {
|
||||
const chainName = "algorand";
|
||||
let n = NETWORKS[environment][chainName];
|
||||
if (!n.key) {
|
||||
throw Error(`No ${environment} key defined for Algorand`);
|
||||
const { key, rpc } = NETWORKS[network][chainName];
|
||||
if (!key) {
|
||||
throw Error(`No ${network} key defined for Algorand`);
|
||||
}
|
||||
if (!n.rpc) {
|
||||
throw Error(`No ${environment} rpc defined for Algorand`);
|
||||
|
||||
if (!rpc) {
|
||||
throw Error(`No ${network} rpc defined for Algorand`);
|
||||
}
|
||||
let contracts = CONTRACTS[environment][chainName];
|
||||
|
||||
const contracts = CONTRACTS[network][chainName];
|
||||
console.log("contracts", contracts);
|
||||
const ALGORAND_HOST = {
|
||||
algodToken: "",
|
||||
algodServer: n.rpc,
|
||||
algodServer: rpc,
|
||||
algodPort: "",
|
||||
};
|
||||
if (environment === "DEVNET") {
|
||||
if (network === "DEVNET") {
|
||||
ALGORAND_HOST.algodToken =
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
|
||||
ALGORAND_HOST.algodPort = "4001";
|
||||
}
|
||||
|
||||
let target_contract: string;
|
||||
|
||||
switch (payload.module) {
|
||||
case "Core":
|
||||
target_contract = contracts.core;
|
||||
|
@ -99,22 +101,20 @@ export async function execute_algorand(
|
|||
throw Error("Can't complete payload 3 transfer from CLI");
|
||||
default:
|
||||
impossible(payload);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
target_contract = impossible(payload);
|
||||
}
|
||||
|
||||
const target = BigInt(parseInt(target_contract));
|
||||
|
||||
const CORE_ID = BigInt(parseInt(contracts.core));
|
||||
|
||||
const algodClient = new Algodv2(
|
||||
ALGORAND_HOST.algodToken,
|
||||
ALGORAND_HOST.algodServer,
|
||||
ALGORAND_HOST.algodPort
|
||||
);
|
||||
const algoWallet: Account = mnemonicToSecretKey(n.key);
|
||||
const algoWallet: Account = mnemonicToSecretKey(key);
|
||||
|
||||
// Create transaction
|
||||
const txs = await _submitVAAAlgorand(
|
||||
|
@ -124,6 +124,7 @@ export async function execute_algorand(
|
|||
vaa,
|
||||
algoWallet.addr
|
||||
);
|
||||
|
||||
// Sign and send transaction
|
||||
const result = await signSendAndConfirmAlgorand(algodClient, txs, algoWallet);
|
||||
console.log("Confirmed in round:", result["confirmed-round"]);
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
import { AptosAccount, TxnBuilderTypes, AptosClient, BCS } from "aptos";
|
||||
import { NETWORKS } from "./networks";
|
||||
import { impossible, Payload } from "./vaa";
|
||||
import { sha3_256 } from "js-sha3";
|
||||
import { ethers } from "ethers";
|
||||
import {
|
||||
assertChain,
|
||||
ChainId,
|
||||
CONTRACTS,
|
||||
ChainId,
|
||||
assertChain,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import { AptosAccount, AptosClient, BCS, TxnBuilderTypes } from "aptos";
|
||||
import { ethers } from "ethers";
|
||||
import { sha3_256 } from "js-sha3";
|
||||
import { NETWORKS } from "./networks";
|
||||
import { Network } from "./utils";
|
||||
import { Payload, impossible } from "./vaa";
|
||||
|
||||
export async function execute_aptos(
|
||||
payload: Payload,
|
||||
vaa: Buffer,
|
||||
network: "MAINNET" | "TESTNET" | "DEVNET",
|
||||
network: Network,
|
||||
contract: string | undefined,
|
||||
rpc: string | undefined
|
||||
) {
|
||||
|
@ -24,11 +25,12 @@ export async function execute_aptos(
|
|||
const bcsVAA = serializer.getBytes();
|
||||
|
||||
switch (payload.module) {
|
||||
case "Core":
|
||||
case "Core": {
|
||||
contract = contract ?? CONTRACTS[network][chain]["core"];
|
||||
if (contract === undefined) {
|
||||
throw Error("core bridge contract is undefined");
|
||||
}
|
||||
|
||||
switch (payload.type) {
|
||||
case "GuardianSetUpgrade":
|
||||
console.log("Submitting new guardian set");
|
||||
|
@ -57,12 +59,15 @@ export async function execute_aptos(
|
|||
default:
|
||||
impossible(payload);
|
||||
}
|
||||
|
||||
break;
|
||||
case "NFTBridge":
|
||||
}
|
||||
case "NFTBridge": {
|
||||
contract = contract ?? CONTRACTS[network][chain]["nft_bridge"];
|
||||
if (contract === undefined) {
|
||||
throw Error("nft bridge contract is undefined");
|
||||
}
|
||||
|
||||
switch (payload.type) {
|
||||
case "ContractUpgrade":
|
||||
console.log("Upgrading contract");
|
||||
|
@ -103,12 +108,15 @@ export async function execute_aptos(
|
|||
default:
|
||||
impossible(payload);
|
||||
}
|
||||
|
||||
break;
|
||||
case "TokenBridge":
|
||||
}
|
||||
case "TokenBridge": {
|
||||
contract = contract ?? CONTRACTS[network][chain]["token_bridge"];
|
||||
if (contract === undefined) {
|
||||
throw Error("token bridge contract is undefined");
|
||||
}
|
||||
|
||||
switch (payload.type) {
|
||||
case "ContractUpgrade":
|
||||
console.log("Upgrading contract");
|
||||
|
@ -215,9 +223,10 @@ export async function execute_aptos(
|
|||
throw Error("Can't complete payload 3 transfer from CLI");
|
||||
default:
|
||||
impossible(payload);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
impossible(payload);
|
||||
}
|
||||
|
@ -250,7 +259,7 @@ export function deriveWrappedAssetAddress(
|
|||
export function deriveResourceAccount(
|
||||
deployer: Uint8Array, // 32 bytes
|
||||
seed: string
|
||||
) {
|
||||
): string {
|
||||
// from https://github.com/aptos-labs/aptos-core/blob/25696fd266498d81d346fe86e01c330705a71465/aptos-move/framework/aptos-framework/sources/account.move#L90-L95
|
||||
let DERIVE_RESOURCE_ACCOUNT_SCHEME = Buffer.alloc(1);
|
||||
DERIVE_RESOURCE_ACCOUNT_SCHEME.writeUInt8(255);
|
||||
|
@ -270,7 +279,7 @@ export async function callEntryFunc(
|
|||
func: string,
|
||||
ty_args: BCS.Seq<TxnBuilderTypes.TypeTag>,
|
||||
args: BCS.Seq<BCS.Bytes>
|
||||
) {
|
||||
): Promise<string> {
|
||||
let key: string | undefined = NETWORKS[network]["aptos"].key;
|
||||
if (key === undefined) {
|
||||
throw new Error("No key for aptos");
|
||||
|
@ -310,6 +319,7 @@ export async function callEntryFunc(
|
|||
throw new Error(`Transaction failed: ${tx.vm_status}`);
|
||||
}
|
||||
});
|
||||
|
||||
// simulation successful... let's do it
|
||||
const bcsTxn = AptosClient.generateBCSTransaction(accountFrom, rawTxn);
|
||||
const transactionRes = await client.submitSignedBCSTransaction(bcsTxn);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { APTOS_DEPLOYER_ADDRESS_DEVNET } from "@certusone/wormhole-sdk";
|
||||
import {
|
||||
assertChain,
|
||||
CHAIN_ID_APTOS,
|
||||
|
@ -23,9 +24,11 @@ import {
|
|||
RPC_OPTIONS,
|
||||
} from "../consts";
|
||||
import { NETWORKS } from "../networks";
|
||||
import { runCommand, validator_args } from "../start-validator";
|
||||
import { runCommand, VALIDATOR_OPTIONS } from "../start-validator";
|
||||
import { assertNetwork, checkBinary, evm_address, hex } from "../utils";
|
||||
|
||||
const APTOS_NODE_URL = "http://0.0.0.0:8080/v1";
|
||||
const APTOS_FAUCET_URL = "http://0.0.0.0:8081";
|
||||
const README_URL =
|
||||
"https://github.com/wormhole-foundation/wormhole/blob/main/aptos/README.md";
|
||||
|
||||
|
@ -42,427 +45,410 @@ interface PackageBCS {
|
|||
|
||||
export const command = "aptos";
|
||||
export const desc = "Aptos utilities";
|
||||
export const builder = function (y: typeof yargs) {
|
||||
return (
|
||||
y
|
||||
// NOTE: there's no init-nft-bridge, because the native module initialiser
|
||||
// functionality has stabilised on mainnet, so we just use that one (which
|
||||
// gets called automatically)
|
||||
.command(
|
||||
"init-token-bridge",
|
||||
"Init token bridge contract",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS);
|
||||
},
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
const contract_address = evm_address(
|
||||
CONTRACTS[network].aptos.token_bridge
|
||||
);
|
||||
const rpc = argv.rpc ?? NETWORKS[network]["aptos"].rpc;
|
||||
await callEntryFunc(
|
||||
network,
|
||||
rpc,
|
||||
`${contract_address}::token_bridge`,
|
||||
"init",
|
||||
[],
|
||||
[]
|
||||
);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"init-wormhole",
|
||||
"Init Wormhole core contract",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS)
|
||||
.option("chain-id", {
|
||||
describe: "Chain id",
|
||||
type: "number",
|
||||
default: CHAIN_ID_APTOS,
|
||||
required: false,
|
||||
})
|
||||
.option("governance-chain-id", {
|
||||
describe: "Governance chain id",
|
||||
type: "number",
|
||||
default: GOVERNANCE_CHAIN,
|
||||
required: false,
|
||||
})
|
||||
.option("governance-address", {
|
||||
describe: "Governance address",
|
||||
type: "string",
|
||||
default: GOVERNANCE_EMITTER,
|
||||
required: false,
|
||||
})
|
||||
.option("guardian-address", {
|
||||
alias: "g",
|
||||
required: true,
|
||||
describe: "Initial guardian's addresses (CSV)",
|
||||
type: "string",
|
||||
});
|
||||
},
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
export const builder = (y: typeof yargs) =>
|
||||
y
|
||||
// NOTE: there's no init-nft-bridge, because the native module initialiser
|
||||
// functionality has stabilised on mainnet, so we just use that one (which
|
||||
// gets called automatically)
|
||||
.command(
|
||||
"init-token-bridge",
|
||||
"Init token bridge contract",
|
||||
(yargs) =>
|
||||
yargs.option("network", NETWORK_OPTIONS).option("rpc", RPC_OPTIONS),
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
const contract_address = evm_address(
|
||||
CONTRACTS[network].aptos.token_bridge
|
||||
);
|
||||
const rpc = argv.rpc ?? NETWORKS[network]["aptos"].rpc;
|
||||
await callEntryFunc(
|
||||
network,
|
||||
rpc,
|
||||
`${contract_address}::token_bridge`,
|
||||
"init",
|
||||
[],
|
||||
[]
|
||||
);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"init-wormhole",
|
||||
"Init Wormhole core contract",
|
||||
(yargs) =>
|
||||
yargs
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS)
|
||||
.option("chain-id", {
|
||||
describe: "Chain id",
|
||||
type: "number",
|
||||
default: CHAIN_ID_APTOS,
|
||||
demandOption: false,
|
||||
})
|
||||
.option("governance-chain-id", {
|
||||
describe: "Governance chain id",
|
||||
type: "number",
|
||||
default: GOVERNANCE_CHAIN,
|
||||
demandOption: false,
|
||||
})
|
||||
.option("governance-address", {
|
||||
describe: "Governance address",
|
||||
type: "string",
|
||||
default: GOVERNANCE_EMITTER,
|
||||
demandOption: false,
|
||||
})
|
||||
.option("guardian-address", {
|
||||
alias: "g",
|
||||
demandOption: true,
|
||||
describe: "Initial guardian's addresses (CSV)",
|
||||
type: "string",
|
||||
}),
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
|
||||
const contract_address = evm_address(CONTRACTS[network].aptos.core);
|
||||
const guardian_addresses = argv["guardian-address"]
|
||||
.split(",")
|
||||
.map((address) => evm_address(address).substring(24));
|
||||
const chain_id = argv["chain-id"];
|
||||
const governance_address = evm_address(argv["governance-address"]);
|
||||
const governance_chain_id = argv["governance-chain-id"];
|
||||
const contract_address = evm_address(CONTRACTS[network].aptos.core);
|
||||
const guardian_addresses = argv["guardian-address"]
|
||||
.split(",")
|
||||
.map((address) => evm_address(address).substring(24));
|
||||
const chain_id = argv["chain-id"];
|
||||
const governance_address = evm_address(argv["governance-address"]);
|
||||
const governance_chain_id = argv["governance-chain-id"];
|
||||
|
||||
const guardians_serializer = new BCS.Serializer();
|
||||
guardians_serializer.serializeU32AsUleb128(guardian_addresses.length);
|
||||
guardian_addresses.forEach((address) =>
|
||||
guardians_serializer.serializeBytes(Buffer.from(address, "hex"))
|
||||
);
|
||||
const guardians_serializer = new BCS.Serializer();
|
||||
guardians_serializer.serializeU32AsUleb128(guardian_addresses.length);
|
||||
guardian_addresses.forEach((address) =>
|
||||
guardians_serializer.serializeBytes(Buffer.from(address, "hex"))
|
||||
);
|
||||
|
||||
const args = [
|
||||
BCS.bcsSerializeUint64(chain_id),
|
||||
BCS.bcsSerializeUint64(governance_chain_id),
|
||||
BCS.bcsSerializeBytes(Buffer.from(governance_address, "hex")),
|
||||
guardians_serializer.getBytes(),
|
||||
];
|
||||
const rpc = argv.rpc ?? NETWORKS[network]["aptos"].rpc;
|
||||
await callEntryFunc(
|
||||
network,
|
||||
rpc,
|
||||
`${contract_address}::wormhole`,
|
||||
"init",
|
||||
[],
|
||||
args
|
||||
);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"deploy <package-dir>",
|
||||
"Deploy an Aptos package",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
.positional("package-dir", {
|
||||
type: "string",
|
||||
})
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS)
|
||||
.option("named-addresses", NAMED_ADDRESSES_OPTIONS);
|
||||
},
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
checkBinary("aptos", README_URL);
|
||||
const p = buildPackage(argv["package-dir"], argv["named-addresses"]);
|
||||
const b = serializePackage(p);
|
||||
const rpc = argv.rpc ?? NETWORKS[network]["aptos"].rpc;
|
||||
await callEntryFunc(
|
||||
network,
|
||||
rpc,
|
||||
"0x1::code",
|
||||
"publish_package_txn",
|
||||
[],
|
||||
[b.meta, b.bytecodes]
|
||||
);
|
||||
console.log("Deployed:", p.mv_files);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"deploy-resource <seed> <package-dir>",
|
||||
"Deploy an Aptos package using a resource account",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
.positional("seed", {
|
||||
type: "string",
|
||||
})
|
||||
.positional("package-dir", {
|
||||
type: "string",
|
||||
})
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS)
|
||||
.option("named-addresses", NAMED_ADDRESSES_OPTIONS);
|
||||
},
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
checkBinary("aptos", README_URL);
|
||||
const p = buildPackage(argv["package-dir"], argv["named-addresses"]);
|
||||
const b = serializePackage(p);
|
||||
const seed = Buffer.from(argv["seed"], "ascii");
|
||||
const args = [
|
||||
BCS.bcsSerializeUint64(chain_id),
|
||||
BCS.bcsSerializeUint64(governance_chain_id),
|
||||
BCS.bcsSerializeBytes(Buffer.from(governance_address, "hex")),
|
||||
guardians_serializer.getBytes(),
|
||||
];
|
||||
const rpc = argv.rpc ?? NETWORKS[network]["aptos"].rpc;
|
||||
await callEntryFunc(
|
||||
network,
|
||||
rpc,
|
||||
`${contract_address}::wormhole`,
|
||||
"init",
|
||||
[],
|
||||
args
|
||||
);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"deploy <package-dir>",
|
||||
"Deploy an Aptos package",
|
||||
(yargs) =>
|
||||
yargs
|
||||
.positional("package-dir", {
|
||||
type: "string",
|
||||
describe: "Path to package directory",
|
||||
demandOption: true,
|
||||
})
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS)
|
||||
.option("named-addresses", NAMED_ADDRESSES_OPTIONS),
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
checkBinary("aptos", README_URL);
|
||||
const p = buildPackage(argv["package-dir"], argv["named-addresses"]);
|
||||
const b = serializePackage(p);
|
||||
const rpc = argv.rpc ?? NETWORKS[network]["aptos"].rpc;
|
||||
await callEntryFunc(
|
||||
network,
|
||||
rpc,
|
||||
"0x1::code",
|
||||
"publish_package_txn",
|
||||
[],
|
||||
[b.meta, b.bytecodes]
|
||||
);
|
||||
console.log("Deployed:", p.mv_files);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"deploy-resource <seed> <package-dir>",
|
||||
"Deploy an Aptos package using a resource account",
|
||||
(yargs) =>
|
||||
yargs
|
||||
.positional("seed", {
|
||||
type: "string",
|
||||
describe: "Seed for resource account",
|
||||
demandOption: true,
|
||||
})
|
||||
.positional("package-dir", {
|
||||
type: "string",
|
||||
describe: "Path to package directory",
|
||||
demandOption: true,
|
||||
})
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS)
|
||||
.option("named-addresses", NAMED_ADDRESSES_OPTIONS),
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
checkBinary("aptos", README_URL);
|
||||
const p = buildPackage(argv["package-dir"], argv["named-addresses"]);
|
||||
const b = serializePackage(p);
|
||||
const seed = Buffer.from(argv["seed"], "ascii");
|
||||
|
||||
// TODO(csongor): use deployer address from sdk (when it's there)
|
||||
let module_name =
|
||||
"0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b::deployer";
|
||||
if (network == "TESTNET" || network == "MAINNET") {
|
||||
module_name =
|
||||
"0x0108bc32f7de18a5f6e1e7d6ee7aff9f5fc858d0d87ac0da94dd8d2a5d267d6b::deployer";
|
||||
}
|
||||
const rpc = argv.rpc ?? NETWORKS[network]["aptos"].rpc;
|
||||
await callEntryFunc(
|
||||
network,
|
||||
rpc,
|
||||
module_name,
|
||||
"deploy_derived",
|
||||
[],
|
||||
[b.meta, b.bytecodes, BCS.bcsSerializeBytes(seed)]
|
||||
);
|
||||
console.log("Deployed:", p.mv_files);
|
||||
// TODO(csongor): use deployer address from sdk (when it's there)
|
||||
let module_name =
|
||||
"0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b::deployer";
|
||||
if (network == "TESTNET" || network == "MAINNET") {
|
||||
module_name =
|
||||
"0x0108bc32f7de18a5f6e1e7d6ee7aff9f5fc858d0d87ac0da94dd8d2a5d267d6b::deployer";
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"send-example-message <message>",
|
||||
"Send example message",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
.positional("message", {
|
||||
type: "string",
|
||||
})
|
||||
.option("network", NETWORK_OPTIONS);
|
||||
},
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
const rpc = NETWORKS[network]["aptos"].rpc;
|
||||
// TODO(csongor): use sdk address
|
||||
let module_name =
|
||||
"0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b::sender";
|
||||
if (network == "TESTNET" || network == "MAINNET") {
|
||||
module_name =
|
||||
"0x0108bc32f7de18a5f6e1e7d6ee7aff9f5fc858d0d87ac0da94dd8d2a5d267d6b::sender";
|
||||
}
|
||||
await callEntryFunc(
|
||||
network,
|
||||
rpc,
|
||||
module_name,
|
||||
"send_message",
|
||||
[],
|
||||
[BCS.bcsSerializeBytes(Buffer.from(argv["message"], "ascii"))]
|
||||
);
|
||||
const rpc = argv.rpc ?? NETWORKS[network]["aptos"].rpc;
|
||||
await callEntryFunc(
|
||||
network,
|
||||
rpc,
|
||||
module_name,
|
||||
"deploy_derived",
|
||||
[],
|
||||
[b.meta, b.bytecodes, BCS.bcsSerializeBytes(seed)]
|
||||
);
|
||||
console.log("Deployed:", p.mv_files);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"send-example-message <message>",
|
||||
"Send example message",
|
||||
(yargs) =>
|
||||
yargs
|
||||
.positional("message", {
|
||||
type: "string",
|
||||
describe: "Message to send",
|
||||
demandOption: true,
|
||||
})
|
||||
.option("network", NETWORK_OPTIONS),
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
const rpc = NETWORKS[network]["aptos"].rpc;
|
||||
// TODO(csongor): use sdk address
|
||||
let module_name =
|
||||
"0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b::sender";
|
||||
if (network == "TESTNET" || network == "MAINNET") {
|
||||
module_name =
|
||||
"0x0108bc32f7de18a5f6e1e7d6ee7aff9f5fc858d0d87ac0da94dd8d2a5d267d6b::sender";
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"derive-resource-account <account> <seed>",
|
||||
"Derive resource account address",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
.positional("account", {
|
||||
type: "string",
|
||||
})
|
||||
.positional("seed", {
|
||||
type: "string",
|
||||
});
|
||||
},
|
||||
async (argv) => {
|
||||
console.log(
|
||||
deriveResourceAccount(
|
||||
Buffer.from(hex(argv["account"]).substring(2), "hex"),
|
||||
argv["seed"]
|
||||
)
|
||||
);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"derive-wrapped-address <chain> <origin-address>",
|
||||
"Derive wrapped coin type",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
.positional("chain", {
|
||||
type: "string",
|
||||
})
|
||||
.positional("origin-address", {
|
||||
type: "string",
|
||||
})
|
||||
.option("network", NETWORK_OPTIONS);
|
||||
},
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
let address = CONTRACTS[network].aptos.token_bridge;
|
||||
if (address.startsWith("0x")) address = address.substring(2);
|
||||
const token_bridge_address = Buffer.from(address, "hex");
|
||||
assertChain(argv["chain"]);
|
||||
const chain = coalesceChainId(argv["chain"]);
|
||||
const origin_address = Buffer.from(
|
||||
evm_address(argv["origin-address"]),
|
||||
"hex"
|
||||
);
|
||||
console.log(
|
||||
deriveWrappedAssetAddress(
|
||||
token_bridge_address,
|
||||
chain,
|
||||
origin_address
|
||||
)
|
||||
);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"hash-contracts <package-dir>",
|
||||
"Hash contract bytecodes for upgrade",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
.positional("seed", {
|
||||
type: "string",
|
||||
})
|
||||
.positional("package-dir", {
|
||||
type: "string",
|
||||
})
|
||||
.option("named-addresses", NAMED_ADDRESSES_OPTIONS);
|
||||
},
|
||||
(argv) => {
|
||||
checkBinary("aptos", README_URL);
|
||||
const p = buildPackage(argv["package-dir"], argv["named-addresses"]);
|
||||
const b = serializePackage(p);
|
||||
console.log(Buffer.from(b.codeHash).toString("hex"));
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"upgrade <package-dir>",
|
||||
"Perform upgrade after VAA has been submitted",
|
||||
(_yargs) => {
|
||||
return (
|
||||
yargs
|
||||
.positional("package-dir", {
|
||||
type: "string",
|
||||
})
|
||||
// TODO(csongor): once the sdk has the addresses, just look that up
|
||||
// based on the module
|
||||
.option("contract-address", {
|
||||
alias: "a",
|
||||
required: true,
|
||||
describe: "Address where the wormhole module is deployed",
|
||||
type: "string",
|
||||
})
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS)
|
||||
.option("named-addresses", NAMED_ADDRESSES_OPTIONS)
|
||||
);
|
||||
},
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
checkBinary("aptos", README_URL);
|
||||
const p = buildPackage(argv["package-dir"], argv["named-addresses"]);
|
||||
const b = serializePackage(p);
|
||||
const rpc = argv.rpc ?? NETWORKS[network]["aptos"].rpc;
|
||||
// TODO(csongor): use deployer address from sdk (when it's there)
|
||||
const hash = await callEntryFunc(
|
||||
network,
|
||||
rpc,
|
||||
`${argv["contract-address"]}::contract_upgrade`,
|
||||
"upgrade",
|
||||
[],
|
||||
[b.meta, b.bytecodes]
|
||||
);
|
||||
console.log("Deployed:", p.mv_files);
|
||||
console.log(hash);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"migrate",
|
||||
"Perform migration after contract upgrade",
|
||||
(_yargs) => {
|
||||
return (
|
||||
yargs
|
||||
// TODO(csongor): once the sdk has the addresses, just look that up
|
||||
// based on the module
|
||||
.option("contract-address", {
|
||||
alias: "a",
|
||||
required: true,
|
||||
describe: "Address where the wormhole module is deployed",
|
||||
type: "string",
|
||||
})
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS)
|
||||
);
|
||||
},
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
checkBinary("aptos", README_URL);
|
||||
const rpc = argv.rpc ?? NETWORKS[network]["aptos"].rpc;
|
||||
// TODO(csongor): use deployer address from sdk (when it's there)
|
||||
const hash = await callEntryFunc(
|
||||
network,
|
||||
rpc,
|
||||
`${argv["contract-address"]}::contract_upgrade`,
|
||||
"migrate",
|
||||
[],
|
||||
[]
|
||||
);
|
||||
console.log(hash);
|
||||
}
|
||||
)
|
||||
// TODO - make faucet support testnet in additional to localnet
|
||||
.command(
|
||||
"faucet",
|
||||
"Request money from the faucet for a given account",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
.option("rpc", RPC_OPTIONS)
|
||||
.option("faucet", {
|
||||
alias: "f",
|
||||
required: false,
|
||||
describe: "Faucet url",
|
||||
type: "string",
|
||||
})
|
||||
.option("amount", {
|
||||
alias: "m",
|
||||
required: false,
|
||||
describe: "Amount to request",
|
||||
type: "number",
|
||||
})
|
||||
.option("account", {
|
||||
alias: "a",
|
||||
required: false,
|
||||
describe: "Account to fund",
|
||||
type: "string",
|
||||
});
|
||||
},
|
||||
async (argv) => {
|
||||
let NODE_URL = "http://0.0.0.0:8080/v1";
|
||||
let FAUCET_URL = "http://0.0.0.0:8081";
|
||||
let account =
|
||||
"0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b";
|
||||
let amount = 40000000;
|
||||
await callEntryFunc(
|
||||
network,
|
||||
rpc,
|
||||
module_name,
|
||||
"send_message",
|
||||
[],
|
||||
[BCS.bcsSerializeBytes(Buffer.from(argv["message"], "ascii"))]
|
||||
);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"derive-resource-account <account> <seed>",
|
||||
"Derive resource account address",
|
||||
(yargs) =>
|
||||
yargs
|
||||
.positional("account", {
|
||||
type: "string",
|
||||
describe: "Account address",
|
||||
demandOption: true,
|
||||
})
|
||||
.positional("seed", {
|
||||
type: "string",
|
||||
describe: "Seed for resource account",
|
||||
demandOption: true,
|
||||
}),
|
||||
async (argv) => {
|
||||
console.log(
|
||||
deriveResourceAccount(
|
||||
Buffer.from(hex(argv["account"]).substring(2), "hex"),
|
||||
argv["seed"]
|
||||
)
|
||||
);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"derive-wrapped-address <chain> <origin-address>",
|
||||
"Derive wrapped coin type",
|
||||
(yargs) =>
|
||||
yargs
|
||||
.positional("chain", {
|
||||
type: "string",
|
||||
describe: "Origin chain name",
|
||||
demandOption: true,
|
||||
})
|
||||
.positional("origin-address", {
|
||||
type: "string",
|
||||
describe: "Address on origin chain",
|
||||
demandOption: true,
|
||||
})
|
||||
.option("network", NETWORK_OPTIONS),
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
let address = CONTRACTS[network].aptos.token_bridge;
|
||||
if (address.startsWith("0x")) address = address.substring(2);
|
||||
const token_bridge_address = Buffer.from(address, "hex");
|
||||
assertChain(argv["chain"]);
|
||||
const chain = coalesceChainId(argv["chain"]);
|
||||
const origin_address = Buffer.from(
|
||||
evm_address(argv["origin-address"]),
|
||||
"hex"
|
||||
);
|
||||
console.log(
|
||||
deriveWrappedAssetAddress(token_bridge_address, chain, origin_address)
|
||||
);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"hash-contracts <package-dir>",
|
||||
"Hash contract bytecodes for upgrade",
|
||||
(yargs) =>
|
||||
yargs
|
||||
.positional("package-dir", {
|
||||
type: "string",
|
||||
describe: "Path to package directory",
|
||||
demandOption: true,
|
||||
})
|
||||
.option("named-addresses", NAMED_ADDRESSES_OPTIONS),
|
||||
(argv) => {
|
||||
checkBinary("aptos", README_URL);
|
||||
const p = buildPackage(argv["package-dir"], argv["named-addresses"]);
|
||||
const b = serializePackage(p);
|
||||
console.log(Buffer.from(b.codeHash).toString("hex"));
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"upgrade <package-dir>",
|
||||
"Perform upgrade after VAA has been submitted",
|
||||
(_yargs) =>
|
||||
yargs
|
||||
.positional("package-dir", {
|
||||
type: "string",
|
||||
describe: "Path to package directory",
|
||||
demandOption: true,
|
||||
})
|
||||
// TODO(csongor): once the sdk has the addresses, just look that up
|
||||
// based on the module
|
||||
.option("contract-address", {
|
||||
alias: "a",
|
||||
demandOption: true,
|
||||
describe: "Address where the wormhole module is deployed",
|
||||
type: "string",
|
||||
})
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS)
|
||||
.option("named-addresses", NAMED_ADDRESSES_OPTIONS),
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
checkBinary("aptos", README_URL);
|
||||
const p = buildPackage(argv["package-dir"], argv["named-addresses"]);
|
||||
const b = serializePackage(p);
|
||||
const rpc = argv.rpc ?? NETWORKS[network]["aptos"].rpc;
|
||||
// TODO(csongor): use deployer address from sdk (when it's there)
|
||||
const hash = await callEntryFunc(
|
||||
network,
|
||||
rpc,
|
||||
`${argv["contract-address"]}::contract_upgrade`,
|
||||
"upgrade",
|
||||
[],
|
||||
[b.meta, b.bytecodes]
|
||||
);
|
||||
console.log("Deployed:", p.mv_files);
|
||||
console.log(hash);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"migrate",
|
||||
"Perform migration after contract upgrade",
|
||||
(_yargs) =>
|
||||
yargs
|
||||
// TODO(csongor): once the sdk has the addresses, just look that up
|
||||
// based on the module
|
||||
.option("contract-address", {
|
||||
alias: "a",
|
||||
demandOption: true,
|
||||
describe: "Address where the wormhole module is deployed",
|
||||
type: "string",
|
||||
})
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS),
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
checkBinary("aptos", README_URL);
|
||||
const rpc = argv.rpc ?? NETWORKS[network]["aptos"].rpc;
|
||||
// TODO(csongor): use deployer address from sdk (when it's there)
|
||||
const hash = await callEntryFunc(
|
||||
network,
|
||||
rpc,
|
||||
`${argv["contract-address"]}::contract_upgrade`,
|
||||
"migrate",
|
||||
[],
|
||||
[]
|
||||
);
|
||||
console.log(hash);
|
||||
}
|
||||
)
|
||||
// TODO - make faucet support testnet in additional to localnet
|
||||
.command(
|
||||
"faucet",
|
||||
"Request money from the faucet for a given account",
|
||||
(_yargs) =>
|
||||
yargs
|
||||
.option("rpc", {
|
||||
alias: "r",
|
||||
describe: "Override default rpc endpoint url",
|
||||
type: "string",
|
||||
demandOption: false,
|
||||
default: APTOS_NODE_URL,
|
||||
})
|
||||
.option("faucet", {
|
||||
alias: "f",
|
||||
demandOption: false,
|
||||
describe: "Faucet url",
|
||||
type: "string",
|
||||
default: APTOS_FAUCET_URL,
|
||||
})
|
||||
.option("amount", {
|
||||
alias: "m",
|
||||
demandOption: false,
|
||||
describe: "Amount to request",
|
||||
type: "number",
|
||||
default: 40000000,
|
||||
})
|
||||
.option("account", {
|
||||
alias: "a",
|
||||
demandOption: false,
|
||||
describe: "Account to fund",
|
||||
type: "string",
|
||||
default: APTOS_DEPLOYER_ADDRESS_DEVNET,
|
||||
}),
|
||||
async (argv) => {
|
||||
const faucetClient = new FaucetClient(argv.rpc, argv.faucet);
|
||||
await faucetClient.fundAccount(argv.account, argv.amount);
|
||||
console.log(`Funded ${argv.account} with ${argv.amount} coins`);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"start-validator",
|
||||
"Start a local aptos validator",
|
||||
(yargs) => yargs.option("validator-args", VALIDATOR_OPTIONS),
|
||||
(argv) => {
|
||||
checkBinary("aptos", README_URL);
|
||||
const cmd = `cd ${homedir()} && aptos node run-local-testnet --with-faucet --force-restart --assume-yes`;
|
||||
runCommand(cmd, argv["validator-args"]);
|
||||
}
|
||||
)
|
||||
.strict()
|
||||
.demandCommand();
|
||||
export const handler = () => {};
|
||||
|
||||
if (argv.faucet != undefined) {
|
||||
FAUCET_URL = argv.faucet as string;
|
||||
}
|
||||
if (argv.rpc != undefined) {
|
||||
NODE_URL = argv.rpc as string;
|
||||
}
|
||||
if (argv.amount != undefined) {
|
||||
amount = argv.amount as number;
|
||||
}
|
||||
if (argv.account != undefined) {
|
||||
account = argv.account as string;
|
||||
}
|
||||
const faucetClient = new FaucetClient(NODE_URL, FAUCET_URL);
|
||||
await faucetClient.fundAccount(account, amount);
|
||||
console.log(`Funded ${account} with ${amount} coins`);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"start-validator",
|
||||
"Start a local aptos validator",
|
||||
(yargs) => {
|
||||
return yargs.option("validator-args", validator_args);
|
||||
},
|
||||
(argv) => {
|
||||
checkBinary("aptos", README_URL);
|
||||
const cmd = `cd ${homedir()} && aptos node run-local-testnet --with-faucet --force-restart --assume-yes`;
|
||||
runCommand(cmd, argv["validator-args"]);
|
||||
}
|
||||
)
|
||||
.strict()
|
||||
.demandCommand()
|
||||
);
|
||||
};
|
||||
|
||||
function buildPackage(dir: string, addrs?: string): Package {
|
||||
const buildPackage = (dir: string, addrs?: string): Package => {
|
||||
const named_addresses = addrs ? ["--named-addresses", addrs] : [];
|
||||
const aptos = spawnSync("aptos", [
|
||||
"move",
|
||||
|
@ -498,9 +484,9 @@ function buildPackage(dir: string, addrs?: string): Package {
|
|||
(mod: string) => `${buildDir}/bytecode_modules/${mod.split("::")[1]}.mv`
|
||||
),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function serializePackage(p: Package): PackageBCS {
|
||||
const serializePackage = (p: Package): PackageBCS => {
|
||||
const metaBytes = fs.readFileSync(p.meta_file);
|
||||
const packageMetadataSerializer = new BCS.Serializer();
|
||||
packageMetadataSerializer.serializeBytes(metaBytes);
|
||||
|
@ -522,6 +508,4 @@ function serializePackage(p: Package): PackageBCS {
|
|||
bytecodes: serializedModules,
|
||||
codeHash,
|
||||
};
|
||||
}
|
||||
|
||||
export const handler = (argv) => {};
|
||||
};
|
||||
|
|
|
@ -13,9 +13,10 @@ export const builder = (y: typeof yargs) => {
|
|||
describe: "Chain to query",
|
||||
type: "string",
|
||||
choices: Object.keys(CHAINS),
|
||||
});
|
||||
demandOption: true,
|
||||
} as const);
|
||||
};
|
||||
export const handler = (argv) => {
|
||||
export const handler = (argv: Awaited<ReturnType<typeof builder>["argv"]>) => {
|
||||
assertChain(argv["chain"]);
|
||||
console.log(coalesceChainId(argv["chain"]));
|
||||
};
|
||||
|
|
|
@ -5,59 +5,70 @@ import {
|
|||
import yargs from "yargs";
|
||||
import { CONTRACTS } from "../consts";
|
||||
import { getEmitterAddress } from "../emitter";
|
||||
import { assertNetwork } from "../utils";
|
||||
import { impossible } from "../vaa";
|
||||
|
||||
export const command = "contract <network> <chain> <module>";
|
||||
export const desc = "Print contract address";
|
||||
export const builder = (y: typeof yargs) => {
|
||||
return y
|
||||
export const builder = (y: typeof yargs) =>
|
||||
y
|
||||
.positional("network", {
|
||||
describe: "network",
|
||||
type: "string",
|
||||
describe: "Network",
|
||||
choices: ["mainnet", "testnet", "devnet"],
|
||||
})
|
||||
demandOption: true,
|
||||
} as const)
|
||||
.positional("chain", {
|
||||
describe: "Chain to query",
|
||||
type: "string",
|
||||
choices: Object.keys(CHAINS),
|
||||
})
|
||||
demandOption: true,
|
||||
} as const)
|
||||
.positional("module", {
|
||||
describe: "Module to query",
|
||||
type: "string",
|
||||
choices: ["Core", "NFTBridge", "TokenBridge"],
|
||||
})
|
||||
demandOption: true,
|
||||
} as const)
|
||||
.option("emitter", {
|
||||
alias: "e",
|
||||
describe: "Print in emitter address format",
|
||||
type: "boolean",
|
||||
default: false,
|
||||
required: false,
|
||||
demandOption: false,
|
||||
});
|
||||
};
|
||||
export const handler = async (argv) => {
|
||||
export const handler = async (
|
||||
argv: Awaited<ReturnType<typeof builder>["argv"]>
|
||||
) => {
|
||||
assertChain(argv["chain"]);
|
||||
const network = argv.network.toUpperCase();
|
||||
if (network !== "MAINNET" && network !== "TESTNET" && network !== "DEVNET") {
|
||||
throw Error(`Unknown network: ${network}`);
|
||||
}
|
||||
let chain = argv["chain"];
|
||||
let module = argv["module"] as "Core" | "NFTBridge" | "TokenBridge";
|
||||
let addr = "";
|
||||
assertNetwork(network);
|
||||
const chain = argv["chain"];
|
||||
const module = argv["module"];
|
||||
let addr: string | undefined;
|
||||
switch (module) {
|
||||
case "Core":
|
||||
addr = CONTRACTS[network][chain]["core"];
|
||||
addr = CONTRACTS[network][chain].core;
|
||||
break;
|
||||
case "NFTBridge":
|
||||
addr = CONTRACTS[network][chain]["nft_bridge"];
|
||||
const addresses = CONTRACTS[network][chain];
|
||||
if (!("nft_bridge" in addresses)) {
|
||||
throw new Error(`NFTBridge not deployed on ${chain}`);
|
||||
}
|
||||
|
||||
addr = addresses.nft_bridge;
|
||||
break;
|
||||
case "TokenBridge":
|
||||
addr = CONTRACTS[network][chain]["token_bridge"];
|
||||
addr = CONTRACTS[network][chain].token_bridge;
|
||||
break;
|
||||
default:
|
||||
impossible(module);
|
||||
}
|
||||
|
||||
if (!addr) {
|
||||
throw new Error(`${module} not deployed on ${chain}`);
|
||||
}
|
||||
|
||||
if (argv["emitter"]) {
|
||||
addr = await getEmitterAddress(chain, addr);
|
||||
}
|
||||
|
||||
console.log(addr);
|
||||
};
|
||||
|
|
|
@ -1,26 +1,30 @@
|
|||
import yargs from "yargs";
|
||||
import {
|
||||
CHAINS,
|
||||
assertChain,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import yargs from "yargs";
|
||||
import { getEmitterAddress } from "../emitter";
|
||||
|
||||
export const command = "convert-to-emitter <chain> <address-to-convert>";
|
||||
export const desc = "Print address in emitter address format";
|
||||
export const builder = (y: typeof yargs) => {
|
||||
return y
|
||||
export const builder = (y: typeof yargs) =>
|
||||
y
|
||||
.positional("chain", {
|
||||
describe: "Chain to query",
|
||||
type: "string",
|
||||
choices: Object.keys(CHAINS),
|
||||
})
|
||||
demandOption: true,
|
||||
} as const)
|
||||
.positional("address-to-convert", {
|
||||
describe: "Address to be converted to emitter address format",
|
||||
type: "string",
|
||||
demandOption: true,
|
||||
});
|
||||
};
|
||||
export const handler = async (argv) => {
|
||||
export const handler = async (
|
||||
argv: Awaited<ReturnType<typeof builder>["argv"]>
|
||||
) => {
|
||||
assertChain(argv["chain"]);
|
||||
let chain = argv["chain"];
|
||||
console.log(await getEmitterAddress(chain, argv["address-to-convert"]));
|
||||
console.log(
|
||||
await getEmitterAddress(argv["chain"], argv["address-to-convert"])
|
||||
);
|
||||
};
|
||||
|
|
|
@ -23,23 +23,25 @@ import axios from "axios";
|
|||
import { ethers } from "ethers";
|
||||
import yargs from "yargs";
|
||||
import { NETWORKS } from "../networks";
|
||||
import { assertNetwork, Network } from "../utils";
|
||||
import { parse, Payload, serialiseVAA, sign, Signature, VAA } from "../vaa";
|
||||
|
||||
export const command = "edit-vaa";
|
||||
export const desc = "Edits or generates a VAA";
|
||||
export const builder = (y: typeof yargs) => {
|
||||
return y
|
||||
export const builder = (y: typeof yargs) =>
|
||||
y
|
||||
.option("vaa", {
|
||||
alias: "v",
|
||||
describe: "vaa in hex format",
|
||||
type: "string",
|
||||
demandOption: true,
|
||||
})
|
||||
.option("network", {
|
||||
alias: "n",
|
||||
describe: "network",
|
||||
type: "string",
|
||||
choices: ["mainnet", "testnet", "devnet"],
|
||||
})
|
||||
demandOption: true,
|
||||
} as const)
|
||||
.option("guardian-set-index", {
|
||||
alias: "gsi",
|
||||
describe: "guardian set index",
|
||||
|
@ -65,7 +67,7 @@ export const builder = (y: typeof yargs) => {
|
|||
alias: "ec",
|
||||
describe: "emitter chain id to be used in the vaa",
|
||||
type: "number",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
})
|
||||
.option("emitter-address", {
|
||||
alias: "ea",
|
||||
|
@ -102,21 +104,29 @@ export const builder = (y: typeof yargs) => {
|
|||
describe: "Guardian's secret key",
|
||||
type: "string",
|
||||
});
|
||||
};
|
||||
export const handler = async (argv) => {
|
||||
export const handler = async (
|
||||
argv: Awaited<ReturnType<typeof builder>["argv"]>
|
||||
) => {
|
||||
const network = argv["network"].toUpperCase();
|
||||
assertNetwork(network);
|
||||
|
||||
let numSigs = 0;
|
||||
if (argv["signatures"]) {
|
||||
numSigs += 1;
|
||||
}
|
||||
|
||||
if (argv["wormscanfile"]) {
|
||||
numSigs += 1;
|
||||
}
|
||||
|
||||
if (argv["wormscanurl"]) {
|
||||
numSigs += 1;
|
||||
}
|
||||
|
||||
if (argv["guardian-secret"]) {
|
||||
numSigs += 1;
|
||||
}
|
||||
|
||||
if (numSigs > 1) {
|
||||
throw new Error(
|
||||
`may only specify one of "--signatures", "--wormscanfile", "--wormscanurl" or "--guardian-secret"`
|
||||
|
@ -161,20 +171,17 @@ export const handler = async (argv) => {
|
|||
}
|
||||
|
||||
if (argv["signatures"]) {
|
||||
vaa.signatures = argv["signatures"].split(",");
|
||||
vaa.signatures = argv["signatures"].split(",").map((s, i) => ({
|
||||
signature: s,
|
||||
guardianSetIndex: i,
|
||||
}));
|
||||
} else if (argv["wormscanfile"]) {
|
||||
const wormscanData = require(argv["wormscanfile"]);
|
||||
const guardianSet = await getGuardianSet(
|
||||
argv["network"],
|
||||
vaa.guardianSetIndex
|
||||
);
|
||||
const guardianSet = await getGuardianSet(network, vaa.guardianSetIndex);
|
||||
vaa.signatures = await getSigsFromWormscanData(wormscanData, guardianSet);
|
||||
} else if (argv["wormscanurl"]) {
|
||||
const wormscanData = await axios.get(argv["wormscanurl"]);
|
||||
const guardianSet = await getGuardianSet(
|
||||
argv["network"],
|
||||
vaa.guardianSetIndex
|
||||
);
|
||||
const guardianSet = await getGuardianSet(network, vaa.guardianSetIndex);
|
||||
vaa.signatures = await getSigsFromWormscanData(
|
||||
wormscanData.data,
|
||||
guardianSet
|
||||
|
@ -219,19 +226,10 @@ export const handler = async (argv) => {
|
|||
};
|
||||
|
||||
// getGuardianSet queries the core contract on Ethereum for the guardian set and returns it.
|
||||
async function getGuardianSet(
|
||||
nwork: string,
|
||||
const getGuardianSet = async (
|
||||
network: Network,
|
||||
guardianSetIndex: number
|
||||
): Promise<string[]> {
|
||||
if (!nwork) {
|
||||
throw Error(`"--network" is required to read guardian set`);
|
||||
}
|
||||
|
||||
const network = nwork.toUpperCase();
|
||||
if (network !== "MAINNET" && network !== "TESTNET" && network !== "DEVNET") {
|
||||
throw Error(`Unknown network: ${network}`);
|
||||
}
|
||||
|
||||
): Promise<string[]> => {
|
||||
let n = NETWORKS[network]["ethereum"];
|
||||
let contract_address = CONTRACTS[network]["ethereum"].core;
|
||||
if (contract_address === undefined) {
|
||||
|
@ -242,14 +240,14 @@ async function getGuardianSet(
|
|||
const contract = Implementation__factory.connect(contract_address, provider);
|
||||
const result = await contract.getGuardianSet(guardianSetIndex);
|
||||
return result[0];
|
||||
}
|
||||
};
|
||||
|
||||
// getSigsFromWormscanData reads the guardian address / signature pairs from the wormscan data
|
||||
// and generates an array of signature objects. It then sorts them into order by address.
|
||||
function getSigsFromWormscanData(
|
||||
const getSigsFromWormscanData = (
|
||||
wormscanData: any,
|
||||
guardianSet: string[]
|
||||
): any {
|
||||
): Signature[] => {
|
||||
let sigs: Signature[] = [];
|
||||
for (let data in wormscanData) {
|
||||
let guardianAddr = wormscanData[data].guardianAddr;
|
||||
|
@ -272,6 +270,7 @@ function getSigsFromWormscanData(
|
|||
|
||||
sigs.push(sig);
|
||||
}
|
||||
|
||||
return sigs.sort((s1, s2) => {
|
||||
if (s1.guardianSetIndex > s2.guardianSetIndex) {
|
||||
return 1;
|
||||
|
@ -283,4 +282,4 @@ function getSigsFromWormscanData(
|
|||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -16,8 +16,8 @@ import {
|
|||
setStorageAt,
|
||||
} from "../evm";
|
||||
import { NETWORKS } from "../networks";
|
||||
import { runCommand, validator_args } from "../start-validator";
|
||||
import { evm_address } from "../utils";
|
||||
import { runCommand, VALIDATOR_OPTIONS } from "../start-validator";
|
||||
import { assertNetwork, evm_address } from "../utils";
|
||||
|
||||
export const command = "evm";
|
||||
export const desc = "EVM utilities";
|
||||
|
@ -26,17 +26,17 @@ export const builder = function (y: typeof yargs) {
|
|||
.option("rpc", {
|
||||
describe: "RPC endpoint",
|
||||
type: "string",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
})
|
||||
.command(
|
||||
"address-from-secret <secret>",
|
||||
"Compute a 20 byte eth address from a 32 byte private key",
|
||||
(yargs) => {
|
||||
return yargs.positional("secret", {
|
||||
(yargs) =>
|
||||
yargs.positional("secret", {
|
||||
type: "string",
|
||||
describe: "Secret key (32 bytes)",
|
||||
});
|
||||
},
|
||||
demandOption: true,
|
||||
} as const),
|
||||
(argv) => {
|
||||
console.log(ethers.utils.computeAddress(argv["secret"]));
|
||||
}
|
||||
|
@ -44,28 +44,31 @@ export const builder = function (y: typeof yargs) {
|
|||
.command(
|
||||
"storage-update",
|
||||
"Update a storage slot on an EVM fork during testing (anvil or hardhat)",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
(yargs) =>
|
||||
yargs
|
||||
.option("contract-address", {
|
||||
alias: "a",
|
||||
describe: "Contract address",
|
||||
type: "string",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
})
|
||||
.option("storage-slot", {
|
||||
alias: "k",
|
||||
describe: "Storage slot to modify",
|
||||
type: "string",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
})
|
||||
.option("value", {
|
||||
alias: "v",
|
||||
describe: "Value to write into the slot (32 bytes)",
|
||||
type: "string",
|
||||
required: true,
|
||||
});
|
||||
},
|
||||
demandOption: true,
|
||||
}),
|
||||
async (argv) => {
|
||||
if (!argv["rpc"]) {
|
||||
throw new Error("RPC required");
|
||||
}
|
||||
|
||||
const result = await setStorageAt(
|
||||
argv["rpc"],
|
||||
evm_address(argv["contract-address"]),
|
||||
|
@ -87,56 +90,49 @@ export const builder = function (y: typeof yargs) {
|
|||
.command(
|
||||
"info",
|
||||
"Query info about the on-chain state of the contract",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
(yargs) =>
|
||||
yargs
|
||||
.option("chain", {
|
||||
alias: "c",
|
||||
describe: "Chain to query",
|
||||
type: "string",
|
||||
choices: Object.keys(CHAINS),
|
||||
required: true,
|
||||
demandOption: true,
|
||||
})
|
||||
.option("module", {
|
||||
alias: "m",
|
||||
describe: "Module to query",
|
||||
type: "string",
|
||||
choices: ["Core", "NFTBridge", "TokenBridge"],
|
||||
required: true,
|
||||
demandOption: true,
|
||||
})
|
||||
.option("network", {
|
||||
alias: "n",
|
||||
describe: "network",
|
||||
type: "string",
|
||||
choices: ["mainnet", "testnet", "devnet"],
|
||||
required: true,
|
||||
demandOption: true,
|
||||
})
|
||||
.option("contract-address", {
|
||||
alias: "a",
|
||||
describe: "Contract to query (override config)",
|
||||
type: "string",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
})
|
||||
.option("implementation-only", {
|
||||
alias: "i",
|
||||
describe: "Only query implementation (faster)",
|
||||
type: "boolean",
|
||||
default: false,
|
||||
required: false,
|
||||
});
|
||||
},
|
||||
demandOption: 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;
|
||||
assertNetwork(network);
|
||||
const module = argv["module"] as "Core" | "NFTBridge" | "TokenBridge";
|
||||
const rpc = argv["rpc"] ?? NETWORKS[network][argv["chain"]].rpc;
|
||||
if (argv["implementation-only"]) {
|
||||
console.log(
|
||||
await getImplementation(
|
||||
|
@ -167,8 +163,8 @@ export const builder = function (y: typeof yargs) {
|
|||
.command(
|
||||
"hijack",
|
||||
"Override the guardian set of the core bridge contract during testing (anvil or hardhat)",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
(yargs) =>
|
||||
yargs
|
||||
.option("core-contract-address", {
|
||||
alias: "a",
|
||||
describe: "Core contract address",
|
||||
|
@ -177,18 +173,17 @@ export const builder = function (y: typeof yargs) {
|
|||
})
|
||||
.option("guardian-address", {
|
||||
alias: "g",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
describe: "Guardians' public addresses (CSV)",
|
||||
type: "string",
|
||||
})
|
||||
.option("guardian-set-index", {
|
||||
alias: "i",
|
||||
required: false,
|
||||
demandOption: 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;
|
||||
|
@ -203,9 +198,7 @@ export const builder = function (y: typeof yargs) {
|
|||
.command(
|
||||
"start-validator",
|
||||
"Start a local EVM validator",
|
||||
(yargs) => {
|
||||
return yargs.option("validator-args", validator_args);
|
||||
},
|
||||
(yargs) => yargs.option("validator-args", VALIDATOR_OPTIONS),
|
||||
(argv) => {
|
||||
const cmd = `cd ${homedir()} && npx ganache-cli -e 10000 --deterministic --time="1970-01-01T00:00:00+00:00"`;
|
||||
runCommand(cmd, argv["validator-args"]);
|
||||
|
@ -214,5 +207,4 @@ export const builder = function (y: typeof yargs) {
|
|||
.strict()
|
||||
.demandCommand();
|
||||
};
|
||||
|
||||
export const handler = (argv) => {};
|
||||
export const handler = () => {};
|
||||
|
|
|
@ -54,7 +54,7 @@ export const builder = function (y: typeof yargs) {
|
|||
y
|
||||
.option("guardian-secret", {
|
||||
alias: "g",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
describe: "Guardians' secret keys (CSV)",
|
||||
type: "string",
|
||||
})
|
||||
|
@ -62,33 +62,30 @@ export const builder = function (y: typeof yargs) {
|
|||
.command(
|
||||
"registration",
|
||||
"Generate registration VAA",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
(yargs) =>
|
||||
yargs
|
||||
.option("chain", {
|
||||
alias: "c",
|
||||
describe: "Chain to register",
|
||||
type: "string",
|
||||
choices: Object.keys(CHAINS),
|
||||
required: true,
|
||||
})
|
||||
demandOption: true,
|
||||
} as const)
|
||||
.option("contract-address", {
|
||||
alias: "a",
|
||||
describe: "Contract to register",
|
||||
type: "string",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
})
|
||||
.option("module", {
|
||||
alias: "m",
|
||||
describe: "Module to upgrade",
|
||||
type: "string",
|
||||
choices: ["NFTBridge", "TokenBridge"],
|
||||
required: true,
|
||||
});
|
||||
},
|
||||
demandOption: true,
|
||||
} as const),
|
||||
(argv) => {
|
||||
let module = argv["module"] as "NFTBridge" | "TokenBridge";
|
||||
const module = argv["module"];
|
||||
assertChain(argv["chain"]);
|
||||
let payload: PortalRegisterChain<typeof module> = {
|
||||
const payload: PortalRegisterChain<typeof module> = {
|
||||
module,
|
||||
type: "RegisterChain",
|
||||
chain: 0,
|
||||
|
@ -98,115 +95,110 @@ export const builder = function (y: typeof yargs) {
|
|||
argv["contract-address"]
|
||||
),
|
||||
};
|
||||
let v = makeVAA(
|
||||
const vaa = makeVAA(
|
||||
GOVERNANCE_CHAIN,
|
||||
GOVERNANCE_EMITTER,
|
||||
argv["guardian-secret"].split(","),
|
||||
payload
|
||||
);
|
||||
console.log(serialiseVAA(v));
|
||||
console.log(serialiseVAA(vaa));
|
||||
}
|
||||
)
|
||||
// Upgrade
|
||||
.command(
|
||||
"upgrade",
|
||||
"Generate contract upgrade VAA",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
(yargs) =>
|
||||
yargs
|
||||
.option("chain", {
|
||||
alias: "c",
|
||||
describe: "Chain to upgrade",
|
||||
type: "string",
|
||||
choices: Object.keys(CHAINS),
|
||||
required: true,
|
||||
})
|
||||
demandOption: true,
|
||||
} as const)
|
||||
.option("contract-address", {
|
||||
alias: "a",
|
||||
describe: "Contract to upgrade to",
|
||||
type: "string",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
})
|
||||
.option("module", {
|
||||
alias: "m",
|
||||
describe: "Module to upgrade",
|
||||
type: "string",
|
||||
choices: ["Core", "NFTBridge", "TokenBridge"],
|
||||
required: true,
|
||||
});
|
||||
},
|
||||
demandOption: true,
|
||||
} as const),
|
||||
(argv) => {
|
||||
assertChain(argv["chain"]);
|
||||
let module = argv["module"] as "Core" | "NFTBridge" | "TokenBridge";
|
||||
let payload: ContractUpgrade = {
|
||||
const module = argv["module"];
|
||||
const payload: ContractUpgrade = {
|
||||
module,
|
||||
type: "ContractUpgrade",
|
||||
chain: toChainId(argv["chain"]),
|
||||
address: parseCodeAddress(argv["chain"], argv["contract-address"]),
|
||||
};
|
||||
let v = makeVAA(
|
||||
const vaa = makeVAA(
|
||||
GOVERNANCE_CHAIN,
|
||||
GOVERNANCE_EMITTER,
|
||||
argv["guardian-secret"].split(","),
|
||||
payload
|
||||
);
|
||||
console.log(serialiseVAA(v));
|
||||
console.log(serialiseVAA(vaa));
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"attestation",
|
||||
"Generate a token attestation VAA",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
(yargs) =>
|
||||
yargs
|
||||
.option("emitter-chain", {
|
||||
alias: "e",
|
||||
describe: "Emitter chain of the VAA",
|
||||
type: "string",
|
||||
choices: Object.keys(CHAINS),
|
||||
required: true,
|
||||
})
|
||||
demandOption: true,
|
||||
} as const)
|
||||
.option("emitter-address", {
|
||||
alias: "f",
|
||||
describe: "Emitter address of the VAA",
|
||||
type: "string",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
})
|
||||
.option("chain", {
|
||||
alias: "c",
|
||||
describe: "Token's chain",
|
||||
type: "string",
|
||||
choices: Object.keys(CHAINS),
|
||||
required: true,
|
||||
demandOption: true,
|
||||
})
|
||||
.option("token-address", {
|
||||
alias: "a",
|
||||
describe: "Token's address",
|
||||
type: "string",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
})
|
||||
.option("decimals", {
|
||||
alias: "d",
|
||||
describe: "Token's decimals",
|
||||
type: "number",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
})
|
||||
.option("symbol", {
|
||||
alias: "s",
|
||||
describe: "Token's symbol",
|
||||
type: "string",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
})
|
||||
.option("name", {
|
||||
alias: "n",
|
||||
describe: "Token's name",
|
||||
type: "string",
|
||||
required: true,
|
||||
});
|
||||
},
|
||||
demandOption: true,
|
||||
}),
|
||||
(argv) => {
|
||||
let emitter_chain = argv["emitter-chain"] as string;
|
||||
const emitter_chain = argv["emitter-chain"];
|
||||
assertChain(argv["chain"]);
|
||||
assertChain(emitter_chain);
|
||||
let payload: TokenBridgeAttestMeta = {
|
||||
const payload: TokenBridgeAttestMeta = {
|
||||
module: "TokenBridge",
|
||||
type: "AttestMeta",
|
||||
chain: 0,
|
||||
|
@ -216,60 +208,59 @@ export const builder = function (y: typeof yargs) {
|
|||
symbol: argv["symbol"],
|
||||
name: argv["name"],
|
||||
};
|
||||
let v = makeVAA(
|
||||
const vaa = makeVAA(
|
||||
toChainId(emitter_chain),
|
||||
parseAddress(emitter_chain, argv["emitter-address"] as string),
|
||||
parseAddress(emitter_chain, argv["emitter-address"]),
|
||||
argv["guardian-secret"].split(","),
|
||||
payload
|
||||
);
|
||||
console.log(serialiseVAA(v));
|
||||
console.log(serialiseVAA(vaa));
|
||||
}
|
||||
)
|
||||
// RecoverChainId
|
||||
.command(
|
||||
"recover-chain-id",
|
||||
"Generate a recover chain ID VAA",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
(yargs) =>
|
||||
yargs
|
||||
.option("module", {
|
||||
alias: "m",
|
||||
describe: "Module to upgrade",
|
||||
type: "string",
|
||||
choices: ["Core", "NFTBridge", "TokenBridge"],
|
||||
required: true,
|
||||
})
|
||||
demandOption: true,
|
||||
} as const)
|
||||
.option("evm-chain-id", {
|
||||
alias: "e",
|
||||
describe: "EVM chain ID to set",
|
||||
type: "string",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
})
|
||||
.option("new-chain-id", {
|
||||
alias: "c",
|
||||
describe: "New chain ID to set",
|
||||
type: "number",
|
||||
required: true,
|
||||
});
|
||||
},
|
||||
demandOption: true,
|
||||
}),
|
||||
(argv) => {
|
||||
let module = argv["module"] as "Core" | "NFTBridge" | "TokenBridge";
|
||||
let payload: RecoverChainId = {
|
||||
const module = argv["module"];
|
||||
const payload: RecoverChainId = {
|
||||
module,
|
||||
type: "RecoverChainId",
|
||||
evmChainId: BigInt(argv["evm-chain-id"]),
|
||||
newChainId: argv["new-chain-id"],
|
||||
};
|
||||
let v = makeVAA(
|
||||
const vaa = makeVAA(
|
||||
GOVERNANCE_CHAIN,
|
||||
GOVERNANCE_EMITTER,
|
||||
argv["guardian-secret"].split(","),
|
||||
payload
|
||||
);
|
||||
console.log(serialiseVAA(v));
|
||||
console.log(serialiseVAA(vaa));
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
export const handler = () => {};
|
||||
|
||||
function parseAddress(chain: ChainName, address: string): string {
|
||||
if (chain === "unset") {
|
||||
|
@ -311,5 +302,3 @@ function parseCodeAddress(chain: ChainName, address: string): string {
|
|||
return parseAddress(chain, address);
|
||||
}
|
||||
}
|
||||
|
||||
export const handler = (argv) => {};
|
||||
|
|
|
@ -13,5 +13,4 @@ export const builder = (y: typeof yargs) =>
|
|||
.command(contractAddress)
|
||||
.command(convertToEmitter)
|
||||
.command(rpc);
|
||||
|
||||
export const handler = (argv) => {};
|
||||
export const handler = () => {};
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
import BN from "bn.js";
|
||||
import { readFileSync } from "fs";
|
||||
import { Account, KeyPair, connect } from "near-api-js";
|
||||
import { InMemoryKeyStore } from "near-api-js/lib/key_stores";
|
||||
import { parseSeedPhrase } from "near-seed-phrase";
|
||||
import yargs from "yargs";
|
||||
import { deploy_near, upgrade_near } from "../near";
|
||||
import { CONTRACTS, NETWORK_OPTIONS, RPC_OPTIONS } from "../consts";
|
||||
import { NETWORKS } from "../networks";
|
||||
import { assertNetwork } from "../utils";
|
||||
|
||||
// Near utilities
|
||||
export const command = "near";
|
||||
|
@ -9,68 +16,188 @@ export const builder = function (y: typeof yargs) {
|
|||
.option("module", {
|
||||
alias: "m",
|
||||
describe: "Module to query",
|
||||
type: "string",
|
||||
choices: ["Core", "NFTBridge", "TokenBridge"],
|
||||
required: false,
|
||||
})
|
||||
.option("network", {
|
||||
alias: "n",
|
||||
describe: "network",
|
||||
type: "string",
|
||||
choices: ["mainnet", "testnet", "devnet"],
|
||||
required: true,
|
||||
})
|
||||
demandOption: false,
|
||||
} as const)
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("account", {
|
||||
describe: "near deployment account",
|
||||
describe: "Near deployment account",
|
||||
type: "string",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
})
|
||||
.option("attach", {
|
||||
describe: "attach some near",
|
||||
describe: "Attach some near",
|
||||
type: "string",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
})
|
||||
.option("target", {
|
||||
describe: "near account to upgrade",
|
||||
describe: "Near account to upgrade",
|
||||
type: "string",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
})
|
||||
.option("mnemonic", {
|
||||
describe: "near private keys",
|
||||
describe: "Near private keys",
|
||||
type: "string",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
})
|
||||
.option("keys", {
|
||||
describe: "near private keys",
|
||||
.option("key", {
|
||||
describe: "Near private key",
|
||||
type: "string",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
})
|
||||
.option("rpc", RPC_OPTIONS)
|
||||
.command(
|
||||
"contract-update <file>",
|
||||
"Submit a contract update using our specific APIs",
|
||||
(yargs) => {
|
||||
return yargs.positional("file", {
|
||||
(yargs) =>
|
||||
yargs.positional("file", {
|
||||
type: "string",
|
||||
describe: "wasm",
|
||||
});
|
||||
},
|
||||
demandOption: true,
|
||||
}),
|
||||
async (argv) => {
|
||||
await upgrade_near(argv);
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
const contracts = CONTRACTS[network].near;
|
||||
const {
|
||||
rpc: defaultRpc,
|
||||
key: defaultKey,
|
||||
networkId,
|
||||
} = NETWORKS[network].near;
|
||||
|
||||
const key =
|
||||
argv.key ??
|
||||
(argv.mnemonic && parseSeedPhrase(argv.mnemonic).secretKey) ??
|
||||
defaultKey;
|
||||
if (!key) {
|
||||
throw Error(`No ${network} key defined for NEAR`);
|
||||
}
|
||||
|
||||
const rpc = argv.rpc ?? defaultRpc;
|
||||
if (!rpc) {
|
||||
throw Error(`No ${network} rpc defined for NEAR`);
|
||||
}
|
||||
|
||||
let target = argv.target;
|
||||
if (!argv.target && argv.module) {
|
||||
if (argv.module === "Core") {
|
||||
target = contracts.core;
|
||||
console.log("Setting target to core");
|
||||
}
|
||||
|
||||
if (argv.module === "TokenBridge") {
|
||||
target = contracts.token_bridge;
|
||||
console.log("Setting target to token_bridge");
|
||||
}
|
||||
}
|
||||
|
||||
if (!target) {
|
||||
throw Error(`No target defined for NEAR`);
|
||||
}
|
||||
|
||||
const masterKey = KeyPair.fromString(key);
|
||||
const keyStore = new InMemoryKeyStore();
|
||||
keyStore.setKey(networkId, argv["account"], masterKey);
|
||||
const near = await connect({
|
||||
deps: {
|
||||
keyStore,
|
||||
},
|
||||
networkId,
|
||||
nodeUrl: rpc,
|
||||
headers: {},
|
||||
});
|
||||
|
||||
const masterAccount = new Account(near.connection, argv["account"]);
|
||||
const result = await masterAccount.functionCall({
|
||||
contractId: target,
|
||||
methodName: "update_contract",
|
||||
args: readFileSync(argv["file"]),
|
||||
attachedDeposit: new BN("22797900000000000000000000"),
|
||||
gas: new BN("300000000000000"),
|
||||
});
|
||||
console.log(result);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"deploy <file>",
|
||||
"Submit a contract update using near APIs",
|
||||
(yargs) => {
|
||||
return yargs.positional("file", {
|
||||
(yargs) =>
|
||||
yargs.positional("file", {
|
||||
type: "string",
|
||||
describe: "wasm",
|
||||
});
|
||||
},
|
||||
demandOption: true,
|
||||
}),
|
||||
async (argv) => {
|
||||
await deploy_near(argv);
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
const contracts = CONTRACTS[network].near;
|
||||
const {
|
||||
rpc: defaultRpc,
|
||||
key: defaultKey,
|
||||
networkId,
|
||||
} = NETWORKS[network].near;
|
||||
|
||||
const key =
|
||||
argv.key ??
|
||||
(argv.mnemonic && parseSeedPhrase(argv.mnemonic).secretKey) ??
|
||||
defaultKey;
|
||||
if (!key) {
|
||||
throw Error(`No ${network} key defined for NEAR`);
|
||||
}
|
||||
|
||||
const rpc = argv.rpc ?? defaultRpc;
|
||||
if (!rpc) {
|
||||
throw Error(`No ${network} rpc defined for NEAR`);
|
||||
}
|
||||
|
||||
let target = argv.target;
|
||||
if (!argv.target && argv.module) {
|
||||
if (argv.module === "Core") {
|
||||
target = contracts.core;
|
||||
console.log("Setting target to core");
|
||||
}
|
||||
|
||||
if (argv.module === "TokenBridge") {
|
||||
target = contracts.token_bridge;
|
||||
console.log("Setting target to token_bridge");
|
||||
}
|
||||
}
|
||||
|
||||
if (!target) {
|
||||
throw Error(`No target defined for NEAR`);
|
||||
}
|
||||
|
||||
const masterKey = KeyPair.fromString(key);
|
||||
const keyStore = new InMemoryKeyStore();
|
||||
keyStore.setKey(networkId, argv["account"], masterKey);
|
||||
keyStore.setKey(networkId, target, masterKey);
|
||||
|
||||
const near = await connect({
|
||||
deps: {
|
||||
keyStore,
|
||||
},
|
||||
networkId: networkId,
|
||||
nodeUrl: rpc,
|
||||
headers: {},
|
||||
});
|
||||
const masterAccount = new Account(near.connection, argv["account"]);
|
||||
const targetAccount = new Account(near.connection, target);
|
||||
console.log({ ...argv, key, rpc, target });
|
||||
|
||||
if (argv.attach) {
|
||||
console.log(
|
||||
`Sending money: ${target} from ${argv["account"]} being sent ${argv["attach"]}`
|
||||
);
|
||||
console.log(
|
||||
await masterAccount.sendMoney(target, new BN(argv.attach))
|
||||
);
|
||||
}
|
||||
|
||||
console.log("deploying contract");
|
||||
console.log(
|
||||
await targetAccount.deployContract(readFileSync(argv["file"]))
|
||||
);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const handler = (argv) => {};
|
||||
export const handler = () => {};
|
||||
|
|
|
@ -7,9 +7,10 @@ export const builder = (y: typeof yargs) => {
|
|||
return y.positional("vaa", {
|
||||
describe: "vaa",
|
||||
type: "string",
|
||||
demandOption: true,
|
||||
});
|
||||
};
|
||||
export const handler = (argv) => {
|
||||
export const handler = (argv: Awaited<ReturnType<typeof builder>["argv"]>) => {
|
||||
let buf: Buffer;
|
||||
try {
|
||||
buf = Buffer.from(String(argv.vaa), "hex");
|
||||
|
@ -22,8 +23,9 @@ export const handler = (argv) => {
|
|||
throw Error("Couldn't parse VAA as base64 or hex");
|
||||
}
|
||||
}
|
||||
const parsed_vaa = parse(buf);
|
||||
let parsed_vaa_with_digest = parsed_vaa;
|
||||
parsed_vaa_with_digest["digest"] = vaaDigest(parsed_vaa);
|
||||
console.log(JSON.stringify(parsed_vaa_with_digest, null, 2));
|
||||
|
||||
const parsedVaa = parse(buf);
|
||||
console.log(
|
||||
JSON.stringify({ ...parsedVaa, digest: vaaDigest(parsedVaa) }, null, 2)
|
||||
);
|
||||
};
|
||||
|
|
|
@ -4,18 +4,22 @@ import { hex } from "../utils";
|
|||
|
||||
export const command = "recover <digest> <signature>";
|
||||
export const desc = "Recover an address from a signature";
|
||||
export const builder = (y: typeof yargs) => {
|
||||
return y
|
||||
export const builder = (y: typeof yargs) =>
|
||||
y
|
||||
.positional("digest", {
|
||||
describe: "digest",
|
||||
type: "string",
|
||||
demandOption: true,
|
||||
})
|
||||
.positional("signature", {
|
||||
describe: "signature",
|
||||
type: "string",
|
||||
demandOption: true,
|
||||
});
|
||||
};
|
||||
export const handler = async (argv) => {
|
||||
|
||||
export const handler = async (
|
||||
argv: Awaited<ReturnType<typeof builder>["argv"]>
|
||||
) => {
|
||||
console.log(
|
||||
ethers.utils.recoverAddress(hex(argv["digest"]), hex(argv["signature"]))
|
||||
);
|
||||
|
|
|
@ -4,27 +4,27 @@ import {
|
|||
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import yargs from "yargs";
|
||||
import { NETWORKS } from "../networks";
|
||||
import { assertNetwork } from "../utils";
|
||||
|
||||
export const command = "rpc <network> <chain>";
|
||||
export const desc = "Print RPC address";
|
||||
export const builder = (y: typeof yargs) => {
|
||||
return y
|
||||
export const builder = (y: typeof yargs) =>
|
||||
y
|
||||
.positional("network", {
|
||||
describe: "network",
|
||||
type: "string",
|
||||
choices: ["mainnet", "testnet", "devnet"],
|
||||
})
|
||||
demandOption: true,
|
||||
} as const)
|
||||
.positional("chain", {
|
||||
describe: "Chain to query",
|
||||
type: "string",
|
||||
choices: Object.keys(CHAINS),
|
||||
});
|
||||
};
|
||||
export const handler = async (argv) => {
|
||||
demandOption: true,
|
||||
} as const);
|
||||
export const handler = async (
|
||||
argv: Awaited<ReturnType<typeof builder>["argv"]>
|
||||
) => {
|
||||
assertChain(argv["chain"]);
|
||||
const network = argv.network.toUpperCase();
|
||||
if (network !== "MAINNET" && network !== "TESTNET" && network !== "DEVNET") {
|
||||
throw Error(`Unknown network: ${network}`);
|
||||
}
|
||||
assertNetwork(network);
|
||||
console.log(NETWORKS[network][argv["chain"]].rpc);
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import yargs from "yargs";
|
||||
import { execute_algorand } from "../algorand";
|
||||
import { execute_aptos } from "../aptos";
|
||||
import { execute_evm } from "../evm";
|
||||
import { execute_injective } from "../injective";
|
||||
import { execute_near } from "../near";
|
||||
|
@ -16,58 +17,55 @@ import { execute_sei } from "../sei";
|
|||
import { execute_solana } from "../solana";
|
||||
import { submit as submitSui } from "../sui";
|
||||
import { execute_terra } from "../terra";
|
||||
import * as vaa from "../vaa";
|
||||
import { assertNetwork } from "../utils";
|
||||
import { assertKnownPayload, impossible, parse } from "../vaa";
|
||||
import { execute_xpla } from "../xpla";
|
||||
import { execute_aptos } from "../aptos";
|
||||
|
||||
export const command = "submit <vaa>";
|
||||
export const desc = "Execute a VAA";
|
||||
export const builder = (y: typeof yargs) => {
|
||||
return y
|
||||
export const builder = (y: typeof yargs) =>
|
||||
y
|
||||
.positional("vaa", {
|
||||
describe: "vaa",
|
||||
type: "string",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
})
|
||||
.option("chain", {
|
||||
alias: "c",
|
||||
describe: "chain name",
|
||||
type: "string",
|
||||
choices: Object.keys(CHAINS),
|
||||
required: false,
|
||||
})
|
||||
demandOption: false,
|
||||
} as const)
|
||||
.option("network", {
|
||||
alias: "n",
|
||||
describe: "network",
|
||||
type: "string",
|
||||
choices: ["mainnet", "testnet", "devnet"],
|
||||
required: true,
|
||||
})
|
||||
demandOption: true,
|
||||
} as const)
|
||||
.option("contract-address", {
|
||||
alias: "a",
|
||||
describe: "Contract to submit VAA to (override config)",
|
||||
type: "string",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
})
|
||||
.option("rpc", {
|
||||
describe: "RPC endpoint",
|
||||
type: "string",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
});
|
||||
};
|
||||
export const handler = async (argv) => {
|
||||
export const handler = async (
|
||||
argv: Awaited<ReturnType<typeof builder>["argv"]>
|
||||
) => {
|
||||
const vaa_hex = String(argv.vaa);
|
||||
const buf = Buffer.from(vaa_hex, "hex");
|
||||
const parsed_vaa = vaa.parse(buf);
|
||||
const parsed_vaa = parse(buf);
|
||||
|
||||
vaa.assertKnownPayload(parsed_vaa);
|
||||
assertKnownPayload(parsed_vaa);
|
||||
|
||||
console.log(parsed_vaa.payload);
|
||||
|
||||
const network = argv.network.toUpperCase();
|
||||
if (network !== "MAINNET" && network !== "TESTNET" && network !== "DEVNET") {
|
||||
throw Error(`Unknown network: ${network}`);
|
||||
}
|
||||
assertNetwork(network);
|
||||
|
||||
// We figure out the target chain to submit the VAA to.
|
||||
// The VAA might specify this itself (for example a contract upgrade VAA
|
||||
|
@ -156,6 +154,6 @@ export const handler = async (argv) => {
|
|||
} else {
|
||||
// If you get a type error here, hover over `chain`'s type and it tells you
|
||||
// which cases are not handled
|
||||
vaa.impossible(chain);
|
||||
impossible(chain);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -21,33 +21,33 @@ export const addBuildCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
.option("decimals", {
|
||||
alias: "d",
|
||||
describe: "Decimals of asset",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
type: "number",
|
||||
})
|
||||
// Can't be called version because of a conflict with the native version option
|
||||
.option("version-struct", {
|
||||
alias: "v",
|
||||
describe: "Version control struct name (e.g. V__0_1_0)",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
type: "string",
|
||||
})
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("package-path", {
|
||||
alias: "p",
|
||||
describe: "Path to coin module",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
type: "string",
|
||||
})
|
||||
.option("wormhole-state", {
|
||||
alias: "w",
|
||||
describe: "Wormhole state object ID",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
type: "string",
|
||||
})
|
||||
.option("token-bridge-state", {
|
||||
alias: "t",
|
||||
describe: "Token bridge state object ID",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
type: "string",
|
||||
})
|
||||
.option("rpc", RPC_OPTIONS),
|
||||
|
@ -65,11 +65,23 @@ export const addBuildCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
argv["wormhole-state"] ?? CONTRACTS[network].sui.core;
|
||||
const tokenBridgeStateObjectId =
|
||||
argv["token-bridge-state"] ?? CONTRACTS[network].sui.token_bridge;
|
||||
|
||||
if (!coreBridgeStateObjectId) {
|
||||
throw new Error(
|
||||
`Couldn't find core bridge state object ID for network ${network}`
|
||||
);
|
||||
}
|
||||
|
||||
if (!tokenBridgeStateObjectId) {
|
||||
throw new Error(
|
||||
`Couldn't find token bridge state object ID for network ${network}`
|
||||
);
|
||||
}
|
||||
|
||||
const provider = getProvider(
|
||||
network,
|
||||
argv.rpc ?? NETWORKS[network].sui.rpc
|
||||
);
|
||||
|
||||
const build = await buildCoin(
|
||||
provider,
|
||||
network,
|
||||
|
|
|
@ -27,16 +27,17 @@ export const addDeployCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
y.command(
|
||||
"deploy <package-dir>",
|
||||
"Deploy a Sui package",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
(yargs) =>
|
||||
yargs
|
||||
.positional("package-dir", {
|
||||
type: "string",
|
||||
describe: "Path to package directory",
|
||||
demandOption: true,
|
||||
})
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("debug", DEBUG_OPTIONS)
|
||||
.option("private-key", PRIVATE_KEY_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS);
|
||||
},
|
||||
.option("rpc", RPC_OPTIONS),
|
||||
async (argv) => {
|
||||
checkBinary("sui", README_URL);
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ import { addUtilsCommands } from "./utils";
|
|||
|
||||
export const command = "sui";
|
||||
export const desc = "Sui utilities";
|
||||
export const builder = function (y: typeof yargs) {
|
||||
return new Yargs(y)
|
||||
export const builder = (y: typeof yargs) =>
|
||||
new Yargs(y)
|
||||
.addCommands(addBuildCommands)
|
||||
.addCommands(addDeployCommands)
|
||||
.addCommands(addInitCommands)
|
||||
|
@ -20,5 +20,4 @@ export const builder = function (y: typeof yargs) {
|
|||
.y()
|
||||
.strict()
|
||||
.demandCommand();
|
||||
};
|
||||
export const handler = (argv) => {};
|
||||
export const handler = () => {};
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
isSameType,
|
||||
logTransactionDigest,
|
||||
logTransactionSender,
|
||||
setMaxGasBudgetDevnet,
|
||||
} from "../../sui";
|
||||
import { Network, assertNetwork } from "../../utils";
|
||||
import { YargsAddCommandsFn } from "../Yargs";
|
||||
|
@ -29,24 +30,23 @@ export const addInitCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
.command(
|
||||
"init-example-message-app",
|
||||
"Initialize example core message app",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
(yargs) =>
|
||||
yargs
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("package-id", {
|
||||
alias: "p",
|
||||
describe: "Example app package ID",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
type: "string",
|
||||
})
|
||||
.option("wormhole-state", {
|
||||
alias: "w",
|
||||
describe: "Wormhole state object ID",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
type: "string",
|
||||
})
|
||||
.option("private-key", PRIVATE_KEY_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS);
|
||||
},
|
||||
.option("rpc", RPC_OPTIONS),
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
|
@ -69,26 +69,26 @@ export const addInitCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
"Example app state object ID",
|
||||
getCreatedObjects(res).find((e) =>
|
||||
isSameType(e.type, `${packageId}::sender::State`)
|
||||
).objectId
|
||||
)?.objectId
|
||||
);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"init-token-bridge",
|
||||
"Initialize token bridge contract",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
(yargs) =>
|
||||
yargs
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("package-id", {
|
||||
alias: "p",
|
||||
describe: "Token bridge package ID",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
type: "string",
|
||||
})
|
||||
.option("wormhole-state", {
|
||||
alias: "w",
|
||||
describe: "Wormhole state object ID",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
type: "string",
|
||||
})
|
||||
.option("governance-chain-id", {
|
||||
|
@ -96,18 +96,17 @@ export const addInitCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
describe: "Governance chain ID",
|
||||
default: GOVERNANCE_CHAIN,
|
||||
type: "number",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
})
|
||||
.option("governance-address", {
|
||||
alias: "a",
|
||||
describe: "Governance contract address",
|
||||
type: "string",
|
||||
default: GOVERNANCE_EMITTER,
|
||||
required: false,
|
||||
demandOption: false,
|
||||
})
|
||||
.option("private-key", PRIVATE_KEY_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS);
|
||||
},
|
||||
.option("rpc", RPC_OPTIONS),
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
|
@ -134,25 +133,25 @@ export const addInitCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
"Token bridge state object ID",
|
||||
getCreatedObjects(res).find((e) =>
|
||||
isSameType(e.type, `${packageId}::state::State`)
|
||||
).objectId
|
||||
)?.objectId
|
||||
);
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"init-wormhole",
|
||||
"Initialize wormhole core contract",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
(yargs) =>
|
||||
yargs
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("package-id", {
|
||||
alias: "p",
|
||||
describe: "Core bridge package ID",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
type: "string",
|
||||
})
|
||||
.option("initial-guardian", {
|
||||
alias: "i",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
describe: "Initial guardian public keys",
|
||||
type: "string",
|
||||
})
|
||||
|
@ -162,25 +161,24 @@ export const addInitCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
describe: "Governance chain ID",
|
||||
default: GOVERNANCE_CHAIN,
|
||||
type: "number",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
})
|
||||
.option("guardian-set-index", {
|
||||
alias: "s",
|
||||
describe: "Governance set index",
|
||||
default: 0,
|
||||
type: "number",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
})
|
||||
.option("governance-address", {
|
||||
alias: "a",
|
||||
describe: "Governance contract address",
|
||||
type: "string",
|
||||
default: GOVERNANCE_EMITTER,
|
||||
required: false,
|
||||
demandOption: false,
|
||||
})
|
||||
.option("private-key", PRIVATE_KEY_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS);
|
||||
},
|
||||
.option("rpc", RPC_OPTIONS),
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
|
@ -209,7 +207,7 @@ export const addInitCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
"Wormhole state object ID",
|
||||
getCreatedObjects(res).find((e) =>
|
||||
isSameType(e.type, `${packageId}::state::State`)
|
||||
).objectId
|
||||
)?.objectId
|
||||
);
|
||||
if (debug) {
|
||||
logTransactionSender(res);
|
||||
|
@ -228,16 +226,13 @@ export const initExampleApp = async (
|
|||
const provider = getProvider(network, rpc);
|
||||
const signer = getSigner(provider, network, privateKey);
|
||||
|
||||
const transactionBlock = new TransactionBlock();
|
||||
if (network === "DEVNET") {
|
||||
// Avoid Error checking transaction input objects: GasBudgetTooHigh { gas_budget: 50000000000, max_budget: 10000000000 }
|
||||
transactionBlock.setGasBudget(10000000000);
|
||||
}
|
||||
transactionBlock.moveCall({
|
||||
const tx = new TransactionBlock();
|
||||
setMaxGasBudgetDevnet(network, tx);
|
||||
tx.moveCall({
|
||||
target: `${packageId}::sender::init_with_params`,
|
||||
arguments: [transactionBlock.object(wormholeStateObjectId)],
|
||||
arguments: [tx.object(wormholeStateObjectId)],
|
||||
});
|
||||
return executeTransactionBlock(signer, transactionBlock);
|
||||
return executeTransactionBlock(signer, tx);
|
||||
};
|
||||
|
||||
export const initTokenBridge = async (
|
||||
|
@ -283,26 +278,23 @@ export const initTokenBridge = async (
|
|||
coreBridgeStateObjectId
|
||||
);
|
||||
|
||||
const transactionBlock = new TransactionBlock();
|
||||
if (network === "DEVNET") {
|
||||
// Avoid Error checking transaction input objects: GasBudgetTooHigh { gas_budget: 50000000000, max_budget: 10000000000 }
|
||||
transactionBlock.setGasBudget(10000000000);
|
||||
}
|
||||
const [emitterCap] = transactionBlock.moveCall({
|
||||
const tx = new TransactionBlock();
|
||||
setMaxGasBudgetDevnet(network, tx);
|
||||
const [emitterCap] = tx.moveCall({
|
||||
target: `${wormholePackageId}::emitter::new`,
|
||||
arguments: [transactionBlock.object(coreBridgeStateObjectId)],
|
||||
arguments: [tx.object(coreBridgeStateObjectId)],
|
||||
});
|
||||
transactionBlock.moveCall({
|
||||
tx.moveCall({
|
||||
target: `${tokenBridgePackageId}::setup::complete`,
|
||||
arguments: [
|
||||
transactionBlock.object(deployerCapObjectId),
|
||||
transactionBlock.object(upgradeCapObjectId),
|
||||
tx.object(deployerCapObjectId),
|
||||
tx.object(upgradeCapObjectId),
|
||||
emitterCap,
|
||||
transactionBlock.pure(governanceChainId),
|
||||
transactionBlock.pure([...Buffer.from(governanceContract, "hex")]),
|
||||
tx.pure(governanceChainId),
|
||||
tx.pure([...Buffer.from(governanceContract, "hex")]),
|
||||
],
|
||||
});
|
||||
return executeTransactionBlock(signer, transactionBlock);
|
||||
return executeTransactionBlock(signer, tx);
|
||||
};
|
||||
|
||||
export const initWormhole = async (
|
||||
|
@ -344,25 +336,22 @@ export const initWormhole = async (
|
|||
);
|
||||
}
|
||||
|
||||
const transactionBlock = new TransactionBlock();
|
||||
if (network === "DEVNET") {
|
||||
// Avoid Error checking transaction input objects: GasBudgetTooHigh { gas_budget: 50000000000, max_budget: 10000000000 }
|
||||
transactionBlock.setGasBudget(10000000000);
|
||||
}
|
||||
transactionBlock.moveCall({
|
||||
const tx = new TransactionBlock();
|
||||
setMaxGasBudgetDevnet(network, tx);
|
||||
tx.moveCall({
|
||||
target: `${coreBridgePackageId}::setup::complete`,
|
||||
arguments: [
|
||||
transactionBlock.object(deployerCapObjectId),
|
||||
transactionBlock.object(upgradeCapObjectId),
|
||||
transactionBlock.pure(governanceChainId),
|
||||
transactionBlock.pure([...Buffer.from(governanceContract, "hex")]),
|
||||
transactionBlock.pure(guardianSetIndex),
|
||||
transactionBlock.pure(
|
||||
tx.object(deployerCapObjectId),
|
||||
tx.object(upgradeCapObjectId),
|
||||
tx.pure(governanceChainId),
|
||||
tx.pure([...Buffer.from(governanceContract, "hex")]),
|
||||
tx.pure(guardianSetIndex),
|
||||
tx.pure(
|
||||
initialGuardians.split(",").map((g) => [...Buffer.from(g, "hex")])
|
||||
),
|
||||
transactionBlock.pure(24 * 60 * 60), // Guardian set TTL in seconds
|
||||
transactionBlock.pure("0"), // Message fee
|
||||
tx.pure(24 * 60 * 60), // Guardian set TTL in seconds
|
||||
tx.pure("0"), // Message fee
|
||||
],
|
||||
});
|
||||
return executeTransactionBlock(signer, transactionBlock);
|
||||
return executeTransactionBlock(signer, tx);
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
getSigner,
|
||||
logTransactionDigest,
|
||||
logTransactionSender,
|
||||
setMaxGasBudgetDevnet,
|
||||
} from "../../sui";
|
||||
import { assertNetwork } from "../../utils";
|
||||
import { YargsAddCommandsFn } from "../Yargs";
|
||||
|
@ -22,41 +23,40 @@ export const addPublishMessageCommands: YargsAddCommandsFn = (
|
|||
y.command(
|
||||
"publish-example-message",
|
||||
"Publish message from example app via core bridge",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
(yargs) =>
|
||||
yargs
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("package-id", {
|
||||
alias: "p",
|
||||
describe: "Package ID/module address",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
type: "string",
|
||||
})
|
||||
.option("state", {
|
||||
alias: "s",
|
||||
describe: "Core messages app state object ID",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
type: "string",
|
||||
})
|
||||
.option("wormhole-state", {
|
||||
alias: "w",
|
||||
describe: "Wormhole state object ID",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
type: "string",
|
||||
})
|
||||
.option("message", {
|
||||
alias: "m",
|
||||
describe: "Message payload",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
type: "string",
|
||||
})
|
||||
.option("private-key", {
|
||||
alias: "k",
|
||||
describe: "Custom private key to sign txs",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
type: "string",
|
||||
})
|
||||
.option("rpc", RPC_OPTIONS);
|
||||
},
|
||||
.option("rpc", RPC_OPTIONS),
|
||||
async (argv) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
assertNetwork(network);
|
||||
|
@ -71,26 +71,23 @@ export const addPublishMessageCommands: YargsAddCommandsFn = (
|
|||
const signer = getSigner(provider, network, privateKey);
|
||||
|
||||
// Publish message
|
||||
const transactionBlock = new TransactionBlock();
|
||||
if (network === "DEVNET") {
|
||||
// Avoid Error checking transaction input objects: GasBudgetTooHigh { gas_budget: 50000000000, max_budget: 10000000000 }
|
||||
transactionBlock.setGasBudget(10000000000);
|
||||
}
|
||||
transactionBlock.moveCall({
|
||||
const tx = new TransactionBlock();
|
||||
setMaxGasBudgetDevnet(network, tx);
|
||||
tx.moveCall({
|
||||
target: `${packageId}::sender::send_message_entry`,
|
||||
arguments: [
|
||||
transactionBlock.object(stateObjectId),
|
||||
transactionBlock.object(wormholeStateObjectId),
|
||||
transactionBlock.pure(message),
|
||||
transactionBlock.object(SUI_CLOCK_OBJECT_ID),
|
||||
tx.object(stateObjectId),
|
||||
tx.object(wormholeStateObjectId),
|
||||
tx.pure(message),
|
||||
tx.object(SUI_CLOCK_OBJECT_ID),
|
||||
],
|
||||
});
|
||||
const res = await executeTransactionBlock(signer, transactionBlock);
|
||||
const res = await executeTransactionBlock(signer, tx);
|
||||
|
||||
// Hacky way to grab event since we don't require package ID of the
|
||||
// core bridge as input. Doesn't really matter since this is a test
|
||||
// command.
|
||||
const event = res.events.find(
|
||||
const event = res.events?.find(
|
||||
(e) =>
|
||||
normalizeSuiAddress(e.packageId) === normalizeSuiAddress(packageId) &&
|
||||
e.type.includes("publish_message::WormholeMessage")
|
||||
|
@ -107,10 +104,10 @@ export const addPublishMessageCommands: YargsAddCommandsFn = (
|
|||
console.log("Publish message succeeded:", {
|
||||
sender: event.sender,
|
||||
type: event.type,
|
||||
payload: Buffer.from(event.parsedJson.payload).toString(),
|
||||
emitter: Buffer.from(event.parsedJson.sender).toString("hex"),
|
||||
sequence: event.parsedJson.sequence,
|
||||
nonce: event.parsedJson.nonce,
|
||||
payload: Buffer.from(event.parsedJson?.payload).toString(),
|
||||
emitter: Buffer.from(event.parsedJson?.sender).toString("hex"),
|
||||
sequence: event.parsedJson?.sequence,
|
||||
nonce: event.parsedJson?.nonce,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
ChainId,
|
||||
ChainName,
|
||||
coalesceChainName,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import { parseTokenBridgeRegisterChainVaa } from "@certusone/wormhole-sdk/lib/esm/vaa/tokenBridge";
|
||||
|
@ -30,6 +31,7 @@ import {
|
|||
logPublishedPackageId,
|
||||
logTransactionDigest,
|
||||
registerChain,
|
||||
setMaxGasBudgetDevnet,
|
||||
} from "../../sui";
|
||||
import { YargsAddCommandsFn } from "../Yargs";
|
||||
import { deploy } from "./deploy";
|
||||
|
@ -39,16 +41,15 @@ export const addSetupCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
y.command(
|
||||
"setup-devnet",
|
||||
"Setup devnet by deploying and initializing core and token bridges and submitting chain registrations.",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
(yargs) =>
|
||||
yargs
|
||||
.option("private-key", {
|
||||
alias: "k",
|
||||
describe: "Custom private key to sign txs",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
type: "string",
|
||||
})
|
||||
.option("rpc", RPC_OPTIONS);
|
||||
},
|
||||
.option("rpc", RPC_OPTIONS),
|
||||
async (argv) => {
|
||||
const network = "DEVNET";
|
||||
const privateKey = argv["private-key"];
|
||||
|
@ -62,8 +63,8 @@ export const addSetupCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
rpc,
|
||||
privateKey
|
||||
);
|
||||
assertSuccess(coreBridgeDeployRes, "Core bridge deployment failed.");
|
||||
logTransactionDigest(coreBridgeDeployRes);
|
||||
assertSuccess(coreBridgeDeployRes, "Core bridge deployment failed.");
|
||||
logPublishedPackageId(coreBridgeDeployRes);
|
||||
|
||||
// Init core bridge
|
||||
|
@ -79,11 +80,17 @@ export const addSetupCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
rpc,
|
||||
privateKey
|
||||
);
|
||||
logTransactionDigest(coreBridgeInitRes);
|
||||
assertSuccess(coreBridgeInitRes, "Core bridge initialization failed.");
|
||||
|
||||
// Get core bridge state object ID
|
||||
const coreBridgeStateObjectId = getCreatedObjects(coreBridgeInitRes).find(
|
||||
(e) => isSameType(e.type, `${coreBridgePackageId}::state::State`)
|
||||
).objectId;
|
||||
assertSuccess(coreBridgeInitRes, "Core bridge initialization failed.");
|
||||
logTransactionDigest(coreBridgeInitRes);
|
||||
)?.objectId;
|
||||
if (!coreBridgeStateObjectId) {
|
||||
throw new Error("Couldn't find core bridge state object ID.");
|
||||
}
|
||||
|
||||
console.log("Core bridge state object ID", coreBridgeStateObjectId);
|
||||
|
||||
// Deploy token bridge
|
||||
|
@ -94,8 +101,8 @@ export const addSetupCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
rpc,
|
||||
privateKey
|
||||
);
|
||||
assertSuccess(tokenBridgeDeployRes, "Token bridge deployment failed.");
|
||||
logTransactionDigest(tokenBridgeDeployRes);
|
||||
assertSuccess(tokenBridgeDeployRes, "Token bridge deployment failed.");
|
||||
logPublishedPackageId(tokenBridgeDeployRes);
|
||||
|
||||
// Init token bridge
|
||||
|
@ -110,13 +117,19 @@ export const addSetupCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
rpc,
|
||||
privateKey
|
||||
);
|
||||
logTransactionDigest(tokenBridgeInitRes);
|
||||
assertSuccess(tokenBridgeInitRes, "Token bridge initialization failed.");
|
||||
|
||||
// Get token bridge state object ID
|
||||
const tokenBridgeStateObjectId = getCreatedObjects(
|
||||
tokenBridgeInitRes
|
||||
).find((e) =>
|
||||
isSameType(e.type, `${tokenBridgePackageId}::state::State`)
|
||||
).objectId;
|
||||
assertSuccess(tokenBridgeInitRes, "Token bridge initialization failed.");
|
||||
logTransactionDigest(tokenBridgeInitRes);
|
||||
)?.objectId;
|
||||
if (!tokenBridgeStateObjectId) {
|
||||
throw new Error("Couldn't find token bridge state object ID.");
|
||||
}
|
||||
|
||||
console.log("Token bridge state object ID", tokenBridgeStateObjectId);
|
||||
|
||||
// Deploy example app
|
||||
|
@ -142,7 +155,7 @@ export const addSetupCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
);
|
||||
const exampleAppStateObjectId = getCreatedObjects(exampleAppInitRes).find(
|
||||
(e) => isSameType(e.type, `${exampleAppPackageId}::sender::State`)
|
||||
).objectId;
|
||||
)?.objectId;
|
||||
logTransactionDigest(exampleAppInitRes);
|
||||
console.log("Example app state object ID", exampleAppStateObjectId);
|
||||
|
||||
|
@ -185,10 +198,10 @@ export const addSetupCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
}
|
||||
|
||||
dotenv.config({ path: envPath });
|
||||
const signer = getSigner(provider, network, privateKey);
|
||||
|
||||
const tx = new TransactionBlock();
|
||||
tx.setGasBudget(10000000000);
|
||||
const registrations = [];
|
||||
setMaxGasBudgetDevnet("DEVNET", tx);
|
||||
const registrations: { chain: ChainName; module: string }[] = [];
|
||||
for (const key in process.env) {
|
||||
if (/^REGISTER_(.+)_TOKEN_BRIDGE_VAA$/.test(key)) {
|
||||
// Get VAA info
|
||||
|
@ -210,6 +223,7 @@ export const addSetupCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
}
|
||||
}
|
||||
|
||||
const signer = getSigner(provider, network, privateKey);
|
||||
const registerRes = await executeTransactionBlock(signer, tx);
|
||||
assertSuccess(registerRes, "Chain registrations failed.");
|
||||
|
||||
|
@ -228,13 +242,12 @@ export const addSetupCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
const getEmitterCapObjectId = async (
|
||||
provider: JsonRpcProvider,
|
||||
tokenBridgeStateObjectId: string
|
||||
): Promise<string> => {
|
||||
return getObjectFields(
|
||||
): Promise<string> =>
|
||||
getObjectFields(
|
||||
await provider.getObject({
|
||||
id: tokenBridgeStateObjectId,
|
||||
options: {
|
||||
showContent: true,
|
||||
},
|
||||
})
|
||||
).emitter_cap.fields.id.id;
|
||||
};
|
||||
)?.emitter_cap.fields.id.id;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { PaginatedObjectsResponse } from "@mysten/sui.js";
|
||||
import yargs from "yargs";
|
||||
import { NETWORK_OPTIONS, RPC_OPTIONS } from "../../consts";
|
||||
import { NETWORKS } from "../../networks";
|
||||
|
@ -15,6 +16,7 @@ export const addUtilsCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
.positional("owner", {
|
||||
describe: "Owner address",
|
||||
type: "string",
|
||||
demandOption: true,
|
||||
})
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS),
|
||||
|
@ -25,11 +27,15 @@ export const addUtilsCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
const owner = argv.owner;
|
||||
|
||||
const provider = getProvider(network, rpc);
|
||||
const objects = [];
|
||||
const objects: PaginatedObjectsResponse["data"] = [];
|
||||
|
||||
let cursor = undefined;
|
||||
let cursor: PaginatedObjectsResponse["nextCursor"] | undefined =
|
||||
undefined;
|
||||
while (true) {
|
||||
const res = await provider.getOwnedObjects({ owner, cursor });
|
||||
const res: PaginatedObjectsResponse = await provider.getOwnedObjects({
|
||||
owner,
|
||||
cursor,
|
||||
});
|
||||
objects.push(...res.data);
|
||||
if (res.hasNextPage) {
|
||||
cursor = res.nextCursor;
|
||||
|
@ -51,6 +57,7 @@ export const addUtilsCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
.positional("state-object-id", {
|
||||
describe: "Object ID of State object",
|
||||
type: "string",
|
||||
demandOption: true,
|
||||
})
|
||||
.option("network", NETWORK_OPTIONS)
|
||||
.option("rpc", RPC_OPTIONS),
|
||||
|
@ -72,6 +79,7 @@ export const addUtilsCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
.positional("transaction-digest", {
|
||||
describe: "Digest of transaction to fetch",
|
||||
type: "string",
|
||||
demandOption: true,
|
||||
})
|
||||
.option("network", {
|
||||
alias: "n",
|
||||
|
@ -79,7 +87,7 @@ export const addUtilsCommands: YargsAddCommandsFn = (y: typeof yargs) =>
|
|||
type: "string",
|
||||
choices: ["mainnet", "testnet", "devnet"],
|
||||
default: "devnet",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
})
|
||||
.option("rpc", RPC_OPTIONS),
|
||||
async (argv) => {
|
||||
|
|
|
@ -5,43 +5,41 @@ import { CONTRACTS } from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
|||
import { ethers } from "ethers";
|
||||
import yargs from "yargs";
|
||||
import { NETWORKS } from "../networks";
|
||||
import { assertNetwork } from "../utils";
|
||||
|
||||
export const command = "verify-vaa";
|
||||
export const desc = "Verifies a VAA by querying the core contract on Ethereum";
|
||||
export const builder = (y: typeof yargs) => {
|
||||
return y
|
||||
export const builder = (y: typeof yargs) =>
|
||||
y
|
||||
.option("vaa", {
|
||||
alias: "v",
|
||||
describe: "vaa in hex format",
|
||||
type: "string",
|
||||
required: true,
|
||||
demandOption: true,
|
||||
})
|
||||
.option("network", {
|
||||
alias: "n",
|
||||
describe: "network",
|
||||
type: "string",
|
||||
choices: ["mainnet", "testnet", "devnet"],
|
||||
required: true,
|
||||
});
|
||||
};
|
||||
export const handler = async (argv) => {
|
||||
demandOption: true,
|
||||
} as const);
|
||||
export const handler = async (
|
||||
argv: Awaited<ReturnType<typeof builder>["argv"]>
|
||||
) => {
|
||||
const network = argv.network.toUpperCase();
|
||||
if (network !== "MAINNET" && network !== "TESTNET" && network !== "DEVNET") {
|
||||
throw Error(`Unknown network: ${network}`);
|
||||
}
|
||||
assertNetwork(network);
|
||||
|
||||
const buf = Buffer.from(String(argv.vaa), "hex");
|
||||
let n = NETWORKS[network]["ethereum"];
|
||||
let contract_address = CONTRACTS[network]["ethereum"].core;
|
||||
|
||||
if (contract_address === undefined) {
|
||||
const contract_address = CONTRACTS[network].ethereum.core;
|
||||
if (!contract_address) {
|
||||
throw Error(`Unknown core contract on ${network} for ethereum`);
|
||||
}
|
||||
|
||||
const provider = new ethers.providers.JsonRpcProvider(n.rpc);
|
||||
const provider = new ethers.providers.JsonRpcProvider(
|
||||
NETWORKS[network].ethereum.rpc
|
||||
);
|
||||
const contract = Implementation__factory.connect(contract_address, provider);
|
||||
const result = await contract.parseAndVerifyVM(buf);
|
||||
|
||||
if (result[1]) {
|
||||
console.log("Verification succeeded!");
|
||||
} else {
|
||||
|
|
|
@ -58,27 +58,26 @@ export const DEBUG_OPTIONS = {
|
|||
alias: "d",
|
||||
describe: "Log debug info",
|
||||
type: "boolean",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
} as const;
|
||||
|
||||
export const NAMED_ADDRESSES_OPTIONS = {
|
||||
describe: "Named addresses in the format addr1=0x0,addr2=0x1,...",
|
||||
type: "string",
|
||||
require: false,
|
||||
demandOption: false,
|
||||
} as const;
|
||||
|
||||
export const NETWORK_OPTIONS = {
|
||||
alias: "n",
|
||||
describe: "Network",
|
||||
type: "string",
|
||||
choices: ["mainnet", "testnet", "devnet"],
|
||||
required: true,
|
||||
demandOption: true,
|
||||
} as const;
|
||||
|
||||
export const PRIVATE_KEY_OPTIONS = {
|
||||
alias: "k",
|
||||
describe: "Custom private key to sign transactions",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
type: "string",
|
||||
} as const;
|
||||
|
||||
|
@ -86,7 +85,7 @@ export const RPC_OPTIONS = {
|
|||
alias: "r",
|
||||
describe: "Override default rpc endpoint url",
|
||||
type: "string",
|
||||
required: false,
|
||||
demandOption: false,
|
||||
} as const;
|
||||
|
||||
export const GOVERNANCE_CHAIN = CHAIN_ID_SOLANA;
|
||||
|
|
|
@ -1,58 +1,57 @@
|
|||
import { ethers } from "ethers";
|
||||
import { NETWORKS } from "./networks";
|
||||
import { encode, Encoding, impossible, Payload, typeWidth } from "./vaa";
|
||||
import axios from "axios";
|
||||
import * as celo from "@celo-tools/celo-ethers-wrapper";
|
||||
import { solidityKeccak256 } from "ethers/lib/utils";
|
||||
import {
|
||||
BridgeImplementation__factory,
|
||||
Implementation__factory,
|
||||
NFTBridgeImplementation__factory,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/ethers-contracts";
|
||||
import {
|
||||
CHAINS,
|
||||
CONTRACTS,
|
||||
Contracts,
|
||||
EVMChainName,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import {
|
||||
BridgeImplementation__factory,
|
||||
Implementation__factory,
|
||||
NFTBridgeImplementation__factory,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/ethers-contracts";
|
||||
import axios from "axios";
|
||||
import { ethers } from "ethers";
|
||||
import { solidityKeccak256 } from "ethers/lib/utils";
|
||||
import { NETWORKS } from "./networks";
|
||||
import { Network } from "./utils";
|
||||
import { Encoding, Payload, encode, impossible, typeWidth } from "./vaa";
|
||||
|
||||
const _IMPLEMENTATION_SLOT =
|
||||
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
|
||||
|
||||
export async function query_contract_evm(
|
||||
network: "MAINNET" | "TESTNET" | "DEVNET",
|
||||
network: Network,
|
||||
chain: EVMChainName,
|
||||
module: "Core" | "NFTBridge" | "TokenBridge",
|
||||
contract_address: string | undefined,
|
||||
_rpc: string | undefined
|
||||
): Promise<object> {
|
||||
let n = NETWORKS[network][chain];
|
||||
let rpc: string | undefined = _rpc ?? n.rpc;
|
||||
if (rpc === undefined) {
|
||||
const n = NETWORKS[network][chain];
|
||||
const rpc: string | undefined = _rpc ?? n.rpc;
|
||||
if (!rpc) {
|
||||
throw Error(`No ${network} rpc defined for ${chain} (see networks.ts)`);
|
||||
}
|
||||
|
||||
let contracts: Contracts = CONTRACTS[network][chain];
|
||||
|
||||
const contracts: Contracts = CONTRACTS[network][chain];
|
||||
const provider = new ethers.providers.JsonRpcProvider(rpc);
|
||||
|
||||
let result: any = {};
|
||||
|
||||
const result: any = {};
|
||||
switch (module) {
|
||||
case "Core":
|
||||
contract_address = contract_address ? contract_address : contracts.core;
|
||||
if (contract_address === undefined) {
|
||||
if (!contract_address) {
|
||||
throw Error(`Unknown core contract on ${network} for ${chain}`);
|
||||
}
|
||||
|
||||
const core = Implementation__factory.connect(contract_address, provider);
|
||||
result.address = contract_address;
|
||||
result.currentGuardianSetIndex = await core.getCurrentGuardianSetIndex();
|
||||
let guardianSetsPromise = Promise.all(
|
||||
const guardianSetsPromise = Promise.all(
|
||||
[...Array(result.currentGuardianSetIndex + 1).keys()].map((i) =>
|
||||
core.getGuardianSet(i)
|
||||
)
|
||||
);
|
||||
let [
|
||||
const [
|
||||
guardianSetExpiry,
|
||||
chainId,
|
||||
evmChainId,
|
||||
|
@ -84,7 +83,7 @@ export async function query_contract_evm(
|
|||
result.isInitialized = await core.isInitialized(result.implementation);
|
||||
result.guardianSet = {};
|
||||
|
||||
for (let [i, guardianSet] of guardianSets.entries()) {
|
||||
for (const [i, guardianSet] of guardianSets.entries()) {
|
||||
result.guardianSet[i] = {
|
||||
keys: guardianSet[0],
|
||||
expiry: guardianSet[1],
|
||||
|
@ -112,7 +111,7 @@ export async function query_contract_evm(
|
|||
await tb.bridgeContracts(c_id),
|
||||
])
|
||||
);
|
||||
let [
|
||||
const [
|
||||
wormhole,
|
||||
implementationSlotTb,
|
||||
tokenImplementation,
|
||||
|
@ -150,7 +149,7 @@ export async function query_contract_evm(
|
|||
result.WETH = WETH;
|
||||
result.registrations = {};
|
||||
|
||||
for (let [c_name, c] of registrations) {
|
||||
for (const [c_name, c] of registrations) {
|
||||
result.registrations[c_name] = c;
|
||||
}
|
||||
break;
|
||||
|
@ -174,7 +173,7 @@ export async function query_contract_evm(
|
|||
await nb.bridgeContracts(c_id),
|
||||
])
|
||||
);
|
||||
let [
|
||||
const [
|
||||
wormholeNb,
|
||||
implementationSlotNb,
|
||||
tokenImplementationNb,
|
||||
|
@ -209,7 +208,7 @@ export async function query_contract_evm(
|
|||
result.governanceContract = governanceContractNb;
|
||||
result.registrations = {};
|
||||
|
||||
for (let [c_name, c] of registrationsNb) {
|
||||
for (const [c_name, c] of registrationsNb) {
|
||||
result.registrations[c_name] = c;
|
||||
}
|
||||
break;
|
||||
|
@ -221,20 +220,19 @@ export async function query_contract_evm(
|
|||
}
|
||||
|
||||
export async function getImplementation(
|
||||
network: "MAINNET" | "TESTNET" | "DEVNET",
|
||||
network: Network,
|
||||
chain: EVMChainName,
|
||||
module: "Core" | "NFTBridge" | "TokenBridge",
|
||||
contract_address: string | undefined,
|
||||
_rpc: string | undefined
|
||||
): Promise<ethers.BigNumber> {
|
||||
let n = NETWORKS[network][chain];
|
||||
let rpc: string | undefined = _rpc ?? n.rpc;
|
||||
if (rpc === undefined) {
|
||||
const n = NETWORKS[network][chain];
|
||||
const rpc: string | undefined = _rpc ?? n.rpc;
|
||||
if (!rpc) {
|
||||
throw Error(`No ${network} rpc defined for ${chain} (see networks.ts)`);
|
||||
}
|
||||
|
||||
let contracts: Contracts = CONTRACTS[network][chain];
|
||||
|
||||
const contracts: Contracts = CONTRACTS[network][chain];
|
||||
switch (module) {
|
||||
case "Core":
|
||||
contract_address = contract_address ? contract_address : contracts.core;
|
||||
|
@ -253,6 +251,10 @@ export async function getImplementation(
|
|||
impossible(module);
|
||||
}
|
||||
|
||||
if (!contract_address) {
|
||||
throw Error(`Unknown ${module} contract on ${network} for ${chain}`);
|
||||
}
|
||||
|
||||
return (
|
||||
await getStorageAt(rpc, contract_address, _IMPLEMENTATION_SLOT, ["address"])
|
||||
)[0];
|
||||
|
@ -261,23 +263,23 @@ export async function getImplementation(
|
|||
export async function execute_evm(
|
||||
payload: Payload,
|
||||
vaa: Buffer,
|
||||
network: "MAINNET" | "TESTNET" | "DEVNET",
|
||||
network: Network,
|
||||
chain: EVMChainName,
|
||||
contract_address: string | undefined,
|
||||
_rpc: string | undefined
|
||||
) {
|
||||
let n = NETWORKS[network][chain];
|
||||
let rpc: string | undefined = _rpc ?? n.rpc;
|
||||
if (rpc === undefined) {
|
||||
const n = NETWORKS[network][chain];
|
||||
const rpc: string | undefined = _rpc ?? n.rpc;
|
||||
if (!rpc) {
|
||||
throw Error(`No ${network} rpc defined for ${chain} (see networks.ts)`);
|
||||
}
|
||||
|
||||
if (!n.key) {
|
||||
throw Error(`No ${network} key defined for ${chain} (see networks.ts)`);
|
||||
}
|
||||
let key: string = n.key;
|
||||
|
||||
let contracts: Contracts = CONTRACTS[network][chain];
|
||||
|
||||
const key: string = n.key;
|
||||
const contracts: Contracts = CONTRACTS[network][chain];
|
||||
let provider: ethers.providers.JsonRpcProvider;
|
||||
let signer: ethers.Wallet;
|
||||
if (chain === "celo") {
|
||||
|
@ -294,9 +296,9 @@ export async function execute_evm(
|
|||
// testnet (or devnet), they might require additional guards
|
||||
let overrides: ethers.Overrides = {};
|
||||
if (chain === "karura" || chain == "acala") {
|
||||
overrides = await getKaruraGasParams(n.rpc);
|
||||
overrides = await getKaruraGasParams(rpc);
|
||||
} else if (chain === "polygon") {
|
||||
let feeData = await provider.getFeeData();
|
||||
const feeData = await provider.getFeeData();
|
||||
overrides = {
|
||||
maxFeePerGas: feeData.maxFeePerGas?.mul(50) || undefined,
|
||||
maxPriorityFeePerGas: feeData.maxPriorityFeePerGas?.mul(50) || undefined,
|
||||
|
@ -306,13 +308,13 @@ export async function execute_evm(
|
|||
}
|
||||
|
||||
switch (payload.module) {
|
||||
case "Core":
|
||||
case "Core": {
|
||||
contract_address = contract_address ? contract_address : contracts.core;
|
||||
if (contract_address === undefined) {
|
||||
throw Error(`Unknown core contract on ${network} for ${chain}`);
|
||||
}
|
||||
let c = new Implementation__factory(signer);
|
||||
let cb = c.attach(contract_address);
|
||||
const c = new Implementation__factory(signer);
|
||||
const cb = c.attach(contract_address);
|
||||
switch (payload.type) {
|
||||
case "GuardianSetUpgrade":
|
||||
console.log("Submitting new guardian set");
|
||||
|
@ -335,16 +337,18 @@ export async function execute_evm(
|
|||
default:
|
||||
impossible(payload);
|
||||
}
|
||||
|
||||
break;
|
||||
case "NFTBridge":
|
||||
}
|
||||
case "NFTBridge": {
|
||||
contract_address = contract_address
|
||||
? contract_address
|
||||
: contracts.nft_bridge;
|
||||
if (contract_address === undefined) {
|
||||
throw Error(`Unknown nft bridge contract on ${network} for ${chain}`);
|
||||
}
|
||||
let n = new NFTBridgeImplementation__factory(signer);
|
||||
let nb = n.attach(contract_address);
|
||||
const n = new NFTBridgeImplementation__factory(signer);
|
||||
const nb = n.attach(contract_address);
|
||||
switch (payload.type) {
|
||||
case "ContractUpgrade":
|
||||
console.log("Upgrading contract");
|
||||
|
@ -372,16 +376,18 @@ export async function execute_evm(
|
|||
default:
|
||||
impossible(payload);
|
||||
}
|
||||
|
||||
break;
|
||||
case "TokenBridge":
|
||||
}
|
||||
case "TokenBridge": {
|
||||
contract_address = contract_address
|
||||
? contract_address
|
||||
: contracts.token_bridge;
|
||||
if (contract_address === undefined) {
|
||||
throw Error(`Unknown token bridge contract on ${network} for ${chain}`);
|
||||
}
|
||||
let t = new BridgeImplementation__factory(signer);
|
||||
let tb = t.attach(contract_address);
|
||||
const t = new BridgeImplementation__factory(signer);
|
||||
const tb = t.attach(contract_address);
|
||||
switch (payload.type) {
|
||||
case "ContractUpgrade":
|
||||
console.log("Upgrading contract");
|
||||
|
@ -419,9 +425,10 @@ export async function execute_evm(
|
|||
break;
|
||||
default:
|
||||
impossible(payload);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
impossible(payload);
|
||||
}
|
||||
|
@ -440,7 +447,7 @@ export async function execute_evm(
|
|||
* @param rpc the JSON RPC endpoint (needs to be hardhat of anvil)
|
||||
* @param contract_address address of the core bridge contract
|
||||
* @param guardian_addresses addresses of the desired guardian set to upgrade to
|
||||
* @param new_guardian_set_index if specified, the new guardian set will be
|
||||
* @param newGuardianSetIndex if specified, the new guardian set will be
|
||||
* written into this guardian set index, and the guardian set index of the
|
||||
* contract changed to it.
|
||||
* If unspecified, then the current guardian set index will be overridden.
|
||||
|
@ -452,16 +459,14 @@ export async function hijack_evm(
|
|||
rpc: string,
|
||||
contract_address: string,
|
||||
guardian_addresses: string[],
|
||||
new_guardian_set_index: number | undefined
|
||||
newGuardianSetIndex: number | undefined
|
||||
): Promise<void> {
|
||||
const GUARDIAN_SETS_SLOT = 0x02;
|
||||
const GUARDIAN_SET_INDEX_SLOT = 0x3;
|
||||
|
||||
const provider = new ethers.providers.JsonRpcProvider(rpc);
|
||||
const core = Implementation__factory.connect(contract_address, provider);
|
||||
let guardianSetIndex: number;
|
||||
let guardianSetExpiry: number;
|
||||
[guardianSetIndex, guardianSetExpiry] = await getStorageAt(
|
||||
let [guardianSetIndex, guardianSetExpiry] = await getStorageAt(
|
||||
rpc,
|
||||
contract_address,
|
||||
GUARDIAN_SET_INDEX_SLOT,
|
||||
|
@ -472,21 +477,22 @@ export async function hijack_evm(
|
|||
console.log(`Current guardian set (index ${guardianSetIndex}):`);
|
||||
console.log(current_set[0]);
|
||||
|
||||
if (new_guardian_set_index !== undefined) {
|
||||
if (newGuardianSetIndex !== undefined) {
|
||||
await setStorageAt(
|
||||
rpc,
|
||||
contract_address,
|
||||
GUARDIAN_SET_INDEX_SLOT,
|
||||
["uint32", "uint32"],
|
||||
[new_guardian_set_index, guardianSetExpiry]
|
||||
[newGuardianSetIndex, guardianSetExpiry]
|
||||
);
|
||||
guardianSetIndex = await core.getCurrentGuardianSetIndex();
|
||||
if (new_guardian_set_index !== guardianSetIndex) {
|
||||
if (newGuardianSetIndex !== guardianSetIndex) {
|
||||
throw Error("Failed to update guardian set index.");
|
||||
} else {
|
||||
console.log(`Guardian set index updated to ${new_guardian_set_index}`);
|
||||
console.log(`Guardian set index updated to ${newGuardianSetIndex}`);
|
||||
}
|
||||
}
|
||||
|
||||
const addresses_slot = computeMappingElemSlot(
|
||||
GUARDIAN_SETS_SLOT,
|
||||
guardianSetIndex
|
||||
|
@ -621,7 +627,7 @@ async function getStorageAt(
|
|||
rpc
|
||||
).getStorageAt(contract_address, storage_slot);
|
||||
let val = ethers.BigNumber.from(string_val);
|
||||
let ret: any[] = [];
|
||||
const ret: any[] = [];
|
||||
// we decode the elements one by one, by shifting down the stuff we've parsed already
|
||||
types.forEach((typ) => {
|
||||
const padded = ethers.utils.defaultAbiCoder.encode(["uint256"], [val]);
|
||||
|
@ -699,15 +705,19 @@ export async function setStorageAt(
|
|||
).data;
|
||||
}
|
||||
|
||||
async function maybeUnsupported<T>(
|
||||
const maybeUnsupported = async <T>(
|
||||
query: Promise<T>
|
||||
): Promise<T | "unsupported"> {
|
||||
): Promise<T | "unsupported"> => {
|
||||
try {
|
||||
return await query;
|
||||
return query;
|
||||
} catch (e) {
|
||||
if (e.reason === "unsupported") {
|
||||
return e.reason;
|
||||
if (isUnsupportedError(e)) {
|
||||
return "unsupported";
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const isUnsupportedError = (e: any): e is { reason: string } =>
|
||||
e && typeof e === "object" && "reason" in e && e.reason === "unsupported";
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import { CONTRACTS } from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import { getNetworkInfo, Network } from "@injectivelabs/networks";
|
||||
import {
|
||||
getNetworkInfo,
|
||||
Network as InjectiveNetwork,
|
||||
} from "@injectivelabs/networks";
|
||||
import {
|
||||
ChainRestAuthApi,
|
||||
createTransaction,
|
||||
|
@ -10,43 +13,44 @@ import {
|
|||
import { DEFAULT_STD_FEE, getStdFee } from "@injectivelabs/utils";
|
||||
import { fromUint8Array } from "js-base64";
|
||||
import { NETWORKS } from "./networks";
|
||||
import { Network } from "./utils";
|
||||
import { impossible, Payload } from "./vaa";
|
||||
|
||||
export async function execute_injective(
|
||||
payload: Payload,
|
||||
vaa: Buffer,
|
||||
environment: "MAINNET" | "TESTNET" | "DEVNET"
|
||||
network: Network
|
||||
) {
|
||||
if (environment === "DEVNET") {
|
||||
if (network === "DEVNET") {
|
||||
throw new Error("Injective is not supported in DEVNET");
|
||||
}
|
||||
const chainName = "injective";
|
||||
let n = NETWORKS[environment][chainName];
|
||||
if (!n.key) {
|
||||
throw Error(`No ${environment} key defined for Injective`);
|
||||
const chain = "injective";
|
||||
let { key } = NETWORKS[network][chain];
|
||||
if (!key) {
|
||||
throw Error(`No ${network} key defined for Injective`);
|
||||
}
|
||||
let contracts = CONTRACTS[environment][chainName];
|
||||
const endPoint =
|
||||
environment === "MAINNET" ? Network.MainnetK8s : Network.TestnetK8s;
|
||||
|
||||
const network = getNetworkInfo(endPoint);
|
||||
const walletPKHash = n.key;
|
||||
const walletPK = PrivateKey.fromMnemonic(walletPKHash);
|
||||
let contracts = CONTRACTS[network][chain];
|
||||
const endPoint =
|
||||
network === "MAINNET"
|
||||
? InjectiveNetwork.MainnetK8s
|
||||
: InjectiveNetwork.TestnetK8s;
|
||||
|
||||
const networkInfo = getNetworkInfo(endPoint);
|
||||
const walletPK = PrivateKey.fromMnemonic(key);
|
||||
const walletInjAddr = walletPK.toBech32();
|
||||
const walletPublicKey = walletPK.toPublicKey().toBase64();
|
||||
|
||||
let target_contract: string;
|
||||
let action: string;
|
||||
let execute_msg: object;
|
||||
let action: "submit_v_a_a" | "submit_vaa";
|
||||
let execute_msg: { vaa: string } | { data: string };
|
||||
|
||||
switch (payload.module) {
|
||||
case "Core":
|
||||
case "Core": {
|
||||
target_contract = contracts.core;
|
||||
action = "submit_v_a_a";
|
||||
execute_msg = {
|
||||
[action]: {
|
||||
vaa: fromUint8Array(vaa),
|
||||
},
|
||||
vaa: fromUint8Array(vaa),
|
||||
};
|
||||
switch (payload.type) {
|
||||
case "GuardianSetUpgrade":
|
||||
|
@ -60,20 +64,21 @@ export async function execute_injective(
|
|||
default:
|
||||
impossible(payload);
|
||||
}
|
||||
|
||||
break;
|
||||
case "NFTBridge":
|
||||
if (contracts.nft_bridge === undefined) {
|
||||
}
|
||||
case "NFTBridge": {
|
||||
if (!contracts.nft_bridge) {
|
||||
// NOTE: this code can safely be removed once the injective NFT bridge is
|
||||
// released, but it's fine for it to stay, as the condition will just be
|
||||
// skipped once 'contracts.nft_bridge' is defined
|
||||
throw new Error("NFT bridge not supported yet for injective");
|
||||
}
|
||||
|
||||
target_contract = contracts.nft_bridge;
|
||||
action = "submit_vaa";
|
||||
execute_msg = {
|
||||
[action]: {
|
||||
data: fromUint8Array(vaa),
|
||||
},
|
||||
data: fromUint8Array(vaa),
|
||||
};
|
||||
switch (payload.type) {
|
||||
case "ContractUpgrade":
|
||||
|
@ -90,18 +95,19 @@ export async function execute_injective(
|
|||
default:
|
||||
impossible(payload);
|
||||
}
|
||||
|
||||
break;
|
||||
case "TokenBridge":
|
||||
}
|
||||
case "TokenBridge": {
|
||||
console.log("contracts:", contracts);
|
||||
if (contracts.token_bridge === undefined) {
|
||||
if (!contracts.token_bridge) {
|
||||
throw new Error("contracts.token_bridge is undefined");
|
||||
}
|
||||
|
||||
target_contract = contracts.token_bridge;
|
||||
action = "submit_vaa";
|
||||
execute_msg = {
|
||||
[action]: {
|
||||
data: fromUint8Array(vaa),
|
||||
},
|
||||
data: fromUint8Array(vaa),
|
||||
};
|
||||
switch (payload.type) {
|
||||
case "ContractUpgrade":
|
||||
|
@ -122,30 +128,32 @@ export async function execute_injective(
|
|||
throw Error("Can't complete payload 3 transfer from CLI");
|
||||
default:
|
||||
impossible(payload);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
action = impossible(payload);
|
||||
target_contract = impossible(payload);
|
||||
execute_msg = impossible(payload);
|
||||
}
|
||||
|
||||
console.log("execute_msg", execute_msg);
|
||||
console.log("execute_msg", { [action]: execute_msg });
|
||||
const transaction = MsgExecuteContractCompat.fromJSON({
|
||||
sender: walletInjAddr,
|
||||
contractAddress: target_contract,
|
||||
exec: {
|
||||
action,
|
||||
msg: {
|
||||
...execute_msg[action],
|
||||
...execute_msg,
|
||||
},
|
||||
},
|
||||
});
|
||||
console.log("transaction:", transaction);
|
||||
|
||||
const accountDetails = await new ChainRestAuthApi(network.rest).fetchAccount(
|
||||
walletInjAddr
|
||||
);
|
||||
const accountDetails = await new ChainRestAuthApi(
|
||||
networkInfo.rest
|
||||
).fetchAccount(walletInjAddr);
|
||||
const { signBytes, txRaw } = createTransaction({
|
||||
message: transaction,
|
||||
memo: "",
|
||||
|
@ -156,21 +164,20 @@ export async function execute_injective(
|
|||
accountDetails.account.base_account.account_number,
|
||||
10
|
||||
),
|
||||
chainId: network.chainId,
|
||||
chainId: networkInfo.chainId,
|
||||
});
|
||||
console.log("txRaw", txRaw);
|
||||
|
||||
// Sign transaction
|
||||
console.log("sign transaction...");
|
||||
/** Sign transaction */
|
||||
const sig = await walletPK.sign(Buffer.from(signBytes));
|
||||
|
||||
/** Append Signatures */
|
||||
// Append Signatures
|
||||
txRaw.signatures = [sig];
|
||||
|
||||
const txService = new TxGrpcApi(network.grpc);
|
||||
|
||||
// Simulate transaction
|
||||
console.log("simulate transaction...");
|
||||
/** Simulate transaction */
|
||||
const txService = new TxGrpcApi(networkInfo.grpc);
|
||||
try {
|
||||
const simulationResponse = await txService.simulate(txRaw);
|
||||
console.log(
|
||||
|
@ -183,8 +190,8 @@ export async function execute_injective(
|
|||
return;
|
||||
}
|
||||
|
||||
// Broadcast transaction
|
||||
console.log("broadcast transaction...");
|
||||
/** Broadcast transaction */
|
||||
const txResponse = await txService.broadcast(txRaw);
|
||||
console.log("txResponse", txResponse);
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
declare module "near-seed-phrase" {
|
||||
export function parseSeedPhrase(
|
||||
seedPhrase: string,
|
||||
derivationPath?: string
|
||||
): {
|
||||
seedPhrase: string;
|
||||
secretKey: string;
|
||||
publicKey: string;
|
||||
};
|
||||
}
|
|
@ -1,128 +1,34 @@
|
|||
import { impossible, Payload } from "./vaa";
|
||||
import { NETWORKS } from "./networks";
|
||||
import { CONTRACTS } from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import { parseSeedPhrase, generateSeedPhrase } from "near-seed-phrase";
|
||||
import BN from "bn.js";
|
||||
import { readFileSync } from "fs";
|
||||
import { Account, connect, KeyPair } from "near-api-js";
|
||||
import { InMemoryKeyStore } from "near-api-js/lib/key_stores";
|
||||
import { NETWORKS } from "./networks";
|
||||
import { Network } from "./utils";
|
||||
import { impossible, Payload } from "./vaa";
|
||||
|
||||
function default_near_args(argv) {
|
||||
let network = argv["n"].toUpperCase();
|
||||
let contracts = CONTRACTS[network]["near"];
|
||||
let n = NETWORKS[network]["near"];
|
||||
|
||||
if (!("rpc" in argv)) {
|
||||
argv["rpc"] = n["rpc"];
|
||||
}
|
||||
|
||||
if (!("target" in argv) && "module" in argv) {
|
||||
if (argv["module"] == "Core") {
|
||||
argv["target"] = contracts["core"];
|
||||
console.log("Setting target to core");
|
||||
}
|
||||
if (argv["module"] == "TokenBridge") {
|
||||
argv["target"] = contracts["token_bridge"];
|
||||
console.log("Setting target to token_bridge");
|
||||
}
|
||||
}
|
||||
|
||||
if (!("key" in argv)) {
|
||||
if (n["key"]) {
|
||||
argv["key"] = n["key"];
|
||||
}
|
||||
}
|
||||
|
||||
if (!("key" in argv)) {
|
||||
if ("mnemonic" in argv) {
|
||||
let k = parseSeedPhrase(argv["mnemonic"]);
|
||||
argv["key"] = k["secretKey"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function deploy_near(argv) {
|
||||
default_near_args(argv);
|
||||
|
||||
let masterKey = KeyPair.fromString(argv["key"]);
|
||||
let keyStore = new InMemoryKeyStore();
|
||||
keyStore.setKey(argv["networkId"], argv["account"], masterKey);
|
||||
keyStore.setKey(argv["networkId"], argv["target"], masterKey);
|
||||
|
||||
let near = await connect({
|
||||
deps: {
|
||||
keyStore,
|
||||
},
|
||||
networkId: argv["networkId"],
|
||||
nodeUrl: argv["rpc"],
|
||||
headers: {},
|
||||
});
|
||||
|
||||
let masterAccount = new Account(near.connection, argv["account"]);
|
||||
let targetAccount = new Account(near.connection, argv["target"]);
|
||||
|
||||
console.log(argv);
|
||||
|
||||
if ("attach" in argv) {
|
||||
console.log(
|
||||
"Sending money: " +
|
||||
argv["target"] +
|
||||
" from " +
|
||||
argv["account"] +
|
||||
" being sent " +
|
||||
argv["attach"]
|
||||
);
|
||||
console.log(await masterAccount.sendMoney(argv["target"], argv["attach"]));
|
||||
}
|
||||
|
||||
console.log("deploying contract");
|
||||
console.log(await targetAccount.deployContract(readFileSync(argv["file"])));
|
||||
}
|
||||
|
||||
export async function upgrade_near(argv) {
|
||||
default_near_args(argv);
|
||||
|
||||
let masterKey = KeyPair.fromString(argv["key"]);
|
||||
let keyStore = new InMemoryKeyStore();
|
||||
keyStore.setKey(argv["networkId"], argv["account"], masterKey);
|
||||
|
||||
let near = await connect({
|
||||
deps: {
|
||||
keyStore,
|
||||
},
|
||||
networkId: argv["networkId"],
|
||||
nodeUrl: argv["rpc"],
|
||||
headers: {},
|
||||
});
|
||||
|
||||
let masterAccount = new Account(near.connection, argv["account"]);
|
||||
|
||||
let result = await masterAccount.functionCall({
|
||||
contractId: argv["target"],
|
||||
methodName: "update_contract",
|
||||
args: readFileSync(argv["file"]),
|
||||
attachedDeposit: new BN("22797900000000000000000000"),
|
||||
gas: new BN("300000000000000"),
|
||||
});
|
||||
console.log(result);
|
||||
}
|
||||
|
||||
export async function execute_near(
|
||||
export const execute_near = async (
|
||||
payload: Payload,
|
||||
vaa: string,
|
||||
network: "MAINNET" | "TESTNET" | "DEVNET"
|
||||
) {
|
||||
let n = NETWORKS[network]["near"];
|
||||
let contracts = CONTRACTS[network]["near"];
|
||||
network: Network
|
||||
): Promise<void> => {
|
||||
const { rpc, key, networkId, deployerAccount } = NETWORKS[network].near;
|
||||
if (!key) {
|
||||
throw Error(`No ${network} key defined for NEAR`);
|
||||
}
|
||||
|
||||
let target_contract = "";
|
||||
if (!rpc) {
|
||||
throw Error(`No ${network} rpc defined for NEAR`);
|
||||
}
|
||||
|
||||
const contracts = CONTRACTS[network].near;
|
||||
let target_contract: string;
|
||||
let numSubmits = 1;
|
||||
|
||||
switch (payload.module) {
|
||||
case "Core":
|
||||
if (contracts.core === undefined) {
|
||||
throw new Error("Core bridge not supported yet for near");
|
||||
case "Core": {
|
||||
if (!contracts.core) {
|
||||
throw new Error(`Core bridge address not defined for NEAR ${network}`);
|
||||
}
|
||||
|
||||
target_contract = contracts.core;
|
||||
switch (payload.type) {
|
||||
case "GuardianSetUpgrade":
|
||||
|
@ -137,10 +43,12 @@ export async function execute_near(
|
|||
impossible(payload);
|
||||
}
|
||||
break;
|
||||
case "NFTBridge":
|
||||
if (contracts.nft_bridge === undefined) {
|
||||
throw new Error("NFT bridge not supported yet for near");
|
||||
}
|
||||
case "NFTBridge": {
|
||||
if (!contracts.nft_bridge) {
|
||||
throw new Error(`NFT bridge address not defined for NEAR ${network}`);
|
||||
}
|
||||
|
||||
numSubmits = 2;
|
||||
target_contract = contracts.nft_bridge;
|
||||
switch (payload.type) {
|
||||
|
@ -158,11 +66,14 @@ export async function execute_near(
|
|||
default:
|
||||
impossible(payload);
|
||||
}
|
||||
|
||||
break;
|
||||
case "TokenBridge":
|
||||
if (contracts.token_bridge === undefined) {
|
||||
throw new Error("Token bridge not supported yet for near");
|
||||
}
|
||||
case "TokenBridge": {
|
||||
if (!contracts.token_bridge) {
|
||||
throw new Error(`Token bridge address not defined for NEAR ${network}`);
|
||||
}
|
||||
|
||||
numSubmits = 2;
|
||||
target_contract = contracts.token_bridge;
|
||||
switch (payload.type) {
|
||||
|
@ -184,37 +95,32 @@ export async function execute_near(
|
|||
throw Error("Can't complete payload 3 transfer from CLI");
|
||||
default:
|
||||
impossible(payload);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
impossible(payload);
|
||||
}
|
||||
|
||||
let key = KeyPair.fromString(n.key);
|
||||
|
||||
let keyStore = new InMemoryKeyStore();
|
||||
keyStore.setKey(n.networkId, n.deployerAccount, key);
|
||||
|
||||
let near = await connect({
|
||||
const keyStore = new InMemoryKeyStore();
|
||||
keyStore.setKey(networkId, deployerAccount, KeyPair.fromString(key));
|
||||
const near = await connect({
|
||||
keyStore,
|
||||
networkId: n.networkId,
|
||||
nodeUrl: n.rpc,
|
||||
networkId,
|
||||
nodeUrl: rpc,
|
||||
headers: {},
|
||||
});
|
||||
let nearAccount = new Account(near.connection, n.deployerAccount);
|
||||
const nearAccount = new Account(near.connection, deployerAccount);
|
||||
|
||||
console.log("submitting vaa the first time");
|
||||
let result1 = await nearAccount.functionCall({
|
||||
const result1 = await nearAccount.functionCall({
|
||||
contractId: target_contract,
|
||||
methodName: "submit_vaa",
|
||||
args: {
|
||||
vaa: vaa,
|
||||
},
|
||||
args: { vaa },
|
||||
attachedDeposit: new BN("100000000000000000000000"),
|
||||
gas: new BN("300000000000000"),
|
||||
});
|
||||
|
||||
if (numSubmits <= 1) {
|
||||
console.log("Hash: " + result1.transaction.hash);
|
||||
return;
|
||||
|
@ -224,16 +130,13 @@ export async function execute_near(
|
|||
// The first time, it checks if it has been seen at all.
|
||||
// The second time, it executes.
|
||||
console.log("submitting vaa the second time");
|
||||
let result2 = await nearAccount.functionCall({
|
||||
const result2 = await nearAccount.functionCall({
|
||||
contractId: target_contract,
|
||||
methodName: "submit_vaa",
|
||||
args: {
|
||||
vaa: vaa,
|
||||
},
|
||||
args: { vaa },
|
||||
attachedDeposit: new BN("100000000000000000000000"),
|
||||
gas: new BN("300000000000000"),
|
||||
});
|
||||
|
||||
let txHash = result1.transaction.hash + ":" + result2.transaction.hash;
|
||||
const txHash = result1.transaction.hash + ":" + result2.transaction.hash;
|
||||
console.log("Hash: " + txHash);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -2,24 +2,34 @@ import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
|
|||
import { calculateFee } from "@cosmjs/stargate";
|
||||
import { getSigningCosmWasmClient } from "@sei-js/core";
|
||||
|
||||
import { impossible, Payload } from "./vaa";
|
||||
import { NETWORKS } from "./networks";
|
||||
import { CONTRACTS } from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import { NETWORKS } from "./networks";
|
||||
import { Network } from "./utils";
|
||||
import { impossible, Payload } from "./vaa";
|
||||
|
||||
export async function execute_sei(
|
||||
payload: Payload,
|
||||
vaa: Buffer,
|
||||
network: "MAINNET" | "TESTNET" | "DEVNET"
|
||||
network: Network
|
||||
) {
|
||||
let chain = "sei";
|
||||
let n = NETWORKS[network][chain];
|
||||
let contracts = CONTRACTS[network][chain];
|
||||
const contracts = CONTRACTS[network].sei;
|
||||
const { rpc, key } = NETWORKS[network].sei;
|
||||
if (!key) {
|
||||
throw Error(`No ${network} key defined for NEAR`);
|
||||
}
|
||||
|
||||
if (!rpc) {
|
||||
throw Error(`No ${network} rpc defined for NEAR`);
|
||||
}
|
||||
|
||||
let target_contract: string;
|
||||
let execute_msg: object;
|
||||
|
||||
switch (payload.module) {
|
||||
case "Core":
|
||||
case "Core": {
|
||||
if (!contracts.core) {
|
||||
throw new Error(`Core bridge address not defined for Sei ${network}`);
|
||||
}
|
||||
|
||||
target_contract = contracts.core;
|
||||
// sigh...
|
||||
execute_msg = {
|
||||
|
@ -39,14 +49,17 @@ export async function execute_sei(
|
|||
default:
|
||||
impossible(payload);
|
||||
}
|
||||
|
||||
break;
|
||||
case "NFTBridge":
|
||||
if (contracts.nft_bridge === undefined) {
|
||||
}
|
||||
case "NFTBridge": {
|
||||
if (!contracts.nft_bridge) {
|
||||
// NOTE: this code can safely be removed once the sei NFT bridge is
|
||||
// released, but it's fine for it to stay, as the condition will just be
|
||||
// skipped once 'contracts.nft_bridge' is defined
|
||||
throw new Error("NFT bridge not supported yet for sei");
|
||||
throw new Error("NFT bridge not supported yet for Sei");
|
||||
}
|
||||
|
||||
target_contract = contracts.nft_bridge;
|
||||
execute_msg = {
|
||||
submit_vaa: {
|
||||
|
@ -68,8 +81,14 @@ export async function execute_sei(
|
|||
default:
|
||||
impossible(payload);
|
||||
}
|
||||
|
||||
break;
|
||||
case "TokenBridge":
|
||||
}
|
||||
case "TokenBridge": {
|
||||
if (!contracts.token_bridge) {
|
||||
throw new Error(`Token bridge address not defined for Sei ${network}`);
|
||||
}
|
||||
|
||||
target_contract = contracts.token_bridge;
|
||||
execute_msg = {
|
||||
submit_vaa: {
|
||||
|
@ -97,17 +116,19 @@ export async function execute_sei(
|
|||
impossible(payload);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
target_contract = impossible(payload);
|
||||
execute_msg = impossible(payload);
|
||||
}
|
||||
|
||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(n.key, {
|
||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(key, {
|
||||
prefix: "sei",
|
||||
});
|
||||
const [account] = await wallet.getAccounts();
|
||||
const client = await getSigningCosmWasmClient(n.rpc, wallet);
|
||||
const client = await getSigningCosmWasmClient(rpc, wallet);
|
||||
const fee = calculateFee(300000, "0.1usei");
|
||||
const result = await client.execute(
|
||||
account.address,
|
||||
|
|
|
@ -14,6 +14,7 @@ console.info = function (x: string) {
|
|||
info(x);
|
||||
}
|
||||
};
|
||||
|
||||
const warn = console.warn;
|
||||
console.warn = function (x: string) {
|
||||
if (
|
||||
|
|
|
@ -1,17 +1,8 @@
|
|||
import * as web3s from "@solana/web3.js";
|
||||
import { NETWORKS } from "./networks";
|
||||
import { impossible, Payload, VAA } from "./vaa";
|
||||
import base58 from "bs58";
|
||||
import { postVaaSolanaWithRetry } from "@certusone/wormhole-sdk/lib/esm/solana";
|
||||
import {
|
||||
CHAINS,
|
||||
CONTRACTS,
|
||||
SolanaChainName,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import {
|
||||
createUpgradeContractInstruction as createWormholeUpgradeContractInstruction,
|
||||
createUpgradeGuardianSetInstruction,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/solana/wormhole";
|
||||
createRegisterChainInstruction as createNFTBridgeRegisterChainInstruction,
|
||||
createUpgradeContractInstruction as createNFTBridgeUpgradeContractInstruction,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/solana/nftBridge";
|
||||
import {
|
||||
createCompleteTransferNativeInstruction,
|
||||
createCompleteTransferWrappedInstruction,
|
||||
|
@ -20,9 +11,18 @@ import {
|
|||
createUpgradeContractInstruction as createTokenBridgeUpgradeContractInstruction,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/solana/tokenBridge";
|
||||
import {
|
||||
createRegisterChainInstruction as createNFTBridgeRegisterChainInstruction,
|
||||
createUpgradeContractInstruction as createNFTBridgeUpgradeContractInstruction,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/solana/nftBridge";
|
||||
createUpgradeGuardianSetInstruction,
|
||||
createUpgradeContractInstruction as createWormholeUpgradeContractInstruction,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/solana/wormhole";
|
||||
import {
|
||||
CHAINS,
|
||||
CONTRACTS,
|
||||
SolanaChainName,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import * as web3s from "@solana/web3.js";
|
||||
import base58 from "bs58";
|
||||
import { NETWORKS } from "./networks";
|
||||
import { Payload, VAA, impossible } from "./vaa";
|
||||
|
||||
export async function execute_solana(
|
||||
v: VAA<Payload>,
|
||||
|
@ -30,20 +30,36 @@ export async function execute_solana(
|
|||
network: "MAINNET" | "TESTNET" | "DEVNET",
|
||||
chain: SolanaChainName
|
||||
) {
|
||||
const { rpc, key } = NETWORKS[network][chain];
|
||||
if (!key) {
|
||||
throw Error(`No ${network} key defined for NEAR`);
|
||||
}
|
||||
|
||||
if (!rpc) {
|
||||
throw Error(`No ${network} rpc defined for NEAR`);
|
||||
}
|
||||
|
||||
const connection = setupConnection(rpc);
|
||||
const from = web3s.Keypair.fromSecretKey(base58.decode(key));
|
||||
|
||||
const contracts = CONTRACTS[network][chain];
|
||||
if (!contracts.core) {
|
||||
throw new Error(`Core bridge address not defined for ${chain} ${network}`);
|
||||
}
|
||||
|
||||
if (!contracts.nft_bridge) {
|
||||
throw new Error(`NFT bridge address not defined for ${chain} ${network}`);
|
||||
}
|
||||
|
||||
if (!contracts.token_bridge) {
|
||||
throw new Error(`Token bridge address not defined for ${chain} ${network}`);
|
||||
}
|
||||
|
||||
const bridgeId = new web3s.PublicKey(contracts.core);
|
||||
const tokenBridgeId = new web3s.PublicKey(contracts.token_bridge);
|
||||
const nftBridgeId = new web3s.PublicKey(contracts.nft_bridge);
|
||||
|
||||
let ix: web3s.TransactionInstruction;
|
||||
const connection = setupConnection(NETWORKS[network][chain].rpc);
|
||||
const bridgeId = new web3s.PublicKey(CONTRACTS[network][chain].core);
|
||||
const tokenBridgeId =
|
||||
CONTRACTS[network][chain].token_bridge &&
|
||||
new web3s.PublicKey(CONTRACTS[network][chain].token_bridge);
|
||||
const nftBridgeId =
|
||||
CONTRACTS[network][chain].nft_bridge &&
|
||||
new web3s.PublicKey(CONTRACTS[network][chain].nft_bridge);
|
||||
|
||||
const from = web3s.Keypair.fromSecretKey(
|
||||
base58.decode(NETWORKS[network][chain].key)
|
||||
);
|
||||
|
||||
switch (v.payload.module) {
|
||||
case "Core":
|
||||
if (bridgeId === undefined) {
|
||||
|
@ -194,6 +210,5 @@ export async function execute_solana(
|
|||
console.log("SIGNATURE", signature);
|
||||
}
|
||||
|
||||
function setupConnection(rpc: string): web3s.Connection {
|
||||
return new web3s.Connection(rpc, "confirmed");
|
||||
}
|
||||
const setupConnection = (rpc: string): web3s.Connection =>
|
||||
new web3s.Connection(rpc, "confirmed");
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { spawnSync } from 'child_process';
|
||||
import { spawnSync } from "child_process";
|
||||
|
||||
export const validator_args = {
|
||||
export const VALIDATOR_OPTIONS = {
|
||||
alias: "a",
|
||||
type: "string",
|
||||
array: true,
|
||||
|
@ -8,9 +8,9 @@ export const validator_args = {
|
|||
describe: "Additional args to validator",
|
||||
} as const;
|
||||
|
||||
export function runCommand(baseCmd: string, args: readonly string[]) {
|
||||
const args_string = args.map(a => `"${a}"`).join(" ");
|
||||
export const runCommand = (baseCmd: string, args: readonly string[]): void => {
|
||||
const args_string = args.map((a) => `"${a}"`).join(" ");
|
||||
const cmd = `${baseCmd} ${args_string}`;
|
||||
console.log("\x1b[33m%s\x1b[0m", cmd);
|
||||
spawnSync(cmd, { shell: true, stdio: "inherit" });
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import { parseAttestMetaVaa } from "@certusone/wormhole-sdk/lib/esm/vaa/tokenBridge";
|
||||
import { getForeignAssetSui } from "@certusone/wormhole-sdk/lib/esm/token_bridge/getForeignAsset";
|
||||
import { getWrappedCoinType } from "@certusone/wormhole-sdk/lib/esm/sui";
|
||||
import {
|
||||
createWrappedOnSui,
|
||||
createWrappedOnSuiPrepare,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/token_bridge/createWrapped";
|
||||
import { assertChain } from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import { getWrappedCoinType } from "@certusone/wormhole-sdk/lib/esm/sui";
|
||||
import { getForeignAssetSui } from "@certusone/wormhole-sdk/lib/esm/token_bridge/getForeignAsset";
|
||||
import {
|
||||
CHAIN_ID_SUI,
|
||||
CHAIN_ID_TO_NAME,
|
||||
CONTRACTS,
|
||||
assertChain,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import { parseAttestMetaVaa } from "@certusone/wormhole-sdk/lib/esm/vaa/tokenBridge";
|
||||
import { SUI_CLOCK_OBJECT_ID, TransactionBlock } from "@mysten/sui.js";
|
||||
import { Network } from "../utils";
|
||||
import { Payload, impossible } from "../vaa";
|
||||
|
@ -23,6 +23,7 @@ import {
|
|||
isSuiCreateEvent,
|
||||
isSuiPublishEvent,
|
||||
registerChain,
|
||||
setMaxGasBudgetDevnet,
|
||||
} from "./utils";
|
||||
|
||||
export const submit = async (
|
||||
|
@ -114,10 +115,16 @@ export const submit = async (
|
|||
);
|
||||
setMaxGasBudgetDevnet(network, prepareTx);
|
||||
const prepareRes = await executeTransactionBlock(signer, prepareTx);
|
||||
assertSuccess(prepareRes, "Prepare registration failed.");
|
||||
const coinPackageId =
|
||||
prepareRes.objectChanges.find(isSuiPublishEvent).packageId;
|
||||
console.log(` Digest ${prepareRes.digest}`);
|
||||
assertSuccess(prepareRes, "Prepare registration failed.");
|
||||
|
||||
// Get the coin package ID from the publish event
|
||||
const coinPackageId =
|
||||
prepareRes.objectChanges?.find(isSuiPublishEvent)?.packageId;
|
||||
if (!coinPackageId) {
|
||||
throw new Error("Publish coin failed.");
|
||||
}
|
||||
|
||||
console.log(` Published to ${coinPackageId}`);
|
||||
console.log(` Type ${getWrappedCoinType(coinPackageId)}`);
|
||||
|
||||
|
@ -130,10 +137,17 @@ export const submit = async (
|
|||
|
||||
console.log("\n[2/2] Registering asset...");
|
||||
const wrappedAssetSetup = prepareRes.objectChanges
|
||||
.filter(isSuiCreateEvent)
|
||||
?.filter(isSuiCreateEvent)
|
||||
.find((e) =>
|
||||
/create_wrapped::WrappedAssetSetup/.test(e.objectType)
|
||||
);
|
||||
if (!wrappedAssetSetup) {
|
||||
throw new Error(
|
||||
"Wrapped asset setup not found. Object changes: " +
|
||||
JSON.stringify(prepareRes.objectChanges)
|
||||
);
|
||||
}
|
||||
|
||||
const completeTx = await createWrappedOnSui(
|
||||
provider,
|
||||
coreBridgeStateObjectId,
|
||||
|
@ -191,21 +205,6 @@ export const submit = async (
|
|||
console.warn = consoleWarnTemp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Currently, (Sui SDK version 0.32.2 and Sui 1.0.0 testnet), there is a
|
||||
* mismatch in the max gas budget that causes an error when executing a
|
||||
* transaction. Because these values are hardcoded, we set the max gas budget
|
||||
* as a temporary workaround.
|
||||
* @param network
|
||||
* @param tx
|
||||
*/
|
||||
const setMaxGasBudgetDevnet = (network: Network, tx: TransactionBlock) => {
|
||||
if (network === "DEVNET") {
|
||||
// Avoid Error checking transaction input objects: GasBudgetTooHigh { gas_budget: 50000000000, max_budget: 10000000000 }
|
||||
tx.setGasBudget(10000000000);
|
||||
}
|
||||
};
|
||||
|
||||
const sleep = (ms: number): Promise<void> => {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
getPublishedObjectChanges,
|
||||
normalizeSuiAddress,
|
||||
} from "@mysten/sui.js";
|
||||
import { DynamicFieldPage } from "@mysten/sui.js/dist/types/dynamic_fields";
|
||||
import { NETWORKS } from "../networks";
|
||||
import { Network } from "../utils";
|
||||
import { Payload, VAA, parse, serialiseVAA } from "../vaa";
|
||||
|
@ -71,7 +72,7 @@ export const findOwnedObjectByType = async (
|
|||
throw new SuiRpcValidationError(res);
|
||||
}
|
||||
|
||||
const object = res.data.find((d) => d.data.type === type);
|
||||
const object = res.data.find((d) => d.data?.type === type);
|
||||
|
||||
if (!object && res.hasNextPage) {
|
||||
return findOwnedObjectByType(
|
||||
|
@ -83,19 +84,31 @@ export const findOwnedObjectByType = async (
|
|||
} else if (!object && !res.hasNextPage) {
|
||||
return null;
|
||||
} else {
|
||||
return object.data.objectId;
|
||||
return object?.data?.objectId ?? null;
|
||||
}
|
||||
};
|
||||
|
||||
export const getCreatedObjects = (
|
||||
res: SuiTransactionBlockResponse
|
||||
): { type: string; objectId: string; owner: string }[] => {
|
||||
return res.objectChanges.filter(isSuiCreateEvent).map((e) => ({
|
||||
type: e.objectType,
|
||||
objectId: e.objectId,
|
||||
owner: e.owner["AddressOwner"] || e.owner["ObjectOwner"] || e.owner,
|
||||
}));
|
||||
};
|
||||
): { type: string; objectId: string; owner: string }[] =>
|
||||
res.objectChanges?.filter(isSuiCreateEvent).map((e) => {
|
||||
let owner: string;
|
||||
if (typeof e.owner === "string") {
|
||||
owner = e.owner;
|
||||
} else if ("AddressOwner" in e.owner) {
|
||||
owner = e.owner.AddressOwner;
|
||||
} else if ("ObjectOwner" in e.owner) {
|
||||
owner = e.owner.ObjectOwner;
|
||||
} else {
|
||||
owner = "Shared";
|
||||
}
|
||||
|
||||
return {
|
||||
owner,
|
||||
type: e.objectType,
|
||||
objectId: e.objectId,
|
||||
};
|
||||
}) ?? [];
|
||||
|
||||
export const getOwnedObjectId = async (
|
||||
provider: JsonRpcProvider,
|
||||
|
@ -127,7 +140,7 @@ export const getOwnedObjectId = async (
|
|||
|
||||
const objects = res.data.filter((o) => o.data?.objectId);
|
||||
if (objects.length === 1) {
|
||||
return objects[0].data?.objectId;
|
||||
return objects[0].data?.objectId ?? null;
|
||||
} else if (objects.length > 1) {
|
||||
const objectsStr = JSON.stringify(objects, null, 2);
|
||||
throw new Error(
|
||||
|
@ -148,25 +161,27 @@ export const getOwnedObjectId = async (
|
|||
};
|
||||
|
||||
// TODO(kp): remove this once it's in the sdk
|
||||
export async function getPackageId(
|
||||
export const getPackageId = async (
|
||||
provider: JsonRpcProvider,
|
||||
objectId: string
|
||||
): Promise<string> {
|
||||
): Promise<string> => {
|
||||
let currentPackage;
|
||||
let nextCursor;
|
||||
do {
|
||||
const dynamicFields = await provider.getDynamicFields({
|
||||
const dynamicFields: DynamicFieldPage = await provider.getDynamicFields({
|
||||
parentId: objectId,
|
||||
cursor: nextCursor,
|
||||
});
|
||||
currentPackage = dynamicFields.data.find((field) =>
|
||||
field.name.type.endsWith("CurrentPackage")
|
||||
currentPackage = dynamicFields.data.find(
|
||||
(field: DynamicFieldPage["data"][number]) =>
|
||||
field.name.type.endsWith("CurrentPackage")
|
||||
);
|
||||
nextCursor = dynamicFields.hasNextPage ? dynamicFields.nextCursor : null;
|
||||
} while (nextCursor && !currentPackage);
|
||||
if (!currentPackage) {
|
||||
throw new Error("CurrentPackage not found");
|
||||
}
|
||||
|
||||
const obj = await provider.getObject({
|
||||
id: currentPackage.objectId,
|
||||
options: {
|
||||
|
@ -180,8 +195,9 @@ export async function getPackageId(
|
|||
if (!packageId) {
|
||||
throw new Error("Unable to get current package");
|
||||
}
|
||||
|
||||
return packageId;
|
||||
}
|
||||
};
|
||||
|
||||
export const getProvider = (
|
||||
network?: Network,
|
||||
|
@ -191,7 +207,7 @@ export const getProvider = (
|
|||
throw new Error("Must provide network or RPC to initialize provider");
|
||||
}
|
||||
|
||||
rpc = rpc || NETWORKS[network]["sui"].rpc;
|
||||
rpc = rpc || NETWORKS[network!]["sui"].rpc;
|
||||
if (!rpc) {
|
||||
throw new Error(`No default RPC found for Sui ${network}`);
|
||||
}
|
||||
|
@ -265,7 +281,7 @@ export const getUpgradeCapObjectId = async (
|
|||
);
|
||||
if (objects.length === 1) {
|
||||
// We've found the object we're looking for
|
||||
return objects[0].data?.objectId;
|
||||
return objects[0].data?.objectId ?? null;
|
||||
} else if (objects.length > 1) {
|
||||
const objectsStr = JSON.stringify(objects, null, 2);
|
||||
throw new Error(
|
||||
|
@ -285,26 +301,21 @@ export const isSameType = (a: string, b: string) => {
|
|||
};
|
||||
|
||||
export const isSuiCreateEvent = <
|
||||
T extends SuiTransactionBlockResponse["objectChanges"][number],
|
||||
T extends NonNullable<SuiTransactionBlockResponse["objectChanges"]>[number],
|
||||
K extends Extract<T, { type: "created" }>
|
||||
>(
|
||||
event: T
|
||||
): event is K => {
|
||||
return event.type === "created";
|
||||
};
|
||||
): event is K => event?.type === "created";
|
||||
|
||||
export const isSuiPublishEvent = <
|
||||
T extends SuiTransactionBlockResponse["objectChanges"][number],
|
||||
T extends NonNullable<SuiTransactionBlockResponse["objectChanges"]>[number],
|
||||
K extends Extract<T, { type: "published" }>
|
||||
>(
|
||||
event: T
|
||||
): event is K => {
|
||||
return event.type === "published";
|
||||
};
|
||||
): event is K => event?.type === "published";
|
||||
|
||||
export const isValidSuiAddress = (objectId: string): boolean => {
|
||||
return /^(0x)?[0-9a-f]{1,64}$/.test(objectId);
|
||||
};
|
||||
export const isValidSuiAddress = (objectId: string): boolean =>
|
||||
/^(0x)?[0-9a-f]{1,64}$/.test(objectId);
|
||||
|
||||
// todo(aki): this needs to correctly handle types such as
|
||||
// 0x2::dynamic_field::Field<0x3c6d386861470e6f9cb35f3c91f69e6c1f1737bd5d217ca06a15f582e1dc1ce3::state::MigrationControl, bool>
|
||||
|
@ -385,3 +396,21 @@ export const registerChain = async (
|
|||
|
||||
return tx;
|
||||
};
|
||||
|
||||
/**
|
||||
* Currently, (Sui SDK version 0.32.2 and Sui 1.0.0 testnet), there is a
|
||||
* mismatch in the max gas budget that causes an error when executing a
|
||||
* transaction. Because these values are hardcoded, we set the max gas budget
|
||||
* as a temporary workaround.
|
||||
* @param network
|
||||
* @param tx
|
||||
*/
|
||||
export const setMaxGasBudgetDevnet = (
|
||||
network: Network,
|
||||
tx: TransactionBlock
|
||||
) => {
|
||||
if (network === "DEVNET") {
|
||||
// Avoid Error checking transaction input objects: GasBudgetTooHigh { gas_budget: 50000000000, max_budget: 10000000000 }
|
||||
tx.setGasBudget(10000000000);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
import {
|
||||
CONTRACTS,
|
||||
TerraChainName,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import {
|
||||
Coin,
|
||||
Fee,
|
||||
|
@ -5,33 +9,30 @@ import {
|
|||
MnemonicKey,
|
||||
MsgExecuteContract,
|
||||
} from "@terra-money/terra.js";
|
||||
import { fromUint8Array } from "js-base64";
|
||||
import { impossible, Payload } from "./vaa";
|
||||
import { NETWORKS } from "./networks";
|
||||
import axios from "axios";
|
||||
import {
|
||||
CONTRACTS,
|
||||
TerraChainName,
|
||||
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import { fromUint8Array } from "js-base64";
|
||||
import { NETWORKS } from "./networks";
|
||||
import { Network } from "./utils";
|
||||
import { Payload, impossible } from "./vaa";
|
||||
|
||||
export async function execute_terra(
|
||||
payload: Payload,
|
||||
vaa: Buffer,
|
||||
network: "MAINNET" | "TESTNET" | "DEVNET",
|
||||
network: Network,
|
||||
chain: TerraChainName
|
||||
) {
|
||||
let n = NETWORKS[network][chain];
|
||||
let contracts = CONTRACTS[network][chain];
|
||||
): Promise<void> {
|
||||
const { rpc, key, chain_id } = NETWORKS[network][chain];
|
||||
const contracts = CONTRACTS[network][chain];
|
||||
|
||||
const terra = new LCDClient({
|
||||
URL: n.rpc,
|
||||
chainID: n.chain_id,
|
||||
URL: rpc,
|
||||
chainID: chain_id,
|
||||
isClassic: chain === "terra",
|
||||
});
|
||||
|
||||
const wallet = terra.wallet(
|
||||
new MnemonicKey({
|
||||
mnemonic: n.key,
|
||||
mnemonic: key,
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -39,7 +40,13 @@ export async function execute_terra(
|
|||
let execute_msg: object;
|
||||
|
||||
switch (payload.module) {
|
||||
case "Core":
|
||||
case "Core": {
|
||||
if (!contracts.core) {
|
||||
throw new Error(
|
||||
`Core bridge address not defined for ${chain} ${network}`
|
||||
);
|
||||
}
|
||||
|
||||
target_contract = contracts.core;
|
||||
// sigh...
|
||||
execute_msg = {
|
||||
|
@ -59,14 +66,17 @@ export async function execute_terra(
|
|||
default:
|
||||
impossible(payload);
|
||||
}
|
||||
|
||||
break;
|
||||
case "NFTBridge":
|
||||
if (contracts.nft_bridge === undefined) {
|
||||
}
|
||||
case "NFTBridge": {
|
||||
if (!contracts.nft_bridge) {
|
||||
// NOTE: this code can safely be removed once the terra NFT bridge is
|
||||
// released, but it's fine for it to stay, as the condition will just be
|
||||
// skipped once 'contracts.nft_bridge' is defined
|
||||
throw new Error("NFT bridge not supported yet for terra");
|
||||
throw new Error(`NFT bridge not supported yet for ${chain}`);
|
||||
}
|
||||
|
||||
target_contract = contracts.nft_bridge;
|
||||
execute_msg = {
|
||||
submit_vaa: {
|
||||
|
@ -88,8 +98,16 @@ export async function execute_terra(
|
|||
default:
|
||||
impossible(payload);
|
||||
}
|
||||
|
||||
break;
|
||||
case "TokenBridge":
|
||||
}
|
||||
case "TokenBridge": {
|
||||
if (!contracts.token_bridge) {
|
||||
throw new Error(
|
||||
`Token bridge address not defined for ${chain} ${network}`
|
||||
);
|
||||
}
|
||||
|
||||
target_contract = contracts.token_bridge;
|
||||
execute_msg = {
|
||||
submit_vaa: {
|
||||
|
@ -115,9 +133,10 @@ export async function execute_terra(
|
|||
throw Error("Can't complete payload 3 transfer from CLI");
|
||||
default:
|
||||
impossible(payload);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
target_contract = impossible(payload);
|
||||
execute_msg = impossible(payload);
|
||||
|
@ -131,11 +150,9 @@ export async function execute_terra(
|
|||
);
|
||||
|
||||
const feeDenoms = ["uluna"];
|
||||
|
||||
const gasPrices = await axios
|
||||
.get("https://terra-classic-fcd.publicnode.com/v1/txs/gas_prices")
|
||||
.then((result) => result.data);
|
||||
|
||||
const feeEstimate = await terra.tx.estimateFee(
|
||||
[
|
||||
{
|
||||
|
@ -151,7 +168,7 @@ export async function execute_terra(
|
|||
}
|
||||
);
|
||||
|
||||
wallet
|
||||
return wallet
|
||||
.createAndSignTx({
|
||||
msgs: [transaction],
|
||||
memo: "",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Parser } from "binary-parser"
|
||||
import * as elliptic from "elliptic"
|
||||
import { BigNumber, ethers } from "ethers"
|
||||
import { solidityKeccak256 } from "ethers/lib/utils"
|
||||
import * as elliptic from "elliptic"
|
||||
|
||||
export interface Signature {
|
||||
guardianSetIndex: number
|
||||
|
@ -103,7 +103,7 @@ export function parse(buffer: Buffer): VAA<Payload | Other> {
|
|||
if (payload === null) {
|
||||
payload = {type: "Other", hex: Buffer.from(vaa.payload).toString("hex"), ascii: Buffer.from(vaa.payload).toString('utf8')}
|
||||
} else {
|
||||
delete payload['tokenURILength']
|
||||
delete (payload as any)['tokenURILength']
|
||||
}
|
||||
var myVAA = { ...vaa, payload }
|
||||
|
||||
|
@ -829,7 +829,7 @@ function nftBridgeTransferParser(): P<NFTBridgeTransfer> {
|
|||
.array("tokenURI", {
|
||||
type: "uint8",
|
||||
lengthInBytes: function() {
|
||||
return this.tokenURILength
|
||||
return (this as any).tokenURILength
|
||||
},
|
||||
formatter: (arr: Uint8Array) => Buffer.from(arr).toString("utf8")
|
||||
})
|
||||
|
@ -868,7 +868,7 @@ function serialiseNFTBridgeTransfer(payload: NFTBridgeTransfer): string {
|
|||
// in, this function just throws. If the enum type is extended with new cases,
|
||||
// the call to this function will then fail to compile, drawing attention to an
|
||||
// unhandled case somewhere.
|
||||
export function impossible(a: never): any {
|
||||
export function impossible(a: never): never {
|
||||
throw new Error(`Impossible: ${a}`)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { CONTRACTS } from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import {
|
||||
Coin,
|
||||
Fee,
|
||||
|
@ -6,35 +7,44 @@ import {
|
|||
MsgExecuteContract,
|
||||
} from "@xpla/xpla.js";
|
||||
import { fromUint8Array } from "js-base64";
|
||||
import { impossible, Payload } from "./vaa";
|
||||
import { NETWORKS } from "./networks";
|
||||
import { CONTRACTS } from "@certusone/wormhole-sdk/lib/esm/utils/consts";
|
||||
import { Network } from "./utils";
|
||||
import { Payload, impossible } from "./vaa";
|
||||
|
||||
export async function execute_xpla(
|
||||
payload: Payload,
|
||||
vaa: Buffer,
|
||||
network: "MAINNET" | "TESTNET" | "DEVNET"
|
||||
network: Network
|
||||
) {
|
||||
const chain = "xpla";
|
||||
let n = NETWORKS[network][chain];
|
||||
let contracts = CONTRACTS[network][chain];
|
||||
const { rpc, key, chain_id } = NETWORKS[network].xpla;
|
||||
const contracts = CONTRACTS[network].xpla;
|
||||
if (!key) {
|
||||
throw Error(`No ${network} key defined for XPLA`);
|
||||
}
|
||||
|
||||
if (!rpc) {
|
||||
throw Error(`No ${network} rpc defined for XPLA`);
|
||||
}
|
||||
|
||||
const client = new LCDClient({
|
||||
URL: n.rpc,
|
||||
chainID: n.chain_id,
|
||||
URL: rpc,
|
||||
chainID: chain_id,
|
||||
});
|
||||
|
||||
const wallet = client.wallet(
|
||||
new MnemonicKey({
|
||||
mnemonic: n.key,
|
||||
mnemonic: key,
|
||||
})
|
||||
);
|
||||
|
||||
let target_contract: string;
|
||||
let execute_msg: object;
|
||||
|
||||
switch (payload.module) {
|
||||
case "Core":
|
||||
case "Core": {
|
||||
if (!contracts.core) {
|
||||
throw new Error(`Core bridge address not defined for XPLA ${network}`);
|
||||
}
|
||||
|
||||
target_contract = contracts.core;
|
||||
execute_msg = {
|
||||
submit_v_a_a: {
|
||||
|
@ -53,14 +63,17 @@ export async function execute_xpla(
|
|||
default:
|
||||
impossible(payload);
|
||||
}
|
||||
|
||||
break;
|
||||
case "NFTBridge":
|
||||
if (contracts.nft_bridge === undefined) {
|
||||
}
|
||||
case "NFTBridge": {
|
||||
if (!contracts.nft_bridge) {
|
||||
// NOTE: this code can safely be removed once the terra NFT bridge is
|
||||
// released, but it's fine for it to stay, as the condition will just be
|
||||
// skipped once 'contracts.nft_bridge' is defined
|
||||
throw new Error("NFT bridge not supported yet for XPLA");
|
||||
}
|
||||
|
||||
target_contract = contracts.nft_bridge;
|
||||
execute_msg = {
|
||||
submit_vaa: {
|
||||
|
@ -82,8 +95,14 @@ export async function execute_xpla(
|
|||
default:
|
||||
impossible(payload);
|
||||
}
|
||||
|
||||
break;
|
||||
case "TokenBridge":
|
||||
}
|
||||
case "TokenBridge": {
|
||||
if (!contracts.token_bridge) {
|
||||
throw new Error(`Token bridge address not defined for XPLA ${network}`);
|
||||
}
|
||||
|
||||
target_contract = contracts.token_bridge;
|
||||
execute_msg = {
|
||||
submit_vaa: {
|
||||
|
@ -109,9 +128,10 @@ export async function execute_xpla(
|
|||
throw Error("Can't complete payload 3 transfer from CLI");
|
||||
default:
|
||||
impossible(payload);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
target_contract = impossible(payload);
|
||||
execute_msg = impossible(payload);
|
||||
|
@ -121,15 +141,13 @@ export async function execute_xpla(
|
|||
wallet.key.accAddress,
|
||||
target_contract,
|
||||
execute_msg,
|
||||
{ axpla: 1700000000000000000 }
|
||||
{ axpla: "1700000000000000000" }
|
||||
);
|
||||
|
||||
const feeDenoms = ["axpla"];
|
||||
|
||||
// const gasPrices = await axios
|
||||
// .get("https://dimension-lcd.xpla.dev/v1/txs/gas_prices")
|
||||
// .then((result) => result.data);
|
||||
|
||||
const feeEstimate = await client.tx.estimateFee(
|
||||
[
|
||||
{
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
"outDir": "./build",
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue