[evm] Wormhole receiver deploy all (#1009)
* Add verification logic for evm set wormhole address instruction * Minor improvements and cleanup on contract manager evm * Batch deploy script * Better docs on verification * Fix zkSync deployment script and update documentation
This commit is contained in:
parent
caca2da9e2
commit
e422fb9321
|
@ -5,6 +5,7 @@ import { createHash } from "crypto";
|
||||||
import { DefaultStore } from "../src/store";
|
import { DefaultStore } from "../src/store";
|
||||||
import {
|
import {
|
||||||
CosmosUpgradeContract,
|
CosmosUpgradeContract,
|
||||||
|
EvmSetWormholeAddress,
|
||||||
EvmUpgradeContract,
|
EvmUpgradeContract,
|
||||||
getProposalInstructions,
|
getProposalInstructions,
|
||||||
MultisigParser,
|
MultisigParser,
|
||||||
|
@ -17,7 +18,8 @@ import {
|
||||||
} from "@pythnetwork/client/lib/cluster";
|
} from "@pythnetwork/client/lib/cluster";
|
||||||
import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
|
import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
|
||||||
import { AccountMeta, Keypair, PublicKey } from "@solana/web3.js";
|
import { AccountMeta, Keypair, PublicKey } from "@solana/web3.js";
|
||||||
import { EvmContract } from "../src/contracts/evm";
|
import { EvmContract, WormholeEvmContract } from "../src/contracts/evm";
|
||||||
|
import Web3 from "web3";
|
||||||
|
|
||||||
const parser = yargs(hideBin(process.argv))
|
const parser = yargs(hideBin(process.argv))
|
||||||
.scriptName("check_proposal.ts")
|
.scriptName("check_proposal.ts")
|
||||||
|
@ -55,6 +57,42 @@ async function main() {
|
||||||
|
|
||||||
for (const instruction of parsedInstructions) {
|
for (const instruction of parsedInstructions) {
|
||||||
if (instruction instanceof WormholeMultisigInstruction) {
|
if (instruction instanceof WormholeMultisigInstruction) {
|
||||||
|
if (instruction.governanceAction instanceof EvmSetWormholeAddress) {
|
||||||
|
console.log(
|
||||||
|
`Verifying EVM set wormhole address on ${instruction.governanceAction.targetChainId}`
|
||||||
|
);
|
||||||
|
for (const chain of Object.values(DefaultStore.chains)) {
|
||||||
|
if (
|
||||||
|
chain instanceof EvmChain &&
|
||||||
|
chain.isMainnet() === (cluster === "mainnet-beta") &&
|
||||||
|
chain.wormholeChainName ===
|
||||||
|
instruction.governanceAction.targetChainId
|
||||||
|
) {
|
||||||
|
const address = instruction.governanceAction.address;
|
||||||
|
const contract = new WormholeEvmContract(chain, address);
|
||||||
|
const currentIndex = await contract.getCurrentGuardianSetIndex();
|
||||||
|
const guardianSet = await contract.getGuardianSet();
|
||||||
|
|
||||||
|
const proxyContract = new EvmContract(chain, address);
|
||||||
|
const proxyCode = await proxyContract.getCode();
|
||||||
|
const receiverImplementation =
|
||||||
|
await proxyContract.getImplementationAddress();
|
||||||
|
const implementationCode = await new EvmContract(
|
||||||
|
chain,
|
||||||
|
receiverImplementation
|
||||||
|
).getCode();
|
||||||
|
const proxyDigest = Web3.utils.keccak256(proxyCode);
|
||||||
|
const implementationDigest =
|
||||||
|
Web3.utils.keccak256(implementationCode);
|
||||||
|
const guardianSetDigest = Web3.utils.keccak256(
|
||||||
|
JSON.stringify(guardianSet)
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`Address:\t\t${address}\nproxy digest:\t\t${proxyDigest}\nimplementation digest:\t${implementationDigest} \nguardian set index:\t${currentIndex} \nguardian set:\t\t${guardianSetDigest}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (instruction.governanceAction instanceof EvmUpgradeContract) {
|
if (instruction.governanceAction instanceof EvmUpgradeContract) {
|
||||||
console.log(
|
console.log(
|
||||||
`Verifying EVM Upgrade Contract on ${instruction.governanceAction.targetChainId}`
|
`Verifying EVM Upgrade Contract on ${instruction.governanceAction.targetChainId}`
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
SetDataSources,
|
SetDataSources,
|
||||||
SetValidPeriod,
|
SetValidPeriod,
|
||||||
DataSource,
|
DataSource,
|
||||||
|
EvmSetWormholeAddress,
|
||||||
} from "xc_admin_common";
|
} from "xc_admin_common";
|
||||||
import { AptosClient } from "aptos";
|
import { AptosClient } from "aptos";
|
||||||
import Web3 from "web3";
|
import Web3 from "web3";
|
||||||
|
@ -40,7 +41,9 @@ export abstract class Chain extends Storable {
|
||||||
super();
|
super();
|
||||||
this.wormholeChainName = wormholeChainName as ChainName;
|
this.wormholeChainName = wormholeChainName as ChainName;
|
||||||
if (toChainId(this.wormholeChainName) === undefined)
|
if (toChainId(this.wormholeChainName) === undefined)
|
||||||
throw new Error(`Invalid chain name ${wormholeChainName}`);
|
throw new Error(
|
||||||
|
`Invalid chain name ${wormholeChainName}. Try rebuilding xc_admin_common package`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getId(): string {
|
getId(): string {
|
||||||
|
@ -270,6 +273,10 @@ export class EvmChain extends Chain {
|
||||||
return new EvmUpgradeContract(this.wormholeChainName, address).encode();
|
return new EvmUpgradeContract(this.wormholeChainName, address).encode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generateGovernanceSetWormholeAddressPayload(address: string): Buffer {
|
||||||
|
return new EvmSetWormholeAddress(this.wormholeChainName, address).encode();
|
||||||
|
}
|
||||||
|
|
||||||
toJson(): any {
|
toJson(): any {
|
||||||
return {
|
return {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
|
@ -294,6 +301,47 @@ export class EvmChain extends Chain {
|
||||||
}
|
}
|
||||||
return gasPrice;
|
return gasPrice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deploys a contract on this chain
|
||||||
|
* @param privateKey hex string of the 32 byte private key without the 0x prefix
|
||||||
|
* @param abi the abi of the contract, can be obtained from the compiled contract json file
|
||||||
|
* @param bytecode bytecode of the contract, can be obtained from the compiled contract json file
|
||||||
|
* @param deployArgs arguments to pass to the constructor
|
||||||
|
* @returns the address of the deployed contract
|
||||||
|
*/
|
||||||
|
async deploy(
|
||||||
|
privateKey: string,
|
||||||
|
abi: any,
|
||||||
|
bytecode: string,
|
||||||
|
deployArgs: any[]
|
||||||
|
): Promise<string> {
|
||||||
|
const web3 = new Web3(this.getRpcUrl());
|
||||||
|
const signer = web3.eth.accounts.privateKeyToAccount(privateKey);
|
||||||
|
web3.eth.accounts.wallet.add(signer);
|
||||||
|
const contract = new web3.eth.Contract(abi);
|
||||||
|
const deployTx = contract.deploy({ data: bytecode, arguments: deployArgs });
|
||||||
|
const gas = await deployTx.estimateGas();
|
||||||
|
const gasPrice = await this.getGasPrice();
|
||||||
|
const deployerBalance = await web3.eth.getBalance(signer.address);
|
||||||
|
const gasDiff = BigInt(gas) * BigInt(gasPrice) - BigInt(deployerBalance);
|
||||||
|
if (gasDiff > 0n) {
|
||||||
|
throw new Error(
|
||||||
|
`Insufficient funds to deploy contract. Need ${gas} (gas) * ${gasPrice} (gasPrice)= ${
|
||||||
|
BigInt(gas) * BigInt(gasPrice)
|
||||||
|
} wei, but only have ${deployerBalance} wei. We need ${
|
||||||
|
Number(gasDiff) / 10 ** 18
|
||||||
|
} ETH more.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const deployedContract = await deployTx.send({
|
||||||
|
from: signer.address,
|
||||||
|
gas,
|
||||||
|
gasPrice,
|
||||||
|
});
|
||||||
|
return deployedContract.options.address;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AptosChain extends Chain {
|
export class AptosChain extends Chain {
|
||||||
|
|
|
@ -303,39 +303,6 @@ export class EvmContract extends Contract {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async deploy(
|
|
||||||
chain: EvmChain,
|
|
||||||
privateKey: string,
|
|
||||||
abi: any,
|
|
||||||
bytecode: string
|
|
||||||
): Promise<EvmContract> {
|
|
||||||
const web3 = new Web3(chain.getRpcUrl());
|
|
||||||
const signer = web3.eth.accounts.privateKeyToAccount(privateKey);
|
|
||||||
web3.eth.accounts.wallet.add(signer);
|
|
||||||
const contract = new web3.eth.Contract(abi);
|
|
||||||
const deployTx = contract.deploy({ data: bytecode });
|
|
||||||
const gas = await deployTx.estimateGas();
|
|
||||||
const gasPrice = await chain.getGasPrice();
|
|
||||||
const deployerBalance = await web3.eth.getBalance(signer.address);
|
|
||||||
const gasDiff = BigInt(gas) * BigInt(gasPrice) - BigInt(deployerBalance);
|
|
||||||
if (gasDiff > 0n) {
|
|
||||||
throw new Error(
|
|
||||||
`Insufficient funds to deploy contract. Need ${gas} (gas) * ${gasPrice} (gasPrice)= ${
|
|
||||||
BigInt(gas) * BigInt(gasPrice)
|
|
||||||
} wei, but only have ${deployerBalance} wei. We need ${
|
|
||||||
Number(gasDiff) / 10 ** 18
|
|
||||||
} ETH more.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const deployedContract = await deployTx.send({
|
|
||||||
from: signer.address,
|
|
||||||
gas,
|
|
||||||
gasPrice,
|
|
||||||
});
|
|
||||||
return new EvmContract(chain, deployedContract.options.address);
|
|
||||||
}
|
|
||||||
|
|
||||||
getContract() {
|
getContract() {
|
||||||
const web3 = new Web3(this.chain.getRpcUrl());
|
const web3 = new Web3(this.chain.getRpcUrl());
|
||||||
const pythContract = new web3.eth.Contract(EXTENDED_PYTH_ABI, this.address);
|
const pythContract = new web3.eth.Contract(EXTENDED_PYTH_ABI, this.address);
|
||||||
|
|
|
@ -30,6 +30,10 @@ export abstract class WormholeContract {
|
||||||
for (let i = currentIndex; i < MAINNET_UPGRADE_VAAS.length; i++) {
|
for (let i = currentIndex; i < MAINNET_UPGRADE_VAAS.length; i++) {
|
||||||
const vaa = MAINNET_UPGRADE_VAAS[i];
|
const vaa = MAINNET_UPGRADE_VAAS[i];
|
||||||
await this.upgradeGuardianSets(senderPrivateKey, Buffer.from(vaa, "hex"));
|
await this.upgradeGuardianSets(senderPrivateKey, Buffer.from(vaa, "hex"));
|
||||||
|
// make sure the upgrade is complete before continuing
|
||||||
|
while ((await this.getCurrentGuardianSetIndex()) <= i) {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,20 +8,9 @@ repl.evalCode(
|
||||||
"import { loadHotWallet, Vault } from './src/governance';" +
|
"import { loadHotWallet, Vault } from './src/governance';" +
|
||||||
"import { SuiChain, CosmWasmChain, AptosChain, EvmChain } from './src/chains';" +
|
"import { SuiChain, CosmWasmChain, AptosChain, EvmChain } from './src/chains';" +
|
||||||
"import { SuiContract } from './src/contracts/sui';" +
|
"import { SuiContract } from './src/contracts/sui';" +
|
||||||
"import { CosmWasmContract } from './src/contracts/cosmwasm';" +
|
"import { WormholeCosmWasmContract, CosmWasmContract } from './src/contracts/cosmwasm';" +
|
||||||
"import { EvmContract } from './src/contracts/evm';" +
|
"import { WormholeEvmContract, EvmContract } from './src/contracts/evm';" +
|
||||||
"import { AptosContract } from './src/contracts/aptos';" +
|
"import { AptosContract } from './src/contracts/aptos';" +
|
||||||
"import { DefaultStore } from './src/store';" +
|
"import { DefaultStore } from './src/store';" +
|
||||||
"DefaultStore"
|
"DefaultStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
// import * as repl from 'node:repl';
|
|
||||||
// import { CosmWasmChain, Chains, ChainContracts } from './entities';
|
|
||||||
// // import { CHAINS_NETWORK_CONFIG } from './chains-manager/chains';
|
|
||||||
|
|
||||||
// const replServer = repl.start('Pyth shell> ')
|
|
||||||
// // const mnemonic = "salon myth guide analyst umbrella load arm first roast pelican stuff satoshi";
|
|
||||||
|
|
||||||
// replServer.context.CosmWasmChain = CosmWasmChain;
|
|
||||||
// replServer.context.Chains = Chains;
|
|
||||||
// replServer.context.ChainContracts = ChainContracts;
|
|
||||||
|
|
|
@ -137,13 +137,15 @@ We include artifacts required for verifying the contract in each release. To cre
|
||||||
|
|
||||||
```
|
```
|
||||||
npx sol-merger contracts/pyth/PythUpgradable.sol
|
npx sol-merger contracts/pyth/PythUpgradable.sol
|
||||||
|
npx sol-merger contracts/pyth/ReceiverImplementation.sol
|
||||||
npx truffle run stdjsonin PythUpgradable
|
npx truffle run stdjsonin PythUpgradable
|
||||||
|
npx truffle run stdjsonin ReceiverImplementation
|
||||||
```
|
```
|
||||||
|
|
||||||
These commands create the files `contracts/pyth/PythUpgradable_merged.sol` and `PythUpgradable-input.json` respectively.
|
These commands create the files `contracts/pyth/PythUpgradable_merged.sol`, `contracts/pyth/ReceiverImplementation_merged.sol`, `PythUpgradable-input.json`, and `ReceiverImplementation-input.json` respectively.
|
||||||
The first file is a flattened version of the contract, and the second file is the standard json input of the contract.
|
The `.sol` files are the flattened version of the contracts, and the `.json` files are the standard json input of the contracts.
|
||||||
|
|
||||||
Please include both of these in the verification folder of the release.
|
Please include all of these in the release.
|
||||||
|
|
||||||
## Verifying the contract
|
## Verifying the contract
|
||||||
|
|
||||||
|
@ -168,14 +170,13 @@ compile it to their binary format (zk-solc) and deploy it. As of this writing th
|
||||||
contract or a new contract do the following steps in addition to the steps described above:
|
contract or a new contract do the following steps in addition to the steps described above:
|
||||||
|
|
||||||
1. Update the [`hardhad.config.ts`](./hardhat.config.ts) file.
|
1. Update the [`hardhad.config.ts`](./hardhat.config.ts) file.
|
||||||
2. Add the configuration files to `truffle-config.js` and `.env.prod.<network>` file as described above. Truffle
|
2. Add the required chain configuration in the contract manager files as described above.
|
||||||
config is required as the above deployment script still works in changing the contract (except upgrades).
|
|
||||||
3. Run `npx hardhat clean && npx hardhat compile` to have a clean compile the contracts.
|
3. Run `npx hardhat clean && npx hardhat compile` to have a clean compile the contracts.
|
||||||
4. Prepare the enviornment:
|
4. Prepare the enviornment:
|
||||||
|
|
||||||
- Export the secret recovery phrase for the deployment account. Please store it in a file and read
|
- Export the secret recovery phrase for the deployment account. Please store it in a file and read
|
||||||
the file into `MNEMONIC` environment variable like so: `export MNEMONIC=$(cat path/to/mnemonic)`.
|
the file into `MNEMONIC` environment variable like so: `export MNEMONIC=$(cat path/to/mnemonic)`.
|
||||||
- Copy the correct env file (e.g: `.env.production.zksync`) to `.env`.
|
- Create the env settings by running `node create-env.js zksync` and verifying the `.env` file.
|
||||||
|
|
||||||
5. If you wish to deploy the contract run `npx hardhat deploy-zksync --network <network> --script deploy/zkSyncDeploy` to deploy it to the new network. Otherwise
|
5. If you wish to deploy the contract run `npx hardhat deploy-zksync --network <network> --script deploy/zkSyncDeploy` to deploy it to the new network. Otherwise
|
||||||
run `npx hardhat deploy-zksync --network <network> --script deploy/zkSyncDeployNewPythImpl.ts` to get a new implementation address. Then put it in
|
run `npx hardhat deploy-zksync --network <network> --script deploy/zkSyncDeployNewPythImpl.ts` to get a new implementation address. Then put it in
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { CHAINS } from "xc_admin_common";
|
||||||
import { assert } from "chai";
|
import { assert } from "chai";
|
||||||
import { writeFileSync } from "fs";
|
import { writeFileSync } from "fs";
|
||||||
|
|
||||||
|
const { getDefaultConfig } = require("../scripts/contractManagerConfig");
|
||||||
loadEnv("./");
|
loadEnv("./");
|
||||||
|
|
||||||
function envOrErr(name: string): string {
|
function envOrErr(name: string): string {
|
||||||
|
@ -36,9 +37,16 @@ export default async function (hre: HardhatRuntimeEnvironment) {
|
||||||
// await depositHandle.wait();
|
// await depositHandle.wait();
|
||||||
|
|
||||||
// Deploy WormholeReceiver contract.
|
// Deploy WormholeReceiver contract.
|
||||||
const initialSigners = JSON.parse(envOrErr("INIT_SIGNERS"));
|
|
||||||
const whGovernanceChainId = envOrErr("INIT_GOV_CHAIN_ID");
|
const {
|
||||||
const whGovernanceContract = envOrErr("INIT_GOV_CONTRACT"); // bytes32
|
wormholeGovernanceChainId,
|
||||||
|
wormholeGovernanceContract,
|
||||||
|
wormholeInitialSigners,
|
||||||
|
governanceEmitter,
|
||||||
|
governanceChainId,
|
||||||
|
emitterAddresses,
|
||||||
|
emitterChainIds,
|
||||||
|
} = getDefaultConfig(envOrErr("MIGRATIONS_NETWORK"));
|
||||||
|
|
||||||
const chainName = envOrErr("WORMHOLE_CHAIN_NAME");
|
const chainName = envOrErr("WORMHOLE_CHAIN_NAME");
|
||||||
const wormholeReceiverChainId = CHAINS[chainName];
|
const wormholeReceiverChainId = CHAINS[chainName];
|
||||||
|
@ -62,10 +70,10 @@ export default async function (hre: HardhatRuntimeEnvironment) {
|
||||||
"setup",
|
"setup",
|
||||||
[
|
[
|
||||||
receiverImplContract.address,
|
receiverImplContract.address,
|
||||||
initialSigners,
|
wormholeInitialSigners,
|
||||||
wormholeReceiverChainId,
|
wormholeReceiverChainId,
|
||||||
whGovernanceChainId,
|
wormholeGovernanceChainId,
|
||||||
whGovernanceContract,
|
wormholeGovernanceContract,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -79,18 +87,6 @@ export default async function (hre: HardhatRuntimeEnvironment) {
|
||||||
`Deployed WormholeReceiver on ${wormholeReceiverContract.address}`
|
`Deployed WormholeReceiver on ${wormholeReceiverContract.address}`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Deploy Pyth contract.
|
|
||||||
const emitterChainIds = [
|
|
||||||
envOrErr("SOLANA_CHAIN_ID"),
|
|
||||||
envOrErr("PYTHNET_CHAIN_ID"),
|
|
||||||
];
|
|
||||||
const emitterAddresses = [
|
|
||||||
envOrErr("SOLANA_EMITTER"),
|
|
||||||
envOrErr("PYTHNET_EMITTER"),
|
|
||||||
];
|
|
||||||
const governanceChainId = envOrErr("GOVERNANCE_CHAIN_ID");
|
|
||||||
const governanceEmitter = envOrErr("GOVERNANCE_EMITTER");
|
|
||||||
// Default value for this field is 0
|
|
||||||
const governanceInitialSequence = Number(
|
const governanceInitialSequence = Number(
|
||||||
process.env.GOVERNANCE_INITIAL_SEQUENCE ?? "0"
|
process.env.GOVERNANCE_INITIAL_SEQUENCE ?? "0"
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
/**
|
||||||
|
* This script deploys the receiver contracts on all the chains and creates a governance proposal to update the
|
||||||
|
* wormhole addresses to the deployed receiver contracts.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import yargs from "yargs";
|
||||||
|
import { hideBin } from "yargs/helpers";
|
||||||
|
import {
|
||||||
|
DefaultStore,
|
||||||
|
EvmChain,
|
||||||
|
loadHotWallet,
|
||||||
|
WormholeEvmContract,
|
||||||
|
} from "contract_manager";
|
||||||
|
import Web3 from "web3";
|
||||||
|
import { CHAINS } from "xc_admin_common";
|
||||||
|
import * as fs from "fs";
|
||||||
|
|
||||||
|
const { getDefaultConfig } = require("./contractManagerConfig");
|
||||||
|
|
||||||
|
const parser = yargs(hideBin(process.argv))
|
||||||
|
.usage(
|
||||||
|
"Usage: $0 --contracts <path-to-contract-json-folder> --network <contract_id> --private-key <private-key> --ops-wallet <ops-wallet>"
|
||||||
|
)
|
||||||
|
.options({
|
||||||
|
contract: {
|
||||||
|
type: "string",
|
||||||
|
demandOption: true,
|
||||||
|
desc: "Path to the contract json file containing abi and bytecode",
|
||||||
|
},
|
||||||
|
network: {
|
||||||
|
type: "string",
|
||||||
|
demandOption: true,
|
||||||
|
choices: ["testnet", "mainnet"],
|
||||||
|
desc: "The network to deploy the contract on",
|
||||||
|
},
|
||||||
|
"private-key": {
|
||||||
|
type: "string",
|
||||||
|
demandOption: true,
|
||||||
|
desc: "Private key to sign the transactions. Hex format, without 0x prefix.",
|
||||||
|
},
|
||||||
|
"ops-wallet": {
|
||||||
|
type: "string",
|
||||||
|
demandOption: true,
|
||||||
|
desc: "Path to operations wallet json file",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
async function memoize(key: string, fn: () => Promise<any>) {
|
||||||
|
const path = `./cache/${key}.json`;
|
||||||
|
if (fs.existsSync(path)) {
|
||||||
|
return JSON.parse(fs.readFileSync(path).toString());
|
||||||
|
}
|
||||||
|
const result = await fn();
|
||||||
|
fs.writeFileSync(path, JSON.stringify(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const argv = await parser.argv;
|
||||||
|
const privateKey = argv["private-key"];
|
||||||
|
const network = argv["network"];
|
||||||
|
const setupInfo = require(argv["contract"] + "/ReceiverSetup.json");
|
||||||
|
const implementationInfo = require(argv["contract"] +
|
||||||
|
"/ReceiverImplementation.json");
|
||||||
|
const receiverInfo = require(argv["contract"] + "/WormholeReceiver.json");
|
||||||
|
|
||||||
|
const payloads: Buffer[] = [];
|
||||||
|
for (const chain of Object.values(DefaultStore.chains)) {
|
||||||
|
if (
|
||||||
|
chain instanceof EvmChain &&
|
||||||
|
chain.isMainnet() === (network === "mainnet")
|
||||||
|
) {
|
||||||
|
if (chain.wormholeChainName === "zksync") continue; // deploy zksync receiver separately
|
||||||
|
const {
|
||||||
|
wormholeGovernanceChainId,
|
||||||
|
wormholeGovernanceContract,
|
||||||
|
wormholeInitialSigners,
|
||||||
|
} = getDefaultConfig(chain.getId());
|
||||||
|
console.log(chain.getId());
|
||||||
|
const address = await memoize(chain.getId(), async () => {
|
||||||
|
const setupAddress = await chain.deploy(
|
||||||
|
privateKey,
|
||||||
|
setupInfo.abi,
|
||||||
|
setupInfo.bytecode,
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
console.log("setupAddress", setupAddress);
|
||||||
|
const implementationAddress = await chain.deploy(
|
||||||
|
privateKey,
|
||||||
|
implementationInfo.abi,
|
||||||
|
implementationInfo.bytecode,
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
console.log("implementationAddress", implementationAddress);
|
||||||
|
const web3 = new Web3();
|
||||||
|
const setup = new web3.eth.Contract(setupInfo.abi, setupAddress);
|
||||||
|
const initData = setup.methods
|
||||||
|
.setup(
|
||||||
|
implementationAddress,
|
||||||
|
wormholeInitialSigners,
|
||||||
|
CHAINS[chain.wormholeChainName],
|
||||||
|
wormholeGovernanceChainId,
|
||||||
|
wormholeGovernanceContract
|
||||||
|
)
|
||||||
|
.encodeABI();
|
||||||
|
|
||||||
|
// deploy proxy
|
||||||
|
const receiverAddress = await chain.deploy(
|
||||||
|
privateKey,
|
||||||
|
receiverInfo.abi,
|
||||||
|
receiverInfo.bytecode,
|
||||||
|
[setupAddress, initData]
|
||||||
|
);
|
||||||
|
const contract = new WormholeEvmContract(chain, receiverAddress);
|
||||||
|
console.log("receiverAddress", receiverAddress);
|
||||||
|
await contract.syncMainnetGuardianSets(privateKey);
|
||||||
|
console.log("synced");
|
||||||
|
return contract.address;
|
||||||
|
});
|
||||||
|
const payload = chain.generateGovernanceSetWormholeAddressPayload(
|
||||||
|
address.replace("0x", "")
|
||||||
|
);
|
||||||
|
payloads.push(payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let vaultName;
|
||||||
|
if (network === "mainnet") {
|
||||||
|
vaultName = "mainnet-beta_FVQyHcooAtThJ83XFrNnv74BcinbRH3bRmfFamAHBfuj";
|
||||||
|
} else {
|
||||||
|
vaultName = "devnet_6baWtW1zTUVMSJHJQVxDUXWzqrQeYBr6mu31j3bTKwY3";
|
||||||
|
}
|
||||||
|
const vault = DefaultStore.vaults[vaultName];
|
||||||
|
vault.connect(await loadHotWallet(argv["ops-wallet"]));
|
||||||
|
await vault.proposeWormholeMessage(payloads);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
Loading…
Reference in New Issue