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

delvtech / hyperdrive / 8928108247

02 May 2024 05:18PM UTC coverage: 92.999% (-0.6%) from 93.634%
8928108247

push

github

web-flow
Price Discovery Fix Pt. 1 (#1012)

* Updated `calculateUpdateLiquidity` to use the new algorithm

* Implemented the initialization logic

* Updated to the latest solution

* Fixed some add liquidity unit tests

* Fixed the `openShort` unit tests

* Fixed the `closeLong` unit tests

* Fixed `estimateLongProceeds` and `estimateShortProceeds`

* Fixed more tests

* Fixed the `ExtremeInputs` tests

* Fixed the `updateLiquidity` tests

* Fixed most of the intra-checkpoint netting tests

* Fixed more tests

* Fixed the remaining sandwich test

* Added an error for `InvalidEffectiveShareReserves` and fixed the remaining tests

* Cleaned up the PR

* Added another target

* Moved the add liquidity sandwich into `SandwichTest`

* Appeased the nit gods

* Addressed review feedback from @mcclurejt

* Increased coverage

---------

Co-authored-by: Jonny Rhea <5555162+jrhea@users.noreply.github.com>

38 of 40 new or added lines in 11 files covered. (95.0%)

20 existing lines in 5 files now uncovered.

1820 of 1957 relevant lines covered (93.0%)

385748.08 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);
50,775✔
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);
33,850✔
62
        //  (c / µ) * (µ * (ze + dz))^(1 - t)
63
        ze = c.mulDivDown(ze, mu);
33,850✔
64

65
        // If k < ze, we have no choice but to revert.
66
        if (k < ze) {
33,850✔
67
            Errors.throwInsufficientLiquidityError();
254✔
68
        }
69

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

85
        // If y < _y, we have no choice but to revert.
86
        if (y < _y) {
33,596✔
87
            Errors.throwInsufficientLiquidityError();
×
88
        }
89

90
        // Δy = y - (k - (c / µ) * (µ * (ze + dz))^(1 - t))^(1 / (1 - t))
91
        unchecked {
92
            return y - _y;
50,394✔
93
        }
94
    }
95

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

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

153
        // If y < dy, we return a failure flag since the calculation would have
154
        // underflowed.
155
        if (y < dy) {
294,828✔
156
            return (0, false);
2✔
157
        }
158

159
        // (y - dy)^(1 - t)
160
        unchecked {
161
            y -= dy;
294,826✔
162
        }
163
        y = y.pow(t);
294,826✔
164

165
        // If k < y, we return a failure flag since the calculation would have
166
        // underflowed.
167
        if (k < y) {
294,826✔
168
            return (0, false);
×
169
        }
170

171
        // NOTE: We round _z up to make the lhs of the equation larger.
172
        //
173
        // ((k - (y - dy)^(1 - t) ) / (c / µ))^(1 / (1 - t))
174
        uint256 _z;
294,826✔
175
        unchecked {
176
            _z = k - y;
294,826✔
177
        }
178
        _z = _z.mulDivUp(mu, c);
294,826✔
179
        if (_z >= ONE) {
294,826✔
180
            // Rounding up the exponent results in a larger result.
181
            _z = _z.pow(ONE.divUp(t));
283,324✔
182
        } else {
183
            // Rounding down the exponent results in a larger result.
184
            _z = _z.pow(ONE.divDown(t));
11,502✔
185
        }
186
        // ((k - (y - dy)^(1 - t) ) / (c / µ))^(1 / (1 - t))) / µ
187
        _z = _z.divUp(mu);
294,826✔
188

189
        // If _z < ze, we return a failure flag since the calculation would have
190
        // underflowed.
191
        if (_z < ze) {
294,826✔
UNCOV
192
            return (0, false);
×
193
        }
194

195
        // Δz = (((k - (y - dy)^(1 - t) ) / (c / µ))^(1 / (1 - t))) / µ - ze
