• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

delvtech / hyperdrive / 8742767509

18 Apr 2024 06:15PM UTC coverage: 93.371% (+0.03%) from 93.337%
8742767509

Pull #989

github

jalextowle
Addressed review feedback from @jrhea and @mcclurejt
Pull Request #989: Metadata Functions

9 of 9 new or added lines in 9 files covered. (100.0%)

2 existing lines in 1 file now uncovered.

1803 of 1931 relevant lines covered (93.37%)

385199.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.1
/contracts/src/factory/HyperdriveFactory.sol
1
// SPDX-License-Identifier: Apache-2.0
2
pragma solidity 0.8.20;
3

4
import { IHyperdrive } from "../interfaces/IHyperdrive.sol";
5
import { IHyperdriveFactory } from "../interfaces/IHyperdriveFactory.sol";
6
import { IHyperdriveDeployerCoordinator } from "../interfaces/IHyperdriveDeployerCoordinator.sol";
7
import { FixedPointMath, ONE } from "../libraries/FixedPointMath.sol";
8
import { VERSION } from "../libraries/Constants.sol";
9
import { HyperdriveMath } from "../libraries/HyperdriveMath.sol";
10

11
/// @author DELV
12
/// @title HyperdriveFactory
13
/// @notice Deploys hyperdrive instances and initializes them. It also holds a
14
///         registry of all deployed hyperdrive instances.
15
/// @custom:disclaimer The language used in this code is for coding convenience
16
///                    only, and is not intended to, and does not, have any
17
///                    particular legal or regulatory significance.
18
contract HyperdriveFactory is IHyperdriveFactory {
19
    using FixedPointMath for uint256;
20

21
    /// @notice The factory's name.
22
    string public name;
23

24
    /// @dev Signifies an unlocked receive function, used by isReceiveLocked
25
    uint256 private constant RECEIVE_UNLOCKED = 1;
26

27
    /// @dev Signifies a locked receive function, used by isReceiveLocked
28
    uint256 private constant RECEIVE_LOCKED = 2;
29

30
    /// @dev Locks the receive function. This can be used to prevent stuck ether
31
    ///      from ending up in the contract but still allowing refunds to be
32
    ///      received. Defaults to `RECEIVE_LOCKED`
33
    uint256 private receiveLockState = RECEIVE_LOCKED;
34

35
    /// @notice The governance address that updates the factory's configuration.
36
    address public governance;
37

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

41
    /// @notice The linker factory used when new instances are deployed.
42
    address public linkerFactory;
43

44
    /// @notice The linker code hash used when new instances are deployed.
45
    bytes32 public linkerCodeHash;
46

47
    /// @notice The fee collector used when new instances are deployed.
48
    address public feeCollector;
49

50
    /// @notice The sweep collector used when new instances are deployed.
51
    address public sweepCollector;
52

53
    /// @notice The resolution for the checkpoint duration. Every checkpoint
54
    ///         duration must be a multiple of this resolution.
55
    uint256 public checkpointDurationResolution;
56

57
    /// @notice The minimum checkpoint duration that can be used by new
58
    ///         deployments.
59
    uint256 public minCheckpointDuration;
60

61
    /// @notice The maximum checkpoint duration that can be used by new
62
    ///         deployments.
63
    uint256 public maxCheckpointDuration;
64

65
    /// @notice The minimum position duration that can be used by new
66
    ///         deployments.
67
    uint256 public minPositionDuration;
68

69
    /// @notice The maximum position duration that can be used by new
70
    ///         deployments.
71
    uint256 public maxPositionDuration;
72

73
    /// @notice The minimum fixed APR that can be used by new deployments.
74
    uint256 public minFixedAPR;
75

76
    /// @notice The maximum fixed APR that can be used by new deployments.
77
    uint256 public maxFixedAPR;
78

79
    /// @notice The minimum time stretch APR that can be used by new deployments.
80
    uint256 public minTimeStretchAPR;
81

82
    /// @notice The maximum time stretch APR that can be used by new deployments.
83
    uint256 public maxTimeStretchAPR;
84

85
    /// @notice The minimum fee parameters that can be used by new deployments.
86
    IHyperdrive.Fees internal _minFees;
87

88
    /// @notice The maximum fee parameters that can be used by new deployments.
89
    IHyperdrive.Fees internal _maxFees;
90

91
    /// @notice The defaultPausers used when new instances are deployed.
92
    address[] internal _defaultPausers;
93

94
    struct FactoryConfig {
95
        /// @dev The address which can update a factory.
96
        address governance;
97
        /// @dev The address which is set as the governor of hyperdrive.
98
        address hyperdriveGovernance;
99
        /// @dev The default addresses which will be set to have the pauser role.
100
        address[] defaultPausers;
101
        /// @dev The recipient of governance fees from new deployments.
102
        address feeCollector;
103
        /// @dev The recipient of swept tokens from new deployments.
104
        address sweepCollector;
105
        /// @dev The resolution for the checkpoint duration.
106
        uint256 checkpointDurationResolution;
107
        /// @dev The minimum checkpoint duration that can be used in new
108
        ///      deployments.
109
        uint256 minCheckpointDuration;
110
        /// @dev The maximum checkpoint duration that can be used in new
111
        ///      deployments.
112
        uint256 maxCheckpointDuration;
113
        /// @dev The minimum position duration that can be used in new
114
        ///      deployments.
115
        uint256 minPositionDuration;
116
        /// @dev The maximum position duration that can be used in new
117
        ///      deployments.
118
        uint256 maxPositionDuration;
119
        /// @dev The minimum fixed APR that can be used in new deployments.
120
        uint256 minFixedAPR;
121
        /// @dev The maximum fixed APR that can be used in new deployments.
122
        uint256 maxFixedAPR;
123
        /// @dev The minimum time stretch APR that can be used in new
124
        ///      deployments.
125
        uint256 minTimeStretchAPR;
126
        /// @dev The maximum time stretch APR that can be used in new
127
        ///      deployments.
128
        uint256 maxTimeStretchAPR;
129
        /// @dev The lower bound on the fees that can be used in new deployments.
130
        /// @dev Most of the fee parameters are used unmodified; however, the
131
        ///      flat fee parameter is interpreted as the minimum annualized
132
        ///      flat fee. This allows deployers to specify a smaller flat fee
133
        ///      than the minimum for terms shorter than a year and ensures that
134
        ///      they specify a larger flat fee than the minimum for terms
135
        ///      longer than a year.
136
        IHyperdrive.Fees minFees;
137
        /// @dev The upper bound on the fees that can be used in new deployments.
138
        /// @dev Most of the fee parameters are used unmodified; however, the
139
        ///      flat fee parameter is interpreted as the maximum annualized
140
        ///      flat fee. This ensures that deployers specify a smaller flat
141
        ///      fee than the maximum for terms shorter than a year and allows
142
        ///      deployers to specify a larger flat fee than the maximum for
143
        ///      terms longer than a year.
144
        IHyperdrive.Fees maxFees;
145
        /// @dev The address of the linker factory.
146
        address linkerFactory;
147
        /// @dev The hash of the linker contract's constructor code.
148
        bytes32 linkerCodeHash;
149
    }
150

151
    /// @dev List of all deployer coordinators registered by governance.
152
    address[] internal _deployerCoordinators;
153

154
    /// @notice Mapping to check if a deployer coordinator has been registered
155
    ///         by governance.
156
    mapping(address => bool) public isDeployerCoordinator;
157

158
    /// @notice A mapping from deployed Hyperdrive instances to the deployer
159
    ///         coordinator that deployed them. This is useful for verifying
160
    ///         the bytecode that was used to deploy the instance.
161
    mapping(address instance => address deployCoordinator)
162
        public instancesToDeployerCoordinators;
163

164
    /// @dev Array of all instances deployed by this factory.
165
    address[] internal _instances;
166

167
    /// @dev Mapping to check if an instance is in the _instances array.
168
    mapping(address => bool) public isInstance;
169

170
    /// @notice Initializes the factory.
171
    /// @param _factoryConfig Configuration of the Hyperdrive Factory.
172
    /// @param _name The factory's name.
173
    constructor(FactoryConfig memory _factoryConfig, string memory _name) {
174
        // Set the factory's name.
175
        name = _name;
50✔
176

177
        // Ensure that the minimum checkpoint duration is greater than or equal
178
        // to the checkpoint duration resolution and is a multiple of the
179
        // checkpoint duration resolution.
180
        if (
181
            _factoryConfig.minCheckpointDuration <
60✔
182
            _factoryConfig.checkpointDurationResolution ||
183
            _factoryConfig.minCheckpointDuration %
70✔
184
                _factoryConfig.checkpointDurationResolution !=
185
            0
186
        ) {
187
            revert IHyperdriveFactory.InvalidMinCheckpointDuration();
8✔
188
        }
189
        minCheckpointDuration = _factoryConfig.minCheckpointDuration;
44✔
190

191
        // Ensure that the maximum checkpoint duration is greater than or equal
192
        // to the minimum checkpoint duration and is a multiple of the
193
        // checkpoint duration resolution.
194
        if (
195
            _factoryConfig.maxCheckpointDuration <
66✔
196
            _factoryConfig.minCheckpointDuration ||
197
            _factoryConfig.maxCheckpointDuration %
61✔
198
                _factoryConfig.checkpointDurationResolution !=
199
            0
200
        ) {
201
            revert IHyperdriveFactory.InvalidMaxCheckpointDuration();
16✔
202
        }
203
        maxCheckpointDuration = _factoryConfig.maxCheckpointDuration;
38✔
204

205
        // Ensure that the minimum position duration is greater than or equal
206
        // to the maximum checkpoint duration and is a multiple of the
207
        // checkpoint duration resolution.
208
        if (
209
            _factoryConfig.minPositionDuration <
57✔
210
            _factoryConfig.maxCheckpointDuration ||
211
            _factoryConfig.minPositionDuration %
48✔
212
                _factoryConfig.checkpointDurationResolution !=
213
            0
214
        ) {
215
            revert IHyperdriveFactory.InvalidMinPositionDuration();
16✔
216
        }
217
        minPositionDuration = _factoryConfig.minPositionDuration;
26✔
218

219
        // Ensure that the maximum position duration is greater than or equal
220
        // to the minimum position duration and is a multiple of the checkpoint
221
        // duration resolution.
222
        if (
223
            _factoryConfig.maxPositionDuration <
36✔
224
            _factoryConfig.minPositionDuration ||
225
            _factoryConfig.maxPositionDuration %
50✔
226
                _factoryConfig.checkpointDurationResolution !=
227
            0
228
        ) {
229
            revert IHyperdriveFactory.InvalidMaxPositionDuration();
8✔
230
        }
231
        maxPositionDuration = _factoryConfig.maxPositionDuration;
20✔
232

233
        // Ensure that the minimum fixed APR is less than or equal to the
234
        // maximum fixed APR.
235
        if (_factoryConfig.minFixedAPR > _factoryConfig.maxFixedAPR) {
34✔
236
            revert IHyperdriveFactory.InvalidFixedAPR();
12✔
237
        }
238
        minFixedAPR = _factoryConfig.minFixedAPR;
32✔
239
        maxFixedAPR = _factoryConfig.maxFixedAPR;
24✔
240

241
        // Ensure that the minimum time stretch APR is less than or equal to the
242
        // maximum time stretch APR.
243
        if (
244
            _factoryConfig.minTimeStretchAPR > _factoryConfig.maxTimeStretchAPR
22✔
245
        ) {
246
            revert IHyperdriveFactory.InvalidTimeStretchAPR();
24✔
247
        }
248
        minTimeStretchAPR = _factoryConfig.minTimeStretchAPR;
20✔
249
        maxTimeStretchAPR = _factoryConfig.maxTimeStretchAPR;
20✔
250

251
        // Ensure that the max fees are each less than or equal to 100% and set
252
        // the fees.
253
        if (
254
            _factoryConfig.maxFees.curve > ONE ||
100✔
255
            _factoryConfig.maxFees.flat > ONE ||
38✔
256
            _factoryConfig.maxFees.governanceLP > ONE ||
40✔
257
            _factoryConfig.maxFees.governanceZombie > ONE
78✔
258
        ) {
259
            revert IHyperdriveFactory.InvalidMaxFees();
74✔
260
        }
261
        _maxFees = _factoryConfig.maxFees;
12✔
262

263
        // Ensure that the min fees are each less than or equal to the
264
        // corresponding and parameter in the max fees and set the fees.
265
        if (
266
            _factoryConfig.minFees.curve > _factoryConfig.maxFees.curve ||
140✔
267
            _factoryConfig.minFees.flat > _factoryConfig.maxFees.flat ||
20✔
268
            _factoryConfig.minFees.governanceLP >
12✔
269
            _factoryConfig.maxFees.governanceLP ||
270
            _factoryConfig.minFees.governanceZombie >
10✔
271
            _factoryConfig.maxFees.governanceZombie
272
        ) {
273
            revert IHyperdriveFactory.InvalidMinFees();
8✔
274
        }
275
        _minFees = _factoryConfig.minFees;
4✔
276

277
        // Initialize the other parameters.
278
        governance = _factoryConfig.governance;
14✔
279
        hyperdriveGovernance = _factoryConfig.hyperdriveGovernance;
18✔
280
        feeCollector = _factoryConfig.feeCollector;
4✔
281
        sweepCollector = _factoryConfig.sweepCollector;
18✔
282
        _defaultPausers = _factoryConfig.defaultPausers;
16✔
283
        linkerFactory = _factoryConfig.linkerFactory;
56✔
284
        linkerCodeHash = _factoryConfig.linkerCodeHash;
20✔
285
        checkpointDurationResolution = _factoryConfig
14✔
286
            .checkpointDurationResolution;
287
    }
288

289
    /// @dev Ensure that the sender is the governance address.
290
    modifier onlyGovernance() {
291
        if (msg.sender != governance) {
22✔
292
            revert IHyperdriveFactory.Unauthorized();
2✔
293
        }
294
        _;
295
    }
296

297
    /// @notice Allows ether to be sent to the contract. This is gated by a lock
298
    ///         to prevent ether from becoming stuck in the contract.
299
    receive() external payable {
300
        if (receiveLockState == RECEIVE_LOCKED) {
301
            revert IHyperdriveFactory.ReceiveLocked();
302
        }
303
    }
304

305
    /// @notice Gets the factory's version.
306
    /// @return The factory's version.
307
    function version() external pure returns (string memory) {
308
        return VERSION;
2✔
309
    }
310

311
    /// @notice Allows governance to transfer the governance role.
312
    /// @param _governance The new governance address.
313
    function updateGovernance(address _governance) external onlyGovernance {
314
        governance = _governance;
2✔
315
        emit GovernanceUpdated(_governance);
2✔
316
    }
317

318
    /// @notice Allows governance to change the hyperdrive governance address
319
    /// @param _hyperdriveGovernance The new hyperdrive governance address.
320
    function updateHyperdriveGovernance(
321
        address _hyperdriveGovernance
322
    ) external onlyGovernance {
323
        hyperdriveGovernance = _hyperdriveGovernance;
2✔
324
        emit HyperdriveGovernanceUpdated(_hyperdriveGovernance);
2✔
325
    }
326

327
    /// @notice Allows governance to change the linker factory.
328
    /// @param _linkerFactory The new linker factory.
329
    function updateLinkerFactory(
330
        address _linkerFactory
331
    ) external onlyGovernance {
332
        linkerFactory = _linkerFactory;
2✔
333
        emit LinkerFactoryUpdated(_linkerFactory);
2✔
334
    }
335

336
    /// @notice Allows governance to change the linker code hash. This allows
337
    ///         governance to update the implementation of the ERC20Forwarder.
338
    /// @param _linkerCodeHash The new linker code hash.
339
    function updateLinkerCodeHash(
340
        bytes32 _linkerCodeHash
341
    ) external onlyGovernance {
342
        linkerCodeHash = _linkerCodeHash;
2✔
343
        emit LinkerCodeHashUpdated(_linkerCodeHash);
2✔
344
    }
345

346
    /// @notice Allows governance to change the fee collector address.
347
    /// @param _feeCollector The new fee collector address.
348
    function updateFeeCollector(address _feeCollector) external onlyGovernance {
349
        feeCollector = _feeCollector;
2✔
350
        emit FeeCollectorUpdated(_feeCollector);
2✔
351
    }
352

353
    /// @notice Allows governance to change the sweep collector address.
354
    /// @param _sweepCollector The new sweep collector address.
355
    function updateSweepCollector(
356
        address _sweepCollector
357
    ) external onlyGovernance {
358
        sweepCollector = _sweepCollector;
2✔
359
        emit SweepCollectorUpdated(_sweepCollector);
2✔
360
    }
361

362
    /// @notice Allows governance to change the checkpoint duration resolution.
363
    /// @param _checkpointDurationResolution The new checkpoint duration
364
    ///        resolution.
365
    function updateCheckpointDurationResolution(
366
        uint256 _checkpointDurationResolution
367
    ) external onlyGovernance {
368
        // Ensure that the minimum checkpoint duration, maximum checkpoint
369
        // duration, minimum position duration, and maximum position duration
370
        // are all multiples of the checkpoint duration resolution.
371
        if (
372
            minCheckpointDuration % _checkpointDurationResolution != 0 ||
30✔
373
            maxCheckpointDuration % _checkpointDurationResolution != 0 ||
12✔
374
            minPositionDuration % _checkpointDurationResolution != 0 ||
9✔
375
            maxPositionDuration % _checkpointDurationResolution != 0
6✔
376
        ) {
377
            revert IHyperdriveFactory.InvalidCheckpointDurationResolution();
8✔
378
        }
379

380
        // Update the checkpoint duration resolution and emit an event.
381
        checkpointDurationResolution = _checkpointDurationResolution;
2✔
382
        emit CheckpointDurationResolutionUpdated(_checkpointDurationResolution);
2✔
383
    }
384

385
    /// @notice Allows governance to update the maximum checkpoint duration.
386
    /// @param _maxCheckpointDuration The new maximum checkpoint duration.
387
    function updateMaxCheckpointDuration(
388
        uint256 _maxCheckpointDuration
389
    ) external onlyGovernance {
390
        // Ensure that the maximum checkpoint duration is greater than or equal
391
        // to the minimum checkpoint duration and is a multiple of the
392
        // checkpoint duration resolution. Also ensure that the maximum
393
        // checkpoint duration is less than or equal to the minimum position
394
        // duration.
395
        if (
396
            _maxCheckpointDuration < minCheckpointDuration ||
36✔
397
            _maxCheckpointDuration % checkpointDurationResolution != 0 ||
24✔
398
            _maxCheckpointDuration > minPositionDuration
12✔
399
        ) {
400
            revert IHyperdriveFactory.InvalidMaxCheckpointDuration();
6✔
401
        }
402

403
        // Update the maximum checkpoint duration and emit an event.
404
        maxCheckpointDuration = _maxCheckpointDuration;
12✔
405
        emit MaxCheckpointDurationUpdated(_maxCheckpointDuration);
12✔
406
    }
407

408
    /// @notice Allows governance to update the minimum checkpoint duration.
409
    /// @param _minCheckpointDuration The new minimum checkpoint duration.
410
    function updateMinCheckpointDuration(
411
        uint256 _minCheckpointDuration
412
    ) external onlyGovernance {
413
        // Ensure that the minimum checkpoint duration is greater than or equal
414
        // to the checkpoint duration resolution and is a multiple of the
415
        // checkpoint duration resolution. Also ensure that the minimum
416
        // checkpoint duration is less than or equal to the maximum checkpoint
417
        // duration.
418
        if (
419
            _minCheckpointDuration < checkpointDurationResolution ||
36✔
420
            _minCheckpointDuration % checkpointDurationResolution != 0 ||
24✔
421
            _minCheckpointDuration > maxCheckpointDuration
12✔
422
        ) {
423
            revert IHyperdriveFactory.InvalidMinCheckpointDuration();
6✔
424
        }
425

426
        // Update the minimum checkpoint duration and emit an event.
427
        minCheckpointDuration = _minCheckpointDuration;
12✔
428
        emit MinCheckpointDurationUpdated(_minCheckpointDuration);
12✔
429
    }
430

431
    /// @notice Allows governance to update the maximum position duration.
432
    /// @param _maxPositionDuration The new maximum position duration.
433
    function updateMaxPositionDuration(
434
        uint256 _maxPositionDuration
435
    ) external onlyGovernance {
436
        // Ensure that the maximum position duration is greater than or equal
437
        // to the minimum position duration and is a multiple of the checkpoint
438
        // duration resolution.
439
        if (
440
            _maxPositionDuration < minPositionDuration ||
24✔
441
            _maxPositionDuration % checkpointDurationResolution != 0
21✔
442
        ) {
443
            revert IHyperdriveFactory.InvalidMaxPositionDuration();
4✔
444
        }
445

446
        // Update the maximum position duration and emit an event.
447
        maxPositionDuration = _maxPositionDuration;
12✔
448
        emit MaxPositionDurationUpdated(_maxPositionDuration);
12✔
449
    }
450

451
    /// @notice Allows governance to update the minimum position duration.
452
    /// @param _minPositionDuration The new minimum position duration.
453
    function updateMinPositionDuration(
454
        uint256 _minPositionDuration
455
    ) external onlyGovernance {
456
        // Ensure that the minimum position duration is greater than or equal
457
        // to the maximum checkpoint duration and is a multiple of the
458
        // checkpoint duration resolution. Also ensure that the minimum position
459
        // duration is less than or equal to the maximum position duration.
460
        if (
461
            _minPositionDuration < maxCheckpointDuration ||
36✔
462
            _minPositionDuration % checkpointDurationResolution != 0 ||
24✔
463
            _minPositionDuration > maxPositionDuration
12✔
464
        ) {
465
            revert IHyperdriveFactory.InvalidMinPositionDuration();
6✔
466
        }
467

468
        // Update the minimum position duration and emit an event.
469
        minPositionDuration = _minPositionDuration;
12✔
470
        emit MinPositionDurationUpdated(_minPositionDuration);
12✔
471
    }
472

473
    /// @notice Allows governance to update the maximum fixed APR.
474
    /// @param _maxFixedAPR The new maximum fixed APR.
475
    function updateMaxFixedAPR(uint256 _maxFixedAPR) external onlyGovernance {
476
        // Ensure that the maximum fixed APR is greater than or equal to the
477
        // minimum fixed APR.
478
        if (_maxFixedAPR < minFixedAPR) {
4✔
479
            revert IHyperdriveFactory.InvalidMaxFixedAPR();
2✔
480
        }
481

482
        // Update the maximum fixed APR and emit an event.
483
        maxFixedAPR = _maxFixedAPR;
2✔
484
        emit MaxFixedAPRUpdated(_maxFixedAPR);
2✔
485
    }
486

487
    /// @notice Allows governance to update the minimum fixed APR.
488
    /// @param _minFixedAPR The new minimum fixed APR.
489
    function updateMinFixedAPR(uint256 _minFixedAPR) external onlyGovernance {
490
        // Ensure that the minimum fixed APR is less than or equal to the
491
        // maximum fixed APR.
492
        if (_minFixedAPR > maxFixedAPR) {
4✔
493
            revert IHyperdriveFactory.InvalidMinFixedAPR();
2✔
494
        }
495

496
        // Update the minimum fixed APR and emit an event.
497
        minFixedAPR = _minFixedAPR;
2✔
498
        emit MinFixedAPRUpdated(_minFixedAPR);
2✔
499
    }
500

501
    /// @notice Allows governance to update the maximum time stretch APR.
502
    /// @param _maxTimeStretchAPR The new maximum time stretch APR.
503
    function updateMaxTimeStretchAPR(
504
        uint256 _maxTimeStretchAPR
505
    ) external onlyGovernance {
506
        // Ensure that the maximum time stretch APR is greater than or equal
507
        // to the minimum time stretch APR.
508
        if (_maxTimeStretchAPR < minTimeStretchAPR) {
8✔
509
            revert IHyperdriveFactory.InvalidMaxTimeStretchAPR();
2✔
510
        }
511

512
        // Update the maximum time stretch APR and emit an event.
513
        maxTimeStretchAPR = _maxTimeStretchAPR;
6✔
514
        emit MaxTimeStretchAPRUpdated(_maxTimeStretchAPR);
6✔
515
    }
516

517
    /// @notice Allows governance to update the minimum time stretch APR.
518
    /// @param _minTimeStretchAPR The new minimum time stretch APR.
519
    function updateMinTimeStretchAPR(
520
        uint256 _minTimeStretchAPR
521
    ) external onlyGovernance {
522
        // Ensure that the minimum time stretch APR is less than or equal
523
        // to the maximum time stretch APR.
524
        if (_minTimeStretchAPR > maxTimeStretchAPR) {
16✔
525
            revert IHyperdriveFactory.InvalidMinTimeStretchAPR();
2✔
526
        }
527

528
        // Update the minimum time stretch APR and emit an event.
529
        minTimeStretchAPR = _minTimeStretchAPR;
14✔
530
        emit MinTimeStretchAPRUpdated(_minTimeStretchAPR);
14✔
531
    }
532

533
    /// @notice Allows governance to update the maximum fee parameters.
534
    /// @param __maxFees The new maximum fee parameters.
535
    function updateMaxFees(
536
        IHyperdrive.Fees calldata __maxFees
537
    ) external onlyGovernance {
538
        // Ensure that the max fees are each less than or equal to 100% and that
539
        // the max fees are each greater than or equal to the corresponding min
540
        // fee.
541
        IHyperdrive.Fees memory minFees_ = _minFees;
28✔
542
        if (
543
            __maxFees.curve > ONE ||
126✔
544
            __maxFees.flat > ONE ||
26✔
545
            __maxFees.governanceLP > ONE ||
24✔
546
            __maxFees.governanceZombie > ONE ||
22✔
547
            __maxFees.curve < minFees_.curve ||
20✔
548
            __maxFees.flat < minFees_.flat ||
18✔
549
            __maxFees.governanceLP < minFees_.governanceLP ||
16✔
550
            __maxFees.governanceZombie < minFees_.governanceZombie
14✔
551
        ) {
552
            revert IHyperdriveFactory.InvalidMaxFees();
16✔
553
        }
554

555
        // Update the max fees and emit an event.
556
        _maxFees = __maxFees;
12✔
557
        emit MaxFeesUpdated(__maxFees);
12✔
558
    }
559

560
    /// @notice Allows governance to update the minimum fee parameters.
561
    /// @param __minFees The new minimum fee parameters.
562
    function updateMinFees(
563
        IHyperdrive.Fees calldata __minFees
564
    ) external onlyGovernance {
565
        // Ensure that the min fees are each less than or the corresponding max
566
        // fee.
567
        IHyperdrive.Fees memory maxFees_ = _maxFees;
20✔
568
        if (
569
            __minFees.curve > maxFees_.curve ||
50✔
570
            __minFees.flat > maxFees_.flat ||
18✔
571
            __minFees.governanceLP > maxFees_.governanceLP ||
16✔
572
            __minFees.governanceZombie > maxFees_.governanceZombie
14✔
573
        ) {
574
            revert IHyperdriveFactory.InvalidMinFees();
8✔
575
        }
576

577
        // Update the max fees and emit an event.
578
        _minFees = __minFees;
12✔
579
        emit MinFeesUpdated(__minFees);
12✔
580
    }
581

582
    /// @notice Allows governance to change the default pausers.
583
    /// @param _defaultPausers_ The new list of default pausers.
584
    function updateDefaultPausers(
585
        address[] calldata _defaultPausers_
586
    ) external onlyGovernance {
587
        _defaultPausers = _defaultPausers_;
2✔
588
        emit DefaultPausersUpdated(_defaultPausers_);
2✔
589
    }
590

591
    /// @notice Allows governance to add a new deployer coordinator.
592
    /// @param _deployerCoordinator The new deployer coordinator.
593
    function addDeployerCoordinator(
594
        address _deployerCoordinator
595
    ) external onlyGovernance {
596
        if (isDeployerCoordinator[_deployerCoordinator]) {
1,683✔
597
            revert IHyperdriveFactory.DeployerCoordinatorAlreadyAdded();
2✔
598
        }
599
        isDeployerCoordinator[_deployerCoordinator] = true;
3,364✔
600
        _deployerCoordinators.push(_deployerCoordinator);
3,364✔
601
        emit DeployerCoordinatorAdded(_deployerCoordinator);
3,364✔
602
    }
603

604
    /// @notice Allows governance to remove an existing deployer coordinator.
605
    /// @param _deployerCoordinator The deployer coordinator to remove.
606
    /// @param _index The index of the deployer coordinator to remove.
607
    function removeDeployerCoordinator(
608
        address _deployerCoordinator,
609
        uint256 _index
610
    ) external onlyGovernance {
611
        if (!isDeployerCoordinator[_deployerCoordinator]) {
12✔
612
            revert IHyperdriveFactory.DeployerCoordinatorNotAdded();
2✔
613
        }
614
        if (_deployerCoordinators[_index] != _deployerCoordinator) {
10✔
615
            revert IHyperdriveFactory.DeployerCoordinatorIndexMismatch();
2✔
616
        }
617
        isDeployerCoordinator[_deployerCoordinator] = false;
8✔
618
        _deployerCoordinators[_index] = _deployerCoordinators[
8✔
619
            _deployerCoordinators.length - 1
620
        ];
621
        _deployerCoordinators.pop();
8✔
622
        emit DeployerCoordinatorRemoved(_deployerCoordinator);
8✔
623
    }
624

625
    /// @notice Deploys a Hyperdrive instance with the factory's configuration.
626
    /// @dev This function is declared as payable to allow payable overrides
627
    ///      to accept ether on initialization, but payability is not supported
628
    ///      by default.
629
    /// @param _deploymentId The deployment ID to use when deploying the pool.
630
    /// @param _deployerCoordinator The deployer coordinator to use in this
631
    ///        deployment.
632
    /// @param _config The configuration of the Hyperdrive pool.
633
    /// @param _extraData The extra data that contains data necessary for the
634
    ///        specific deployer.
635
    /// @param _contribution The contribution amount in base to the pool.
636
    /// @param _fixedAPR The fixed APR used to initialize the pool.
637
    /// @param _timeStretchAPR The time stretch APR used to initialize the pool.
638
    /// @param _options The options for the `initialize` call.
639
    /// @param _salt The create2 salt to use for the deployment.
640
    /// @return The hyperdrive address deployed.
641
    function deployAndInitialize(
642
        bytes32 _deploymentId,
643
        address _deployerCoordinator,
644
        IHyperdrive.PoolDeployConfig memory _config,
645
        bytes memory _extraData,
646
        uint256 _contribution,
647
        uint256 _fixedAPR,
648
        uint256 _timeStretchAPR,
649
        IHyperdrive.Options memory _options,
650
        bytes32 _salt
651
    ) external payable returns (IHyperdrive) {
652
        // Ensure that the deployer coordinator has been registered.
653
        if (!isDeployerCoordinator[_deployerCoordinator]) {
3,494✔
654
            revert IHyperdriveFactory.InvalidDeployerCoordinator();
2✔
655
        }
656

657
        // Override the config values to the default values set by governance
658
        // and ensure that the config is valid.
659
        _overrideConfig(_config, _fixedAPR, _timeStretchAPR);
3,492✔
660

661
        // Deploy the Hyperdrive instance with the specified deployer
662
        // coordinator.
663
        IHyperdrive hyperdrive = IHyperdrive(
5,163✔
664
            IHyperdriveDeployerCoordinator(_deployerCoordinator).deploy(
665
                // NOTE: We hash the deployer's address into the deployment ID
666
                // to prevent their deployment from being front-run.
667
                keccak256(abi.encode(msg.sender, _deploymentId)),
668
                _config,
669
                _extraData,
670
                _salt
671
            )
672
        );
673

674
        // Add this instance to the registry and emit an event with the
675
        // deployment configuration.
676
        instancesToDeployerCoordinators[
3,442✔
677
            address(hyperdrive)
678
        ] = _deployerCoordinator;
679
        _config.governance = hyperdriveGovernance;
3,442✔
680
        emit Deployed(
3,442✔
681
            _deployerCoordinator,
682
            address(hyperdrive),
683
            _config,
684
            _extraData
685
        );
686

687
        // Add the newly deployed Hyperdrive instance to the registry.
688
        _instances.push(address(hyperdrive));
3,442✔
689
        isInstance[address(hyperdrive)] = true;
3,442✔
690

691
        // Initialize the Hyperdrive instance.
692
        receiveLockState = RECEIVE_UNLOCKED;
3,442✔
693
        IHyperdriveDeployerCoordinator(_deployerCoordinator).initialize{
3,442✔
694
            value: msg.value
695
        }(
696
            // NOTE: We hash the deployer's address into the deployment ID
697
            // to prevent their deployment from being front-run.
698
            keccak256(abi.encode(msg.sender, _deploymentId)),
699
            msg.sender,
700
            _contribution,
701
            _fixedAPR,
702
            _options
703
        );
704
        receiveLockState = RECEIVE_LOCKED;
3,436✔
705

706
        // Set the default pausers and transfer the governance status to the
707
        // hyperdrive governance address.
708
        for (uint256 i = 0; i < _defaultPausers.length; ) {
6,872✔
709
            hyperdrive.setPauser(_defaultPausers[i], true);
3,436✔
710
            unchecked {
711
                ++i;
3,436✔
712
            }
713
        }
714
        hyperdrive.setGovernance(hyperdriveGovernance);
3,436✔
715

716
        // Refund any excess ether that was sent to this contract.
717
        uint256 refund = address(this).balance;
3,436✔
718
        if (refund > 0) {
3,436✔
719
            (bool success, ) = payable(msg.sender).call{ value: refund }("");
3✔
720
            if (!success) {
2✔
UNCOV
721
                revert IHyperdriveFactory.TransferFailed();
×
722
            }
723
        }
724

725
        return hyperdrive;
3,436✔
726
    }
727

728
    /// @notice Deploys a Hyperdrive target with the factory's configuration.
729
    /// @param _deploymentId The deployment ID to use when deploying the pool.
730
    /// @param _deployerCoordinator The deployer coordinator to use in this
731
    ///        deployment.
732
    /// @param _config The configuration of the Hyperdrive pool.
733
    /// @param _extraData The extra data that contains data necessary for the
734
    ///        specific deployer.
735
    /// @param _fixedAPR The fixed APR used to initialize the pool.
736
    /// @param _timeStretchAPR The time stretch APR used to initialize the pool.
737
    /// @param _targetIndex The index of the target to deploy.
738
    /// @param _salt The create2 salt to use for the deployment.
739
    /// @return The target address deployed.
740
    function deployTarget(
741
        bytes32 _deploymentId,
742
        address _deployerCoordinator,
743
        IHyperdrive.PoolDeployConfig memory _config,
744
        bytes memory _extraData,
745
        uint256 _fixedAPR,
746
        uint256 _timeStretchAPR,
747
        uint256 _targetIndex,
748
        bytes32 _salt
749
    ) external returns (address) {
750
        // Ensure that the deployer coordinator has been registered.
751
        if (!isDeployerCoordinator[_deployerCoordinator]) {
17,222✔
UNCOV
752
            revert IHyperdriveFactory.InvalidDeployerCoordinator();
×
753
        }
754

755
        // Override the config values to the default values set by governance
756
        // and ensure that the config is valid.
757
        _overrideConfig(_config, _fixedAPR, _timeStretchAPR);
17,222✔
758

759
        // Deploy the target instance with the specified deployer coordinator.
760
        address target = IHyperdriveDeployerCoordinator(_deployerCoordinator)
25,815✔
761
            .deployTarget(
762
                // NOTE: We hash the deployer's address into the deployment ID
763
                // to prevent their deployment from being front-run.
764
                keccak256(abi.encode(msg.sender, _deploymentId)),
765
                _config,
766
                _extraData,
767
                _targetIndex,
768
                _salt
769
            );
770

771
        return target;
17,210✔
772
    }
773

774
    /// @notice Gets the max fees.
775
    /// @return The max fees.
776
    function maxFees() external view returns (IHyperdrive.Fees memory) {
777
        return _maxFees;
16✔
778
    }
779

780
    /// @notice Gets the min fees.
781
    /// @return The min fees.
782
    function minFees() external view returns (IHyperdrive.Fees memory) {
783
        return _minFees;
16✔
784
    }
785

786
    /// @notice Gets the default pausers.
787
    /// @return The default pausers.
788
    function defaultPausers() external view returns (address[] memory) {
789
        return _defaultPausers;
4✔
790
    }
791

792
    /// @notice Gets the number of instances deployed by this factory.
793
    /// @return The number of instances deployed by this factory.
794
    function getNumberOfInstances() external view returns (uint256) {
795
        return _instances.length;
210✔
796
    }
797

798
    /// @notice Gets the instance at the specified index.
799
    /// @param index The index of the instance to get.
800
    /// @return The instance at the specified index.
801
    function getInstanceAtIndex(uint256 index) external view returns (address) {
802
        return _instances[index];
1,098✔
803
    }
804

805
    /// @notice Returns the _instances array according to specified indices.
806
    /// @param startIndex The starting index of the instances to get.
807
    /// @param endIndex The ending index of the instances to get.
808
    /// @return range The resulting custom portion of the _instances array.
809
    function getInstancesInRange(
810
        uint256 startIndex,
811
        uint256 endIndex
812
    ) external view returns (address[] memory range) {
813
        // If the indexes are malformed, revert.
814
        if (startIndex > endIndex) {
210✔
815
            revert IHyperdriveFactory.InvalidIndexes();
2✔
816
        }
817
        if (endIndex >= _instances.length) {
208✔
818
            revert IHyperdriveFactory.EndIndexTooLarge();
2✔
819
        }
820

821
        // Return the range of instances.
822
        range = new address[](endIndex - startIndex + 1);
206✔
823
        for (uint256 i = startIndex; i <= endIndex; i++) {
729✔
824
            unchecked {
825
                range[i - startIndex] = _instances[i];
420✔
826
            }
827
        }
828
    }
829

830
    /// @notice Gets the number of deployer coordinators registered in this
831
    ///         factory.
832
    /// @return The number of deployer coordinators deployed by this factory.
833
    function getNumberOfDeployerCoordinators() external view returns (uint256) {
834
        return _deployerCoordinators.length;
212✔
835
    }
836

837
    /// @notice Gets the deployer coordinator at the specified index.
838
    /// @param index The index of the deployer coordinator to get.
839
    /// @return The deployer coordinator at the specified index.
840
    function getDeployerCoordinatorAtIndex(
841
        uint256 index
842
    ) external view returns (address) {
843
        return _deployerCoordinators[index];
1,064✔
844
    }
845

846
    /// @notice Returns the deployer coordinators with an index between the
847
    ///         starting and ending indexes (inclusive).
848
    /// @param startIndex The starting index (inclusive).
849
    /// @param endIndex The ending index (inclusive).
850
    /// @return range The deployer coordinators within the specified range.
851
    function getDeployerCoordinatorsInRange(
852
        uint256 startIndex,
853
        uint256 endIndex
854
    ) external view returns (address[] memory range) {
855
        // If the indexes are malformed, revert.
856
        if (startIndex > endIndex) {
212✔
857
            revert IHyperdriveFactory.InvalidIndexes();
2✔
858
        }
859
        if (endIndex >= _deployerCoordinators.length) {
210✔
860
            revert IHyperdriveFactory.EndIndexTooLarge();
2✔
861
        }
862

863
        // Return the range of instances.
864
        range = new address[](endIndex - startIndex + 1);
208✔
865
        for (uint256 i = startIndex; i <= endIndex; i++) {
720✔
866
            unchecked {
867
                range[i - startIndex] = _deployerCoordinators[i];
408✔
868
            }
869
        }
870
    }
871

872
    /// @dev Overrides the config values to the default values set by
873
    ///      governance. In the process of overriding these parameters, this
874
    ///      verifies that the specified config is valid.
875
    /// @param _config The config to override.
876
    /// @param _fixedAPR The fixed APR to use in the override.
877
    /// @param _timeStretchAPR The time stretch APR to use in the override.
878
    function _overrideConfig(
879
        IHyperdrive.PoolDeployConfig memory _config,
880
        uint256 _fixedAPR,
881
        uint256 _timeStretchAPR
882
    ) internal view {
883
        // Ensure that the specified checkpoint duration is within the minimum
884
        // and maximum checkpoint durations and is a multiple of the checkpoint
885
        // duration resolution.
886
        if (
887
            _config.checkpointDuration < minCheckpointDuration ||
41,428✔
888
            _config.checkpointDuration > maxCheckpointDuration ||
20,712✔
889
            _config.checkpointDuration % checkpointDurationResolution != 0
31,065✔
890
        ) {
891
            revert IHyperdriveFactory.InvalidCheckpointDuration();
6✔
892
        }
893

894
        // Ensure that the specified checkpoint duration is within the minimum
895
        // and maximum position durations and is a multiple of the specified
896
        // checkpoint duration.
897
        if (
898
            _config.positionDuration < minPositionDuration ||
41,416✔
899
            _config.positionDuration > maxPositionDuration ||
20,706✔
900
            _config.positionDuration % _config.checkpointDuration != 0
31,056✔
901
        ) {
902
            revert IHyperdriveFactory.InvalidPositionDuration();
6✔
903
        }
904

905
        // Ensure that the specified fees are within the minimum and maximum
906
        // fees. The flat fee is annualized so that it is consistent across all
907
        // term lengths.
908
        if (
909
            _config.fees.curve > _maxFees.curve ||
93,159✔
910
            // NOTE: Round up here to make the check stricter
911
            ///      since truthy values causes revert.
912
            _config.fees.flat.mulDivUp(365 days, _config.positionDuration) >
31,050✔
913
            _maxFees.flat ||
914
            _config.fees.governanceLP > _maxFees.governanceLP ||
20,694✔
915
            _config.fees.governanceZombie > _maxFees.governanceZombie ||
20,692✔
916
            _config.fees.curve < _minFees.curve ||
20,690✔
917
            // NOTE: Round down here to make the check stricter
918
            ///      since truthy values causes revert.
919
            _config.fees.flat.mulDivDown(365 days, _config.positionDuration) <
31,032✔
920
            _minFees.flat ||
921
            _config.fees.governanceLP < _minFees.governanceLP ||
20,682✔
922
            _config.fees.governanceZombie < _minFees.governanceZombie
20,680✔
923
        ) {
924
            revert IHyperdriveFactory.InvalidFees();
24✔
925
        }
926

927
        // Ensure that specified fixed APR is within the minimum and maximum
928
        // fixed APRs.
929
        if (_fixedAPR < minFixedAPR || _fixedAPR > maxFixedAPR) {
41,355✔
930
            revert IHyperdriveFactory.InvalidFixedAPR();
4✔
931
        }
932

933
        // Calculate the time stretch using the provided APR and ensure that
934
        // the time stretch falls within a safe range and the guards specified
935
        // by governance.
936
        uint256 lowerBound = _fixedAPR.divDown(2e18).max(0.005e18);
31,011✔
937
        if (
938
            _timeStretchAPR < minTimeStretchAPR.max(lowerBound) ||
41,348✔
939
            _timeStretchAPR >
20,668✔
940
            maxTimeStretchAPR.min(_fixedAPR.max(lowerBound).mulDown(2e18))
20,668✔
941
        ) {
942
            revert IHyperdriveFactory.InvalidTimeStretchAPR();
12✔
943
        }
944
        uint256 timeStretch = HyperdriveMath.calculateTimeStretch(
30,993✔
945
            _timeStretchAPR,
946
            _config.positionDuration
947
        );
948

949
        // Ensure that the linker factory, linker code hash, fee collector, and
950
        // governance addresses are set to the expected values. This ensures
951
        // that the deployer is aware of the correct values. The time stretch
952
        // should be set to zero to signal that the deployer is aware that it
953
        // will be overwritten.
954
        if (
955
            _config.linkerFactory != linkerFactory ||
72,317✔
956
            _config.linkerCodeHash != linkerCodeHash ||
20,660✔
957
            _config.feeCollector != feeCollector ||
20,658✔
958
            _config.sweepCollector != sweepCollector ||
20,656✔
959
            _config.governance != hyperdriveGovernance ||
20,654✔
960
            _config.timeStretch != 0
20,652✔
961
        ) {
962
            revert IHyperdriveFactory.InvalidDeployConfig();
10✔
963
        }
964

965
        // Override the config values to the default values set by governance.
966
        // The factory assumes the governance role during deployment so that it
967
        // can set up some initial values; however the governance role will
968
        // ultimately be transferred to the hyperdrive governance address.
969
        _config.governance = address(this);
20,652✔
970
        _config.timeStretch = timeStretch;
20,652✔
971
    }
972
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc