Skip to content

Commit

Permalink
Deploy scripts for UniV3Zap and the matching engine (#1224)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
jalextowle authored Dec 16, 2024
1 parent 5e39e30 commit e4d61f6
Show file tree
Hide file tree
Showing 9 changed files with 274 additions and 69 deletions.
13 changes: 9 additions & 4 deletions hardhat.config.mainnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
},
},
},
},
Expand Down
74 changes: 74 additions & 0 deletions tasks/deploy/hyperdrive-matching-engine.ts
Original file line number Diff line number Diff line change
@@ -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,
);
},
);
17 changes: 17 additions & 0 deletions tasks/deploy/hyperdrive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
}
},
);
2 changes: 2 additions & 0 deletions tasks/deploy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
10 changes: 10 additions & 0 deletions tasks/deploy/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions tasks/deploy/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,4 +224,13 @@ export type HyperdriveConfig = {
CoordinatorPrefix<ContractName>
>[];
instances: HyperdriveInstanceConfig<InstancePrefix<ContractName>>[];
hyperdriveMatchingEngine?: {
name: string;
morpho: Address;
};
uniV3Zap?: {
name: string;
swapRouter: Address;
weth: Address;
};
};
31 changes: 30 additions & 1 deletion tasks/deploy/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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.
*/
Expand Down
114 changes: 50 additions & 64 deletions tasks/deploy/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
);
});
Loading

0 comments on commit e4d61f6

Please sign in to comment.