196
        unchecked {
197
            return (_z - ze, true);
294,826✔
198
        }
199
    }
200

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

224
        // If y < dy, we have no choice but to revert.
225
        if (y < dy) {
17,602✔
226
            Errors.throwInsufficientLiquidityError();
2✔
227
        }
228

229
        // (y - dy)^(1 - t)
230
        unchecked {
231
            y -= dy;
17,600✔
232
        }
233
        y = y.pow(t);
17,600✔
234

235
        // If k < y, we have no choice but to revert.
236
        if (k < y) {
17,600✔
237
            Errors.throwInsufficientLiquidityError();
×
238
        }
239

240
        // NOTE: We round _z down to make the lhs of the equation smaller.
241
        //
242
        // _z = ((k - (y - dy)^(1 - t) ) / (c / µ))^(1 / (1 - t))
243
        uint256 _z;
17,600✔
244
        unchecked {
245
            _z = k - y;
17,600✔
246
        }
247
        _z = _z.mulDivDown(mu, c);
17,600✔
248
        if (_z >= ONE) {
17,600✔
249
            // Rounding down the exponent results in a smaller result.
250
            _z = _z.pow(ONE.divDown(t));
2,792✔
251
        } else {
252
            // Rounding up the exponent results in a smaller result.
253
            _z = _z.pow(ONE.divUp(t));
14,808✔
254
        }
255
        // ((k - (y - dy)^(1 - t) ) / (c / µ))^(1 / (1 - t))) / µ
256
        _z = _z.divDown(mu);
17,600✔
257

258
        // If _z < ze, we have no choice but to revert.
259
        if (_z < ze) {
17,600✔
260
            Errors.throwInsufficientLiquidityError();
×
261
        }
262

263
        // Δz = (((k - (y - dy)^(1 - t) ) / (c / µ))^(1 / (1 - t))) / µ - ze
264
        unchecked {
265
            return _z - ze;
26,400✔
266
        }
267
    }
268

269
    /// @dev Calculates the amount of shares a user will receive from the pool
270
    ///      by providing a specified amount of bonds. This function reverts if
271
    ///      an integer overflow or underflow occurs. We underestimate the
272
    ///      amount of shares out.
273
    /// @param ze The effective share reserves.
274
    /// @param y The bond reserves.
275
    /// @param dy The amount of bonds paid to the pool.
276
    /// @param t The time elapsed since the term's start.
277
    /// @param c The vault share price.
278
    /// @param mu The initial vault share price.
279
    /// @return result The amount of shares the user receives.
280
    function calculateSharesOutGivenBondsInDown(
281
        uint256 ze,
282
        uint256 y,
283
        uint256 dy,
284
        uint256 t,
285
        uint256 c,
286
        uint256 mu
287
    ) internal pure returns (uint256 result) {
288
        bool success;
45,608✔
289
        (result, success) = calculateSharesOutGivenBondsInDownSafe(
45,608✔
290
            ze,
291
            y,
292
            dy,
293
            t,
294
            c,
295
            mu
296
        );
297
        if (!success) {
45,608✔
298
            Errors.throwInsufficientLiquidityError();
288✔
299
        }
300
    }
301

302
    /// @dev Calculates the amount of shares a user will receive from the pool
303
    ///      by providing a specified amount of bonds. This function returns a
304
    ///      success flag instead of reverting. We underestimate the amount of
305
    ///      shares out.
306
    /// @param ze The effective share reserves.
307
    /// @param y The bond reserves.
308
    /// @param dy The amount of bonds paid to the pool.
309
    /// @param t The time elapsed since the term's start.
310
    /// @param c The vault share price.
311
    /// @param mu The initial vault share price.
312
    /// @return The amount of shares the user receives
313
    /// @return A flag indicating if the calculation succeeded.
314
    function calculateSharesOutGivenBondsInDownSafe(
315
        uint256 ze,
316
        uint256 y,
317
        uint256 dy,
318
        uint256 t,
319
        uint256 c,
320
        uint256 mu
321
    ) internal pure returns (uint256, bool) {
322
        // NOTE: We round k up to make the rhs of the equation larger.
323
        //
324
        // k = (c / µ) * (µ * ze)^(1 - t) + y^(1 - t)
325
        uint256 k = kUp(ze, y, t, c, mu);
542,190✔
326

327
        // (y + dy)^(1 - t)
328
        y = (y + dy).pow(t);
361,460✔
329

330
        // If k is less than y, we return with a failure flag.
331
        if (k < y) {
361,460✔
332
            return (0, false);
288✔
333
        }
334

335
        // NOTE: We round _z up to make the rhs of the equation larger.
336
        //
337
        // ((k - (y + dy)^(1 - t)) / (c / µ))^(1 / (1 - t)))
338
        uint256 _z;
361,172✔
339
        unchecked {
340
            _z = k - y;
361,172✔
341
        }
342
        _z = _z.mulDivUp(mu, c);
361,172✔
343
        if (_z >= ONE) {
361,172✔
344
            // Rounding the exponent up results in a larger outcome.
345
            _z = _z.pow(ONE.divUp(t));
340,590✔
346
        } else {
347
            // Rounding the exponent down results in a larger outcome.
348
            _z = _z.pow(ONE.divDown(t));
20,582✔
349
        }
350
        // ((k - (y + dy)^(1 - t) ) / (c / µ))^(1 / (1 - t))) / µ
351
        _z = _z.divUp(mu);
361,172✔
352

353
        // If ze is less than _z, we return a failure flag since the calculation
354
        // underflowed.
355
        if (ze < _z) {
361,172✔
356
            return (0, false);
80,884✔
357
        }
358

359
        // Δz = ze - ((k - (y + dy)^(1 - t) ) / (c / µ))^(1 / (1 - t)) / µ
360
        unchecked {
361
            return (ze - _z, true);
280,288✔
362
        }
363
    }
364

365
    /// @dev Calculates the share payment required to purchase the maximum
366
    ///      amount of bonds from the pool. This function returns a success flag
367
    ///      instead of reverting. We round so that the max buy amount is
368
    ///      underestimated.
369
    /// @param ze The effective share reserves.
370
    /// @param y The bond reserves.
371
    /// @param t The time elapsed since the term's start.
372
    /// @param c The vault share price.
373
    /// @param mu The initial vault share price.
374
    /// @return The share payment to purchase the maximum amount of bonds.
375
    /// @return A flag indicating if the calculation succeeded.
376
    function calculateMaxBuySharesInSafe(
377
        uint256 ze,
378
        uint256 y,
379
        uint256 t,
380
        uint256 c,
381
        uint256 mu
382
    ) internal pure returns (uint256, bool) {
383
        // We solve for the maximum buy using the constraint that the pool's
384
        // spot price can never exceed 1. We do this by noting that a spot price
385
        // of 1, ((mu * ze) / y) ** tau = 1, implies that mu * ze = y. This
386
        // simplifies YieldSpace to:
387
        //
388
        // k = ((c / mu) + 1) * (mu * ze') ** (1 - tau),
389
        //
390
        // This gives us the maximum effective share reserves of:
391
        //
392
        // ze' = (1 / mu) * (k / ((c / mu) + 1)) ** (1 / (1 - tau)).
393
        uint256 k = kDown(ze, y, t, c, mu);
3,114✔
394
        uint256 optimalZe = k.divDown(c.divUp(mu) + ONE);
3,114✔
395
        if (optimalZe >= ONE) {
2,076✔
396
            // Rounding the exponent down results in a smaller outcome.
397
            optimalZe = optimalZe.pow(ONE.divDown(t));
1,960✔
398
        } else {
399
            // Rounding the exponent up results in a smaller outcome.
400
            optimalZe = optimalZe.pow(ONE.divUp(t));
116✔
401
        }
402
        optimalZe = optimalZe.divDown(mu);
2,076✔
403

404
        // The optimal trade size is given by dz = ze' - ze. If the calculation
405
        // underflows, we return a failure flag.
406
        if (optimalZe < ze) {
2,076✔
407
            return (0, false);
×
408
        }
409
        unchecked {
410
            return (optimalZe - ze, true);
2,076✔
411
        }
412
    }
