From b9e322551b3f9e6c7bf3b210401a1641e675b0d4 Mon Sep 17 00:00:00 2001 From: Alex Towle Date: Sat, 20 Jan 2024 09:44:52 -0600 Subject: [PATCH 1/5] Started the factory cleanup --- contracts/src/factory/HyperdriveFactory.sol | 433 +++++++-- contracts/src/interfaces/IHyperdrive.sol | 11 +- .../factory/HyperdriveFactory.t.sol | 835 ++++++++++++++++-- test/utils/HyperdriveUtils.sol | 11 +- 4 files changed, 1165 insertions(+), 125 deletions(-) diff --git a/contracts/src/factory/HyperdriveFactory.sol b/contracts/src/factory/HyperdriveFactory.sol index 1896cbd82..5fc9cc5ba 100644 --- a/contracts/src/factory/HyperdriveFactory.sol +++ b/contracts/src/factory/HyperdriveFactory.sol @@ -18,32 +18,68 @@ contract HyperdriveFactory { using FixedPointMath for uint256; using SafeTransferLib for ERC20; + /// @notice Emitted when new instances are deployed. + event Deployed( + uint256 indexed version, + address hyperdrive, + IHyperdrive.PoolDeployConfig config, + bytes extraData + ); + + /// @notice Emitted when the default pausers are updated. + event DefaultPausersUpdated(address[] newDefaultPausers); + + /// @notice Emitted when the fee collector is updated. + event FeeCollectorUpdated(address newFeeCollector); + /// @notice Emitted when governance is transferred. - event GovernanceUpdated(address indexed governance); + event GovernanceUpdated(address governance); - /// @notice Emitted when the Hyperdrive implementation is updated. - event ImplementationUpdated(address indexed newDeployer); + /// @notice Emitted when a new Hyperdrive deployer is added. + event HyperdriveDeployerAdded(address hyperdriveDeployer); + + /// @notice Emitted when a Hyperdrive deployer is remove. + event HyperdriveDeployerRemoved(address hyperdriveDeployer); /// @notice Emitted when the Hyperdrive governance address is updated. - event HyperdriveGovernanceUpdated(address indexed hyperdriveGovernance); + event HyperdriveGovernanceUpdated(address hyperdriveGovernance); - /// @notice Emitted when the fee collector is updated. - event FeeCollectorUpdated(address indexed newFeeCollector); + /// @notice Emitted when the Hyperdrive implementation is updated. + event ImplementationUpdated(address newDeployer); /// @notice Emitted when the linker factory is updated. - event LinkerFactoryUpdated(address indexed newLinkerFactory); + event LinkerFactoryUpdated(address newLinkerFactory); /// @notice Emitted when the linker code hash is updated. - event LinkerCodeHashUpdated(bytes32 indexed newLinkerCodeHash); + event LinkerCodeHashUpdated(bytes32 newLinkerCodeHash); - /// @notice The event that is emitted when new instances are deployed. - event Deployed( - uint256 indexed version, - address hyperdrive, - IHyperdrive.PoolDeployConfig config, - bytes extraData + /// @notice Emitted when the checkpoint duration resolution is updated. + event CheckpointDurationResolutionUpdated( + uint256 newCheckpointDurationResolution ); + /// @notice Emitted when the maximum checkpoint duration is updated. + event MaxCheckpointDurationUpdated(uint256 newMaxCheckpointDuration); + + /// @notice Emitted when the minimum checkpoint duration is updated. + event MinCheckpointDurationUpdated(uint256 newMinCheckpointDuration); + + /// @notice Emitted when the maximum position duration is updated. + event MaxPositionDurationUpdated(uint256 newMaxPositionDuration); + + /// @notice Emitted when the minimum position duration is updated. + event MinPositionDurationUpdated(uint256 newMinPositionDuration); + + /// @notice Emitted when the max fees are updated. + event MaxFeesUpdated(IHyperdrive.Fees newMaxFees); + + /// @notice Emitted when the min fees are updated. + event MinFeesUpdated(IHyperdrive.Fees newMinFees); + + /// @notice The resolution for the checkpoint duration. Every checkpoint + /// duration must be a multiple of this resolution. + uint256 public checkpointDurationResolution; + /// @notice The governance address that updates the factory's configuration. address public governance; @@ -63,25 +99,32 @@ contract HyperdriveFactory { /// @notice The linker code hash used when new instances are deployed. bytes32 public linkerCodeHash; - /// @notice The fee parameters used when new instances are deployed. - IHyperdrive.Fees public fees; - /// @notice The fee collector used when new instances are deployed. address public feeCollector; - /// @dev The maximum curve fee that can be used as a factory default. - uint256 internal immutable maxCurveFee; + /// @notice The minimum checkpoint duration that can be used by new + /// deployments. + uint256 public minCheckpointDuration; + + /// @notice The maximum checkpoint duration that can be used by new + /// deployments. + uint256 public maxCheckpointDuration; - /// @dev The maximum flat fee that can be used as a factory default. - uint256 internal immutable maxFlatFee; + /// @notice The minimum position duration that can be used by new + /// deployments. + uint256 public minPositionDuration; - /// @dev The maximum governance LP fee that can be used as a factory default. - uint256 internal immutable maxGovernanceLPFee; + /// @notice The maximum position duration that can be used by new + /// deployments. + uint256 public maxPositionDuration; - /// @dev The maximum governance zombie fee that can be used as a factory default. - uint256 internal immutable maxGovernanceZombieFee; + /// @notice The minimum fee parameters that can be used by new deployments. + IHyperdrive.Fees internal _minFees; - /// @dev The defaultPausers used when new instances are deployed. + /// @notice The maximum fee parameters that can be used by new deployments. + IHyperdrive.Fees internal _maxFees; + + /// @notice The defaultPausers used when new instances are deployed. address[] internal _defaultPausers; struct FactoryConfig { @@ -93,9 +136,23 @@ contract HyperdriveFactory { address[] defaultPausers; /// @dev The recipient of governance fees from new deployments. address feeCollector; - /// @dev The fees each deployed instance will have. - IHyperdrive.Fees fees; - /// @dev The upper bounds on the fee parameters that governance can set. + /// @dev The resolution for the checkpoint duration. + uint256 checkpointDurationResolution; + /// @dev The minimum checkpoint duration that can be used in new + /// deployments. + uint256 minCheckpointDuration; + /// @dev The maximum checkpoint duration that can be used in new + /// deployments. + uint256 maxCheckpointDuration; + /// @dev The minimum position duration that can be used in new + /// deployments. + uint256 minPositionDuration; + /// @dev The maximum position duration that can be used in new + /// deployments. + uint256 maxPositionDuration; + /// @dev The lower bound on the fees that can be used in new deployments. + IHyperdrive.Fees minFees; + /// @dev The upper bound on the fees that can be used in new deployments. IHyperdrive.Fees maxFees; /// @dev The address of the linker factory. address linkerFactory; @@ -119,30 +176,85 @@ contract HyperdriveFactory { /// @notice Initializes the factory. /// @param _factoryConfig Configuration of the Hyperdrive Factory. constructor(FactoryConfig memory _factoryConfig) { - // Initialize fee parameters to ensure that max fees are less than - // 100% and that the initial fee configuration satisfies the max fee - // constraint. - maxCurveFee = _factoryConfig.maxFees.curve; - maxFlatFee = _factoryConfig.maxFees.flat; - maxGovernanceLPFee = _factoryConfig.maxFees.governanceLP; - maxGovernanceZombieFee = _factoryConfig.maxFees.governanceZombie; + // Ensure that the minimum checkpoint duration is greater than or equal + // to the checkpoint duration resolution and is a multiple of the + // checkpoint duration resolution. + if ( + _factoryConfig.minCheckpointDuration < + _factoryConfig.checkpointDurationResolution || + _factoryConfig.minCheckpointDuration % + _factoryConfig.checkpointDurationResolution != + 0 + ) { + revert IHyperdrive.InvalidMinCheckpointDuration(); + } + minCheckpointDuration = _factoryConfig.minCheckpointDuration; + + // Ensure that the maximum checkpoint duration is greater than or equal + // to the minimum checkpoint duration and is a multiple of the + // checkpoint duration resolution. + if ( + _factoryConfig.maxCheckpointDuration < + _factoryConfig.minCheckpointDuration || + _factoryConfig.maxCheckpointDuration % + _factoryConfig.checkpointDurationResolution != + 0 + ) { + revert IHyperdrive.InvalidMaxCheckpointDuration(); + } + maxCheckpointDuration = _factoryConfig.maxCheckpointDuration; + + // Ensure that the minimum position duration is greater than or equal + // to the maximum checkpoint duration and is a multiple of the + // checkpoint duration resolution. + if ( + _factoryConfig.minPositionDuration < + _factoryConfig.maxCheckpointDuration || + _factoryConfig.minPositionDuration % + _factoryConfig.checkpointDurationResolution != + 0 + ) { + revert IHyperdrive.InvalidMinPositionDuration(); + } + + // Ensure that the maximum position duration is greater than or equal + // to the minimum position duration and is a multiple of the checkpoint + // duration resolution. if ( - maxCurveFee > ONE || - maxFlatFee > ONE || - maxGovernanceLPFee > ONE || - maxGovernanceZombieFee > ONE + _factoryConfig.maxPositionDuration < + _factoryConfig.minPositionDuration || + _factoryConfig.maxPositionDuration % + _factoryConfig.checkpointDurationResolution != + 0 ) { - revert IHyperdrive.MaxFeeTooHigh(); + revert IHyperdrive.InvalidMaxPositionDuration(); } + + // Ensure that the max fees are each less than or equal to 100% and set + // the fees. + if ( + _factoryConfig.maxFees.curve > ONE || + _factoryConfig.maxFees.flat > ONE || + _factoryConfig.maxFees.governanceLP > ONE || + _factoryConfig.maxFees.governanceZombie > ONE + ) { + revert IHyperdrive.InvalidMaxFees(); + } + _maxFees = _factoryConfig.maxFees; + + // Ensure that the min fees are each less than or equal to the + // corresponding and parameter in the max fees and set the fees. if ( - _factoryConfig.fees.curve > maxCurveFee || - _factoryConfig.fees.flat > maxFlatFee || - _factoryConfig.fees.governanceLP > maxGovernanceLPFee || - _factoryConfig.fees.governanceZombie > maxGovernanceZombieFee + _factoryConfig.minFees.curve > _factoryConfig.maxFees.curve || + _factoryConfig.minFees.flat > _factoryConfig.maxFees.flat || + _factoryConfig.minFees.governanceLP > + _factoryConfig.maxFees.governanceLP || + _factoryConfig.minFees.governanceZombie > + _factoryConfig.maxFees.governanceZombie ) { - revert IHyperdrive.FeeTooHigh(); + revert IHyperdrive.InvalidMinFees(); } - fees = _factoryConfig.fees; + _minFees = _factoryConfig.minFees; // Initialize the other parameters. governance = _factoryConfig.governance; @@ -151,6 +263,8 @@ contract HyperdriveFactory { _defaultPausers = _factoryConfig.defaultPausers; linkerFactory = _factoryConfig.linkerFactory; linkerCodeHash = _factoryConfig.linkerCodeHash; + checkpointDurationResolution = _factoryConfig + .checkpointDurationResolution; } /// @dev Ensure that the sender is the governance address. @@ -180,7 +294,6 @@ contract HyperdriveFactory { function updateLinkerFactory( address _linkerFactory ) external onlyGovernance { - require(_linkerFactory != address(0)); linkerFactory = _linkerFactory; emit LinkerFactoryUpdated(_linkerFactory); } @@ -202,21 +315,162 @@ contract HyperdriveFactory { emit FeeCollectorUpdated(_feeCollector); } - /// @notice Allows governance to update the default fee schedule that will - /// be used in new deployments. - /// @param _fees The new defaults for the fee parameters. - function updateFees( - IHyperdrive.Fees calldata _fees + /// @notice Allows governance to change the checkpoint duration resolution. + /// @param _checkpointDurationResolution The new checkpoint duration + /// resolution. + function updateCheckpointDurationResolution( + uint256 _checkpointDurationResolution + ) external onlyGovernance { + // Ensure that the minimum checkpoint duration, maximum checkpoint + // duration, minimum position duration, and maximum position duration + // are all multiples of the checkpoint duration resolution. + if ( + minCheckpointDuration % _checkpointDurationResolution != 0 || + maxCheckpointDuration % _checkpointDurationResolution != 0 || + minPositionDuration % _checkpointDurationResolution != 0 || + maxPositionDuration % _checkpointDurationResolution != 0 + ) { + revert IHyperdrive.InvalidCheckpointDurationResolution(); + } + + // Update the checkpoint duration resolution and emit an event. + checkpointDurationResolution = _checkpointDurationResolution; + emit CheckpointDurationResolutionUpdated(_checkpointDurationResolution); + } + + /// @notice Allows governance to update the maximum checkpoint duration. + /// @param _maxCheckpointDuration The new maximum checkpoint duration. + function updateMaxCheckpointDuration( + uint256 _maxCheckpointDuration + ) external onlyGovernance { + // Ensure that the maximum checkpoint duration is greater than or equal + // to the minimum checkpoint duration and is a multiple of the + // checkpoint duration resolution. Also ensure that the maximum + // checkpoint duration is less than or equal to the minimum position + // duration. + if ( + _maxCheckpointDuration < minCheckpointDuration || + _maxCheckpointDuration % checkpointDurationResolution != 0 || + _maxCheckpointDuration > minPositionDuration + ) { + revert IHyperdrive.InvalidMaxCheckpointDuration(); + } + + // Update the maximum checkpoint duration and emit an event. + maxCheckpointDuration = _maxCheckpointDuration; + emit MaxCheckpointDurationUpdated(_maxCheckpointDuration); + } + + /// @notice Allows governance to update the minimum checkpoint duration. + /// @param _minCheckpointDuration The new minimum checkpoint duration. + function updateMinCheckpointDuration( + uint256 _minCheckpointDuration + ) external onlyGovernance { + // Ensure that the minimum checkpoint duration is greater than or equal + // to the checkpoint duration resolution and is a multiple of the + // checkpoint duration resolution. Also ensure that the minimum + // checkpoint duration is less than or equal to the maximum checkpoint + // duration. + if ( + _minCheckpointDuration < checkpointDurationResolution || + _minCheckpointDuration % checkpointDurationResolution != 0 || + _minCheckpointDuration > maxCheckpointDuration + ) { + revert IHyperdrive.InvalidMinCheckpointDuration(); + } + + // Update the minimum checkpoint duration and emit an event. + minCheckpointDuration = _minCheckpointDuration; + emit MinCheckpointDurationUpdated(_minCheckpointDuration); + } + + /// @notice Allows governance to update the maximum position duration. + /// @param _maxPositionDuration The new maximum position duration. + function updateMaxPositionDuration( + uint256 _maxPositionDuration + ) external onlyGovernance { + // Ensure that the maximum position duration is greater than or equal + // to the minimum position duration and is a multiple of the checkpoint + // duration resolution. + if ( + _maxPositionDuration < minPositionDuration || + _maxPositionDuration % checkpointDurationResolution != 0 + ) { + revert IHyperdrive.InvalidMaxPositionDuration(); + } + + // Update the maximum position duration and emit an event. + maxPositionDuration = _maxPositionDuration; + emit MaxPositionDurationUpdated(_maxPositionDuration); + } + + /// @notice Allows governance to update the minimum position duration. + /// @param _minPositionDuration The new minimum position duration. + function updateMinPositionDuration( + uint256 _minPositionDuration + ) external onlyGovernance { + // Ensure that the minimum position duration is greater than or equal + // to the maximum checkpoint duration and is a multiple of the + // checkpoint duration resolution. Also ensure that the minimum position + // duration is less than or equal to the maximum position duration. + if ( + _minPositionDuration < maxCheckpointDuration || + _minPositionDuration % checkpointDurationResolution != 0 || + _minPositionDuration > maxPositionDuration + ) { + revert IHyperdrive.InvalidMinPositionDuration(); + } + + // Update the minimum position duration and emit an event. + minPositionDuration = _minPositionDuration; + emit MinPositionDurationUpdated(_minPositionDuration); + } + + /// @notice Allows governance to update the maximum fee parameters. + /// @param __maxFees The new maximum fee parameters. + function updateMaxFees( + IHyperdrive.Fees calldata __maxFees ) external onlyGovernance { + // Ensure that the max fees are each less than or equal to 100% and that + // the max fees are each greater than or equal to the corresponding min + // fee. if ( - _fees.curve > maxCurveFee || - _fees.flat > maxFlatFee || - _fees.governanceLP > maxGovernanceLPFee || - _fees.governanceZombie > maxGovernanceZombieFee + __maxFees.curve > ONE || + __maxFees.flat > ONE || + __maxFees.governanceLP > ONE || + __maxFees.governanceZombie > ONE || + __maxFees.curve < _minFees.curve || + __maxFees.flat < _minFees.flat || + __maxFees.governanceLP < _minFees.governanceLP || + __maxFees.governanceZombie < _minFees.governanceZombie ) { - revert IHyperdrive.FeeTooHigh(); + revert IHyperdrive.InvalidMaxFees(); } - fees = _fees; + + // Update the max fees and emit an event. + _maxFees = __maxFees; + emit MaxFeesUpdated(__maxFees); + } + + /// @notice Allows governance to update the minimum fee parameters. + /// @param __minFees The new minimum fee parameters. + function updateMinFees( + IHyperdrive.Fees calldata __minFees + ) external onlyGovernance { + // Ensure that the min fees are each less than or the corresponding max + // fee. + if ( + __minFees.curve > _maxFees.curve || + __minFees.flat > _maxFees.flat || + __minFees.governanceLP < _maxFees.governanceLP || + __minFees.governanceZombie < _maxFees.governanceZombie + ) { + revert IHyperdrive.InvalidMinFees(); + } + + // Update the max fees and emit an event. + _minFees = __minFees; + emit MinFeesUpdated(__minFees); } /// @notice Allows governance to change the default pausers. @@ -224,8 +478,8 @@ contract HyperdriveFactory { function updateDefaultPausers( address[] calldata _defaultPausers_ ) external onlyGovernance { - // Update the list of default pausers. _defaultPausers = _defaultPausers_; + emit DefaultPausersUpdated(_defaultPausers_); } /// @notice Allows governance to add a new hyperdrive deployer. @@ -238,6 +492,7 @@ contract HyperdriveFactory { } isHyperdriveDeployer[_hyperdriveDeployer] = true; _hyperdriveDeployers.push(_hyperdriveDeployer); + emit HyperdriveDeployerAdded(_hyperdriveDeployer); } /// @notice Allows governance to remove an existing hyperdrive deployer. @@ -258,6 +513,7 @@ contract HyperdriveFactory { _hyperdriveDeployers.length - 1 ]; _hyperdriveDeployers.pop(); + emit HyperdriveDeployerRemoved(_hyperdriveDeployer); } /// @notice Deploys a Hyperdrive instance with the factory's configuration. @@ -285,23 +541,52 @@ contract HyperdriveFactory { revert IHyperdrive.InvalidDeployer(); } - // Deploy the data provider and the instance with the factory's - // configuration. Add this instance to the registry and emit an event - // with the deployment configuration. 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. + // 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 IHyperdrive.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.linkerFactory != address(0) || + _deployConfig.linkerCodeHash != bytes32(0) || + _deployConfig.feeCollector != address(0) || + _deployConfig.governance != address(0) + ) { + revert IHyperdrive.InvalidDeployConfig(); + } + + // 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.linkerFactory = linkerFactory; _deployConfig.linkerCodeHash = linkerCodeHash; _deployConfig.feeCollector = feeCollector; _deployConfig.governance = address(this); - _deployConfig.fees = fees; + + // Deploy the Hyperdrive instance with the specified Hyperdrive + // deployer. IHyperdrive hyperdrive = IHyperdrive( IHyperdriveDeployer(_hyperdriveDeployer).deploy( _deployConfig, _extraData ) ); + + // Add this instance to the registry and emit an event with the + // deployment configuration. isOfficial[address(hyperdrive)] = versionCounter; _deployConfig.governance = hyperdriveGovernance; emit Deployed( @@ -381,9 +666,21 @@ contract HyperdriveFactory { return hyperdrive; } + /// @notice Gets the max fees. + /// @return The max fees. + function maxFees() external view returns (IHyperdrive.Fees memory) { + return _maxFees; + } + + /// @notice Gets the min fees. + /// @return The min fees. + function minFees() external view returns (IHyperdrive.Fees memory) { + return _minFees; + } + /// @notice Gets the default pausers. /// @return The default pausers. - function getDefaultPausers() external view returns (address[] memory) { + function defaultPausers() external view returns (address[] memory) { return _defaultPausers; } diff --git a/contracts/src/interfaces/IHyperdrive.sol b/contracts/src/interfaces/IHyperdrive.sol index 9bf936019..505b3578b 100644 --- a/contracts/src/interfaces/IHyperdrive.sol +++ b/contracts/src/interfaces/IHyperdrive.sol @@ -307,10 +307,17 @@ interface IHyperdrive is IHyperdriveRead, IHyperdriveCore, IMultiToken { /// ### Factory ### /// ############### error Unauthorized(); + error InvalidCheckpointDurationResolution(); error InvalidContribution(); + error InvalidDeployConfig(); + error InvalidFees(); + error InvalidMaxFees(); + error InvalidMinFees(); + error InvalidMaxCheckpointDuration(); + error InvalidMinCheckpointDuration(); + error InvalidMaxPositionDuration(); + error InvalidMinPositionDuration(); error InvalidToken(); - error MaxFeeTooHigh(); - error FeeTooHigh(); error NonPayableInitialization(); error HyperdriveDeployerAlreadyAdded(); error HyperdriveDeployerNotAdded(); diff --git a/test/integrations/factory/HyperdriveFactory.t.sol b/test/integrations/factory/HyperdriveFactory.t.sol index 52ef4a9f9..fe8ddf396 100644 --- a/test/integrations/factory/HyperdriveFactory.t.sol +++ b/test/integrations/factory/HyperdriveFactory.t.sol @@ -14,7 +14,7 @@ import { MockERC4626, ERC20 } from "contracts/test/MockERC4626.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; import { IHyperdriveDeployer } from "contracts/src/interfaces/IHyperdriveDeployer.sol"; import { AssetId } from "contracts/src/libraries/AssetId.sol"; -import { FixedPointMath } from "contracts/src/libraries/FixedPointMath.sol"; +import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; import { ForwarderFactory } from "contracts/src/token/ForwarderFactory.sol"; import { ERC20Mintable } from "contracts/test/ERC20Mintable.sol"; import { MockHyperdriveDeployer, MockHyperdriveTargetDeployer } from "contracts/test/MockHyperdriveDeployer.sol"; @@ -22,82 +22,815 @@ import { HyperdriveTest } from "test/utils/HyperdriveTest.sol"; import { HyperdriveUtils } from "test/utils/HyperdriveUtils.sol"; contract HyperdriveFactoryTest is HyperdriveTest { - function test_hyperdrive_factory_fees() external { + HyperdriveFactory internal factory; + + event DefaultPausersUpdated(address[] newDefaultPausers); + + event FeeCollectorUpdated(address newFeeCollector); + + /// @notice Emitted when governance is transferred. + event GovernanceUpdated(address governance); + + /// @notice Emitted when a new Hyperdrive deployer is added. + event HyperdriveDeployerAdded(address hyperdriveDeployer); + + /// @notice Emitted when a Hyperdrive deployer is remove. + event HyperdriveDeployerRemoved(address hyperdriveDeployer); + + /// @notice Emitted when the Hyperdrive governance address is updated. + event HyperdriveGovernanceUpdated(address hyperdriveGovernance); + + /// @notice Emitted when the Hyperdrive implementation is updated. + event ImplementationUpdated(address newDeployer); + + /// @notice Emitted when the linker factory is updated. + event LinkerFactoryUpdated(address newLinkerFactory); + + /// @notice Emitted when the linker code hash is updated. + event LinkerCodeHashUpdated(bytes32 newLinkerCodeHash); + + /// @notice Emitted when the checkpoint duration resolution is updated. + event CheckpointDurationResolutionUpdated( + uint256 newCheckpointDurationResolution + ); + + /// @notice Emitted when the maximum checkpoint duration is updated. + event MaxCheckpointDurationUpdated(uint256 newMaxCheckpointDuration); + + /// @notice Emitted when the minimum checkpoint duration is updated. + event MinCheckpointDurationUpdated(uint256 newMinCheckpointDuration); + + /// @notice Emitted when the maximum position duration is updated. + event MaxPositionDurationUpdated(uint256 newMaxPositionDuration); + + /// @notice Emitted when the minimum position duration is updated. + event MinPositionDurationUpdated(uint256 newMinPositionDuration); + + /// @notice Emitted when the max fees are updated. + event MaxFeesUpdated(IHyperdrive.Fees newMaxFees); + + /// @notice Emitted when the min fees are updated. + event MinFeesUpdated(IHyperdrive.Fees newMinFees); + + function setUp() public override { + super.setUp(); + + // Deploy the factory. + address[] memory defaults = new address[](1); + defaults[0] = bob; + HyperdriveFactory.FactoryConfig memory config = HyperdriveFactory + .FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: celine, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees(0, 0, 0, 0), + maxFees: IHyperdrive.Fees(ONE, ONE, ONE, ONE), + linkerFactory: address(0xdeadbeef), + linkerCodeHash: bytes32(uint256(0xdeadbabe)) + }); + factory = new HyperdriveFactory(config); + } + + function test_constructor() external { address[] memory defaults = new address[](1); defaults[0] = bob; - HyperdriveFactory factory = new HyperdriveFactory( + + // Ensure that the factory can't be constructed with a minimum + // checkpoint duration less than the checkpoint duration resolution. + vm.expectRevert(IHyperdrive.InvalidMinCheckpointDuration.selector); + new HyperdriveFactory( HyperdriveFactory.FactoryConfig({ governance: alice, hyperdriveGovernance: bob, feeCollector: bob, defaultPausers: defaults, - fees: IHyperdrive.Fees(0, 0, 0, 0), - maxFees: IHyperdrive.Fees(0, 0, 0, 0), + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 30 minutes, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees(0, 0, 0, 0), + maxFees: IHyperdrive.Fees(ONE, ONE, ONE, ONE), linkerFactory: address(0), linkerCodeHash: bytes32(0) }) ); - assertEq(factory.governance(), alice); - vm.startPrank(alice); + // Ensure that the factory can't be constructed with a minimum + // checkpoint duration that isn't a multiple of the checkpoint duration + // resolution. + vm.expectRevert(IHyperdrive.InvalidMinCheckpointDuration.selector); + new HyperdriveFactory( + HyperdriveFactory.FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: bob, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 1.5 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees(0, 0, 0, 0), + maxFees: IHyperdrive.Fees(ONE, ONE, ONE, ONE), + linkerFactory: address(0), + linkerCodeHash: bytes32(0) + }) + ); - // Curve fee can not exceed maximum curve fee. - vm.expectRevert(IHyperdrive.FeeTooHigh.selector); - factory.updateFees(IHyperdrive.Fees(2e18, 0, 0, 0)); + // Ensure that the factory can't be constructed with a maximum + // checkpoint duration that is less than the minimum checkpoint + // duration. + vm.expectRevert(IHyperdrive.InvalidMaxCheckpointDuration.selector); + new HyperdriveFactory( + HyperdriveFactory.FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: bob, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 7 hours, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees(0, 0, 0, 0), + maxFees: IHyperdrive.Fees(ONE, ONE, ONE, ONE), + linkerFactory: address(0), + linkerCodeHash: bytes32(0) + }) + ); - // Flat fee can not exceed maximum flat fee. - vm.expectRevert(IHyperdrive.FeeTooHigh.selector); - factory.updateFees(IHyperdrive.Fees(0, 2e18, 0, 0)); + // Ensure that the factory can't be constructed with a maximum + // checkpoint duration that isn't a multiple of the checkpoint duration + // resolution. + vm.expectRevert(IHyperdrive.InvalidMaxCheckpointDuration.selector); + new HyperdriveFactory( + HyperdriveFactory.FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: bob, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 8.5 hours, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees(0, 0, 0, 0), + maxFees: IHyperdrive.Fees(ONE, ONE, ONE, ONE), + linkerFactory: address(0), + linkerCodeHash: bytes32(0) + }) + ); - // Governance LP fee can not exceed maximum governance LP fee. - vm.expectRevert(IHyperdrive.FeeTooHigh.selector); - factory.updateFees(IHyperdrive.Fees(0, 0, 2e18, 0)); + // Ensure that the factory can't be constructed with a minimum position + // duration that is less than the maximum checkpoint duration. + vm.expectRevert(IHyperdrive.InvalidMinPositionDuration.selector); + new HyperdriveFactory( + HyperdriveFactory.FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: bob, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 8 hours, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees(0, 0, 0, 0), + maxFees: IHyperdrive.Fees(ONE, ONE, ONE, ONE), + linkerFactory: address(0), + linkerCodeHash: bytes32(0) + }) + ); - // Governance Zombie fee can not exceed maximum governance zombie fee. - vm.expectRevert(IHyperdrive.FeeTooHigh.selector); - factory.updateFees(IHyperdrive.Fees(0, 0, 0, 2e18)); - } + // Ensure that the factory can't be constructed with a minimum + // position duration that isn't a multiple of the checkpoint duration + // resolution. + vm.expectRevert(IHyperdrive.InvalidMinPositionDuration.selector); + new HyperdriveFactory( + HyperdriveFactory.FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: bob, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days + 30 minutes, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees(0, 0, 0, 0), + maxFees: IHyperdrive.Fees(ONE, ONE, ONE, ONE), + linkerFactory: address(0), + linkerCodeHash: bytes32(0) + }) + ); - // Ensure that the maximum curve fee can not exceed 100%. - function test_hyperdrive_factory_max_fees() external { - address[] memory defaults = new address[](1); - defaults[0] = bob; - HyperdriveFactory.FactoryConfig memory config = HyperdriveFactory - .FactoryConfig({ + // Ensure that the factory can't be constructed with a maximum + // position duration that is less than the minimum position duration. + vm.expectRevert(IHyperdrive.InvalidMaxPositionDuration.selector); + new HyperdriveFactory( + HyperdriveFactory.FactoryConfig({ governance: alice, hyperdriveGovernance: bob, feeCollector: bob, defaultPausers: defaults, - fees: IHyperdrive.Fees(0, 0, 0, 0), - maxFees: IHyperdrive.Fees(0, 0, 0, 0), + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 6 days, + minFees: IHyperdrive.Fees(0, 0, 0, 0), + maxFees: IHyperdrive.Fees(ONE, ONE, ONE, ONE), + linkerFactory: address(0), + linkerCodeHash: bytes32(0) + }) + ); + + // Ensure that the factory can't be constructed with a maximum + // position duration that isn't a multiple of the checkpoint duration + // resolution. + vm.expectRevert(IHyperdrive.InvalidMaxPositionDuration.selector); + new HyperdriveFactory( + HyperdriveFactory.FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: bob, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days + 30 minutes, + minFees: IHyperdrive.Fees(0, 0, 0, 0), + maxFees: IHyperdrive.Fees(ONE, ONE, ONE, ONE), + linkerFactory: address(0), + linkerCodeHash: bytes32(0) + }) + ); + + // Ensure that the factory can't be constructed with a maximum + // curve fee greater than 1. + vm.expectRevert(IHyperdrive.InvalidMaxFees.selector); + new HyperdriveFactory( + HyperdriveFactory.FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: bob, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees(0, 0, 0, 0), + maxFees: IHyperdrive.Fees(2 * ONE, ONE, ONE, ONE), + linkerFactory: address(0), + linkerCodeHash: bytes32(0) + }) + ); + + // Ensure that the factory can't be constructed with a maximum + // flat fee greater than 1. + vm.expectRevert(IHyperdrive.InvalidMaxFees.selector); + new HyperdriveFactory( + HyperdriveFactory.FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: bob, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees(0, 0, 0, 0), + maxFees: IHyperdrive.Fees(ONE, 2 * ONE, ONE, ONE), + linkerFactory: address(0), + linkerCodeHash: bytes32(0) + }) + ); + + // Ensure that the factory can't be constructed with a maximum + // governance LP fee greater than 1. + vm.expectRevert(IHyperdrive.InvalidMaxFees.selector); + new HyperdriveFactory( + HyperdriveFactory.FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: bob, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees(0, 0, 0, 0), + maxFees: IHyperdrive.Fees(ONE, ONE, 2 * ONE, ONE), + linkerFactory: address(0), + linkerCodeHash: bytes32(0) + }) + ); + + // Ensure that the factory can't be constructed with a maximum + // governance zombie fee greater than 1. + vm.expectRevert(IHyperdrive.InvalidMaxFees.selector); + new HyperdriveFactory( + HyperdriveFactory.FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: bob, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees(0, 0, 0, 0), + maxFees: IHyperdrive.Fees(ONE, ONE, ONE, 2 * ONE), + linkerFactory: address(0), + linkerCodeHash: bytes32(0) + }) + ); + + // Ensure that the factory can't be constructed with a minimum + // curve fee greater than the maximum curve fee. + vm.expectRevert(IHyperdrive.InvalidMinFees.selector); + new HyperdriveFactory( + HyperdriveFactory.FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: bob, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees(ONE, 0, 0, 0), + maxFees: IHyperdrive.Fees(0, ONE, ONE, ONE), + linkerFactory: address(0), + linkerCodeHash: bytes32(0) + }) + ); + + // Ensure that the factory can't be constructed with a minimum + // flat fee greater than the maximum flat fee. + vm.expectRevert(IHyperdrive.InvalidMinFees.selector); + new HyperdriveFactory( + HyperdriveFactory.FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: bob, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees(0, ONE, 0, 0), + maxFees: IHyperdrive.Fees(ONE, 0, ONE, ONE), + linkerFactory: address(0), + linkerCodeHash: bytes32(0) + }) + ); + + // Ensure that the factory can't be constructed with a minimum + // governance LP fee greater than the maximum governance LP fee. + vm.expectRevert(IHyperdrive.InvalidMinFees.selector); + new HyperdriveFactory( + HyperdriveFactory.FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: bob, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees(0, 0, ONE, 0), + maxFees: IHyperdrive.Fees(ONE, ONE, 0, ONE), linkerFactory: address(0), linkerCodeHash: bytes32(0) + }) + ); + + // Ensure that the factory can't be constructed with a minimum + // governance zombie fee greater than the maximum governance zombie fee. + vm.expectRevert(IHyperdrive.InvalidMinFees.selector); + new HyperdriveFactory( + HyperdriveFactory.FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: bob, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees(0, 0, 0, ONE), + maxFees: IHyperdrive.Fees(ONE, ONE, ONE, 0), + linkerFactory: address(0), + linkerCodeHash: bytes32(0) + }) + ); + + // Ensure that the factory can be constructed with a valid configuration + // and that the factory's parameters are set correctly. + HyperdriveFactory.FactoryConfig memory config = HyperdriveFactory + .FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: celine, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees(0, 0, 0, 0), + maxFees: IHyperdrive.Fees(ONE, ONE, ONE, ONE), + linkerFactory: address(0xdeadbeef), + linkerCodeHash: bytes32(uint256(0xdeadbabe)) }); + factory = new HyperdriveFactory(config); + assertEq(factory.governance(), config.governance); + assertEq(factory.hyperdriveGovernance(), config.hyperdriveGovernance); + assertEq(factory.linkerFactory(), config.linkerFactory); + assertEq(factory.linkerCodeHash(), config.linkerCodeHash); + assertEq(factory.feeCollector(), config.feeCollector); + assertEq( + factory.checkpointDurationResolution(), + config.checkpointDurationResolution + ); + assertEq(factory.minCheckpointDuration(), config.minCheckpointDuration); + assertEq(factory.maxCheckpointDuration(), config.maxCheckpointDuration); + assertEq(factory.minPositionDuration(), config.minPositionDuration); + assertEq(factory.maxPositionDuration(), config.maxPositionDuration); + assertEq( + keccak256(abi.encode(factory.minFees())), + keccak256(abi.encode(config.minFees)) + ); + assertEq( + keccak256(abi.encode(factory.maxFees())), + keccak256(abi.encode(config.maxFees)) + ); + assertEq( + keccak256(abi.encode(factory.defaultPausers())), + keccak256(abi.encode(config.defaultPausers)) + ); + } + + function test_updateGovernance() external { + address newGovernance = address(0xdeadbeef); - // Ensure that the maximum curve fee can not exceed 100%. - vm.expectRevert(IHyperdrive.MaxFeeTooHigh.selector); - config.maxFees.curve = 2e18; - new HyperdriveFactory(config); - config.maxFees.curve = 0; - - // Ensure that the maximum flat fee can not exceed 100%. - vm.expectRevert(IHyperdrive.MaxFeeTooHigh.selector); - config.maxFees.flat = 2e18; - new HyperdriveFactory(config); - config.maxFees.flat = 0; - - // Ensure that the maximum governance LP fee can not exceed 100%. - vm.expectRevert(IHyperdrive.MaxFeeTooHigh.selector); - config.maxFees.governanceLP = 2e18; - new HyperdriveFactory(config); - config.maxFees.governanceLP = 0; - - // Ensure that the maximum governance zombie fee can not exceed 100%. - vm.expectRevert(IHyperdrive.MaxFeeTooHigh.selector); - config.maxFees.governanceZombie = 2e18; - new HyperdriveFactory(config); - config.maxFees.governanceZombie = 0; + // Ensure that governance can't be updated by someone other than + // the current governance. + vm.prank(bob); + vm.expectRevert(IHyperdrive.Unauthorized.selector); + factory.updateGovernance(newGovernance); + + // Ensure that governance was updated successfully and that the correct + // event was emitted. + vm.prank(factory.governance()); + vm.expectEmit(true, true, true, true); + emit GovernanceUpdated(newGovernance); + factory.updateGovernance(newGovernance); + assertEq(factory.governance(), newGovernance); } + + function test_updateHyperdriveGovernance() external { + address newHyperdriveGovernance = address(0xdeadbeef); + + // Ensure that hyperdrive governance can't be updated by someone other + // than the current governance. + vm.prank(bob); + vm.expectRevert(IHyperdrive.Unauthorized.selector); + factory.updateHyperdriveGovernance(newHyperdriveGovernance); + + // Ensure that hyperdrive governance was updated successfully and that + // the correct event was emitted. + vm.prank(factory.governance()); + vm.expectEmit(true, true, true, true); + emit HyperdriveGovernanceUpdated(newHyperdriveGovernance); + factory.updateHyperdriveGovernance(newHyperdriveGovernance); + assertEq(factory.hyperdriveGovernance(), newHyperdriveGovernance); + } + + function test_updateLinkerFactory() external { + address newLinkerFactory = address(0xdeadbeef); + + // Ensure that the linker factory can't be updated by someone other + // than the current governance. + vm.prank(bob); + vm.expectRevert(IHyperdrive.Unauthorized.selector); + factory.updateLinkerFactory(newLinkerFactory); + + // Ensure that the linker factory was updated successfully and that the + // correct event was emitted. + vm.prank(factory.governance()); + vm.expectEmit(true, true, true, true); + emit LinkerFactoryUpdated(newLinkerFactory); + factory.updateLinkerFactory(newLinkerFactory); + assertEq(factory.linkerFactory(), newLinkerFactory); + } + + function test_updateLinkerCodeHash() external { + bytes32 newLinkerCodeHash = bytes32(uint256(0xdeadbeef)); + + // Ensure that the linker code hash can't be updated by someone other + // than the current governance. + vm.prank(bob); + vm.expectRevert(IHyperdrive.Unauthorized.selector); + factory.updateLinkerCodeHash(newLinkerCodeHash); + + // Ensure that the linker code hash was updated successfully and that + // the correct event was emitted. + vm.prank(factory.governance()); + vm.expectEmit(true, true, true, true); + emit LinkerCodeHashUpdated(newLinkerCodeHash); + factory.updateLinkerCodeHash(newLinkerCodeHash); + assertEq(factory.linkerCodeHash(), newLinkerCodeHash); + } + + function test_updateFeeCollector() external { + address newFeeCollector = address(0xdeadbeef); + + // Ensure that the fee collector can't be updated by someone other than + // the current governance. + vm.prank(bob); + vm.expectRevert(IHyperdrive.Unauthorized.selector); + factory.updateFeeCollector(newFeeCollector); + + // Ensure that the fee collector was updated successfully and that the + // correct event was emitted. + vm.prank(factory.governance()); + vm.expectEmit(true, true, true, true); + emit FeeCollectorUpdated(newFeeCollector); + factory.updateFeeCollector(newFeeCollector); + assertEq(factory.feeCollector(), newFeeCollector); + } + + function test_updateCheckpointDurationResolution() external { + uint256 newCheckpointDurationResolution = 30 minutes; + + // Ensure that the checkpoint duration resolution can't be updated by + // someone other than the current governance. + vm.prank(bob); + vm.expectRevert(IHyperdrive.Unauthorized.selector); + factory.updateCheckpointDurationResolution( + newCheckpointDurationResolution + ); + + // Ensure that the checkpoint duration resolution can't be set to a + // value that doesn't divide the min checkpoint duration. + vm.prank(factory.governance()); + factory.updateMinCheckpointDuration(3 hours); + factory.updateMaxCheckpointDuration(4 hours); + factory.updateMinPositionDuration(4 hours); + factory.updateMaxPositionDuration(4 hours); + vm.expectRevert( + IHyperdrive.InvalidCheckpointDurationResolution.selector + ); + factory.updateCheckpointDurationResolution(2 hours); + + // Ensure that the checkpoint duration resolution can't be set to a + // value that doesn't divide the max checkpoint duration. + vm.prank(factory.governance()); + factory.updateMinCheckpointDuration(3 hours); + factory.updateMaxCheckpointDuration(4 hours); + factory.updateMinPositionDuration(6 hours); + factory.updateMaxPositionDuration(6 hours); + vm.expectRevert( + IHyperdrive.InvalidCheckpointDurationResolution.selector + ); + factory.updateCheckpointDurationResolution(3 hours); + + // Ensure that the checkpoint duration resolution can't be set to a + // value that doesn't divide the min position duration. + vm.prank(factory.governance()); + factory.updateMinCheckpointDuration(3 hours); + factory.updateMaxCheckpointDuration(3 hours); + factory.updateMinPositionDuration(4 hours); + factory.updateMaxPositionDuration(6 hours); + vm.expectRevert( + IHyperdrive.InvalidCheckpointDurationResolution.selector + ); + factory.updateCheckpointDurationResolution(3 hours); + + // Ensure that the checkpoint duration resolution can't be set to a + // value that doesn't divide the max position duration. + vm.prank(factory.governance()); + factory.updateMinCheckpointDuration(3 hours); + factory.updateMaxCheckpointDuration(3 hours); + factory.updateMinPositionDuration(3 hours); + factory.updateMaxPositionDuration(4 hours); + vm.expectRevert( + IHyperdrive.InvalidCheckpointDurationResolution.selector + ); + factory.updateCheckpointDurationResolution(3 hours); + + // Ensure that the fee collector was updated successfully and that the + // correct event was emitted. + vm.prank(factory.governance()); + factory.updateMinCheckpointDuration(8 hours); + factory.updateMaxCheckpointDuration(1 days); + factory.updateMinPositionDuration(7 days); + factory.updateMaxPositionDuration(10 * 365 days); + vm.expectEmit(true, true, true, true); + emit CheckpointDurationResolutionUpdated( + newCheckpointDurationResolution + ); + factory.updateFeeCollector(newCheckpointDurationResolution); + assertEq( + factory.checkpointDurationResolution(), + newCheckpointDurationResolution + ); + } + + function test_updateMaxCheckpointDuration() external { + uint256 newMaxCheckpointDuration = 2 days; + + // Ensure that the max checkpoint duration can't be updated by someone + // other than the current governance. + vm.prank(bob); + vm.expectRevert(IHyperdrive.Unauthorized.selector); + factory.updateMaxCheckpointDuration(newMaxCheckpointDuration); + + // Ensure that the max checkpoint duration can't be set to a value + // less than the min checkpoint duration. + vm.prank(factory.governance()); + vm.expectRevert(IHyperdrive.InvalidMaxCheckpointDuration.selector); + factory.updateMaxCheckpointDuration( + factory.minCheckpointDuration() - 1 + ); + + // Ensure that the max checkpoint duration can't be set to a value + // that isn't a multiple of the checkpoint duration resolution. + vm.prank(factory.governance()); + vm.expectRevert(IHyperdrive.InvalidMaxCheckpointDuration.selector); + factory.updateMaxCheckpointDuration( + factory.minCheckpointDuration() + + factory.checkpointDurationResolution() / + 2 + ); + + // Ensure that the max checkpoint duration can't be set to a value + // greater than the min position duration. + vm.prank(factory.governance()); + vm.expectRevert(IHyperdrive.InvalidMaxCheckpointDuration.selector); + factory.updateMaxCheckpointDuration(factory.minPositionDuration() + 1); + + // Ensure that the max checkpoint duration was updated successfully and + // that the correct event was emitted. + vm.prank(factory.governance()); + vm.expectEmit(true, true, true, true); + emit MaxCheckpointDurationUpdated(newMaxCheckpointDuration); + factory.updateMaxCheckpointDuration(newMaxCheckpointDuration); + assertEq(factory.maxCheckpointDuration(), newMaxCheckpointDuration); + } + + function test_updateMinCheckpointDuration() external { + uint256 newMinCheckpointDuration = 12 hours; + + // Ensure that the min checkpoint duration can't be updated by someone + // other than the current governance. + vm.prank(bob); + vm.expectRevert(IHyperdrive.Unauthorized.selector); + factory.updateMinCheckpointDuration(newMinCheckpointDuration); + + // Ensure that the min checkpoint duration can't be set to a value + // less than the checkpoint duration resolution. + vm.prank(factory.governance()); + vm.expectRevert(IHyperdrive.InvalidMinCheckpointDuration.selector); + factory.updateMinCheckpointDuration( + factory.checkpointDurationResolution() - 1 + ); + + // Ensure that the min checkpoint duration can't be set to a value + // that isn't a multiple of the checkpoint duration resolution. + vm.prank(factory.governance()); + vm.expectRevert(IHyperdrive.InvalidMinCheckpointDuration.selector); + factory.updateMinCheckpointDuration( + factory.minCheckpointDuration() + + factory.checkpointDurationResolution() / + 2 + ); + + // Ensure that the min checkpoint duration can't be set to a value + // greater than the max checkpoint duration. + vm.prank(factory.governance()); + vm.expectRevert(IHyperdrive.InvalidMinCheckpointDuration.selector); + factory.updateMinCheckpointDuration( + factory.maxCheckpointDuration() + 1 + ); + + // Ensure that the min checkpoint duration was updated successfully and + // that the correct event was emitted. + vm.prank(factory.governance()); + vm.expectEmit(true, true, true, true); + emit MinCheckpointDurationUpdated(newMinCheckpointDuration); + factory.updateMinCheckpointDuration(newMinCheckpointDuration); + assertEq(factory.minCheckpointDuration(), newMinCheckpointDuration); + } + + function test_updateMaxPositionDuration() external { + uint256 newMaxPositionDuration = 30 * 365 days; + + // Ensure that the max position duration can't be updated by someone + // other than the current governance. + vm.prank(bob); + vm.expectRevert(IHyperdrive.Unauthorized.selector); + factory.updateMaxPositionDuration(newMaxPositionDuration); + + // Ensure that the max position duration can't be set to a value + // less than the min position duration. + vm.prank(factory.governance()); + vm.expectRevert(IHyperdrive.InvalidMaxPositionDuration.selector); + factory.updateMaxPositionDuration(factory.minPositionDuration() - 1); + + // Ensure that the max position duration can't be set to a value + // that isn't a multiple of the checkpoint duration resolution. + vm.prank(factory.governance()); + vm.expectRevert(IHyperdrive.InvalidMaxPositionDuration.selector); + factory.updateMaxPositionDuration( + factory.minPositionDuration() + + factory.checkpointDurationResolution() / + 2 + ); + + // Ensure that the max position duration was updated successfully and + // that the correct event was emitted. + vm.prank(factory.governance()); + vm.expectEmit(true, true, true, true); + emit MaxPositionDurationUpdated(newMaxPositionDuration); + factory.updateMaxPositionDuration(newMaxPositionDuration); + assertEq(factory.maxPositionDuration(), newMaxPositionDuration); + } + + function test_updateMinPositionDuration() external { + uint256 newMinPositionDuration = 3 days; + + // Ensure that the min position duration can't be updated by someone + // other than the current governance. + vm.prank(bob); + vm.expectRevert(IHyperdrive.Unauthorized.selector); + factory.updateMinPositionDuration(newMinPositionDuration); + + // Ensure that the min position duration can't be set to a value + // less than the max checkpoint duration. + vm.prank(factory.governance()); + vm.expectRevert(IHyperdrive.InvalidMinPositionDuration.selector); + factory.updateMinPositionDuration( + factory.checkpointDurationResolution() - 1 + ); + + // Ensure that the min position duration can't be set to a value that + // isn't a multiple of the checkpoint duration resolution. + vm.prank(factory.governance()); + vm.expectRevert(IHyperdrive.InvalidMinPositionDuration.selector); + factory.updateMinPositionDuration( + factory.maxCheckpointDuration() + + factory.checkpointDurationResolution() / + 2 + ); + + // Ensure that the min position duration can't be set to a value greater + // than the max position duration. + vm.prank(factory.governance()); + vm.expectRevert(IHyperdrive.InvalidMinPositionDuration.selector); + factory.updateMinPositionDuration(factory.maxPositionDuration() + 1); + + // Ensure that the min position duration was updated successfully and + // that the correct event was emitted. + vm.prank(factory.governance()); + vm.expectEmit(true, true, true, true); + emit MinPositionDurationUpdated(newMinPositionDuration); + factory.updateMinPositionDuration(newMinPositionDuration); + assertEq(factory.minPositionDuration(), newMinPositionDuration); + } + + // FIXME + function test_updateMaxFees() external {} + + // FIXME + function test_updateMinFees() external {} + + // FIXME + function test_updateDefaultPausers() external {} + + // FIXME + function test_addHyperdriveDeployer() external {} + + // FIXME + function test_removeHyperdriveDeployer() external {} } contract HyperdriveFactoryBaseTest is HyperdriveTest { diff --git a/test/utils/HyperdriveUtils.sol b/test/utils/HyperdriveUtils.sol index 6d30062ac..89cf76f3a 100644 --- a/test/utils/HyperdriveUtils.sol +++ b/test/utils/HyperdriveUtils.sol @@ -1674,11 +1674,14 @@ library HyperdriveUtils { if (_selector == IHyperdrive.InvalidToken.selector) { return "InvalidToken"; } - if (_selector == IHyperdrive.MaxFeeTooHigh.selector) { - return "MaxFeeTooHigh"; + if (_selector == IHyperdrive.InvalidFees.selector) { + return "InvalidFees"; } - if (_selector == IHyperdrive.FeeTooHigh.selector) { - return "FeeTooHigh"; + if (_selector == IHyperdrive.InvalidMaxFees.selector) { + return "InvalidMaxFees"; + } + if (_selector == IHyperdrive.InvalidMinFees.selector) { + return "InvalidMinFees"; } if (_selector == IHyperdrive.NonPayableInitialization.selector) { return "NonPayableInitialization"; From 32dd0bf4e84ba45cfbadee84ed2ac9c6804d5141 Mon Sep 17 00:00:00 2001 From: Alex Towle Date: Sun, 21 Jan 2024 17:23:14 -0600 Subject: [PATCH 2/5] Fixed the remaining tests --- contracts/src/factory/HyperdriveFactory.sol | 6 +- script/DevnetMigration.s.sol | 139 +++- .../instances/erc4626/ERC4626Hyperdrive.t.sol | 29 +- .../instances/erc4626/ERC4626Validation.t.sol | 30 +- test/instances/erc4626/UsdcERC4626.t.sol | 29 +- test/instances/steth/StETHHyperdrive.t.sol | 37 +- .../factory/HyperdriveFactory.t.sol | 632 +++++++++++++++--- test/units/hyperdrive/HyperdriveDeploy.t.sol | 100 --- 8 files changed, 738 insertions(+), 264 deletions(-) delete mode 100644 test/units/hyperdrive/HyperdriveDeploy.t.sol diff --git a/contracts/src/factory/HyperdriveFactory.sol b/contracts/src/factory/HyperdriveFactory.sol index 5fc9cc5ba..c7968f973 100644 --- a/contracts/src/factory/HyperdriveFactory.sol +++ b/contracts/src/factory/HyperdriveFactory.sol @@ -216,6 +216,7 @@ contract HyperdriveFactory { ) { revert IHyperdrive.InvalidMinPositionDuration(); } + minPositionDuration = _factoryConfig.minPositionDuration; // Ensure that the maximum position duration is greater than or equal // to the minimum position duration and is a multiple of the checkpoint @@ -229,6 +230,7 @@ contract HyperdriveFactory { ) { revert IHyperdrive.InvalidMaxPositionDuration(); } + maxPositionDuration = _factoryConfig.maxPositionDuration; // Ensure that the max fees are each less than or equal to 100% and set // the fees. @@ -462,8 +464,8 @@ contract HyperdriveFactory { if ( __minFees.curve > _maxFees.curve || __minFees.flat > _maxFees.flat || - __minFees.governanceLP < _maxFees.governanceLP || - __minFees.governanceZombie < _maxFees.governanceZombie + __minFees.governanceLP > _maxFees.governanceLP || + __minFees.governanceZombie > _maxFees.governanceZombie ) { revert IHyperdrive.InvalidMinFees(); } diff --git a/script/DevnetMigration.s.sol b/script/DevnetMigration.s.sol index f7783f087..7919c8348 100644 --- a/script/DevnetMigration.s.sol +++ b/script/DevnetMigration.s.sol @@ -58,10 +58,15 @@ contract DevnetMigration is Script { // lido configuration uint256 lidoStartingRate; // factory configuration - uint256 factoryCurveFee; - uint256 factoryFlatFee; - uint256 factoryGovernanceLPFee; - uint256 factoryGovernanceZombieFee; + uint256 factoryCheckpointDurationResolution; + uint256 factoryMinCheckpointDuration; + uint256 factoryMaxCheckpointDuration; + uint256 factoryMinPositionDuration; + uint256 factoryMaxPositionDuration; + uint256 factoryMinCurveFee; + uint256 factoryMinFlatFee; + uint256 factoryMinGovernanceLPFee; + uint256 factoryMinGovernanceZombieFee; uint256 factoryMaxCurveFee; uint256 factoryMaxFlatFee; uint256 factoryMaxGovernanceLPFee; @@ -74,6 +79,10 @@ contract DevnetMigration is Script { uint256 erc4626HyperdrivePositionDuration; uint256 erc4626HyperdriveCheckpointDuration; uint256 erc4626HyperdriveTimeStretchApr; + uint256 erc4626HyperdriveCurveFee; + uint256 erc4626HyperdriveFlatFee; + uint256 erc4626HyperdriveGovernanceLPFee; + uint256 erc4626HyperdriveGovernanceZombieFee; // steth hyperdrive configuration uint256 stethHyperdriveContribution; uint256 stethHyperdriveFixedRate; @@ -82,6 +91,10 @@ contract DevnetMigration is Script { uint256 stethHyperdrivePositionDuration; uint256 stethHyperdriveCheckpointDuration; uint256 stethHyperdriveTimeStretchApr; + uint256 stethHyperdriveCurveFee; + uint256 stethHyperdriveFlatFee; + uint256 stethHyperdriveGovernanceLPFee; + uint256 stethHyperdriveGovernanceZombieFee; } function run() external { @@ -113,31 +126,57 @@ contract DevnetMigration is Script { // lido configuration lidoStartingRate: vm.envOr("LIDO_STARTING_RATE", uint256(0.035e18)), // factory configuration - factoryCurveFee: vm.envOr("FACTORY_CURVE_FEE", uint256(0.01e18)), - factoryFlatFee: vm.envOr("FACTORY_FLAT_FEE", uint256(0.0005e18)), - factoryGovernanceLPFee: vm.envOr( - "FACTORY_GOVERNANCE_LP_FEE", - uint256(0.01e18) + factoryCheckpointDurationResolution: vm.envOr( + "FACTORY_CHECKPOINT_DURATION_RESOLUTION", + uint256(1 hours) ), - factoryGovernanceZombieFee: vm.envOr( - "FACTORY_GOVERNANCE_ZOMBIE_FEE", - uint256(0.1e18) + factoryMinCheckpointDuration: vm.envOr( + "FACTORY_MIN_CHECKPOINT_DURATION", + uint256(8 hours) + ), + factoryMaxCheckpointDuration: vm.envOr( + "FACTORY_MAX_CHECKPOINT_DURATION", + uint256(1 days) + ), + factoryMinPositionDuration: vm.envOr( + "FACTORY_MIN_POSITION_DURATION", + uint256(7 days) + ), + factoryMaxPositionDuration: vm.envOr( + "FACTORY_MAX_POSITION_DURATION", + uint256(10 * 365 days) + ), + factoryMinCurveFee: vm.envOr( + "FACTORY_MIN_CURVE_FEE", + uint256(0.001e18) + ), + factoryMinFlatFee: vm.envOr( + "FACTORY_MIN_FLAT_FEE", + uint256(0.0001e18) + ), + factoryMinGovernanceLPFee: vm.envOr( + "FACTORY_MIN_GOVERNANCE_LP_FEE", + uint256(0.15e18) + ), + factoryMinGovernanceZombieFee: vm.envOr( + "FACTORY_MIN_GOVERNANCE_ZOMBIE_FEE", + uint256(0.03e18) ), factoryMaxCurveFee: vm.envOr( "FACTORY_MAX_CURVE_FEE", - uint256(0.03e18) + uint256(0.1e18) ), factoryMaxFlatFee: vm.envOr( "FACTORY_MAX_FLAT_FEE", - uint256(0.0015e18) + uint256(0.001e18) ), factoryMaxGovernanceLPFee: vm.envOr( "FACTORY_MAX_GOVERNANCE_LP_FEE", - uint256(0.3e18) + uint256(0.15e18) ), factoryMaxGovernanceZombieFee: vm.envOr( "FACTORY_MAX_GOVERNANCE_ZOMBIE_FEE", - uint256(0.3e18) + uint256(0.03e18) ), // erc4626 hyperdrive configuration erc4626HyperdriveContribution: vm.envOr( @@ -168,6 +207,22 @@ contract DevnetMigration is Script { "ERC4626_HYPERDRIVE_TIME_STRETCH_APR", uint256(0.05e18) ), + erc4626HyperdriveCurveFee: vm.envOr( + "ERC4626_HYPERDRIVE_CURVE_FEE", + uint256(0.01e18) + ), + erc4626HyperdriveFlatFee: vm.envOr( + "ERC4626_HYPERDRIVE_FLAT_FEE", + uint256(0.0005e18) + ), + erc4626HyperdriveGovernanceLPFee: vm.envOr( + "ERC4626_HYPERDRIVE_GOVERNANCE_LP_FEE", + uint256(0.15e18) + ), + erc4626HyperdriveGovernanceZombieFee: vm.envOr( + "ERC4626_HYPERDRIVE_GOVERNANCE_ZOMBIE_FEE", + uint256(0.03e18) + ), // steth hyperdrive configuration stethHyperdriveContribution: vm.envOr( "STETH_HYPERDRIVE_CONTRIBUTION", @@ -196,6 +251,22 @@ contract DevnetMigration is Script { stethHyperdriveTimeStretchApr: vm.envOr( "STETH_HYPERDRIVE_TIME_STRETCH_APR", uint256(0.035e18) + ), + stethHyperdriveCurveFee: vm.envOr( + "STETH_HYPERDRIVE_CURVE_FEE", + uint256(0.01e18) + ), + stethHyperdriveFlatFee: vm.envOr( + "STETH_HYPERDRIVE_FLAT_FEE", + uint256(0.0005e18) + ), + stethHyperdriveGovernanceLPFee: vm.envOr( + "STETH_HYPERDRIVE_GOVERNANCE_LP_FEE", + uint256(0.15e18) + ), + stethHyperdriveGovernanceZombieFee: vm.envOr( + "STETH_HYPERDRIVE_GOVERNANCE_ZOMBIE_FEE", + uint256(0.03e18) ) }); @@ -250,11 +321,18 @@ contract DevnetMigration is Script { governance: msg.sender, hyperdriveGovernance: config.admin, feeCollector: config.admin, - fees: IHyperdrive.Fees({ - curve: config.factoryCurveFee, - flat: config.factoryFlatFee, - governanceLP: config.factoryGovernanceLPFee, - governanceZombie: config.factoryGovernanceZombieFee + defaultPausers: defaultPausers, + checkpointDurationResolution: config + .factoryCheckpointDurationResolution, + minCheckpointDuration: config.factoryMinCheckpointDuration, + maxCheckpointDuration: config.factoryMaxCheckpointDuration, + minPositionDuration: config.factoryMinPositionDuration, + maxPositionDuration: config.factoryMaxPositionDuration, + minFees: IHyperdrive.Fees({ + curve: config.factoryMinCurveFee, + flat: config.factoryMinFlatFee, + governanceLP: config.factoryMinGovernanceLPFee, + governanceZombie: config.factoryMinGovernanceZombieFee }), maxFees: IHyperdrive.Fees({ curve: config.factoryMaxCurveFee, @@ -262,7 +340,6 @@ contract DevnetMigration is Script { governanceLP: config.factoryMaxGovernanceLPFee, governanceZombie: config.factoryMaxGovernanceZombieFee }), - defaultPausers: defaultPausers, linkerFactory: address(forwarderFactory), linkerCodeHash: forwarderFactory.ERC20LINK_HASH() }); @@ -308,10 +385,11 @@ contract DevnetMigration is Script { governance: config.admin, feeCollector: config.admin, fees: IHyperdrive.Fees({ - curve: config.factoryCurveFee, - flat: config.factoryFlatFee, - governanceLP: config.factoryGovernanceLPFee, - governanceZombie: config.factoryGovernanceZombieFee + curve: config.erc4626HyperdriveCurveFee, + flat: config.erc4626HyperdriveFlatFee, + governanceLP: config.erc4626HyperdriveGovernanceLPFee, + governanceZombie: config + .erc4626HyperdriveGovernanceZombieFee }) }); erc4626Hyperdrive = factory.deployAndInitialize( @@ -363,10 +441,11 @@ contract DevnetMigration is Script { governance: config.admin, feeCollector: config.admin, fees: IHyperdrive.Fees({ - curve: config.factoryCurveFee, - flat: config.factoryFlatFee, - governanceLP: config.factoryGovernanceLPFee, - governanceZombie: config.factoryGovernanceZombieFee + curve: config.stethHyperdriveCurveFee, + flat: config.stethHyperdriveFlatFee, + governanceLP: config.stethHyperdriveGovernanceLPFee, + governanceZombie: config + .stethHyperdriveGovernanceZombieFee }) }); stethHyperdrive = factory.deployAndInitialize{ diff --git a/test/instances/erc4626/ERC4626Hyperdrive.t.sol b/test/instances/erc4626/ERC4626Hyperdrive.t.sol index 09e3627a3..c6de2f485 100644 --- a/test/instances/erc4626/ERC4626Hyperdrive.t.sol +++ b/test/instances/erc4626/ERC4626Hyperdrive.t.sol @@ -83,10 +83,25 @@ contract ERC4626HyperdriveTest is HyperdriveTest { HyperdriveFactory.FactoryConfig({ governance: alice, hyperdriveGovernance: bob, - feeCollector: bob, + feeCollector: celine, defaultPausers: defaults, - fees: IHyperdrive.Fees(0, 0, 0, 0), - maxFees: IHyperdrive.Fees(0, 0, 0, 0), + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees({ + curve: 0, + flat: 0, + governanceLP: 0, + governanceZombie: 0 + }), + maxFees: IHyperdrive.Fees({ + curve: ONE, + flat: ONE, + governanceLP: ONE, + governanceZombie: ONE + }), linkerFactory: address(forwarderFactory), linkerCodeHash: forwarderFactory.ERC20LINK_HASH() }) @@ -268,8 +283,8 @@ contract ERC4626HyperdriveTest is HyperdriveTest { apr, 365 days ), - governance: alice, - feeCollector: bob, + governance: address(0), + feeCollector: address(0), fees: IHyperdrive.Fees(0, 0, 0, 0) }); dai.approve(address(factory), type(uint256).max); @@ -322,8 +337,8 @@ contract ERC4626HyperdriveTest is HyperdriveTest { apr, 365 days ), - governance: alice, - feeCollector: bob, + governance: address(0), + feeCollector: address(0), fees: IHyperdrive.Fees(0, 0, 0, 0) }); dai.approve(address(factory), type(uint256).max); diff --git a/test/instances/erc4626/ERC4626Validation.t.sol b/test/instances/erc4626/ERC4626Validation.t.sol index bcd4d75a4..d2a6d59cf 100644 --- a/test/instances/erc4626/ERC4626Validation.t.sol +++ b/test/instances/erc4626/ERC4626Validation.t.sol @@ -70,10 +70,25 @@ abstract contract ERC4626ValidationTest is HyperdriveTest { HyperdriveFactory.FactoryConfig({ governance: alice, hyperdriveGovernance: bob, - feeCollector: bob, + feeCollector: celine, defaultPausers: defaults, - fees: IHyperdrive.Fees(0, 0, 0, 0), - maxFees: IHyperdrive.Fees(1e18, 1e18, 1e18, 1e18), + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees({ + curve: 0, + flat: 0, + governanceLP: 0, + governanceZombie: 0 + }), + maxFees: IHyperdrive.Fees({ + curve: ONE, + flat: ONE, + governanceLP: ONE, + governanceZombie: ONE + }), linkerFactory: address(forwarderFactory), linkerCodeHash: forwarderFactory.ERC20LINK_HASH() }) @@ -85,6 +100,10 @@ abstract contract ERC4626ValidationTest is HyperdriveTest { POSITION_DURATION ); config.baseToken = underlyingToken; + config.feeCollector = address(0); + config.governance = address(0); + config.linkerFactory = address(0); + config.linkerCodeHash = bytes32(0); uint256 contribution = 7_500e18; vm.stopPrank(); vm.startPrank(alice); @@ -126,7 +145,10 @@ abstract contract ERC4626ValidationTest is HyperdriveTest { FIXED_RATE, POSITION_DURATION ); - // Required to support ERC4626, since the test config initialVaultSharePrice is wrong + config.governance = address(0); + config.feeCollector = address(0); + config.linkerFactory = address(0); + config.linkerCodeHash = bytes32(0); config.baseToken = underlyingToken; // Designed to ensure compatibility ../../contracts/src/instances/ERC4626Hyperdrive.sol#L122C1-L122C1 config.minimumTransactionAmount = hyperdrive diff --git a/test/instances/erc4626/UsdcERC4626.t.sol b/test/instances/erc4626/UsdcERC4626.t.sol index 39a01e40c..8aae40769 100644 --- a/test/instances/erc4626/UsdcERC4626.t.sol +++ b/test/instances/erc4626/UsdcERC4626.t.sol @@ -78,12 +78,27 @@ contract UsdcERC4626 is ERC4626ValidationTest { HyperdriveFactory.FactoryConfig({ governance: alice, hyperdriveGovernance: bob, + feeCollector: celine, defaultPausers: defaults, - feeCollector: bob, - fees: IHyperdrive.Fees(0, 0, 0, 0), - maxFees: IHyperdrive.Fees(1e18, 1e18, 1e18, 1e18), - linkerFactory: address(forwarderFactory), - linkerCodeHash: forwarderFactory.ERC20LINK_HASH() + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees({ + curve: 0, + flat: 0, + governanceLP: 0, + governanceZombie: 0 + }), + maxFees: IHyperdrive.Fees({ + curve: ONE, + flat: ONE, + governanceLP: ONE, + governanceZombie: ONE + }), + linkerFactory: address(0xdeadbeef), + linkerCodeHash: bytes32(uint256(0xdeadbabe)) }) ); @@ -92,6 +107,10 @@ contract UsdcERC4626 is ERC4626ValidationTest { FIXED_RATE, POSITION_DURATION ); + config.governance = address(0); + config.feeCollector = address(0); + config.linkerFactory = address(0); + config.linkerCodeHash = bytes32(0); config.baseToken = underlyingToken; config.minimumTransactionAmount = 1e6; config.minimumShareReserves = 1e6; diff --git a/test/instances/steth/StETHHyperdrive.t.sol b/test/instances/steth/StETHHyperdrive.t.sol index fe108bfaf..f6049a3d6 100644 --- a/test/instances/steth/StETHHyperdrive.t.sol +++ b/test/instances/steth/StETHHyperdrive.t.sol @@ -13,7 +13,7 @@ import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; import { ILido } from "contracts/src/interfaces/ILido.sol"; import { AssetId } from "contracts/src/libraries/AssetId.sol"; -import { FixedPointMath } from "contracts/src/libraries/FixedPointMath.sol"; +import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; import { ForwarderFactory } from "contracts/src/token/ForwarderFactory.sol"; import { ERC20Mintable } from "contracts/test/ERC20Mintable.sol"; @@ -53,12 +53,27 @@ contract StETHHyperdriveTest is HyperdriveTest { forwarderFactory = new ForwarderFactory(); factory = new HyperdriveFactory( HyperdriveFactory.FactoryConfig({ - governance: deployer, + governance: alice, hyperdriveGovernance: bob, - feeCollector: bob, + feeCollector: celine, defaultPausers: defaults, - fees: IHyperdrive.Fees(0, 0, 0, 0), - maxFees: IHyperdrive.Fees(0, 0, 0, 0), + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees({ + curve: 0, + flat: 0, + governanceLP: 0, + governanceZombie: 0 + }), + maxFees: IHyperdrive.Fees({ + curve: ONE, + flat: ONE, + governanceLP: ONE, + governanceZombie: ONE + }), linkerFactory: address(forwarderFactory), linkerCodeHash: forwarderFactory.ERC20LINK_HASH() }) @@ -66,6 +81,8 @@ contract StETHHyperdriveTest is HyperdriveTest { // Deploy the hyperdrive deployers and register the deployer coordinator // in the factory. + vm.stopPrank(); + vm.startPrank(alice); deployerCoordinator = address( new StETHHyperdriveDeployerCoordinator( address(new StETHHyperdriveCoreDeployer(LIDO)), @@ -79,8 +96,6 @@ contract StETHHyperdriveTest is HyperdriveTest { factory.addHyperdriveDeployer(address(deployerCoordinator)); // Alice deploys the hyperdrive instance. - vm.stopPrank(); - vm.startPrank(alice); IHyperdrive.PoolDeployConfig memory config = IHyperdrive .PoolDeployConfig({ baseToken: IERC20(ETH), @@ -94,8 +109,8 @@ contract StETHHyperdriveTest is HyperdriveTest { 0.05e18, POSITION_DURATION ), - governance: governance, - feeCollector: feeCollector, + governance: address(0), + feeCollector: address(0), fees: IHyperdrive.Fees({ curve: 0, flat: 0, @@ -150,6 +165,8 @@ contract StETHHyperdriveTest is HyperdriveTest { IHyperdrive.PoolDeployConfig memory config = IHyperdrive .PoolDeployConfig({ baseToken: IERC20(ETH), + governance: address(0), + feeCollector: address(0), linkerFactory: address(0), linkerCodeHash: bytes32(0), minimumShareReserves: 1e15, @@ -160,8 +177,6 @@ contract StETHHyperdriveTest is HyperdriveTest { 0.05e18, POSITION_DURATION ), - governance: governance, - feeCollector: feeCollector, fees: IHyperdrive.Fees({ curve: 0, flat: 0, diff --git a/test/integrations/factory/HyperdriveFactory.t.sol b/test/integrations/factory/HyperdriveFactory.t.sol index fe8ddf396..2a446cb2a 100644 --- a/test/integrations/factory/HyperdriveFactory.t.sol +++ b/test/integrations/factory/HyperdriveFactory.t.sol @@ -76,6 +76,8 @@ contract HyperdriveFactoryTest is HyperdriveTest { super.setUp(); // Deploy the factory. + vm.stopPrank(); + vm.startPrank(alice); address[] memory defaults = new address[](1); defaults[0] = bob; HyperdriveFactory.FactoryConfig memory config = HyperdriveFactory @@ -89,8 +91,18 @@ contract HyperdriveFactoryTest is HyperdriveTest { maxCheckpointDuration: 1 days, minPositionDuration: 7 days, maxPositionDuration: 10 * 365 days, - minFees: IHyperdrive.Fees(0, 0, 0, 0), - maxFees: IHyperdrive.Fees(ONE, ONE, ONE, ONE), + minFees: IHyperdrive.Fees({ + curve: 0.001e18, + flat: 0.0001e18, + governanceLP: 0.15e18, + governanceZombie: 0.03e18 + }), + maxFees: IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.01e18, + governanceLP: 0.15e18, + governanceZombie: 0.03e18 + }), linkerFactory: address(0xdeadbeef), linkerCodeHash: bytes32(uint256(0xdeadbabe)) }); @@ -493,13 +505,15 @@ contract HyperdriveFactoryTest is HyperdriveTest { // Ensure that governance can't be updated by someone other than // the current governance. - vm.prank(bob); + vm.stopPrank(); + vm.startPrank(bob); vm.expectRevert(IHyperdrive.Unauthorized.selector); factory.updateGovernance(newGovernance); // Ensure that governance was updated successfully and that the correct // event was emitted. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); vm.expectEmit(true, true, true, true); emit GovernanceUpdated(newGovernance); factory.updateGovernance(newGovernance); @@ -511,13 +525,15 @@ contract HyperdriveFactoryTest is HyperdriveTest { // Ensure that hyperdrive governance can't be updated by someone other // than the current governance. - vm.prank(bob); + vm.stopPrank(); + vm.startPrank(bob); vm.expectRevert(IHyperdrive.Unauthorized.selector); factory.updateHyperdriveGovernance(newHyperdriveGovernance); // Ensure that hyperdrive governance was updated successfully and that // the correct event was emitted. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); vm.expectEmit(true, true, true, true); emit HyperdriveGovernanceUpdated(newHyperdriveGovernance); factory.updateHyperdriveGovernance(newHyperdriveGovernance); @@ -529,13 +545,15 @@ contract HyperdriveFactoryTest is HyperdriveTest { // Ensure that the linker factory can't be updated by someone other // than the current governance. - vm.prank(bob); + vm.stopPrank(); + vm.startPrank(bob); vm.expectRevert(IHyperdrive.Unauthorized.selector); factory.updateLinkerFactory(newLinkerFactory); // Ensure that the linker factory was updated successfully and that the // correct event was emitted. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); vm.expectEmit(true, true, true, true); emit LinkerFactoryUpdated(newLinkerFactory); factory.updateLinkerFactory(newLinkerFactory); @@ -547,13 +565,15 @@ contract HyperdriveFactoryTest is HyperdriveTest { // Ensure that the linker code hash can't be updated by someone other // than the current governance. - vm.prank(bob); + vm.stopPrank(); + vm.startPrank(bob); vm.expectRevert(IHyperdrive.Unauthorized.selector); factory.updateLinkerCodeHash(newLinkerCodeHash); // Ensure that the linker code hash was updated successfully and that // the correct event was emitted. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); vm.expectEmit(true, true, true, true); emit LinkerCodeHashUpdated(newLinkerCodeHash); factory.updateLinkerCodeHash(newLinkerCodeHash); @@ -565,13 +585,15 @@ contract HyperdriveFactoryTest is HyperdriveTest { // Ensure that the fee collector can't be updated by someone other than // the current governance. - vm.prank(bob); + vm.stopPrank(); + vm.startPrank(bob); vm.expectRevert(IHyperdrive.Unauthorized.selector); factory.updateFeeCollector(newFeeCollector); // Ensure that the fee collector was updated successfully and that the // correct event was emitted. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); vm.expectEmit(true, true, true, true); emit FeeCollectorUpdated(newFeeCollector); factory.updateFeeCollector(newFeeCollector); @@ -583,7 +605,8 @@ contract HyperdriveFactoryTest is HyperdriveTest { // Ensure that the checkpoint duration resolution can't be updated by // someone other than the current governance. - vm.prank(bob); + vm.stopPrank(); + vm.startPrank(bob); vm.expectRevert(IHyperdrive.Unauthorized.selector); factory.updateCheckpointDurationResolution( newCheckpointDurationResolution @@ -591,7 +614,8 @@ contract HyperdriveFactoryTest is HyperdriveTest { // Ensure that the checkpoint duration resolution can't be set to a // value that doesn't divide the min checkpoint duration. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); factory.updateMinCheckpointDuration(3 hours); factory.updateMaxCheckpointDuration(4 hours); factory.updateMinPositionDuration(4 hours); @@ -603,11 +627,12 @@ contract HyperdriveFactoryTest is HyperdriveTest { // Ensure that the checkpoint duration resolution can't be set to a // value that doesn't divide the max checkpoint duration. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); factory.updateMinCheckpointDuration(3 hours); factory.updateMaxCheckpointDuration(4 hours); - factory.updateMinPositionDuration(6 hours); - factory.updateMaxPositionDuration(6 hours); + factory.updateMinPositionDuration(4 hours); + factory.updateMaxPositionDuration(4 hours); vm.expectRevert( IHyperdrive.InvalidCheckpointDurationResolution.selector ); @@ -615,7 +640,8 @@ contract HyperdriveFactoryTest is HyperdriveTest { // Ensure that the checkpoint duration resolution can't be set to a // value that doesn't divide the min position duration. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); factory.updateMinCheckpointDuration(3 hours); factory.updateMaxCheckpointDuration(3 hours); factory.updateMinPositionDuration(4 hours); @@ -627,7 +653,8 @@ contract HyperdriveFactoryTest is HyperdriveTest { // Ensure that the checkpoint duration resolution can't be set to a // value that doesn't divide the max position duration. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); factory.updateMinCheckpointDuration(3 hours); factory.updateMaxCheckpointDuration(3 hours); factory.updateMinPositionDuration(3 hours); @@ -639,16 +666,19 @@ contract HyperdriveFactoryTest is HyperdriveTest { // Ensure that the fee collector was updated successfully and that the // correct event was emitted. - vm.prank(factory.governance()); - factory.updateMinCheckpointDuration(8 hours); - factory.updateMaxCheckpointDuration(1 days); - factory.updateMinPositionDuration(7 days); + vm.stopPrank(); + vm.startPrank(factory.governance()); factory.updateMaxPositionDuration(10 * 365 days); + factory.updateMinPositionDuration(7 days); + factory.updateMaxCheckpointDuration(1 days); + factory.updateMinCheckpointDuration(8 hours); vm.expectEmit(true, true, true, true); emit CheckpointDurationResolutionUpdated( newCheckpointDurationResolution ); - factory.updateFeeCollector(newCheckpointDurationResolution); + factory.updateCheckpointDurationResolution( + newCheckpointDurationResolution + ); assertEq( factory.checkpointDurationResolution(), newCheckpointDurationResolution @@ -660,37 +690,42 @@ contract HyperdriveFactoryTest is HyperdriveTest { // Ensure that the max checkpoint duration can't be updated by someone // other than the current governance. - vm.prank(bob); + vm.stopPrank(); + vm.startPrank(bob); vm.expectRevert(IHyperdrive.Unauthorized.selector); factory.updateMaxCheckpointDuration(newMaxCheckpointDuration); // Ensure that the max checkpoint duration can't be set to a value // less than the min checkpoint duration. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); + uint256 minCheckpointDuration = factory.minCheckpointDuration(); vm.expectRevert(IHyperdrive.InvalidMaxCheckpointDuration.selector); - factory.updateMaxCheckpointDuration( - factory.minCheckpointDuration() - 1 - ); + factory.updateMaxCheckpointDuration(minCheckpointDuration - 1); // Ensure that the max checkpoint duration can't be set to a value // that isn't a multiple of the checkpoint duration resolution. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); + uint256 checkpointDurationResolution = factory + .checkpointDurationResolution(); vm.expectRevert(IHyperdrive.InvalidMaxCheckpointDuration.selector); factory.updateMaxCheckpointDuration( - factory.minCheckpointDuration() + - factory.checkpointDurationResolution() / - 2 + minCheckpointDuration + checkpointDurationResolution / 2 ); // Ensure that the max checkpoint duration can't be set to a value // greater than the min position duration. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); + uint256 minPositionDuration = factory.minPositionDuration(); vm.expectRevert(IHyperdrive.InvalidMaxCheckpointDuration.selector); - factory.updateMaxCheckpointDuration(factory.minPositionDuration() + 1); + factory.updateMaxCheckpointDuration(minPositionDuration + 1); // Ensure that the max checkpoint duration was updated successfully and // that the correct event was emitted. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); vm.expectEmit(true, true, true, true); emit MaxCheckpointDurationUpdated(newMaxCheckpointDuration); factory.updateMaxCheckpointDuration(newMaxCheckpointDuration); @@ -702,39 +737,42 @@ contract HyperdriveFactoryTest is HyperdriveTest { // Ensure that the min checkpoint duration can't be updated by someone // other than the current governance. - vm.prank(bob); + vm.stopPrank(); + vm.startPrank(bob); vm.expectRevert(IHyperdrive.Unauthorized.selector); factory.updateMinCheckpointDuration(newMinCheckpointDuration); // Ensure that the min checkpoint duration can't be set to a value // less than the checkpoint duration resolution. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); + uint256 checkpointDurationResolution = factory + .checkpointDurationResolution(); vm.expectRevert(IHyperdrive.InvalidMinCheckpointDuration.selector); - factory.updateMinCheckpointDuration( - factory.checkpointDurationResolution() - 1 - ); + factory.updateMinCheckpointDuration(checkpointDurationResolution - 1); // Ensure that the min checkpoint duration can't be set to a value // that isn't a multiple of the checkpoint duration resolution. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); + uint256 minCheckpointDuration = factory.minCheckpointDuration(); vm.expectRevert(IHyperdrive.InvalidMinCheckpointDuration.selector); factory.updateMinCheckpointDuration( - factory.minCheckpointDuration() + - factory.checkpointDurationResolution() / - 2 + minCheckpointDuration + checkpointDurationResolution / 2 ); // Ensure that the min checkpoint duration can't be set to a value // greater than the max checkpoint duration. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); + uint256 maxCheckpointDuration = factory.maxCheckpointDuration(); vm.expectRevert(IHyperdrive.InvalidMinCheckpointDuration.selector); - factory.updateMinCheckpointDuration( - factory.maxCheckpointDuration() + 1 - ); + factory.updateMinCheckpointDuration(maxCheckpointDuration + 1); // Ensure that the min checkpoint duration was updated successfully and // that the correct event was emitted. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); vm.expectEmit(true, true, true, true); emit MinCheckpointDurationUpdated(newMinCheckpointDuration); factory.updateMinCheckpointDuration(newMinCheckpointDuration); @@ -746,29 +784,34 @@ contract HyperdriveFactoryTest is HyperdriveTest { // Ensure that the max position duration can't be updated by someone // other than the current governance. - vm.prank(bob); + vm.stopPrank(); + vm.startPrank(bob); vm.expectRevert(IHyperdrive.Unauthorized.selector); factory.updateMaxPositionDuration(newMaxPositionDuration); // Ensure that the max position duration can't be set to a value // less than the min position duration. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); + uint256 minPositionDuration = factory.minPositionDuration(); vm.expectRevert(IHyperdrive.InvalidMaxPositionDuration.selector); - factory.updateMaxPositionDuration(factory.minPositionDuration() - 1); + factory.updateMaxPositionDuration(minPositionDuration - 1); // Ensure that the max position duration can't be set to a value // that isn't a multiple of the checkpoint duration resolution. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); + uint256 checkpointDurationResolution = factory + .checkpointDurationResolution(); vm.expectRevert(IHyperdrive.InvalidMaxPositionDuration.selector); factory.updateMaxPositionDuration( - factory.minPositionDuration() + - factory.checkpointDurationResolution() / - 2 + minPositionDuration + checkpointDurationResolution / 2 ); // Ensure that the max position duration was updated successfully and // that the correct event was emitted. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); vm.expectEmit(true, true, true, true); emit MaxPositionDurationUpdated(newMaxPositionDuration); factory.updateMaxPositionDuration(newMaxPositionDuration); @@ -780,57 +823,376 @@ contract HyperdriveFactoryTest is HyperdriveTest { // Ensure that the min position duration can't be updated by someone // other than the current governance. - vm.prank(bob); + vm.stopPrank(); + vm.startPrank(bob); vm.expectRevert(IHyperdrive.Unauthorized.selector); factory.updateMinPositionDuration(newMinPositionDuration); // Ensure that the min position duration can't be set to a value // less than the max checkpoint duration. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); + uint256 checkpointDurationResolution = factory + .checkpointDurationResolution(); vm.expectRevert(IHyperdrive.InvalidMinPositionDuration.selector); - factory.updateMinPositionDuration( - factory.checkpointDurationResolution() - 1 - ); + factory.updateMinPositionDuration(checkpointDurationResolution - 1); // Ensure that the min position duration can't be set to a value that // isn't a multiple of the checkpoint duration resolution. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); + uint256 maxCheckpointDuration = factory.maxCheckpointDuration(); vm.expectRevert(IHyperdrive.InvalidMinPositionDuration.selector); factory.updateMinPositionDuration( - factory.maxCheckpointDuration() + - factory.checkpointDurationResolution() / - 2 + maxCheckpointDuration + checkpointDurationResolution / 2 ); // Ensure that the min position duration can't be set to a value greater // than the max position duration. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); + uint256 maxPositionDuration = factory.maxPositionDuration(); vm.expectRevert(IHyperdrive.InvalidMinPositionDuration.selector); - factory.updateMinPositionDuration(factory.maxPositionDuration() + 1); + factory.updateMinPositionDuration(maxPositionDuration + 1); // Ensure that the min position duration was updated successfully and // that the correct event was emitted. - vm.prank(factory.governance()); + vm.stopPrank(); + vm.startPrank(factory.governance()); vm.expectEmit(true, true, true, true); emit MinPositionDurationUpdated(newMinPositionDuration); factory.updateMinPositionDuration(newMinPositionDuration); assertEq(factory.minPositionDuration(), newMinPositionDuration); } - // FIXME - function test_updateMaxFees() external {} + function test_updateMaxFees() external { + IHyperdrive.Fees memory newMaxFees = IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.001e18, + governanceLP: 0.3e18, + governanceZombie: 0.1e18 + }); + + // Ensure that the maximum fees can't be updated by someone other than + // the current governance. + vm.stopPrank(); + vm.startPrank(bob); + vm.expectRevert(IHyperdrive.Unauthorized.selector); + factory.updateMaxFees(newMaxFees); + + // Ensure that the maximum fees can't be set when the curve fee is + // greater than 1. + vm.stopPrank(); + vm.startPrank(factory.governance()); + vm.expectRevert(IHyperdrive.InvalidMaxFees.selector); + factory.updateMaxFees( + IHyperdrive.Fees({ + curve: 1.1e18, + flat: 0.001e18, + governanceLP: 0.3e18, + governanceZombie: 0.1e18 + }) + ); + + // Ensure that the maximum fees can't be set when the flat fee is + // greater than 1. + vm.stopPrank(); + vm.startPrank(factory.governance()); + vm.expectRevert(IHyperdrive.InvalidMaxFees.selector); + factory.updateMaxFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 1.001e18, + governanceLP: 0.3e18, + governanceZombie: 0.1e18 + }) + ); + + // Ensure that the maximum fees can't be set when the governance LP fee + // is greater than 1. + vm.stopPrank(); + vm.startPrank(factory.governance()); + vm.expectRevert(IHyperdrive.InvalidMaxFees.selector); + factory.updateMaxFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.001e18, + governanceLP: 1.3e18, + governanceZombie: 0.1e18 + }) + ); + + // Ensure that the maximum fees can't be set when the governance zombie + // fee is greater than 1. + vm.stopPrank(); + vm.startPrank(factory.governance()); + vm.expectRevert(IHyperdrive.InvalidMaxFees.selector); + factory.updateMaxFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.001e18, + governanceLP: 0.3e18, + governanceZombie: 1.1e18 + }) + ); + + // Ensure that the maximum fees can't be set when the curve fee is + // less than the minimum curve fee. + vm.stopPrank(); + vm.startPrank(factory.governance()); + factory.updateMinFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.001e18, + governanceLP: 0.15e18, + governanceZombie: 0.03e18 + }) + ); + vm.expectRevert(IHyperdrive.InvalidMaxFees.selector); + factory.updateMaxFees( + IHyperdrive.Fees({ + curve: 0.05e18, + flat: 0.001e18, + governanceLP: 0.15e18, + governanceZombie: 0.1e18 + }) + ); - // FIXME - function test_updateMinFees() external {} + // Ensure that the maximum fees can't be set when the flat fee is + // less than the minimum flat fee. + vm.stopPrank(); + vm.startPrank(factory.governance()); + factory.updateMinFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.001e18, + governanceLP: 0.15e18, + governanceZombie: 0.03e18 + }) + ); + vm.expectRevert(IHyperdrive.InvalidMaxFees.selector); + factory.updateMaxFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.0005e18, + governanceLP: 0.3e18, + governanceZombie: 0.1e18 + }) + ); - // FIXME - function test_updateDefaultPausers() external {} + // Ensure that the maximum fees can't be set when the governance LP fee + // is less than the minimum governance LP fee. + vm.stopPrank(); + vm.startPrank(factory.governance()); + factory.updateMinFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.001e18, + governanceLP: 0.15e18, + governanceZombie: 0.03e18 + }) + ); + vm.expectRevert(IHyperdrive.InvalidMaxFees.selector); + factory.updateMaxFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.001e18, + governanceLP: 0.075e18, + governanceZombie: 0.1e18 + }) + ); - // FIXME - function test_addHyperdriveDeployer() external {} + // Ensure that the maximum fees can't be set when the governance zombie + // fee is less than the minimum governance zombie fee. + vm.stopPrank(); + vm.startPrank(factory.governance()); + factory.updateMinFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.001e18, + governanceLP: 0.15e18, + governanceZombie: 0.03e18 + }) + ); + vm.expectRevert(IHyperdrive.InvalidMaxFees.selector); + factory.updateMaxFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.001e18, + governanceLP: 0.3e18, + governanceZombie: 0.01e18 + }) + ); - // FIXME - function test_removeHyperdriveDeployer() external {} + // Ensure that the maximum fees were updated successfully and that the + // correct event was emitted. + vm.stopPrank(); + vm.startPrank(factory.governance()); + factory.updateMinFees( + IHyperdrive.Fees({ + curve: 0.05e18, + flat: 0.0005e18, + governanceLP: 0.15e18, + governanceZombie: 0.03e18 + }) + ); + vm.expectEmit(true, true, true, true); + emit MaxFeesUpdated(newMaxFees); + factory.updateMaxFees(newMaxFees); + assertEq( + keccak256(abi.encode(factory.maxFees())), + keccak256(abi.encode(newMaxFees)) + ); + } + + function test_updateMinFees() external { + IHyperdrive.Fees memory newMinFees = IHyperdrive.Fees({ + curve: 0.05e18, + flat: 0.0005e18, + governanceLP: 0.15e18, + governanceZombie: 0.05e18 + }); + + // Ensure that the minimum fees can't be updated by someone other than + // the current governance. + vm.stopPrank(); + vm.startPrank(bob); + vm.expectRevert(IHyperdrive.Unauthorized.selector); + factory.updateMinFees(newMinFees); + + // Ensure that the minimum fees can't be set when the curve fee is + // greater than the maximum curve fee. + vm.stopPrank(); + vm.startPrank(factory.governance()); + factory.updateMaxFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.001e18, + governanceLP: 0.3e18, + governanceZombie: 0.1e18 + }) + ); + vm.expectRevert(IHyperdrive.InvalidMinFees.selector); + factory.updateMinFees( + IHyperdrive.Fees({ + curve: 0.2e18, + flat: 0.001e18, + governanceLP: 0.3e18, + governanceZombie: 0.1e18 + }) + ); + + // Ensure that the minimum fees can't be set when the flat fee is + // greater than the maximum flat fee. + vm.stopPrank(); + vm.startPrank(factory.governance()); + factory.updateMaxFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.001e18, + governanceLP: 0.3e18, + governanceZombie: 0.1e18 + }) + ); + vm.expectRevert(IHyperdrive.InvalidMinFees.selector); + factory.updateMinFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.002e18, + governanceLP: 0.3e18, + governanceZombie: 0.1e18 + }) + ); + + // Ensure that the minimum fees can't be set when the governance LP fee + // is greater than the maximum governance LP fee. + vm.stopPrank(); + vm.startPrank(factory.governance()); + factory.updateMaxFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.001e18, + governanceLP: 0.3e18, + governanceZombie: 0.1e18 + }) + ); + vm.expectRevert(IHyperdrive.InvalidMinFees.selector); + factory.updateMinFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.001e18, + governanceLP: 0.4e18, + governanceZombie: 0.1e18 + }) + ); + + // Ensure that the minimum fees can't be set when the governance zombie + // fee is greater than the maximum governance zombie fee. + vm.stopPrank(); + vm.startPrank(factory.governance()); + factory.updateMaxFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.001e18, + governanceLP: 0.3e18, + governanceZombie: 0.1e18 + }) + ); + vm.expectRevert(IHyperdrive.InvalidMinFees.selector); + factory.updateMinFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.001e18, + governanceLP: 0.3e18, + governanceZombie: 0.2e18 + }) + ); + + // Ensure that the maximum fees were updated successfully and that the + // correct event was emitted. + vm.stopPrank(); + vm.startPrank(factory.governance()); + factory.updateMaxFees( + IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.001e18, + governanceLP: 0.3e18, + governanceZombie: 0.1e18 + }) + ); + vm.expectEmit(true, true, true, true); + emit MinFeesUpdated(newMinFees); + factory.updateMinFees(newMinFees); + assertEq( + keccak256(abi.encode(factory.minFees())), + keccak256(abi.encode(newMinFees)) + ); + } + + function test_updateDefaultPausers() external { + address[] memory newDefaultPausers = new address[](2); + newDefaultPausers[0] = bob; + newDefaultPausers[1] = celine; + + // Ensure that the default pausers can't be updated by someone other + // than the current governance. + vm.stopPrank(); + vm.startPrank(bob); + vm.expectRevert(IHyperdrive.Unauthorized.selector); + factory.updateDefaultPausers(newDefaultPausers); + + // Ensure that the default pausers were updated successfully and that + // the correct event was emitted. + vm.stopPrank(); + vm.startPrank(factory.governance()); + vm.expectEmit(true, true, true, true); + emit DefaultPausersUpdated(newDefaultPausers); + factory.updateDefaultPausers(newDefaultPausers); + assertEq( + keccak256(abi.encode(factory.defaultPausers())), + keccak256(abi.encode(newDefaultPausers)) + ); + } } contract HyperdriveFactoryBaseTest is HyperdriveTest { @@ -886,12 +1248,27 @@ contract HyperdriveFactoryBaseTest is HyperdriveTest { HyperdriveFactory.FactoryConfig({ governance: alice, hyperdriveGovernance: bob, - feeCollector: bob, - fees: IHyperdrive.Fees(0, 0, 0, 0), - maxFees: IHyperdrive.Fees(0, 0, 0, 0), + feeCollector: celine, defaultPausers: defaults, - linkerFactory: address(forwarderFactory), - linkerCodeHash: forwarderFactory.ERC20LINK_HASH() + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees({ + curve: 0.001e18, + flat: 0.0001e18, + governanceLP: 0.15e18, + governanceZombie: 0.03e18 + }), + maxFees: IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.01e18, + governanceLP: 0.15e18, + governanceZombie: 0.03e18 + }), + linkerFactory: address(0xdeadbeef), + linkerCodeHash: bytes32(uint256(0xdeadbabe)) }) ); @@ -903,11 +1280,11 @@ contract HyperdriveFactoryBaseTest is HyperdriveTest { positionDuration: 365 days, checkpointDuration: 1 days, timeStretch: HyperdriveUtils.calculateTimeStretch(APR, 365 days), - governance: alice, - feeCollector: bob, - fees: IHyperdrive.Fees(0, 0, 0, 0), - linkerFactory: address(forwarderFactory), - linkerCodeHash: forwarderFactory.ERC20LINK_HASH() + governance: address(0), + feeCollector: address(0), + fees: IHyperdrive.Fees(0.01e18, 0.001e18, 0.15e18, 0.03e18), + linkerFactory: address(0), + linkerCodeHash: bytes32(0) }); vm.stopPrank(); @@ -1229,12 +1606,27 @@ contract HyperdriveDeployerGetterTest is HyperdriveTest { HyperdriveFactory.FactoryConfig({ governance: alice, hyperdriveGovernance: bob, - feeCollector: bob, + feeCollector: celine, defaultPausers: defaults, - fees: IHyperdrive.Fees(0, 0, 0, 0), - maxFees: IHyperdrive.Fees(0, 0, 0, 0), - linkerFactory: address(0), - linkerCodeHash: bytes32(0) + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees({ + curve: 0.001e18, + flat: 0.0001e18, + governanceLP: 0.15e18, + governanceZombie: 0.03e18 + }), + maxFees: IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.01e18, + governanceLP: 0.15e18, + governanceZombie: 0.03e18 + }), + linkerFactory: address(0xdeadbeef), + linkerCodeHash: bytes32(uint256(0xdeadbabe)) }) ); } @@ -1379,12 +1771,27 @@ contract HyperdriveFactoryAddHyperdriveFactoryTest is HyperdriveTest { HyperdriveFactory.FactoryConfig({ governance: alice, hyperdriveGovernance: bob, - feeCollector: bob, + feeCollector: celine, defaultPausers: defaults, - fees: IHyperdrive.Fees(0, 0, 0, 0), - maxFees: IHyperdrive.Fees(0, 0, 0, 0), - linkerFactory: address(0), - linkerCodeHash: bytes32(0) + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees({ + curve: 0.001e18, + flat: 0.0001e18, + governanceLP: 0.15e18, + governanceZombie: 0.03e18 + }), + maxFees: IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.01e18, + governanceLP: 0.15e18, + governanceZombie: 0.03e18 + }), + linkerFactory: address(0xdeadbeef), + linkerCodeHash: bytes32(uint256(0xdeadbabe)) }) ); } @@ -1453,12 +1860,27 @@ contract HyperdriveFactoryRemoveInstanceTest is HyperdriveTest { HyperdriveFactory.FactoryConfig({ governance: alice, hyperdriveGovernance: bob, - feeCollector: bob, + feeCollector: celine, defaultPausers: defaults, - fees: IHyperdrive.Fees(0, 0, 0, 0), - maxFees: IHyperdrive.Fees(0, 0, 0, 0), - linkerFactory: address(0), - linkerCodeHash: bytes32(0) + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFees: IHyperdrive.Fees({ + curve: 0.001e18, + flat: 0.0001e18, + governanceLP: 0.15e18, + governanceZombie: 0.03e18 + }), + maxFees: IHyperdrive.Fees({ + curve: 0.1e18, + flat: 0.01e18, + governanceLP: 0.15e18, + governanceZombie: 0.03e18 + }), + linkerFactory: address(0xdeadbeef), + linkerCodeHash: bytes32(uint256(0xdeadbabe)) }) ); diff --git a/test/units/hyperdrive/HyperdriveDeploy.t.sol b/test/units/hyperdrive/HyperdriveDeploy.t.sol deleted file mode 100644 index 0c297bf56..000000000 --- a/test/units/hyperdrive/HyperdriveDeploy.t.sol +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.19; - -import { HyperdriveFactory } from "contracts/src/factory/HyperdriveFactory.sol"; -import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; -import { ForwarderFactory } from "contracts/src/token/ForwarderFactory.sol"; -import { HyperdriveTest } from "test/utils/HyperdriveTest.sol"; - -contract HyperdriveFactoryTest is HyperdriveTest { - function test_hyperdrive_factory_admin_functions() - external - __mainnet_fork(16_685_972) - { - // Deploy the DsrHyperdrive factory and deployer. - alice = createUser("alice"); - bob = createUser("bob"); - - vm.startPrank(deployer); - - address[] memory defaults = new address[](1); - defaults[0] = bob; - forwarderFactory = new ForwarderFactory(); - HyperdriveFactory factory = new HyperdriveFactory( - HyperdriveFactory.FactoryConfig({ - governance: alice, - hyperdriveGovernance: bob, - defaultPausers: defaults, - feeCollector: bob, - fees: IHyperdrive.Fees(0, 0, 0, 0), - maxFees: IHyperdrive.Fees(1e18, 1e18, 1e18, 1e18), - linkerFactory: address(forwarderFactory), - linkerCodeHash: forwarderFactory.ERC20LINK_HASH() - }) - ); - - address hyperdriveDeployer = makeAddr("hyperdriveDeployer"); - - assertEq(factory.governance(), alice); - - // Bob can't access the admin functions. - vm.stopPrank(); - vm.startPrank(bob); - vm.expectRevert(IHyperdrive.Unauthorized.selector); - factory.updateGovernance(bob); - vm.expectRevert(IHyperdrive.Unauthorized.selector); - factory.updateHyperdriveGovernance(bob); - vm.expectRevert(IHyperdrive.Unauthorized.selector); - factory.updateLinkerFactory(address(uint160(0xdeadbeef))); - vm.expectRevert(IHyperdrive.Unauthorized.selector); - factory.updateLinkerCodeHash(bytes32(uint256(0xdeadbeef))); - vm.expectRevert(IHyperdrive.Unauthorized.selector); - factory.updateFeeCollector(bob); - vm.expectRevert(IHyperdrive.Unauthorized.selector); - factory.updateFees(IHyperdrive.Fees(1, 2, 4, 5)); - vm.expectRevert(IHyperdrive.Unauthorized.selector); - factory.updateDefaultPausers(defaults); - vm.expectRevert(IHyperdrive.Unauthorized.selector); - factory.addHyperdriveDeployer(hyperdriveDeployer); - vm.expectRevert(IHyperdrive.Unauthorized.selector); - factory.removeHyperdriveDeployer(hyperdriveDeployer, 0); - vm.stopPrank(); - - // Alice can change governance. - vm.startPrank(alice); - factory.updateGovernance(bob); - assertEq(factory.governance(), bob); - vm.stopPrank(); - - // Bob can change the other values. - vm.startPrank(bob); - factory.updateHyperdriveGovernance(alice); - assertEq(factory.hyperdriveGovernance(), alice); - factory.updateLinkerFactory(address(uint160(0xdeadbeef))); - assertEq(factory.linkerFactory(), address(uint160(0xdeadbeef))); - factory.updateLinkerCodeHash(bytes32(uint256(0xdeadbeef))); - assertEq(factory.linkerCodeHash(), bytes32(uint256(0xdeadbeef))); - factory.updateFees(IHyperdrive.Fees(1, 2, 3, 4)); - ( - uint256 curve, - uint256 flat, - uint256 govLPFee, - uint256 govZombieFee - ) = factory.fees(); - assertEq(curve, 1); - assertEq(flat, 2); - assertEq(govLPFee, 3); - assertEq(govZombieFee, 4); - defaults[0] = alice; - factory.updateDefaultPausers(defaults); - address[] memory updateDefaultPausers = factory.getDefaultPausers(); - assertEq(updateDefaultPausers.length, 1); - assertEq(updateDefaultPausers[0], alice); - factory.updateFeeCollector(alice); - assertEq(factory.feeCollector(), alice); - factory.addHyperdriveDeployer(hyperdriveDeployer); - assertEq(factory.isHyperdriveDeployer(hyperdriveDeployer), true); - factory.removeHyperdriveDeployer(hyperdriveDeployer, 0); - assertEq(factory.isHyperdriveDeployer(hyperdriveDeployer), false); - } -} From a6d8542eeb9d8fc0c848fcb1a4429392868b319a Mon Sep 17 00:00:00 2001 From: Alex Towle Date: Mon, 22 Jan 2024 11:47:10 -0600 Subject: [PATCH 3/5] Wrote failure tests for `deployAndInitialize` --- contracts/src/factory/HyperdriveFactory.sol | 29 ++ .../factory/HyperdriveFactory.t.sol | 380 ++++++++++++++++++ 2 files changed, 409 insertions(+) diff --git a/contracts/src/factory/HyperdriveFactory.sol b/contracts/src/factory/HyperdriveFactory.sol index c7968f973..604d7f1bb 100644 --- a/contracts/src/factory/HyperdriveFactory.sol +++ b/contracts/src/factory/HyperdriveFactory.sol @@ -484,6 +484,10 @@ contract HyperdriveFactory { emit DefaultPausersUpdated(_defaultPausers_); } + // FIXME: Update this name to `addDeployerCoordinator`. + // + // FIXME: Furthermore, update `hyperdriveDeployers` to `deployerCoordinators`. + // /// @notice Allows governance to add a new hyperdrive deployer. /// @param _hyperdriveDeployer The new hyperdrive deployer. function addHyperdriveDeployer( @@ -497,6 +501,8 @@ contract HyperdriveFactory { emit HyperdriveDeployerAdded(_hyperdriveDeployer); } + // FIXME: Update this name to `removeDeployerCoordinator`. + // /// @notice Allows governance to remove an existing hyperdrive deployer. /// @param _hyperdriveDeployer The hyperdrive deployer to remove. /// @param _index The index of the hyperdrive deployer to remove. @@ -543,6 +549,29 @@ contract HyperdriveFactory { revert IHyperdrive.InvalidDeployer(); } + // 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 IHyperdrive.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 IHyperdrive.InvalidPositionDuration(); + } + // Ensure that the specified fees are within the minimum and maximum fees. if ( _deployConfig.fees.curve > _maxFees.curve || diff --git a/test/integrations/factory/HyperdriveFactory.t.sol b/test/integrations/factory/HyperdriveFactory.t.sol index 2a446cb2a..49df64623 100644 --- a/test/integrations/factory/HyperdriveFactory.t.sol +++ b/test/integrations/factory/HyperdriveFactory.t.sol @@ -1193,6 +1193,386 @@ contract HyperdriveFactoryTest is HyperdriveTest { keccak256(abi.encode(newDefaultPausers)) ); } + + function test_deployAndInitialize() external { + // Deploy an ERC4626 vault. + ERC20Mintable base = new ERC20Mintable( + "Base", + "BASE", + 18, + address(0), + false + ); + IERC4626 vault = IERC4626( + address( + new MockERC4626(base, "Vault", "VAULT", 0, address(0), false) + ) + ); + base.mint(bob, 10_000e18); + base.approve(address(factory), 10_000e18); + + // Add a deployer coordinator to the factory. + vm.stopPrank(); + vm.startPrank(factory.governance()); + address deployerCoordinator = address( + new ERC4626HyperdriveDeployerCoordinator( + address(new ERC4626HyperdriveCoreDeployer()), + address(new ERC4626Target0Deployer()), + address(new ERC4626Target1Deployer()), + address(new ERC4626Target2Deployer()), + address(new ERC4626Target3Deployer()) + ) + ); + factory.addHyperdriveDeployer(deployerCoordinator); + + // Define a config that can be reused for each test. + IHyperdrive.PoolDeployConfig memory config = IHyperdrive + .PoolDeployConfig({ + baseToken: IERC20(address(base)), + minimumShareReserves: 1e18, + minimumTransactionAmount: 1e15, + positionDuration: 365 days, + checkpointDuration: 1 days, + timeStretch: HyperdriveUtils.calculateTimeStretch( + 0.05e18, + 365 days + ), + governance: address(0), + feeCollector: address(0), + fees: IHyperdrive.Fees(0.01e18, 0.001e18, 0.15e18, 0.03e18), + 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(IHyperdrive.InvalidDeployer.selector); + factory.deployAndInitialize( + address(0xdeadbeef), + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + + // 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(IHyperdrive.InvalidCheckpointDuration.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + 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(IHyperdrive.InvalidCheckpointDuration.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + 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(IHyperdrive.InvalidCheckpointDuration.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + 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(IHyperdrive.InvalidPositionDuration.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + 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(IHyperdrive.InvalidPositionDuration.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + 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(IHyperdrive.InvalidPositionDuration.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + config.positionDuration = oldPositionDuration; + + // 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(IHyperdrive.InvalidFees.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + 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(IHyperdrive.InvalidFees.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + 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(IHyperdrive.InvalidFees.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + 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(IHyperdrive.InvalidFees.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + 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(IHyperdrive.InvalidFees.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + 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(IHyperdrive.InvalidFees.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + 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(IHyperdrive.InvalidFees.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + 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(IHyperdrive.InvalidFees.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + 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(IHyperdrive.InvalidDeployConfig.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + 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(IHyperdrive.InvalidDeployConfig.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + 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(IHyperdrive.InvalidDeployConfig.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + config.feeCollector = oldFeeCollector; + + // Ensure than an instance can't be deployed with a governance address + // that is set. + vm.stopPrank(); + vm.startPrank(bob); + address oldGovernance = config.governance; + config.governance = address(0xdeadbeef); + vm.expectRevert(IHyperdrive.InvalidDeployConfig.selector); + factory.deployAndInitialize( + deployerCoordinator, + config, + extraData, + 10_000e18, + 0.02e18, + new bytes(0) + ); + config.governance = oldGovernance; + } } contract HyperdriveFactoryBaseTest is HyperdriveTest { From 6ea85619dd928e605f5dcf8ef2b7f6144f725861 Mon Sep 17 00:00:00 2001 From: Alex Towle Date: Mon, 22 Jan 2024 12:09:09 -0600 Subject: [PATCH 4/5] Renamed `hyperdriveDeployer` to `deployerCoordinator` --- .../HyperdriveDeployerCoordinator.sol | 4 +- contracts/src/factory/HyperdriveFactory.sol | 121 ++++----- ...eDeployer.sol => IDeployerCoordinator.sol} | 2 +- contracts/src/interfaces/IHyperdrive.sol | 8 +- contracts/test/MockHyperdriveDeployer.sol | 4 +- script/DevnetMigration.s.sol | 4 +- .../instances/erc4626/ERC4626Hyperdrive.t.sol | 4 +- .../instances/erc4626/ERC4626Validation.t.sol | 4 +- test/instances/erc4626/UsdcERC4626.t.sol | 4 +- test/instances/steth/StETHHyperdrive.t.sol | 2 +- .../factory/HyperdriveFactory.t.sol | 256 ++++++++++-------- 11 files changed, 219 insertions(+), 194 deletions(-) rename contracts/src/interfaces/{IHyperdriveDeployer.sol => IDeployerCoordinator.sol} (88%) diff --git a/contracts/src/deployers/HyperdriveDeployerCoordinator.sol b/contracts/src/deployers/HyperdriveDeployerCoordinator.sol index 4b19debf6..931b7deac 100644 --- a/contracts/src/deployers/HyperdriveDeployerCoordinator.sol +++ b/contracts/src/deployers/HyperdriveDeployerCoordinator.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.19; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; import { IHyperdriveCoreDeployer } from "../interfaces/IHyperdriveCoreDeployer.sol"; -import { IHyperdriveDeployer } from "../interfaces/IHyperdriveDeployer.sol"; +import { IDeployerCoordinator } from "../interfaces/IDeployerCoordinator.sol"; import { IHyperdriveTargetDeployer } from "../interfaces/IHyperdriveTargetDeployer.sol"; /// @author DELV @@ -14,7 +14,7 @@ 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 IHyperdriveDeployer { +abstract contract HyperdriveDeployerCoordinator is IDeployerCoordinator { /// @notice The contract used to deploy new instances of Hyperdrive. address public immutable coreDeployer; diff --git a/contracts/src/factory/HyperdriveFactory.sol b/contracts/src/factory/HyperdriveFactory.sol index 604d7f1bb..c795a3fd7 100644 --- a/contracts/src/factory/HyperdriveFactory.sol +++ b/contracts/src/factory/HyperdriveFactory.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.19; import { ERC20 } from "solmate/tokens/ERC20.sol"; import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol"; import { IHyperdrive } from "../interfaces/IHyperdrive.sol"; -import { IHyperdriveDeployer } from "../interfaces/IHyperdriveDeployer.sol"; +import { IDeployerCoordinator } from "../interfaces/IDeployerCoordinator.sol"; import { FixedPointMath, ONE } from "../libraries/FixedPointMath.sol"; /// @author DELV @@ -26,6 +26,12 @@ contract HyperdriveFactory { bytes extraData ); + /// @notice Emitted when a new deployer coordinator is added. + event DeployerCoordinatorAdded(address deployerCoordinator); + + /// @notice Emitted when a deployer coordinator is removed. + event DeployerCoordinatorRemoved(address deployerCoordinator); + /// @notice Emitted when the default pausers are updated. event DefaultPausersUpdated(address[] newDefaultPausers); @@ -35,12 +41,6 @@ contract HyperdriveFactory { /// @notice Emitted when governance is transferred. event GovernanceUpdated(address governance); - /// @notice Emitted when a new Hyperdrive deployer is added. - event HyperdriveDeployerAdded(address hyperdriveDeployer); - - /// @notice Emitted when a Hyperdrive deployer is remove. - event HyperdriveDeployerRemoved(address hyperdriveDeployer); - /// @notice Emitted when the Hyperdrive governance address is updated. event HyperdriveGovernanceUpdated(address hyperdriveGovernance); @@ -160,14 +160,14 @@ contract HyperdriveFactory { bytes32 linkerCodeHash; } - /// @dev List of all hyperdrive deployers onboarded by governance. - address[] internal _hyperdriveDeployers; + /// @dev List of all deployer coordinators registered by governance. + address[] internal _deployerCoordinators; - /// @notice Mapping to check if an hyperdriveDeployer is in the _hyperdriveDeployers array. - mapping(address => bool) public isHyperdriveDeployer; + /// @notice Mapping to check if a deployer coordinator has been registered' + /// by governance. + mapping(address => bool) public isDeployerCoordinator; /// @dev Array of all instances deployed by this factory. - /// @dev Can be manually updated by governance to add previous instances deployed. address[] internal _instances; /// @dev Mapping to check if an instance is in the _instances array. @@ -484,51 +484,46 @@ contract HyperdriveFactory { emit DefaultPausersUpdated(_defaultPausers_); } - // FIXME: Update this name to `addDeployerCoordinator`. - // - // FIXME: Furthermore, update `hyperdriveDeployers` to `deployerCoordinators`. - // - /// @notice Allows governance to add a new hyperdrive deployer. - /// @param _hyperdriveDeployer The new hyperdrive deployer. - function addHyperdriveDeployer( - address _hyperdriveDeployer + /// @notice Allows governance to add a new deployer coordinator. + /// @param _deployerCoordinator The new deployer coordinator. + function addDeployerCoordinator( + address _deployerCoordinator ) external onlyGovernance { - if (isHyperdriveDeployer[_hyperdriveDeployer]) { - revert IHyperdrive.HyperdriveDeployerAlreadyAdded(); + if (isDeployerCoordinator[_deployerCoordinator]) { + revert IHyperdrive.DeployerCoordinatorAlreadyAdded(); } - isHyperdriveDeployer[_hyperdriveDeployer] = true; - _hyperdriveDeployers.push(_hyperdriveDeployer); - emit HyperdriveDeployerAdded(_hyperdriveDeployer); + isDeployerCoordinator[_deployerCoordinator] = true; + _deployerCoordinators.push(_deployerCoordinator); + emit DeployerCoordinatorAdded(_deployerCoordinator); } - // FIXME: Update this name to `removeDeployerCoordinator`. - // - /// @notice Allows governance to remove an existing hyperdrive deployer. - /// @param _hyperdriveDeployer The hyperdrive deployer to remove. - /// @param _index The index of the hyperdrive deployer to remove. - function removeHyperdriveDeployer( - address _hyperdriveDeployer, + /// @notice Allows governance to remove an existing deployer coordinator. + /// @param _deployerCoordinator The deployer coordinator to remove. + /// @param _index The index of the deployer coordinator to remove. + function removeDeployerCoordinator( + address _deployerCoordinator, uint256 _index ) external onlyGovernance { - if (!isHyperdriveDeployer[_hyperdriveDeployer]) { - revert IHyperdrive.HyperdriveDeployerNotAdded(); + if (!isDeployerCoordinator[_deployerCoordinator]) { + revert IHyperdrive.DeployerCoordinatorNotAdded(); } - if (_hyperdriveDeployers[_index] != _hyperdriveDeployer) { - revert IHyperdrive.HyperdriveDeployerIndexMismatch(); + if (_deployerCoordinators[_index] != _deployerCoordinator) { + revert IHyperdrive.DeployerCoordinatorIndexMismatch(); } - isHyperdriveDeployer[_hyperdriveDeployer] = false; - _hyperdriveDeployers[_index] = _hyperdriveDeployers[ - _hyperdriveDeployers.length - 1 + isDeployerCoordinator[_deployerCoordinator] = false; + _deployerCoordinators[_index] = _deployerCoordinators[ + _deployerCoordinators.length - 1 ]; - _hyperdriveDeployers.pop(); - emit HyperdriveDeployerRemoved(_hyperdriveDeployer); + _deployerCoordinators.pop(); + emit DeployerCoordinatorRemoved(_deployerCoordinator); } /// @notice Deploys a Hyperdrive instance with the factory's configuration. /// @dev This function is declared as payable to allow payable overrides /// to accept ether on initialization, but payability is not supported /// by default. - /// @param _hyperdriveDeployer Address of the hyperdrive deployer. + /// @param _deployerCoordinator The deployer coordinator to use in this + /// deployment. /// @param _deployConfig The deploy configuration of the Hyperdrive pool. /// @param _extraData The extra data that contains data necessary for the /// specific deployer. @@ -537,7 +532,7 @@ contract HyperdriveFactory { /// @param _initializeExtraData The extra data for the `initialize` call. /// @return The hyperdrive address deployed. function deployAndInitialize( - address _hyperdriveDeployer, + address _deployerCoordinator, IHyperdrive.PoolDeployConfig memory _deployConfig, bytes memory _extraData, uint256 _contribution, @@ -545,8 +540,8 @@ contract HyperdriveFactory { bytes memory _initializeExtraData ) public payable virtual returns (IHyperdrive) { // Ensure that the target deployer has been registered. - if (!isHyperdriveDeployer[_hyperdriveDeployer]) { - revert IHyperdrive.InvalidDeployer(); + if (!isDeployerCoordinator[_deployerCoordinator]) { + revert IHyperdrive.InvalidDeployerCoordinator(); } // Ensure that the specified checkpoint duration is within the minimum @@ -610,7 +605,7 @@ contract HyperdriveFactory { // Deploy the Hyperdrive instance with the specified Hyperdrive // deployer. IHyperdrive hyperdrive = IHyperdrive( - IHyperdriveDeployer(_hyperdriveDeployer).deploy( + IDeployerCoordinator(_deployerCoordinator).deploy( _deployConfig, _extraData ) @@ -751,26 +746,28 @@ contract HyperdriveFactory { } } - /// @notice Gets the number of hyperdrive deployers deployed by this factory. - /// @return The number of hyperdrive deployers deployed by this factory. - function getNumberOfHyperdriveDeployers() external view returns (uint256) { - return _hyperdriveDeployers.length; + /// @notice Gets the number of deployer coordinators registered in this + /// factory. + /// @return The number of deployer coordinators deployed by this factory. + function getNumberOfDeployerCoordinators() external view returns (uint256) { + return _deployerCoordinators.length; } - /// @notice Gets the instance at the specified index. - /// @param index The index of the instance to get. - /// @return The instance at the specified index. - function getHyperdriveDeployerAtIndex( + /// @notice Gets the deployer coordinator at the specified index. + /// @param index The index of the deployer coordinator to get. + /// @return The deployer coordinator at the specified index. + function getDeployerCoordinatorAtIndex( uint256 index ) external view returns (address) { - return _hyperdriveDeployers[index]; + return _deployerCoordinators[index]; } - /// @notice Returns the hyperdrive deployers array according to specified indices. - /// @param startIndex The starting index of the hyperdrive deployers to get. - /// @param endIndex The ending index of the hyperdrive deployers to get. - /// @return range The resulting custom portion of the hyperdrive deployers array. - function getHyperdriveDeployersInRange( + /// @notice Returns the deployer coordinators with an index between the + /// starting and ending indexes (inclusive). + /// @param startIndex The starting index (inclusive). + /// @param endIndex The ending index (inclusive). + /// @return range The deployer coordinators within the specified range. + function getDeployerCoordinatorsInRange( uint256 startIndex, uint256 endIndex ) external view returns (address[] memory range) { @@ -778,14 +775,14 @@ contract HyperdriveFactory { if (startIndex > endIndex) { revert IHyperdrive.InvalidIndexes(); } - if (endIndex > _hyperdriveDeployers.length) { + if (endIndex > _deployerCoordinators.length) { revert IHyperdrive.EndIndexTooLarge(); } // Return the range of instances. range = new address[](endIndex - startIndex + 1); for (uint256 i = startIndex; i <= endIndex; i++) { - range[i - startIndex] = _hyperdriveDeployers[i]; + range[i - startIndex] = _deployerCoordinators[i]; } } } diff --git a/contracts/src/interfaces/IHyperdriveDeployer.sol b/contracts/src/interfaces/IDeployerCoordinator.sol similarity index 88% rename from contracts/src/interfaces/IHyperdriveDeployer.sol rename to contracts/src/interfaces/IDeployerCoordinator.sol index 5457e1892..636432234 100644 --- a/contracts/src/interfaces/IHyperdriveDeployer.sol +++ b/contracts/src/interfaces/IDeployerCoordinator.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.19; import { IHyperdrive } from "./IHyperdrive.sol"; -interface IHyperdriveDeployer { +interface IDeployerCoordinator { function deploy( IHyperdrive.PoolDeployConfig memory _config, bytes memory _extraData diff --git a/contracts/src/interfaces/IHyperdrive.sol b/contracts/src/interfaces/IHyperdrive.sol index 505b3578b..ef5a95513 100644 --- a/contracts/src/interfaces/IHyperdrive.sol +++ b/contracts/src/interfaces/IHyperdrive.sol @@ -262,7 +262,6 @@ interface IHyperdrive is IHyperdriveRead, IHyperdriveCore, IMultiToken { error InvalidBaseToken(); error InvalidCheckpointTime(); error InvalidCheckpointDuration(); - error InvalidDeployer(); error InvalidEffectiveShareReserves(); error InvalidFeeAmounts(); error InvalidFeeDestination(); @@ -310,6 +309,7 @@ interface IHyperdrive is IHyperdriveRead, IHyperdriveCore, IMultiToken { error InvalidCheckpointDurationResolution(); error InvalidContribution(); error InvalidDeployConfig(); + error InvalidDeployerCoordinator(); error InvalidFees(); error InvalidMaxFees(); error InvalidMinFees(); @@ -319,9 +319,9 @@ interface IHyperdrive is IHyperdriveRead, IHyperdriveCore, IMultiToken { error InvalidMinPositionDuration(); error InvalidToken(); error NonPayableInitialization(); - error HyperdriveDeployerAlreadyAdded(); - error HyperdriveDeployerNotAdded(); - error HyperdriveDeployerIndexMismatch(); + error DeployerCoordinatorAlreadyAdded(); + error DeployerCoordinatorNotAdded(); + error DeployerCoordinatorIndexMismatch(); /// ###################### /// ### ERC20Forwarder ### diff --git a/contracts/test/MockHyperdriveDeployer.sol b/contracts/test/MockHyperdriveDeployer.sol index 956a3f8aa..c4346da1a 100644 --- a/contracts/test/MockHyperdriveDeployer.sol +++ b/contracts/test/MockHyperdriveDeployer.sol @@ -2,11 +2,11 @@ pragma solidity 0.8.19; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; -import { IHyperdriveDeployer } from "contracts/src/interfaces/IHyperdriveDeployer.sol"; +import { IDeployerCoordinator } from "contracts/src/interfaces/IDeployerCoordinator.sol"; import { IHyperdriveTargetDeployer } from "contracts/src/interfaces/IHyperdriveTargetDeployer.sol"; import { MockHyperdrive } from "./MockHyperdrive.sol"; -contract MockHyperdriveDeployer is IHyperdriveDeployer { +contract MockHyperdriveDeployer is IDeployerCoordinator { function deploy( IHyperdrive.PoolDeployConfig memory _deployConfig, bytes memory diff --git a/script/DevnetMigration.s.sol b/script/DevnetMigration.s.sol index 7919c8348..7f0fb9fc4 100644 --- a/script/DevnetMigration.s.sol +++ b/script/DevnetMigration.s.sol @@ -356,7 +356,7 @@ contract DevnetMigration is Script { address(new ERC4626Target3Deployer()) ) ); - factory.addHyperdriveDeployer(erc4626DeployerCoordinator); + factory.addDeployerCoordinator(erc4626DeployerCoordinator); // Deploy and initialize an initial ERC4626Hyperdrive instance. IHyperdrive erc4626Hyperdrive; @@ -413,7 +413,7 @@ contract DevnetMigration is Script { ILido(address(lido)) ) ); - factory.addHyperdriveDeployer(stethDeployerCoordinator); + factory.addDeployerCoordinator(stethDeployerCoordinator); // Deploy and initialize an initial StETHHyperdrive instance. IHyperdrive stethHyperdrive; diff --git a/test/instances/erc4626/ERC4626Hyperdrive.t.sol b/test/instances/erc4626/ERC4626Hyperdrive.t.sol index c6de2f485..6bd5063f4 100644 --- a/test/instances/erc4626/ERC4626Hyperdrive.t.sol +++ b/test/instances/erc4626/ERC4626Hyperdrive.t.sol @@ -16,7 +16,7 @@ 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 { IHyperdriveDeployer } from "contracts/src/interfaces/IHyperdriveDeployer.sol"; +import { IDeployerCoordinator } from "contracts/src/interfaces/IDeployerCoordinator.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"; @@ -141,7 +141,7 @@ contract ERC4626HyperdriveTest is HyperdriveTest { vm.stopPrank(); vm.startPrank(alice); - factory.addHyperdriveDeployer(deployerCoordinator); + factory.addDeployerCoordinator(deployerCoordinator); dai.approve(address(factory), type(uint256).max); dai.approve(address(hyperdrive), type(uint256).max); dai.approve(address(mockHyperdrive), type(uint256).max); diff --git a/test/instances/erc4626/ERC4626Validation.t.sol b/test/instances/erc4626/ERC4626Validation.t.sol index d2a6d59cf..d313e4eb5 100644 --- a/test/instances/erc4626/ERC4626Validation.t.sol +++ b/test/instances/erc4626/ERC4626Validation.t.sol @@ -11,7 +11,7 @@ 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 { IHyperdriveDeployer } from "contracts/src/interfaces/IHyperdriveDeployer.sol"; +import { IDeployerCoordinator } from "contracts/src/interfaces/IDeployerCoordinator.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"; @@ -108,7 +108,7 @@ abstract contract ERC4626ValidationTest is HyperdriveTest { vm.stopPrank(); vm.startPrank(alice); - factory.addHyperdriveDeployer(deployerCoordinator); + factory.addDeployerCoordinator(deployerCoordinator); // Set approval to allow initial contribution to factory underlyingToken.approve(address(factory), type(uint256).max); diff --git a/test/instances/erc4626/UsdcERC4626.t.sol b/test/instances/erc4626/UsdcERC4626.t.sol index 8aae40769..238c30cd5 100644 --- a/test/instances/erc4626/UsdcERC4626.t.sol +++ b/test/instances/erc4626/UsdcERC4626.t.sol @@ -11,7 +11,7 @@ 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 { IHyperdriveDeployer } from "contracts/src/interfaces/IHyperdriveDeployer.sol"; +import { IDeployerCoordinator } from "contracts/src/interfaces/IDeployerCoordinator.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"; @@ -118,7 +118,7 @@ contract UsdcERC4626 is ERC4626ValidationTest { vm.stopPrank(); vm.startPrank(alice); - factory.addHyperdriveDeployer(deployerCoordinator); + factory.addDeployerCoordinator(deployerCoordinator); // Set approval to allow initial contribution to factory. underlyingToken.approve(address(factory), type(uint256).max); diff --git a/test/instances/steth/StETHHyperdrive.t.sol b/test/instances/steth/StETHHyperdrive.t.sol index f6049a3d6..2d8328ae0 100644 --- a/test/instances/steth/StETHHyperdrive.t.sol +++ b/test/instances/steth/StETHHyperdrive.t.sol @@ -93,7 +93,7 @@ contract StETHHyperdriveTest is HyperdriveTest { LIDO ) ); - factory.addHyperdriveDeployer(address(deployerCoordinator)); + factory.addDeployerCoordinator(address(deployerCoordinator)); // Alice deploys the hyperdrive instance. IHyperdrive.PoolDeployConfig memory config = IHyperdrive diff --git a/test/integrations/factory/HyperdriveFactory.t.sol b/test/integrations/factory/HyperdriveFactory.t.sol index 49df64623..dc3de76a5 100644 --- a/test/integrations/factory/HyperdriveFactory.t.sol +++ b/test/integrations/factory/HyperdriveFactory.t.sol @@ -12,7 +12,7 @@ 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 { IHyperdriveDeployer } from "contracts/src/interfaces/IHyperdriveDeployer.sol"; +import { IDeployerCoordinator } from "contracts/src/interfaces/IDeployerCoordinator.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"; @@ -32,10 +32,10 @@ contract HyperdriveFactoryTest is HyperdriveTest { event GovernanceUpdated(address governance); /// @notice Emitted when a new Hyperdrive deployer is added. - event HyperdriveDeployerAdded(address hyperdriveDeployer); + event DeployerCoordinatorAdded(address deployerCoordinator); /// @notice Emitted when a Hyperdrive deployer is remove. - event HyperdriveDeployerRemoved(address hyperdriveDeployer); + event DeployerCoordinatorRemoved(address deployerCoordinator); /// @notice Emitted when the Hyperdrive governance address is updated. event HyperdriveGovernanceUpdated(address hyperdriveGovernance); @@ -1223,7 +1223,7 @@ contract HyperdriveFactoryTest is HyperdriveTest { address(new ERC4626Target3Deployer()) ) ); - factory.addHyperdriveDeployer(deployerCoordinator); + factory.addDeployerCoordinator(deployerCoordinator); // Define a config that can be reused for each test. IHyperdrive.PoolDeployConfig memory config = IHyperdrive @@ -1249,7 +1249,7 @@ contract HyperdriveFactoryTest is HyperdriveTest { vm.stopPrank(); vm.startPrank(bob); bytes memory extraData = abi.encode(vault); - vm.expectRevert(IHyperdrive.InvalidDeployer.selector); + vm.expectRevert(IHyperdrive.InvalidDeployerCoordinator.selector); factory.deployAndInitialize( address(0xdeadbeef), config, @@ -1670,7 +1670,7 @@ contract HyperdriveFactoryBaseTest is HyperdriveTest { vm.stopPrank(); vm.prank(alice); - factory.addHyperdriveDeployer(deployerCoordinator); + factory.addDeployerCoordinator(deployerCoordinator); // Deploy yield sources pool1 = IERC4626( @@ -1746,7 +1746,7 @@ contract ERC4626FactoryMultiDeployTest is HyperdriveFactoryBaseTest { ); vm.prank(alice); - factory.addHyperdriveDeployer(deployerCoordinator1); + factory.addDeployerCoordinator(deployerCoordinator1); } function test_hyperdriveFactoryDeploy_multiDeploy_multiPool() external { @@ -1972,7 +1972,7 @@ contract ERC4626InstanceGetterTest is HyperdriveFactoryBaseTest { } } -contract HyperdriveDeployerGetterTest is HyperdriveTest { +contract DeployerCoordinatorGetterTest is HyperdriveTest { HyperdriveFactory factory; function setUp() public override { @@ -2011,21 +2011,21 @@ contract HyperdriveDeployerGetterTest is HyperdriveTest { ); } - function testFuzz_hyperdriveFactory_getNumberOfHyperdriveDeployers( - uint256 numberOfHyperdriveDeployers + function testFuzz_hyperdriveFactory_getNumberOfDeployerCoordinators( + uint256 numberOfDeployerCoordinators ) external { - numberOfHyperdriveDeployers = _bound( - numberOfHyperdriveDeployers, + numberOfDeployerCoordinators = _bound( + numberOfDeployerCoordinators, 1, 10 ); - address[] memory hyperdriveDeployers = new address[]( - numberOfHyperdriveDeployers + address[] memory deployerCoordinators = new address[]( + numberOfDeployerCoordinators ); - for (uint256 i; i < numberOfHyperdriveDeployers; i++) { - hyperdriveDeployers[i] = address( + for (uint256 i; i < numberOfDeployerCoordinators; i++) { + deployerCoordinators[i] = address( new ERC4626HyperdriveDeployerCoordinator( address(new ERC4626HyperdriveCoreDeployer()), address(new ERC4626Target0Deployer()), @@ -2036,30 +2036,30 @@ contract HyperdriveDeployerGetterTest is HyperdriveTest { ); vm.prank(alice); - factory.addHyperdriveDeployer(hyperdriveDeployers[i]); + factory.addDeployerCoordinator(deployerCoordinators[i]); } assertEq( - factory.getNumberOfHyperdriveDeployers(), - numberOfHyperdriveDeployers + factory.getNumberOfDeployerCoordinators(), + numberOfDeployerCoordinators ); } - function testFuzz_hyperdriveFactory_getHyperdriveDeployerAtIndex( - uint256 numberOfHyperdriveDeployers + function testFuzz_hyperdriveFactory_getDeployerCoordinatorAtIndex( + uint256 numberOfDeployerCoordinators ) external { - numberOfHyperdriveDeployers = _bound( - numberOfHyperdriveDeployers, + numberOfDeployerCoordinators = _bound( + numberOfDeployerCoordinators, 1, 10 ); - address[] memory hyperdriveDeployers = new address[]( - numberOfHyperdriveDeployers + address[] memory deployerCoordinators = new address[]( + numberOfDeployerCoordinators ); - for (uint256 i; i < numberOfHyperdriveDeployers; i++) { - hyperdriveDeployers[i] = address( + for (uint256 i; i < numberOfDeployerCoordinators; i++) { + deployerCoordinators[i] = address( new ERC4626HyperdriveDeployerCoordinator( address(new ERC4626HyperdriveCoreDeployer()), address(new ERC4626Target0Deployer()), @@ -2070,40 +2070,44 @@ contract HyperdriveDeployerGetterTest is HyperdriveTest { ); vm.prank(alice); - factory.addHyperdriveDeployer(hyperdriveDeployers[i]); + factory.addDeployerCoordinator(deployerCoordinators[i]); } - for (uint256 i; i < numberOfHyperdriveDeployers; i++) { + for (uint256 i; i < numberOfDeployerCoordinators; i++) { assertEq( - factory.getHyperdriveDeployerAtIndex(i), - address(hyperdriveDeployers[i]) + factory.getDeployerCoordinatorAtIndex(i), + address(deployerCoordinators[i]) ); } } - function testFuzz_hyperdriveFactory_getHyperdriveDeployersInRange( - uint256 numberOfHyperdriveDeployers, + function testFuzz_hyperdriveFactory_getDeployerCoordinatorsInRange( + uint256 numberOfDeployerCoordinators, uint256 startingIndex, uint256 endingIndex ) external { - numberOfHyperdriveDeployers = bound(numberOfHyperdriveDeployers, 1, 10); + numberOfDeployerCoordinators = bound( + numberOfDeployerCoordinators, + 1, + 10 + ); startingIndex = bound( startingIndex, 0, - numberOfHyperdriveDeployers - 1 + numberOfDeployerCoordinators - 1 ); endingIndex = bound( endingIndex, startingIndex, - numberOfHyperdriveDeployers - 1 + numberOfDeployerCoordinators - 1 ); - address[] memory hyperdriveDeployers = new address[]( - numberOfHyperdriveDeployers + address[] memory deployerCoordinators = new address[]( + numberOfDeployerCoordinators ); - for (uint256 i; i < numberOfHyperdriveDeployers; i++) { - hyperdriveDeployers[i] = address( + for (uint256 i; i < numberOfDeployerCoordinators; i++) { + deployerCoordinators[i] = address( new ERC4626HyperdriveDeployerCoordinator( address(new ERC4626HyperdriveCoreDeployer()), address(new ERC4626Target0Deployer()), @@ -2114,21 +2118,21 @@ contract HyperdriveDeployerGetterTest is HyperdriveTest { ); vm.prank(alice); - factory.addHyperdriveDeployer(hyperdriveDeployers[i]); + factory.addDeployerCoordinator(deployerCoordinators[i]); } - address[] memory hyperdriveDeployersArray = factory - .getHyperdriveDeployersInRange(startingIndex, endingIndex); + address[] memory deployerCoordinatorsArray = factory + .getDeployerCoordinatorsInRange(startingIndex, endingIndex); assertEq( - hyperdriveDeployersArray.length, + deployerCoordinatorsArray.length, endingIndex - startingIndex + 1 ); - for (uint256 i; i < hyperdriveDeployersArray.length; i++) { + for (uint256 i; i < deployerCoordinatorsArray.length; i++) { assertEq( - hyperdriveDeployersArray[i], - address(hyperdriveDeployers[i + startingIndex]) + deployerCoordinatorsArray[i], + address(deployerCoordinators[i + startingIndex]) ); } } @@ -2137,8 +2141,8 @@ contract HyperdriveDeployerGetterTest is HyperdriveTest { contract HyperdriveFactoryAddHyperdriveFactoryTest is HyperdriveTest { HyperdriveFactory factory; - address hyperdriveDeployer0 = makeAddr("hyperdriveDeployer0"); - address hyperdriveDeployer1 = makeAddr("hyperdriveDeployer1"); + address deployerCoordinator0 = makeAddr("deployerCoordinator0"); + address deployerCoordinator1 = makeAddr("deployerCoordinator1"); function setUp() public override { super.setUp(); @@ -2176,60 +2180,69 @@ contract HyperdriveFactoryAddHyperdriveFactoryTest is HyperdriveTest { ); } - function test_hyperdriveFactory_addHyperdriveDeployer_notGovernance() + function test_hyperdriveFactory_addDeployerCoordinator_notGovernance() external { vm.expectRevert(IHyperdrive.Unauthorized.selector); - factory.addHyperdriveDeployer(hyperdriveDeployer0); + factory.addDeployerCoordinator(deployerCoordinator0); vm.prank(alice); - factory.addHyperdriveDeployer(hyperdriveDeployer0); + factory.addDeployerCoordinator(deployerCoordinator0); } - function test_hyperdriveFactory_addHyperdriveDeployer_alreadyAdded() + function test_hyperdriveFactory_addDeployerCoordinator_alreadyAdded() external { vm.startPrank(alice); - factory.addHyperdriveDeployer(hyperdriveDeployer0); + factory.addDeployerCoordinator(deployerCoordinator0); - vm.expectRevert(IHyperdrive.HyperdriveDeployerAlreadyAdded.selector); - factory.addHyperdriveDeployer(hyperdriveDeployer0); + vm.expectRevert(IHyperdrive.DeployerCoordinatorAlreadyAdded.selector); + factory.addDeployerCoordinator(deployerCoordinator0); } - function test_hyperdriveFactory_addHyperdriveDeployer() external { - assertEq(factory.getNumberOfHyperdriveDeployers(), 0); + function test_hyperdriveFactory_addDeployerCoordinator() external { + assertEq(factory.getNumberOfDeployerCoordinators(), 0); vm.prank(alice); - factory.addHyperdriveDeployer(hyperdriveDeployer0); + factory.addDeployerCoordinator(deployerCoordinator0); - assertEq(factory.getNumberOfHyperdriveDeployers(), 1); - assertEq(factory.getHyperdriveDeployerAtIndex(0), hyperdriveDeployer0); + assertEq(factory.getNumberOfDeployerCoordinators(), 1); + assertEq( + factory.getDeployerCoordinatorAtIndex(0), + deployerCoordinator0 + ); - address[] memory hyperdriveDeployers = factory - .getHyperdriveDeployersInRange(0, 0); - assertEq(hyperdriveDeployers.length, 1); - assertEq(hyperdriveDeployers[0], hyperdriveDeployer0); + address[] memory deployerCoordinators = factory + .getDeployerCoordinatorsInRange(0, 0); + assertEq(deployerCoordinators.length, 1); + assertEq(deployerCoordinators[0], deployerCoordinator0); vm.prank(alice); - factory.addHyperdriveDeployer(hyperdriveDeployer1); + factory.addDeployerCoordinator(deployerCoordinator1); - assertEq(factory.getNumberOfHyperdriveDeployers(), 2); - assertEq(factory.getHyperdriveDeployerAtIndex(0), hyperdriveDeployer0); - assertEq(factory.getHyperdriveDeployerAtIndex(1), hyperdriveDeployer1); + assertEq(factory.getNumberOfDeployerCoordinators(), 2); + assertEq( + factory.getDeployerCoordinatorAtIndex(0), + deployerCoordinator0 + ); + assertEq( + factory.getDeployerCoordinatorAtIndex(1), + deployerCoordinator1 + ); - hyperdriveDeployers = factory.getHyperdriveDeployersInRange(0, 1); - assertEq(hyperdriveDeployers.length, 2); - assertEq(hyperdriveDeployers[0], hyperdriveDeployer0); - assertEq(hyperdriveDeployers[1], hyperdriveDeployer1); + deployerCoordinators = factory.getDeployerCoordinatorsInRange(0, 1); + assertEq(deployerCoordinators.length, 2); + assertEq(deployerCoordinators[0], deployerCoordinator0); + assertEq(deployerCoordinators[1], deployerCoordinator1); } } contract HyperdriveFactoryRemoveInstanceTest is HyperdriveTest { HyperdriveFactory factory; - address hyperdriveDeployer0 = makeAddr("hyperdriveDeployer0"); - address hyperdriveDeployer1 = makeAddr("hyperdriveDeployer1"); - address hyperdriveDeployer2 = makeAddr("hyperdriveDeployer2"); + address deployerCoordinator0 = makeAddr("deployerCoordinator0"); + address deployerCoordinator1 = makeAddr("deployerCoordinator1"); + address deployerCoordinator2 = makeAddr("deployerCoordinator2"); function setUp() public override { super.setUp(); @@ -2265,78 +2278,93 @@ contract HyperdriveFactoryRemoveInstanceTest is HyperdriveTest { ); vm.startPrank(alice); - factory.addHyperdriveDeployer(hyperdriveDeployer0); - factory.addHyperdriveDeployer(hyperdriveDeployer1); - factory.addHyperdriveDeployer(hyperdriveDeployer2); + factory.addDeployerCoordinator(deployerCoordinator0); + factory.addDeployerCoordinator(deployerCoordinator1); + factory.addDeployerCoordinator(deployerCoordinator2); vm.stopPrank(); } function test_hyperdriveFactory_removeInstance_notGovernance() external { vm.expectRevert(IHyperdrive.Unauthorized.selector); - factory.removeHyperdriveDeployer(hyperdriveDeployer0, 0); + factory.removeDeployerCoordinator(deployerCoordinator0, 0); vm.startPrank(alice); - factory.removeHyperdriveDeployer(hyperdriveDeployer0, 0); + factory.removeDeployerCoordinator(deployerCoordinator0, 0); } - function test_hyperdriveFactory_removeHyperdriveDeployer_notAdded() + function test_hyperdriveFactory_removeDeployerCoordinator_notAdded() external { vm.startPrank(alice); - vm.expectRevert(IHyperdrive.HyperdriveDeployerNotAdded.selector); - factory.removeHyperdriveDeployer( + vm.expectRevert(IHyperdrive.DeployerCoordinatorNotAdded.selector); + factory.removeDeployerCoordinator( address(makeAddr("not added address")), 0 ); - factory.removeHyperdriveDeployer(hyperdriveDeployer0, 0); + factory.removeDeployerCoordinator(deployerCoordinator0, 0); } - function test_hyperdriveFactory_removeHyperdriveDeployer_indexMismatch() + function test_hyperdriveFactory_removeDeployerCoordinator_indexMismatch() external { vm.startPrank(alice); - vm.expectRevert(IHyperdrive.HyperdriveDeployerIndexMismatch.selector); - factory.removeHyperdriveDeployer(hyperdriveDeployer0, 1); + vm.expectRevert(IHyperdrive.DeployerCoordinatorIndexMismatch.selector); + factory.removeDeployerCoordinator(deployerCoordinator0, 1); - factory.removeHyperdriveDeployer(hyperdriveDeployer0, 0); + factory.removeDeployerCoordinator(deployerCoordinator0, 0); } - function test_hyperdriveFactory_removeHyperdriveDeployer() external { - assertEq(factory.getNumberOfHyperdriveDeployers(), 3); - assertEq(factory.getHyperdriveDeployerAtIndex(0), hyperdriveDeployer0); - assertEq(factory.getHyperdriveDeployerAtIndex(1), hyperdriveDeployer1); - assertEq(factory.getHyperdriveDeployerAtIndex(2), hyperdriveDeployer2); + function test_hyperdriveFactory_removeDeployerCoordinator() external { + assertEq(factory.getNumberOfDeployerCoordinators(), 3); + assertEq( + factory.getDeployerCoordinatorAtIndex(0), + deployerCoordinator0 + ); + assertEq( + factory.getDeployerCoordinatorAtIndex(1), + deployerCoordinator1 + ); + assertEq( + factory.getDeployerCoordinatorAtIndex(2), + deployerCoordinator2 + ); - address[] memory hyperdriveDeployers = factory - .getHyperdriveDeployersInRange(0, 2); - assertEq(hyperdriveDeployers.length, 3); - assertEq(hyperdriveDeployers[0], hyperdriveDeployer0); - assertEq(hyperdriveDeployers[1], hyperdriveDeployer1); - assertEq(hyperdriveDeployers[2], hyperdriveDeployer2); + address[] memory deployerCoordinators = factory + .getDeployerCoordinatorsInRange(0, 2); + assertEq(deployerCoordinators.length, 3); + assertEq(deployerCoordinators[0], deployerCoordinator0); + assertEq(deployerCoordinators[1], deployerCoordinator1); + assertEq(deployerCoordinators[2], deployerCoordinator2); - assertEq(factory.isHyperdriveDeployer(hyperdriveDeployer0), true); - assertEq(factory.isHyperdriveDeployer(hyperdriveDeployer1), true); - assertEq(factory.isHyperdriveDeployer(hyperdriveDeployer2), true); + assertEq(factory.isDeployerCoordinator(deployerCoordinator0), true); + assertEq(factory.isDeployerCoordinator(deployerCoordinator1), true); + assertEq(factory.isDeployerCoordinator(deployerCoordinator2), true); vm.prank(alice); - factory.removeHyperdriveDeployer(hyperdriveDeployer0, 0); + factory.removeDeployerCoordinator(deployerCoordinator0, 0); // NOTE: Demonstrate that array order is NOT preserved after removal. - assertEq(factory.getNumberOfHyperdriveDeployers(), 2); - assertEq(factory.getHyperdriveDeployerAtIndex(0), hyperdriveDeployer2); - assertEq(factory.getHyperdriveDeployerAtIndex(1), hyperdriveDeployer1); + assertEq(factory.getNumberOfDeployerCoordinators(), 2); + assertEq( + factory.getDeployerCoordinatorAtIndex(0), + deployerCoordinator2 + ); + assertEq( + factory.getDeployerCoordinatorAtIndex(1), + deployerCoordinator1 + ); - hyperdriveDeployers = factory.getHyperdriveDeployersInRange(0, 1); - assertEq(hyperdriveDeployers.length, 2); - assertEq(hyperdriveDeployers[0], hyperdriveDeployer2); - assertEq(hyperdriveDeployers[1], hyperdriveDeployer1); + deployerCoordinators = factory.getDeployerCoordinatorsInRange(0, 1); + assertEq(deployerCoordinators.length, 2); + assertEq(deployerCoordinators[0], deployerCoordinator2); + assertEq(deployerCoordinators[1], deployerCoordinator1); - assertEq(factory.isHyperdriveDeployer(hyperdriveDeployer0), false); - assertEq(factory.isHyperdriveDeployer(hyperdriveDeployer1), true); - assertEq(factory.isHyperdriveDeployer(hyperdriveDeployer2), true); + assertEq(factory.isDeployerCoordinator(deployerCoordinator0), false); + assertEq(factory.isDeployerCoordinator(deployerCoordinator1), true); + assertEq(factory.isDeployerCoordinator(deployerCoordinator2), true); } } From a60fd8df022a819ecc8b4dcdb28bd81e998c02d5 Mon Sep 17 00:00:00 2001 From: Alex Towle Date: Mon, 22 Jan 2024 14:16:17 -0600 Subject: [PATCH 5/5] Update contracts/src/factory/HyperdriveFactory.sol Co-authored-by: Jonny Rhea <5555162+jrhea@users.noreply.github.com> --- contracts/src/factory/HyperdriveFactory.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/src/factory/HyperdriveFactory.sol b/contracts/src/factory/HyperdriveFactory.sol index c795a3fd7..d8a9f708f 100644 --- a/contracts/src/factory/HyperdriveFactory.sol +++ b/contracts/src/factory/HyperdriveFactory.sol @@ -163,7 +163,7 @@ contract HyperdriveFactory { /// @dev List of all deployer coordinators registered by governance. address[] internal _deployerCoordinators; - /// @notice Mapping to check if a deployer coordinator has been registered' + /// @notice Mapping to check if a deployer coordinator has been registered /// by governance. mapping(address => bool) public isDeployerCoordinator;