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

delvtech / hyperdrive / 8732730472

18 Apr 2024 05:12AM UTC coverage: 93.378% (+0.04%) from 93.337%
8732730472

Pull #989

github

web-flow
Merge e5c94423d into 78a1b5959
Pull Request #989: Metadata Functions

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

52 existing lines in 7 files now uncovered.

1805 of 1933 relevant lines covered (93.38%)

383731.12 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 { HyperdriveMath } from "../libraries/HyperdriveMath.sol";
9

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

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

23
    /// @notice The factory's version.
24
    string public constant version = "v1.0.0";
25

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

376
        // Update the checkpoint duration resolution and emit an event.
377
        checkpointDurationResolution = _checkpointDurationResolution;
2✔
378
        emit CheckpointDurationResolutionUpdated(_checkpointDurationResolution);
2✔
379
    }
380

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

399
        // Update the maximum checkpoint duration and emit an event.
400
        maxCheckpointDuration = _maxCheckpointDuration;
12✔
401
        emit MaxCheckpointDurationUpdated(_maxCheckpointDuration);
12✔
402
    }
403

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

422
        // Update the minimum checkpoint duration and emit an event.
423
        minCheckpointDuration = _minCheckpointDuration;
12✔
424
        emit MinCheckpointDurationUpdated(_minCheckpointDuration);
12✔
425
    }
426

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

442
        // Update the maximum position duration and emit an event.
443
        maxPositionDuration = _maxPositionDuration;
12✔
444
        emit MaxPositionDurationUpdated(_maxPositionDuration);
12✔
445
    }
446

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

464
        // Update the minimum position duration and emit an event.
465
        minPositionDuration = _minPositionDuration;
12✔
466
        emit MinPositionDurationUpdated(_minPositionDuration);
12✔
467
    }
468

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

478
        // Update the maximum fixed APR and emit an event.
479
        maxFixedAPR = _maxFixedAPR;
2✔
480
        emit MaxFixedAPRUpdated(_maxFixedAPR);
2✔
481
    }
482

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

492
        // Update the minimum fixed APR and emit an event.
493
        minFixedAPR = _minFixedAPR;
2✔
494
        emit MinFixedAPRUpdated(_minFixedAPR);
2✔
495
    }
496

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

508
        // Update the maximum time stretch APR and emit an event.
509
        maxTimeStretchAPR = _maxTimeStretchAPR;
6✔
510
        emit MaxTimeStretchAPRUpdated(_maxTimeStretchAPR);
6✔
511
    }
512

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

524
        // Update the minimum time stretch APR and emit an event.
525
        minTimeStretchAPR = _minTimeStretchAPR;
14✔
526
        emit MinTimeStretchAPRUpdated(_minTimeStretchAPR);
14✔
527
    }
528

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

551
        // Update the max fees and emit an event.
552
        _maxFees = __maxFees;
12✔
553
        emit MaxFeesUpdated(__maxFees);
12✔
554
    }
555

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

573
        // Update the max fees and emit an event.
574
        _minFees = __minFees;
12✔
575
        emit MinFeesUpdated(__minFees);
12✔
576
    }
577

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

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

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

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

653
        // Override the config values to the default values set by governance
654
        // and ensure that the config is valid.
655
        _overrideConfig(_config, _fixedAPR, _timeStretchAPR);
3,398✔
656

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

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

683
        // Add the newly deployed Hyperdrive instance to the registry.
684
        _instances.push(address(hyperdrive));
3,348✔
685
        isInstance[address(hyperdrive)] = true;
3,348✔
686

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

702
        // Set the default pausers and transfer the governance status to the
703
        // hyperdrive governance address.
704
        for (uint256 i = 0; i < _defaultPausers.length; ) {
6,684✔
705
            hyperdrive.setPauser(_defaultPausers[i], true);
3,342✔
706
            unchecked {
707
                ++i;
3,342✔
708
            }
709
        }
710
        hyperdrive.setGovernance(hyperdriveGovernance);
3,342✔
711

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

721
        return hyperdrive;
3,342✔
722
    }
723

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

751
        // Override the config values to the default values set by governance
752
        // and ensure that the config is valid.
753
        _overrideConfig(_config, _fixedAPR, _timeStretchAPR);
16,752✔
754

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

767
        return target;
16,740✔
768
    }
769

770
    /// @notice Gets the max fees.
771
    /// @return The max fees.
772
    function maxFees() external view returns (IHyperdrive.Fees memory) {
773
        return _maxFees;
16✔
774
    }
775

776
    /// @notice Gets the min fees.
777
    /// @return The min fees.
778
    function minFees() external view returns (IHyperdrive.Fees memory) {
779
        return _minFees;
16✔
780
    }
781

782
    /// @notice Gets the default pausers.
783
    /// @return The default pausers.
784
    function defaultPausers() external view returns (address[] memory) {
785
        return _defaultPausers;
4✔
786
    }
787

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

794
    /// @notice Gets the instance at the specified index.
