Skip to content

Commit

Permalink
Corn Integration (#1171)
Browse files Browse the repository at this point in the history
* Added the skeleton for the Corn integration

* Implemented the `CornBase` contract

* Wired up the Corn Hyperdrive instance

* Added an instance test for the Corn integration

* Added deployment scripts for the Corn integration

* Addressed review feedback from @jrhea and @mcclurejt
  • Loading branch information
jalextowle authored Sep 16, 2024
1 parent 8e32d2f commit 2cdddd9
Show file tree
Hide file tree
Showing 44 changed files with 1,584 additions and 43 deletions.
11 changes: 4 additions & 7 deletions codegen/example/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,16 @@
name:
# Capitalized version of the name to be used i.e. for contract names, file
# names, and comments.
capitalized: "MorphoBlue"
capitalized: "ExampleName"

# All upper case name to be used for constants.
uppercase: "MORPHO_BLUE"

# All upper case name to be used for constants.
uppercase: "TEST_ETH"
uppercase: "EXAMPLE_NAME"

# All lower case name to be used for directories.
lowercase: "morpho-blue"
lowercase: "example-name"

# Camel case name to be used i.e. for variables.
camelcase: "morphoBlue"
camelcase: "exampleName"

# Configuration parameters for the hyperdrive instance.
contract:
Expand Down
71 changes: 71 additions & 0 deletions contracts/src/deployers/corn/CornHyperdriveCoreDeployer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.22;

import { ICornSilo } from "../../interfaces/ICornSilo.sol";
import { IHyperdrive } from "../../interfaces/IHyperdrive.sol";
import { IHyperdriveAdminController } from "../../interfaces/IHyperdriveAdminController.sol";
import { IHyperdriveCoreDeployer } from "../../interfaces/IHyperdriveCoreDeployer.sol";
import { CornHyperdrive } from "../../instances/corn/CornHyperdrive.sol";

/// @author DELV
/// @title CornHyperdriveCoreDeployer
/// @notice The core deployer for the CornHyperdrive implementation.
/// @custom:disclaimer The language used in this code is for coding convenience
/// only, and is not intended to, and does not, have any
/// particular legal or regulatory significance.
contract CornHyperdriveCoreDeployer is IHyperdriveCoreDeployer {
/// @dev The Corn Silo contract. This is where the base token will be
/// deposited.
ICornSilo internal immutable cornSilo;

/// @notice Instantiates the CornHyperdrive base contract.
/// @param _cornSilo The Corn Silo contract.
constructor(ICornSilo _cornSilo) {
cornSilo = _cornSilo;
}

/// @notice Deploys a Hyperdrive instance with the given parameters.
/// @param __name The name of the Hyperdrive pool.
/// @param _config The configuration of the Hyperdrive pool.
/// @param _adminController The admin controller that will specify the
/// admin parameters for this instance.
/// @param _target0 The target0 address.
/// @param _target1 The target1 address.
/// @param _target2 The target2 address.
/// @param _target3 The target3 address.
/// @param _target4 The target4 address.
/// @param _salt The create2 salt used in the deployment.
/// @return The address of the newly deployed CornHyperdrive instance.
function deployHyperdrive(
string memory __name,
IHyperdrive.PoolConfig memory _config,
IHyperdriveAdminController _adminController,
bytes memory, // unused _extraData,
address _target0,
address _target1,
address _target2,
address _target3,
address _target4,
bytes32 _salt
) external returns (address) {
return (
address(
// NOTE: We hash the sender with the salt to prevent the
// front-running of deployments.
new CornHyperdrive{
salt: keccak256(abi.encode(msg.sender, _salt))
}(
__name,
_config,
_adminController,
_target0,
_target1,
_target2,
_target3,
_target4,
cornSilo
)
)
);
}
}
168 changes: 168 additions & 0 deletions contracts/src/deployers/corn/CornHyperdriveDeployerCoordinator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.22;

import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol";
import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol";
import { CornConversions } from "../../instances/corn/CornConversions.sol";
import { IHyperdrive } from "../../interfaces/IHyperdrive.sol";
import { IHyperdriveDeployerCoordinator } from "../../interfaces/IHyperdriveDeployerCoordinator.sol";
import { CORN_HYPERDRIVE_DEPLOYER_COORDINATOR_KIND } from "../../libraries/Constants.sol";
import { ONE } from "../../libraries/FixedPointMath.sol";
import { HyperdriveDeployerCoordinator } from "../HyperdriveDeployerCoordinator.sol";

/// @author DELV
/// @title CornHyperdriveDeployerCoordinator
/// @notice The deployer coordinator for the CornHyperdrive
/// implementation.
/// @custom:disclaimer The language used in this code is for coding convenience
/// only, and is not intended to, and does not, have any
/// particular legal or regulatory significance.
contract CornHyperdriveDeployerCoordinator is HyperdriveDeployerCoordinator {
using SafeERC20 for ERC20;

/// @notice The deployer coordinator's kind.
string public constant override kind =
CORN_HYPERDRIVE_DEPLOYER_COORDINATOR_KIND;

/// @notice Instantiates the deployer coordinator.
/// @param _name The deployer coordinator's name.
/// @param _factory The factory that this deployer will be registered with.
/// @param _coreDeployer The core deployer.
/// @param _target0Deployer The target0 deployer.
/// @param _target1Deployer The target1 deployer.
/// @param _target2Deployer The target2 deployer.
/// @param _target3Deployer The target3 deployer.
/// @param _target4Deployer The target4 deployer.
constructor(
string memory _name,
address _factory,
address _coreDeployer,
address _target0Deployer,
address _target1Deployer,
address _target2Deployer,
address _target3Deployer,
address _target4Deployer
)
HyperdriveDeployerCoordinator(
_name,
_factory,
_coreDeployer,
_target0Deployer,
_target1Deployer,
_target2Deployer,
_target3Deployer,
_target4Deployer
)
{}

/// @dev Prepares the coordinator for initialization by drawing funds from
/// the LP, if necessary.
/// @param _hyperdrive The Hyperdrive instance that is being initialized.
/// @param _lp The LP that is initializing the pool.
/// @param _contribution The amount of capital to supply. The units of this
/// quantity are either base or vault shares, depending on the value
/// of `_options.asBase`.
/// @param _options The options that configure how the initialization is
/// settled.
/// @return value The value that should be sent in the initialize transaction.
function _prepareInitialize(
IHyperdrive _hyperdrive,
address _lp,
uint256 _contribution,
IHyperdrive.Options memory _options
) internal override returns (uint256 value) {
// Depositing with shares is not supported.
if (!_options.asBase) {
revert IHyperdrive.UnsupportedToken();
}

// Transfer base from the LP and approve the Hyperdrive pool.
ERC20 baseToken = ERC20(_hyperdrive.baseToken());
baseToken.safeTransferFrom(_lp, address(this), _contribution);
baseToken.forceApprove(address(_hyperdrive), _contribution);

// This yield source isn't payable, so we should always send 0 value.
return 0;
}

/// @notice Convert an amount of vault shares to an amount of base.
/// @param _shareAmount The vault shares amount.
/// @return The base amount.
function convertToBase(uint256 _shareAmount) public pure returns (uint256) {
return CornConversions.convertToBase(_shareAmount);
}

/// @notice Convert an amount of base to an amount of vault shares.
/// @param _baseAmount The base amount.
/// @return The vault shares amount.
function convertToShares(
uint256 _baseAmount
) public pure returns (uint256) {
return CornConversions.convertToShares(_baseAmount);
}

/// @dev We override the message value check since this integration is
/// not payable.
function _checkMessageValue() internal view override {
if (msg.value != 0) {
revert IHyperdriveDeployerCoordinator.NotPayable();
}
}

/// @notice Checks the pool configuration to ensure that it is valid.
/// @param _deployConfig The deploy configuration of the Hyperdrive pool.
/// @param _extraData The empty extra data.
function _checkPoolConfig(
IHyperdrive.PoolDeployConfig memory _deployConfig,
bytes memory _extraData
) internal view override {
// Perform the default checks.
super._checkPoolConfig(_deployConfig, _extraData);

// Ensure that the base token address is properly configured.
if (address(_deployConfig.baseToken) == address(0)) {
revert IHyperdriveDeployerCoordinator.InvalidBaseToken();
}

// Ensure that the vault shares token address is properly configured.
// Since the CornSilo doesn't support shares transfers, the vault shares
// token should be the zero address.
if (address(_deployConfig.vaultSharesToken) != address(0)) {
revert IHyperdriveDeployerCoordinator.InvalidVaultSharesToken();
}

// Ensure that the minimum share reserves are large enough to meet the
// minimum requirements for safety.
//
// NOTE: Some pools may require larger minimum share reserves to be
// considered safe. This is just a sanity check.
if (
_deployConfig.minimumShareReserves <
10 ** (_deployConfig.baseToken.decimals() - 3)
) {
revert IHyperdriveDeployerCoordinator.InvalidMinimumShareReserves();
}

// Ensure that the minimum transaction amount is large enough to meet
// the minimum requirements for safety.
//
// NOTE: Some pools may require larger minimum transaction amounts to be
// considered safe. This is just a sanity check.
if (
_deployConfig.minimumTransactionAmount <
10 ** (_deployConfig.baseToken.decimals() - 3)
) {
revert IHyperdriveDeployerCoordinator
.InvalidMinimumTransactionAmount();
}
}

/// @dev Gets the initial vault share price of the Hyperdrive pool.
/// @return The initial vault share price of the Hyperdrive pool.
function _getInitialVaultSharePrice(
IHyperdrive.PoolDeployConfig memory, // unused _deployConfig
bytes memory // unused _extraData
) internal pure override returns (uint256) {
return convertToBase(ONE);
}
}
48 changes: 48 additions & 0 deletions contracts/src/deployers/corn/CornTarget0Deployer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.22;

import { CornTarget0 } from "../../instances/corn/CornTarget0.sol";
import { ICornSilo } from "../../interfaces/ICornSilo.sol";
import { IHyperdrive } from "../../interfaces/IHyperdrive.sol";
import { IHyperdriveAdminController } from "../../interfaces/IHyperdriveAdminController.sol";
import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol";

/// @author DELV
/// @title CornTarget0Deployer
/// @notice The target0 deployer for the CornHyperdrive implementation.
/// @custom:disclaimer The language used in this code is for coding convenience
/// only, and is not intended to, and does not, have any
/// particular legal or regulatory significance.
contract CornTarget0Deployer is IHyperdriveTargetDeployer {
/// @dev The Corn Silo contract. This is where the base token will be
/// deposited.
ICornSilo internal immutable cornSilo;

/// @notice Instantiates the CornHyperdrive base contract.
/// @param _cornSilo The Corn Silo contract.
constructor(ICornSilo _cornSilo) {
cornSilo = _cornSilo;
}

/// @notice Deploys a target0 instance with the given parameters.
/// @param _config The configuration of the Hyperdrive pool.
/// @param _adminController The admin controller that will specify the
/// admin parameters for this instance.
/// @param _salt The create2 salt used in the deployment.
/// @return The address of the newly deployed CornTarget0 instance.
function deployTarget(
IHyperdrive.PoolConfig memory _config,
IHyperdriveAdminController _adminController,
bytes memory, // unused _extraData
bytes32 _salt
) external returns (address) {
return
address(
// NOTE: We hash the sender with the salt to prevent the
// front-running of deployments.
new CornTarget0{
salt: keccak256(abi.encode(msg.sender, _salt))
}(_config, _adminController, cornSilo)
);
}
}
48 changes: 48 additions & 0 deletions contracts/src/deployers/corn/CornTarget1Deployer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.22;

import { CornTarget1 } from "../../instances/corn/CornTarget1.sol";
import { ICornSilo } from "../../interfaces/ICornSilo.sol";
import { IHyperdrive } from "../../interfaces/IHyperdrive.sol";
import { IHyperdriveAdminController } from "../../interfaces/IHyperdriveAdminController.sol";
import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol";

/// @author DELV
/// @title CornTarget1Deployer
/// @notice The target1 deployer for the CornHyperdrive implementation.
/// @custom:disclaimer The language used in this code is for coding convenience
/// only, and is not intended to, and does not, have any
/// particular legal or regulatory significance.
contract CornTarget1Deployer is IHyperdriveTargetDeployer {
/// @dev The Corn Silo contract. This is where the base token will be
/// deposited.
ICornSilo internal immutable cornSilo;

/// @notice Instantiates the CornHyperdrive base contract.
/// @param _cornSilo The Corn Silo contract.
constructor(ICornSilo _cornSilo) {
cornSilo = _cornSilo;
}

/// @notice Deploys a target1 instance with the given parameters.
/// @param _config The configuration of the Hyperdrive pool.
/// @param _adminController The admin controller that will specify the
/// admin parameters for this instance.
/// @param _salt The create2 salt used in the deployment.
/// @return The address of the newly deployed CornTarget1 instance.
function deployTarget(
IHyperdrive.PoolConfig memory _config,
IHyperdriveAdminController _adminController,
bytes memory, // unused _extraData
bytes32 _salt
) external returns (address) {
return
address(
// NOTE: We hash the sender with the salt to prevent the
// front-running of deployments.
new CornTarget1{
salt: keccak256(abi.encode(msg.sender, _salt))
}(_config, _adminController, cornSilo)
);
}
}
Loading

0 comments on commit 2cdddd9

Please sign in to comment.