diff --git a/.forge-snapshots/Base-V3DutchOrder-BaseExecuteSingleWithFee.snap b/.forge-snapshots/Base-V3DutchOrder-BaseExecuteSingleWithFee.snap index d0e11ef3..8d568a0e 100644 --- a/.forge-snapshots/Base-V3DutchOrder-BaseExecuteSingleWithFee.snap +++ b/.forge-snapshots/Base-V3DutchOrder-BaseExecuteSingleWithFee.snap @@ -1 +1 @@ -199162 \ No newline at end of file +199140 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatch.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatch.snap index b686cada..8435ecfc 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatch.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatch.snap @@ -1 +1 @@ -231943 \ No newline at end of file +231899 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputs.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputs.snap index 93bce628..94184e2e 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputs.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputs.snap @@ -1 +1 @@ -245803 \ No newline at end of file +245748 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputsDifferentTokens.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputsDifferentTokens.snap index 34c24fb0..6c03d83b 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputsDifferentTokens.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputsDifferentTokens.snap @@ -1 +1 @@ -303588 \ No newline at end of file +303522 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchNativeOutput.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchNativeOutput.snap index 6b14a7ee..04a1e7b7 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchNativeOutput.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchNativeOutput.snap @@ -1 +1 @@ -225470 \ No newline at end of file +225426 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingle.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingle.snap index ed4964dc..5d053c0e 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingle.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingle.snap @@ -1 +1 @@ -165545 \ No newline at end of file +165523 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleNativeOutput.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleNativeOutput.snap index 74c548a4..588d4376 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleNativeOutput.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleNativeOutput.snap @@ -1 +1 @@ -151107 \ No newline at end of file +151085 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleValidation.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleValidation.snap index cc88aca3..08e791ca 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleValidation.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleValidation.snap @@ -1 +1 @@ -174856 \ No newline at end of file +174834 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-RevertInvalidNonce.snap b/.forge-snapshots/Base-V3DutchOrder-RevertInvalidNonce.snap index 959c1f86..55167125 100644 --- a/.forge-snapshots/Base-V3DutchOrder-RevertInvalidNonce.snap +++ b/.forge-snapshots/Base-V3DutchOrder-RevertInvalidNonce.snap @@ -1 +1 @@ -44180 \ No newline at end of file +44158 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-V3-ExclusiveFiller.snap b/.forge-snapshots/Base-V3DutchOrder-V3-ExclusiveFiller.snap index 8ea13b83..2d877d64 100644 --- a/.forge-snapshots/Base-V3DutchOrder-V3-ExclusiveFiller.snap +++ b/.forge-snapshots/Base-V3DutchOrder-V3-ExclusiveFiller.snap @@ -1 +1 @@ -169480 \ No newline at end of file +169458 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-V3-InputOverride.snap b/.forge-snapshots/Base-V3DutchOrder-V3-InputOverride.snap index 563a0ff4..dcd33d51 100644 --- a/.forge-snapshots/Base-V3DutchOrder-V3-InputOverride.snap +++ b/.forge-snapshots/Base-V3DutchOrder-V3-InputOverride.snap @@ -1 +1 @@ -169561 \ No newline at end of file +169539 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-V3-OutputOverride.snap b/.forge-snapshots/Base-V3DutchOrder-V3-OutputOverride.snap index 8cac0069..d107b689 100644 --- a/.forge-snapshots/Base-V3DutchOrder-V3-OutputOverride.snap +++ b/.forge-snapshots/Base-V3DutchOrder-V3-OutputOverride.snap @@ -1 +1 @@ -169504 \ No newline at end of file +169482 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecay.snap b/.forge-snapshots/V3-DutchDecay.snap index 55abb6fe..284a734f 100644 --- a/.forge-snapshots/V3-DutchDecay.snap +++ b/.forge-snapshots/V3-DutchDecay.snap @@ -1 +1 @@ -13131 \ No newline at end of file +13371 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayBounded.snap b/.forge-snapshots/V3-DutchDecayBounded.snap index 7862d759..29001eb5 100644 --- a/.forge-snapshots/V3-DutchDecayBounded.snap +++ b/.forge-snapshots/V3-DutchDecayBounded.snap @@ -1 +1 @@ -1209 \ No newline at end of file +1206 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayFullyDecayed.snap b/.forge-snapshots/V3-DutchDecayFullyDecayed.snap index a2953231..e2b27312 100644 --- a/.forge-snapshots/V3-DutchDecayFullyDecayed.snap +++ b/.forge-snapshots/V3-DutchDecayFullyDecayed.snap @@ -1 +1 @@ -6653 \ No newline at end of file +6779 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayFullyDecayedNegative.snap b/.forge-snapshots/V3-DutchDecayFullyDecayedNegative.snap index b8baf8da..67e488ea 100644 --- a/.forge-snapshots/V3-DutchDecayFullyDecayedNegative.snap +++ b/.forge-snapshots/V3-DutchDecayFullyDecayedNegative.snap @@ -1 +1 @@ -6341 \ No newline at end of file +6467 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayNegative.snap b/.forge-snapshots/V3-DutchDecayNegative.snap index 11b9a892..34201494 100644 --- a/.forge-snapshots/V3-DutchDecayNegative.snap +++ b/.forge-snapshots/V3-DutchDecayNegative.snap @@ -1 +1 @@ -1271 \ No newline at end of file +1265 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayNoDecayYet.snap b/.forge-snapshots/V3-DutchDecayNoDecayYet.snap index 9b08816d..222192ce 100644 --- a/.forge-snapshots/V3-DutchDecayNoDecayYet.snap +++ b/.forge-snapshots/V3-DutchDecayNoDecayYet.snap @@ -1 +1 @@ -4703 \ No newline at end of file +4697 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayNoDecayYetNegative.snap b/.forge-snapshots/V3-DutchDecayNoDecayYetNegative.snap index 9b08816d..222192ce 100644 --- a/.forge-snapshots/V3-DutchDecayNoDecayYetNegative.snap +++ b/.forge-snapshots/V3-DutchDecayNoDecayYetNegative.snap @@ -1 +1 @@ -4703 \ No newline at end of file +4697 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayRange.snap b/.forge-snapshots/V3-DutchDecayRange.snap index 11b9a892..34201494 100644 --- a/.forge-snapshots/V3-DutchDecayRange.snap +++ b/.forge-snapshots/V3-DutchDecayRange.snap @@ -1 +1 @@ -1271 \ No newline at end of file +1265 \ No newline at end of file diff --git a/.forge-snapshots/V3-ExtendedMultiPointDutchDecay.snap b/.forge-snapshots/V3-ExtendedMultiPointDutchDecay.snap index 90208a5f..6dffa512 100644 --- a/.forge-snapshots/V3-ExtendedMultiPointDutchDecay.snap +++ b/.forge-snapshots/V3-ExtendedMultiPointDutchDecay.snap @@ -1 +1 @@ -87250 \ No newline at end of file +88450 \ No newline at end of file diff --git a/.forge-snapshots/V3-MultiPointDutchDecay.snap b/.forge-snapshots/V3-MultiPointDutchDecay.snap index 37c7ea87..1a263175 100644 --- a/.forge-snapshots/V3-MultiPointDutchDecay.snap +++ b/.forge-snapshots/V3-MultiPointDutchDecay.snap @@ -1 +1 @@ -26056 \ No newline at end of file +26539 \ No newline at end of file diff --git a/src/lib/NonlinearDutchDecayLib.sol b/src/lib/NonlinearDutchDecayLib.sol index 05d1a95e..bdeaa5f1 100644 --- a/src/lib/NonlinearDutchDecayLib.sol +++ b/src/lib/NonlinearDutchDecayLib.sol @@ -5,6 +5,7 @@ import {OutputToken, InputToken} from "../base/ReactorStructs.sol"; import {V3DutchOutput, V3DutchInput, NonlinearDutchDecay} from "../lib/V3DutchOrderLib.sol"; import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol"; import {MathExt} from "./MathExt.sol"; +import {Math} from "openzeppelin-contracts/utils/math/Math.sol"; import {Uint16ArrayLibrary, Uint16Array, fromUnderlying} from "../types/Uint16Array.sol"; import {DutchDecayLib} from "./DutchDecayLib.sol"; @@ -39,8 +40,9 @@ library NonlinearDutchDecayLib { if (decayStartBlock >= block.number || curve.relativeAmounts.length == 0) { return startAmount.bound(minAmount, maxAmount); } - - uint16 blockDelta = uint16(block.number - decayStartBlock); + // If the blockDelta is larger than type(uint16).max, a downcast overflow will occur + // We prevent this by capping the blockDelta to type(uint16).max to express a full decay + uint16 blockDelta = uint16(Math.min(block.number - decayStartBlock, type(uint16).max)); (uint16 startPoint, uint16 endPoint, int256 relStartAmount, int256 relEndAmount) = locateCurvePosition(curve, blockDelta); // get decay of only the relative amounts diff --git a/test/lib/NonLinearDutchDecayLib.t.sol b/test/lib/NonLinearDutchDecayLib.t.sol index c4217418..8fa6c522 100644 --- a/test/lib/NonLinearDutchDecayLib.t.sol +++ b/test/lib/NonLinearDutchDecayLib.t.sol @@ -8,6 +8,7 @@ import {DutchDecayLib} from "../../src/lib/DutchDecayLib.sol"; import {NonlinearDutchDecayLib} from "../../src/lib/NonlinearDutchDecayLib.sol"; import {V3DutchOutput, V3DutchInput, NonlinearDutchDecay} from "../../src/lib/V3DutchOrderLib.sol"; import {Uint16Array, toUint256} from "../../src/types/Uint16Array.sol"; +import {Math} from "openzeppelin-contracts/utils/math/Math.sol"; import {ArrayBuilder} from "../util/ArrayBuilder.sol"; import {CurveBuilder} from "../util/CurveBuilder.sol"; @@ -474,4 +475,44 @@ contract NonlinearDutchDecayLibTest is Test, GasSnapshot { vm.expectRevert(NonlinearDutchDecayLib.InvalidDecayCurve.selector); mockNonlinearDutchDecayLibContract.decay(curve, startAmount, decayStartBlock, 1 ether, 1 ether); } + + function testFuzzDutchDecayBeyondUint16Max( + uint16 lastValidBlock, // For curve + uint256 decayAmountFuzz, // For curve + // decay(curve, startAmount, decayStartBlock, minAmount, maxAmount); + uint256 startAmount, + uint256 decayStartBlock, + uint256 minAmount, + uint256 maxAmount, + uint256 currentBlock + ) public { + vm.assume(decayStartBlock < type(uint256).max - type(uint16).max); + vm.assume(lastValidBlock > 0); + vm.assume(startAmount > 0 && startAmount < uint256(type(int256).max)); + vm.assume(maxAmount >= startAmount); + minAmount = bound(minAmount, 0, startAmount); + // bound only takes uint256, so we need to limit decayAmountFuzz to int256.max + // because we cast it to int256 in the decay function + decayAmountFuzz = bound(decayAmountFuzz, minAmount, startAmount); + + // Testing that we get a fully decayed curve instead of overflowed mistake + // This will happen when the block delta is larger than type(uint16).max + vm.assume(currentBlock > decayStartBlock + type(uint16).max); + + uint16[] memory blocks = new uint16[](1); + blocks[0] = lastValidBlock; + + int256[] memory decayAmounts = new int256[](1); + decayAmounts[0] = int256(decayAmountFuzz); + + NonlinearDutchDecay memory curve = CurveBuilder.multiPointCurve(blocks, decayAmounts); + + vm.roll(currentBlock); + uint256 decayed = NonlinearDutchDecayLib.decay(curve, startAmount, decayStartBlock, minAmount, maxAmount); + assertEq( + decayed, + Math.max(startAmount - decayAmountFuzz, minAmount), + "Should be fully decayed for block delta beyond uint16.max" + ); + } }