795
    /// @param index The index of the instance to get.
796
    /// @return The instance at the specified index.
797
    function getInstanceAtIndex(uint256 index) external view returns (address) {
798
        return _instances[index];
1,094✔
799
    }
800

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

817
        // Return the range of instances.
818
        range = new address[](endIndex - startIndex + 1);
206✔
819
        for (uint256 i = startIndex; i <= endIndex; i++) {
717✔
820
            unchecked {
821
                range[i - startIndex] = _instances[i];
408✔
822
            }
823
        }
824
    }
825

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

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

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

859
        // Return the range of instances.
860
        range = new address[](endIndex - startIndex + 1);
208✔
861
        for (uint256 i = startIndex; i <= endIndex; i++) {
710✔
862
            unchecked {
863
                range[i - startIndex] = _deployerCoordinators[i];
398✔
864
            }
865
        }
866
    }
867

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

890
        // Ensure that the specified checkpoint duration is within the minimum
891
        // and maximum position durations and is a multiple of the specified
892
        // checkpoint duration.
893
        if (
894
            _config.positionDuration < minPositionDuration ||
40,288✔
895
            _config.positionDuration > maxPositionDuration ||
20,142✔
896
            _config.positionDuration % _config.checkpointDuration != 0
30,210✔
897
        ) {
898
            revert IHyperdriveFactory.InvalidPositionDuration();
6✔
899
        }
900

901
        // Ensure that the specified fees are within the minimum and maximum
902
        // fees. The flat fee is annualized so that it is consistent across all
903
        // term lengths.
904
        if (
905
            _config.fees.curve > _maxFees.curve ||
90,621✔
906
            // NOTE: Round up here to make the check stricter
907
            ///      since truthy values causes revert.
908
            _config.fees.flat.mulDivUp(365 days, _config.positionDuration) >
30,204✔
909
            _maxFees.flat ||
910
            _config.fees.governanceLP > _maxFees.governanceLP ||
20,130✔
911
            _config.fees.governanceZombie > _maxFees.governanceZombie ||
20,128✔
912
            _config.fees.curve < _minFees.curve ||
20,126✔
913
            // NOTE: Round down here to make the check stricter
914
            ///      since truthy values causes revert.
915
            _config.fees.flat.mulDivDown(365 days, _config.positionDuration) <
30,186✔
916
            _minFees.flat ||
917
            _config.fees.governanceLP < _minFees.governanceLP ||
20,118✔
918
            _config.fees.governanceZombie < _minFees.governanceZombie
20,116✔
919
        ) {
920
            revert IHyperdriveFactory.InvalidFees();
24✔
921
        }
922

923
        // Ensure that specified fixed APR is within the minimum and maximum
924
        // fixed APRs.
925
        if (_fixedAPR < minFixedAPR || _fixedAPR > maxFixedAPR) {
40,227✔
926
            revert IHyperdriveFactory.InvalidFixedAPR();
4✔
927
        }
928

929
        // Calculate the time stretch using the provided APR and ensure that
930
        // the time stretch falls within a safe range and the guards specified
931
        // by governance.
932
        uint256 lowerBound = _fixedAPR.divDown(2e18).max(0.005e18);
30,165✔
933
        if (
934
            _timeStretchAPR < minTimeStretchAPR.max(lowerBound) ||
40,220✔
935
            _timeStretchAPR >
20,104✔
936
            maxTimeStretchAPR.min(_fixedAPR.max(lowerBound).mulDown(2e18))
20,104✔
937
        ) {
938
            revert IHyperdriveFactory.InvalidTimeStretchAPR();
12✔
939
        }
940
        uint256 timeStretch = HyperdriveMath.calculateTimeStretch(
30,147✔
941
            _timeStretchAPR,
942
            _config.positionDuration
943
        );
944

945
        // Ensure that the linker factory, linker code hash, fee collector, and
946
        // governance addresses are set to the expected values. This ensures
947
        // that the deployer is aware of the correct values. The time stretch
948
        // should be set to zero to signal that the deployer is aware that it
949
        // will be overwritten.
950
        if (
951
            _config.linkerFactory != linkerFactory ||
70,343✔
952
            _config.linkerCodeHash != linkerCodeHash ||
20,096✔
953
            _config.feeCollector != feeCollector ||
20,094✔
954
            _config.sweepCollector != sweepCollector ||
20,092✔
955
            _config.governance != hyperdriveGovernance ||
20,090✔
956
            _config.timeStretch != 0
20,088✔
957
        ) {
958
            revert IHyperdriveFactory.InvalidDeployConfig();
10✔
959
        }
960

961
        // Override the config values to the default values set by governance.
962
        // The factory assumes the governance role during deployment so that it
963
        // can set up some initial values; however the governance role will
964
        // ultimately be transferred to the hyperdrive governance address.
965
        _config.governance = address(this);
20,088✔
966
        _config.timeStretch = timeStretch;
20,088✔
967
    }
968
}
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