From 13ca0a920b806a62bdfb1a0e445a2db69fb6d685 Mon Sep 17 00:00:00 2001 From: Cody Born Date: Tue, 3 Sep 2024 17:01:52 -0400 Subject: [PATCH] More reactor tests, address PR feedback --- ...V3DutchOrder-BaseExecuteSingleWithFee.snap | 2 +- .../Base-V3DutchOrder-ExecuteBatch.snap | 2 +- ...utchOrder-ExecuteBatchMultipleOutputs.snap | 2 +- ...teBatchMultipleOutputsDifferentTokens.snap | 2 +- ...V3DutchOrder-ExecuteBatchNativeOutput.snap | 2 +- .../Base-V3DutchOrder-ExecuteSingle.snap | 2 +- ...3DutchOrder-ExecuteSingleNativeOutput.snap | 2 +- ...-V3DutchOrder-ExecuteSingleValidation.snap | 2 +- .../Base-V3DutchOrder-RevertInvalidNonce.snap | 2 +- .forge-snapshots/V3-DutchDecayBounded.snap | 2 +- .../V3-DutchDecayFullyDecayed.snap | 2 +- .../V3-DutchDecayFullyDecayedNegative.snap | 2 +- .../V3-ExtendedMultiPointDutchDecay.snap | 2 +- .../V3-LocateCurvePositionMulti.snap | 2 +- .../V3-LocateCurvePositionSingle.snap | 2 +- .forge-snapshots/V3-MultiPointDutchDecay.snap | 2 +- src/lib/NonlinearDutchDecayLib.sol | 7 +- src/lib/V3DutchOrderLib.sol | 4 +- src/reactors/V3DutchOrderReactor.sol | 9 +- src/types/Uint16Array.sol | 2 - test/lib/NonLinearDutchDecayLib.t.sol | 1 - test/lib/Uint16Array.t.sol | 4 +- test/reactors/V3DutchOrderReactor.t.sol | 687 +++++++++++++++--- test/util/OutputsBuilder.sol | 18 +- 24 files changed, 622 insertions(+), 142 deletions(-) diff --git a/.forge-snapshots/Base-V3DutchOrder-BaseExecuteSingleWithFee.snap b/.forge-snapshots/Base-V3DutchOrder-BaseExecuteSingleWithFee.snap index 2825e932..f096fc15 100644 --- a/.forge-snapshots/Base-V3DutchOrder-BaseExecuteSingleWithFee.snap +++ b/.forge-snapshots/Base-V3DutchOrder-BaseExecuteSingleWithFee.snap @@ -1 +1 @@ -192981 \ No newline at end of file +192980 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatch.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatch.snap index 2ab57fb9..6f25147c 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatch.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatch.snap @@ -1 +1 @@ -219434 \ No newline at end of file +219432 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputs.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputs.snap index 3c001253..173e14c0 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputs.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputs.snap @@ -1 +1 @@ -231444 \ No newline at end of file +231439 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputsDifferentTokens.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputsDifferentTokens.snap index eef5a09a..921318a6 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputsDifferentTokens.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputsDifferentTokens.snap @@ -1 +1 @@ -287371 \ No newline at end of file +287363 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchNativeOutput.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchNativeOutput.snap index b4dbf0f4..b67cac65 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchNativeOutput.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchNativeOutput.snap @@ -1 +1 @@ -212953 \ No newline at end of file +212951 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingle.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingle.snap index d1ade6b4..8ae6c44e 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingle.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingle.snap @@ -1 +1 @@ -159369 \ No newline at end of file +159368 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleNativeOutput.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleNativeOutput.snap index eab5e06d..9507876d 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleNativeOutput.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleNativeOutput.snap @@ -1 +1 @@ -144927 \ No newline at end of file +144926 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleValidation.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleValidation.snap index d23dabd5..6523b747 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleValidation.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleValidation.snap @@ -1 +1 @@ -168675 \ No newline at end of file +168674 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-RevertInvalidNonce.snap b/.forge-snapshots/Base-V3DutchOrder-RevertInvalidNonce.snap index 0e0324bc..4159e5c8 100644 --- a/.forge-snapshots/Base-V3DutchOrder-RevertInvalidNonce.snap +++ b/.forge-snapshots/Base-V3DutchOrder-RevertInvalidNonce.snap @@ -1 +1 @@ -37963 \ No newline at end of file +37962 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayBounded.snap b/.forge-snapshots/V3-DutchDecayBounded.snap index db604d62..3af7d09a 100644 --- a/.forge-snapshots/V3-DutchDecayBounded.snap +++ b/.forge-snapshots/V3-DutchDecayBounded.snap @@ -1 +1 @@ -5778 \ No newline at end of file +1070 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayFullyDecayed.snap b/.forge-snapshots/V3-DutchDecayFullyDecayed.snap index a901a15c..55ffc0c6 100644 --- a/.forge-snapshots/V3-DutchDecayFullyDecayed.snap +++ b/.forge-snapshots/V3-DutchDecayFullyDecayed.snap @@ -1 +1 @@ -14782 \ No newline at end of file +14810 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayFullyDecayedNegative.snap b/.forge-snapshots/V3-DutchDecayFullyDecayedNegative.snap index 9ce7dd3d..718fee6a 100644 --- a/.forge-snapshots/V3-DutchDecayFullyDecayedNegative.snap +++ b/.forge-snapshots/V3-DutchDecayFullyDecayedNegative.snap @@ -1 +1 @@ -14634 \ No newline at end of file +14662 \ No newline at end of file diff --git a/.forge-snapshots/V3-ExtendedMultiPointDutchDecay.snap b/.forge-snapshots/V3-ExtendedMultiPointDutchDecay.snap index e4368d80..fa08fe03 100644 --- a/.forge-snapshots/V3-ExtendedMultiPointDutchDecay.snap +++ b/.forge-snapshots/V3-ExtendedMultiPointDutchDecay.snap @@ -1 +1 @@ -219186 \ No newline at end of file +208112 \ No newline at end of file diff --git a/.forge-snapshots/V3-LocateCurvePositionMulti.snap b/.forge-snapshots/V3-LocateCurvePositionMulti.snap index 6c884d81..06648cad 100644 --- a/.forge-snapshots/V3-LocateCurvePositionMulti.snap +++ b/.forge-snapshots/V3-LocateCurvePositionMulti.snap @@ -1 +1 @@ -24798 \ No newline at end of file +24086 \ No newline at end of file diff --git a/.forge-snapshots/V3-LocateCurvePositionSingle.snap b/.forge-snapshots/V3-LocateCurvePositionSingle.snap index 111a659b..ca44913f 100644 --- a/.forge-snapshots/V3-LocateCurvePositionSingle.snap +++ b/.forge-snapshots/V3-LocateCurvePositionSingle.snap @@ -1 +1 @@ -8820 \ No newline at end of file +8758 \ No newline at end of file diff --git a/.forge-snapshots/V3-MultiPointDutchDecay.snap b/.forge-snapshots/V3-MultiPointDutchDecay.snap index a605cd33..a507085d 100644 --- a/.forge-snapshots/V3-MultiPointDutchDecay.snap +++ b/.forge-snapshots/V3-MultiPointDutchDecay.snap @@ -1 +1 @@ -51976 \ No newline at end of file +51174 \ No newline at end of file diff --git a/src/lib/NonlinearDutchDecayLib.sol b/src/lib/NonlinearDutchDecayLib.sol index b8927759..9784081e 100644 --- a/src/lib/NonlinearDutchDecayLib.sol +++ b/src/lib/NonlinearDutchDecayLib.sol @@ -5,7 +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 {sub} from "./MathExt.sol"; -import {Uint16Array, fromUnderlying} from "../types/Uint16Array.sol"; +import {Uint16ArrayLibrary, Uint16Array, fromUnderlying} from "../types/Uint16Array.sol"; /// @notice thrown when the decay curve is invalid error InvalidDecayCurve(); @@ -14,6 +14,7 @@ error InvalidDecayCurve(); library NonlinearDutchDecayLib { using FixedPointMathLib for uint256; using {sub} for uint256; + using Uint16ArrayLibrary for Uint16Array; /// @notice locates the current position on the curve and calculates the decay /// @param curve The curve to search @@ -61,12 +62,12 @@ library NonlinearDutchDecayLib { returns (uint16 prev, uint16 next) { Uint16Array relativeBlocks = fromUnderlying(curve.relativeBlocks); - while (next < curve.relativeAmounts.length) { + uint16 curveLength = uint16(curve.relativeAmounts.length); + for (; next < curveLength; next++) { if (relativeBlocks.getElement(next) >= currentRelativeBlock) { return (prev, next); } prev = next; - next++; } return (next - 1, next - 1); } diff --git a/src/lib/V3DutchOrderLib.sol b/src/lib/V3DutchOrderLib.sol index 04783433..60a6145d 100644 --- a/src/lib/V3DutchOrderLib.sol +++ b/src/lib/V3DutchOrderLib.sol @@ -143,8 +143,8 @@ library V3DutchOrderLib { function hash(V3DutchOutput[] memory outputs) internal pure returns (bytes32) { unchecked { bytes memory packedHashes = new bytes(32 * outputs.length); - - for (uint256 i = 0; i < outputs.length; i++) { + uint256 outputsLength = outputs.length; + for (uint256 i = 0; i < outputsLength; i++) { bytes32 outputHash = hash(outputs[i]); assembly { mstore(add(add(packedHashes, 0x20), mul(i, 0x20)), outputHash) diff --git a/src/reactors/V3DutchOrderReactor.sol b/src/reactors/V3DutchOrderReactor.sol index 82e02339..465acec1 100644 --- a/src/reactors/V3DutchOrderReactor.sol +++ b/src/reactors/V3DutchOrderReactor.sol @@ -51,9 +51,6 @@ contract V3DutchOrderReactor is BaseReactor { // hash the order _before_ overriding amounts, as this is the hash the user would have signed bytes32 orderHash = order.hash(); - if (order.info.deadline < block.timestamp) { - revert DeadlineReached(); - } _validateOrder(orderHash, order); _updateWithCosignerAmounts(order); @@ -108,8 +105,12 @@ contract V3DutchOrderReactor is BaseReactor { /// @notice validate the dutch order fields /// - deadline must have not passed + /// - cosigner is valid if specified /// @dev Throws if the order is invalid - function _validateOrder(bytes32 orderHash, V3DutchOrder memory order) internal pure { + function _validateOrder(bytes32 orderHash, V3DutchOrder memory order) internal view { + if (order.info.deadline < block.timestamp) { + revert DeadlineReached(); + } (bytes32 r, bytes32 s) = abi.decode(order.cosignature, (bytes32, bytes32)); uint8 v = uint8(order.cosignature[64]); // cosigner signs over (orderHash || cosignerData) diff --git a/src/types/Uint16Array.sol b/src/types/Uint16Array.sol index b6624eae..a940d33a 100644 --- a/src/types/Uint16Array.sol +++ b/src/types/Uint16Array.sol @@ -4,8 +4,6 @@ pragma solidity ^0.8.0; /// @dev An uint16 array of max 16 values packed into a single uint256 type Uint16Array is uint256; -using Uint16ArrayLibrary for Uint16Array global; - error IndexOutOfBounds(); error InvalidArrLength(); diff --git a/test/lib/NonLinearDutchDecayLib.t.sol b/test/lib/NonLinearDutchDecayLib.t.sol index d87587ee..ed9d536d 100644 --- a/test/lib/NonLinearDutchDecayLib.t.sol +++ b/test/lib/NonLinearDutchDecayLib.t.sol @@ -200,7 +200,6 @@ contract NonlinearDutchDecayLibTest is Test, GasSnapshot { vm.assume(decayAmount > 0); vm.assume(decayAmount < 2 ** 255 - 1); vm.assume(startAmount <= UINT256_MAX - decayAmount); - vm.assume(decayDuration > 0); NonlinearDutchDecay memory curve = CurveBuilder.singlePointCurve(decayDuration, 0 - int256(decayAmount)); snapStart("V3-DutchDecayBounded"); diff --git a/test/lib/Uint16Array.t.sol b/test/lib/Uint16Array.t.sol index e54a3d67..2d0ede85 100644 --- a/test/lib/Uint16Array.t.sol +++ b/test/lib/Uint16Array.t.sol @@ -5,9 +5,11 @@ import {Test} from "forge-std/Test.sol"; import {NonlinearDutchDecayLib} from "../../src/lib/NonlinearDutchDecayLib.sol"; import {V3DutchOutput, V3DutchInput, NonlinearDutchDecay} from "../../src/lib/V3DutchOrderLib.sol"; import {ArrayBuilder} from "../util/ArrayBuilder.sol"; -import {Uint16Array, toUint16Array, InvalidArrLength, IndexOutOfBounds} from "../../src/types/Uint16Array.sol"; +import {Uint16ArrayLibrary, Uint16Array, toUint16Array, InvalidArrLength, IndexOutOfBounds} from "../../src/types/Uint16Array.sol"; contract Uint16ArrayTest is Test { + using Uint16ArrayLibrary for Uint16Array; + function testGetElement(uint16 value, uint16 length) public { vm.assume(length <= 16); Uint16Array packedArr = toUint16Array(ArrayBuilder.fillUint16(length, value)); diff --git a/test/reactors/V3DutchOrderReactor.t.sol b/test/reactors/V3DutchOrderReactor.t.sol index 26bc0557..77d2c2e3 100644 --- a/test/reactors/V3DutchOrderReactor.t.sol +++ b/test/reactors/V3DutchOrderReactor.t.sol @@ -27,10 +27,19 @@ import {PermitSignature} from "../util/PermitSignature.sol"; import {ReactorEvents} from "../../src/base/ReactorEvents.sol"; import {BaseReactorTest} from "../base/BaseReactor.t.sol"; import {CurveBuilder} from "../util/CurveBuilder.sol"; +import {OrderQuoter} from "../../src/lens/OrderQuoter.sol"; +import {Solarray} from "solarray/Solarray.sol"; +import {sub} from "../../src/lib/MathExt.sol"; contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { using OrderInfoBuilder for OrderInfo; - using V3DutchOrderLib for V3DutchOrder; + using V3DutchOrderLib for V3DutchOrder; + OrderQuoter quoter; + using {sub} for uint256; + + constructor() { + quoter = new OrderQuoter(); + } uint256 constant cosignerPrivateKey = 0x99999999; @@ -88,57 +97,9 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { return (SignedOrder(abi.encode(order), signOrder(swapperPrivateKey, address(permit2), order)), orderHash); } - function testWrongCosigner() public { - address wrongCosigner = makeAddr("wrongCosigner"); - CosignerData memory cosignerData = CosignerData({ - decayStartBlock: block.number, - exclusiveFiller: address(0), - exclusivityOverrideBps: 0, - inputAmount: 1 ether, - outputAmounts: ArrayBuilder.fill(1, 1 ether) - }); - - V3DutchOrder memory order = V3DutchOrder({ - info: OrderInfoBuilder.init(address(reactor)).withSwapper(swapper), - cosigner: wrongCosigner, - baseInput: V3DutchInput(tokenIn, 1 ether, CurveBuilder.emptyCurve(), 1 ether), - baseOutputs: OutputsBuilder.singleV3Dutch(address(tokenOut), 1 ether, 1 ether, swapper), - cosignerData: cosignerData, - cosignature: bytes("") - }); - order.cosignature = cosignOrder(order.hash(), cosignerData); - SignedOrder memory signedOrder = - SignedOrder(abi.encode(order), signOrder(swapperPrivateKey, address(permit2), order)); - vm.expectRevert(V3DutchOrderReactor.InvalidCosignature.selector); - fillContract.execute(signedOrder); - } - - function testInvalidCosignature() public { - address wrongCosigner = makeAddr("wrongCosigner"); - CosignerData memory cosignerData = CosignerData({ - decayStartBlock: block.number, - exclusiveFiller: address(0), - exclusivityOverrideBps: 0, - inputAmount: 1 ether, - outputAmounts: ArrayBuilder.fill(1, 1 ether) - }); - - V3DutchOrder memory order = V3DutchOrder({ - info: OrderInfoBuilder.init(address(reactor)).withSwapper(swapper), - cosigner: wrongCosigner, - baseInput: V3DutchInput(tokenIn, 1 ether, CurveBuilder.emptyCurve(), 1 ether), - baseOutputs: OutputsBuilder.singleV3Dutch(address(tokenOut), 1 ether, 1 ether, swapper), - cosignerData: cosignerData, - cosignature: bytes("") - }); - order.cosignature = bytes.concat(keccak256("invalidSignature"), keccak256("invalidSignature"), hex"33"); - SignedOrder memory signedOrder = - SignedOrder(abi.encode(order), signOrder(swapperPrivateKey, address(permit2), order)); - vm.expectRevert(V3DutchOrderReactor.InvalidCosignature.selector); - fillContract.execute(signedOrder); - } + /* Cosigner tests */ - function testInputOverrideWorse() public { + function testV3InputOverrideWorse() public { CosignerData memory cosignerData = CosignerData({ decayStartBlock: block.number, exclusiveFiller: address(0), @@ -152,7 +113,12 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { info: OrderInfoBuilder.init(address(reactor)).withSwapper(swapper), cosigner: vm.addr(cosignerPrivateKey), baseInput: V3DutchInput(tokenIn, 0.8 ether, CurveBuilder.emptyCurve(), 1 ether), - baseOutputs: OutputsBuilder.singleV3Dutch(address(tokenOut), 1 ether, 1 ether, swapper), + baseOutputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 1 ether, + CurveBuilder.singlePointCurve(1, 0 ether), + swapper + ), cosignerData: cosignerData, cosignature: bytes("") }); @@ -163,7 +129,7 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { fillContract.execute(signedOrder); } - function testOutputOverrideWorse() public { + function testV3OutputOverrideWorse() public { CosignerData memory cosignerData = CosignerData({ decayStartBlock: block.number, exclusiveFiller: address(0), @@ -177,7 +143,12 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { info: OrderInfoBuilder.init(address(reactor)).withSwapper(swapper), cosigner: vm.addr(cosignerPrivateKey), baseInput: V3DutchInput(tokenIn, 1 ether, CurveBuilder.emptyCurve(), 1 ether), - baseOutputs: OutputsBuilder.singleV3Dutch(address(tokenOut), 1 ether, 0.8 ether, swapper), + baseOutputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 1 ether, + CurveBuilder.singlePointCurve(1, .2 ether), + swapper + ), cosignerData: cosignerData, cosignature: bytes("") }); @@ -188,7 +159,7 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { fillContract.execute(signedOrder); } - function testOutputOverrideWrongLength() public { + function testV3OutputOverrideWrongLength() public { CosignerData memory cosignerData = CosignerData({ decayStartBlock: block.number, exclusiveFiller: address(0), @@ -202,7 +173,12 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { info: OrderInfoBuilder.init(address(reactor)).withSwapper(swapper), cosigner: vm.addr(cosignerPrivateKey), baseInput: V3DutchInput(tokenIn, 1 ether, CurveBuilder.emptyCurve(), 1 ether), - baseOutputs: OutputsBuilder.singleV3Dutch(address(tokenOut), 1 ether, 0.8 ether, swapper), + baseOutputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 1 ether, + CurveBuilder.singlePointCurve(1, .2 ether), + swapper + ), cosignerData: cosignerData, cosignature: bytes("") }); @@ -213,7 +189,7 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { fillContract.execute(signedOrder); } - function testOverrideInput() public { + function testV3OverrideInput() public { uint256 outputAmount = 1 ether; uint256 overriddenInputAmount = 0.7 ether; tokenIn.mint(swapper, overriddenInputAmount); @@ -231,7 +207,12 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { info: OrderInfoBuilder.init(address(reactor)).withSwapper(swapper), cosigner: vm.addr(cosignerPrivateKey), baseInput: V3DutchInput(tokenIn, 0.8 ether, CurveBuilder.emptyCurve(), 1 ether), - baseOutputs: OutputsBuilder.singleV3Dutch(address(tokenOut), outputAmount, outputAmount, swapper), + baseOutputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + outputAmount, + CurveBuilder.singlePointCurve(1, 0 ether), + swapper + ), cosignerData: cosignerData, cosignature: bytes("") }); @@ -248,7 +229,7 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { assertEq(tokenIn.balanceOf(address(fillContract)), overriddenInputAmount); } - function testOverrideOutput() public { + function testV3OverrideOutput() public { uint256 overriddenOutputAmount = 1.1 ether; uint256 inputAmount = 1 ether; tokenIn.mint(swapper, inputAmount); @@ -266,7 +247,12 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { info: OrderInfoBuilder.init(address(reactor)).withSwapper(swapper), cosigner: vm.addr(cosignerPrivateKey), baseInput: V3DutchInput(tokenIn, inputAmount, CurveBuilder.emptyCurve(), inputAmount), - baseOutputs: OutputsBuilder.singleV3Dutch(address(tokenOut), 1 ether, 0.9 ether, swapper), + baseOutputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 1 ether, + CurveBuilder.singlePointCurve(1, .1 ether), + swapper + ), cosignerData: cosignerData, cosignature: bytes("") }); @@ -283,7 +269,7 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { assertEq(tokenIn.balanceOf(address(fillContract)), inputAmount); } - function testStrictExclusivityInvalidCaller() public { + function testV3StrictExclusivityInvalidCaller() public { uint256 inputAmount = 1 ether; tokenIn.mint(swapper, inputAmount); tokenOut.mint(address(fillContract), inputAmount); @@ -300,7 +286,12 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { info: OrderInfoBuilder.init(address(reactor)).withSwapper(swapper), cosigner: vm.addr(cosignerPrivateKey), baseInput: V3DutchInput(tokenIn, inputAmount, CurveBuilder.emptyCurve(), inputAmount), - baseOutputs: OutputsBuilder.singleV3Dutch(address(tokenOut), 1 ether, 0.9 ether, swapper), + baseOutputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 1 ether, + CurveBuilder.singlePointCurve(1, .1 ether), + swapper + ), cosignerData: cosignerData, cosignature: bytes("") }); @@ -311,7 +302,7 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { fillContract.execute(signedOrder); } - function testStrictExclusivityValidCaller() public { + function testV3StrictExclusivityValidCaller() public { uint256 inputAmount = 1 ether; uint256 outputAmount = 1 ether; tokenIn.mint(swapper, inputAmount); @@ -329,7 +320,12 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { info: OrderInfoBuilder.init(address(reactor)).withSwapper(swapper), cosigner: vm.addr(cosignerPrivateKey), baseInput: V3DutchInput(tokenIn, inputAmount, CurveBuilder.emptyCurve(), inputAmount), - baseOutputs: OutputsBuilder.singleV3Dutch(address(tokenOut), outputAmount, 0.9 ether, swapper), + baseOutputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 1 ether, + CurveBuilder.singlePointCurve(1, .1 ether), + swapper + ), cosignerData: cosignerData, cosignature: bytes("") }); @@ -347,7 +343,7 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { assertEq(tokenIn.balanceOf(address(fillContract)), inputAmount); } - function testExclusiveOverrideInvalidCallerCosignedAmountOutput() public { + function testV3ExclusiveOverrideInvalidCallerCosignedAmountOutput() public { uint256 inputAmount = 1 ether; uint256 outputAmount = 1 ether; uint256 exclusivityOverrideBps = 10; @@ -366,7 +362,12 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { info: OrderInfoBuilder.init(address(reactor)).withSwapper(swapper), cosigner: vm.addr(cosignerPrivateKey), baseInput: V3DutchInput(tokenIn, inputAmount, CurveBuilder.emptyCurve(), inputAmount), - baseOutputs: OutputsBuilder.singleV3Dutch(address(tokenOut), 1 ether, 0.9 ether, swapper), + baseOutputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 1 ether, + CurveBuilder.singlePointCurve(1, .1 ether), + swapper + ), cosignerData: cosignerData, cosignature: bytes("") }); @@ -379,7 +380,7 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { assertEq(tokenIn.balanceOf(address(fillContract)), inputAmount); } - function testExclusiveOverrideInvalidCallerNoCosignedAmountOutput() public { + function testV3ExclusiveOverrideInvalidCallerNoCosignedAmountOutput() public { uint256 inputAmount = 1 ether; uint256 outputAmount = 1 ether; uint256 exclusivityOverrideBps = 10; @@ -398,7 +399,12 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { info: OrderInfoBuilder.init(address(reactor)).withSwapper(swapper), cosigner: vm.addr(cosignerPrivateKey), baseInput: V3DutchInput(tokenIn, inputAmount, CurveBuilder.emptyCurve(), inputAmount), - baseOutputs: OutputsBuilder.singleV3Dutch(address(tokenOut), outputAmount, 0.9 ether, swapper), + baseOutputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 1 ether, + CurveBuilder.singlePointCurve(1, .1 ether), + swapper + ), cosignerData: cosignerData, cosignature: bytes("") }); @@ -412,37 +418,520 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest { assertEq(tokenIn.balanceOf(address(fillContract)), inputAmount); } - // function testExecuteInputAndOutputDecay() public { - // uint256 inputAmount = 1 ether; - // uint256 outputAmount = 1 ether; - // uint256 startTime = block.timestamp; - // uint256 deadline = startTime + 1000; - // // Seed both swapper and fillContract with enough tokens (important for dutch order) - // tokenIn.mint(address(swapper), uint256(inputAmount) * 100); - // tokenOut.mint(address(fillContract), uint256(outputAmount) * 100); - // tokenIn.forceApprove(swapper, address(permit2), inputAmount); - - // SignedOrder memory order = generateOrder( - // TestDutchOrderSpec({ - // currentTime: startTime, - // startTime: startTime, - // endTime: deadline, - // deadline: deadline, - // input: V3DutchInput(tokenIn, inputAmount, inputAmount * 110 / 100), - // outputs: OutputsBuilder.singleV3Dutch(tokenOut, outputAmount, outputAmount * 90 / 100, address(swapper)) - // }) - // ); - // uint256 swapperInputBalanceStart = tokenIn.balanceOf(address(swapper)); - // uint256 swapperOutputBalanceStart = tokenOut.balanceOf(address(swapper)); - // vm.expectEmit(false, true, true, false, address(reactor)); - // emit Fill(keccak256("not checked"), address(fillContract), swapper, 0); - // vm.warp(startTime + 500); - // fillContract.execute(order); - // uint256 swapperInputBalanceEnd = tokenIn.balanceOf(address(swapper)); - // uint256 swapperOutputBalanceEnd = tokenOut.balanceOf(address(swapper)); - // assertEq(swapperInputBalanceStart - swapperInputBalanceEnd, inputAmount * 105 / 100); - // assertEq(swapperOutputBalanceEnd - swapperOutputBalanceStart, outputAmount * 95 / 100); - // } + /* Validation tests */ + + function testV3WrongCosigner() public { + address wrongCosigner = makeAddr("wrongCosigner"); + CosignerData memory cosignerData = CosignerData({ + decayStartBlock: block.number, + exclusiveFiller: address(0), + exclusivityOverrideBps: 0, + inputAmount: 1 ether, + outputAmounts: ArrayBuilder.fill(1, 1 ether) + }); + + V3DutchOrder memory order = V3DutchOrder({ + info: OrderInfoBuilder.init(address(reactor)).withSwapper(swapper), + cosigner: wrongCosigner, + baseInput: V3DutchInput(tokenIn, 1 ether, CurveBuilder.emptyCurve(), 1 ether), + baseOutputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 1 ether, + CurveBuilder.singlePointCurve(1, 0 ether), + swapper + ), + cosignerData: cosignerData, + cosignature: bytes("") + }); + order.cosignature = cosignOrder(order.hash(), cosignerData); + SignedOrder memory signedOrder = + SignedOrder(abi.encode(order), signOrder(swapperPrivateKey, address(permit2), order)); + vm.expectRevert(V3DutchOrderReactor.InvalidCosignature.selector); + fillContract.execute(signedOrder); + } + + function testV3InvalidCosignature() public { + address wrongCosigner = makeAddr("wrongCosigner"); + CosignerData memory cosignerData = CosignerData({ + decayStartBlock: block.number, + exclusiveFiller: address(0), + exclusivityOverrideBps: 0, + inputAmount: 1 ether, + outputAmounts: ArrayBuilder.fill(1, 1 ether) + }); + + V3DutchOrder memory order = V3DutchOrder({ + info: OrderInfoBuilder.init(address(reactor)).withSwapper(swapper), + cosigner: wrongCosigner, + baseInput: V3DutchInput(tokenIn, 1 ether, CurveBuilder.emptyCurve(), 1 ether), + baseOutputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 1 ether, + CurveBuilder.singlePointCurve(1, 0 ether), + swapper + ), + cosignerData: cosignerData, + cosignature: bytes("") + }); + order.cosignature = bytes.concat(keccak256("invalidSignature"), keccak256("invalidSignature"), hex"33"); + SignedOrder memory signedOrder = + SignedOrder(abi.encode(order), signOrder(swapperPrivateKey, address(permit2), order)); + vm.expectRevert(V3DutchOrderReactor.InvalidCosignature.selector); + fillContract.execute(signedOrder); + } + + function testV3ExecutePastDeadline() public { + uint256 inputAmount = 1 ether; + uint256 outputAmount = 1 ether; + uint256 startBlock = block.number; + uint256 deadline = block.timestamp + 1000; + tokenOut.mint(address(fillContract), uint256(outputAmount) * 100); + + SignedOrder memory order = generateOrder( + TestDutchOrderSpec({ + currentBlock: block.number, + startBlock: startBlock, + deadline: deadline, + input: V3DutchInput( + tokenIn, + inputAmount, + CurveBuilder.singlePointCurve(1000, 0-int256(inputAmount * 10 / 100)), + inputAmount * 110 / 100 + ), + outputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + outputAmount, + CurveBuilder.singlePointCurve(1000, int256(inputAmount * 10 / 100)), + address(swapper) + ) + }) + ); + vm.warp(deadline + 1); + vm.expectRevert(V3DutchOrderReactor.DeadlineReached.selector); + fillContract.execute(order); + } + + /* Block decay tests */ + + function testV3ExecuteInputAndOutputHalfDecay() public { + uint256 inputAmount = 1 ether; + uint256 outputAmount = 1 ether; + uint256 startBlock = block.number; + uint256 deadline = block.timestamp + 1000; + tokenOut.mint(address(fillContract), uint256(outputAmount) * 100); + + SignedOrder memory order = generateOrder( + TestDutchOrderSpec({ + currentBlock: block.number, + startBlock: startBlock, + deadline: deadline, + input: V3DutchInput( + tokenIn, + inputAmount, + CurveBuilder.singlePointCurve(1000, 0-int256(inputAmount * 10 / 100)), + inputAmount * 110 / 100 + ), + outputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + outputAmount, + CurveBuilder.singlePointCurve(1000, int256(inputAmount * 10 / 100)), + address(swapper) + ) + }) + ); + uint256 swapperInputBalanceStart = tokenIn.balanceOf(address(swapper)); + uint256 swapperOutputBalanceStart = tokenOut.balanceOf(address(swapper)); + vm.expectEmit(false, true, true, false, address(reactor)); + emit Fill(keccak256("not checked"), address(fillContract), swapper, 0); + vm.roll(startBlock + 500); + fillContract.execute(order); + uint256 swapperInputBalanceEnd = tokenIn.balanceOf(address(swapper)); + uint256 swapperOutputBalanceEnd = tokenOut.balanceOf(address(swapper)); + assertEq(swapperInputBalanceStart - swapperInputBalanceEnd, inputAmount * 105 / 100); + assertEq(swapperOutputBalanceEnd - swapperOutputBalanceStart, outputAmount * 95 / 100); + } + + function testV3ExecuteInputAndOutputFullDecay() public { + uint256 inputAmount = 1 ether; + uint256 outputAmount = 1 ether; + uint256 startBlock = block.number; + uint256 deadline = block.timestamp + 1000; + tokenOut.mint(address(fillContract), uint256(outputAmount) * 100); + + SignedOrder memory order = generateOrder( + TestDutchOrderSpec({ + currentBlock: block.number, + startBlock: startBlock, + deadline: deadline, + input: V3DutchInput( + tokenIn, + inputAmount, + CurveBuilder.singlePointCurve(1000, 0-int256(inputAmount * 10 / 100)), + inputAmount * 110 / 100 + ), + outputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + outputAmount, + CurveBuilder.singlePointCurve(1000, int256(inputAmount * 10 / 100)), + address(swapper) + ) + }) + ); + uint256 swapperInputBalanceStart = tokenIn.balanceOf(address(swapper)); + uint256 swapperOutputBalanceStart = tokenOut.balanceOf(address(swapper)); + vm.expectEmit(false, true, true, false, address(reactor)); + emit Fill(keccak256("not checked"), address(fillContract), swapper, 0); + vm.roll(startBlock + 1000); + fillContract.execute(order); + uint256 swapperInputBalanceEnd = tokenIn.balanceOf(address(swapper)); + uint256 swapperOutputBalanceEnd = tokenOut.balanceOf(address(swapper)); + assertEq(swapperInputBalanceStart - swapperInputBalanceEnd, inputAmount * 110 / 100); + assertEq(swapperOutputBalanceEnd - swapperOutputBalanceStart, outputAmount * 90 / 100); + } + + function testV3ResolveNotStarted() public { + uint256 currentBlock = 1000; + vm.roll(currentBlock); + + SignedOrder memory order = generateOrder( + TestDutchOrderSpec({ + currentBlock: currentBlock, + startBlock: currentBlock + 100, + deadline: currentBlock + 200, + input: V3DutchInput( + tokenIn, + 1000, + CurveBuilder.singlePointCurve(200, 1000), + 2000 + ), + outputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 0, + CurveBuilder.singlePointCurve(200, -100), + address(0) + ) + }) + ); + ResolvedOrder memory resolvedOrder = quoter.quote(order.order, order.sig); + assertEq(resolvedOrder.outputs[0].amount, 0); + assertEq(resolvedOrder.input.amount, 1000); + } + + function testV3ResolveOutputHalfwayDecayed() public { + uint256 currentBlock = 1000; + vm.roll(currentBlock); + + SignedOrder memory order = generateOrder( + TestDutchOrderSpec({ + currentBlock: currentBlock, + startBlock: currentBlock - 100, + deadline: currentBlock + 200, + input: V3DutchInput( + tokenIn, + 0, + CurveBuilder.singlePointCurve(100, 0), + 0 + ), + outputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 2000, + CurveBuilder.singlePointCurve(200, 1000), + address(0) + ) + }) + ); + ResolvedOrder memory resolvedOrder = quoter.quote(order.order, order.sig); + assertEq(resolvedOrder.outputs[0].amount, 1500); + assertEq(resolvedOrder.input.amount, 0); + } + + function testV3ResolveOutputFullyDecayed() public { + uint256 currentBlock = 1000; + vm.roll(currentBlock); + + SignedOrder memory order = generateOrder( + TestDutchOrderSpec({ + currentBlock: currentBlock, + startBlock: currentBlock - 200, + deadline: currentBlock + 200, + input: V3DutchInput( + tokenIn, + 100, + CurveBuilder.singlePointCurve(200, 100), + 100 + ), + outputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 2000, + CurveBuilder.singlePointCurve(200, 1000), + address(0) + ) + }) + ); + ResolvedOrder memory resolvedOrder = quoter.quote(order.order, order.sig); + assertEq(resolvedOrder.outputs[0].amount, 1000); + assertEq(resolvedOrder.input.amount, 0); + } + + function testV3ResolveInputHalfwayDecayed() public { + uint256 currentBlock = 1000; + vm.roll(currentBlock); + + SignedOrder memory order = generateOrder( + TestDutchOrderSpec({ + currentBlock: currentBlock, + startBlock: currentBlock - 100, + deadline: currentBlock + 200, + input: V3DutchInput( + tokenIn, + 1000, + CurveBuilder.singlePointCurve(200, 1000), + 1000 + ), + outputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 1000, + CurveBuilder.singlePointCurve(200, 0), + address(0) + ) + }) + ); + ResolvedOrder memory resolvedOrder = quoter.quote(order.order, order.sig); + assertEq(resolvedOrder.outputs[0].amount, 1000); + assertEq(resolvedOrder.input.amount, 500); + } + + function testV3ResolveInputFullyDecayed() public { + uint256 currentBlock = 1000; + vm.roll(currentBlock); + + SignedOrder memory order = generateOrder( + TestDutchOrderSpec({ + currentBlock: currentBlock, + startBlock: currentBlock - 100, + deadline: currentBlock + 200, + input: V3DutchInput( + tokenIn, + 1000, + CurveBuilder.singlePointCurve(100, 1000), + 1000 + ), + outputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 1000, + CurveBuilder.singlePointCurve(100, 0), + address(0) + ) + }) + ); + ResolvedOrder memory resolvedOrder = quoter.quote(order.order, order.sig); + assertEq(resolvedOrder.outputs[0].amount, 1000); + assertEq(resolvedOrder.input.amount, 0); + } + + // 1000 - (100 * (1659087340-1659029740) / (65535)) = 913 + function testV3ResolveEndBlockAfterNow() public { + uint256 currentBlock = 1659087340; + uint16 relativeEndBlock = 65535; + vm.roll(currentBlock); + + SignedOrder memory order = generateOrder( + TestDutchOrderSpec({ + currentBlock: currentBlock, + startBlock: 1659029740, + deadline: 1659130540, + input: V3DutchInput( + tokenIn, + 0, + CurveBuilder.singlePointCurve(relativeEndBlock, 0), + 0 + ), + outputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 1000, + CurveBuilder.singlePointCurve(relativeEndBlock, 100), + address(0) + ) + }) + ); + ResolvedOrder memory resolvedOrder = quoter.quote(order.order, order.sig); + assertEq(resolvedOrder.outputs[0].amount, 913); + assertEq(resolvedOrder.outputs.length, 1); + assertEq(resolvedOrder.input.amount, 0); + } + + // Test multiple dutch outputs get resolved correctly. + function testV3ResolveMultipleDutchOutputs() public { + uint256 currentBlock = 1659087340; + uint16 relativeEndBlock = 65535; + vm.roll(currentBlock); + + NonlinearDutchDecay[] memory curves = new NonlinearDutchDecay[](3); + curves[0] = CurveBuilder.singlePointCurve(relativeEndBlock, 100); + curves[1] = CurveBuilder.singlePointCurve(relativeEndBlock, 1000); + curves[2] = CurveBuilder.singlePointCurve(relativeEndBlock, 1000); + SignedOrder memory order = generateOrder( + TestDutchOrderSpec({ + currentBlock: currentBlock, + startBlock: 1659029740, + deadline: 1659130540, + input: V3DutchInput(tokenIn, 0, CurveBuilder.singlePointCurve(relativeEndBlock, 0), 0), + outputs: OutputsBuilder.multipleV3Dutch( + address(tokenOut), + Solarray.uint256s(1000, 10000, 2000), + curves, + address(0) + ) + }) + ); + ResolvedOrder memory resolvedOrder = quoter.quote(order.order, order.sig); + assertEq(resolvedOrder.outputs.length, 3); + assertEq(resolvedOrder.outputs[0].amount, 913); + assertEq(resolvedOrder.outputs[1].amount, 9122); + assertEq(resolvedOrder.outputs[2].amount, 1122); + assertEq(resolvedOrder.input.amount, 0); + } + + // Test that when decayStartBlock = now, that the output = startAmount + function testV3ResolveStartBlockEqualsNow() public { + uint256 currentBlock = 1659029740; + uint16 relativeEndBlock = 65535; + vm.roll(currentBlock); + + SignedOrder memory order = generateOrder( + TestDutchOrderSpec({ + currentBlock: currentBlock, + startBlock: currentBlock, + deadline: 1659130540, + input: V3DutchInput(tokenIn, 0, CurveBuilder.singlePointCurve(relativeEndBlock, 0), 0), + outputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 1000, + CurveBuilder.singlePointCurve(relativeEndBlock, 100), + address(0) + ) + }) + ); + ResolvedOrder memory resolvedOrder = quoter.quote(order.order, order.sig); + assertEq(resolvedOrder.outputs[0].amount, 1000); + assertEq(resolvedOrder.outputs.length, 1); + assertEq(resolvedOrder.input.amount, 0); + } + + // At block 1659030395, output will still be 1000. One block later at 1659030396, + // the first decay will occur and the output will be 999. + function testV3ResolveFirstDecay() public { + uint256 startBlock = 1659029740; + uint256 currentBlock = 1659030395; // 1659030395 - 1659029740 = 655 = 0.00999 * 65535 + uint16 relativeEndBlock = 65535; + vm.roll(currentBlock); + + SignedOrder memory order = generateOrder( + TestDutchOrderSpec({ + currentBlock: currentBlock, + startBlock: startBlock, + deadline: 1659130540, + input: V3DutchInput(tokenIn, 0, CurveBuilder.singlePointCurve(relativeEndBlock, 0), 0), + outputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + 1000, + CurveBuilder.singlePointCurve(relativeEndBlock, 100), + address(0) + ) + }) + ); + ResolvedOrder memory resolvedOrder = quoter.quote(order.order, order.sig); + assertEq(resolvedOrder.outputs[0].amount, 1000); + + vm.roll(currentBlock + 1); + resolvedOrder = quoter.quote(order.order, order.sig); + assertEq(resolvedOrder.outputs[0].amount, 999); + } + + function testV3FuzzPositiveDecayNeverOutOfBounds( + uint128 currentBlock, + uint128 decayStartBlock, + uint256 startAmount, + uint16 decayDuration, + uint256 decayAmount + ) public { + vm.assume(decayAmount > 0); + vm.assume(decayAmount < 2 ** 255 - 1); + vm.assume(startAmount <= UINT256_MAX - decayAmount); + + SignedOrder memory order = generateOrder( + TestDutchOrderSpec({ + currentBlock: uint256(currentBlock), + startBlock: uint256(decayStartBlock), + deadline: type(uint256).max, + input: V3DutchInput( + tokenIn, + 0, + CurveBuilder.singlePointCurve(decayDuration, 0), + 0 + ), + outputs: OutputsBuilder.singleV3Dutch( + address(tokenOut), + uint256(startAmount), + CurveBuilder.singlePointCurve(decayDuration, 0 - int256(decayAmount)), + address(0) + ) + }) + ); + ResolvedOrder memory resolvedOrder = quoter.quote(order.order, order.sig); + assertGe(resolvedOrder.outputs[0].amount, startAmount); + uint256 endAmount = startAmount + decayAmount; + assertLe(resolvedOrder.outputs[0].amount, endAmount); + } + + /* Test helpers */ + + struct TestDutchOrderSpec { + uint256 currentBlock; + uint256 startBlock; + uint256 deadline; + V3DutchInput input; + V3DutchOutput[] outputs; + } + + /// @dev Create a signed order and return the order and orderHash + /// @param request Order to sign + function createAndSignDutchOrder(V3DutchOrder memory request) + public + virtual + returns (SignedOrder memory signedOrder, bytes32 orderHash) + { + orderHash = request.hash(); + return (SignedOrder(abi.encode(request), signOrder(swapperPrivateKey, address(permit2), request)), orderHash); + } + + function generateOrder(TestDutchOrderSpec memory spec) internal returns (SignedOrder memory order) { + tokenIn.mint(address(swapper), uint256(spec.input.maxAmount)); + tokenIn.forceApprove(swapper, address(permit2), spec.input.maxAmount); + + uint256[] memory outputAmounts = new uint256[](spec.outputs.length); + for (uint256 i = 0; i < spec.outputs.length; i++) { + outputAmounts[i] = 0; + } + CosignerData memory cosignerData = CosignerData({ + decayStartBlock: spec.startBlock, + exclusiveFiller: address(0), + exclusivityOverrideBps: 0, + inputAmount: 0, + outputAmounts: outputAmounts + }); + V3DutchOrder memory request = V3DutchOrder({ + info: OrderInfoBuilder.init(address(reactor)).withDeadline(spec.deadline).withSwapper(address(swapper)), + cosigner: vm.addr(cosignerPrivateKey), + baseInput: spec.input, + baseOutputs: spec.outputs, + cosignerData: cosignerData, + cosignature: bytes("") + }); + bytes32 orderHash = request.hash(); + request.cosignature = cosignOrder(orderHash, cosignerData); + (order,) = createAndSignDutchOrder(request); + } function cosignOrder(bytes32 orderHash, CosignerData memory cosignerData) private pure returns (bytes memory sig) { bytes32 msgHash = keccak256(abi.encodePacked(orderHash, abi.encode(cosignerData))); diff --git a/test/util/OutputsBuilder.sol b/test/util/OutputsBuilder.sol index f0796be5..9943d273 100644 --- a/test/util/OutputsBuilder.sol +++ b/test/util/OutputsBuilder.sol @@ -92,35 +92,25 @@ library OutputsBuilder { return result; } - function singleV3Dutch(address token, uint256 amount, uint256 endAmount, address recipient) + function singleV3Dutch(address token, uint256 amount, NonlinearDutchDecay memory curve, address recipient) internal pure returns (V3DutchOutput[] memory) { - int256 delta = int256(amount - endAmount); - NonlinearDutchDecay memory curve = NonlinearDutchDecay({ - relativeBlocks: toUint256(ArrayBuilder.fillUint16(0, 0)), - relativeAmounts: ArrayBuilder.fillInt(1, delta) - }); V3DutchOutput[] memory result = new V3DutchOutput[](1); result[0] = V3DutchOutput(token, amount, curve, recipient); return result; } - function multipleV3Dutch(address token, uint256[] memory amounts, uint256 endAmount, address recipient) + function multipleV3Dutch(address token, uint256[] memory amounts, NonlinearDutchDecay[] memory curves, address recipient) internal pure returns (V3DutchOutput[] memory) { V3DutchOutput[] memory result = new V3DutchOutput[](amounts.length); for (uint256 i = 0; i < amounts.length; i++) { - int256 delta = int256(amounts[i] - endAmount); - NonlinearDutchDecay memory curve = NonlinearDutchDecay({ - relativeBlocks: toUint256(ArrayBuilder.fillUint16(0, 0)), - relativeAmounts: ArrayBuilder.fillInt(1, delta) - }); - result[i] = V3DutchOutput(token, amounts[i], curve, recipient); + result[i] = V3DutchOutput(token, amounts[i], curves[i], recipient); } return result; } -} +} \ No newline at end of file