deploy_evm_pricefeed_contracts.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  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. EvmPriceFeedContract,
  8. getDefaultDeploymentConfig,
  9. PrivateKey,
  10. toDeploymentType,
  11. toPrivateKey,
  12. WormholeEvmContract,
  13. } from "../src";
  14. import {
  15. COMMON_DEPLOY_OPTIONS,
  16. deployIfNotCached,
  17. getWeb3Contract,
  18. } from "./common";
  19. type DeploymentConfig = {
  20. type: DeploymentType;
  21. validTimePeriodSeconds: number;
  22. singleUpdateFeeInWei: number;
  23. gasMultiplier: number;
  24. gasPriceMultiplier: number;
  25. privateKey: PrivateKey;
  26. jsonOutputDir: string;
  27. saveContract: boolean;
  28. };
  29. const CACHE_FILE = ".cache-deploy-evm";
  30. const parser = yargs(hideBin(process.argv))
  31. .scriptName("deploy_evm_pricefeed_contracts.ts")
  32. .usage(
  33. "Usage: $0 --std-output-dir <path/to/std-output-dir/> --private-key <private-key> --chain <chain0> --chain <chain1>"
  34. )
  35. .options({
  36. ...COMMON_DEPLOY_OPTIONS,
  37. "valid-time-period-seconds": {
  38. type: "number",
  39. demandOption: false,
  40. default: 60,
  41. desc: "Valid time period in seconds for the price feed staleness",
  42. },
  43. "single-update-fee-in-wei": {
  44. type: "number",
  45. demandOption: false,
  46. default: 1,
  47. desc: "Single update fee in wei for the price feed",
  48. },
  49. });
  50. async function deployWormholeReceiverContracts(
  51. chain: EvmChain,
  52. config: DeploymentConfig
  53. ): Promise<string> {
  54. const receiverSetupAddr = await deployIfNotCached(
  55. CACHE_FILE,
  56. chain,
  57. config,
  58. "ReceiverSetup",
  59. []
  60. );
  61. const receiverImplAddr = await deployIfNotCached(
  62. CACHE_FILE,
  63. chain,
  64. config,
  65. "ReceiverImplementation",
  66. []
  67. );
  68. // Craft the init data for the proxy contract
  69. const setupContract = getWeb3Contract(
  70. config.jsonOutputDir,
  71. "ReceiverSetup",
  72. receiverSetupAddr
  73. );
  74. const { wormholeConfig } = getDefaultDeploymentConfig(config.type);
  75. const initData = setupContract.methods
  76. .setup(
  77. receiverImplAddr,
  78. wormholeConfig.initialGuardianSet.map((addr: string) => "0x" + addr),
  79. chain.getWormholeChainId(),
  80. wormholeConfig.governanceChainId,
  81. "0x" + wormholeConfig.governanceContract
  82. )
  83. .encodeABI();
  84. const wormholeReceiverAddr = await deployIfNotCached(
  85. CACHE_FILE,
  86. chain,
  87. config,
  88. "WormholeReceiver",
  89. [receiverSetupAddr, initData]
  90. );
  91. const wormholeEvmContract = new WormholeEvmContract(
  92. chain,
  93. wormholeReceiverAddr
  94. );
  95. if (config.type === "stable") {
  96. console.log(`Syncing mainnet guardian sets for ${chain.getId()}...`);
  97. // TODO: Add a way to pass gas configs to this
  98. await wormholeEvmContract.syncMainnetGuardianSets(config.privateKey);
  99. console.log(`✅ Synced mainnet guardian sets for ${chain.getId()}`);
  100. }
  101. return wormholeReceiverAddr;
  102. }
  103. async function deployPriceFeedContracts(
  104. chain: EvmChain,
  105. config: DeploymentConfig,
  106. wormholeAddr: string
  107. ): Promise<string> {
  108. const pythImplAddr = await deployIfNotCached(
  109. CACHE_FILE,
  110. chain,
  111. config,
  112. "PythUpgradable",
  113. []
  114. );
  115. // Craft the init data for the proxy contract
  116. const { dataSources, governanceDataSource } = getDefaultDeploymentConfig(
  117. config.type
  118. );
  119. const pythImplContract = getWeb3Contract(
  120. config.jsonOutputDir,
  121. "PythUpgradable",
  122. pythImplAddr
  123. );
  124. const pythInitData = pythImplContract.methods
  125. .initialize(
  126. wormholeAddr,
  127. dataSources.map((ds) => ds.emitterChain),
  128. dataSources.map((ds) => "0x" + ds.emitterAddress),
  129. governanceDataSource.emitterChain,
  130. "0x" + governanceDataSource.emitterAddress,
  131. 0, // governanceInitialSequence
  132. config.validTimePeriodSeconds,
  133. config.singleUpdateFeeInWei
  134. )
  135. .encodeABI();
  136. return await deployIfNotCached(CACHE_FILE, chain, config, "ERC1967Proxy", [
  137. pythImplAddr,
  138. pythInitData,
  139. ]);
  140. }
  141. async function main() {
  142. const argv = await parser.argv;
  143. const deploymentConfig: DeploymentConfig = {
  144. type: toDeploymentType(argv.deploymentType),
  145. validTimePeriodSeconds: argv.validTimePeriodSeconds,
  146. singleUpdateFeeInWei: argv.singleUpdateFeeInWei,
  147. gasMultiplier: argv.gasMultiplier,
  148. gasPriceMultiplier: argv.gasPriceMultiplier,
  149. privateKey: toPrivateKey(argv.privateKey),
  150. jsonOutputDir: argv.stdOutputDir,
  151. saveContract: argv.saveContract,
  152. };
  153. console.log(
  154. `Deployment config: ${JSON.stringify(deploymentConfig, null, 2)}\n`
  155. );
  156. const chainNames = argv.chain;
  157. for (const chainName of chainNames) {
  158. const chain = DefaultStore.chains[chainName];
  159. if (!chain) {
  160. throw new Error(`Chain ${chainName} not found`);
  161. } else if (!(chain instanceof EvmChain)) {
  162. throw new Error(`Chain ${chainName} is not an EVM chain`);
  163. }
  164. console.log(`Deploying price feed contracts on ${chain.getId()}...`);
  165. const wormholeAddr = await deployWormholeReceiverContracts(
  166. chain,
  167. deploymentConfig
  168. );
  169. const priceFeedAddr = await deployPriceFeedContracts(
  170. chain,
  171. deploymentConfig,
  172. wormholeAddr
  173. );
  174. if (deploymentConfig.saveContract) {
  175. console.log("Saving the contract in the store...");
  176. const contract = new EvmPriceFeedContract(chain, priceFeedAddr);
  177. DefaultStore.contracts[contract.getId()] = contract;
  178. DefaultStore.saveAllContracts();
  179. }
  180. console.log(
  181. `✅ Deployed price feed contracts on ${chain.getId()} at ${priceFeedAddr}\n\n`
  182. );
  183. }
  184. }
  185. main();