batchDeployReceivers.ts 4.5 KB

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