Skip to content

Commit 1d96a66

Browse files
authored
Final Polish Pass (#750)
* Added unit tests for `deployTarget` * Finished the deployer coordinator tests * Final polish of `HyperdriveCheckpoint` * Polishing `HyperdriveAdmin` * More polishing * Finished polishing the `HyperdriveFactory` * Add an `InsufficientBalance` error * Addressed nits and jokes from @jrhea
1 parent 5a8e9f7 commit 1d96a66

30 files changed

Lines changed: 807 additions & 197 deletions

contracts/src/deployers/HyperdriveDeployerCoordinator.sol

Lines changed: 57 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ abstract contract HyperdriveDeployerCoordinator is
6363
address public immutable target4Deployer;
6464

6565
/// @notice A mapping from deployer to deployment ID to deployment.
66-
mapping(address => mapping(bytes32 => Deployment)) public deployments;
66+
mapping(address => mapping(bytes32 => Deployment)) internal _deployments;
6767

6868
/// @notice Instantiates the deployer coordinator.
6969
/// @param _coreDeployer The core deployer.
@@ -100,7 +100,7 @@ abstract contract HyperdriveDeployerCoordinator is
100100
bytes32 _salt
101101
) external returns (address) {
102102
// Ensure that the Hyperdrive entrypoint has not already been deployed.
103-
Deployment memory deployment = deployments[msg.sender][_deploymentId];
103+
Deployment memory deployment = _deployments[msg.sender][_deploymentId];
104104
if (deployment.hyperdrive != address(0)) {
105105
revert IHyperdriveDeployerCoordinator.HyperdriveAlreadyDeployed();
106106
}
@@ -132,23 +132,31 @@ abstract contract HyperdriveDeployerCoordinator is
132132
revert IHyperdriveDeployerCoordinator.MismatchedExtraData();
133133
}
134134

135+
// Check the pool configuration to ensure that it's a valid
136+
// configuration for this instance. This was already done when deploying
137+
// target0, but we check again as a precaution in case the check relies
138+
// on state that can change.
139+
_checkPoolConfig(_deployConfig);
140+
135141
// Convert the deploy config into the pool config and set the initial
136142
// vault share price.
137143
IHyperdrive.PoolConfig memory config = _copyPoolConfig(_deployConfig);
138144
config.initialVaultSharePrice = deployment.initialSharePrice;
139145

140-
// Deploy the Hyperdrive instance.
141-
return
142-
IHyperdriveCoreDeployer(coreDeployer).deploy(
143-
config,
144-
_extraData,
145-
deployment.target0,
146-
deployment.target1,
147-
deployment.target2,
148-
deployment.target3,
149-
deployment.target4,
150-
_salt
151-
);
146+
// Deploy the Hyperdrive instance and add it to the deployment struct.
147+
address hyperdrive = IHyperdriveCoreDeployer(coreDeployer).deploy(
148+
config,
149+
_extraData,
150+
deployment.target0,
151+
deployment.target1,
152+
deployment.target2,
153+
deployment.target3,
154+
deployment.target4,
155+
_salt
156+
);
157+
_deployments[msg.sender][_deploymentId].hyperdrive = hyperdrive;
158+
159+
return hyperdrive;
152160
}
153161

154162
/// @notice Deploys a Hyperdrive target instance with the given parameters.
@@ -174,7 +182,7 @@ abstract contract HyperdriveDeployerCoordinator is
174182
// Ensure that the deployment is a fresh deployment. We can check this
175183
// by ensuring that the config hash is not set.
176184
if (
177-
deployments[msg.sender][_deploymentId].configHash != bytes32(0)
185+
_deployments[msg.sender][_deploymentId].configHash != bytes32(0)
178186
) {
179187
revert IHyperdriveDeployerCoordinator.DeploymentAlreadyExists();
180188
}
@@ -204,96 +212,113 @@ abstract contract HyperdriveDeployerCoordinator is
204212
);
205213

206214
// Store the deployment.
207-
deployments[msg.sender][_deploymentId].configHash = configHash;
208-
deployments[msg.sender][_deploymentId]
215+
_deployments[msg.sender][_deploymentId].configHash = configHash;
216+
_deployments[msg.sender][_deploymentId]
209217
.extraDataHash = extraDataHash;
210-
deployments[msg.sender][_deploymentId]
218+
_deployments[msg.sender][_deploymentId]
211219
.initialSharePrice = initialSharePrice;
212-
deployments[msg.sender][_deploymentId].target0 = target;
220+
_deployments[msg.sender][_deploymentId].target0 = target;
213221

