From 688bd7ea8a9e4612aee36f176e5faae466e47988 Mon Sep 17 00:00:00 2001 From: Alex Towle Date: Wed, 8 Feb 2023 20:29:39 -0600 Subject: [PATCH 1/3] Fixed up the HyperdriveMath library --- contracts/libraries/HyperdriveMath.sol | 63 +++++++++++++++----------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/contracts/libraries/HyperdriveMath.sol b/contracts/libraries/HyperdriveMath.sol index 4e447bf51..81076a406 100644 --- a/contracts/libraries/HyperdriveMath.sol +++ b/contracts/libraries/HyperdriveMath.sol @@ -91,7 +91,9 @@ library HyperdriveMath { /// the capital efficiency of the AMM. Otherwise, the APR would be 0% /// when share_reserves = bond_reserves, which would ensure that half /// of the pool reserves couldn't be used to provide liquidity. - /// @param _amountIn The amount of the asset that is provided. + /// @param _amountIn The amount to be traded. This quantity is denominated + /// in shares if bonds are being traded out and bonds if shares are + /// being traded out. /// @param _timeRemaining The amount of time until maturity in seconds. /// @param _timeStretch The time stretch parameter. /// @param _sharePrice The share price. @@ -122,30 +124,34 @@ library HyperdriveMath { uint256 userDelta ) { - // TODO: See if this is actually true. - // - // This pricing model only supports the purchasing of bonds when - // timeRemaining = 1. - if (_isBondOut && _timeRemaining < 1) { - revert Errors.HyperdriveMath_BaseWithNonzeroTime(); - } if (_isBondOut) { - // If bonds are being purchased, then the entire trade occurs on the - // curved portion since t = 1. - uint256 amountOut = YieldSpaceMath.calculateOutGivenIn( - _shareReserves, - _bondReserves, + // We consider (1-timeRemaining)*amountIn of the bonds being + // purchased to be fully matured and we use the remaining + // timeRemaining*amountIn shares to purchase newly minted bonds on a + // YieldSpace curve configured to timeRemaining = 1. + uint256 flat = _amountIn.mulDown( + FixedPointMath.ONE_18.sub(_timeRemaining) + ); + uint256 curveIn = _amountIn.mulDown(_timeRemaining); + uint256 curveOut = YieldSpaceMath.calculateOutGivenIn( + // Credit the share reserves by the flat trade. + _shareReserves.add(flat), + // Dedit the bond reserves by the flat trade. + _bondReserves.sub(flat.mulDown(_sharePrice)), _bondReserveAdjustment, - _amountIn, + curveIn, FixedPointMath.ONE_18, _timeStretch, _sharePrice, _initialSharePrice, _isBondOut ); - return (_amountIn, amountOut, amountOut); + return ( + _amountIn, + curveOut, + flat.mulDown(_sharePrice).add(curveOut) + ); } else { - // Since we are trading bonds, it's possible that timeRemaining < 1. // We consider (1-timeRemaining)*amountIn of the bonds to be fully // matured and timeRemaining*amountIn of the bonds to be newly // minted. The fully matured bonds are redeemed one-to-one to base @@ -154,13 +160,15 @@ library HyperdriveMath { // traded on a YieldSpace curve configured to timeRemaining = 1. uint256 flat = _amountIn .mulDown(FixedPointMath.ONE_18.sub(_timeRemaining)) - .divDown(_sharePrice); - uint256 curveIn = _amountIn.mulDown(_timeRemaining); + .divDow(_sharePrice); + uint256 curveIn = _amountIn.mulDown(_timeRemaining).divDown( + _sharePrice + ); uint256 curveOut = YieldSpaceMath.calculateOutGivenIn( // Debit the share reserves by the flat trade. - _shareReserves.sub(flat.divDown(_initialSharePrice)), + _shareReserves.sub(flat), // Credit the bond reserves by the flat trade. - _bondReserves.add(flat), + _bondReserves.add(flat.mulDown(_sharePrice)), _bondReserveAdjustment, curveIn, FixedPointMath.ONE_18, @@ -169,7 +177,8 @@ library HyperdriveMath { _initialSharePrice, _isBondOut ); - return (flat.add(curveOut), curveIn, flat.add(curveOut)); + uint256 shareDelta = flat.add(curveOut); + return (shareDelta, curveIn, shareDelta); } } @@ -191,7 +200,7 @@ library HyperdriveMath { /// @return poolBondDelta The delta that should be applied to the pool's /// bond reserves. /// @return userDelta The amount of assets the user should receive. - function calculateBaseInGivenBondsOut( + function calculateSharesInGivenBondsOut( uint256 _shareReserves, uint256 _bondReserves, uint256 _bondReserveAdjustment, @@ -220,12 +229,14 @@ library HyperdriveMath { uint256 flat = _amountOut .mulDown(FixedPointMath.ONE_18.sub(_timeRemaining)) .divDown(_sharePrice); - uint256 curveOut = _amountOut.mulDown(_timeRemaining); + uint256 curveOut = _amountOut.mulDown(_timeRemaining).divDown( + _sharePrice + ); uint256 curveIn = YieldSpaceMath.calculateInGivenOut( // Credit the share reserves by the flat trade. - _shareReserves.add(flat.divDown(_sharePrice)), + _shareReserves.add(flat), // Debit the bond reserves by the flat trade. - _bondReserves.sub(flat), + _bondReserves.sub(flat.mulDown(_sharePrice)), _bondReserveAdjustment, curveOut, FixedPointMath.ONE_18, @@ -234,7 +245,7 @@ library HyperdriveMath { _initialSharePrice, false ); - return (flat.add(curveIn), curveIn, flat.add(curveIn)); + return (flat.add(curveIn), curveOut, flat.add(curveIn)); } // TODO: Use an allocation scheme that doesn't punish early LPs. From 70d7da3a5e07b4bddad1f99818f30d28ae86911c Mon Sep 17 00:00:00 2001 From: Alex Towle Date: Wed, 8 Feb 2023 20:35:28 -0600 Subject: [PATCH 2/3] Fixed the build and appeased the linter --- contracts/Hyperdrive.sol | 2 +- contracts/libraries/AssetId.sol | 2 +- contracts/libraries/HyperdriveMath.sol | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/Hyperdrive.sol b/contracts/Hyperdrive.sol index 541f0af58..4652df563 100644 --- a/contracts/Hyperdrive.sol +++ b/contracts/Hyperdrive.sol @@ -499,7 +499,7 @@ contract Hyperdrive is MultiToken { uint256 poolShareDelta, uint256 poolBondDelta, uint256 sharePayment - ) = HyperdriveMath.calculateBaseInGivenBondsOut( + ) = HyperdriveMath.calculateSharesInGivenBondsOut( shareReserves, bondReserves, totalSupply[AssetId._LP_ASSET_ID], diff --git a/contracts/libraries/AssetId.sol b/contracts/libraries/AssetId.sol index 1fdf346f1..52308f34b 100644 --- a/contracts/libraries/AssetId.sol +++ b/contracts/libraries/AssetId.sol @@ -68,7 +68,7 @@ library AssetId { uint256 _id ) internal - view + pure returns (AssetIdPrefix _prefix, uint256 _data, uint256 _timestamp) { // [identifier: 8 bits][data: 216 bits][timestamp: 32 bits] diff --git a/contracts/libraries/HyperdriveMath.sol b/contracts/libraries/HyperdriveMath.sol index 81076a406..3cbfaf36b 100644 --- a/contracts/libraries/HyperdriveMath.sol +++ b/contracts/libraries/HyperdriveMath.sol @@ -136,7 +136,7 @@ library HyperdriveMath { uint256 curveOut = YieldSpaceMath.calculateOutGivenIn( // Credit the share reserves by the flat trade. _shareReserves.add(flat), - // Dedit the bond reserves by the flat trade. + // Debit the bond reserves by the flat trade. _bondReserves.sub(flat.mulDown(_sharePrice)), _bondReserveAdjustment, curveIn, @@ -160,7 +160,7 @@ library HyperdriveMath { // traded on a YieldSpace curve configured to timeRemaining = 1. uint256 flat = _amountIn .mulDown(FixedPointMath.ONE_18.sub(_timeRemaining)) - .divDow(_sharePrice); + .divDown(_sharePrice); uint256 curveIn = _amountIn.mulDown(_timeRemaining).divDown( _sharePrice ); From 84fe169b0f10791b196d6fa6e5ba490cac62310d Mon Sep 17 00:00:00 2001 From: Alex Towle Date: Wed, 8 Feb 2023 21:15:47 -0600 Subject: [PATCH 3/3] Addressed review feedback from @jrhea --- contracts/libraries/Errors.sol | 5 ----- contracts/libraries/HyperdriveMath.sol | 10 ++++------ 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/contracts/libraries/Errors.sol b/contracts/libraries/Errors.sol index 245d9418b..bf3d3887e 100644 --- a/contracts/libraries/Errors.sol +++ b/contracts/libraries/Errors.sol @@ -36,11 +36,6 @@ library Errors { error FixedPointMath_NegativeOrZeroInput(); error FixedPointMath_NegativeInput(); - /// ###################### - /// ### HyperdriveMath ### - /// ###################### - error HyperdriveMath_BaseWithNonzeroTime(); - /// ############### /// ### AssetId ### /// ############### diff --git a/contracts/libraries/HyperdriveMath.sol b/contracts/libraries/HyperdriveMath.sol index 3cbfaf36b..ba509c0cb 100644 --- a/contracts/libraries/HyperdriveMath.sol +++ b/contracts/libraries/HyperdriveMath.sol @@ -124,14 +124,14 @@ library HyperdriveMath { uint256 userDelta ) { + uint256 flat = _amountIn.mulDown( + FixedPointMath.ONE_18.sub(_timeRemaining) + ); if (_isBondOut) { // We consider (1-timeRemaining)*amountIn of the bonds being // purchased to be fully matured and we use the remaining // timeRemaining*amountIn shares to purchase newly minted bonds on a // YieldSpace curve configured to timeRemaining = 1. - uint256 flat = _amountIn.mulDown( - FixedPointMath.ONE_18.sub(_timeRemaining) - ); uint256 curveIn = _amountIn.mulDown(_timeRemaining); uint256 curveOut = YieldSpaceMath.calculateOutGivenIn( // Credit the share reserves by the flat trade. @@ -158,9 +158,7 @@ library HyperdriveMath { // (our result is given in shares, so we divide the one-to-one // redemption by the share price) and the newly minted bonds are // traded on a YieldSpace curve configured to timeRemaining = 1. - uint256 flat = _amountIn - .mulDown(FixedPointMath.ONE_18.sub(_timeRemaining)) - .divDown(_sharePrice); + flat = flat.divDown(_sharePrice); uint256 curveIn = _amountIn.mulDown(_timeRemaining).divDown( _sharePrice );