batchDeployReceivers.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /* eslint-disable @typescript-eslint/no-unsafe-return */
  2. /* eslint-disable @typescript-eslint/no-unsafe-call */
  3. /* eslint-disable @typescript-eslint/no-floating-promises */
  4. /* eslint-disable @typescript-eslint/no-unsafe-argument */
  5. /* eslint-disable @typescript-eslint/no-unsafe-member-access */
  6. /* eslint-disable @typescript-eslint/no-unsafe-assignment */
  7. /* eslint-disable unicorn/prefer-top-level-await */
  8. /* eslint-disable no-console */
  9. /**
  10. * This script deploys the receiver contracts on all the chains and creates a governance proposal to update the
  11. * wormhole addresses to the deployed receiver contracts.
  12. */
  13. import * as fs from "node:fs";
  14. import { CHAINS } from "@pythnetwork/xc-admin-common";
  15. import Web3 from "web3";
  16. import yargs from "yargs";
  17. import { hideBin } from "yargs/helpers";
  18. import { getDefaultConfig } from "../../target_chains/ethereum/contracts/scripts/contractManagerConfig.js";
  19. import type { PrivateKey } from "../src/core/base.js";
  20. import { EvmChain } from "../src/core/chains.js";
  21. import { EvmWormholeContract } from "../src/core/contracts/evm.js";
  22. import { loadHotWallet } from "../src/node/utils/governance.js";
  23. import { DefaultStore } from "../src/node/utils/store.js";
  24. const parser = yargs(hideBin(process.argv))
  25. .usage(
  26. "Usage: $0 --contracts <path-to-contract-json-folder> --network <contract_id> --private-key <private-key> --ops-wallet <ops-wallet>",
  27. )
  28. .options({
  29. contract: {
  30. type: "string",
  31. demandOption: true,
  32. desc: "Path to the contract json file containing abi and bytecode",
  33. },
  34. network: {
  35. type: "string",
  36. demandOption: true,
  37. choices: ["testnet", "mainnet"],
  38. desc: "The network to deploy the contract on",
  39. },
  40. "private-key": {
  41. type: "string",
  42. demandOption: true,
  43. desc: "Private key to sign the transactions. Hex format, without 0x prefix.",
  44. },
  45. "ops-wallet": {
  46. type: "string",
  47. demandOption: true,
  48. desc: "Path to operations wallet json file",
  49. },
  50. });
  51. async function memoize(
  52. key: string,
  53. fn: () => Promise<string>,
  54. ): Promise<string> {
  55. const cacheDir = "../../target_chains/ethereum/contracts/cache";
  56. const path = `${cacheDir}/${key}.json`;
  57. if (fs.existsSync(path)) {
  58. return JSON.parse(fs.readFileSync(path).toString());
  59. }
  60. const result = await fn();
  61. fs.writeFileSync(path, JSON.stringify(result));
  62. return result;
  63. }
  64. async function main() {
  65. const argv = await parser.argv;
  66. const privateKey = argv["private-key"];
  67. const network = argv.network;
  68. const setupInfo = await import(argv.contract + "/ReceiverSetup.json");
  69. const implementationInfo = await import(
  70. argv.contract + "/ReceiverImplementation.json"
  71. );
  72. const receiverInfo = await import(argv.contract + "/WormholeReceiver.json");
  73. const payloads: Buffer[] = [];
  74. for (const chain of Object.values(DefaultStore.chains)) {
  75. if (
  76. chain instanceof EvmChain &&
  77. chain.isMainnet() === (network === "mainnet")
  78. ) {
  79. if (chain.wormholeChainName === "zksync") continue; // deploy zksync receiver separately
  80. const {
  81. wormholeGovernanceChainId,
  82. wormholeGovernanceContract,
  83. wormholeInitialSigners,
  84. } = getDefaultConfig(chain.getId());
  85. console.log(chain.getId());
  86. const address = await memoize(chain.getId(), async () => {
  87. const setupAddress = await chain.deploy(
  88. privateKey as PrivateKey,
  89. setupInfo.abi,
  90. setupInfo.bytecode,
  91. [],
  92. );
  93. console.log("setupAddress", setupAddress);
  94. const implementationAddress = await chain.deploy(
  95. privateKey as PrivateKey,
  96. implementationInfo.abi,
  97. implementationInfo.bytecode,
  98. [],
  99. );
  100. console.log("implementationAddress", implementationAddress);
  101. const web3 = new Web3();
  102. const setup = new web3.eth.Contract(setupInfo.abi, setupAddress);
  103. const initData = setup.methods
  104. .setup(
  105. implementationAddress,
  106. wormholeInitialSigners,
  107. CHAINS[chain.wormholeChainName],
  108. wormholeGovernanceChainId,
  109. wormholeGovernanceContract,
  110. )
  111. .encodeABI();
  112. // deploy proxy
  113. const receiverAddress = await chain.deploy(
  114. privateKey as PrivateKey,
  115. receiverInfo.abi,
  116. receiverInfo.bytecode,
  117. [setupAddress, initData],
  118. );
  119. const contract = new EvmWormholeContract(chain, receiverAddress);
  120. console.log("receiverAddress", receiverAddress);
  121. await contract.syncMainnetGuardianSets(privateKey as PrivateKey);
  122. console.log("synced");
  123. return contract.address;
  124. });
  125. const payload = chain.generateGovernanceSetWormholeAddressPayload(
  126. address.replace("0x", ""),
  127. );
  128. payloads.push(payload);
  129. }
  130. }
  131. const vaultName =
  132. network === "mainnet"
  133. ? "mainnet-beta_FVQyHcooAtThJ83XFrNnv74BcinbRH3bRmfFamAHBfuj"
  134. : "devnet_6baWtW1zTUVMSJHJQVxDUXWzqrQeYBr6mu31j3bTKwY3";
  135. const vault = DefaultStore.vaults[vaultName];
  136. vault?.connect(await loadHotWallet(argv["ops-wallet"]));
  137. await vault?.proposeWormholeMessage(payloads);
  138. }
  139. main();