From e4d61f6fc829f1e94d591f0de4600b3ea1628913 Mon Sep 17 00:00:00 2001 From: Alex Towle Date: Mon, 16 Dec 2024 13:58:55 -0600 Subject: [PATCH] Deploy scripts for `UniV3Zap` and the matching engine (#1224) * Added the UniV3 zap tooling * Wired up the UniV3Zap * Added a deployment script for the Hyperdrive matching engine * Updated the deploy scripts * Addressed review feedback from John McClure * Fixed issue with the publish script --- hardhat.config.mainnet.ts | 13 ++- tasks/deploy/hyperdrive-matching-engine.ts | 74 +++++++++++++ tasks/deploy/hyperdrive.ts | 17 +++ tasks/deploy/index.ts | 2 + tasks/deploy/lib/constants.ts | 10 ++ tasks/deploy/lib/types.ts | 9 ++ tasks/deploy/lib/utils.ts | 31 +++++- tasks/deploy/registry.ts | 114 +++++++++------------ tasks/deploy/uni-v3-zap.ts | 73 +++++++++++++ 9 files changed, 274 insertions(+), 69 deletions(-) create mode 100644 tasks/deploy/hyperdrive-matching-engine.ts create mode 100644 tasks/deploy/uni-v3-zap.ts diff --git a/hardhat.config.mainnet.ts b/hardhat.config.mainnet.ts index 6317d4d61..7f5468759 100644 --- a/hardhat.config.mainnet.ts +++ b/hardhat.config.mainnet.ts @@ -11,11 +11,9 @@ import { MAINNET_EZETH_182DAY, MAINNET_EZETH_COORDINATOR, MAINNET_FACTORY, - MAINNET_MORPHO_BLUE_CBBTC_USDC_182DAY, MAINNET_MORPHO_BLUE_COORDINATOR, MAINNET_MORPHO_BLUE_SUSDE_DAI_182DAY, MAINNET_MORPHO_BLUE_USDE_DAI_182DAY, - MAINNET_MORPHO_BLUE_WBTC_USDC_182DAY, MAINNET_MORPHO_BLUE_WSTETH_USDA_182DAY, MAINNET_RETH_182DAY, MAINNET_RETH_COORDINATOR, @@ -47,14 +45,21 @@ const config: HardhatUserConfig = { MAINNET_MORPHO_BLUE_SUSDE_DAI_182DAY, MAINNET_MORPHO_BLUE_USDE_DAI_182DAY, MAINNET_MORPHO_BLUE_WSTETH_USDA_182DAY, - MAINNET_MORPHO_BLUE_WBTC_USDC_182DAY, - MAINNET_MORPHO_BLUE_CBBTC_USDC_182DAY, MAINNET_STUSD_182DAY, MAINNET_SUSDE_182DAY, MAINNET_SGYD_182DAY, ], checkpointRewarders: [], checkpointSubrewarders: [], + hyperdriveMatchingEngine: { + name: "DELV Hyperdrive Matching Engine", + morpho: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb", // Morpho + }, + uniV3Zap: { + name: "DELV UniV3 Zap", + swapRouter: "0xE592427A0AEce92De3Edee1F18E0157C05861564", // Uniswap V3 SwapRouter + weth: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH on mainnet + }, }, }, }, diff --git a/tasks/deploy/hyperdrive-matching-engine.ts b/tasks/deploy/hyperdrive-matching-engine.ts new file mode 100644 index 000000000..2f533bdf2 --- /dev/null +++ b/tasks/deploy/hyperdrive-matching-engine.ts @@ -0,0 +1,74 @@ +import { subtask } from "hardhat/config"; +import { Address, decodeEventLog, encodeDeployData, encodePacked } from "viem"; +import { CREATEX_ABI } from "../../lib/createx/interface/src/lib/constants"; +import { + CREATE_X_FACTORY, + HYPERDRIVE_MATCHING_ENGINE_SALT, + HyperdriveDeployBaseTask, + HyperdriveDeployNamedTaskParams, + deployCreateX, +} from "./lib"; + +// Extend params to include the additional constructor arguments +export interface DeployHyperdriveMatchingEngineParams + extends HyperdriveDeployNamedTaskParams { + morpho: Address; +} + +HyperdriveDeployBaseTask( + subtask( + "deploy:hyperdrive-matching-engine", + "deploys the HyperdriveMatchingEngine contract to the configured chain", + ), +).setAction( + async ({ name, morpho }: DeployHyperdriveMatchingEngineParams, hre) => { + console.log("\nRunning deploy:hyperdrive-matching-engine ..."); + const { hyperdriveDeploy, artifacts, viem, network } = hre; + + // If the network is anvil, we need to deploy the CREATEX factory if it + // hasn't been deployed before. + await deployCreateX(hre); + + // Skip if the zap is already deployed + if (!!hyperdriveDeploy.deployments.byNameSafe(name)) { + console.log(`skipping ${name}, found existing deployment`); + return; + } + + // Assemble the creation code by packing the contract's bytecode with + // its constructor arguments. + let artifact = artifacts.readArtifactSync("HyperdriveMatchingEngine"); + let deployData = encodeDeployData({ + abi: artifact.abi, + bytecode: artifact.bytecode, + args: [name, morpho], + }); + let creationCode = encodePacked(["bytes"], [deployData]); + + // Call the Create3 deployer to deploy the contract + // Note: No initialization data needed since we're using a constructor + let createXDeployer = await viem.getContractAt( + "IDeterministicDeployer", + CREATE_X_FACTORY, + ); + let tx = await createXDeployer.write.deployCreate3([ + HYPERDRIVE_MATCHING_ENGINE_SALT, + creationCode, + ]); + let { logs } = await pc.waitForTransactionReceipt({ hash: tx }); + const decodedLog = decodeEventLog({ + abi: CREATEX_ABI, + topics: logs[1].topics, + data: logs[1].data, + }); + let deployedAddress = decodedLog.args.newContract; + + // Save the deployment + console.log(` - saving ${name}...`); + hyperdriveDeploy.deployments.add( + name, + "HyperdriveMatchingEngine", + deployedAddress as Address, + ); + }, +); diff --git a/tasks/deploy/hyperdrive.ts b/tasks/deploy/hyperdrive.ts index fe7c159cc..353891388 100644 --- a/tasks/deploy/hyperdrive.ts +++ b/tasks/deploy/hyperdrive.ts @@ -68,5 +68,22 @@ HyperdriveDeployBaseTask( ...rest, } as DeployInstanceParams); } + + // deploy the HyperdriveMatchingEngine contract. + if (hyperdriveDeploy.hyperdriveMatchingEngine) { + await run("deploy:hyperdrive-matching-engine", { + name: hyperdriveDeploy.hyperdriveMatchingEngine.name, + morpho: hyperdriveDeploy.hyperdriveMatchingEngine.morpho, + }); + } + + // deploy the UniV3Zap contract. + if (hyperdriveDeploy.uniV3Zap) { + await run("deploy:uni-v3-zap", { + name: hyperdriveDeploy.uniV3Zap.name, + swapRouter: hyperdriveDeploy.uniV3Zap.swapRouter, + weth: hyperdriveDeploy.uniV3Zap.weth, + }); + } }, ); diff --git a/tasks/deploy/index.ts b/tasks/deploy/index.ts index bef779fa3..bb55aa4b2 100644 --- a/tasks/deploy/index.ts +++ b/tasks/deploy/index.ts @@ -3,8 +3,10 @@ export * from "./checkpoint-subrewarder"; export * from "./coordinator"; export * from "./factory"; export * from "./hyperdrive"; +export * from "./hyperdrive-matching-engine"; export * from "./instance"; export * from "./lib"; export * from "./registry"; export * from "./registry-create2-info"; +export * from "./uni-v3-zap"; export * from "./verify"; diff --git a/tasks/deploy/lib/constants.ts b/tasks/deploy/lib/constants.ts index 442f2e9fc..e5e9027f4 100644 --- a/tasks/deploy/lib/constants.ts +++ b/tasks/deploy/lib/constants.ts @@ -3,11 +3,21 @@ import { Address } from "viem"; export const ETH_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" as Address; +// The salt for the Create 3 deployment of the Hyperdrive Matching Engine. This will +// generate the address "0x6662b6e771facd61e33ccafdc23be16b4ead0666". +export const HYPERDRIVE_MATCHING_ENGINE_SALT = + "0xdc32683411729a01a997be000000000000000000000000000000000000000000" as `0x${string}`; + // The salt for the Create 3 deployment of the Hyperdrive Registry. This will // generate the address "0x6668310631Ad5a5ac92dC9549353a5BaaE16C666". export const REGISTRY_SALT = "0x01f4fa8cb977b40332a83c000000000000000000000000000000000000000000" as `0x${string}`; +// The salt for the Create 3 deployment of the Hyperdrive UniV3Zap. This will +// generate the address "0x6662a80a8d2dea71065cb38ee8b931db0105d666". +export const UNI_V3_ZAP_SALT = + "0xbb06acea8880460066ae5a000000000000000000000000000000000000000000" as `0x${string}`; + // Address for Create 2/3 factory https://github.com/pcaversaccio/createx/tree/main export const CREATE_X_FACTORY = "0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed" as Address; diff --git a/tasks/deploy/lib/types.ts b/tasks/deploy/lib/types.ts index 5b3d2cce0..f310a27ec 100644 --- a/tasks/deploy/lib/types.ts +++ b/tasks/deploy/lib/types.ts @@ -224,4 +224,13 @@ export type HyperdriveConfig = { CoordinatorPrefix >[]; instances: HyperdriveInstanceConfig>[]; + hyperdriveMatchingEngine?: { + name: string; + morpho: Address; + }; + uniV3Zap?: { + name: string; + swapRouter: Address; + weth: Address; + }; }; diff --git a/tasks/deploy/lib/utils.ts b/tasks/deploy/lib/utils.ts index 793b34c4c..58ce4387c 100644 --- a/tasks/deploy/lib/utils.ts +++ b/tasks/deploy/lib/utils.ts @@ -1,7 +1,12 @@ import dayjs from "dayjs"; import _duration from "dayjs/plugin/duration"; import { HardhatRuntimeEnvironment } from "hardhat/types"; -import { Address, Hex, toHex } from "viem"; +import { Address, Hex, parseEther, toHex } from "viem"; +import { + CREATE_X_FACTORY, + CREATE_X_FACTORY_DEPLOYER, + CREATE_X_PRESIGNED_TRANSACTION, +} from "./constants"; import { HyperdriveDeployRuntimeOptions } from "./environment-extensions"; import { DurationString, @@ -12,6 +17,30 @@ import { dayjs.extend(_duration); +/** + * Deploys the CreateX contract on anvil networks if it hasn't already been + * deployed. + */ +export async function deployCreateX(hre: HardhatRuntimeEnvironment) { + // If the network is anvil, we need to deploy the CREATEX factory if it + // hasn't been deployed before. + let pc = await hre.viem.getPublicClient(); + let bytecode = await pc.getBytecode({ + address: CREATE_X_FACTORY as Address, + }); + if (hre.network.name == "anvil" && !bytecode) { + let tc = await hre.viem.getTestClient(); + await tc.setBalance({ + value: parseEther("1"), + address: CREATE_X_FACTORY_DEPLOYER, + }); + let wc = await hre.viem.getWalletClient(CREATE_X_FACTORY_DEPLOYER); + await wc.sendRawTransaction({ + serializedTransaction: CREATE_X_PRESIGNED_TRANSACTION, + }); + } +} + /** * Generates a 32-byte hex string from the input value. */ diff --git a/tasks/deploy/registry.ts b/tasks/deploy/registry.ts index 60580745e..e2a6d0d9f 100644 --- a/tasks/deploy/registry.ts +++ b/tasks/deploy/registry.ts @@ -4,16 +4,14 @@ import { decodeEventLog, encodeFunctionData, encodePacked, - parseEther, } from "viem"; import { CREATEX_ABI } from "../../lib/createx/interface/src/lib/constants"; import { CREATE_X_FACTORY, - CREATE_X_FACTORY_DEPLOYER, - CREATE_X_PRESIGNED_TRANSACTION, HyperdriveDeployBaseTask, HyperdriveDeployNamedTaskParams, REGISTRY_SALT, + deployCreateX, } from "./lib"; export type DeployRegistryParams = HyperdriveDeployNamedTaskParams; @@ -23,71 +21,59 @@ HyperdriveDeployBaseTask( "deploy:registry", "deploys the hyperdrive registry to the configured chain", ), -).setAction( - async ( - { name }: DeployRegistryParams, - { hyperdriveDeploy, artifacts, getNamedAccounts, viem, network }, - ) => { - console.log("\nRunning deploy:registry ..."); +).setAction(async ({ name }: DeployRegistryParams, hre) => { + console.log("\nRunning deploy:registry ..."); + const { hyperdriveDeploy, artifacts, getNamedAccounts, viem } = hre; - let deployer = (await getNamedAccounts())["deployer"] as Address; + let deployer = (await getNamedAccounts())["deployer"] as Address; - if (network.name == "anvil") { - let tc = await viem.getTestClient(); - await tc.setBalance({ - value: parseEther("1"), - address: CREATE_X_FACTORY_DEPLOYER, - }); - let wc = await viem.getWalletClient(CREATE_X_FACTORY_DEPLOYER); - await wc.sendRawTransaction({ - serializedTransaction: CREATE_X_PRESIGNED_TRANSACTION, - }); - } + // If the network is anvil, we need to deploy the CREATEX factory if it + // hasn't been deployed before. + await deployCreateX(hre); - // Skip if the registry is already deployed. - if (!!hyperdriveDeploy.deployments.byNameSafe(name)) { - console.log(`skipping ${name}, found existing deployment`); - return; - } + // Skip if the registry is already deployed. + if (!!hyperdriveDeploy.deployments.byNameSafe(name)) { + console.log(`skipping ${name}, found existing deployment`); + return; + } - let createXDeployer = await viem.getContractAt( - "IDeterministicDeployer", - CREATE_X_FACTORY, - ); + let createXDeployer = await viem.getContractAt( + "IDeterministicDeployer", + CREATE_X_FACTORY, + ); - // Assemble the creation code by packing the registry contract's - // bytecode with its constructor arguments. - let artifact = artifacts.readArtifactSync("HyperdriveRegistry"); - let creationCode = encodePacked(["bytes"], [artifact.bytecode]); - let initializationData = encodeFunctionData({ - abi: artifact.abi, - functionName: "initialize", - args: [name, deployer], - }); + // Assemble the creation code by packing the registry contract's + // bytecode with its constructor arguments. + let artifact = artifacts.readArtifactSync("HyperdriveRegistry"); + let creationCode = encodePacked(["bytes"], [artifact.bytecode]); + let initializationData = encodeFunctionData({ + abi: artifact.abi, + functionName: "initialize", + args: [name, deployer], + }); - // Call the Create3 deployer to deploy the contract. - let tx = await createXDeployer.write.deployCreate3AndInit([ - REGISTRY_SALT, - creationCode, - initializationData, - { constructorAmount: 0n, initCallAmount: 0n }, - ]); - let pc = await viem.getPublicClient(); - let { logs } = await pc.waitForTransactionReceipt({ hash: tx }); - const decodedLog = decodeEventLog({ - abi: CREATEX_ABI, - topics: logs[1].topics, - data: logs[1].data, - }); - let deployedAddress = decodedLog.args.newContract; + // Call the Create3 deployer to deploy the contract. + let tx = await createXDeployer.write.deployCreate3AndInit([ + REGISTRY_SALT, + creationCode, + initializationData, + { constructorAmount: 0n, initCallAmount: 0n }, + ]); + let pc = await viem.getPublicClient(); + let { logs } = await pc.waitForTransactionReceipt({ hash: tx }); + const decodedLog = decodeEventLog({ + abi: CREATEX_ABI, + topics: logs[1].topics, + data: logs[1].data, + }); + let deployedAddress = decodedLog.args.newContract; - // Use the deployer address to back-compute the deployed contract address - // and store the deployment configuration in deployments.json. - console.log(` - saving ${name}...`); - hyperdriveDeploy.deployments.add( - name, - "HyperdriveRegistry", - deployedAddress as Address, - ); - }, -); + // Use the deployer address to back-compute the deployed contract address + // and store the deployment configuration in deployments.json. + console.log(` - saving ${name}...`); + hyperdriveDeploy.deployments.add( + name, + "HyperdriveRegistry", + deployedAddress as Address, + ); +}); diff --git a/tasks/deploy/uni-v3-zap.ts b/tasks/deploy/uni-v3-zap.ts new file mode 100644 index 000000000..e58da05b6 --- /dev/null +++ b/tasks/deploy/uni-v3-zap.ts @@ -0,0 +1,73 @@ +import { subtask } from "hardhat/config"; +import { Address, decodeEventLog, encodeDeployData, encodePacked } from "viem"; +import { CREATEX_ABI } from "../../lib/createx/interface/src/lib/constants"; +import { + CREATE_X_FACTORY, + HyperdriveDeployBaseTask, + HyperdriveDeployNamedTaskParams, + UNI_V3_ZAP_SALT, + deployCreateX, +} from "./lib"; + +// Extend params to include the additional constructor arguments +export interface DeployUniV3ZapParams extends HyperdriveDeployNamedTaskParams { + swapRouter: Address; + weth: Address; +} + +HyperdriveDeployBaseTask( + subtask( + "deploy:uni-v3-zap", + "deploys the UniV3Zap contract to the configured chain", + ), +).setAction(async ({ name, swapRouter, weth }: DeployUniV3ZapParams, hre) => { + console.log("\nRunning deploy:univ3zap ..."); + const { hyperdriveDeploy, artifacts, viem, network } = hre; + + // If the network is anvil, we need to deploy the CREATEX factory if it + // hasn't been deployed before. + await deployCreateX(hre); + + // Skip if the zap is already deployed + if (!!hyperdriveDeploy.deployments.byNameSafe(name)) { + console.log(`skipping ${name}, found existing deployment`); + return; + } + + // Assemble the creation code by packing the contract's bytecode with + // its constructor arguments. + let artifact = artifacts.readArtifactSync("UniV3Zap"); + let deployData = encodeDeployData({ + abi: artifact.abi, + bytecode: artifact.bytecode, + args: [name, swapRouter, weth], + }); + let creationCode = encodePacked(["bytes"], [deployData]); + + // Call the Create3 deployer to deploy the contract + // Note: No initialization data needed since we're using a constructor + let createXDeployer = await viem.getContractAt( + "IDeterministicDeployer", + CREATE_X_FACTORY, + ); + let tx = await createXDeployer.write.deployCreate3([ + UNI_V3_ZAP_SALT, + creationCode, + ]); + let pc = await viem.getPublicClient(); + let { logs } = await pc.waitForTransactionReceipt({ hash: tx }); + const decodedLog = decodeEventLog({ + abi: CREATEX_ABI, + topics: logs[1].topics, + data: logs[1].data, + }); + let deployedAddress = decodedLog.args.newContract; + + // Save the deployment + console.log(` - saving ${name}...`); + hyperdriveDeploy.deployments.add( + name, + "UniV3Zap", + deployedAddress as Address, + ); +});