214222
return target;
215223
}
216224

217225
// Ensure that the deployment is not a fresh deployment. We can check
218226
// this by ensuring that the config hash is set.
219-
if (deployments[msg.sender][_deploymentId].configHash == bytes32(0)) {
227+
if (_deployments[msg.sender][_deploymentId].configHash == bytes32(0)) {
220228
revert IHyperdriveDeployerCoordinator.DeploymentDoesNotExist();
221229
}
222230

223231
// Ensure that the provided config matches the config hash.
224232
if (
225233
keccak256(abi.encode(_deployConfig)) !=
226-
deployments[msg.sender][_deploymentId].configHash
234+
_deployments[msg.sender][_deploymentId].configHash
227235
) {
228236
revert IHyperdriveDeployerCoordinator.MismatchedConfig();
229237
}
230238

231239
// Ensure that the provided extra data matches the extra data hash.
232240
if (
233241
keccak256(_extraData) !=
234-
deployments[msg.sender][_deploymentId].extraDataHash
242+
_deployments[msg.sender][_deploymentId].extraDataHash
235243
) {
236244
revert IHyperdriveDeployerCoordinator.MismatchedExtraData();
237245
}
238246

247+
// Check the pool configuration to ensure that it's a valid
248+
// configuration for this instance. This was already done when deploying
249+
// target0, but we check again as a precaution in case the check relies
250+
// on state that can change.
251+
_checkPoolConfig(_deployConfig);
252+
239253
// Convert the deploy config into the pool config and set the initial
240254
// vault share price.
241255
IHyperdrive.PoolConfig memory config = _copyPoolConfig(_deployConfig);
242-
config.initialVaultSharePrice = deployments[msg.sender][_deploymentId]
256+
config.initialVaultSharePrice = _deployments[msg.sender][_deploymentId]
243257
.initialSharePrice;
244258

245259
// If the target index is greater than 0, then we're deploying one of
246260
// the other target instances. We don't allow targets to be deployed
247261
// more than once, and their addresses are stored in the deployment
248262
// state.
249263
if (_targetIndex == 1) {
250-
if (deployments[msg.sender][_deploymentId].target1 != address(0)) {
264+
if (_deployments[msg.sender][_deploymentId].target1 != address(0)) {
251265
revert IHyperdriveDeployerCoordinator.TargetAlreadyDeployed();
252266
}
253267
target = IHyperdriveTargetDeployer(target1Deployer).deploy(
254268
config,
255269
_extraData,
256270
_salt
257271
);
258-
deployments[msg.sender][_deploymentId].target1 = target;
272+
_deployments[msg.sender][_deploymentId].target1 = target;
259273
} else if (_targetIndex == 2) {
260-
if (deployments[msg.sender][_deploymentId].target2 != address(0)) {
274+
if (_deployments[msg.sender][_deploymentId].target2 != address(0)) {
261275
revert IHyperdriveDeployerCoordinator.TargetAlreadyDeployed();
262276
}
263277
target = IHyperdriveTargetDeployer(target2Deployer).deploy(
264278
config,
265279
_extraData,
266280
_salt
267281
);
268-
deployments[msg.sender][_deploymentId].target2 = target;
282+
_deployments[msg.sender][_deploymentId].target2 = target;
269283
} else if (_targetIndex == 3) {
270-
if (deployments[msg.sender][_deploymentId].target3 != address(0)) {
284+
if (_deployments[msg.sender][_deploymentId].target3 != address(0)) {
271285
revert IHyperdriveDeployerCoordinator.TargetAlreadyDeployed();
272286
}
273287
target = IHyperdriveTargetDeployer(target3Deployer).deploy(
274288
config,
275289
_extraData,
276290
_salt
277291
);
278-
deployments[msg.sender][_deploymentId].target3 = target;
292+
_deployments[msg.sender][_deploymentId].target3 = target;
279293
} else if (_targetIndex == 4) {
280-
if (deployments[msg.sender][_deploymentId].target4 != address(0)) {
294+
if (_deployments[msg.sender][_deploymentId].target4 != address(0)) {
281295
revert IHyperdriveDeployerCoordinator.TargetAlreadyDeployed();
282296
}
283297
target = IHyperdriveTargetDeployer(target4Deployer).deploy(
284298
config,
285299
_extraData,
286300
_salt
287301
);
288-
deployments[msg.sender][_deploymentId].target4 = target;
302+
_deployments[msg.sender][_deploymentId].target4 = target;
289303
} else {
290304
revert IHyperdriveDeployerCoordinator.InvalidTargetIndex();
291305
}
292306

293307
return target;
294308
}
295309

296-
/// @notice Checks the pool configuration to ensure that it is valid.
310+
/// @notice Gets the deployment specified by the deployer and deployment ID.
311+
/// @param _deployer The deployer.
312+
/// @param _deploymentId The deployment ID.
313+
/// @return The deployment.
314+
function deployments(
315+
address _deployer,
316+
bytes32 _deploymentId
317+
) external view returns (Deployment memory) {
318+
return _deployments[_deployer][_deploymentId];
319+
}
320+
321+
/// @dev Checks the pool configuration to ensure that it is valid.
297322
/// @param _deployConfig The deploy configuration of the Hyperdrive pool.
298323
function _checkPoolConfig(
299324
IHyperdrive.PoolDeployConfig memory _deployConfig

contracts/src/external/HyperdriveTarget0.sol

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,13 @@ abstract contract HyperdriveTarget0 is
203203

204204
/// Getters ///
205205

206+
/// @notice Gets the pauser status of an address.
207+
/// @param _account The account to check.
208+
/// @return The pauser status.
209+
function isPauser(address _account) external view returns (bool) {
210+
_revert(abi.encode(_pausers[_account]));
211+
}
212+
206213
/// @notice Gets the base token.
207214
/// @return The base token.
208215
function baseToken() external view returns (address) {

contracts/src/factory/HyperdriveFactory.sol

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,9 @@ contract HyperdriveFactory is IHyperdriveFactory {
2020
using FixedPointMath for uint256;
2121
using SafeERC20 for ERC20;
2222

23-
/// @notice The resolution for the checkpoint duration. Every checkpoint
24-
/// duration must be a multiple of this resolution.
25-
uint256 public checkpointDurationResolution;
26-
2723
/// @notice The governance address that updates the factory's configuration.
2824
address public governance;
2925

30-
/// @notice The number of times the factory's deployer has been updated.
31-
uint256 public versionCounter = 1;
32-
33-
/// @notice A mapping from deployed Hyperdrive instances to the version
34-
/// of the deployer that deployed them.
35-
mapping(address instance => uint256 version) public isOfficial;
36-
3726
/// @notice The governance address used when new instances are deployed.
3827
address public hyperdriveGovernance;
3928

@@ -46,6 +35,10 @@ contract HyperdriveFactory is IHyperdriveFactory {
4635
/// @notice The fee collector used when new instances are deployed.
4736
address public feeCollector;
4837

38+
/// @notice The resolution for the checkpoint duration. Every checkpoint
39+
/// duration must be a multiple of this resolution.
40+
uint256 public checkpointDurationResolution;
41+
4942
/// @notice The minimum checkpoint duration that can be used by new
5043
/// deployments.
5144
uint256 public minCheckpointDuration;
@@ -133,6 +126,12 @@ contract HyperdriveFactory is IHyperdriveFactory {
133126
/// by governance.
134127
mapping(address => bool) public isDeployerCoordinator;
135128

129+
/// @notice A mapping from deployed Hyperdrive instances to the deployer
130+
/// coordintor that deployed them. This is useful for verifying
131+
/// the bytecode that was used to deploy the instance.
132+
mapping(address instance => address deployCoordinator)
133+
public instancesToDeployerCoordinators;
134+
136135
/// @dev Array of all instances deployed by this factory.
137136
address[] internal _instances;
138137

@@ -615,9 +614,16 @@ contract HyperdriveFactory is IHyperdriveFactory {
615614

616615
// Add this instance to the registry and emit an event with the
617616
// deployment configuration.
618-
isOfficial[address(hyperdrive)] = versionCounter;
617+
instancesToDeployerCoordinators[
618+
address(hyperdrive)
619+
] = _deployerCoordinator;
619620
_config.governance = hyperdriveGovernance;
620-
emit Deployed(versionCounter, address(hyperdrive), _config, _extraData);
621+
emit Deployed(
622+
_deployerCoordinator,
623+
address(hyperdrive),
624+
_config,
625+
_extraData
626+
);
621627

622628
// Add the newly deployed Hyperdrive instance to the registry.
623629
_instances.push(address(hyperdrive));

contracts/src/interfaces/IForwarderFactory.sol renamed to contracts/src/interfaces/IERC20ForwarderFactory.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pragma solidity 0.8.20;
44
import { IERC20Forwarder } from "./IERC20Forwarder.sol";
55
import { IMultiToken } from "./IMultiToken.sol";
66

7-
interface IForwarderFactory {
7+
interface IERC20ForwarderFactory {
88
/// Errors ///
99

1010
error InvalidForwarderAddress();

contracts/src/interfaces/IHyperdrive.sol

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ interface IHyperdrive is
206206
/// @notice Thrown when a permit signature is expired.
207207
error ExpiredDeadline();
208208

209+
/// @notice Thrown when a user doesn't have a sufficient balance to perform
210+
/// an action.
211+
error InsufficientBalance();
212+
209213
/// @notice Thrown when the pool doesn't have sufficient liquidity to
210214
/// complete the trade.
211215
error InsufficientLiquidity(InsufficientLiquidityReason reason);

contracts/src/interfaces/IHyperdriveEvents.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,6 @@ interface IHyperdriveEvents is IMultiTokenEvents {
8585
event GovernanceUpdated(address indexed newGovernance);
8686

8787
event PauserUpdated(address indexed newPauser);
88+
89+
event PauseStatusUpdated(bool isPaused);
8890
}

contracts/src/interfaces/IHyperdriveFactory.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ interface IHyperdriveFactory {
77
/// Events ///
88

99
event Deployed(
10-
uint256 indexed version,
10+
address indexed deployerCoordinator,
1111
address hyperdrive,
1212
IHyperdrive.PoolDeployConfig config,
1313
bytes extraData

contracts/src/interfaces/IHyperdriveRead.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ interface IHyperdriveRead is IMultiTokenRead {
3434

3535
function getPoolInfo() external view returns (IHyperdrive.PoolInfo memory);
3636

37+
function isPauser(address _account) external view returns (bool);
38+
3739
function load(
3840
uint256[] calldata _slots
3941
) external view returns (bytes32[] memory);

contracts/src/internal/HyperdriveAdmin.sol

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,26 +47,39 @@ abstract contract HyperdriveAdmin is IHyperdriveEvents, HyperdriveBase {
4747
/// @dev Allows an authorized address to pause this contract.
4848
/// @param _status True to pause all deposits and false to unpause them.
4949
function _pause(bool _status) internal {
50-
if (!_pausers[msg.sender]) revert IHyperdrive.Unauthorized();
51-
_marketState.isPaused = _status;
50+
// Ensure that the sender is authorized to pause the contract.
51+
if (!_pausers[msg.sender]) {
52+
revert IHyperdrive.Unauthorized();
53+
}
5254

53-
// FIXME: This needs to emit an event.
55+
// Update the paused status and emit an event.
56+
_marketState.isPaused = _status;
57+
emit PauseStatusUpdated(_status);
5458
}
5559

5660
/// @dev Allows governance to change governance.
5761
/// @param _who The new governance address.
5862
function _setGovernance(address _who) internal {
59-
if (msg.sender != _governance) revert IHyperdrive.Unauthorized();
60-
_governance = _who;
63+
// Ensure that the sender is governance.
64+
if (msg.sender != _governance) {
65+
revert IHyperdrive.Unauthorized();
66+
}
6167

68+
// Update the governance address and emit an event.
69+
_governance = _who;
6270
emit GovernanceUpdated(_who);
6371
}
6472

6573
/// @dev Allows governance to change the pauser status of an address.
6674
/// @param who The address to change.
6775
/// @param status The new pauser status.
6876
function _setPauser(address who, bool status) internal {
69-
if (msg.sender != _governance) revert IHyperdrive.Unauthorized();
77+
// Ensure that the sender is governance.
78+
if (msg.sender != _governance) {
79+
revert IHyperdrive.Unauthorized();
80+
}
81+
82+
// Update the pauser status and emit an event.
7083
_pausers[who] = status;
7184
emit PauserUpdated(who);
7285
}

0 commit comments

Comments
 (0)