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

delvtech / hyperdrive / 8517843340

02 Apr 2024 05:21AM UTC coverage: 92.214%. First build
8517843340

Pull #906

github

web-flow
Merge 650223444 into cbc93bbc2
Pull Request #906: fix unsafe routes in _distributeExcessIdleSafe

13 of 16 new or added lines in 3 files covered. (81.25%)

1658 of 1798 relevant lines covered (92.21%)

415800.84 hits per line

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

91.43
/contracts/src/libraries/YieldSpaceMath.sol
1
/// SPDX-License-Identifier: Apache-2.0
2
pragma solidity 0.8.20;
3

4
import { IHyperdrive } from "../interfaces/IHyperdrive.sol";
5
import { Errors } from "./Errors.sol";
6
import { FixedPointMath, ONE } from "./FixedPointMath.sol";
7
import { HyperdriveMath } from "./HyperdriveMath.sol";
8

9
/// @author DELV
10
/// @title YieldSpaceMath
11
/// @notice Math for the YieldSpace pricing model.
12
/// @custom:disclaimer The language used in this code is for coding convenience
13
///                    only, and is not intended to, and does not, have any
14
///                    particular legal or regulatory significance.
15
///
16
/// @dev It is advised for developers to attain the pre-requisite knowledge
17
///      of how this implementation works on the mathematical level. This
18
///      excerpt attempts to document this pre-requisite knowledge explaining
19
///      the underpinning mathematical concepts in an understandable manner and
20
///      relating it directly to the code implementation.
21
///      This implementation is based on a paper called "YieldSpace with Yield
22
///      Bearing Vaults" or more casually "Modified YieldSpace". It can be
23
///      found at the following link.
24
///
25
///      https://hackmd.io/lRZ4mgdrRgOpxZQXqKYlFw?view
26
///
27
///      That paper builds on the original YieldSpace paper, "YieldSpace:
28
///      An Automated Liquidity Provider for Fixed Yield Tokens". It can be
29
///      found at the following link:
30
///
31
///      https://yieldprotocol.com/YieldSpace.pdf
32
library YieldSpaceMath {
33
    using FixedPointMath for uint256;
34

35
    /// @dev Calculates the amount of bonds a user will receive from the pool by
36
    ///      providing a specified amount of shares. We underestimate the amount
37
    ///      of bonds out.
38
    /// @param ze The effective share reserves.
39
    /// @param y The bond reserves.
40
    /// @param dz The amount of shares paid to the pool.
41
    /// @param t The time elapsed since the term's start.
42
    /// @param c The vault share price.
43
    /// @param mu The initial vault share price.
44
    /// @return The amount of bonds the trader receives.
45
    function calculateBondsOutGivenSharesInDown(
46
        uint256 ze,
47
        uint256 y,
48
        uint256 dz,
49
        uint256 t,
50
        uint256 c,
51
        uint256 mu
52
    ) internal pure returns (uint256) {
53
        // NOTE: We round k up to make the rhs of the equation larger.
54
        //
55
        // k = (c / µ) * (µ * ze)^(1 - t) + y^(1 - t)
56
        uint256 k = kUp(ze, y, t, c, mu);
54,660✔
57

58
        // NOTE: We round ze down to make the rhs of the equation larger.
59
        //
60
        //  (µ * (ze + dz))^(1 - t)
61
        ze = mu.mulDown(ze + dz).pow(t);
36,440✔
62
        //  (c / µ) * (µ * (ze + dz))^(1 - t)
63
        ze = c.mulDivDown(ze, mu);
36,440✔
64

65
        // If k < ze, we have no choice but to revert.
66
        if (k < ze) {
36,440✔
67
            Errors.throwInsufficientLiquidityError(
214✔
68
                IHyperdrive.InsufficientLiquidityReason.ArithmeticUnderflow
69
            );
70
        }
71

72
        // NOTE: We round _y up to make the rhs of the equation larger.
73
        //
74
        // (k - (c / µ) * (µ * (ze + dz))^(1 - t))^(1 / (1 - t))
75
        uint256 _y;
36,226✔
76
        unchecked {
77
            _y = k - ze;
36,226✔
78
        }
79
        if (_y >= ONE) {
36,226✔
80
            // Rounding up the exponent results in a larger result.
81
            _y = _y.pow(ONE.divUp(t));
33,160✔
82
        } else {
83
            // Rounding down the exponent results in a larger result.
84
            _y = _y.pow(ONE.divDown(t));
3,066✔
85
        }
86

87
        // If y < _y, we have no choice but to revert.
88
        if (y < _y) {
36,226✔
89
            Errors.throwInsufficientLiquidityError(
×
90
                IHyperdrive.InsufficientLiquidityReason.ArithmeticUnderflow
91
            );
92
        }
93

94
        // Δy = y - (k - (c / µ) * (µ * (ze + dz))^(1 - t))^(1 / (1 - t))
95
        unchecked {
96
            return y - _y;
54,339✔
97
        }
98
    }
99

100
    /// @dev Calculates the amount of shares a user must provide the pool to
101
    ///      receive a specified amount of bonds. We overestimate the amount of
102
    ///      shares in.
103
    /// @param ze The effective share reserves.
104
    /// @param y The bond reserves.
105
    /// @param dy The amount of bonds paid to the trader.
106
    /// @param t The time elapsed since the term's start.
107
    /// @param c The vault share price.
108
    /// @param mu The initial vault share price.
109
    /// @return result The amount of shares the trader pays.
110
    function calculateSharesInGivenBondsOutUp(
111
        uint256 ze,
112
        uint256 y,
113
        uint256 dy,
114
        uint256 t,
115
        uint256 c,
116
        uint256 mu
117
    ) internal pure returns (uint256 result) {
118
        bool success;
13,736✔
119
        (result, success) = calculateSharesInGivenBondsOutUpSafe(
13,736✔
120
            ze,
121
            y,
122
            dy,
123
            t,
124
            c,
125
            mu
126
        );
127
        if (!success) {
13,736✔
128
            Errors.throwInsufficientLiquidityError(
×
129
                IHyperdrive.InsufficientLiquidityReason.ArithmeticUnderflow
130
            );
131
        }
132
    }
133

134
    /// @dev Calculates the amount of shares a user must provide the pool to
135
    ///      receive a specified amount of bonds. This function returns a
136
    ///      success flag instead of reverting. We overestimate the amount of
137
    ///      shares in.
138
    /// @param ze The effective share reserves.
139
    /// @param y The bond reserves.
140
    /// @param dy The amount of bonds paid to the trader.
141
    /// @param t The time elapsed since the term's start.
142
    /// @param c The vault share price.
143
    /// @param mu The initial vault share price.
144
    /// @return The amount of shares the trader pays.
145
    /// @return A flag indicating if the calculation succeeded.
146
    function calculateSharesInGivenBondsOutUpSafe(
147
        uint256 ze,
148
        uint256 y,
149
        uint256 dy,
150
        uint256 t,
151
        uint256 c,
152
        uint256 mu
153
    ) internal pure returns (uint256, bool) {
154
        // NOTE: We round k up to make the lhs of the equation larger.
155
        //
156
        // k = (c / µ) * (µ * ze)^(1 - t) + y^(1 - t)
157
        uint256 k = kUp(ze, y, t, c, mu);
452,850✔
158

159
        // If y < dy, we return a failure flag since the calculation would have
160
        // underflowed.
161
        if (y < dy) {
301,900✔
162
            return (0, false);
×
163
        }
164

165
        // (y - dy)^(1 - t)
166
        unchecked {
167
            y -= dy;
301,900✔
168
        }
169
        y = y.pow(t);
301,900✔
170

171
        // If k < y, we return a failure flag since the calculation would have
172
        // underflowed.
173
        if (k < y) {
301,900✔
174
            return (0, false);
×
175
        }
176

177
        // NOTE: We round _z up to make the lhs of the equation larger.
178
        //
179
        // ((k - (y - dy)^(1 - t) ) / (c / µ))^(1 / (1 - t))
180
        uint256 _z;
301,900✔
181
        unchecked {
182
            _z = k - y;
301,900✔
183
        }
184
        _z = _z.mulDivUp(mu, c);
301,900✔
185
        if (_z >= ONE) {
301,900✔
186
            // Rounding up the exponent results in a larger result.
187
            _z = _z.pow(ONE.divUp(t));
296,068✔
188
        } else {
189
            // Rounding down the exponent results in a larger result.
190
            _z = _z.pow(ONE.divDown(t));
5,832✔
191
        }
192
        // ((k - (y - dy)^(1 - t) ) / (c / µ))^(1 / (1 - t))) / µ
193
        _z = _z.divUp(mu);
301,900✔
194

195
        // If _z < ze, we return a failure flag since the calculation would have
196
        // underflowed.
197
        if (_z < ze) {
301,900✔
198
            return (0, false);
2✔
199
        }
200

201
        // Δz = (((k - (y - dy)^(1 - t) ) / (c / µ))^(1 / (1 - t))) / µ - ze
202
        unchecked {
203
            return (_z - ze, true);
301,898✔
204
        }
205
    }
206

207
    /// @dev Calculates the amount of shares a user must provide the pool to
208
    ///      receive a specified amount of bonds. We underestimate the amount of
209
    ///      shares in.
210
    /// @param ze The effective share reserves.
211
    /// @param y The bond reserves.
212
    /// @param dy The amount of bonds paid to the trader.
213
    /// @param t The time elapsed since the term's start.
214
    /// @param c The vault share price.
215
    /// @param mu The initial vault share price.
216
    /// @return The amount of shares the user pays.
217
    function calculateSharesInGivenBondsOutDown(
218
        uint256 ze,
219
        uint256 y,
220
        uint256 dy,
221
        uint256 t,
222
        uint256 c,
223
        uint256 mu
224
    ) internal pure returns (uint256) {
225
        // NOTE: We round k down to make the lhs of the equation smaller.
226
        //
227
        // k = (c / µ) * (µ * ze)^(1 - t) + y^(1 - t)
228
        uint256 k = kDown(ze, y, t, c, mu);
26,403✔
229

230
        // If y < dy, we have no choice but to revert.
231
        if (y < dy) {
17,602✔
232
            Errors.throwInsufficientLiquidityError(
2✔
233
                IHyperdrive.InsufficientLiquidityReason.ArithmeticUnderflow
234
            );
235
        }
236

237
        // (y - dy)^(1 - t)
238
        unchecked {
239
            y -= dy;
17,600✔
240
        }
241
        y = y.pow(t);
17,600✔
242

243
        // If k < y, we have no choice but to revert.
244
        if (k < y) {
17,600✔
245
            Errors.throwInsufficientLiquidityError(
×
246
                IHyperdrive.InsufficientLiquidityReason.ArithmeticUnderflow
247
            );
248
        }
249

250
        // NOTE: We round _z down to make the lhs of the equation smaller.
251
        //
252
        // _z = ((k - (y - dy)^(1 - t) ) / (c / µ))^(1 / (1 - t))
253
        uint256 _z;
17,600✔
254
        unchecked {
255
            _z = k - y;
17,600✔
256
        }
257
        _z = _z.mulDivDown(mu, c);
17,600✔
258
        if (_z >= ONE) {
17,600✔
259
            // Rounding down the exponent results in a smaller result.
260
            _z = _z.pow(ONE.divDown(t));
2,504✔
261
        } else {
262
            // Rounding up the exponent results in a smaller result.
263
            _z = _z.pow(ONE.divUp(t));
15,096✔
264
        }
265
        // ((k - (y - dy)^(1 - t) ) / (c / µ))^(1 / (1 - t))) / µ
266
        _z = _z.divDown(mu);
17,600✔
267

268
        // If _z < ze, we have no choice but to revert.
269
        if (_z < ze) {
17,600✔
270
            Errors.throwInsufficientLiquidityError(
×
271
                IHyperdrive.InsufficientLiquidityReason.ArithmeticUnderflow
272
            );
273
        }
274

275
        // Δz = (((k - (y - dy)^(1 - t) ) / (c / µ))^(1 / (1 - t))) / µ - ze
276
        unchecked {
277
            return _z - ze;
26,400✔
278
        }
279
    }
280

281
    /// @dev Calculates the amount of shares a user will receive from the pool
282
    ///      by providing a specified amount of bonds. This function reverts if
283
    ///      an integer overflow or underflow occurs. We underestimate the
284
    ///      amount of shares out.
285
    /// @param ze The effective share reserves.
286
    /// @param y The bond reserves.
287
    /// @param dy The amount of bonds paid to the pool.
288
    /// @param t The time elapsed since the term's start.
289
    /// @param c The vault share price.
290
    /// @param mu The initial vault share price.
291
    /// @return result The amount of shares the user receives.
292
    function calculateSharesOutGivenBondsInDown(
293
        uint256 ze,
294
        uint256 y,
295
        uint256 dy,
296
        uint256 t,
297
        uint256 c,
298
        uint256 mu
299
    ) internal pure returns (uint256 result) {
300
        bool success;
45,832✔
301
        (result, success) = calculateSharesOutGivenBondsInDownSafe(
45,832✔
302
            ze,
303
            y,
304
            dy,
305
            t,
306
            c,
307
            mu
308
        );
309
        if (!success) {
45,832✔
310
            Errors.throwInsufficientLiquidityError(
244✔
311
                IHyperdrive.InsufficientLiquidityReason.ArithmeticUnderflow
312
            );
313
        }
314
    }
315

316
    /// @dev Calculates the amount of shares a user will receive from the pool
317
    ///      by providing a specified amount of bonds. This function returns a
318
    ///      success flag instead of reverting. We underestimate the amount of
319
    ///      shares out.
320
    /// @param ze The effective share reserves.
321
    /// @param y The bond reserves.
322
    /// @param dy The amount of bonds paid to the pool.
323
    /// @param t The time elapsed since the term's start.
324
    /// @param c The vault share price.
325
    /// @param mu The initial vault share price.
326
    /// @return The amount of shares the user receives
327
    /// @return A flag indicating if the calculation succeeded.
328
    function calculateSharesOutGivenBondsInDownSafe(
329
        uint256 ze,
330
        uint256 y,
331
        uint256 dy,
332
        uint256 t,
333
        uint256 c,
334
        uint256 mu
335
    ) internal pure returns (uint256, bool) {
336
        // NOTE: We round k up to make the rhs of the equation larger.
337
        //
338
        // k = (c / µ) * (µ * ze)^(1 - t) + y^(1 - t)
339
        uint256 k = kUp(ze, y, t, c, mu);
583,614✔
340

341
        // (y + dy)^(1 - t)
342
        y = (y + dy).pow(t);
389,076✔
343

344
        // If k is less than y, we return with a failure flag.
345
        if (k < y) {
389,076✔
346
            return (0, false);
244✔
347
        }
348

349
        // NOTE: We round _z up to make the rhs of the equation larger.
350
        //
351
        // ((k - (y + dy)^(1 - t)) / (c / µ))^(1 / (1 - t)))
352
        uint256 _z;
388,832✔
353
        unchecked {
354
            _z = k - y;
388,832✔
355
        }
356
        _z = _z.mulDivUp(mu, c);
388,832✔
357
        if (_z >= ONE) {
388,832✔
358
            // Rounding the exponent up results in a larger outcome.
359
            _z = _z.pow(ONE.divUp(t));
367,270✔
360
        } else {
361
            // Rounding the exponent down results in a larger outcome.
362
            _z = _z.pow(ONE.divDown(t));
21,562✔
363
        }
364
        // ((k - (y + dy)^(1 - t) ) / (c / µ))^(1 / (1 - t))) / µ
365
        _z = _z.divUp(mu);
388,832✔
366

367
        // If ze is less than _z, we return a failure flag since the calculation
368
        // underflowed.
369
        if (ze < _z) {
388,832✔
370
            return (0, false);
83,208✔
371
        }
372

373
        // Δz = ze - ((k - (y + dy)^(1 - t) ) / (c / µ))^(1 / (1 - t)) / µ
374
        unchecked {
375
            return (ze - _z, true);
305,624✔
376
        }
377
    }
378

379
    /// @dev Calculates the share payment required to purchase the maximum
380
    ///      amount of bonds from the pool. This function returns a success flag
381
    ///      instead of reverting. We round so that the max buy amount is
382
    ///      underestimated.
383
    /// @param ze The effective share reserves.
384
    /// @param y The bond reserves.
385
    /// @param t The time elapsed since the term's start.
386
    /// @param c The vault share price.
387
    /// @param mu The initial vault share price.
388
    /// @return The share payment to purchase the maximum amount of bonds.
389
    /// @return A flag indicating if the calculation succeeded.
390
    function calculateMaxBuySharesInSafe(
391
        uint256 ze,
392
        uint256 y,
393
        uint256 t,
394
        uint256 c,
395
        uint256 mu
396
    ) internal pure returns (uint256, bool) {
397
        // We solve for the maximum buy using the constraint that the pool's
398
        // spot price can never exceed 1. We do this by noting that a spot price
399
        // of 1, ((mu * ze) / y) ** tau = 1, implies that mu * ze = y. This
400
        // simplifies YieldSpace to:
401
        //
402
        // k = ((c / mu) + 1) * (mu * ze') ** (1 - tau),
403
        //
404
        // This gives us the maximum effective share reserves of:
405
        //
406
        // ze' = (1 / mu) * (k / ((c / mu) + 1)) ** (1 / (1 - tau)).
407
        uint256 k = kDown(ze, y, t, c, mu);
3,216✔
408
        uint256 optimalZe = k.divDown(c.divUp(mu) + ONE);
3,216✔
409
        if (optimalZe >= ONE) {
2,144✔
410
            // Rounding the exponent down results in a smaller outcome.
411
            optimalZe = optimalZe.pow(ONE.divDown(t));
2,032✔
412
        } else {
413
            // Rounding the exponent up results in a smaller outcome.
414
            optimalZe = optimalZe.pow(ONE.divUp(t));
112✔
415
        }
416
        optimalZe = optimalZe.divDown(mu);
2,144✔
417

418
        // The optimal trade size is given by dz = ze' - ze. If the calculation
419
        // underflows, we return a failure flag.
420
        if (optimalZe < ze) {
2,144✔
421
            return (0, false);
×
422
        }
423
        unchecked {
424
            return (optimalZe - ze, true);
2,144✔
425
        }
426
    }
427

428
    /// @dev Calculates the maximum amount of bonds that can be purchased with
429
    ///      the specified reserves. This function returns a success flag
430
    ///      instead of reverting. We round so that the max buy amount is
431
    ///      underestimated.
432
    /// @param ze The effective share reserves.
433
    /// @param y The bond reserves.
434
    /// @param t The time elapsed since the term's start.
435
    /// @param c The vault share price.
436
    /// @param mu The initial vault share price.
437
    /// @return The maximum amount of bonds that can be purchased.
438
    /// @return A flag indicating if the calculation succeeded.
439
    function calculateMaxBuyBondsOutSafe(
440
        uint256 ze,
441
        uint256 y,
442
        uint256 t,
443
        uint256 c,
444
        uint256 mu
445
    ) internal pure returns (uint256, bool) {
446
        // We can use the same derivation as in `calculateMaxBuySharesIn` to
447
        // calculate the minimum bond reserves as:
448
        //
449
        // y' = (k / ((c / mu) + 1)) ** (1 / (1 - tau)).
450
        uint256 k = kUp(ze, y, t, c, mu);
440,205✔
451
        uint256 optimalY = k.divUp(c.divDown(mu) + ONE);
440,205✔
452
        if (optimalY >= ONE) {
293,470✔
453
            // Rounding the exponent up results in a larger outcome.
454
            optimalY = optimalY.pow(ONE.divUp(t));
289,518✔
455
        } else {
456
            // Rounding the exponent down results in a larger outcome.
457
            optimalY = optimalY.pow(ONE.divDown(t));
3,952✔
458
        }
459

460
        // The optimal trade size is given by dy = y - y'. If the calculation
461
        // underflows, we return a failure flag.
462
        if (y < optimalY) {
293,470✔
463
            return (0, false);
×
464
        }
465
        unchecked {
466
            return (y - optimalY, true);
293,470✔
467
        }
468
    }
469

470
    /// @dev Calculates the maximum amount of bonds that can be sold with the
471
    ///      specified reserves. We round so that the max sell amount is
472
    ///      underestimated.
473
    /// @param z The share reserves.
474
    /// @param zeta The share adjustment.
475
    /// @param y The bond reserves.
476
    /// @param zMin The minimum share reserves.
477
    /// @param t The time elapsed since the term's start.
478
    /// @param c The vault share price.
479
    /// @param mu The initial vault share price.
480
    /// @return The maximum amount of bonds that can be sold.
481
    /// @return A flag indicating whether or not the calculation was successful.
482
    function calculateMaxSellBondsInSafe(
483
        uint256 z,
484
        int256 zeta,
485
        uint256 y,
486
        uint256 zMin,
487
        uint256 t,
488
        uint256 c,
489
        uint256 mu
490
    ) internal pure returns (uint256, bool) {
491
        // If the share adjustment is negative, the minimum share reserves is
492
        // given by `zMin - zeta`, which ensures that the share reserves never
493
        // fall below the minimum share reserves. Otherwise, the minimum share
494
        // reserves is just zMin.
495
        if (zeta < 0) {
332,320✔
496
            zMin = zMin + uint256(-zeta);
10,972✔
497
        }
498

499
        // We solve for the maximum bond amount using the constraint that the
500
        // pool's share reserves can never fall below the minimum share reserves
501
        // `zMin`. Substituting `ze = zMin` simplifies YieldSpace to:
502
        //
503
        // k = (c / mu) * (mu * zMin) ** (1 - tau) + y' ** (1 - tau)
504
        //
505
        // This gives us the maximum bonds that can be sold to the pool as:
506
        //
507
        // y' = (k - (c / mu) * (mu * zMin) ** (1 - tau)) ** (1 / (1 - tau)).
508
        (uint256 ze, bool success) = HyperdriveMath
498,480✔
509
            .calculateEffectiveShareReservesSafe(z, zeta);
510

511
        if (!success) {
332,320✔
NEW
512
            return (0, false);
×
513
        }
514
        uint256 k = kDown(ze, y, t, c, mu);
498,480✔
515
        uint256 rhs = c.mulDivUp(mu.mulUp(zMin).pow(t), mu);
498,480✔
516
        if (k < rhs) {
332,320✔
517
            return (0, false);
14✔
518
        }
519
        uint256 optimalY;
332,306✔
520
        unchecked {
521
            optimalY = k - rhs;
332,306✔
522
        }
523
        if (optimalY >= ONE) {
332,306✔
524
            // Rounding the exponent down results in a smaller outcome.
525
            optimalY = optimalY.pow(ONE.divDown(t));
323,186✔
526
        } else {
527
            // Rounding the exponent up results in a smaller outcome.
528
            optimalY = optimalY.pow(ONE.divUp(t));
9,120✔
529
        }
530

531
        // The optimal trade size is given by dy = y' - y. If this subtraction
532
        // will underflow, we return a failure flag.
533
        if (optimalY < y) {
332,306✔
534
            return (0, false);
212✔
535
        }
536
        unchecked {
537
            return (optimalY - y, true);
332,094✔
538
        }
539
    }
540

541
    /// @dev Calculates the YieldSpace invariant k. This invariant is given by:
542
    ///
543
    ///      k = (c / µ) * (µ * ze)^(1 - t) + y^(1 - t)
544
    ///
545
    ///      This variant of the calculation overestimates the result.
546
    /// @param ze The effective share reserves.
547
    /// @param y The bond reserves.
548
    /// @param t The time elapsed since the term's start.
549
    /// @param c The vault share price.
550
    /// @param mu The initial vault share price.
551
    /// @return The YieldSpace invariant, k.
552
    function kUp(
553
        uint256 ze,
554
        uint256 y,
555
        uint256 t,
556
        uint256 c,
557
        uint256 mu
558
    ) internal pure returns (uint256) {
559
        // NOTE: Rounding up to overestimate the result.
560
        //
561
        /// k = (c / µ) * (µ * ze)^(1 - t) + y^(1 - t)
562
        return c.mulDivUp(mu.mulUp(ze).pow(t), mu) + y.pow(t);
2,563,580✔
563
    }
564

565
    /// @dev Calculates the YieldSpace invariant k. This invariant is given by:
566
    ///
567
    ///      k = (c / µ) * (µ * ze)^(1 - t) + y^(1 - t)
568
    ///
569
    ///      This variant of the calculation underestimates the result.
570
    /// @param ze The effective share reserves.
571
    /// @param y The bond reserves.
572
    /// @param t The time elapsed since the term's start.
573
    /// @param c The vault share price.
574
    /// @param mu The initial vault share price.
575
    /// @return The modified YieldSpace Constant.
576
    function kDown(
577
        uint256 ze,
578
        uint256 y,
579
        uint256 t,
580
        uint256 c,
581
        uint256 mu
582
    ) internal pure returns (uint256) {
583
        // NOTE: Rounding down to underestimate the result.
584
        //
585
        /// k = (c / µ) * (µ * ze)^(1 - t) + y^(1 - t)
586
        return c.mulDivDown(mu.mulDown(ze).pow(t), mu) + y.pow(t);
1,059,255✔
587
    }
588
}
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

© 2026 Coveralls, Inc