diff --git a/.github/workflows/devnet_docker.yml b/.github/workflows/devnet_docker.yml index 265a30d77..9df0b2261 100644 --- a/.github/workflows/devnet_docker.yml +++ b/.github/workflows/devnet_docker.yml @@ -51,3 +51,13 @@ jobs: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + build-args: | + FACTORY_MIN_CURVE_FEE=0 + FACTORY_MIN_FLAT_FEE=0 + FACTORY_MIN_GOVERNANCE_LP_FEE=0 + FACTORY_MIN_GOVERNANCE_ZOMBIE_FEE=0 + FACTORY_MAX_CURVE_FEE=1000000000000000000 + FACTORY_MAX_FLAT_FEE=1000000000000000000 + FACTORY_MAX_GOVERNANCE_LP_FEE=1000000000000000000 + FACTORY_MAX_GOVERNANCE_ZOMBIE_FEE=1000000000000000000 + FACTORY_MIN_POSITION_DURATION=86400 diff --git a/.gitmodules b/.gitmodules index 3008c272f..5611d0f29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,6 +9,7 @@ [submodule "lib/openzeppelin-contracts"] path = lib/openzeppelin-contracts url = https://github.com/OpenZeppelin/openzeppelin-contracts + branch = v5.0.1 [submodule "lib/solmate"] path = lib/solmate url = https://github.com/transmissions11/solmate diff --git a/README.md b/README.md index 66bce1b0f..f8fb0f682 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Tests](https://github.com/delvtech/hyperdrive/actions/workflows/test.yml/badge.svg)](https://github.com/delvtech/hyperdrive/actions/workflows/test.yml) +[![Tests](https://github.com/delvtech/hyperdrive/actions/workflows/solidity_test.yml/badge.svg)](https://github.com/delvtech/hyperdrive/actions/workflows/solidity_test.yml) [![Coverage](https://coveralls.io/repos/github/delvtech/hyperdrive/badge.svg?branch=main&t=vnW3xG&kill_cache=1&service=github)](https://coveralls.io/github/delvtech/hyperdrive?branch=main) # Hyperdrive @@ -41,7 +41,7 @@ If you want to automatically format the code, run `yarn prettier`. ## Yield Sources -The current suggested way of integrating your yield source with hyperdrive is through the [ERC-4626 standard](https://eips.ethereum.org/EIPS/eip-4626) although accomodations can be made if this is not possible. Hyperdrive currently makes use of [Yield Daddy](https://github.com/timeless-fi/yield-daddy) to wrap many existing yield sources into this standard. +The current suggested way of integrating your yield source with hyperdrive is through the [ERC-4626 standard](https://eips.ethereum.org/EIPS/eip-4626) although accomodations can be made if this is not possible. # Disclaimer diff --git a/contracts/src/deployers/HyperdriveDeployerCoordinator.sol b/contracts/src/deployers/HyperdriveDeployerCoordinator.sol index 4b782ab10..c0e6da631 100644 --- a/contracts/src/deployers/HyperdriveDeployerCoordinator.sol +++ b/contracts/src/deployers/HyperdriveDeployerCoordinator.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { IHyperdriveCoreDeployer } from "../interfaces/IHyperdriveCoreDeployer.sol"; -import { IDeployerCoordinator } from "../interfaces/IDeployerCoordinator.sol"; +import { IHyperdriveDeployerCoordinator } from "../interfaces/IHyperdriveDeployerCoordinator.sol"; import { IHyperdriveTargetDeployer } from "../interfaces/IHyperdriveTargetDeployer.sol"; /// @author DELV @@ -14,7 +14,36 @@ import { IHyperdriveTargetDeployer } from "../interfaces/IHyperdriveTargetDeploy /// @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. -abstract contract HyperdriveDeployerCoordinator is IDeployerCoordinator { +abstract contract HyperdriveDeployerCoordinator is + IHyperdriveDeployerCoordinator +{ + struct Deployment { + /// @dev The hash of the config used in this deployment. This is used to + /// ensure that the config is the same across all deployments in + /// the batch. + bytes32 configHash; + /// @dev The hash of the extra data passed to the child deployers. This + /// is used to ensure that the extra data is the same across all + /// deployments in the batch. + bytes32 extraDataHash; + /// @dev The initial share price used in the first part of this + /// deployment. This is used to ensure that the initial share price + /// is the same across all deployments in the batch. + uint256 initialSharePrice; + /// @dev The address of the Hyperdrive entrypoint. + address hyperdrive; + /// @dev The address of the HyperdriveTarget0 contract. + address target0; + /// @dev The address of the HyperdriveTarget1 contract. + address target1; + /// @dev The address of the HyperdriveTarget2 contract. + address target2; + /// @dev The address of the HyperdriveTarget3 contract. + address target3; + /// @dev The address of the HyperdriveTarget4 contract. + address target4; + } + /// @notice The contract used to deploy new instances of Hyperdrive. address public immutable coreDeployer; @@ -30,67 +59,271 @@ abstract contract HyperdriveDeployerCoordinator is IDeployerCoordinator { /// @notice The contract used to deploy new instances of HyperdriveTarget3. address public immutable target3Deployer; + /// @notice The contract used to deploy new instances of HyperdriveTarget4. + address public immutable target4Deployer; + + /// @notice A mapping from deployer to deployment ID to deployment. + mapping(address => mapping(bytes32 => Deployment)) public deployments; + /// @notice Instantiates the deployer coordinator. /// @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( address _coreDeployer, address _target0Deployer, address _target1Deployer, address _target2Deployer, - address _target3Deployer + address _target3Deployer, + address _target4Deployer ) { coreDeployer = _coreDeployer; target0Deployer = _target0Deployer; target1Deployer = _target1Deployer; target2Deployer = _target2Deployer; target3Deployer = _target3Deployer; + target4Deployer = _target4Deployer; } /// @notice Deploys a Hyperdrive instance with the given parameters. + /// @param _deploymentId The ID of the deployment. /// @param _deployConfig The deploy configuration of the Hyperdrive pool. /// @param _extraData The extra data that contains the pool and sweep targets. + /// @param _salt The create2 salt used to deploy Hyperdrive. /// @return The address of the newly deployed ERC4626Hyperdrive Instance. function deploy( + bytes32 _deploymentId, IHyperdrive.PoolDeployConfig memory _deployConfig, - bytes memory _extraData - ) public virtual returns (address) { + bytes memory _extraData, + bytes32 _salt + ) external returns (address) { + // Ensure that the Hyperdrive entrypoint has not already been deployed. + Deployment memory deployment = deployments[msg.sender][_deploymentId]; + if (deployment.hyperdrive != address(0)) { + revert IHyperdriveDeployerCoordinator.HyperdriveAlreadyDeployed(); + } + + // Ensure that the deployment is not a fresh deployment. We can check + // this by ensuring that the config hash is set. + if (deployment.configHash == bytes32(0)) { + revert IHyperdriveDeployerCoordinator.DeploymentDoesNotExist(); + } + + // Ensure that all of the targets have been deployed. + if ( + deployment.target0 == address(0) || + deployment.target1 == address(0) || + deployment.target2 == address(0) || + deployment.target3 == address(0) || + deployment.target4 == address(0) + ) { + revert IHyperdriveDeployerCoordinator.IncompleteDeployment(); + } + + // Ensure that the provided config matches the config hash. + if (keccak256(abi.encode(_deployConfig)) != deployment.configHash) { + revert IHyperdriveDeployerCoordinator.MismatchedConfig(); + } + + // Ensure that the provided extra data matches the extra data hash. + if (keccak256(_extraData) != deployment.extraDataHash) { + revert IHyperdriveDeployerCoordinator.MismatchedExtraData(); + } + // Convert the deploy config into the pool config and set the initial // vault share price. - IHyperdrive.PoolConfig memory _config = _copyPoolConfig(_deployConfig); - _config.initialVaultSharePrice = _getInitialVaultSharePrice(_extraData); - - // Deploy the target0 contract. - address target0 = IHyperdriveTargetDeployer(target0Deployer).deploy( - _config, - _extraData - ); - address target1 = IHyperdriveTargetDeployer(target1Deployer).deploy( - _config, - _extraData - ); - address target2 = IHyperdriveTargetDeployer(target2Deployer).deploy( - _config, - _extraData - ); - address target3 = IHyperdriveTargetDeployer(target3Deployer).deploy( - _config, - _extraData - ); + IHyperdrive.PoolConfig memory config = _copyPoolConfig(_deployConfig); + config.initialVaultSharePrice = deployment.initialSharePrice; // Deploy the Hyperdrive instance. return IHyperdriveCoreDeployer(coreDeployer).deploy( - _config, + config, + _extraData, + deployment.target0, + deployment.target1, + deployment.target2, + deployment.target3, + deployment.target4, + _salt + ); + } + + /// @notice Deploys a Hyperdrive target instance with the given parameters. + /// @dev As a convention, target0 must be deployed first. After this, the + /// targets can be deployed in any order. + /// @param _deploymentId The ID of the deployment. + /// @param _deployConfig The deploy configuration of the Hyperdrive pool. + /// @param _extraData The extra data that contains the pool and sweep targets. + /// @param _targetIndex The index of the target to deploy. + /// @param _salt The create2 salt used to deploy the target. + /// @return target The address of the newly deployed target instance. + function deployTarget( + bytes32 _deploymentId, + IHyperdrive.PoolDeployConfig memory _deployConfig, + bytes memory _extraData, + uint256 _targetIndex, + bytes32 _salt + ) external returns (address target) { + // If the target index is 0, then we're deploying the target0 instance. + // By convention, this target must be deployed first, and as part of the + // deployment of target0, we will register the deployment in the state. + if (_targetIndex == 0) { + // Ensure that the deployment is a fresh deployment. We can check this + // by ensuring that the config hash is not set. + if ( + deployments[msg.sender][_deploymentId].configHash != bytes32(0) + ) { + revert IHyperdriveDeployerCoordinator.DeploymentAlreadyExists(); + } + + // Check the pool configuration to ensure that it's a valid + // configuration for this instance. + _checkPoolConfig(_deployConfig); + + // Get the initial share price and the hashes of the config and extra + // data. + uint256 initialSharePrice = _getInitialVaultSharePrice(_extraData); + bytes32 configHash = keccak256(abi.encode(_deployConfig)); + bytes32 extraDataHash = keccak256(_extraData); + + // Convert the deploy config into the pool config and set the initial + // vault share price. + IHyperdrive.PoolConfig memory config_ = _copyPoolConfig( + _deployConfig + ); + config_.initialVaultSharePrice = initialSharePrice; + + // Deploy the target0 contract. + target = IHyperdriveTargetDeployer(target0Deployer).deploy( + config_, + _extraData, + _salt + ); + + // Store the deployment. + deployments[msg.sender][_deploymentId].configHash = configHash; + deployments[msg.sender][_deploymentId] + .extraDataHash = extraDataHash; + deployments[msg.sender][_deploymentId] + .initialSharePrice = initialSharePrice; + deployments[msg.sender][_deploymentId].target0 = target; + + return target; + } + + // Ensure that the deployment is not a fresh deployment. We can check + // this by ensuring that the config hash is set. + if (deployments[msg.sender][_deploymentId].configHash == bytes32(0)) { + revert IHyperdriveDeployerCoordinator.DeploymentDoesNotExist(); + } + + // Ensure that the provided config matches the config hash. + if ( + keccak256(abi.encode(_deployConfig)) != + deployments[msg.sender][_deploymentId].configHash + ) { + revert IHyperdriveDeployerCoordinator.MismatchedConfig(); + } + + // Ensure that the provided extra data matches the extra data hash. + if ( + keccak256(_extraData) != + deployments[msg.sender][_deploymentId].extraDataHash + ) { + revert IHyperdriveDeployerCoordinator.MismatchedExtraData(); + } + + // Convert the deploy config into the pool config and set the initial + // vault share price. + IHyperdrive.PoolConfig memory config = _copyPoolConfig(_deployConfig); + config.initialVaultSharePrice = deployments[msg.sender][_deploymentId] + .initialSharePrice; + + // If the target index is greater than 0, then we're deploying one of + // the other target instances. We don't allow targets to be deployed + // more than once, and their addresses are stored in the deployment + // state. + if (_targetIndex == 1) { + if (deployments[msg.sender][_deploymentId].target1 != address(0)) { + revert IHyperdriveDeployerCoordinator.TargetAlreadyDeployed(); + } + target = IHyperdriveTargetDeployer(target1Deployer).deploy( + config, + _extraData, + _salt + ); + deployments[msg.sender][_deploymentId].target1 = target; + } else if (_targetIndex == 2) { + if (deployments[msg.sender][_deploymentId].target2 != address(0)) { + revert IHyperdriveDeployerCoordinator.TargetAlreadyDeployed(); + } + target = IHyperdriveTargetDeployer(target2Deployer).deploy( + config, _extraData, - target0, - target1, - target2, - target3 + _salt ); + deployments[msg.sender][_deploymentId].target2 = target; + } else if (_targetIndex == 3) { + if (deployments[msg.sender][_deploymentId].target3 != address(0)) { + revert IHyperdriveDeployerCoordinator.TargetAlreadyDeployed(); + } + target = IHyperdriveTargetDeployer(target3Deployer).deploy( + config, + _extraData, + _salt + ); + deployments[msg.sender][_deploymentId].target3 = target; + } else if (_targetIndex == 4) { + if (deployments[msg.sender][_deploymentId].target4 != address(0)) { + revert IHyperdriveDeployerCoordinator.TargetAlreadyDeployed(); + } + target = IHyperdriveTargetDeployer(target4Deployer).deploy( + config, + _extraData, + _salt + ); + deployments[msg.sender][_deploymentId].target4 = target; + } else { + revert IHyperdriveDeployerCoordinator.InvalidTargetIndex(); + } + + return target; + } + + /// @notice Checks the pool configuration to ensure that it is valid. + /// @param _deployConfig The deploy configuration of the Hyperdrive pool. + function _checkPoolConfig( + IHyperdrive.PoolDeployConfig memory _deployConfig + ) internal view virtual { + // Ensure that the minimum share reserves is at least 1e3. Deployer + // coordinators should override this to be stricter. + if (_deployConfig.minimumShareReserves < 1e3) { + revert IHyperdriveDeployerCoordinator.InvalidMinimumShareReserves(); + } + + if (_deployConfig.checkpointDuration == 0) { + revert IHyperdriveDeployerCoordinator.InvalidCheckpointDuration(); + } + if ( + _deployConfig.positionDuration < _deployConfig.checkpointDuration || + _deployConfig.positionDuration % _deployConfig.checkpointDuration != + 0 + ) { + revert IHyperdriveDeployerCoordinator.InvalidPositionDuration(); + } + + // Ensure that the fees don't exceed 100%. + if ( + _deployConfig.fees.curve > 1e18 || + _deployConfig.fees.flat > 1e18 || + _deployConfig.fees.governanceLP > 1e18 || + _deployConfig.fees.governanceZombie > 1e18 + ) { + revert IHyperdriveDeployerCoordinator.InvalidFeeAmounts(); + } } /// @dev Gets the initial vault share price of the Hyperdrive pool. diff --git a/contracts/src/deployers/erc4626/ERC4626HyperdriveCoreDeployer.sol b/contracts/src/deployers/erc4626/ERC4626HyperdriveCoreDeployer.sol index f88603342..a68a973d9 100644 --- a/contracts/src/deployers/erc4626/ERC4626HyperdriveCoreDeployer.sol +++ b/contracts/src/deployers/erc4626/ERC4626HyperdriveCoreDeployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IERC4626 } from "../../interfaces/IERC4626.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; @@ -20,6 +20,8 @@ contract ERC4626HyperdriveCoreDeployer is IHyperdriveCoreDeployer { /// @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 ERC4626Hyperdrive instance. function deploy( IHyperdrive.PoolConfig memory _config, @@ -27,18 +29,20 @@ contract ERC4626HyperdriveCoreDeployer is IHyperdriveCoreDeployer { address target0, address target1, address target2, - address target3 - ) external override returns (address) { - // Deploy the ERC4626Hyperdrive instance. + address target3, + address target4, + bytes32 _salt + ) external returns (address) { address vault = abi.decode(_extraData, (address)); return ( address( - new ERC4626Hyperdrive( + new ERC4626Hyperdrive{ salt: _salt }( _config, target0, target1, target2, target3, + target4, IERC4626(vault) ) ) diff --git a/contracts/src/deployers/erc4626/ERC4626HyperdriveDeployerCoordinator.sol b/contracts/src/deployers/erc4626/ERC4626HyperdriveDeployerCoordinator.sol index f6523b533..e06ac6b3e 100644 --- a/contracts/src/deployers/erc4626/ERC4626HyperdriveDeployerCoordinator.sol +++ b/contracts/src/deployers/erc4626/ERC4626HyperdriveDeployerCoordinator.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IERC4626 } from "../../interfaces/IERC4626.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { IHyperdriveDeployerCoordinator } from "../../interfaces/IHyperdriveDeployerCoordinator.sol"; import { ONE } from "../../libraries/FixedPointMath.sol"; import { HyperdriveDeployerCoordinator } from "../HyperdriveDeployerCoordinator.sol"; @@ -19,30 +20,33 @@ contract ERC4626HyperdriveDeployerCoordinator is HyperdriveDeployerCoordinator { /// @param _target1Deployer The target1 deployer. /// @param _target2Deployer The target2 deployer. /// @param _target3Deployer The target3 deployer. + /// @param _target4Deployer The target4 deployer. constructor( address _coreDeployer, address _target0Deployer, address _target1Deployer, address _target2Deployer, - address _target3Deployer + address _target3Deployer, + address _target4Deployer ) HyperdriveDeployerCoordinator( _coreDeployer, _target0Deployer, _target1Deployer, _target2Deployer, - _target3Deployer + _target3Deployer, + _target4Deployer ) {} - /// @notice Deploys a Hyperdrive instance with the given parameters. + /// @notice Checks the pool configuration to ensure that it is valid. /// @param _deployConfig The deploy configuration of the Hyperdrive pool. - /// @param _extraData The extra data that contains the pool and sweep targets. - /// @return The address of the newly deployed ERC4626Hyperdrive Instance. - function deploy( - IHyperdrive.PoolDeployConfig memory _deployConfig, - bytes memory _extraData - ) public override returns (address) { + function _checkPoolConfig( + IHyperdrive.PoolDeployConfig memory _deployConfig + ) internal view override { + // Perform the default checks. + super._checkPoolConfig(_deployConfig); + // Ensure that the minimum share reserves are large enough to meet the // minimum requirements for safety. // @@ -52,7 +56,7 @@ contract ERC4626HyperdriveDeployerCoordinator is HyperdriveDeployerCoordinator { _deployConfig.minimumShareReserves < 10 ** (_deployConfig.baseToken.decimals() - 4) ) { - revert IHyperdrive.InvalidMinimumShareReserves(); + revert IHyperdriveDeployerCoordinator.InvalidMinimumShareReserves(); } // Ensure that the minimum transaction amount is large enough to meet @@ -64,11 +68,9 @@ contract ERC4626HyperdriveDeployerCoordinator is HyperdriveDeployerCoordinator { _deployConfig.minimumShareReserves < 10 ** (_deployConfig.baseToken.decimals() - 4) ) { - revert IHyperdrive.InvalidMinimumTransactionAmount(); + revert IHyperdriveDeployerCoordinator + .InvalidMinimumTransactionAmount(); } - - // Deploy the Hyperdrive instance. - return super.deploy(_deployConfig, _extraData); } /// @dev Gets the initial vault share price of the Hyperdrive pool. diff --git a/contracts/src/deployers/erc4626/ERC4626Target0Deployer.sol b/contracts/src/deployers/erc4626/ERC4626Target0Deployer.sol index ea69591ae..e1747d766 100644 --- a/contracts/src/deployers/erc4626/ERC4626Target0Deployer.sol +++ b/contracts/src/deployers/erc4626/ERC4626Target0Deployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { ERC4626Target0 } from "../../instances/erc4626/ERC4626Target0.sol"; import { IERC4626 } from "../../interfaces/IERC4626.sol"; @@ -16,13 +16,14 @@ contract ERC4626Target0Deployer is IHyperdriveTargetDeployer { /// @notice Deploys a target0 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. /// @param _extraData The extra data that contains the pool and sweep targets. + /// @param _salt The create2 salt used in the deployment. /// @return The address of the newly deployed ERC4626Target0 Instance. function deploy( IHyperdrive.PoolConfig memory _config, - bytes memory _extraData - ) external override returns (address) { - // Deploy the ERC4626Target0 instance. + bytes memory _extraData, + bytes32 _salt + ) external returns (address) { IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); - return address(new ERC4626Target0(_config, vault)); + return address(new ERC4626Target0{ salt: _salt }(_config, vault)); } } diff --git a/contracts/src/deployers/erc4626/ERC4626Target1Deployer.sol b/contracts/src/deployers/erc4626/ERC4626Target1Deployer.sol index 98404d0ac..1a6c1eb09 100644 --- a/contracts/src/deployers/erc4626/ERC4626Target1Deployer.sol +++ b/contracts/src/deployers/erc4626/ERC4626Target1Deployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { ERC4626Target1 } from "../../instances/erc4626/ERC4626Target1.sol"; import { IERC4626 } from "../../interfaces/IERC4626.sol"; @@ -16,13 +16,14 @@ contract ERC4626Target1Deployer is IHyperdriveTargetDeployer { /// @notice Deploys a target1 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. /// @param _extraData The extra data that contains the pool and sweep targets. + /// @param _salt The create2 salt used in the deployment. /// @return The address of the newly deployed ERC4626Target1 Instance. function deploy( IHyperdrive.PoolConfig memory _config, - bytes memory _extraData - ) external override returns (address) { - // Deploy the ERC4626Target1 instance. + bytes memory _extraData, + bytes32 _salt + ) external returns (address) { IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); - return address(new ERC4626Target1(_config, vault)); + return address(new ERC4626Target1{ salt: _salt }(_config, vault)); } } diff --git a/contracts/src/deployers/erc4626/ERC4626Target2Deployer.sol b/contracts/src/deployers/erc4626/ERC4626Target2Deployer.sol index 807584d0e..a592e1ae7 100644 --- a/contracts/src/deployers/erc4626/ERC4626Target2Deployer.sol +++ b/contracts/src/deployers/erc4626/ERC4626Target2Deployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { ERC4626Target2 } from "../../instances/erc4626/ERC4626Target2.sol"; import { IERC4626 } from "../../interfaces/IERC4626.sol"; @@ -16,13 +16,14 @@ contract ERC4626Target2Deployer is IHyperdriveTargetDeployer { /// @notice Deploys a target2 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. /// @param _extraData The extra data that contains the pool and sweep targets. + /// @param _salt The create2 salt used in the deployment. /// @return The address of the newly deployed ERC4626Target2 Instance. function deploy( IHyperdrive.PoolConfig memory _config, - bytes memory _extraData - ) external override returns (address) { - // Deploy the ERC4626Target2 instance. + bytes memory _extraData, + bytes32 _salt + ) external returns (address) { IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); - return address(new ERC4626Target2(_config, vault)); + return address(new ERC4626Target2{ salt: _salt }(_config, vault)); } } diff --git a/contracts/src/deployers/erc4626/ERC4626Target3Deployer.sol b/contracts/src/deployers/erc4626/ERC4626Target3Deployer.sol index 000d3abf7..45cbf3b44 100644 --- a/contracts/src/deployers/erc4626/ERC4626Target3Deployer.sol +++ b/contracts/src/deployers/erc4626/ERC4626Target3Deployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { ERC4626Target3 } from "../../instances/erc4626/ERC4626Target3.sol"; import { IERC4626 } from "../../interfaces/IERC4626.sol"; @@ -16,13 +16,14 @@ contract ERC4626Target3Deployer is IHyperdriveTargetDeployer { /// @notice Deploys a target3 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. /// @param _extraData The extra data that contains the pool and sweep targets. + /// @param _salt The create2 salt used in the deployment. /// @return The address of the newly deployed ERC4626Target3 Instance. function deploy( IHyperdrive.PoolConfig memory _config, - bytes memory _extraData - ) external override returns (address) { - // Deploy the ERC4626Target3 instance. + bytes memory _extraData, + bytes32 _salt + ) external returns (address) { IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); - return address(new ERC4626Target3(_config, vault)); + return address(new ERC4626Target3{ salt: _salt }(_config, vault)); } } diff --git a/contracts/src/deployers/erc4626/ERC4626Target4Deployer.sol b/contracts/src/deployers/erc4626/ERC4626Target4Deployer.sol new file mode 100644 index 000000000..cbb29a654 --- /dev/null +++ b/contracts/src/deployers/erc4626/ERC4626Target4Deployer.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { ERC4626Target4 } from "../../instances/erc4626/ERC4626Target4.sol"; +import { IERC4626 } from "../../interfaces/IERC4626.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; + +/// @author DELV +/// @title ERC4626Target4Deployer +/// @notice The target4 deployer for the ERC4626Hyperdrive 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 ERC4626Target4Deployer is IHyperdriveTargetDeployer { + /// @notice Deploys a target4 instance with the given parameters. + /// @param _config The configuration of the Hyperdrive pool. + /// @param _extraData The extra data that contains the pool and sweep targets. + /// @param _salt The create2 salt used in the deployment. + /// @return The address of the newly deployed ERC4626Target4 Instance. + function deploy( + IHyperdrive.PoolConfig memory _config, + bytes memory _extraData, + bytes32 _salt + ) external returns (address) { + IERC4626 vault = IERC4626(abi.decode(_extraData, (address))); + return address(new ERC4626Target4{ salt: _salt }(_config, vault)); + } +} diff --git a/contracts/src/deployers/steth/StETHHyperdriveCoreDeployer.sol b/contracts/src/deployers/steth/StETHHyperdriveCoreDeployer.sol index c6b6ebd22..26eb0b534 100644 --- a/contracts/src/deployers/steth/StETHHyperdriveCoreDeployer.sol +++ b/contracts/src/deployers/steth/StETHHyperdriveCoreDeployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IHyperdriveCoreDeployer } from "../../interfaces/IHyperdriveCoreDeployer.sol"; @@ -28,6 +28,8 @@ contract StETHHyperdriveCoreDeployer is IHyperdriveCoreDeployer { /// @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 StETHHyperdrive Instance. function deploy( IHyperdrive.PoolConfig memory _config, @@ -35,16 +37,19 @@ contract StETHHyperdriveCoreDeployer is IHyperdriveCoreDeployer { address target0, address target1, address target2, - address target3 - ) external override returns (address) { + address target3, + address target4, + bytes32 _salt + ) external returns (address) { return ( address( - new StETHHyperdrive( + new StETHHyperdrive{ salt: _salt }( _config, target0, target1, target2, target3, + target4, lido ) ) diff --git a/contracts/src/deployers/steth/StETHHyperdriveDeployerCoordinator.sol b/contracts/src/deployers/steth/StETHHyperdriveDeployerCoordinator.sol index 412e03ae6..415180fca 100644 --- a/contracts/src/deployers/steth/StETHHyperdriveDeployerCoordinator.sol +++ b/contracts/src/deployers/steth/StETHHyperdriveDeployerCoordinator.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { IHyperdriveDeployerCoordinator } from "../../interfaces/IHyperdriveDeployerCoordinator.sol"; import { ILido } from "../../interfaces/ILido.sol"; import { FixedPointMath, ONE } from "../../libraries/FixedPointMath.sol"; import { HyperdriveDeployerCoordinator } from "../HyperdriveDeployerCoordinator.sol"; @@ -23,6 +25,7 @@ contract StETHHyperdriveDeployerCoordinator is HyperdriveDeployerCoordinator { /// @param _target1Deployer The target1 deployer. /// @param _target2Deployer The target2 deployer. /// @param _target3Deployer The target3 deployer. + /// @param _target4Deployer The target4 deployer. /// @param _lido The Lido contract. constructor( address _coreDeployer, @@ -30,6 +33,7 @@ contract StETHHyperdriveDeployerCoordinator is HyperdriveDeployerCoordinator { address _target1Deployer, address _target2Deployer, address _target3Deployer, + address _target4Deployer, ILido _lido ) HyperdriveDeployerCoordinator( @@ -37,12 +41,37 @@ contract StETHHyperdriveDeployerCoordinator is HyperdriveDeployerCoordinator { _target0Deployer, _target1Deployer, _target2Deployer, - _target3Deployer + _target3Deployer, + _target4Deployer ) { lido = _lido; } + /// @notice Checks the pool configuration to ensure that it is valid. + /// @param _deployConfig The deploy configuration of the Hyperdrive pool. + function _checkPoolConfig( + IHyperdrive.PoolDeployConfig memory _deployConfig + ) internal view override { + // Perform the default checks. + super._checkPoolConfig(_deployConfig); + + // Ensure that the minimum share reserves are equal to 1e15. This value + // has been tested to prevent arithmetic overflows in the + // `_updateLiquidity` function when the share reserves are as high as + // 200 million. + if (_deployConfig.minimumShareReserves != 1e15) { + revert IHyperdriveDeployerCoordinator.InvalidMinimumShareReserves(); + } + + // Ensure that the minimum transaction amount are equal to 1e15. This + // value has been tested to prevent precision issues. + if (_deployConfig.minimumTransactionAmount != 1e15) { + 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( diff --git a/contracts/src/deployers/steth/StETHTarget0Deployer.sol b/contracts/src/deployers/steth/StETHTarget0Deployer.sol index 7af308c09..08a2d91cd 100644 --- a/contracts/src/deployers/steth/StETHTarget0Deployer.sol +++ b/contracts/src/deployers/steth/StETHTarget0Deployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { StETHTarget0 } from "../../instances/steth/StETHTarget0.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; @@ -24,12 +24,13 @@ contract StETHTarget0Deployer is IHyperdriveTargetDeployer { /// @notice Deploys a target0 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. + /// @param _salt The create2 salt used in the deployment. /// @return The address of the newly deployed StETHTarget0 Instance. function deploy( IHyperdrive.PoolConfig memory _config, - bytes memory // unused extra data + bytes memory, // unused extra data + bytes32 _salt ) external override returns (address) { - // Deploy the StETHTarget0 instance. - return address(new StETHTarget0(_config, lido)); + return address(new StETHTarget0{ salt: _salt }(_config, lido)); } } diff --git a/contracts/src/deployers/steth/StETHTarget1Deployer.sol b/contracts/src/deployers/steth/StETHTarget1Deployer.sol index 0cadc1b5d..9270b6a56 100644 --- a/contracts/src/deployers/steth/StETHTarget1Deployer.sol +++ b/contracts/src/deployers/steth/StETHTarget1Deployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { StETHTarget1 } from "../../instances/steth/StETHTarget1.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; @@ -24,12 +24,13 @@ contract StETHTarget1Deployer is IHyperdriveTargetDeployer { /// @notice Deploys a target1 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. + /// @param _salt The create2 salt used in the deployment. /// @return The address of the newly deployed StETHTarget1 Instance. function deploy( IHyperdrive.PoolConfig memory _config, - bytes memory // unused extra data - ) external override returns (address) { - // Deploy the StETHTarget1 instance. - return address(new StETHTarget1(_config, lido)); + bytes memory, // unused extra data + bytes32 _salt + ) external returns (address) { + return address(new StETHTarget1{ salt: _salt }(_config, lido)); } } diff --git a/contracts/src/deployers/steth/StETHTarget2Deployer.sol b/contracts/src/deployers/steth/StETHTarget2Deployer.sol index fd320cfed..46a96b5f8 100644 --- a/contracts/src/deployers/steth/StETHTarget2Deployer.sol +++ b/contracts/src/deployers/steth/StETHTarget2Deployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { StETHTarget2 } from "../../instances/steth/StETHTarget2.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; @@ -24,12 +24,13 @@ contract StETHTarget2Deployer is IHyperdriveTargetDeployer { /// @notice Deploys a target2 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. + /// @param _salt The create2 salt used in the deployment. /// @return The address of the newly deployed StETHTarget2 Instance. function deploy( IHyperdrive.PoolConfig memory _config, - bytes memory // unused extra data - ) external override returns (address) { - // Deploy the StETHTarget2 instance. - return address(new StETHTarget2(_config, lido)); + bytes memory, // unused extra data + bytes32 _salt + ) external returns (address) { + return address(new StETHTarget2{ salt: _salt }(_config, lido)); } } diff --git a/contracts/src/deployers/steth/StETHTarget3Deployer.sol b/contracts/src/deployers/steth/StETHTarget3Deployer.sol index b95b42725..d358339e3 100644 --- a/contracts/src/deployers/steth/StETHTarget3Deployer.sol +++ b/contracts/src/deployers/steth/StETHTarget3Deployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { StETHTarget3 } from "../../instances/steth/StETHTarget3.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; @@ -24,12 +24,13 @@ contract StETHTarget3Deployer is IHyperdriveTargetDeployer { /// @notice Deploys a target3 instance with the given parameters. /// @param _config The configuration of the Hyperdrive pool. + /// @param _salt The create2 salt used in the deployment. /// @return The address of the newly deployed StETHTarget3 Instance. function deploy( IHyperdrive.PoolConfig memory _config, - bytes memory // unused extra data - ) external override returns (address) { - // Deploy the StETHTarget3 instance. - return address(new StETHTarget3(_config, lido)); + bytes memory, // unused extra data + bytes32 _salt + ) external returns (address) { + return address(new StETHTarget3{ salt: _salt }(_config, lido)); } } diff --git a/contracts/src/deployers/steth/StETHTarget4Deployer.sol b/contracts/src/deployers/steth/StETHTarget4Deployer.sol new file mode 100644 index 000000000..ee41f614a --- /dev/null +++ b/contracts/src/deployers/steth/StETHTarget4Deployer.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { StETHTarget4 } from "../../instances/steth/StETHTarget4.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { IHyperdriveTargetDeployer } from "../../interfaces/IHyperdriveTargetDeployer.sol"; +import { ILido } from "../../interfaces/ILido.sol"; + +/// @author DELV +/// @title StETHTarget4Deployer +/// @notice The target4 deployer for the StETHHyperdrive 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 StETHTarget4Deployer is IHyperdriveTargetDeployer { + /// @notice The Lido contract. + ILido public immutable lido; + + /// @notice Instanstiates the target4 deployer. + /// @param _lido The Lido contract. + constructor(ILido _lido) { + lido = _lido; + } + + /// @notice Deploys a target4 instance with the given parameters. + /// @param _config The configuration of the Hyperdrive pool. + /// @param _salt The create2 salt used in the deployment. + /// @return The address of the newly deployed StETHTarget4 Instance. + function deploy( + IHyperdrive.PoolConfig memory _config, + bytes memory, // unused extra data + bytes32 _salt + ) external returns (address) { + return address(new StETHTarget4{ salt: _salt }(_config, lido)); + } +} diff --git a/contracts/src/external/Hyperdrive.sol b/contracts/src/external/Hyperdrive.sol index 703e05a64..ce80eacf3 100644 --- a/contracts/src/external/Hyperdrive.sol +++ b/contracts/src/external/Hyperdrive.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { HyperdriveTarget0 } from "../external/HyperdriveTarget0.sol"; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; @@ -43,6 +43,10 @@ abstract contract Hyperdrive is /// some stateful functions. address public immutable target3; + /// @notice The target4 address. This is a logic contract that contains all + /// some stateful functions. + address public immutable target4; + /// @notice The typehash used to calculate the EIP712 hash for `permitForAll`. bytes32 public constant PERMIT_TYPEHASH = keccak256( @@ -58,18 +62,21 @@ abstract contract Hyperdrive is /// @param _target1 The target1 address. /// @param _target2 The target2 address. /// @param _target3 The target3 address. + /// @param _target4 The target4 address. constructor( IHyperdrive.PoolConfig memory _config, address _target0, address _target1, address _target2, - address _target3 + address _target3, + address _target4 ) HyperdriveStorage(_config) { // Initialize the target contracts. target0 = _target0; target1 = _target1; target2 = _target2; target3 = _target3; + target4 = _target4; // NOTE: It's convenient to keep this in the `Hyperdrive.sol` // entry-point to avoiding issues with initializing the domain @@ -127,7 +134,7 @@ abstract contract Hyperdrive is uint256, IHyperdrive.Options calldata ) external payable returns (uint256, uint256) { - _delegate(target2); + _delegate(target3); } /// @notice Closes a long position with a specified maturity time. @@ -137,7 +144,7 @@ abstract contract Hyperdrive is uint256, IHyperdrive.Options calldata ) external returns (uint256) { - _delegate(target3); + _delegate(target2); } /// Shorts /// @@ -149,7 +156,7 @@ abstract contract Hyperdrive is uint256, IHyperdrive.Options calldata ) external payable returns (uint256, uint256) { - _delegate(target2); + _delegate(target4); } /// @notice Closes a short position with a specified maturity time. @@ -159,7 +166,7 @@ abstract contract Hyperdrive is uint256, IHyperdrive.Options calldata ) external returns (uint256) { - _delegate(target3); + _delegate(target2); } /// LPs /// @@ -209,7 +216,7 @@ abstract contract Hyperdrive is /// @notice Allows anyone to mint a new checkpoint. function checkpoint(uint256) external { - _delegate(target3); + _delegate(target2); } /// Admin /// diff --git a/contracts/src/external/HyperdriveTarget0.sol b/contracts/src/external/HyperdriveTarget0.sol index 187fa8338..6fa16f751 100644 --- a/contracts/src/external/HyperdriveTarget0.sol +++ b/contracts/src/external/HyperdriveTarget0.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { IHyperdriveRead } from "../interfaces/IHyperdriveRead.sol"; diff --git a/contracts/src/external/HyperdriveTarget1.sol b/contracts/src/external/HyperdriveTarget1.sol index 4e5a74c41..2d3e7c2b7 100644 --- a/contracts/src/external/HyperdriveTarget1.sol +++ b/contracts/src/external/HyperdriveTarget1.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { HyperdriveAdmin } from "../internal/HyperdriveAdmin.sol"; diff --git a/contracts/src/external/HyperdriveTarget2.sol b/contracts/src/external/HyperdriveTarget2.sol index 5c45fbf96..9db256f69 100644 --- a/contracts/src/external/HyperdriveTarget2.sol +++ b/contracts/src/external/HyperdriveTarget2.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { HyperdriveAdmin } from "../internal/HyperdriveAdmin.sol"; @@ -32,43 +32,43 @@ abstract contract HyperdriveTarget2 is /// Longs /// - /// @notice Opens a long position. - /// @param _baseAmount The amount of base to use when trading. - /// @param _minOutput The minium number of bonds to receive. - /// @param _minVaultSharePrice The minium share price at which to open the long. - /// This allows traders to protect themselves from opening a long in - /// a checkpoint where negative interest has accrued. + /// @notice Closes a long position with a specified maturity time. + /// @param _maturityTime The maturity time of the short. + /// @param _bondAmount The amount of longs to close. + /// @param _minOutput The minimum amount of base the trader will accept. /// @param _options The options that configure how the trade is settled. - /// @return maturityTime The maturity time of the bonds. - /// @return bondProceeds The amount of bonds the user received. - function openLong( - uint256 _baseAmount, + /// @return The amount of underlying the user receives. + function closeLong( + uint256 _maturityTime, + uint256 _bondAmount, uint256 _minOutput, - uint256 _minVaultSharePrice, IHyperdrive.Options calldata _options - ) external payable returns (uint256 maturityTime, uint256 bondProceeds) { - return - _openLong(_baseAmount, _minOutput, _minVaultSharePrice, _options); + ) external returns (uint256) { + return _closeLong(_maturityTime, _bondAmount, _minOutput, _options); } /// Shorts /// - /// @notice Opens a short position. - /// @param _bondAmount The amount of bonds to short. - /// @param _maxDeposit The most the user expects to deposit for this trade - /// @param _minVaultSharePrice The minium share price at which to open the long. - /// This allows traders to protect themselves from opening a long in - /// a checkpoint where negative interest has accrued. + /// @notice Closes a short position with a specified maturity time. + /// @param _maturityTime The maturity time of the short. + /// @param _bondAmount The amount of shorts to close. + /// @param _minOutput The minimum output of this trade. /// @param _options The options that configure how the trade is settled. - /// @return maturityTime The maturity time of the short. - /// @return traderDeposit The amount the user deposited for this trade. - function openShort( + /// @return The amount of base tokens produced by closing this short. + function closeShort( + uint256 _maturityTime, uint256 _bondAmount, - uint256 _maxDeposit, - uint256 _minVaultSharePrice, + uint256 _minOutput, IHyperdrive.Options calldata _options - ) external payable returns (uint256 maturityTime, uint256 traderDeposit) { - return - _openShort(_bondAmount, _maxDeposit, _minVaultSharePrice, _options); + ) external returns (uint256) { + return _closeShort(_maturityTime, _bondAmount, _minOutput, _options); + } + + /// Checkpoints /// + + /// @notice Allows anyone to mint a new checkpoint. + /// @param _checkpointTime The time of the checkpoint to create. + function checkpoint(uint256 _checkpointTime) external { + _checkpoint(_checkpointTime); } } diff --git a/contracts/src/external/HyperdriveTarget3.sol b/contracts/src/external/HyperdriveTarget3.sol index 64ea06085..ea23993bd 100644 --- a/contracts/src/external/HyperdriveTarget3.sol +++ b/contracts/src/external/HyperdriveTarget3.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { HyperdriveAdmin } from "../internal/HyperdriveAdmin.sol"; @@ -32,43 +32,22 @@ abstract contract HyperdriveTarget3 is /// Longs /// - /// @notice Closes a long position with a specified maturity time. - /// @param _maturityTime The maturity time of the short. - /// @param _bondAmount The amount of longs to close. - /// @param _minOutput The minimum amount of base the trader will accept. + /// @notice Opens a long position. + /// @param _baseAmount The amount of base to use when trading. + /// @param _minOutput The minium number of bonds to receive. + /// @param _minVaultSharePrice The minium share price at which to open the long. + /// This allows traders to protect themselves from opening a long in + /// a checkpoint where negative interest has accrued. /// @param _options The options that configure how the trade is settled. - /// @return The amount of underlying the user receives. - function closeLong( - uint256 _maturityTime, - uint256 _bondAmount, + /// @return maturityTime The maturity time of the bonds. + /// @return bondProceeds The amount of bonds the user received. + function openLong( + uint256 _baseAmount, uint256 _minOutput, + uint256 _minVaultSharePrice, IHyperdrive.Options calldata _options - ) external returns (uint256) { - return _closeLong(_maturityTime, _bondAmount, _minOutput, _options); - } - - /// Shorts /// - - /// @notice Closes a short position with a specified maturity time. - /// @param _maturityTime The maturity time of the short. - /// @param _bondAmount The amount of shorts to close. - /// @param _minOutput The minimum output of this trade. - /// @param _options The options that configure how the trade is settled. - /// @return The amount of base tokens produced by closing this short. - function closeShort( - uint256 _maturityTime, - uint256 _bondAmount, - uint256 _minOutput, - IHyperdrive.Options calldata _options - ) external returns (uint256) { - return _closeShort(_maturityTime, _bondAmount, _minOutput, _options); - } - - /// Checkpoints /// - - /// @notice Allows anyone to mint a new checkpoint. - /// @param _checkpointTime The time of the checkpoint to create. - function checkpoint(uint256 _checkpointTime) external { - _checkpoint(_checkpointTime); + ) external payable returns (uint256 maturityTime, uint256 bondProceeds) { + return + _openLong(_baseAmount, _minOutput, _minVaultSharePrice, _options); } } diff --git a/contracts/src/external/HyperdriveTarget4.sol b/contracts/src/external/HyperdriveTarget4.sol new file mode 100644 index 000000000..a817fde74 --- /dev/null +++ b/contracts/src/external/HyperdriveTarget4.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; +import { HyperdriveAdmin } from "../internal/HyperdriveAdmin.sol"; +import { HyperdriveCheckpoint } from "../internal/HyperdriveCheckpoint.sol"; +import { HyperdriveLong } from "../internal/HyperdriveLong.sol"; +import { HyperdriveLP } from "../internal/HyperdriveLP.sol"; +import { HyperdriveMultiToken } from "../internal/HyperdriveMultiToken.sol"; +import { HyperdriveShort } from "../internal/HyperdriveShort.sol"; +import { HyperdriveStorage } from "../internal/HyperdriveStorage.sol"; + +/// @author DELV +/// @title HyperdriveTarget4 +/// @notice Hyperdrive's target 4 logic contract. +/// @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. +abstract contract HyperdriveTarget4 is + HyperdriveAdmin, + HyperdriveMultiToken, + HyperdriveLP, + HyperdriveLong, + HyperdriveShort, + HyperdriveCheckpoint +{ + /// @notice Instantiates target4. + /// @param _config The configuration of the Hyperdrive pool. + constructor( + IHyperdrive.PoolConfig memory _config + ) HyperdriveStorage(_config) {} + + /// Shorts /// + + /// @notice Opens a short position. + /// @param _bondAmount The amount of bonds to short. + /// @param _maxDeposit The most the user expects to deposit for this trade + /// @param _minVaultSharePrice The minium share price at which to open the long. + /// This allows traders to protect themselves from opening a long in + /// a checkpoint where negative interest has accrued. + /// @param _options The options that configure how the trade is settled. + /// @return maturityTime The maturity time of the short. + /// @return traderDeposit The amount the user deposited for this trade. + function openShort( + uint256 _bondAmount, + uint256 _maxDeposit, + uint256 _minVaultSharePrice, + IHyperdrive.Options calldata _options + ) external payable returns (uint256 maturityTime, uint256 traderDeposit) { + return + _openShort(_bondAmount, _maxDeposit, _minVaultSharePrice, _options); + } +} diff --git a/contracts/src/factory/HyperdriveFactory.sol b/contracts/src/factory/HyperdriveFactory.sol index c1b9c44ee..70dac1a26 100644 --- a/contracts/src/factory/HyperdriveFactory.sol +++ b/contracts/src/factory/HyperdriveFactory.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; -import { ERC20 } from "solmate/tokens/ERC20.sol"; -import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol"; +import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; +import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { IHyperdriveFactory } from "../interfaces/IHyperdriveFactory.sol"; -import { IDeployerCoordinator } from "../interfaces/IDeployerCoordinator.sol"; +import { IHyperdriveDeployerCoordinator } from "../interfaces/IHyperdriveDeployerCoordinator.sol"; import { FixedPointMath, ONE } from "../libraries/FixedPointMath.sol"; import { HyperdriveMath } from "../libraries/HyperdriveMath.sol"; @@ -18,7 +18,7 @@ import { HyperdriveMath } from "../libraries/HyperdriveMath.sol"; /// particular legal or regulatory significance. contract HyperdriveFactory is IHyperdriveFactory { using FixedPointMath for uint256; - using SafeTransferLib for ERC20; + using SafeERC20 for ERC20; /// @notice The resolution for the checkpoint duration. Every checkpoint /// duration must be a multiple of this resolution. @@ -568,131 +568,56 @@ contract HyperdriveFactory is IHyperdriveFactory { /// @dev This function is declared as payable to allow payable overrides /// to accept ether on initialization, but payability is not supported /// by default. + /// @param _deploymentId The deployment ID to use when deploying the pool. /// @param _deployerCoordinator The deployer coordinator to use in this /// deployment. - /// @param _deployConfig The deploy configuration of the Hyperdrive pool. + /// @param _config The configuration of the Hyperdrive pool. /// @param _extraData The extra data that contains data necessary for the /// specific deployer. /// @param _contribution The contribution amount in base to the pool. /// @param _fixedAPR The fixed APR used to initialize the pool. /// @param _timeStretchAPR The time stretch APR used to initialize the pool. /// @param _initializeExtraData The extra data for the `initialize` call. + /// @param _salt The create2 salt to use for the deployment. /// @return The hyperdrive address deployed. function deployAndInitialize( + bytes32 _deploymentId, address _deployerCoordinator, - IHyperdrive.PoolDeployConfig memory _deployConfig, + IHyperdrive.PoolDeployConfig memory _config, bytes memory _extraData, uint256 _contribution, uint256 _fixedAPR, uint256 _timeStretchAPR, - bytes memory _initializeExtraData - ) public payable virtual returns (IHyperdrive) { - // Ensure that the target deployer has been registered. + bytes memory _initializeExtraData, + bytes32 _salt + ) external payable returns (IHyperdrive) { + // Ensure that the deployer coordinator has been registered. if (!isDeployerCoordinator[_deployerCoordinator]) { revert IHyperdriveFactory.InvalidDeployerCoordinator(); } - // Ensure that the specified checkpoint duration is within the minimum - // and maximum checkpoint durations and is a multiple of the checkpoint - // duration resolution. - if ( - _deployConfig.checkpointDuration < minCheckpointDuration || - _deployConfig.checkpointDuration > maxCheckpointDuration || - _deployConfig.checkpointDuration % checkpointDurationResolution != 0 - ) { - revert IHyperdriveFactory.InvalidCheckpointDuration(); - } - - // Ensure that the specified checkpoint duration is within the minimum - // and maximum position durations and is a multiple of the specified - // checkpoint duration. - if ( - _deployConfig.positionDuration < minPositionDuration || - _deployConfig.positionDuration > maxPositionDuration || - _deployConfig.positionDuration % _deployConfig.checkpointDuration != - 0 - ) { - revert IHyperdriveFactory.InvalidPositionDuration(); - } + // Override the config values to the default values set by governance + // and ensure that the config is valid. + _overrideConfig(_config, _fixedAPR, _timeStretchAPR); - // Ensure that the specified fees are within the minimum and maximum fees. - if ( - _deployConfig.fees.curve > _maxFees.curve || - _deployConfig.fees.flat > _maxFees.flat || - _deployConfig.fees.governanceLP > _maxFees.governanceLP || - _deployConfig.fees.governanceZombie > _maxFees.governanceZombie || - _deployConfig.fees.curve < _minFees.curve || - _deployConfig.fees.flat < _minFees.flat || - _deployConfig.fees.governanceLP < _minFees.governanceLP || - _deployConfig.fees.governanceZombie < _minFees.governanceZombie - ) { - revert IHyperdriveFactory.InvalidFees(); - } - - // Ensure that the linker factory, linker code hash, fee collector, - // and governance addresses aren't set. This ensures that the - // deployer isn't trying to set these values. - if ( - _deployConfig.governance != address(0) || - _deployConfig.feeCollector != address(0) || - _deployConfig.linkerFactory != address(0) || - _deployConfig.linkerCodeHash != bytes32(0) || - _deployConfig.timeStretch != 0 - ) { - revert IHyperdriveFactory.InvalidDeployConfig(); - } - - // Ensure that specified fixed APR is within the minimum and maximum - // fixed APRs. - if (_fixedAPR < minFixedAPR || _fixedAPR > maxFixedAPR) { - revert IHyperdriveFactory.InvalidFixedAPR(); - } - - // Calculate the time stretch using the provided APR and ensure that - // the time stretch falls within a safe range and the guards specified - // by governance. - uint256 lowerBound = _fixedAPR.divDown(2e18).max(0.005e18); - if ( - _timeStretchAPR < minTimeStretchAPR.max(lowerBound) || - _timeStretchAPR > - maxTimeStretchAPR.min(_fixedAPR.max(lowerBound).mulDown(2e18)) - ) { - revert IHyperdriveFactory.InvalidTimeStretchAPR(); - } - uint256 timeStretch = HyperdriveMath.calculateTimeStretch( - _timeStretchAPR, - _deployConfig.positionDuration - ); - - // Override the config values to the default values set by governance. - // The factory assumes the governance role during deployment so that it - // can set up some initial values; however the governance role will - // ultimately be transferred to the hyperdrive governance address. - _deployConfig.governance = address(this); - _deployConfig.feeCollector = feeCollector; - _deployConfig.linkerFactory = linkerFactory; - _deployConfig.linkerCodeHash = linkerCodeHash; - _deployConfig.timeStretch = timeStretch; - - // Deploy the Hyperdrive instance with the specified Hyperdrive - // deployer. + // Deploy the Hyperdrive instance with the specified deployer + // coordinator. IHyperdrive hyperdrive = IHyperdrive( - IDeployerCoordinator(_deployerCoordinator).deploy( - _deployConfig, - _extraData + IHyperdriveDeployerCoordinator(_deployerCoordinator).deploy( + // NOTE: We hash the deployer's address into the deployment ID + // to prevent their deployment from being front-run. + keccak256(abi.encode(msg.sender, _deploymentId)), + _config, + _extraData, + _salt ) ); // Add this instance to the registry and emit an event with the // deployment configuration. isOfficial[address(hyperdrive)] = versionCounter; - _deployConfig.governance = hyperdriveGovernance; - emit Deployed( - versionCounter, - address(hyperdrive), - _deployConfig, - _extraData - ); + _config.governance = hyperdriveGovernance; + emit Deployed(versionCounter, address(hyperdrive), _config, _extraData); // Add the newly deployed Hyperdrive instance to the registry. _instances.push(address(hyperdrive)); @@ -721,12 +646,12 @@ contract HyperdriveFactory is IHyperdriveFactory { // Transfer the contribution to this contract and set an approval // on Hyperdrive to prepare for initialization. - ERC20(address(_deployConfig.baseToken)).safeTransferFrom( + ERC20(address(_config.baseToken)).safeTransferFrom( msg.sender, address(this), _contribution ); - ERC20(address(_deployConfig.baseToken)).safeApprove( + ERC20(address(_config.baseToken)).forceApprove( address(hyperdrive), _contribution ); @@ -764,6 +689,52 @@ contract HyperdriveFactory is IHyperdriveFactory { return hyperdrive; } + /// @notice Deploys a Hyperdrive target with the factory's configuration. + /// @param _deploymentId The deployment ID to use when deploying the pool. + /// @param _deployerCoordinator The deployer coordinator to use in this + /// deployment. + /// @param _config The configuration of the Hyperdrive pool. + /// @param _extraData The extra data that contains data necessary for the + /// specific deployer. + /// @param _fixedAPR The fixed APR used to initialize the pool. + /// @param _timeStretchAPR The time stretch APR used to initialize the pool. + /// @param _targetIndex The index of the target to deploy. + /// @param _salt The create2 salt to use for the deployment. + /// @return The target address deployed. + function deployTarget( + bytes32 _deploymentId, + address _deployerCoordinator, + IHyperdrive.PoolDeployConfig memory _config, + bytes memory _extraData, + uint256 _fixedAPR, + uint256 _timeStretchAPR, + uint256 _targetIndex, + bytes32 _salt + ) external returns (address) { + // Ensure that the deployer coordinator has been registered. + if (!isDeployerCoordinator[_deployerCoordinator]) { + revert IHyperdriveFactory.InvalidDeployerCoordinator(); + } + + // Override the config values to the default values set by governance + // and ensure that the config is valid. + _overrideConfig(_config, _fixedAPR, _timeStretchAPR); + + // Deploy the target instance with the specified deployer coordinator. + address target = IHyperdriveDeployerCoordinator(_deployerCoordinator) + .deployTarget( + // NOTE: We hash the deployer's address into the deployment ID + // to prevent their deployment from being front-run. + keccak256(abi.encode(msg.sender, _deploymentId)), + _config, + _extraData, + _targetIndex, + _salt + ); + + return target; + } + /// @notice Gets the max fees. /// @return The max fees. function maxFees() external view returns (IHyperdrive.Fees memory) { @@ -857,4 +828,97 @@ contract HyperdriveFactory is IHyperdriveFactory { range[i - startIndex] = _deployerCoordinators[i]; } } + + /// @dev Overrides the config values to the default values set by + /// governance. In the process of overriding these parameters, this + /// verifies that the specified config is valid. + /// @param _config The config to override. + /// @param _fixedAPR The fixed APR to use in the override. + /// @param _timeStretchAPR The time stretch APR to use in the override. + function _overrideConfig( + IHyperdrive.PoolDeployConfig memory _config, + uint256 _fixedAPR, + uint256 _timeStretchAPR + ) internal view { + // Ensure that the specified checkpoint duration is within the minimum + // and maximum checkpoint durations and is a multiple of the checkpoint + // duration resolution. + if ( + _config.checkpointDuration < minCheckpointDuration || + _config.checkpointDuration > maxCheckpointDuration || + _config.checkpointDuration % checkpointDurationResolution != 0 + ) { + revert IHyperdriveFactory.InvalidCheckpointDuration(); + } + + // Ensure that the specified checkpoint duration is within the minimum + // and maximum position durations and is a multiple of the specified + // checkpoint duration. + if ( + _config.positionDuration < minPositionDuration || + _config.positionDuration > maxPositionDuration || + _config.positionDuration % _config.checkpointDuration != 0 + ) { + revert IHyperdriveFactory.InvalidPositionDuration(); + } + + // Ensure that the specified fees are within the minimum and maximum fees. + if ( + _config.fees.curve > _maxFees.curve || + _config.fees.flat > _maxFees.flat || + _config.fees.governanceLP > _maxFees.governanceLP || + _config.fees.governanceZombie > _maxFees.governanceZombie || + _config.fees.curve < _minFees.curve || + _config.fees.flat < _minFees.flat || + _config.fees.governanceLP < _minFees.governanceLP || + _config.fees.governanceZombie < _minFees.governanceZombie + ) { + revert IHyperdriveFactory.InvalidFees(); + } + + // Ensure that the linker factory, linker code hash, fee collector, and + // governance addresses and time stretch aren't set. This ensures that + // the deployer isn't trying to set these values. + if ( + _config.linkerFactory != address(0) || + _config.linkerCodeHash != bytes32(0) || + _config.feeCollector != address(0) || + _config.governance != address(0) || + _config.timeStretch != 0 + ) { + revert IHyperdriveFactory.InvalidDeployConfig(); + } + + // Ensure that specified fixed APR is within the minimum and maximum + // fixed APRs. + if (_fixedAPR < minFixedAPR || _fixedAPR > maxFixedAPR) { + revert IHyperdriveFactory.InvalidFixedAPR(); + } + + // Calculate the time stretch using the provided APR and ensure that + // the time stretch falls within a safe range and the guards specified + // by governance. + uint256 lowerBound = _fixedAPR.divDown(2e18).max(0.005e18); + if ( + _timeStretchAPR < minTimeStretchAPR.max(lowerBound) || + _timeStretchAPR > + maxTimeStretchAPR.min(_fixedAPR.max(lowerBound).mulDown(2e18)) + ) { + revert IHyperdriveFactory.InvalidTimeStretchAPR(); + } + uint256 timeStretch = HyperdriveMath.calculateTimeStretch( + _timeStretchAPR, + _config.positionDuration + ); + + // Override the config values to the default values set by governance. + // The factory assumes the governance role during deployment so that it + // can set up some initial values; however the governance role will + // ultimately be transferred to the hyperdrive governance address. + _config.linkerFactory = linkerFactory; + _config.linkerCodeHash = linkerCodeHash; + _config.feeCollector = feeCollector; + _config.governance = address(this); + _config.timeStretch = timeStretch; + } } diff --git a/contracts/src/factory/HyperdriveRegistry.sol b/contracts/src/factory/HyperdriveRegistry.sol index 37c4b2f01..ba54ecbf9 100644 --- a/contracts/src/factory/HyperdriveRegistry.sol +++ b/contracts/src/factory/HyperdriveRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { IHyperdriveGovernedRegistry } from "../interfaces/IHyperdriveGovernedRegistry.sol"; @@ -11,7 +11,7 @@ contract HyperdriveRegistry is { address public governance; - mapping(address hyperdrive => uint256 data) _hyperdriveInfo; + mapping(address hyperdrive => uint256 data) internal _hyperdriveInfo; constructor() { governance = msg.sender; diff --git a/contracts/src/instances/erc4626/ERC4626Base.sol b/contracts/src/instances/erc4626/ERC4626Base.sol index 105955642..a80047f6a 100644 --- a/contracts/src/instances/erc4626/ERC4626Base.sol +++ b/contracts/src/instances/erc4626/ERC4626Base.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; -import { ERC20 } from "solmate/tokens/ERC20.sol"; -import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol"; +import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; +import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; import { IERC4626 } from "../../interfaces/IERC4626.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IERC4626Hyperdrive } from "../../interfaces/IERC4626Hyperdrive.sol"; @@ -17,7 +17,7 @@ import { FixedPointMath, ONE } from "../../libraries/FixedPointMath.sol"; /// particular legal or regulatory significance. abstract contract ERC4626Base is HyperdriveBase { using FixedPointMath for uint256; - using SafeTransferLib for ERC20; + using SafeERC20 for ERC20; /// @dev The ERC4626 vault that this pool uses as a yield source. IERC4626 internal immutable _vault; @@ -58,7 +58,14 @@ abstract contract ERC4626Base is HyperdriveBase { ); // Deposit the base into the yield source. - ERC20(address(_baseToken)).safeApprove(address(_vault), _amount); + // + // NOTE: We increase the required approval amount by 1 wei so that + // the vault ends with an approval of 1 wei. This makes future + // approvals cheaper by keeping the storage slot warm. + ERC20(address(_baseToken)).forceApprove( + address(_vault), + _amount + 1 + ); sharesMinted = _vault.deposit(_amount, address(this)); } else { // WARN: This logic doesn't account for slippage in the conversion diff --git a/contracts/src/instances/erc4626/ERC4626Hyperdrive.sol b/contracts/src/instances/erc4626/ERC4626Hyperdrive.sol index 1e7ad80b4..a4fbdb0a8 100644 --- a/contracts/src/instances/erc4626/ERC4626Hyperdrive.sol +++ b/contracts/src/instances/erc4626/ERC4626Hyperdrive.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; -import { ERC20 } from "solmate/tokens/ERC20.sol"; -import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol"; +import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; +import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; import { Hyperdrive } from "../../external/Hyperdrive.sol"; import { IERC20 } from "../../interfaces/IERC20.sol"; import { IERC4626 } from "../../interfaces/IERC4626.sol"; @@ -19,7 +19,7 @@ import { ERC4626Base } from "./ERC4626Base.sol"; /// particular legal or regulatory significance. contract ERC4626Hyperdrive is Hyperdrive, ERC4626Base { using FixedPointMath for uint256; - using SafeTransferLib for ERC20; + using SafeERC20 for ERC20; /// @notice Instantiates Hyperdrive with a ERC4626 vault as the yield source. /// @param _config The configuration of the Hyperdrive pool. @@ -27,6 +27,7 @@ contract ERC4626Hyperdrive is Hyperdrive, ERC4626Base { /// @param _target1 The target1 address. /// @param _target2 The target2 address. /// @param _target3 The target3 address. + /// @param _target4 The target4 address. /// @param __vault The ERC4626 compatible yield source. constructor( IHyperdrive.PoolConfig memory _config, @@ -34,23 +35,12 @@ contract ERC4626Hyperdrive is Hyperdrive, ERC4626Base { address _target1, address _target2, address _target3, + address _target4, IERC4626 __vault ) - Hyperdrive(_config, _target0, _target1, _target2, _target3) + Hyperdrive(_config, _target0, _target1, _target2, _target3, _target4) ERC4626Base(__vault) { - // Ensure that the initial vault share price is properly configured. - // - // WARN: ERC4626 implementations should be checked that if they use an - // asset with decimals less than 18 that the preview deposit is scale - // invariant. EG - because this line uses a very large query to load - // price for USDC if the price per vault share changes based on size of - // deposit then this line will read an incorrect and possibly dangerous - // price. - if (_config.initialVaultSharePrice != _pricePerVaultShare()) { - revert IHyperdrive.InvalidInitialVaultSharePrice(); - } - // Ensure that the base token is the same as the vault's underlying // asset. if (address(_config.baseToken) != IERC4626(_vault).asset()) { @@ -59,7 +49,7 @@ contract ERC4626Hyperdrive is Hyperdrive, ERC4626Base { // Approve the base token with 1 wei. This ensures that all of the // subsequent approvals will be writing to a dirty storage slot. - ERC20(address(_config.baseToken)).safeApprove(address(_vault), 1); + ERC20(address(_config.baseToken)).forceApprove(address(_vault), 1); } /// @notice Some yield sources [eg Morpho] pay rewards directly to this diff --git a/contracts/src/instances/erc4626/ERC4626Target0.sol b/contracts/src/instances/erc4626/ERC4626Target0.sol index 5060e238e..cde00b468 100644 --- a/contracts/src/instances/erc4626/ERC4626Target0.sol +++ b/contracts/src/instances/erc4626/ERC4626Target0.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; -import { ERC20 } from "solmate/tokens/ERC20.sol"; -import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol"; +import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; +import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; import { HyperdriveTarget0 } from "../../external/HyperdriveTarget0.sol"; import { IERC20 } from "../../interfaces/IERC20.sol"; import { IERC4626 } from "../../interfaces/IERC4626.sol"; @@ -18,7 +18,7 @@ import { ERC4626Base } from "./ERC4626Base.sol"; /// only, and is not intended to, and does not, have any /// particular legal or regulatory significance. contract ERC4626Target0 is HyperdriveTarget0, ERC4626Base { - using SafeTransferLib for ERC20; + using SafeERC20 for ERC20; /// @notice Initializes the target0 contract. /// @param _config The configuration of the Hyperdrive pool. diff --git a/contracts/src/instances/erc4626/ERC4626Target1.sol b/contracts/src/instances/erc4626/ERC4626Target1.sol index a24181757..da92256ed 100644 --- a/contracts/src/instances/erc4626/ERC4626Target1.sol +++ b/contracts/src/instances/erc4626/ERC4626Target1.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { HyperdriveTarget1 } from "../../external/HyperdriveTarget1.sol"; import { IERC4626 } from "../../interfaces/IERC4626.sol"; diff --git a/contracts/src/instances/erc4626/ERC4626Target2.sol b/contracts/src/instances/erc4626/ERC4626Target2.sol index 6f2ad54a2..a7c09a3db 100644 --- a/contracts/src/instances/erc4626/ERC4626Target2.sol +++ b/contracts/src/instances/erc4626/ERC4626Target2.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { HyperdriveTarget2 } from "../../external/HyperdriveTarget2.sol"; import { IERC4626 } from "../../interfaces/IERC4626.sol"; diff --git a/contracts/src/instances/erc4626/ERC4626Target3.sol b/contracts/src/instances/erc4626/ERC4626Target3.sol index 1f4f8b81b..c51e68da6 100644 --- a/contracts/src/instances/erc4626/ERC4626Target3.sol +++ b/contracts/src/instances/erc4626/ERC4626Target3.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { HyperdriveTarget3 } from "../../external/HyperdriveTarget3.sol"; import { IERC4626 } from "../../interfaces/IERC4626.sol"; diff --git a/contracts/src/instances/erc4626/ERC4626Target4.sol b/contracts/src/instances/erc4626/ERC4626Target4.sol new file mode 100644 index 000000000..db654cc2e --- /dev/null +++ b/contracts/src/instances/erc4626/ERC4626Target4.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { HyperdriveTarget4 } from "../../external/HyperdriveTarget4.sol"; +import { IERC4626 } from "../../interfaces/IERC4626.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { ERC4626Base } from "./ERC4626Base.sol"; + +/// @author DELV +/// @title ERC4626Target4 +/// @notice ERC4626Hyperdrive's target4 logic contract. This contract contains +/// several stateful functions that couldn't fit into the Hyperdrive +/// contract. +/// @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 ERC4626Target4 is HyperdriveTarget4, ERC4626Base { + /// @notice Initializes the target4 contract. + /// @param _config The configuration of the Hyperdrive pool. + /// @param __vault The ERC4626 compatible vault. + constructor( + IHyperdrive.PoolConfig memory _config, + IERC4626 __vault + ) HyperdriveTarget4(_config) ERC4626Base(__vault) {} +} diff --git a/contracts/src/instances/steth/StETHBase.sol b/contracts/src/instances/steth/StETHBase.sol index fc53d2c58..98c2d1708 100644 --- a/contracts/src/instances/steth/StETHBase.sol +++ b/contracts/src/instances/steth/StETHBase.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { ILido } from "../../interfaces/ILido.sol"; @@ -26,20 +26,6 @@ abstract contract StETHBase is HyperdriveBase { /// @param __lido The Lido contract. constructor(ILido __lido) { _lido = __lido; - - // Ensure that the minimum share reserves are equal to 1e15. This value - // has been tested to prevent arithmetic overflows in the - // `_updateLiquidity` function when the share reserves are as high as - // 200 million. - if (_minimumShareReserves != 1e15) { - revert IHyperdrive.InvalidMinimumShareReserves(); - } - - // Ensure that the minimum transaction amount are equal to 1e15. This - // value has been tested to prevent precision issues. - if (_minimumTransactionAmount != 1e15) { - revert IHyperdrive.InvalidMinimumTransactionAmount(); - } } /// Yield Source /// diff --git a/contracts/src/instances/steth/StETHHyperdrive.sol b/contracts/src/instances/steth/StETHHyperdrive.sol index 4b2753a06..b7d54b5ec 100644 --- a/contracts/src/instances/steth/StETHHyperdrive.sol +++ b/contracts/src/instances/steth/StETHHyperdrive.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { Hyperdrive } from "../../external/Hyperdrive.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; @@ -22,6 +22,7 @@ contract StETHHyperdrive is Hyperdrive, StETHBase { /// @param _target1 The target1 address. /// @param _target2 The target2 address. /// @param _target3 The target3 address. + /// @param _target4 The target4 address. /// @param _lido The Lido contract. constructor( IHyperdrive.PoolConfig memory _config, @@ -29,20 +30,16 @@ contract StETHHyperdrive is Hyperdrive, StETHBase { address _target1, address _target2, address _target3, + address _target4, ILido _lido ) - Hyperdrive(_config, _target0, _target1, _target2, _target3) + Hyperdrive(_config, _target0, _target1, _target2, _target3, _target4) StETHBase(_lido) { // Ensure that the base token address is properly configured. if (address(_config.baseToken) != ETH) { revert IHyperdrive.InvalidBaseToken(); } - - // Ensure that the initial vault share price is properly configured. - if (_config.initialVaultSharePrice != _pricePerVaultShare()) { - revert IHyperdrive.InvalidInitialVaultSharePrice(); - } } /// @notice Some yield sources [eg Morpho] pay rewards directly to this diff --git a/contracts/src/instances/steth/StETHTarget0.sol b/contracts/src/instances/steth/StETHTarget0.sol index 2cc339362..7ce908c30 100644 --- a/contracts/src/instances/steth/StETHTarget0.sol +++ b/contracts/src/instances/steth/StETHTarget0.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; -import { ERC20 } from "solmate/tokens/ERC20.sol"; -import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol"; +import { ERC20 } from "openzeppelin/token/ERC20/ERC20.sol"; +import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; import { HyperdriveTarget0 } from "../../external/HyperdriveTarget0.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; import { IERC20 } from "../../interfaces/IERC20.sol"; @@ -18,7 +18,7 @@ import { StETHBase } from "./StETHBase.sol"; /// only, and is not intended to, and does not, have any /// particular legal or regulatory significance. contract StETHTarget0 is HyperdriveTarget0, StETHBase { - using SafeTransferLib for ERC20; + using SafeERC20 for ERC20; /// @notice Initializes the target0 contract. /// @param _config The configuration of the Hyperdrive pool. diff --git a/contracts/src/instances/steth/StETHTarget1.sol b/contracts/src/instances/steth/StETHTarget1.sol index 29b17ca03..f1f3ff8c1 100644 --- a/contracts/src/instances/steth/StETHTarget1.sol +++ b/contracts/src/instances/steth/StETHTarget1.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { HyperdriveTarget1 } from "../../external/HyperdriveTarget1.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; diff --git a/contracts/src/instances/steth/StETHTarget2.sol b/contracts/src/instances/steth/StETHTarget2.sol index c41c48123..e11a4fb81 100644 --- a/contracts/src/instances/steth/StETHTarget2.sol +++ b/contracts/src/instances/steth/StETHTarget2.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { HyperdriveTarget2 } from "../../external/HyperdriveTarget2.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; diff --git a/contracts/src/instances/steth/StETHTarget3.sol b/contracts/src/instances/steth/StETHTarget3.sol index 5c37b5427..6abf7c590 100644 --- a/contracts/src/instances/steth/StETHTarget3.sol +++ b/contracts/src/instances/steth/StETHTarget3.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { HyperdriveTarget3 } from "../../external/HyperdriveTarget3.sol"; import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; diff --git a/contracts/src/instances/steth/StETHTarget4.sol b/contracts/src/instances/steth/StETHTarget4.sol new file mode 100644 index 000000000..63f605aa2 --- /dev/null +++ b/contracts/src/instances/steth/StETHTarget4.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { HyperdriveTarget4 } from "../../external/HyperdriveTarget4.sol"; +import { IHyperdrive } from "../../interfaces/IHyperdrive.sol"; +import { ILido } from "../../interfaces/ILido.sol"; +import { StETHBase } from "./StETHBase.sol"; + +/// @author DELV +/// @title StETHTarget4 +/// @notice StETHHyperdrive's target4 logic contract. +/// @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 StETHTarget4 is HyperdriveTarget4, StETHBase { + /// @notice Initializes the target4 contract. + /// @param _config The configuration of the Hyperdrive pool. + /// @param _lido The Lido contract. + constructor( + IHyperdrive.PoolConfig memory _config, + ILido _lido + ) HyperdriveTarget4(_config) StETHBase(_lido) {} +} diff --git a/contracts/src/interfaces/IDeployerCoordinator.sol b/contracts/src/interfaces/IDeployerCoordinator.sol deleted file mode 100644 index 636432234..000000000 --- a/contracts/src/interfaces/IDeployerCoordinator.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; - -import { IHyperdrive } from "./IHyperdrive.sol"; - -interface IDeployerCoordinator { - function deploy( - IHyperdrive.PoolDeployConfig memory _config, - bytes memory _extraData - ) external returns (address); -} diff --git a/contracts/src/interfaces/IERC20.sol b/contracts/src/interfaces/IERC20.sol index 2cd5cf777..11f622639 100644 --- a/contracts/src/interfaces/IERC20.sol +++ b/contracts/src/interfaces/IERC20.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; interface IERC20 { event Transfer(address indexed from, address indexed to, uint256 value); diff --git a/contracts/src/interfaces/IERC20Forwarder.sol b/contracts/src/interfaces/IERC20Forwarder.sol index c16d4c390..f52c338c2 100644 --- a/contracts/src/interfaces/IERC20Forwarder.sol +++ b/contracts/src/interfaces/IERC20Forwarder.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IERC20 } from "./IERC20.sol"; import { IMultiToken } from "./IMultiToken.sol"; @@ -31,7 +31,9 @@ interface IERC20Forwarder is IERC20 { function tokenId() external view returns (uint256); + // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); + // solhint-disable-next-line func-name-mixedcase function PERMIT_TYPEHASH() external view returns (bytes32); } diff --git a/contracts/src/interfaces/IERC4626.sol b/contracts/src/interfaces/IERC4626.sol index 15e3d0c62..fd5cede7a 100644 --- a/contracts/src/interfaces/IERC4626.sol +++ b/contracts/src/interfaces/IERC4626.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later // @author is Fei Protocol - https://github.com/fei-protocol/ERC4626/blob/main/src/interfaces/IERC4626.sol -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IERC20 } from "./IERC20.sol"; diff --git a/contracts/src/interfaces/IERC4626Hyperdrive.sol b/contracts/src/interfaces/IERC4626Hyperdrive.sol index 7dbc296fa..f8e1a2c88 100644 --- a/contracts/src/interfaces/IERC4626Hyperdrive.sol +++ b/contracts/src/interfaces/IERC4626Hyperdrive.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IERC4626HyperdriveCore } from "./IERC4626HyperdriveCore.sol"; import { IERC4626HyperdriveRead } from "./IERC4626HyperdriveRead.sol"; diff --git a/contracts/src/interfaces/IERC4626HyperdriveCore.sol b/contracts/src/interfaces/IERC4626HyperdriveCore.sol index a1bf895b5..2adf0ee8c 100644 --- a/contracts/src/interfaces/IERC4626HyperdriveCore.sol +++ b/contracts/src/interfaces/IERC4626HyperdriveCore.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IERC20 } from "./IERC20.sol"; import { IHyperdriveCore } from "./IHyperdriveCore.sol"; diff --git a/contracts/src/interfaces/IERC4626HyperdriveRead.sol b/contracts/src/interfaces/IERC4626HyperdriveRead.sol index d9f3781e3..db8d98784 100644 --- a/contracts/src/interfaces/IERC4626HyperdriveRead.sol +++ b/contracts/src/interfaces/IERC4626HyperdriveRead.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IERC4626 } from "./IERC4626.sol"; import { IHyperdriveRead } from "./IHyperdriveRead.sol"; diff --git a/contracts/src/interfaces/IForwarderFactory.sol b/contracts/src/interfaces/IForwarderFactory.sol index 6c5194204..f48d7416a 100644 --- a/contracts/src/interfaces/IForwarderFactory.sol +++ b/contracts/src/interfaces/IForwarderFactory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IERC20Forwarder } from "./IERC20Forwarder.sol"; import { IMultiToken } from "./IMultiToken.sol"; @@ -23,5 +23,6 @@ interface IForwarderFactory { uint256 _tokenId ) external view returns (address); + // solhint-disable-next-line func-name-mixedcase function ERC20LINK_HASH() external pure returns (bytes32); } diff --git a/contracts/src/interfaces/IHyperdrive.sol b/contracts/src/interfaces/IHyperdrive.sol index 59adeac56..7f36d8906 100644 --- a/contracts/src/interfaces/IHyperdrive.sol +++ b/contracts/src/interfaces/IHyperdrive.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IERC20 } from "./IERC20.sol"; import { IHyperdriveCore } from "./IHyperdriveCore.sol"; @@ -218,9 +218,6 @@ interface IHyperdrive is /// different criteria for what constitutes a valid base token. error InvalidBaseToken(); - /// @notice Thrown when the checkpoint duration specified is zero. - error InvalidCheckpointDuration(); - /// @notice Thrown when the checkpoint time provided to `checkpoint` is /// larger than the current checkpoint or isn't divisible by the /// checkpoint duration. @@ -230,10 +227,6 @@ interface IHyperdrive is /// functions is not the corresponding bridge. error InvalidERC20Bridge(); - /// @notice Thrown when the curve fee, flat fee, governance LP fee, or - /// governance zombie fee is greater than 100%. - error InvalidFeeAmounts(); - /// @notice Thrown when a destination other than the fee collector is /// specified in `collectGovernanceFee`. error InvalidFeeDestination(); @@ -242,19 +235,6 @@ interface IHyperdrive is /// price of the underlying yield source on deployment. error InvalidInitialVaultSharePrice(); - /// @notice Thrown when the minimum share reserves is too small. The - /// absolute smallest allowable minimum share reserves is 1e3; - /// however, yield sources may require a larger minimum share - /// reserves. - error InvalidMinimumShareReserves(); - - /// @notice Thrown when the minimum transaction amount is too small. - error InvalidMinimumTransactionAmount(); - - /// @notice Thrown when the position duration is smaller than the checkpoint - /// duration or is not a multiple of the checkpoint duration. - error InvalidPositionDuration(); - /// @notice Thrown when update liquidity brings the share reserves below /// the minimum share reserves. error InvalidShareReserves(); @@ -362,4 +342,6 @@ interface IHyperdrive is function target2() external view returns (address); function target3() external view returns (address); + + function target4() external view returns (address); } diff --git a/contracts/src/interfaces/IHyperdriveCore.sol b/contracts/src/interfaces/IHyperdriveCore.sol index 92bb0444e..ad30ca5fc 100644 --- a/contracts/src/interfaces/IHyperdriveCore.sol +++ b/contracts/src/interfaces/IHyperdriveCore.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "./IHyperdrive.sol"; import { IMultiTokenCore } from "./IMultiTokenCore.sol"; diff --git a/contracts/src/interfaces/IHyperdriveCoreDeployer.sol b/contracts/src/interfaces/IHyperdriveCoreDeployer.sol index 65b730d14..f0b8c62b2 100644 --- a/contracts/src/interfaces/IHyperdriveCoreDeployer.sol +++ b/contracts/src/interfaces/IHyperdriveCoreDeployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "./IHyperdrive.sol"; @@ -7,9 +7,11 @@ interface IHyperdriveCoreDeployer { function deploy( IHyperdrive.PoolConfig memory _config, bytes memory _extraData, - address target0, - address target1, - address target2, - address target3 + address _target0, + address _target1, + address _target2, + address _target3, + address _target4, + bytes32 _salt ) external returns (address); } diff --git a/contracts/src/interfaces/IHyperdriveDeployerCoordinator.sol b/contracts/src/interfaces/IHyperdriveDeployerCoordinator.sol new file mode 100644 index 000000000..caa9e3db1 --- /dev/null +++ b/contracts/src/interfaces/IHyperdriveDeployerCoordinator.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { IHyperdrive } from "./IHyperdrive.sol"; + +interface IHyperdriveDeployerCoordinator { + /// Errors /// + + /// @notice Thrown when a user attempts to deploy target0 the deployment has + /// already been created. + error DeploymentAlreadyExists(); + + /// @notice Thrown when a user attempts to deploy a contract that requires + /// the deployment to be created and the deployment doesn't exist. + error DeploymentDoesNotExist(); + + /// @notice Thrown when a user attempts to deploy a Hyperdrive entrypoint + /// without first deploying the required targets. + error IncompleteDeployment(); + + /// @notice Thrown when a user attempts to deploy a hyperdrive contract + /// after it has already been deployed. + error HyperdriveAlreadyDeployed(); + + /// @notice Thrown when the checkpoint duration specified is zero. + error InvalidCheckpointDuration(); + + /// @notice Thrown when the curve fee, flat fee, governance LP fee, or + /// governance zombie fee is greater than 100%. + error InvalidFeeAmounts(); + + /// @notice Thrown when the minimum share reserves is too small. The + /// absolute smallest allowable minimum share reserves is 1e3; + /// however, yield sources may require a larger minimum share + /// reserves. + error InvalidMinimumShareReserves(); + + /// @notice Thrown when the minimum transaction amount is too small. + error InvalidMinimumTransactionAmount(); + + /// @notice Thrown when the position duration is smaller than the checkpoint + /// duration or is not a multiple of the checkpoint duration. + error InvalidPositionDuration(); + + /// @notice Thrown when a user attempts to deploy a target using a target + /// index that is outside of the accepted range. + error InvalidTargetIndex(); + + /// @notice Thrown when a user attempts to deploy a contract in an existing + /// deployment with a config that doesn't match the deployment's + /// config hash. + error MismatchedConfig(); + + /// @notice Thrown when a user attempts to deploy a contract in an existing + /// deployment with extra data that doesn't match the deployment's + /// extra data hash. + error MismatchedExtraData(); + + /// @notice Thrown when a user attempts to deploy a target contract after + /// it has already been deployed. + error TargetAlreadyDeployed(); + + /// Functions /// + + function deploy( + bytes32 _deploymentId, + IHyperdrive.PoolDeployConfig memory _config, + bytes memory _extraData, + bytes32 _salt + ) external returns (address); + + function deployTarget( + bytes32 _deploymentId, + IHyperdrive.PoolDeployConfig memory _config, + bytes memory _extraData, + uint256 _targetIndex, + bytes32 _salt + ) external returns (address); +} diff --git a/contracts/src/interfaces/IHyperdriveEvents.sol b/contracts/src/interfaces/IHyperdriveEvents.sol index 5ed219cfb..adeeed29e 100644 --- a/contracts/src/interfaces/IHyperdriveEvents.sol +++ b/contracts/src/interfaces/IHyperdriveEvents.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IMultiTokenEvents } from "./IMultiTokenEvents.sol"; diff --git a/contracts/src/interfaces/IHyperdriveFactory.sol b/contracts/src/interfaces/IHyperdriveFactory.sol index bbe426639..ed5f2636f 100644 --- a/contracts/src/interfaces/IHyperdriveFactory.sol +++ b/contracts/src/interfaces/IHyperdriveFactory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "./IHyperdrive.sol"; diff --git a/contracts/src/interfaces/IHyperdriveGovernedRegistry.sol b/contracts/src/interfaces/IHyperdriveGovernedRegistry.sol index d2ce55991..6f9573e55 100644 --- a/contracts/src/interfaces/IHyperdriveGovernedRegistry.sol +++ b/contracts/src/interfaces/IHyperdriveGovernedRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; interface IHyperdriveGovernedRegistry { /// @notice Emitted when governance is transferred. diff --git a/contracts/src/interfaces/IHyperdriveRead.sol b/contracts/src/interfaces/IHyperdriveRead.sol index bec774314..554c5c981 100644 --- a/contracts/src/interfaces/IHyperdriveRead.sol +++ b/contracts/src/interfaces/IHyperdriveRead.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "./IHyperdrive.sol"; import { IMultiTokenRead } from "./IMultiTokenRead.sol"; diff --git a/contracts/src/interfaces/IHyperdriveRegistry.sol b/contracts/src/interfaces/IHyperdriveRegistry.sol index a91c9b285..12f34c19d 100644 --- a/contracts/src/interfaces/IHyperdriveRegistry.sol +++ b/contracts/src/interfaces/IHyperdriveRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; interface IHyperdriveRegistry { /// @notice Allows anyone to get the info for a hyperdrive instance. diff --git a/contracts/src/interfaces/IHyperdriveTargetDeployer.sol b/contracts/src/interfaces/IHyperdriveTargetDeployer.sol index 35de5a811..cc6ad0568 100644 --- a/contracts/src/interfaces/IHyperdriveTargetDeployer.sol +++ b/contracts/src/interfaces/IHyperdriveTargetDeployer.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "./IHyperdrive.sol"; interface IHyperdriveTargetDeployer { function deploy( IHyperdrive.PoolConfig memory _config, - bytes memory _extraData + bytes memory _extraData, + bytes32 _salt ) external returns (address); } diff --git a/contracts/src/interfaces/ILido.sol b/contracts/src/interfaces/ILido.sol index b5354a72b..8b0af3848 100644 --- a/contracts/src/interfaces/ILido.sol +++ b/contracts/src/interfaces/ILido.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IERC20 } from "./IERC20.sol"; diff --git a/contracts/src/interfaces/IMultiToken.sol b/contracts/src/interfaces/IMultiToken.sol index 9a9a93440..285378c71 100644 --- a/contracts/src/interfaces/IMultiToken.sol +++ b/contracts/src/interfaces/IMultiToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IMultiTokenCore } from "./IMultiTokenCore.sol"; import { IMultiTokenEvents } from "./IMultiTokenEvents.sol"; diff --git a/contracts/src/interfaces/IMultiTokenCore.sol b/contracts/src/interfaces/IMultiTokenCore.sol index 4e8ebc409..2a2289d3c 100644 --- a/contracts/src/interfaces/IMultiTokenCore.sol +++ b/contracts/src/interfaces/IMultiTokenCore.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; interface IMultiTokenCore { /// Functions /// diff --git a/contracts/src/interfaces/IMultiTokenEvents.sol b/contracts/src/interfaces/IMultiTokenEvents.sol index 0304339c2..a9343219e 100644 --- a/contracts/src/interfaces/IMultiTokenEvents.sol +++ b/contracts/src/interfaces/IMultiTokenEvents.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; interface IMultiTokenEvents { event TransferSingle( diff --git a/contracts/src/interfaces/IMultiTokenMetadata.sol b/contracts/src/interfaces/IMultiTokenMetadata.sol index f7c91a774..72f1040ea 100644 --- a/contracts/src/interfaces/IMultiTokenMetadata.sol +++ b/contracts/src/interfaces/IMultiTokenMetadata.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; interface IMultiTokenMetadata { // solhint-disable func-name-mixedcase diff --git a/contracts/src/interfaces/IMultiTokenRead.sol b/contracts/src/interfaces/IMultiTokenRead.sol index cdea14ff6..199053d3c 100644 --- a/contracts/src/interfaces/IMultiTokenRead.sol +++ b/contracts/src/interfaces/IMultiTokenRead.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; interface IMultiTokenRead { function name(uint256 id) external view returns (string memory); diff --git a/contracts/src/interfaces/IStETHHyperdrive.sol b/contracts/src/interfaces/IStETHHyperdrive.sol index ced14f345..f05478f23 100644 --- a/contracts/src/interfaces/IStETHHyperdrive.sol +++ b/contracts/src/interfaces/IStETHHyperdrive.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "./IHyperdrive.sol"; import { IStETHHyperdriveCore } from "./IStETHHyperdriveCore.sol"; diff --git a/contracts/src/interfaces/IStETHHyperdriveCore.sol b/contracts/src/interfaces/IStETHHyperdriveCore.sol index 5116c83e8..e4ecf9f2c 100644 --- a/contracts/src/interfaces/IStETHHyperdriveCore.sol +++ b/contracts/src/interfaces/IStETHHyperdriveCore.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IERC20 } from "./IERC20.sol"; import { IHyperdriveCore } from "./IHyperdriveCore.sol"; diff --git a/contracts/src/interfaces/IStETHHyperdriveRead.sol b/contracts/src/interfaces/IStETHHyperdriveRead.sol index 453c10eb9..b6fd6efc8 100644 --- a/contracts/src/interfaces/IStETHHyperdriveRead.sol +++ b/contracts/src/interfaces/IStETHHyperdriveRead.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdriveRead } from "./IHyperdriveRead.sol"; import { ILido } from "./ILido.sol"; diff --git a/contracts/src/internal/HyperdriveAdmin.sol b/contracts/src/internal/HyperdriveAdmin.sol index 9786da716..1c42a41ab 100644 --- a/contracts/src/internal/HyperdriveAdmin.sol +++ b/contracts/src/internal/HyperdriveAdmin.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { IHyperdriveEvents } from "../interfaces/IHyperdriveEvents.sol"; diff --git a/contracts/src/internal/HyperdriveBase.sol b/contracts/src/internal/HyperdriveBase.sol index 4867908b3..c5d6d78ca 100644 --- a/contracts/src/internal/HyperdriveBase.sol +++ b/contracts/src/internal/HyperdriveBase.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IERC20 } from "../interfaces/IERC20.sol"; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; diff --git a/contracts/src/internal/HyperdriveCheckpoint.sol b/contracts/src/internal/HyperdriveCheckpoint.sol index 752ce46d2..ebeda8af5 100644 --- a/contracts/src/internal/HyperdriveCheckpoint.sol +++ b/contracts/src/internal/HyperdriveCheckpoint.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { IHyperdriveEvents } from "../interfaces/IHyperdriveEvents.sol"; diff --git a/contracts/src/internal/HyperdriveLP.sol b/contracts/src/internal/HyperdriveLP.sol index e61eceb9b..aa8b19989 100644 --- a/contracts/src/internal/HyperdriveLP.sol +++ b/contracts/src/internal/HyperdriveLP.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { IHyperdriveEvents } from "../interfaces/IHyperdriveEvents.sol"; diff --git a/contracts/src/internal/HyperdriveLong.sol b/contracts/src/internal/HyperdriveLong.sol index 141e40c0c..2f1bed23b 100644 --- a/contracts/src/internal/HyperdriveLong.sol +++ b/contracts/src/internal/HyperdriveLong.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { IHyperdriveEvents } from "../interfaces/IHyperdriveEvents.sol"; diff --git a/contracts/src/internal/HyperdriveMultiToken.sol b/contracts/src/internal/HyperdriveMultiToken.sol index 878df1918..308a60a5a 100644 --- a/contracts/src/internal/HyperdriveMultiToken.sol +++ b/contracts/src/internal/HyperdriveMultiToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { IHyperdriveEvents } from "../interfaces/IHyperdriveEvents.sol"; diff --git a/contracts/src/internal/HyperdriveShort.sol b/contracts/src/internal/HyperdriveShort.sol index 58c17138d..4459ba785 100644 --- a/contracts/src/internal/HyperdriveShort.sol +++ b/contracts/src/internal/HyperdriveShort.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { IHyperdriveEvents } from "../interfaces/IHyperdriveEvents.sol"; diff --git a/contracts/src/internal/HyperdriveStorage.sol b/contracts/src/internal/HyperdriveStorage.sol index ffbfb5714..da8ff7ceb 100644 --- a/contracts/src/internal/HyperdriveStorage.sol +++ b/contracts/src/internal/HyperdriveStorage.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; -import { ReentrancyGuard } from "solmate/utils/ReentrancyGuard.sol"; +import { ReentrancyGuard } from "openzeppelin/utils/ReentrancyGuard.sol"; import { IERC20 } from "../interfaces/IERC20.sol"; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { FixedPointMath, ONE } from "../libraries/FixedPointMath.sol"; @@ -127,16 +127,14 @@ abstract contract HyperdriveStorage is ReentrancyGuard { // Initialize the base token address. _baseToken = _config.baseToken; + // Initialize the initial vault share price. + _initialVaultSharePrice = _config.initialVaultSharePrice; + // Initialize the minimum share reserves. The minimum share reserves // defines the amount of shares that will be reserved to ensure that // the share reserves are never empty. We will also burn LP shares equal // to the minimum share reserves upon initialization to ensure that the - // total supply of active LP tokens is always greater than zero. We - // don't allow a value less than 1e3 to avoid numerical issues that - // occur with small amounts of shares. - if (_config.minimumShareReserves < 1e3) { - revert IHyperdrive.InvalidMinimumShareReserves(); - } + // total supply of active LP tokens is always greater than zero. _minimumShareReserves = _config.minimumShareReserves; // Initialize the minimum transaction amount. The minimum transaction @@ -147,31 +145,11 @@ abstract contract HyperdriveStorage is ReentrancyGuard { // Initialize the time configurations. There must be at least one // checkpoint per term to avoid having a position duration of zero. - if (_config.checkpointDuration == 0) { - revert IHyperdrive.InvalidCheckpointDuration(); - } _checkpointDuration = _config.checkpointDuration; - if ( - _config.positionDuration < _config.checkpointDuration || - _config.positionDuration % _config.checkpointDuration != 0 - ) { - revert IHyperdrive.InvalidPositionDuration(); - } _positionDuration = _config.positionDuration; _timeStretch = _config.timeStretch; - _initialVaultSharePrice = _config.initialVaultSharePrice; - _governance = _config.governance; - _feeCollector = _config.feeCollector; // Initialize the fee parameters. - if ( - _config.fees.curve > 1e18 || - _config.fees.flat > 1e18 || - _config.fees.governanceLP > 1e18 || - _config.fees.governanceZombie > 1e18 - ) { - revert IHyperdrive.InvalidFeeAmounts(); - } _curveFee = _config.fees.curve; _flatFee = _config.fees.flat; _governanceLPFee = _config.fees.governanceLP; @@ -180,5 +158,9 @@ abstract contract HyperdriveStorage is ReentrancyGuard { // Initialize the MultiToken immutables. _linkerFactory = _config.linkerFactory; _linkerCodeHash = _config.linkerCodeHash; + + // Initialize the governance and fee collector. + _governance = _config.governance; + _feeCollector = _config.feeCollector; } } diff --git a/contracts/src/libraries/AssetId.sol b/contracts/src/libraries/AssetId.sol index 6e2c52e9a..c8bf3d980 100644 --- a/contracts/src/libraries/AssetId.sol +++ b/contracts/src/libraries/AssetId.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; diff --git a/contracts/src/libraries/Errors.sol b/contracts/src/libraries/Errors.sol index 91e22149c..95abb3403 100644 --- a/contracts/src/libraries/Errors.sol +++ b/contracts/src/libraries/Errors.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; diff --git a/contracts/src/libraries/FixedPointMath.sol b/contracts/src/libraries/FixedPointMath.sol index d4ede9a99..7ccb85914 100644 --- a/contracts/src/libraries/FixedPointMath.sol +++ b/contracts/src/libraries/FixedPointMath.sol @@ -1,5 +1,5 @@ /// SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; @@ -16,7 +16,6 @@ library FixedPointMath { uint256 internal constant MAX_UINT256 = 2 ** 256 - 1; - /// @dev Credit to Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @param x Fixed point number in 1e18 format. /// @param y Fixed point number in 1e18 format. /// @param denominator Fixed point number in 1e18 format. @@ -40,7 +39,6 @@ library FixedPointMath { } } - /// @dev Credit to Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @param a Fixed point number in 1e18 format. /// @param b Fixed point number in 1e18 format. /// @return Result of a * b rounded down. @@ -48,7 +46,6 @@ library FixedPointMath { return (mulDivDown(a, b, 1e18)); } - /// @dev Credit to Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @param a Fixed point number in 1e18 format. /// @param b Fixed point number in 1e18 format. /// @return Result of a / b rounded down. @@ -56,7 +53,6 @@ library FixedPointMath { return (mulDivDown(a, 1e18, b)); // Equivalent to (a * 1e18) / b rounded down. } - /// @dev Credit to Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @param x Fixed point number in 1e18 format. /// @param y Fixed point number in 1e18 format. /// @param denominator Fixed point number in 1e18 format. @@ -84,7 +80,6 @@ library FixedPointMath { } } - /// @dev Credit to Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @param a Fixed point number in 1e18 format. /// @param b Fixed point number in 1e18 format. /// @return The result of a * b rounded up. @@ -92,7 +87,6 @@ library FixedPointMath { return (mulDivUp(a, b, 1e18)); } - /// @dev Credit to Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @param a Fixed point number in 1e18 format. /// @param b Fixed point number in 1e18 format. /// @return The result of a / b rounded up. @@ -101,7 +95,6 @@ library FixedPointMath { } /// @dev Exponentiation (x^y) with unsigned 18 decimal fixed point base and exponent. - /// @dev Partially inspired by Balancer LogExpMath library (https://github.com/balancer-labs/balancer-v2-monorepo/blob/master/pkg/solidity-utils/contracts/math/LogExpMath.sol) /// @param x Fixed point number in 1e18 format. /// @param y Fixed point number in 1e18 format. /// @return The result of x^y. @@ -135,7 +128,7 @@ library FixedPointMath { } /// @dev Computes e^x in 1e18 fixed point. - /// @dev Credit to Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SignedWadMath.sol) + /// @dev Credit to Remco (https://github.com/recmo/experiment-solexp/blob/main/src/FixedPointMathLib.sol) /// @param x Fixed point number in 1e18 format. /// @return r The result of e^x. function exp(int256 x) internal pure returns (int256 r) { @@ -206,7 +199,6 @@ library FixedPointMath { /// @dev Computes ln(x) in 1e18 fixed point. /// @dev Reverts if x is negative - /// @dev Credit to Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SignedWadMath.sol) /// @param x Fixed point number in 1e18 format. /// @return r Result of ln(x). function ln(int256 x) internal pure returns (int256 r) { @@ -299,6 +291,11 @@ library FixedPointMath { uint256 _deltaWeight, bool _isAdding ) internal pure returns (uint256 average) { + // If the delta weight is zero, the average does not change. + if (_deltaWeight == 0) { + return _average; + } + // If the delta weight should be added to the total weight, we compute // the weighted average as: // diff --git a/contracts/src/libraries/HyperdriveMath.sol b/contracts/src/libraries/HyperdriveMath.sol index 1e7432dae..1db964f6d 100644 --- a/contracts/src/libraries/HyperdriveMath.sol +++ b/contracts/src/libraries/HyperdriveMath.sol @@ -1,5 +1,5 @@ /// SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { FixedPointMath, ONE } from "./FixedPointMath.sol"; diff --git a/contracts/src/libraries/LPMath.sol b/contracts/src/libraries/LPMath.sol index 33bb72add..db2624aad 100644 --- a/contracts/src/libraries/LPMath.sol +++ b/contracts/src/libraries/LPMath.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { FixedPointMath, ONE } from "./FixedPointMath.sol"; diff --git a/contracts/src/libraries/SafeCast.sol b/contracts/src/libraries/SafeCast.sol index e95717c01..e70737ddf 100644 --- a/contracts/src/libraries/SafeCast.sol +++ b/contracts/src/libraries/SafeCast.sol @@ -1,10 +1,9 @@ /// SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; /// @notice Safe unsigned integer casting library that reverts on overflow. -/// @author Inspired by Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeCastLib.sol) /// @author Inspired by OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol) library SafeCast { /// @notice This function safely casts a uint256 to a uint112. diff --git a/contracts/src/libraries/YieldSpaceMath.sol b/contracts/src/libraries/YieldSpaceMath.sol index c3f2cf223..5f2bf5a41 100644 --- a/contracts/src/libraries/YieldSpaceMath.sol +++ b/contracts/src/libraries/YieldSpaceMath.sol @@ -1,5 +1,5 @@ /// SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { Errors } from "./Errors.sol"; diff --git a/contracts/src/token/ERC20Forwarder.sol b/contracts/src/token/ERC20Forwarder.sol index c4787f945..c3438b0ba 100644 --- a/contracts/src/token/ERC20Forwarder.sol +++ b/contracts/src/token/ERC20Forwarder.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IERC20Forwarder } from "../interfaces/IERC20Forwarder.sol"; import { IForwarderFactory } from "../interfaces/IForwarderFactory.sol"; diff --git a/contracts/src/token/ForwarderFactory.sol b/contracts/src/token/ForwarderFactory.sol index daf4bc44f..87ebb48df 100644 --- a/contracts/src/token/ForwarderFactory.sol +++ b/contracts/src/token/ForwarderFactory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IERC20Forwarder } from "../interfaces/IERC20Forwarder.sol"; import { IForwarderFactory } from "../interfaces/IForwarderFactory.sol"; diff --git a/contracts/test/ERC20Mintable.sol b/contracts/test/ERC20Mintable.sol index 08c3302ef..a71c76f32 100644 --- a/contracts/test/ERC20Mintable.sol +++ b/contracts/test/ERC20Mintable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { Authority } from "solmate/auth/Auth.sol"; import { MultiRolesAuthority } from "solmate/auth/authorities/MultiRolesAuthority.sol"; diff --git a/contracts/test/EtchingVault.sol b/contracts/test/EtchingVault.sol index d5cd2c692..6f8314709 100644 --- a/contracts/test/EtchingVault.sol +++ b/contracts/test/EtchingVault.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; /// @author DELV /// @title EtchingVault diff --git a/contracts/test/MockAssetId.sol b/contracts/test/MockAssetId.sol index 768a0c1f0..94d128f33 100644 --- a/contracts/test/MockAssetId.sol +++ b/contracts/test/MockAssetId.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { AssetId } from "contracts/src/libraries/AssetId.sol"; diff --git a/contracts/test/MockERC4626.sol b/contracts/test/MockERC4626.sol index 0048bbe65..50646a111 100644 --- a/contracts/test/MockERC4626.sol +++ b/contracts/test/MockERC4626.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { Authority } from "solmate/auth/Auth.sol"; import { MultiRolesAuthority } from "solmate/auth/authorities/MultiRolesAuthority.sol"; diff --git a/contracts/test/MockERC4626Hyperdrive.sol b/contracts/test/MockERC4626Hyperdrive.sol index e10beff89..861d8683c 100644 --- a/contracts/test/MockERC4626Hyperdrive.sol +++ b/contracts/test/MockERC4626Hyperdrive.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { ERC4626Hyperdrive } from "contracts/src/instances/erc4626/ERC4626Hyperdrive.sol"; import { IERC4626 } from "contracts/src/interfaces/IERC4626.sol"; @@ -14,6 +14,7 @@ contract MockERC4626Hyperdrive is ERC4626Hyperdrive { address _target1, address _target2, address _target3, + address _target4, IERC4626 _pool ) ERC4626Hyperdrive( @@ -22,6 +23,7 @@ contract MockERC4626Hyperdrive is ERC4626Hyperdrive { _target1, _target2, _target3, + _target4, _pool ) {} diff --git a/contracts/test/MockFixedPointMath.sol b/contracts/test/MockFixedPointMath.sol index 05ea06cbc..4859f4b83 100644 --- a/contracts/test/MockFixedPointMath.sol +++ b/contracts/test/MockFixedPointMath.sol @@ -1,5 +1,5 @@ /// SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { FixedPointMath } from "../src/libraries/FixedPointMath.sol"; diff --git a/contracts/test/MockHyperdrive.sol b/contracts/test/MockHyperdrive.sol index ca978d29c..f85236e50 100644 --- a/contracts/test/MockHyperdrive.sol +++ b/contracts/test/MockHyperdrive.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { Hyperdrive } from "contracts/src/external/Hyperdrive.sol"; import { HyperdriveTarget0 } from "contracts/src/external/HyperdriveTarget0.sol"; import { HyperdriveTarget1 } from "contracts/src/external/HyperdriveTarget1.sol"; import { HyperdriveTarget2 } from "contracts/src/external/HyperdriveTarget2.sol"; import { HyperdriveTarget3 } from "contracts/src/external/HyperdriveTarget3.sol"; +import { HyperdriveTarget4 } from "contracts/src/external/HyperdriveTarget4.sol"; import { HyperdriveBase } from "contracts/src/internal/HyperdriveBase.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; @@ -177,7 +178,8 @@ contract MockHyperdrive is Hyperdrive, MockHyperdriveBase { address(new MockHyperdriveTarget0(_config)), address(new MockHyperdriveTarget1(_config)), address(new MockHyperdriveTarget2(_config)), - address(new MockHyperdriveTarget3(_config)) + address(new MockHyperdriveTarget3(_config)), + address(new MockHyperdriveTarget4(_config)) ) {} @@ -348,3 +350,9 @@ contract MockHyperdriveTarget3 is HyperdriveTarget3, MockHyperdriveBase { IHyperdrive.PoolConfig memory _config ) HyperdriveTarget3(_config) {} } + +contract MockHyperdriveTarget4 is HyperdriveTarget4, MockHyperdriveBase { + constructor( + IHyperdrive.PoolConfig memory _config + ) HyperdriveTarget4(_config) {} +} diff --git a/contracts/test/MockHyperdriveDeployer.sol b/contracts/test/MockHyperdriveDeployer.sol index c4346da1a..075a6bd67 100644 --- a/contracts/test/MockHyperdriveDeployer.sol +++ b/contracts/test/MockHyperdriveDeployer.sol @@ -1,16 +1,18 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; -import { IDeployerCoordinator } from "contracts/src/interfaces/IDeployerCoordinator.sol"; +import { IHyperdriveDeployerCoordinator } from "contracts/src/interfaces/IHyperdriveDeployerCoordinator.sol"; import { IHyperdriveTargetDeployer } from "contracts/src/interfaces/IHyperdriveTargetDeployer.sol"; import { MockHyperdrive } from "./MockHyperdrive.sol"; -contract MockHyperdriveDeployer is IDeployerCoordinator { +contract MockHyperdriveDeployer is IHyperdriveDeployerCoordinator { function deploy( + bytes32, IHyperdrive.PoolDeployConfig memory _deployConfig, - bytes memory - ) external override returns (address) { + bytes memory, + bytes32 + ) external returns (address) { IHyperdrive.PoolConfig memory _config; // Copy struct info to PoolConfig @@ -26,11 +28,22 @@ contract MockHyperdriveDeployer is IDeployerCoordinator { _config.governance = _deployConfig.governance; _config.feeCollector = _deployConfig.feeCollector; _config.fees = _deployConfig.fees; - _config.initialVaultSharePrice = 1e18; // TODO: Make setter return (address(new MockHyperdrive(_config))); } + + // HACK: This function doesn't return anything because MockHyperdrive + // deploys the target contracts in it's constructor. + function deployTarget( + bytes32, + IHyperdrive.PoolDeployConfig memory, + bytes memory, + uint256, + bytes32 + ) external pure returns (address target) { + return address(0); + } } // HACK: This contract doesn't return anything because MockHyperdrive deploys @@ -38,8 +51,9 @@ contract MockHyperdriveDeployer is IDeployerCoordinator { contract MockHyperdriveTargetDeployer is IHyperdriveTargetDeployer { function deploy( IHyperdrive.PoolConfig memory, - bytes memory - ) external pure override returns (address) { + bytes memory, + bytes32 + ) external pure returns (address) { return address(0); } } diff --git a/contracts/test/MockHyperdriveMath.sol b/contracts/test/MockHyperdriveMath.sol index ac6344e16..225aae364 100644 --- a/contracts/test/MockHyperdriveMath.sol +++ b/contracts/test/MockHyperdriveMath.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; import { HyperdriveUtils } from "test/utils/HyperdriveUtils.sol"; diff --git a/contracts/test/MockLPMath.sol b/contracts/test/MockLPMath.sol index b20711a48..f5e249e6c 100644 --- a/contracts/test/MockLPMath.sol +++ b/contracts/test/MockLPMath.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { LPMath } from "contracts/src/libraries/LPMath.sol"; diff --git a/contracts/test/MockLido.sol b/contracts/test/MockLido.sol index 21f46113b..1f09e2b09 100644 --- a/contracts/test/MockLido.sol +++ b/contracts/test/MockLido.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { Authority } from "solmate/auth/Auth.sol"; import { MultiRolesAuthority } from "solmate/auth/authorities/MultiRolesAuthority.sol"; diff --git a/contracts/test/MockMultiToken.sol b/contracts/test/MockMultiToken.sol index 5497e7a16..07252375a 100644 --- a/contracts/test/MockMultiToken.sol +++ b/contracts/test/MockMultiToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { HyperdriveTarget0 } from "contracts/src/external/HyperdriveTarget0.sol"; import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; diff --git a/contracts/test/MockYieldSpaceMath.sol b/contracts/test/MockYieldSpaceMath.sol index 5d4b5c965..6ee71b8a1 100644 --- a/contracts/test/MockYieldSpaceMath.sol +++ b/contracts/test/MockYieldSpaceMath.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { YieldSpaceMath } from "../src/libraries/YieldSpaceMath.sol"; diff --git a/crates/hyperdrive-wrappers/build.rs b/crates/hyperdrive-wrappers/build.rs index 4de819f1f..d539ddc10 100644 --- a/crates/hyperdrive-wrappers/build.rs +++ b/crates/hyperdrive-wrappers/build.rs @@ -17,6 +17,7 @@ const TARGETS: &[&str] = &[ "ERC4626Target1", "ERC4626Target2", "ERC4626Target3", + "ERC4626Target4", // Test Contracts "ERC20Mintable", "EtchingVault", diff --git a/crates/test-utils/src/chain/test_chain.rs b/crates/test-utils/src/chain/test_chain.rs index 1a39c559f..a813d1203 100644 --- a/crates/test-utils/src/chain/test_chain.rs +++ b/crates/test-utils/src/chain/test_chain.rs @@ -20,6 +20,7 @@ use hyperdrive_wrappers::wrappers::{ erc4626_target1::ERC4626Target1, erc4626_target2::ERC4626Target2, erc4626_target3::ERC4626Target3, + erc4626_target4::ERC4626Target4, etching_vault::EtchingVault, i_hyperdrive::{Fees, PoolConfig}, ierc4626_hyperdrive::IERC4626Hyperdrive, @@ -298,6 +299,10 @@ impl TestChain { .gas_price(DEFAULT_GAS_PRICE) .send() .await?; + let target4 = ERC4626Target4::deploy(client.clone(), (config.clone(), vault.address()))? + .gas_price(DEFAULT_GAS_PRICE) + .send() + .await?; let erc4626_hyperdrive = ERC4626Hyperdrive::deploy( client.clone(), ( @@ -306,6 +311,7 @@ impl TestChain { target1.address(), target2.address(), target3.address(), + target4.address(), vault.address(), ), )? @@ -338,6 +344,7 @@ impl TestChain { let target1_address = hyperdrive.target_1().call().await?; let target2_address = hyperdrive.target_2().call().await?; let target3_address = hyperdrive.target_3().call().await?; + let target4_address = hyperdrive.target_4().call().await?; let vault_address = hyperdrive.vault().call().await?; // Deploy templates for each of the contracts that should be etched and @@ -418,6 +425,14 @@ impl TestChain { .await?; pairs.push((target3_address, target3_template.address())); + // Deploy the target4 template. + let target4_template = + ERC4626Target4::deploy(client.clone(), (config.clone(), vault_address))? + .gas_price(DEFAULT_GAS_PRICE) + .send() + .await?; + pairs.push((target4_address, target4_template.address())); + // Etch the "etching vault" onto the current vault contract. The // etching vault implements `convertToAssets` to return the immutable // that was passed on deployment. This is necessary because the @@ -446,6 +461,7 @@ impl TestChain { target1_address, target2_address, target3_address, + target4_address, vault_address, Vec::
::new(), ), diff --git a/foundry.toml b/foundry.toml index c6fda25d8..f23a86294 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,5 +1,5 @@ [profile.default] -solc_version = '0.8.19' +solc_version = '0.8.20' # The source directory src = 'contracts' # The artifact directory @@ -15,6 +15,7 @@ cache_path = 'forge-cache' # Enables or disables the optimizer remappings = [ 'forge-std=lib/forge-std/src', + 'openzeppelin=lib/openzeppelin-contracts/contracts', 'solmate=lib/solmate/src', ] # gas limit - max u64 diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts new file mode 160000 index 000000000..01ef44898 --- /dev/null +++ b/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit 01ef448981be9d20ca85f2faf6ebdf591ce409f3 diff --git a/script/DevnetMigration.s.sol b/script/DevnetMigration.s.sol index c28bce40e..20991f190 100644 --- a/script/DevnetMigration.s.sol +++ b/script/DevnetMigration.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { Script } from "forge-std/Script.sol"; import { stdJson } from "forge-std/StdJson.sol"; @@ -10,12 +10,14 @@ import { ERC4626Target0Deployer } from "contracts/src/deployers/erc4626/ERC4626T import { ERC4626Target1Deployer } from "contracts/src/deployers/erc4626/ERC4626Target1Deployer.sol"; import { ERC4626Target2Deployer } from "contracts/src/deployers/erc4626/ERC4626Target2Deployer.sol"; import { ERC4626Target3Deployer } from "contracts/src/deployers/erc4626/ERC4626Target3Deployer.sol"; +import { ERC4626Target4Deployer } from "contracts/src/deployers/erc4626/ERC4626Target4Deployer.sol"; import { StETHHyperdriveCoreDeployer } from "contracts/src/deployers/steth/StETHHyperdriveCoreDeployer.sol"; import { StETHHyperdriveDeployerCoordinator } from "contracts/src/deployers/steth/StETHHyperdriveDeployerCoordinator.sol"; import { StETHTarget0Deployer } from "contracts/src/deployers/steth/StETHTarget0Deployer.sol"; import { StETHTarget1Deployer } from "contracts/src/deployers/steth/StETHTarget1Deployer.sol"; import { StETHTarget2Deployer } from "contracts/src/deployers/steth/StETHTarget2Deployer.sol"; import { StETHTarget3Deployer } from "contracts/src/deployers/steth/StETHTarget3Deployer.sol"; +import { StETHTarget4Deployer } from "contracts/src/deployers/steth/StETHTarget4Deployer.sol"; import { HyperdriveFactory } from "contracts/src/factory/HyperdriveFactory.sol"; import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; import { IERC4626 } from "contracts/src/interfaces/IERC4626.sol"; @@ -383,7 +385,8 @@ contract DevnetMigration is Script { address(new ERC4626Target0Deployer()), address(new ERC4626Target1Deployer()), address(new ERC4626Target2Deployer()), - address(new ERC4626Target3Deployer()) + address(new ERC4626Target3Deployer()), + address(new ERC4626Target4Deployer()) ) ); factory.addDeployerCoordinator(erc4626DeployerCoordinator); @@ -419,14 +422,66 @@ contract DevnetMigration is Script { .erc4626HyperdriveGovernanceZombieFee }) }); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + erc4626DeployerCoordinator, + poolConfig, + abi.encode(address(pool)), + config.erc4626HyperdriveFixedAPR, + config.erc4626HyperdriveTimeStretchAPR, + 0, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + erc4626DeployerCoordinator, + poolConfig, + abi.encode(address(pool)), + config.erc4626HyperdriveFixedAPR, + config.erc4626HyperdriveTimeStretchAPR, + 1, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + erc4626DeployerCoordinator, + poolConfig, + abi.encode(address(pool)), + config.erc4626HyperdriveFixedAPR, + config.erc4626HyperdriveTimeStretchAPR, + 2, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + erc4626DeployerCoordinator, + poolConfig, + abi.encode(address(pool)), + config.erc4626HyperdriveFixedAPR, + config.erc4626HyperdriveTimeStretchAPR, + 3, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + erc4626DeployerCoordinator, + poolConfig, + abi.encode(address(pool)), + config.erc4626HyperdriveFixedAPR, + config.erc4626HyperdriveTimeStretchAPR, + 4, + bytes32(uint256(0xdeadbabe)) + ); erc4626Hyperdrive = factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), erc4626DeployerCoordinator, poolConfig, - abi.encode(address(pool), new address[](0)), + abi.encode(address(pool)), config.erc4626HyperdriveContribution, config.erc4626HyperdriveFixedAPR, config.erc4626HyperdriveTimeStretchAPR, - new bytes(0) + new bytes(0), + bytes32(uint256(0xdeadbabe)) ); } @@ -438,6 +493,7 @@ contract DevnetMigration is Script { address(new StETHTarget1Deployer(ILido(address(lido)))), address(new StETHTarget2Deployer(ILido(address(lido)))), address(new StETHTarget3Deployer(ILido(address(lido)))), + address(new StETHTarget4Deployer(ILido(address(lido)))), ILido(address(lido)) ) ); @@ -470,16 +526,68 @@ contract DevnetMigration is Script { .stethHyperdriveGovernanceZombieFee }) }); + factory.deployTarget( + bytes32(uint256(0xbeefbabe)), + stethDeployerCoordinator, + poolConfig, + new bytes(0), + config.stethHyperdriveFixedAPR, + config.stethHyperdriveTimeStretchAPR, + 0, + bytes32(uint256(0xdeadfade)) + ); + factory.deployTarget( + bytes32(uint256(0xbeefbabe)), + stethDeployerCoordinator, + poolConfig, + new bytes(0), + config.stethHyperdriveFixedAPR, + config.stethHyperdriveTimeStretchAPR, + 1, + bytes32(uint256(0xdeadfade)) + ); + factory.deployTarget( + bytes32(uint256(0xbeefbabe)), + stethDeployerCoordinator, + poolConfig, + new bytes(0), + config.stethHyperdriveFixedAPR, + config.stethHyperdriveTimeStretchAPR, + 2, + bytes32(uint256(0xdeadfade)) + ); + factory.deployTarget( + bytes32(uint256(0xbeefbabe)), + stethDeployerCoordinator, + poolConfig, + new bytes(0), + config.stethHyperdriveFixedAPR, + config.stethHyperdriveTimeStretchAPR, + 3, + bytes32(uint256(0xdeadfade)) + ); + factory.deployTarget( + bytes32(uint256(0xbeefbabe)), + stethDeployerCoordinator, + poolConfig, + new bytes(0), + config.stethHyperdriveFixedAPR, + config.stethHyperdriveTimeStretchAPR, + 4, + bytes32(uint256(0xdeadfade)) + ); stethHyperdrive = factory.deployAndInitialize{ value: config.stethHyperdriveContribution }( + bytes32(uint256(0xbeefbabe)), stethDeployerCoordinator, poolConfig, - abi.encode(address(pool), new address[](0)), + new bytes(0), config.stethHyperdriveContribution, config.stethHyperdriveFixedAPR, config.stethHyperdriveTimeStretchAPR, - new bytes(0) + new bytes(0), + bytes32(uint256(0xdeadfade)) ); } @@ -502,7 +610,7 @@ contract DevnetMigration is Script { "erc4626Hyperdrive", address(erc4626Hyperdrive) ); - vm.serializeAddress( + result = vm.serializeAddress( result, "stethHyperdrive", address(stethHyperdrive) diff --git a/test/3rdPartyLibs/LogExpMath.sol b/test/3rdPartyLibs/LogExpMath.sol index 7a47a8650..591dbb76d 100644 --- a/test/3rdPartyLibs/LogExpMath.sol +++ b/test/3rdPartyLibs/LogExpMath.sol @@ -12,7 +12,7 @@ // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { BalancerErrors, _require } from "test/3rdPartyLibs/BalancerErrors.sol"; diff --git a/test/combinatorial/MultiToken._transferFrom.t.sol b/test/combinatorial/MultiToken._transferFrom.t.sol index 18f0fe61d..8f86d8cc0 100644 --- a/test/combinatorial/MultiToken._transferFrom.t.sol +++ b/test/combinatorial/MultiToken._transferFrom.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import "forge-std/Test.sol"; import "forge-std/console2.sol"; diff --git a/test/instances/erc4626/ERC4626Hyperdrive.t.sol b/test/instances/erc4626/ERC4626Hyperdrive.t.sol index 9a8da9c61..ae1bdd859 100644 --- a/test/instances/erc4626/ERC4626Hyperdrive.t.sol +++ b/test/instances/erc4626/ERC4626Hyperdrive.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { ERC4626HyperdriveCoreDeployer } from "contracts/src/deployers/erc4626/ERC4626HyperdriveCoreDeployer.sol"; import { ERC4626HyperdriveDeployerCoordinator } from "contracts/src/deployers/erc4626/ERC4626HyperdriveDeployerCoordinator.sol"; @@ -7,16 +7,18 @@ import { ERC4626Target0Deployer } from "contracts/src/deployers/erc4626/ERC4626T import { ERC4626Target1Deployer } from "contracts/src/deployers/erc4626/ERC4626Target1Deployer.sol"; import { ERC4626Target2Deployer } from "contracts/src/deployers/erc4626/ERC4626Target2Deployer.sol"; import { ERC4626Target3Deployer } from "contracts/src/deployers/erc4626/ERC4626Target3Deployer.sol"; +import { ERC4626Target4Deployer } from "contracts/src/deployers/erc4626/ERC4626Target4Deployer.sol"; import { HyperdriveFactory } from "contracts/src/factory/HyperdriveFactory.sol"; import { ERC4626Target0 } from "contracts/src/instances/erc4626/ERC4626Target0.sol"; import { ERC4626Target1 } from "contracts/src/instances/erc4626/ERC4626Target1.sol"; import { ERC4626Target2 } from "contracts/src/instances/erc4626/ERC4626Target2.sol"; import { ERC4626Target3 } from "contracts/src/instances/erc4626/ERC4626Target3.sol"; +import { ERC4626Target4 } from "contracts/src/instances/erc4626/ERC4626Target4.sol"; import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; import { IERC4626 } from "contracts/src/interfaces/IERC4626.sol"; import { IERC4626Hyperdrive } from "contracts/src/interfaces/IERC4626Hyperdrive.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; -import { IDeployerCoordinator } from "contracts/src/interfaces/IDeployerCoordinator.sol"; +import { IHyperdriveDeployerCoordinator } from "contracts/src/interfaces/IHyperdriveDeployerCoordinator.sol"; import { AssetId } from "contracts/src/libraries/AssetId.sol"; import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; @@ -38,6 +40,7 @@ contract ERC4626HyperdriveTest is HyperdriveTest { address target1Deployer; address target2Deployer; address target3Deployer; + address target4Deployer; IERC20 dai = IERC20(address(0x6B175474E89094C44Da98b954EedeAC495271d0F)); IERC4626 pool; @@ -68,13 +71,15 @@ contract ERC4626HyperdriveTest is HyperdriveTest { target1Deployer = address(new ERC4626Target1Deployer()); target2Deployer = address(new ERC4626Target2Deployer()); target3Deployer = address(new ERC4626Target3Deployer()); + target4Deployer = address(new ERC4626Target4Deployer()); deployerCoordinator = address( new ERC4626HyperdriveDeployerCoordinator( coreDeployer, target0Deployer, target1Deployer, target2Deployer, - target3Deployer + target3Deployer, + target4Deployer ) ); address[] memory defaults = new address[](1); @@ -135,12 +140,14 @@ contract ERC4626HyperdriveTest is HyperdriveTest { address target1 = address(new ERC4626Target1(config, pool)); address target2 = address(new ERC4626Target2(config, pool)); address target3 = address(new ERC4626Target3(config, pool)); + address target4 = address(new ERC4626Target4(config, pool)); mockHyperdrive = new MockERC4626Hyperdrive( config, target0, target1, target2, target3, + target4, pool ); @@ -290,14 +297,66 @@ contract ERC4626HyperdriveTest is HyperdriveTest { fees: IHyperdrive.Fees(0, 0, 0, 0) }); dai.approve(address(factory), type(uint256).max); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + abi.encode(address(pool)), + apr, + apr, + 0, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + abi.encode(address(pool)), + apr, + apr, + 1, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + abi.encode(address(pool)), + apr, + apr, + 2, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + abi.encode(address(pool)), + apr, + apr, + 3, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + abi.encode(address(pool)), + apr, + apr, + 4, + bytes32(uint256(0xdeadbabe)) + ); hyperdrive = factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), deployerCoordinator, config, - abi.encode(address(pool), new address[](0)), + abi.encode(address(pool)), contribution, apr, apr, - new bytes(0) + new bytes(0), + bytes32(uint256(0xdeadbabe)) ); // The initial price per share is one so the LP shares will initially @@ -317,7 +376,7 @@ contract ERC4626HyperdriveTest is HyperdriveTest { contribution, apr, config.minimumShareReserves, - abi.encode(address(pool), new address[](0)), + abi.encode(address(pool)), 0 ); } @@ -342,14 +401,66 @@ contract ERC4626HyperdriveTest is HyperdriveTest { fees: IHyperdrive.Fees(0, 0, 0, 0) }); dai.approve(address(factory), type(uint256).max); + factory.deployTarget( + bytes32(uint256(0xdead)), + deployerCoordinator, + config, + abi.encode(address(pool)), + apr, + apr, + 0, + bytes32(uint256(0xbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdead)), + deployerCoordinator, + config, + abi.encode(address(pool)), + apr, + apr, + 1, + bytes32(uint256(0xbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdead)), + deployerCoordinator, + config, + abi.encode(address(pool)), + apr, + apr, + 2, + bytes32(uint256(0xbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdead)), + deployerCoordinator, + config, + abi.encode(address(pool)), + apr, + apr, + 3, + bytes32(uint256(0xbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdead)), + deployerCoordinator, + config, + abi.encode(address(pool)), + apr, + apr, + 4, + bytes32(uint256(0xbabe)) + ); hyperdrive = factory.deployAndInitialize( + bytes32(uint256(0xdead)), deployerCoordinator, config, - abi.encode(address(pool), new address[](0)), + abi.encode(address(pool)), contribution, apr, apr, - new bytes(0) + new bytes(0), + bytes32(uint256(0xbabe)) ); // Ensure the share price is 1 after initialization. diff --git a/test/instances/erc4626/ERC4626Validation.t.sol b/test/instances/erc4626/ERC4626Validation.t.sol index e4cf1d129..ad6b13810 100644 --- a/test/instances/erc4626/ERC4626Validation.t.sol +++ b/test/instances/erc4626/ERC4626Validation.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { ERC4626HyperdriveCoreDeployer } from "contracts/src/deployers/erc4626/ERC4626HyperdriveCoreDeployer.sol"; import { ERC4626HyperdriveDeployerCoordinator } from "contracts/src/deployers/erc4626/ERC4626HyperdriveDeployerCoordinator.sol"; @@ -7,11 +7,12 @@ import { ERC4626Target0Deployer } from "contracts/src/deployers/erc4626/ERC4626T import { ERC4626Target1Deployer } from "contracts/src/deployers/erc4626/ERC4626Target1Deployer.sol"; import { ERC4626Target2Deployer } from "contracts/src/deployers/erc4626/ERC4626Target2Deployer.sol"; import { ERC4626Target3Deployer } from "contracts/src/deployers/erc4626/ERC4626Target3Deployer.sol"; +import { ERC4626Target4Deployer } from "contracts/src/deployers/erc4626/ERC4626Target4Deployer.sol"; import { HyperdriveFactory } from "contracts/src/factory/HyperdriveFactory.sol"; import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; import { IERC4626 } from "contracts/src/interfaces/IERC4626.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; -import { IDeployerCoordinator } from "contracts/src/interfaces/IDeployerCoordinator.sol"; +import { IHyperdriveDeployerCoordinator } from "contracts/src/interfaces/IHyperdriveDeployerCoordinator.sol"; import { AssetId } from "contracts/src/libraries/AssetId.sol"; import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; @@ -31,6 +32,7 @@ abstract contract ERC4626ValidationTest is HyperdriveTest { address target1Deployer; address target2Deployer; address target3Deployer; + address target4Deployer; HyperdriveFactory internal factory; IERC20 internal underlyingToken; @@ -50,6 +52,7 @@ abstract contract ERC4626ValidationTest is HyperdriveTest { target1Deployer = address(new ERC4626Target1Deployer()); target2Deployer = address(new ERC4626Target2Deployer()); target3Deployer = address(new ERC4626Target3Deployer()); + target4Deployer = address(new ERC4626Target4Deployer()); deployerCoordinator = address( new ERC4626HyperdriveDeployerCoordinator( @@ -57,7 +60,8 @@ abstract contract ERC4626ValidationTest is HyperdriveTest { target0Deployer, target1Deployer, target2Deployer, - target3Deployer + target3Deployer, + target4Deployer ) ); @@ -119,14 +123,66 @@ abstract contract ERC4626ValidationTest is HyperdriveTest { underlyingToken.approve(address(factory), type(uint256).max); // Deploy and set hyperdrive instance + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + abi.encode(address(token)), + FIXED_RATE, + FIXED_RATE, + 0, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + abi.encode(address(token)), + FIXED_RATE, + FIXED_RATE, + 1, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + abi.encode(address(token)), + FIXED_RATE, + FIXED_RATE, + 2, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + abi.encode(address(token)), + FIXED_RATE, + FIXED_RATE, + 3, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + abi.encode(address(token)), + FIXED_RATE, + FIXED_RATE, + 4, + bytes32(uint256(0xdeadbabe)) + ); hyperdrive = factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), deployerCoordinator, config, - abi.encode(address(token), new address[](0)), + abi.encode(address(token)), contribution, FIXED_RATE, FIXED_RATE, - new bytes(0) + new bytes(0), + bytes32(uint256(0xdeadbabe)) ); // Setup maximum approvals so transfers don't require further approval @@ -168,14 +224,67 @@ abstract contract ERC4626ValidationTest is HyperdriveTest { underlyingToken.approve(address(factory), type(uint256).max); // Deploy a new hyperdrive instance + bytes memory extraData = abi.encode(address(token)); + factory.deployTarget( + bytes32(uint256(0xbeef)), + deployerCoordinator, + config, + extraData, + FIXED_RATE, + FIXED_RATE, + 0, + bytes32(uint256(0xfade)) + ); + factory.deployTarget( + bytes32(uint256(0xbeef)), + deployerCoordinator, + config, + extraData, + FIXED_RATE, + FIXED_RATE, + 1, + bytes32(uint256(0xfade)) + ); + factory.deployTarget( + bytes32(uint256(0xbeef)), + deployerCoordinator, + config, + extraData, + FIXED_RATE, + FIXED_RATE, + 2, + bytes32(uint256(0xfade)) + ); + factory.deployTarget( + bytes32(uint256(0xbeef)), + deployerCoordinator, + config, + extraData, + FIXED_RATE, + FIXED_RATE, + 3, + bytes32(uint256(0xfade)) + ); + factory.deployTarget( + bytes32(uint256(0xbeef)), + deployerCoordinator, + config, + extraData, + FIXED_RATE, + FIXED_RATE, + 4, + bytes32(uint256(0xfade)) + ); hyperdrive = factory.deployAndInitialize( + bytes32(uint256(0xbeef)), deployerCoordinator, config, - abi.encode(address(token), new address[](0)), + extraData, contribution, FIXED_RATE, FIXED_RATE, - new bytes(0) + new bytes(0), + bytes32(uint256(0xfade)) ); // Ensure minimumShareReserves were added, and lpTotalSupply increased @@ -192,7 +301,7 @@ abstract contract ERC4626ValidationTest is HyperdriveTest { contribution, FIXED_RATE, config.minimumShareReserves, - abi.encode(address(token), new address[](0)), + extraData, 1e5 ); } diff --git a/test/instances/erc4626/Sweep.t.sol b/test/instances/erc4626/Sweep.t.sol index c6d956140..c36701588 100644 --- a/test/instances/erc4626/Sweep.t.sol +++ b/test/instances/erc4626/Sweep.t.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { ERC4626Hyperdrive } from "contracts/src/instances/erc4626/ERC4626Hyperdrive.sol"; import { ERC4626Target0 } from "contracts/src/instances/erc4626/ERC4626Target0.sol"; import { ERC4626Target1 } from "contracts/src/instances/erc4626/ERC4626Target1.sol"; import { ERC4626Target2 } from "contracts/src/instances/erc4626/ERC4626Target2.sol"; import { ERC4626Target3 } from "contracts/src/instances/erc4626/ERC4626Target3.sol"; +import { ERC4626Target4 } from "contracts/src/instances/erc4626/ERC4626Target4.sol"; import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; import { IERC4626 } from "contracts/src/interfaces/IERC4626.sol"; import { IERC4626Hyperdrive } from "contracts/src/interfaces/IERC4626Hyperdrive.sol"; @@ -90,6 +91,12 @@ contract SweepTest is BaseTest { IERC4626(address(leakyVault)) ) ), + address( + new ERC4626Target4( + config, + IERC4626(address(leakyVault)) + ) + ), IERC4626(address(leakyVault)) ) ) diff --git a/test/instances/erc4626/UsdcERC4626.t.sol b/test/instances/erc4626/UsdcERC4626.t.sol index 1450eebf9..e86066e39 100644 --- a/test/instances/erc4626/UsdcERC4626.t.sol +++ b/test/instances/erc4626/UsdcERC4626.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { ERC4626HyperdriveCoreDeployer } from "contracts/src/deployers/erc4626/ERC4626HyperdriveCoreDeployer.sol"; import { ERC4626HyperdriveDeployerCoordinator } from "contracts/src/deployers/erc4626/ERC4626HyperdriveDeployerCoordinator.sol"; @@ -7,11 +7,12 @@ import { ERC4626Target0Deployer } from "contracts/src/deployers/erc4626/ERC4626T import { ERC4626Target1Deployer } from "contracts/src/deployers/erc4626/ERC4626Target1Deployer.sol"; import { ERC4626Target2Deployer } from "contracts/src/deployers/erc4626/ERC4626Target2Deployer.sol"; import { ERC4626Target3Deployer } from "contracts/src/deployers/erc4626/ERC4626Target3Deployer.sol"; +import { ERC4626Target4Deployer } from "contracts/src/deployers/erc4626/ERC4626Target4Deployer.sol"; import { HyperdriveFactory } from "contracts/src/factory/HyperdriveFactory.sol"; import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; import { IERC4626 } from "contracts/src/interfaces/IERC4626.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; -import { IDeployerCoordinator } from "contracts/src/interfaces/IDeployerCoordinator.sol"; +import { IHyperdriveDeployerCoordinator } from "contracts/src/interfaces/IHyperdriveDeployerCoordinator.sol"; import { ILido } from "contracts/src/interfaces/ILido.sol"; import { AssetId } from "contracts/src/libraries/AssetId.sol"; import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; @@ -59,13 +60,15 @@ contract UsdcERC4626 is ERC4626ValidationTest { target1Deployer = address(new ERC4626Target1Deployer()); target2Deployer = address(new ERC4626Target2Deployer()); target3Deployer = address(new ERC4626Target3Deployer()); + target4Deployer = address(new ERC4626Target4Deployer()); deployerCoordinator = address( new ERC4626HyperdriveDeployerCoordinator( coreDeployer, target0Deployer, target1Deployer, target2Deployer, - target3Deployer + target3Deployer, + target4Deployer ) ); @@ -129,14 +132,67 @@ contract UsdcERC4626 is ERC4626ValidationTest { underlyingToken.approve(address(factory), type(uint256).max); // Deploy and set hyperdrive instance. + bytes memory extraData = abi.encode(address(token)); + factory.deployTarget( + bytes32(uint256(0xbeefbabe)), + deployerCoordinator, + config, + extraData, + FIXED_RATE, + FIXED_RATE, + 0, + bytes32(uint256(0xdeadfade)) + ); + factory.deployTarget( + bytes32(uint256(0xbeefbabe)), + deployerCoordinator, + config, + extraData, + FIXED_RATE, + FIXED_RATE, + 1, + bytes32(uint256(0xdeadfade)) + ); + factory.deployTarget( + bytes32(uint256(0xbeefbabe)), + deployerCoordinator, + config, + extraData, + FIXED_RATE, + FIXED_RATE, + 2, + bytes32(uint256(0xdeadfade)) + ); + factory.deployTarget( + bytes32(uint256(0xbeefbabe)), + deployerCoordinator, + config, + extraData, + FIXED_RATE, + FIXED_RATE, + 3, + bytes32(uint256(0xdeadfade)) + ); + factory.deployTarget( + bytes32(uint256(0xbeefbabe)), + deployerCoordinator, + config, + extraData, + FIXED_RATE, + FIXED_RATE, + 4, + bytes32(uint256(0xdeadfade)) + ); hyperdrive = factory.deployAndInitialize( + bytes32(uint256(0xbeefbabe)), deployerCoordinator, config, - abi.encode(address(token), new address[](0)), + extraData, contribution, FIXED_RATE, FIXED_RATE, - new bytes(0) + new bytes(0), + bytes32(uint256(0xdeadfade)) ); // Setup maximum approvals so transfers don't require further approval. diff --git a/test/instances/erc4626/sDai.t.sol b/test/instances/erc4626/sDai.t.sol index 07eec7bfd..cbb8931f8 100644 --- a/test/instances/erc4626/sDai.t.sol +++ b/test/instances/erc4626/sDai.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; import { IERC4626 } from "contracts/src/interfaces/IERC4626.sol"; diff --git a/test/instances/steth/StETHHyperdrive.t.sol b/test/instances/steth/StETHHyperdrive.t.sol index f7d57c120..c51e844ab 100644 --- a/test/instances/steth/StETHHyperdrive.t.sol +++ b/test/instances/steth/StETHHyperdrive.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { stdStorage, StdStorage } from "forge-std/Test.sol"; import { StETHHyperdriveCoreDeployer } from "contracts/src/deployers/steth/StETHHyperdriveCoreDeployer.sol"; @@ -8,6 +8,7 @@ import { StETHTarget0Deployer } from "contracts/src/deployers/steth/StETHTarget0 import { StETHTarget1Deployer } from "contracts/src/deployers/steth/StETHTarget1Deployer.sol"; import { StETHTarget2Deployer } from "contracts/src/deployers/steth/StETHTarget2Deployer.sol"; import { StETHTarget3Deployer } from "contracts/src/deployers/steth/StETHTarget3Deployer.sol"; +import { StETHTarget4Deployer } from "contracts/src/deployers/steth/StETHTarget4Deployer.sol"; import { HyperdriveFactory } from "contracts/src/factory/HyperdriveFactory.sol"; import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; @@ -94,6 +95,7 @@ contract StETHHyperdriveTest is HyperdriveTest { address(new StETHTarget1Deployer(LIDO)), address(new StETHTarget2Deployer(LIDO)), address(new StETHTarget3Deployer(LIDO)), + address(new StETHTarget4Deployer(LIDO)), LIDO ) ); @@ -120,14 +122,66 @@ contract StETHHyperdriveTest is HyperdriveTest { }) }); uint256 contribution = 10_000e18; + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + new bytes(0), + FIXED_RATE, + FIXED_RATE, + 0, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + new bytes(0), + FIXED_RATE, + FIXED_RATE, + 1, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + new bytes(0), + FIXED_RATE, + FIXED_RATE, + 2, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + new bytes(0), + FIXED_RATE, + FIXED_RATE, + 3, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + new bytes(0), + FIXED_RATE, + FIXED_RATE, + 4, + bytes32(uint256(0xdeadbabe)) + ); hyperdrive = factory.deployAndInitialize{ value: contribution }( + bytes32(uint256(0xdeadbeef)), deployerCoordinator, config, new bytes(0), contribution, FIXED_RATE, FIXED_RATE, - new bytes(0) + new bytes(0), + bytes32(uint256(0xdeadbabe)) ); // Ensure that Bob received the correct amount of LP tokens. She should @@ -184,14 +238,66 @@ contract StETHHyperdriveTest is HyperdriveTest { }) }); uint256 contribution = 5_000e18; + factory.deployTarget( + bytes32(uint256(0xbeefbabe)), + deployerCoordinator, + config, + new bytes(0), + FIXED_RATE, + FIXED_RATE, + 0, + bytes32(uint256(0xdeadfade)) + ); + factory.deployTarget( + bytes32(uint256(0xbeefbabe)), + deployerCoordinator, + config, + new bytes(0), + FIXED_RATE, + FIXED_RATE, + 1, + bytes32(uint256(0xdeadfade)) + ); + factory.deployTarget( + bytes32(uint256(0xbeefbabe)), + deployerCoordinator, + config, + new bytes(0), + FIXED_RATE, + FIXED_RATE, + 2, + bytes32(uint256(0xdeadfade)) + ); + factory.deployTarget( + bytes32(uint256(0xbeefbabe)), + deployerCoordinator, + config, + new bytes(0), + FIXED_RATE, + FIXED_RATE, + 3, + bytes32(uint256(0xdeadfade)) + ); + factory.deployTarget( + bytes32(uint256(0xbeefbabe)), + deployerCoordinator, + config, + new bytes(0), + FIXED_RATE, + FIXED_RATE, + 4, + bytes32(uint256(0xdeadfade)) + ); hyperdrive = factory.deployAndInitialize{ value: contribution + 1e18 }( + bytes32(uint256(0xbeefbabe)), address(deployerCoordinator), config, new bytes(0), contribution, FIXED_RATE, FIXED_RATE, - new bytes(0) + new bytes(0), + bytes32(uint256(0xdeadfade)) ); assertEq(address(bob).balance, bobBalanceBefore - contribution); diff --git a/test/instances/steth/Sweep.t.sol b/test/instances/steth/Sweep.t.sol index 131f75a1d..1a48b3b30 100644 --- a/test/instances/steth/Sweep.t.sol +++ b/test/instances/steth/Sweep.t.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { StETHHyperdrive } from "contracts/src/instances/steth/StETHHyperdrive.sol"; import { StETHTarget0 } from "contracts/src/instances/steth/StETHTarget0.sol"; import { StETHTarget1 } from "contracts/src/instances/steth/StETHTarget1.sol"; import { StETHTarget2 } from "contracts/src/instances/steth/StETHTarget2.sol"; import { StETHTarget3 } from "contracts/src/instances/steth/StETHTarget3.sol"; +import { StETHTarget4 } from "contracts/src/instances/steth/StETHTarget4.sol"; import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; import { ILido } from "contracts/src/interfaces/ILido.sol"; import { IStETHHyperdrive } from "contracts/src/interfaces/IStETHHyperdrive.sol"; @@ -78,6 +79,9 @@ contract SweepTest is BaseTest { address( new StETHTarget3(config, ILido(address(leakyLido))) ), + address( + new StETHTarget4(config, ILido(address(leakyLido))) + ), ILido(address(leakyLido)) ) ) diff --git a/test/integrations/factory/HyperdriveFactory.t.sol b/test/integrations/factory/HyperdriveFactory.t.sol index 20556f8ac..ab1f8b2f0 100644 --- a/test/integrations/factory/HyperdriveFactory.t.sol +++ b/test/integrations/factory/HyperdriveFactory.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { ERC4626HyperdriveCoreDeployer } from "contracts/src/deployers/erc4626/ERC4626HyperdriveCoreDeployer.sol"; import { ERC4626HyperdriveDeployerCoordinator } from "contracts/src/deployers/erc4626/ERC4626HyperdriveDeployerCoordinator.sol"; @@ -7,13 +7,14 @@ import { ERC4626Target0Deployer } from "contracts/src/deployers/erc4626/ERC4626T import { ERC4626Target1Deployer } from "contracts/src/deployers/erc4626/ERC4626Target1Deployer.sol"; import { ERC4626Target2Deployer } from "contracts/src/deployers/erc4626/ERC4626Target2Deployer.sol"; import { ERC4626Target3Deployer } from "contracts/src/deployers/erc4626/ERC4626Target3Deployer.sol"; +import { ERC4626Target4Deployer } from "contracts/src/deployers/erc4626/ERC4626Target4Deployer.sol"; import { HyperdriveFactory } from "contracts/src/factory/HyperdriveFactory.sol"; import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; import { IERC4626 } from "contracts/src/interfaces/IERC4626.sol"; import { MockERC4626, ERC20 } from "contracts/test/MockERC4626.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; import { IHyperdriveFactory } from "contracts/src/interfaces/IHyperdriveFactory.sol"; -import { IDeployerCoordinator } from "contracts/src/interfaces/IDeployerCoordinator.sol"; +import { IHyperdriveDeployerCoordinator } from "contracts/src/interfaces/IHyperdriveDeployerCoordinator.sol"; import { AssetId } from "contracts/src/libraries/AssetId.sol"; import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; import { ForwarderFactory } from "contracts/src/token/ForwarderFactory.sol"; @@ -1417,12 +1418,14 @@ contract HyperdriveFactoryTest is HyperdriveTest { address(new ERC4626Target0Deployer()), address(new ERC4626Target1Deployer()), address(new ERC4626Target2Deployer()), - address(new ERC4626Target3Deployer()) + address(new ERC4626Target3Deployer()), + address(new ERC4626Target4Deployer()) ) ); factory.addDeployerCoordinator(deployerCoordinator); - // Define a config that can be reused for each test. + // Define a config that can be reused for each test and deploy the + // targets with this config. IHyperdrive.PoolDeployConfig memory config = IHyperdrive .PoolDeployConfig({ baseToken: IERC20(address(base)), @@ -1437,470 +1440,644 @@ contract HyperdriveFactoryTest is HyperdriveTest { linkerFactory: address(0), linkerCodeHash: bytes32(0) }); - - // Ensure that an instance can't be deployed with a coordinator that - // hasn't been added. vm.stopPrank(); vm.startPrank(bob); bytes memory extraData = abi.encode(vault); - vm.expectRevert(IHyperdriveFactory.InvalidDeployerCoordinator.selector); - factory.deployAndInitialize( - address(0xdeadbeef), + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, config, extraData, - 10_000e18, - 0.02e18, 0.05e18, - new bytes(0) + 0.05e18, + 0, + bytes32(uint256(0xdeadbabe)) ); - - // Ensure than an instance can't be deployed with a checkpoint duration - // that is greater than the maximum checkpoint duration. - vm.stopPrank(); - vm.startPrank(bob); - uint256 oldCheckpointDuration = config.checkpointDuration; - config.checkpointDuration = - factory.maxCheckpointDuration() + - factory.checkpointDurationResolution(); - vm.expectRevert(IHyperdriveFactory.InvalidCheckpointDuration.selector); - factory.deployAndInitialize( + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), deployerCoordinator, config, extraData, - 10_000e18, - 0.02e18, 0.05e18, - new bytes(0) + 0.05e18, + 1, + bytes32(uint256(0xdeadbabe)) ); - config.checkpointDuration = oldCheckpointDuration; - - // Ensure than an instance can't be deployed with a checkpoint duration - // that is less than the minimum checkpoint duration. - vm.stopPrank(); - vm.startPrank(bob); - oldCheckpointDuration = config.checkpointDuration; - config.checkpointDuration = - factory.minCheckpointDuration() - - factory.checkpointDurationResolution(); - vm.expectRevert(IHyperdriveFactory.InvalidCheckpointDuration.selector); - factory.deployAndInitialize( + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), deployerCoordinator, config, extraData, - 10_000e18, - 0.02e18, 0.05e18, - new bytes(0) + 0.05e18, + 2, + bytes32(uint256(0xdeadbabe)) ); - config.checkpointDuration = oldCheckpointDuration; - - // Ensure than an instance can't be deployed with a checkpoint duration - // that isn't a multiple of the checkpoint duration resolution. - vm.stopPrank(); - vm.startPrank(bob); - oldCheckpointDuration = config.checkpointDuration; - config.checkpointDuration = factory.minCheckpointDuration() + 1; - vm.expectRevert(IHyperdriveFactory.InvalidCheckpointDuration.selector); - factory.deployAndInitialize( + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), deployerCoordinator, config, extraData, - 10_000e18, - 0.02e18, 0.05e18, - new bytes(0) + 0.05e18, + 3, + bytes32(uint256(0xdeadbabe)) ); - config.checkpointDuration = oldCheckpointDuration; - - // Ensure than an instance can't be deployed with a position duration - // that is greater than the maximum position duration. - vm.stopPrank(); - vm.startPrank(bob); - uint256 oldPositionDuration = config.positionDuration; - config.positionDuration = - factory.maxPositionDuration() + - factory.checkpointDurationResolution(); - vm.expectRevert(IHyperdriveFactory.InvalidPositionDuration.selector); - factory.deployAndInitialize( + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), deployerCoordinator, config, extraData, - 10_000e18, - 0.02e18, 0.05e18, - new bytes(0) + 0.05e18, + 4, + bytes32(uint256(0xdeadbabe)) ); - config.positionDuration = oldPositionDuration; + + // Ensure that an instance can't be deployed with a coordinator that + // hasn't been added. + { + vm.stopPrank(); + vm.startPrank(bob); + vm.expectRevert( + IHyperdriveFactory.InvalidDeployerCoordinator.selector + ); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + address(0xdeadbeef), + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + } + + // Ensure than an instance can't be deployed with a checkpoint duration + // that is greater than the maximum checkpoint duration. + { + vm.stopPrank(); + vm.startPrank(bob); + uint256 oldCheckpointDuration = config.checkpointDuration; + config.checkpointDuration = + factory.maxCheckpointDuration() + + factory.checkpointDurationResolution(); + vm.expectRevert( + IHyperdriveFactory.InvalidCheckpointDuration.selector + ); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.checkpointDuration = oldCheckpointDuration; + } + + // Ensure than an instance can't be deployed with a checkpoint duration + // that is less than the minimum checkpoint duration. + { + vm.stopPrank(); + vm.startPrank(bob); + uint256 oldCheckpointDuration = config.checkpointDuration; + config.checkpointDuration = + factory.minCheckpointDuration() - + factory.checkpointDurationResolution(); + vm.expectRevert( + IHyperdriveFactory.InvalidCheckpointDuration.selector + ); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.checkpointDuration = oldCheckpointDuration; + } + + // Ensure than an instance can't be deployed with a checkpoint duration + // that isn't a multiple of the checkpoint duration resolution. + { + vm.stopPrank(); + vm.startPrank(bob); + uint256 oldCheckpointDuration = config.checkpointDuration; + config.checkpointDuration = factory.minCheckpointDuration() + 1; + vm.expectRevert( + IHyperdriveFactory.InvalidCheckpointDuration.selector + ); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.checkpointDuration = oldCheckpointDuration; + } + + // Ensure than an instance can't be deployed with a position duration + // that is greater than the maximum position duration. + { + vm.stopPrank(); + vm.startPrank(bob); + uint256 oldPositionDuration = config.positionDuration; + config.positionDuration = + factory.maxPositionDuration() + + factory.checkpointDurationResolution(); + vm.expectRevert( + IHyperdriveFactory.InvalidPositionDuration.selector + ); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.positionDuration = oldPositionDuration; + } // Ensure than an instance can't be deployed with a position duration // that is less than the minimum position duration. - vm.stopPrank(); - vm.startPrank(bob); - oldPositionDuration = config.positionDuration; - config.positionDuration = - factory.minPositionDuration() - - factory.checkpointDurationResolution(); - vm.expectRevert(IHyperdriveFactory.InvalidPositionDuration.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.02e18, - 0.05e18, - new bytes(0) - ); - config.positionDuration = oldPositionDuration; + { + vm.stopPrank(); + vm.startPrank(bob); + uint256 oldPositionDuration = config.positionDuration; + config.positionDuration = + factory.minPositionDuration() - + factory.checkpointDurationResolution(); + vm.expectRevert( + IHyperdriveFactory.InvalidPositionDuration.selector + ); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.positionDuration = oldPositionDuration; + } // Ensure than an instance can't be deployed with a position duration // that isn't a multiple of the checkpoint duration. - vm.stopPrank(); - vm.startPrank(bob); - oldPositionDuration = config.positionDuration; - config.positionDuration = 365 * config.checkpointDuration + 1; - vm.expectRevert(IHyperdriveFactory.InvalidPositionDuration.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.02e18, - 0.05e18, - new bytes(0) - ); - config.positionDuration = oldPositionDuration; + { + vm.stopPrank(); + vm.startPrank(bob); + uint256 oldPositionDuration = config.positionDuration; + config.positionDuration = 365 * config.checkpointDuration + 1; + vm.expectRevert( + IHyperdriveFactory.InvalidPositionDuration.selector + ); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.positionDuration = oldPositionDuration; + } // Ensure than an instance can't be deployed with a fixed APR less than // the minimum. - vm.stopPrank(); - vm.startPrank(bob); - uint256 fixedAPR = factory.minFixedAPR() - 1; - vm.expectRevert(IHyperdriveFactory.InvalidFixedAPR.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - fixedAPR, - 0.05e18, - new bytes(0) - ); + { + vm.stopPrank(); + vm.startPrank(bob); + uint256 fixedAPR = factory.minFixedAPR() - 1; + vm.expectRevert(IHyperdriveFactory.InvalidFixedAPR.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + fixedAPR, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + } // Ensure than an instance can't be deployed with a fixed APR greater // than the maximum. - vm.stopPrank(); - vm.startPrank(bob); - fixedAPR = factory.maxFixedAPR() + 1; - vm.expectRevert(IHyperdriveFactory.InvalidFixedAPR.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - fixedAPR, - 0.05e18, - new bytes(0) - ); + { + vm.stopPrank(); + vm.startPrank(bob); + uint256 fixedAPR = factory.maxFixedAPR() + 1; + vm.expectRevert(IHyperdriveFactory.InvalidFixedAPR.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + fixedAPR, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + } // Ensure than an instance can't be deployed with a time stretch APR // less than 0.5%. - vm.stopPrank(); - vm.startPrank(factory.governance()); - factory.updateMinTimeStretchAPR(0.001e18); - vm.stopPrank(); - vm.startPrank(bob); - vm.expectRevert(IHyperdriveFactory.InvalidTimeStretchAPR.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.001e18, - 0.004e18, - new bytes(0) - ); + { + vm.stopPrank(); + vm.startPrank(factory.governance()); + factory.updateMinTimeStretchAPR(0.001e18); + vm.stopPrank(); + vm.startPrank(bob); + vm.expectRevert(IHyperdriveFactory.InvalidTimeStretchAPR.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.001e18, + 0.004e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + } // Ensure than an instance can't be deployed with a time stretch APR // less than the fixed rate divided by two. - vm.stopPrank(); - vm.startPrank(bob); - vm.expectRevert(IHyperdriveFactory.InvalidTimeStretchAPR.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.02e18, - 0.006e18, - new bytes(0) - ); + { + vm.stopPrank(); + vm.startPrank(bob); + vm.expectRevert(IHyperdriveFactory.InvalidTimeStretchAPR.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.006e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + } // Ensure than an instance can't be deployed with a time stretch APR // less than the minimum time stretch APR specified by governance. - vm.stopPrank(); - vm.startPrank(factory.governance()); - factory.updateMinTimeStretchAPR(0.02e18); - vm.stopPrank(); - vm.startPrank(bob); - vm.expectRevert(IHyperdriveFactory.InvalidTimeStretchAPR.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.02e18, - 0.019e18, - new bytes(0) - ); + { + vm.stopPrank(); + vm.startPrank(factory.governance()); + factory.updateMinTimeStretchAPR(0.02e18); + vm.stopPrank(); + vm.startPrank(bob); + vm.expectRevert(IHyperdriveFactory.InvalidTimeStretchAPR.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.019e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + } // Ensure than an instance can't be deployed with a time stretch APR // greater than the lower bound (0.5%) multiplied by two. - vm.stopPrank(); - vm.startPrank(factory.governance()); - factory.updateMinTimeStretchAPR(0.001e18); - vm.stopPrank(); - vm.startPrank(bob); - vm.expectRevert(IHyperdriveFactory.InvalidTimeStretchAPR.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.003e18, - 0.011e18, - new bytes(0) - ); + { + vm.stopPrank(); + vm.startPrank(factory.governance()); + factory.updateMinTimeStretchAPR(0.001e18); + vm.stopPrank(); + vm.startPrank(bob); + vm.expectRevert(IHyperdriveFactory.InvalidTimeStretchAPR.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.003e18, + 0.011e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + } // Ensure than an instance can't be deployed with a time stretch APR // greater than the fixed rate multiplied by two. - vm.stopPrank(); - vm.startPrank(bob); - vm.expectRevert(IHyperdriveFactory.InvalidTimeStretchAPR.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.012e18, - 0.025e18, - new bytes(0) - ); + { + vm.stopPrank(); + vm.startPrank(bob); + vm.expectRevert(IHyperdriveFactory.InvalidTimeStretchAPR.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.012e18, + 0.025e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + } // Ensure than an instance can't be deployed with a time stretch APR // greater than the max time stretch APR specified by governance. - vm.stopPrank(); - vm.startPrank(factory.governance()); - factory.updateMaxTimeStretchAPR(0.3e18); - vm.stopPrank(); - vm.startPrank(bob); - vm.expectRevert(IHyperdriveFactory.InvalidTimeStretchAPR.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.3e18, - 0.31e18, - new bytes(0) - ); + { + vm.stopPrank(); + vm.startPrank(factory.governance()); + factory.updateMaxTimeStretchAPR(0.3e18); + vm.stopPrank(); + vm.startPrank(bob); + vm.expectRevert(IHyperdriveFactory.InvalidTimeStretchAPR.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.3e18, + 0.31e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + } // Ensure than an instance can't be deployed with a curve fee greater // than the maximum curve fee. - vm.stopPrank(); - vm.startPrank(bob); - uint256 oldCurveFee = config.fees.curve; - config.fees.curve = factory.maxFees().curve + 1; - vm.expectRevert(IHyperdriveFactory.InvalidFees.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.02e18, - 0.05e18, - new bytes(0) - ); - config.fees.curve = oldCurveFee; + { + vm.stopPrank(); + vm.startPrank(bob); + uint256 oldCurveFee = config.fees.curve; + config.fees.curve = factory.maxFees().curve + 1; + vm.expectRevert(IHyperdriveFactory.InvalidFees.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.fees.curve = oldCurveFee; + } // Ensure than an instance can't be deployed with a curve fee less // than the minimum curve fee. - vm.stopPrank(); - vm.startPrank(bob); - oldCurveFee = config.fees.curve; - config.fees.curve = factory.minFees().curve - 1; - vm.expectRevert(IHyperdriveFactory.InvalidFees.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.02e18, - 0.05e18, - new bytes(0) - ); - config.fees.curve = oldCurveFee; + { + vm.stopPrank(); + vm.startPrank(bob); + uint256 oldCurveFee = config.fees.curve; + config.fees.curve = factory.minFees().curve - 1; + vm.expectRevert(IHyperdriveFactory.InvalidFees.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.fees.curve = oldCurveFee; + } // Ensure than an instance can't be deployed with a flat fee greater // than the maximum flat fee. - vm.stopPrank(); - vm.startPrank(bob); - uint256 oldFlatFee = config.fees.flat; - config.fees.flat = factory.maxFees().flat + 1; - vm.expectRevert(IHyperdriveFactory.InvalidFees.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.02e18, - 0.05e18, - new bytes(0) - ); - config.fees.flat = oldFlatFee; + { + vm.stopPrank(); + vm.startPrank(bob); + uint256 oldFlatFee = config.fees.flat; + config.fees.flat = factory.maxFees().flat + 1; + vm.expectRevert(IHyperdriveFactory.InvalidFees.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.fees.flat = oldFlatFee; + } // Ensure than an instance can't be deployed with a flat fee less // than the minimum flat fee. - vm.stopPrank(); - vm.startPrank(bob); - oldFlatFee = config.fees.flat; - config.fees.flat = factory.minFees().flat - 1; - vm.expectRevert(IHyperdriveFactory.InvalidFees.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.02e18, - 0.05e18, - new bytes(0) - ); - config.fees.flat = oldFlatFee; + { + vm.stopPrank(); + vm.startPrank(bob); + uint256 oldFlatFee = config.fees.flat; + config.fees.flat = factory.minFees().flat - 1; + vm.expectRevert(IHyperdriveFactory.InvalidFees.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.fees.flat = oldFlatFee; + } // Ensure than an instance can't be deployed with a governance LP fee // greater than the maximum governance LP fee. - vm.stopPrank(); - vm.startPrank(bob); - uint256 oldGovernanceLPFee = config.fees.governanceLP; - config.fees.governanceLP = factory.maxFees().governanceLP + 1; - vm.expectRevert(IHyperdriveFactory.InvalidFees.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.02e18, - 0.05e18, - new bytes(0) - ); - config.fees.governanceLP = oldGovernanceLPFee; + { + vm.stopPrank(); + vm.startPrank(bob); + uint256 oldGovernanceLPFee = config.fees.governanceLP; + config.fees.governanceLP = factory.maxFees().governanceLP + 1; + vm.expectRevert(IHyperdriveFactory.InvalidFees.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.fees.governanceLP = oldGovernanceLPFee; + } // Ensure than an instance can't be deployed with a governance LP fee // less than the minimum governance LP fee. - vm.stopPrank(); - vm.startPrank(bob); - oldGovernanceLPFee = config.fees.governanceLP; - config.fees.governanceLP = factory.minFees().governanceLP - 1; - vm.expectRevert(IHyperdriveFactory.InvalidFees.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.02e18, - 0.05e18, - new bytes(0) - ); - config.fees.governanceLP = oldGovernanceLPFee; + { + vm.stopPrank(); + vm.startPrank(bob); + uint256 oldGovernanceLPFee = config.fees.governanceLP; + config.fees.governanceLP = factory.minFees().governanceLP - 1; + vm.expectRevert(IHyperdriveFactory.InvalidFees.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.fees.governanceLP = oldGovernanceLPFee; + } // Ensure than an instance can't be deployed with a governance zombie // fee greater than the maximum governance zombie fee. - vm.stopPrank(); - vm.startPrank(bob); - uint256 oldGovernanceZombieFee = config.fees.governanceZombie; - config.fees.governanceZombie = factory.maxFees().governanceZombie + 1; - vm.expectRevert(IHyperdriveFactory.InvalidFees.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.02e18, - 0.05e18, - new bytes(0) - ); - config.fees.governanceZombie = oldGovernanceZombieFee; + { + vm.stopPrank(); + vm.startPrank(bob); + uint256 oldGovernanceZombieFee = config.fees.governanceZombie; + config.fees.governanceZombie = + factory.maxFees().governanceZombie + + 1; + vm.expectRevert(IHyperdriveFactory.InvalidFees.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.fees.governanceZombie = oldGovernanceZombieFee; + } // Ensure than an instance can't be deployed with a governance zombie // fee less than the minimum governance zombie fee. - vm.stopPrank(); - vm.startPrank(bob); - oldGovernanceZombieFee = config.fees.governanceZombie; - config.fees.governanceZombie = factory.minFees().governanceZombie - 1; - vm.expectRevert(IHyperdriveFactory.InvalidFees.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.02e18, - 0.05e18, - new bytes(0) - ); - config.fees.governanceZombie = oldGovernanceZombieFee; + { + vm.stopPrank(); + vm.startPrank(bob); + uint256 oldGovernanceZombieFee = config.fees.governanceZombie; + config.fees.governanceZombie = + factory.minFees().governanceZombie - + 1; + vm.expectRevert(IHyperdriveFactory.InvalidFees.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.fees.governanceZombie = oldGovernanceZombieFee; + } // Ensure than an instance can't be deployed with a linker factory that // is set. - vm.stopPrank(); - vm.startPrank(bob); - address oldLinkerFactory = config.linkerFactory; - config.linkerFactory = address(0xdeadbeef); - vm.expectRevert(IHyperdriveFactory.InvalidDeployConfig.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.02e18, - 0.05e18, - new bytes(0) - ); - config.linkerFactory = oldLinkerFactory; + { + vm.stopPrank(); + vm.startPrank(bob); + address oldLinkerFactory = config.linkerFactory; + config.linkerFactory = address(0xdeadbeef); + vm.expectRevert(IHyperdriveFactory.InvalidDeployConfig.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.linkerFactory = oldLinkerFactory; + } // Ensure than an instance can't be deployed with a linker code hash // that is set. - vm.stopPrank(); - vm.startPrank(bob); - bytes32 oldLinkerCodeHash = config.linkerCodeHash; - config.linkerCodeHash = bytes32(uint256(0xdeadbeef)); - vm.expectRevert(IHyperdriveFactory.InvalidDeployConfig.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.02e18, - 0.05e18, - new bytes(0) - ); - config.linkerCodeHash = oldLinkerCodeHash; + { + vm.stopPrank(); + vm.startPrank(bob); + bytes32 oldLinkerCodeHash = config.linkerCodeHash; + config.linkerCodeHash = bytes32(uint256(0xdeadbeef)); + vm.expectRevert(IHyperdriveFactory.InvalidDeployConfig.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.linkerCodeHash = oldLinkerCodeHash; + } // Ensure than an instance can't be deployed with a fee collector that // is set. - vm.stopPrank(); - vm.startPrank(bob); - address oldFeeCollector = config.feeCollector; - config.feeCollector = address(0xdeadbeef); - vm.expectRevert(IHyperdriveFactory.InvalidDeployConfig.selector); - factory.deployAndInitialize( - deployerCoordinator, - config, - extraData, - 10_000e18, - 0.02e18, - 0.05e18, - new bytes(0) - ); - config.feeCollector = oldFeeCollector; + { + vm.stopPrank(); + vm.startPrank(bob); + address oldFeeCollector = config.feeCollector; + config.feeCollector = address(0xdeadbeef); + vm.expectRevert(IHyperdriveFactory.InvalidDeployConfig.selector); + factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + 0.05e18, + new bytes(0), + bytes32(uint256(0xdeadbabe)) + ); + config.feeCollector = oldFeeCollector; + } // Ensure than an instance can't be deployed with a governance address // that is set. @@ -1910,13 +2087,15 @@ contract HyperdriveFactoryTest is HyperdriveTest { config.governance = address(0xdeadbeef); vm.expectRevert(IHyperdriveFactory.InvalidDeployConfig.selector); factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), deployerCoordinator, config, extraData, 10_000e18, 0.02e18, 0.05e18, - new bytes(0) + new bytes(0), + bytes32(uint256(0xdeadbabe)) ); config.governance = oldGovernance; } @@ -1933,6 +2112,7 @@ contract HyperdriveFactoryBaseTest is HyperdriveTest { address target1Deployer; address target2Deployer; address target3Deployer; + address target4Deployer; IERC20 dai = IERC20(address(0x6B175474E89094C44Da98b954EedeAC495271d0F)); @@ -1944,6 +2124,9 @@ contract HyperdriveFactoryBaseTest is HyperdriveTest { uint256 constant APR = 0.01e18; // 1% apr uint256 constant CONTRIBUTION = 2_500e18; + bytes32 deploymentId; + bytes32 salt; + IHyperdrive.PoolDeployConfig config; function setUp() public virtual override __mainnet_fork(16_685_972) { @@ -1958,6 +2141,7 @@ contract HyperdriveFactoryBaseTest is HyperdriveTest { target1Deployer = address(new ERC4626Target1Deployer()); target2Deployer = address(new ERC4626Target2Deployer()); target3Deployer = address(new ERC4626Target3Deployer()); + target4Deployer = address(new ERC4626Target4Deployer()); deployerCoordinator = address( new ERC4626HyperdriveDeployerCoordinator( @@ -1965,7 +2149,8 @@ contract HyperdriveFactoryBaseTest is HyperdriveTest { target0Deployer, target1Deployer, target2Deployer, - target3Deployer + target3Deployer, + target4Deployer ) ); address[] memory defaults = new address[](1); @@ -2049,6 +2234,10 @@ contract HyperdriveFactoryBaseTest is HyperdriveTest { ) ); + // Initialize the deployment ID and salt. + deploymentId = keccak256("deploymentId"); + salt = keccak256("salt"); + // Start recording events. vm.recordLogs(); } @@ -2063,14 +2252,69 @@ contract HyperdriveFactoryBaseTest is HyperdriveTest { dai.approve(address(factory), CONTRIBUTION); + deploymentId = keccak256(abi.encode(deploymentId)); + salt = keccak256(abi.encode(salt)); + bytes memory extraData = abi.encode(address(pool)); + factory.deployTarget( + deploymentId, + deployerCoordinator, + config, + extraData, + APR, + APR, + 0, + salt + ); + factory.deployTarget( + deploymentId, + deployerCoordinator, + config, + extraData, + APR, + APR, + 1, + salt + ); + factory.deployTarget( + deploymentId, + deployerCoordinator, + config, + extraData, + APR, + APR, + 2, + salt + ); + factory.deployTarget( + deploymentId, + deployerCoordinator, + config, + extraData, + APR, + APR, + 3, + salt + ); + factory.deployTarget( + deploymentId, + deployerCoordinator, + config, + extraData, + APR, + APR, + 4, + salt + ); IHyperdrive hyperdrive = factory.deployAndInitialize( + deploymentId, deployerCoordinator, config, - abi.encode(address(pool), new address[](0)), // TODO: Add test with sweeps + extraData, CONTRIBUTION, APR, APR, - new bytes(0) + new bytes(0), + salt ); vm.stopPrank(); @@ -2093,7 +2337,8 @@ contract ERC4626FactoryMultiDeployTest is HyperdriveFactoryBaseTest { address(new ERC4626Target0Deployer()), address(new ERC4626Target1Deployer()), address(new ERC4626Target2Deployer()), - address(new ERC4626Target3Deployer()) + address(new ERC4626Target3Deployer()), + address(new ERC4626Target4Deployer()) ) ); @@ -2116,14 +2361,67 @@ contract ERC4626FactoryMultiDeployTest is HyperdriveFactoryBaseTest { assertEq(dai.balanceOf(charlie), CONTRIBUTION); assertEq(dai.balanceOf(address(pool1)), 0); + bytes memory extraData = abi.encode(address(pool1)); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + APR, + APR, + 0, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + APR, + APR, + 1, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + APR, + APR, + 2, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + APR, + APR, + 3, + bytes32(uint256(0xdeadbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdeadbeef)), + deployerCoordinator, + config, + extraData, + APR, + APR, + 4, + bytes32(uint256(0xdeadbabe)) + ); IHyperdrive hyperdrive1 = factory.deployAndInitialize( + bytes32(uint256(0xdeadbeef)), deployerCoordinator, config, - abi.encode(address(pool1), new address[](0)), + extraData, CONTRIBUTION, APR, APR, - new bytes(0) + new bytes(0), + bytes32(uint256(0xdeadbabe)) ); assertEq(dai.balanceOf(charlie), 0); @@ -2146,7 +2444,7 @@ contract ERC4626FactoryMultiDeployTest is HyperdriveFactoryBaseTest { CONTRIBUTION, APR, config.minimumShareReserves, - abi.encode(address(pool1), new address[](0)), + extraData, 0 ); @@ -2163,14 +2461,67 @@ contract ERC4626FactoryMultiDeployTest is HyperdriveFactoryBaseTest { dai.approve(address(factory), CONTRIBUTION); + extraData = abi.encode(address(pool2)); + factory.deployTarget( + bytes32(uint256(0xdead)), + deployerCoordinator1, + config, + extraData, + APR, + APR, + 0, + bytes32(uint256(0xbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdead)), + deployerCoordinator1, + config, + extraData, + APR, + APR, + 1, + bytes32(uint256(0xbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdead)), + deployerCoordinator1, + config, + extraData, + APR, + APR, + 2, + bytes32(uint256(0xbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdead)), + deployerCoordinator1, + config, + extraData, + APR, + APR, + 3, + bytes32(uint256(0xbabe)) + ); + factory.deployTarget( + bytes32(uint256(0xdead)), + deployerCoordinator1, + config, + extraData, + APR, + APR, + 4, + bytes32(uint256(0xbabe)) + ); IHyperdrive hyperdrive2 = factory.deployAndInitialize( + bytes32(uint256(0xdead)), deployerCoordinator1, config, - abi.encode(address(pool2), new address[](0)), + extraData, CONTRIBUTION, APR, APR, - new bytes(0) + new bytes(0), + bytes32(uint256(0xbabe)) ); assertEq(dai.balanceOf(charlie), 0); @@ -2193,7 +2544,7 @@ contract ERC4626FactoryMultiDeployTest is HyperdriveFactoryBaseTest { CONTRIBUTION, APR, config.minimumShareReserves, - abi.encode(address(pool2), new address[](0)), + extraData, 0 ); @@ -2217,14 +2568,67 @@ contract ERC4626FactoryMultiDeployTest is HyperdriveFactoryBaseTest { assertEq(dai.balanceOf(dan), CONTRIBUTION); assertEq(dai.balanceOf(address(pool2)), CONTRIBUTION); // From Charlie + extraData = abi.encode(address(pool2)); + factory.deployTarget( + bytes32(uint256(0xbeef)), + deployerCoordinator, + config, + extraData, + APR, + APR, + 0, + bytes32(uint256(0xdead)) + ); + factory.deployTarget( + bytes32(uint256(0xbeef)), + deployerCoordinator, + config, + extraData, + APR, + APR, + 1, + bytes32(uint256(0xdead)) + ); + factory.deployTarget( + bytes32(uint256(0xbeef)), + deployerCoordinator, + config, + extraData, + APR, + APR, + 2, + bytes32(uint256(0xdead)) + ); + factory.deployTarget( + bytes32(uint256(0xbeef)), + deployerCoordinator, + config, + extraData, + APR, + APR, + 3, + bytes32(uint256(0xdead)) + ); + factory.deployTarget( + bytes32(uint256(0xbeef)), + deployerCoordinator, + config, + extraData, + APR, + APR, + 4, + bytes32(uint256(0xdead)) + ); IHyperdrive hyperdrive3 = factory.deployAndInitialize( + bytes32(uint256(0xbeef)), deployerCoordinator, config, - abi.encode(address(pool2), new address[](0)), + extraData, CONTRIBUTION, APR, APR, - new bytes(0) + new bytes(0), + bytes32(uint256(0xdead)) ); assertEq(dai.balanceOf(dan), 0); @@ -2247,7 +2651,7 @@ contract ERC4626FactoryMultiDeployTest is HyperdriveFactoryBaseTest { CONTRIBUTION, APR, config.minimumShareReserves, - abi.encode(address(pool2), new address[](0)), + extraData, 0 ); @@ -2390,7 +2794,8 @@ contract DeployerCoordinatorGetterTest is HyperdriveTest { address(new ERC4626Target0Deployer()), address(new ERC4626Target1Deployer()), address(new ERC4626Target2Deployer()), - address(new ERC4626Target3Deployer()) + address(new ERC4626Target3Deployer()), + address(new ERC4626Target4Deployer()) ) ); @@ -2424,7 +2829,8 @@ contract DeployerCoordinatorGetterTest is HyperdriveTest { address(new ERC4626Target0Deployer()), address(new ERC4626Target1Deployer()), address(new ERC4626Target2Deployer()), - address(new ERC4626Target3Deployer()) + address(new ERC4626Target3Deployer()), + address(new ERC4626Target4Deployer()) ) ); @@ -2472,7 +2878,8 @@ contract DeployerCoordinatorGetterTest is HyperdriveTest { address(new ERC4626Target0Deployer()), address(new ERC4626Target1Deployer()), address(new ERC4626Target2Deployer()), - address(new ERC4626Target3Deployer()) + address(new ERC4626Target3Deployer()), + address(new ERC4626Target4Deployer()) ) ); diff --git a/test/integrations/hyperdrive/IntraCheckpointNettingTest.t.sol b/test/integrations/hyperdrive/IntraCheckpointNettingTest.t.sol index 9b454e876..e7e90b2b9 100644 --- a/test/integrations/hyperdrive/IntraCheckpointNettingTest.t.sol +++ b/test/integrations/hyperdrive/IntraCheckpointNettingTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { FixedPointMath } from "contracts/src/libraries/FixedPointMath.sol"; import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; diff --git a/test/integrations/hyperdrive/LPWithdrawalTest.t.sol b/test/integrations/hyperdrive/LPWithdrawalTest.t.sol index 7afcdec85..5aba41624 100644 --- a/test/integrations/hyperdrive/LPWithdrawalTest.t.sol +++ b/test/integrations/hyperdrive/LPWithdrawalTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { stdError } from "forge-std/StdError.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; @@ -781,6 +781,7 @@ contract LPWithdrawalTest is HyperdriveTest { ); } vm.revertTo(snapshotId); + snapshotId = vm.snapshot(); { uint256 longBasePaid = 4107; //0.001000000000004107 uint256 shortAmount = 49890332890205; //0.001049890332890205 @@ -792,6 +793,7 @@ contract LPWithdrawalTest is HyperdriveTest { ); } vm.revertTo(snapshotId); + snapshotId = vm.snapshot(); { uint256 longBasePaid = 47622440666488; uint256 shortAmount = 99991360285271; @@ -804,6 +806,7 @@ contract LPWithdrawalTest is HyperdriveTest { } // This edge case caused the present value to become negative. vm.revertTo(snapshotId); + snapshotId = vm.snapshot(); { uint256 longBasePaid = 9359120568038014548496614986532107423060977700952779944229929110473; uint256 shortAmount = 6363481524035208645046457754761807956049413076188199707925459155397040; diff --git a/test/integrations/hyperdrive/NegativeInterestLongFeeTest.t.sol b/test/integrations/hyperdrive/NegativeInterestLongFeeTest.t.sol index e8de0ff24..9d915aa54 100644 --- a/test/integrations/hyperdrive/NegativeInterestLongFeeTest.t.sol +++ b/test/integrations/hyperdrive/NegativeInterestLongFeeTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; diff --git a/test/integrations/hyperdrive/NegativeInterestShortFeeTest.t.sol b/test/integrations/hyperdrive/NegativeInterestShortFeeTest.t.sol index dabc85a32..5c7a54a26 100644 --- a/test/integrations/hyperdrive/NegativeInterestShortFeeTest.t.sol +++ b/test/integrations/hyperdrive/NegativeInterestShortFeeTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; diff --git a/test/integrations/hyperdrive/NonstandardDecimals.sol b/test/integrations/hyperdrive/NonstandardDecimals.sol index 5e8466a6a..0e1c7fdd6 100644 --- a/test/integrations/hyperdrive/NonstandardDecimals.sol +++ b/test/integrations/hyperdrive/NonstandardDecimals.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { AssetId } from "contracts/src/libraries/AssetId.sol"; import { FixedPointMath } from "contracts/src/libraries/FixedPointMath.sol"; diff --git a/test/integrations/hyperdrive/PresentValueTest.t.sol b/test/integrations/hyperdrive/PresentValueTest.t.sol index 853f990a0..194b73686 100644 --- a/test/integrations/hyperdrive/PresentValueTest.t.sol +++ b/test/integrations/hyperdrive/PresentValueTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { console2 as console } from "forge-std/console2.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; diff --git a/test/integrations/hyperdrive/ReentrancyTest.t.sol b/test/integrations/hyperdrive/ReentrancyTest.t.sol index e32b77ab9..47fd80f5f 100644 --- a/test/integrations/hyperdrive/ReentrancyTest.t.sol +++ b/test/integrations/hyperdrive/ReentrancyTest.t.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { stdError } from "forge-std/StdError.sol"; +import { ReentrancyGuard } from "openzeppelin/utils/ReentrancyGuard.sol"; import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; import { ERC20Mintable } from "contracts/test/ERC20Mintable.sol"; @@ -30,7 +31,14 @@ contract ReentrancyTester { function _testReentrancy() internal { (bool success, bytes memory data) = _target.call(_data); - if (!success && data.eq("REENTRANCY".toError())) { + if ( + !success && + data.eq( + abi.encodeWithSelector( + ReentrancyGuard.ReentrancyGuardReentrantCall.selector + ) + ) + ) { isSuccess = true; } } diff --git a/test/integrations/hyperdrive/RoundTripTest.t.sol b/test/integrations/hyperdrive/RoundTripTest.t.sol index dc7420003..6fca1764c 100644 --- a/test/integrations/hyperdrive/RoundTripTest.t.sol +++ b/test/integrations/hyperdrive/RoundTripTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { stdError } from "forge-std/StdError.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; diff --git a/test/integrations/hyperdrive/SandwichTest.t.sol b/test/integrations/hyperdrive/SandwichTest.t.sol index d47ecfbb5..b7fd00c28 100644 --- a/test/integrations/hyperdrive/SandwichTest.t.sol +++ b/test/integrations/hyperdrive/SandwichTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { AssetId } from "contracts/src/libraries/AssetId.sol"; import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; diff --git a/test/integrations/hyperdrive/VariableInterestLongTest.t.sol b/test/integrations/hyperdrive/VariableInterestLongTest.t.sol index b0c312c98..42c258906 100644 --- a/test/integrations/hyperdrive/VariableInterestLongTest.t.sol +++ b/test/integrations/hyperdrive/VariableInterestLongTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { FixedPointMath } from "contracts/src/libraries/FixedPointMath.sol"; import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; diff --git a/test/integrations/hyperdrive/VariableInterestShortTest.t.sol b/test/integrations/hyperdrive/VariableInterestShortTest.t.sol index 4f6368bc3..82d4a82b5 100644 --- a/test/integrations/hyperdrive/VariableInterestShortTest.t.sol +++ b/test/integrations/hyperdrive/VariableInterestShortTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { FixedPointMath } from "contracts/src/libraries/FixedPointMath.sol"; import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; diff --git a/test/integrations/hyperdrive/ZombieInterestTest.t.sol b/test/integrations/hyperdrive/ZombieInterestTest.t.sol index 6d85e9f40..53f3a9d04 100644 --- a/test/integrations/hyperdrive/ZombieInterestTest.t.sol +++ b/test/integrations/hyperdrive/ZombieInterestTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { AssetId } from "contracts/src/libraries/AssetId.sol"; import { FixedPointMath } from "contracts/src/libraries/FixedPointMath.sol"; diff --git a/test/units/ForceRevertDelegatecall.t.sol b/test/units/ForceRevertDelegatecall.t.sol index 2bcd1aafe..d4c056d43 100644 --- a/test/units/ForceRevertDelegatecall.t.sol +++ b/test/units/ForceRevertDelegatecall.t.sol @@ -53,6 +53,7 @@ contract DummyHyperdrive is Hyperdrive, MockHyperdriveBase { address(new DummyProvider()), address(0), address(0), + address(0), address(0) ) {} diff --git a/test/units/MultiToken.t.sol b/test/units/MultiToken.t.sol index f80c84e12..5068e84f5 100644 --- a/test/units/MultiToken.t.sol +++ b/test/units/MultiToken.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; import { AssetId } from "contracts/src/libraries/AssetId.sol"; diff --git a/test/units/hyperdrive/AddLiquidityTest.t.sol b/test/units/hyperdrive/AddLiquidityTest.t.sol index 017ce4b41..7c286f807 100644 --- a/test/units/hyperdrive/AddLiquidityTest.t.sol +++ b/test/units/hyperdrive/AddLiquidityTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { VmSafe } from "forge-std/Vm.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; diff --git a/test/units/hyperdrive/CheckpointTest.t.sol b/test/units/hyperdrive/CheckpointTest.t.sol index cbfdee7b1..f1001b930 100644 --- a/test/units/hyperdrive/CheckpointTest.t.sol +++ b/test/units/hyperdrive/CheckpointTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; import { HyperdriveTest, HyperdriveUtils, MockHyperdrive, IHyperdrive } from "test/utils/HyperdriveTest.sol"; diff --git a/test/units/hyperdrive/CloseLongTest.t.sol b/test/units/hyperdrive/CloseLongTest.t.sol index 15cfee704..775d7c029 100644 --- a/test/units/hyperdrive/CloseLongTest.t.sol +++ b/test/units/hyperdrive/CloseLongTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { stdError } from "forge-std/StdError.sol"; import { VmSafe } from "forge-std/Vm.sol"; diff --git a/test/units/hyperdrive/CloseShortTest.t.sol b/test/units/hyperdrive/CloseShortTest.t.sol index ee513e68f..cc31b3534 100644 --- a/test/units/hyperdrive/CloseShortTest.t.sol +++ b/test/units/hyperdrive/CloseShortTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { stdError } from "forge-std/StdError.sol"; import { VmSafe } from "forge-std/Vm.sol"; diff --git a/test/units/hyperdrive/DataProvider.t.sol b/test/units/hyperdrive/DataProvider.t.sol index daa53e178..de0644b00 100644 --- a/test/units/hyperdrive/DataProvider.t.sol +++ b/test/units/hyperdrive/DataProvider.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { HyperdriveTest } from "test/utils/HyperdriveTest.sol"; diff --git a/test/units/hyperdrive/ExtremeInputs.t.sol b/test/units/hyperdrive/ExtremeInputs.t.sol index eb6705feb..b250831b2 100644 --- a/test/units/hyperdrive/ExtremeInputs.t.sol +++ b/test/units/hyperdrive/ExtremeInputs.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; import { FixedPointMath } from "contracts/src/libraries/FixedPointMath.sol"; diff --git a/test/units/hyperdrive/FeeTest.t.sol b/test/units/hyperdrive/FeeTest.t.sol index 443a10729..2624443db 100644 --- a/test/units/hyperdrive/FeeTest.t.sol +++ b/test/units/hyperdrive/FeeTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { stdError } from "forge-std/StdError.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; diff --git a/test/units/hyperdrive/InitializeTest.t.sol b/test/units/hyperdrive/InitializeTest.t.sol index 4b29417a1..8e93aa6a4 100644 --- a/test/units/hyperdrive/InitializeTest.t.sol +++ b/test/units/hyperdrive/InitializeTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { VmSafe } from "forge-std/Vm.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; diff --git a/test/units/hyperdrive/OpenLongTest.t.sol b/test/units/hyperdrive/OpenLongTest.t.sol index 0557b0cf7..2f05ec391 100644 --- a/test/units/hyperdrive/OpenLongTest.t.sol +++ b/test/units/hyperdrive/OpenLongTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { stdError } from "forge-std/StdError.sol"; import { VmSafe } from "forge-std/Vm.sol"; diff --git a/test/units/hyperdrive/OpenShortTest.t.sol b/test/units/hyperdrive/OpenShortTest.t.sol index 121367ca5..bbcbdd8a6 100644 --- a/test/units/hyperdrive/OpenShortTest.t.sol +++ b/test/units/hyperdrive/OpenShortTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { stdError } from "forge-std/StdError.sol"; import { VmSafe } from "forge-std/Vm.sol"; diff --git a/test/units/hyperdrive/RedeemWithdrawalSharesTest.t.sol b/test/units/hyperdrive/RedeemWithdrawalSharesTest.t.sol index 23be76f12..fbfd7c607 100644 --- a/test/units/hyperdrive/RedeemWithdrawalSharesTest.t.sol +++ b/test/units/hyperdrive/RedeemWithdrawalSharesTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { VmSafe } from "forge-std/Vm.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; diff --git a/test/units/hyperdrive/RemoveLiquidityTest.t.sol b/test/units/hyperdrive/RemoveLiquidityTest.t.sol index 9265d08b0..3e8bad474 100644 --- a/test/units/hyperdrive/RemoveLiquidityTest.t.sol +++ b/test/units/hyperdrive/RemoveLiquidityTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { stdError } from "forge-std/StdError.sol"; import { VmSafe } from "forge-std/Vm.sol"; diff --git a/test/units/hyperdrive/UpdateLiquidityTest.t.sol b/test/units/hyperdrive/UpdateLiquidityTest.t.sol index bf745a1ce..e67fa83d1 100644 --- a/test/units/hyperdrive/UpdateLiquidityTest.t.sol +++ b/test/units/hyperdrive/UpdateLiquidityTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; diff --git a/test/units/libraries/AssetId.t.sol b/test/units/libraries/AssetId.t.sol index 298c7e003..51f87901f 100644 --- a/test/units/libraries/AssetId.t.sol +++ b/test/units/libraries/AssetId.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; import { AssetId } from "contracts/src/libraries/AssetId.sol"; diff --git a/test/units/libraries/FixedPointMath.t.sol b/test/units/libraries/FixedPointMath.t.sol index ecb1a3d9a..46f961b4c 100644 --- a/test/units/libraries/FixedPointMath.t.sol +++ b/test/units/libraries/FixedPointMath.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { stdError, Test } from "forge-std/Test.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; @@ -206,6 +206,10 @@ contract FixedPointMathTest is Test { function test_updateWeightedAverage() public { // NOTE: Coverage only works if I initialize the fixture in the test function MockFixedPointMath mockFixedPointMath = new MockFixedPointMath(); + assertEq( + mockFixedPointMath.updateWeightedAverage(2e18, 1e18, 3e18, 0, true), + 2e18 + ); assertEq( mockFixedPointMath.updateWeightedAverage( 1e18, diff --git a/test/units/libraries/HyperdriveMath.t.sol b/test/units/libraries/HyperdriveMath.t.sol index 729abfe1d..b7888bf03 100644 --- a/test/units/libraries/HyperdriveMath.t.sol +++ b/test/units/libraries/HyperdriveMath.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; diff --git a/test/units/libraries/HyperdriveUtilsTest.t.sol b/test/units/libraries/HyperdriveUtilsTest.t.sol index bbb448df7..7ff58de95 100644 --- a/test/units/libraries/HyperdriveUtilsTest.t.sol +++ b/test/units/libraries/HyperdriveUtilsTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; import { FixedPointMath } from "contracts/src/libraries/FixedPointMath.sol"; diff --git a/test/units/libraries/LPMath.t.sol b/test/units/libraries/LPMath.t.sol index 5caa57822..099895660 100644 --- a/test/units/libraries/LPMath.t.sol +++ b/test/units/libraries/LPMath.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; import { LPMath } from "contracts/src/libraries/LPMath.sol"; diff --git a/test/units/libraries/YieldSpaceMath.t.sol b/test/units/libraries/YieldSpaceMath.t.sol index d6a11191b..80bc67a75 100644 --- a/test/units/libraries/YieldSpaceMath.t.sol +++ b/test/units/libraries/YieldSpaceMath.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { Test } from "forge-std/Test.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; diff --git a/test/utils/BaseTest.sol b/test/utils/BaseTest.sol index a1ef55eb2..a79c7ffed 100644 --- a/test/utils/BaseTest.sol +++ b/test/utils/BaseTest.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { console2 } from "forge-std/console2.sol"; import { Test } from "forge-std/Test.sol"; diff --git a/test/utils/CombinatorialTest.sol b/test/utils/CombinatorialTest.sol index eb9ff7316..0bbd5bd64 100644 --- a/test/utils/CombinatorialTest.sol +++ b/test/utils/CombinatorialTest.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { BaseTest } from "./BaseTest.sol"; import { Lib as lib } from "./Lib.sol"; diff --git a/test/utils/Constants.sol b/test/utils/Constants.sol index 2338cf4b6..6004a9b9b 100644 --- a/test/utils/Constants.sol +++ b/test/utils/Constants.sol @@ -1,4 +1,4 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; address constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; diff --git a/test/utils/HyperdriveTest.sol b/test/utils/HyperdriveTest.sol index d89f73e60..a04d4d163 100644 --- a/test/utils/HyperdriveTest.sol +++ b/test/utils/HyperdriveTest.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { VmSafe } from "forge-std/Vm.sol"; import { HyperdriveFactory } from "contracts/src/factory/HyperdriveFactory.sol"; diff --git a/test/utils/HyperdriveUtils.sol b/test/utils/HyperdriveUtils.sol index ab0e4b340..323c8b7ae 100644 --- a/test/utils/HyperdriveUtils.sol +++ b/test/utils/HyperdriveUtils.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; import { AssetId } from "contracts/src/libraries/AssetId.sol"; diff --git a/test/utils/Lib.sol b/test/utils/Lib.sol index 0a6d67417..d8e252560 100644 --- a/test/utils/Lib.sol +++ b/test/utils/Lib.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; +pragma solidity 0.8.20; import { console2 } from "forge-std/console2.sol"; import { stdMath } from "forge-std/StdMath.sol";