deploy_evm_entropy_contracts.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import yargs from "yargs";
  2. import { hideBin } from "yargs/helpers";
  3. import { EvmChain } from "../src/chains";
  4. import { DefaultStore } from "../src/store";
  5. import {
  6. DeploymentType,
  7. EvmEntropyContract,
  8. getDefaultDeploymentConfig,
  9. toDeploymentType,
  10. toPrivateKey,
  11. } from "../src";
  12. import {
  13. COMMON_DEPLOY_OPTIONS,
  14. deployIfNotCached,
  15. getWeb3Contract,
  16. getOrDeployWormholeContract,
  17. BaseDeployConfig,
  18. } from "./common";
  19. import Web3 from "web3";
  20. interface DeploymentConfig extends BaseDeployConfig {
  21. type: DeploymentType;
  22. saveContract: boolean;
  23. }
  24. const CACHE_FILE = ".cache-deploy-evm-entropy-contracts";
  25. const ENTROPY_DEFAULT_PROVIDER = {
  26. mainnet: "0x52DeaA1c84233F7bb8C8A45baeDE41091c616506",
  27. testnet: "0x6CC14824Ea2918f5De5C2f75A9Da968ad4BD6344",
  28. };
  29. const parser = yargs(hideBin(process.argv))
  30. .scriptName("deploy_evm_entropy_contracts.ts")
  31. .usage(
  32. "Usage: $0 --std-output-dir <path/to/std-output-dir/> --private-key <private-key> --chain <chain> --wormhole-addr <wormhole-addr>"
  33. )
  34. .options({
  35. ...COMMON_DEPLOY_OPTIONS,
  36. chain: {
  37. type: "string",
  38. demandOption: true,
  39. desc: "Chain to upload the contract on. Can be one of the evm chains available in the store",
  40. },
  41. });
  42. async function deployExecutorContracts(
  43. chain: EvmChain,
  44. config: DeploymentConfig,
  45. wormholeAddr: string
  46. ): Promise<string> {
  47. const executorImplAddr = await deployIfNotCached(
  48. CACHE_FILE,
  49. chain,
  50. config,
  51. "ExecutorUpgradable",
  52. []
  53. );
  54. // Craft the init data for the proxy contract
  55. const { governanceDataSource } = getDefaultDeploymentConfig(config.type);
  56. const executorImplContract = getWeb3Contract(
  57. config.jsonOutputDir,
  58. "ExecutorUpgradable",
  59. executorImplAddr
  60. );
  61. const executorInitData = executorImplContract.methods
  62. .initialize(
  63. wormholeAddr,
  64. 0, // lastExecutedSequence,
  65. chain.getWormholeChainId(),
  66. governanceDataSource.emitterChain,
  67. `0x${governanceDataSource.emitterAddress}`
  68. )
  69. .encodeABI();
  70. return await deployIfNotCached(CACHE_FILE, chain, config, "ERC1967Proxy", [
  71. executorImplAddr,
  72. executorInitData,
  73. ]);
  74. }
  75. async function deployEntropyContracts(
  76. chain: EvmChain,
  77. config: DeploymentConfig,
  78. executorAddr: string
  79. ): Promise<string> {
  80. const entropyImplAddr = await deployIfNotCached(
  81. CACHE_FILE,
  82. chain,
  83. config,
  84. "EntropyUpgradable",
  85. []
  86. );
  87. const entropyImplContract = getWeb3Contract(
  88. config.jsonOutputDir,
  89. "EntropyUpgradable",
  90. entropyImplAddr
  91. );
  92. const entropyInitData = entropyImplContract.methods
  93. .initialize(
  94. executorAddr, // owner
  95. executorAddr, // admin
  96. 1, // pythFeeInWei
  97. chain.isMainnet()
  98. ? ENTROPY_DEFAULT_PROVIDER.mainnet
  99. : ENTROPY_DEFAULT_PROVIDER.testnet,
  100. true // prefillRequestStorage
  101. )
  102. .encodeABI();
  103. return await deployIfNotCached(
  104. CACHE_FILE,
  105. chain,
  106. config,
  107. "ERC1967Proxy",
  108. [entropyImplAddr, entropyInitData],
  109. // NOTE: we are deploying a ERC1967Proxy when deploying executor
  110. // we need to provide a different cache key. As the `artifactname`
  111. // is same in both case which means the cache key will be same
  112. `${chain.getId()}-ERC1967Proxy-ENTROPY`
  113. );
  114. }
  115. async function topupProviderIfNecessary(
  116. chain: EvmChain,
  117. deploymentConfig: DeploymentConfig
  118. ) {
  119. const provider = chain.isMainnet()
  120. ? ENTROPY_DEFAULT_PROVIDER.mainnet
  121. : ENTROPY_DEFAULT_PROVIDER.testnet;
  122. const web3 = new Web3(chain.getRpcUrl());
  123. const balance = Number(
  124. web3.utils.fromWei(await web3.eth.getBalance(provider), "ether")
  125. );
  126. const MIN_BALANCE = 0.01;
  127. console.log(`Provider balance: ${balance} ETH`);
  128. if (balance < MIN_BALANCE) {
  129. console.log(
  130. `Balance is less than ${MIN_BALANCE}. Topping up the provider address...`
  131. );
  132. const signer = web3.eth.accounts.privateKeyToAccount(
  133. deploymentConfig.privateKey
  134. );
  135. web3.eth.accounts.wallet.add(signer);
  136. const tx = await web3.eth.sendTransaction({
  137. from: signer.address,
  138. to: provider,
  139. gas: 30000,
  140. value: web3.utils.toWei(`${MIN_BALANCE}`, "ether"),
  141. });
  142. console.log("Topped up the provider address. Tx: ", tx.transactionHash);
  143. }
  144. }
  145. async function main() {
  146. const argv = await parser.argv;
  147. const chainName = argv.chain;
  148. const chain = DefaultStore.chains[chainName];
  149. if (!chain) {
  150. throw new Error(`Chain ${chainName} not found`);
  151. } else if (!(chain instanceof EvmChain)) {
  152. throw new Error(`Chain ${chainName} is not an EVM chain`);
  153. }
  154. const deploymentConfig: DeploymentConfig = {
  155. type: toDeploymentType(argv.deploymentType),
  156. gasMultiplier: argv.gasMultiplier,
  157. gasPriceMultiplier: argv.gasPriceMultiplier,
  158. privateKey: toPrivateKey(argv.privateKey),
  159. jsonOutputDir: argv.stdOutputDir,
  160. saveContract: argv.saveContract,
  161. };
  162. const wormholeContract = await getOrDeployWormholeContract(
  163. chain,
  164. deploymentConfig,
  165. CACHE_FILE
  166. );
  167. await topupProviderIfNecessary(chain, deploymentConfig);
  168. console.log(
  169. `Deployment config: ${JSON.stringify(deploymentConfig, null, 2)}\n`
  170. );
  171. console.log(`Deploying entropy contracts on ${chain.getId()}...`);
  172. const executorAddr = await deployExecutorContracts(
  173. chain,
  174. deploymentConfig,
  175. wormholeContract.address
  176. );
  177. const entropyAddr = await deployEntropyContracts(
  178. chain,
  179. deploymentConfig,
  180. executorAddr
  181. );
  182. if (deploymentConfig.saveContract) {
  183. console.log("Saving the contract in the store...");
  184. const contract = new EvmEntropyContract(chain, entropyAddr);
  185. DefaultStore.entropy_contracts[contract.getId()] = contract;
  186. DefaultStore.saveAllContracts();
  187. }
  188. console.log(
  189. `✅ Deployed entropy contracts on ${chain.getId()} at ${entropyAddr}\n\n`
  190. );
  191. }
  192. main();