Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Generalize to many hyperdrive instances (MIlestone 2) #670

Merged
merged 19 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cSpell.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
"degradation",
"delegatecall",
"denormalize",
"deployers",
"Deployers",
"destinatary",
"ecsign",
"EIP",
Expand Down
84 changes: 0 additions & 84 deletions contracts/src/factory/ERC4626HyperdriveFactory.sol

This file was deleted.

145 changes: 90 additions & 55 deletions contracts/src/factory/HyperdriveFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ pragma solidity 0.8.19;

import { IHyperdrive } from "../interfaces/IHyperdrive.sol";
import { IHyperdriveDeployer } from "../interfaces/IHyperdriveDeployer.sol";
import { IHyperdriveTargetDeployer } from "../interfaces/IHyperdriveTargetDeployer.sol";
import { FixedPointMath, ONE } from "../libraries/FixedPointMath.sol";

/// @author DELV
Expand Down Expand Up @@ -39,7 +38,7 @@ contract HyperdriveFactory {
uint256 indexed version,
address hyperdrive,
IHyperdrive.PoolConfig config,
bytes32[] extraData
bytes extraData
);

/// @notice The governance address that updates the factory's configuration.
Expand All @@ -52,18 +51,6 @@ contract HyperdriveFactory {
/// of the deployer that deployed them.
mapping(address instance => uint256 version) public isOfficial;

/// @notice The contract used to deploy new instances of Hyperdrive.
IHyperdriveDeployer public hyperdriveDeployer;

// TODO: When the factory is updated, we should probably have a list of
// target deployers for each instance.
//
/// @notice The contract used to deploy new instances of Hyperdrive.
IHyperdriveTargetDeployer public target0Deployer;

/// @notice The contract used to deploy new instances of Hyperdrive.
IHyperdriveTargetDeployer public target1Deployer;

/// @notice The governance address used when new instances are deployed.
address public hyperdriveGovernance;

Expand Down Expand Up @@ -104,19 +91,20 @@ contract HyperdriveFactory {
IHyperdrive.Fees fees;
/// @dev The upper bounds on the fee parameters that governance can set.
IHyperdrive.Fees maxFees;
/// @dev The Hyperdrive deployer.
IHyperdriveDeployer hyperdriveDeployer;
/// @dev The Hyperdrive target0 deployer.
IHyperdriveTargetDeployer target0Deployer;
/// @dev The Hyperdrive target1 deployer.
IHyperdriveTargetDeployer target1Deployer;
/// @dev The address of the linker factory.
address linkerFactory;
/// @dev The hash of the linker contract's constructor code.
bytes32 linkerCodeHash;
}

// @dev Array of all instances deployed by this factory.
/// @dev List of all hyperdrive deployers onboarded by governance.
address[] internal _hyperdriveDeployers;

/// @notice Mapping to check if an hyperdriveDeployer is in the _hyperdriveDeployers array.
mapping(address => bool) public isHyperdriveDeployer;

/// @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.
Expand Down Expand Up @@ -148,9 +136,6 @@ contract HyperdriveFactory {
hyperdriveGovernance = _factoryConfig.hyperdriveGovernance;
feeCollector = _factoryConfig.feeCollector;
_defaultPausers = _factoryConfig.defaultPausers;
hyperdriveDeployer = _factoryConfig.hyperdriveDeployer;
target0Deployer = _factoryConfig.target0Deployer;
target1Deployer = _factoryConfig.target1Deployer;
linkerFactory = _factoryConfig.linkerFactory;
linkerCodeHash = _factoryConfig.linkerCodeHash;
}
Expand All @@ -161,23 +146,6 @@ contract HyperdriveFactory {
_;
}

/// @notice Allows governance to update the deployer contract.
/// @param newDeployer The new deployment contract.
function updateImplementation(
IHyperdriveDeployer newDeployer
) external onlyGovernance {
// Update the deployer.
require(address(newDeployer) != address(0));
hyperdriveDeployer = newDeployer;

// Increment the version number.
unchecked {
++versionCounter;
}

emit ImplementationUpdated(address(newDeployer));
}

/// @notice Allows governance to transfer the governance role.
/// @param _governance The new governance address.
function updateGovernance(address _governance) external onlyGovernance {
Expand Down Expand Up @@ -246,25 +214,56 @@ contract HyperdriveFactory {
_defaultPausers = _defaultPausers_;
}

/// @notice Allows governance to add a new hyperdrive deployer.
/// @param _hyperdriveDeployer The new hyperdrive deployer.
function addHyperdriveDeployer(
address _hyperdriveDeployer
) external onlyGovernance {
if (isHyperdriveDeployer[_hyperdriveDeployer]) {
revert IHyperdrive.HyperdriveDeployerAlreadyAdded();
}
isHyperdriveDeployer[_hyperdriveDeployer] = true;
_hyperdriveDeployers.push(_hyperdriveDeployer);
}

/// @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,
uint256 _index
) external onlyGovernance {
if (!isHyperdriveDeployer[_hyperdriveDeployer]) {
revert IHyperdrive.HyperdriveDeployerNotAdded();
}
if (_hyperdriveDeployers[_index] != _hyperdriveDeployer) {
revert IHyperdrive.HyperdriveDeployerIndexMismatch();
}
isHyperdriveDeployer[_hyperdriveDeployer] = false;
_hyperdriveDeployers[_index] = _hyperdriveDeployers[
_hyperdriveDeployers.length - 1
];
_hyperdriveDeployers.pop();
}

/// @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 _config The configuration of the Hyperdrive pool.
/// @param _extraData The extra data that contains data necessary for the specific deployer.
/// @param _contribution Base token to call init with
/// @param _apr The apr to call init with
/// @param _initializeExtraData The extra data for the `initialize` call.
/// @param _extraData The extra data is used by some factories
/// @param _pool The ERC4626 compatible yield source. TODO: Remove
/// @return The hyperdrive address deployed.
function deployAndInitialize(
address _hyperdriveDeployer,
IHyperdrive.PoolConfig memory _config,
bytes memory _extraData,
uint256 _contribution,
uint256 _apr,
bytes memory _initializeExtraData,
// TODO: We should use raw bytes instead of bytes32.
bytes32[] memory _extraData,
address _pool
bytes memory _initializeExtraData
) public payable virtual returns (IHyperdrive) {
if (msg.value > 0) {
revert IHyperdrive.NonPayableInitialization();
Expand All @@ -274,7 +273,11 @@ contract HyperdriveFactory {
// sure that the linker factory and linker code hash are set to zero?
// This kind of check makes it clear that the deployer knows the values
// will be overridden.
//

if (!isHyperdriveDeployer[_hyperdriveDeployer]) {
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
Expand All @@ -287,13 +290,7 @@ contract HyperdriveFactory {
_config.governance = address(this);
_config.fees = fees;
IHyperdrive hyperdrive = IHyperdrive(
hyperdriveDeployer.deploy(
_config,
target0Deployer.deploy(_config, _extraData, _pool),
target1Deployer.deploy(_config, _extraData, _pool),
_extraData,
_pool
)
IHyperdriveDeployer(_hyperdriveDeployer).deploy(_config, _extraData)
);
isOfficial[address(hyperdrive)] = versionCounter;
_config.governance = hyperdriveGovernance;
Expand Down Expand Up @@ -378,4 +375,42 @@ contract HyperdriveFactory {
range[i - startIndex] = _instances[i];
}
}

/// @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 instance at the specified index.
/// @param index The index of the instance to get.
/// @return The instance at the specified index.
function getHyperdriveDeployerAtIndex(
uint256 index
) external view returns (address) {
return _hyperdriveDeployers[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(
uint256 startIndex,
uint256 endIndex
) external view returns (address[] memory range) {
// If the indexes are malformed, revert.
if (startIndex > endIndex) {
revert IHyperdrive.InvalidIndexes();
}
if (endIndex > _hyperdriveDeployers.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];
}
}
}
48 changes: 48 additions & 0 deletions contracts/src/instances/ERC4626HyperdriveCoreDeployer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.19;

import { IERC4626 } from "../interfaces/IERC4626.sol";
import { IHyperdrive } from "../interfaces/IHyperdrive.sol";
import { IERC4626HyperdriveDeployer } from "../interfaces/IERC4626HyperdriveDeployer.sol";
import { ERC4626Hyperdrive } from "../instances/ERC4626Hyperdrive.sol";

/// @author DELV
/// @title ERC4626HyperdriveCoreDeployer
/// @notice This is a minimal factory which contains only the logic to deploy
/// the hyperdrive contract and is called by a more complex factory which
/// initializes the Hyperdrive instances and acts as a registry.
/// @custom:disclaimer The language used in this code is for coding convenience
/// only, and is not intended to, and does not, have any
/// particular legal or regulatory significance.
contract ERC4626HyperdriveCoreDeployer is IERC4626HyperdriveDeployer {
/// @notice Deploys a Hyperdrive instance with the given parameters.
/// @param _config The configuration of the Hyperdrive pool.
/// @param _extraData The extra data that contains the sweep targets.
/// @param target0 The address of the first target contract.
/// @param target1 The address of the second target contract.
/// @return The address of the newly deployed ERC4626Hyperdrive Instance
function deploy(
IHyperdrive.PoolConfig memory _config,
bytes memory _extraData,
address target0,
address target1
) external override returns (address) {
(address pool, address[] memory sweepTargets) = abi.decode(
_extraData,
(address, address[])
);

// Deploy the ERC4626Hyperdrive instance.
return (
address(
new ERC4626Hyperdrive(
_config,
target0,
target1,
IERC4626(pool),
sweepTargets
)
)
);
}
}
Loading