413

414
    /// @dev Calculates the maximum amount of bonds that can be purchased with
415
    ///      the specified reserves. This function returns a success flag
416
    ///      instead of reverting. We round so that the max buy amount is
417
    ///      underestimated.
418
    /// @param ze The effective share reserves.
419
    /// @param y The bond reserves.
420
    /// @param t The time elapsed since the term's start.
421
    /// @param c The vault share price.
422
    /// @param mu The initial vault share price.
423
    /// @return The maximum amount of bonds that can be purchased.
424
    /// @return A flag indicating if the calculation succeeded.
425
    function calculateMaxBuyBondsOutSafe(
426
        uint256 ze,
427
        uint256 y,
428
        uint256 t,
429
        uint256 c,
430
        uint256 mu
431
    ) internal pure returns (uint256, bool) {
432
        // We can use the same derivation as in `calculateMaxBuySharesIn` to
433
        // calculate the minimum bond reserves as:
434
        //
435
        // y' = (k / ((c / mu) + 1)) ** (1 / (1 - tau)).
436
        uint256 k = kUp(ze, y, t, c, mu);
429,447✔
437
        uint256 optimalY = k.divUp(c.divDown(mu) + ONE);
429,447✔
438
        if (optimalY >= ONE) {
286,298✔
439
            // Rounding the exponent up results in a larger outcome.
440
            optimalY = optimalY.pow(ONE.divUp(t));
279,642✔
441
        } else {
442
            // Rounding the exponent down results in a larger outcome.
443
            optimalY = optimalY.pow(ONE.divDown(t));
6,656✔
444
        }
445

446
        // The optimal trade size is given by dy = y - y'. If the calculation
447
        // underflows, we return a failure flag.
448
        if (y < optimalY) {
286,298✔
449
            return (0, false);
×
450
        }
451
        unchecked {
452
            return (y - optimalY, true);
286,298✔
453
        }
454
    }
455

456
    /// @dev Calculates the maximum amount of bonds that can be sold with the
457
    ///      specified reserves. We round so that the max sell amount is
458
    ///      underestimated.
459
    /// @param z The share reserves.
460
    /// @param zeta The share adjustment.
461
    /// @param y The bond reserves.
462
    /// @param zMin The minimum share reserves.
463
    /// @param t The time elapsed since the term's start.
464
    /// @param c The vault share price.
465
    /// @param mu The initial vault share price.
466
    /// @return The maximum amount of bonds that can be sold.
467
    /// @return A flag indicating whether or not the calculation was successful.
468
    function calculateMaxSellBondsInSafe(
469
        uint256 z,
470
        int256 zeta,
471
        uint256 y,
472
        uint256 zMin,
473
        uint256 t,
474
        uint256 c,
475
        uint256 mu
476
    ) internal pure returns (uint256, bool) {
477
        // If the share adjustment is negative, the minimum share reserves is
478
        // given by `zMin - zeta`, which ensures that the share reserves never
479
        // fall below the minimum share reserves. Otherwise, the minimum share
480
        // reserves is just zMin.
481
        if (zeta < 0) {
323,098✔
UNCOV
482
            zMin = zMin + uint256(-zeta);
×
483
        }
484

485
        // We solve for the maximum bond amount using the constraint that the
486
        // pool's share reserves can never fall below the minimum share reserves
487
        // `zMin`. Substituting `ze = zMin` simplifies YieldSpace to:
488
        //
489
        // k = (c / mu) * (mu * zMin) ** (1 - tau) + y' ** (1 - tau)
490
        //
491
        // This gives us the maximum bonds that can be sold to the pool as:
492
        //
493
        // y' = (k - (c / mu) * (mu * zMin) ** (1 - tau)) ** (1 / (1 - tau)).
494
        (uint256 ze, bool success) = HyperdriveMath
484,647✔
495
            .calculateEffectiveShareReservesSafe(z, zeta);
496

497
        if (!success) {
323,098✔
498
            return (0, false);
×
499
        }
500
        uint256 k = kDown(ze, y, t, c, mu);
484,647✔
501
        uint256 rhs = c.mulDivUp(mu.mulUp(zMin).pow(t), mu);
484,647✔
502
        if (k < rhs) {
323,098✔
503
            return (0, false);
154✔
504
        }
505
        uint256 optimalY;
322,944✔
506
        unchecked {
507
            optimalY = k - rhs;
322,944✔
508
        }
509
        if (optimalY >= ONE) {
322,944✔
510
            // Rounding the exponent down results in a smaller outcome.
511
            optimalY = optimalY.pow(ONE.divDown(t));
310,670✔
512
        } else {
513
            // Rounding the exponent up results in a smaller outcome.
514
            optimalY = optimalY.pow(ONE.divUp(t));
12,274✔
515
        }
516

517
        // The optimal trade size is given by dy = y' - y. If this subtraction
518
        // will underflow, we return a failure flag.
519
        if (optimalY < y) {
322,944✔
520
            return (0, false);
5,382✔
521
        }
522
        unchecked {
523
            return (optimalY - y, true);
317,562✔
524
        }
525
    }
526

527
    /// @dev Calculates the YieldSpace invariant k. This invariant is given by:
528
    ///
529
    ///      k = (c / µ) * (µ * ze)^(1 - t) + y^(1 - t)
530
    ///
531
    ///      This variant of the calculation overestimates the result.
532
    /// @param ze The effective share reserves.
533
    /// @param y The bond reserves.
534
    /// @param t The time elapsed since the term's start.
535
    /// @param c The vault share price.
536
    /// @param mu The initial vault share price.
537
    /// @return The YieldSpace invariant, k.
538
    function kUp(
539
        uint256 ze,
540
        uint256 y,
541
        uint256 t,
542
        uint256 c,
543
        uint256 mu
544
    ) internal pure returns (uint256) {
545
        // NOTE: Rounding up to overestimate the result.
546
        //
547
        /// k = (c / µ) * (µ * ze)^(1 - t) + y^(1 - t)
548
        return c.mulDivUp(mu.mulUp(ze).pow(t), mu) + y.pow(t);
2,448,960✔
549
    }
550

551
    /// @dev Calculates the YieldSpace invariant k. This invariant is given by:
552
    ///
553
    ///      k = (c / µ) * (µ * ze)^(1 - t) + y^(1 - t)
554
    ///
555
    ///      This variant of the calculation underestimates the result.
556
    /// @param ze The effective share reserves.
557
    /// @param y The bond reserves.
558
    /// @param t The time elapsed since the term's start.
559
    /// @param c The vault share price.
560
    /// @param mu The initial vault share price.
561
    /// @return The modified YieldSpace Constant.
562
    function kDown(
563
        uint256 ze,
564
        uint256 y,
565
        uint256 t,
566
        uint256 c,
567
        uint256 mu
568
    ) internal pure returns (uint256) {
569
        // NOTE: Rounding down to underestimate the result.
570
        //
571
        /// k = (c / µ) * (µ * ze)^(1 - t) + y^(1 - t)
572
        return c.mulDivDown(mu.mulDown(ze).pow(t), mu) + y.pow(t);
1,021,500✔
573
    }
574
}
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