diff --git a/src/lib/ExclusivityLib.sol b/src/lib/ExclusivityLib.sol index 04df46c6..35ef7ff7 100644 --- a/src/lib/ExclusivityLib.sol +++ b/src/lib/ExclusivityLib.sol @@ -42,7 +42,7 @@ library ExclusivityLib { OutputToken[] memory outputs = order.outputs; for (uint256 i = 0; i < outputs.length;) { OutputToken memory output = outputs[i]; - output.amount = output.amount.mulDivDown(BPS + exclusivityOverrideBps, BPS); + output.amount = output.amount.mulDivUp(BPS + exclusivityOverrideBps, BPS); unchecked { i++; diff --git a/test/lib/ExclusivityLib.t.sol b/test/lib/ExclusivityLib.t.sol index 03a49d6e..eae4ac02 100644 --- a/test/lib/ExclusivityLib.t.sol +++ b/test/lib/ExclusivityLib.t.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; import {Test} from "forge-std/Test.sol"; +import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol"; import {MockERC20} from "../util/mock/MockERC20.sol"; import {OutputsBuilder} from "../util/OutputsBuilder.sol"; import {MockExclusivityLib} from "../util/mock/MockExclusivityLib.sol"; @@ -10,6 +11,8 @@ import {OrderInfo, ResolvedOrder, OutputToken} from "../../src/base/ReactorStruc import {OrderInfoBuilder} from "../util/OrderInfoBuilder.sol"; contract ExclusivityLibTest is Test { + using FixedPointMathLib for uint256; + MockExclusivityLib exclusivity; address token1; address token2; @@ -117,6 +120,18 @@ contract ExclusivityLibTest is Test { assertEq(handled.outputs[0].recipient, recipient); } + function testHandleExclusiveOverrideRoundUp() public { + ResolvedOrder memory order; + order.outputs = OutputsBuilder.single(token1, 1 ether + 1, recipient); + uint256 overrideAmt = 3000; + vm.prank(address(2)); + ResolvedOrder memory handled = + exclusivity.handleExclusiveOverride(order, address(1), block.timestamp + 1, overrideAmt); + // assert overrideAmt applied + assertEq(handled.outputs[0].amount, 1.3 ether + 2); + assertEq(handled.outputs[0].recipient, recipient); + } + function testHandleExclusiveOverrideApplied(address caller, address exclusive, uint256 overrideAmt, uint128 amount) public { @@ -129,7 +144,7 @@ contract ExclusivityLibTest is Test { ResolvedOrder memory handled = exclusivity.handleExclusiveOverride(order, exclusive, block.timestamp + 1, overrideAmt); // assert overrideAmt applied - assertEq(handled.outputs[0].amount, amount * (10000 + overrideAmt) / 10000); + assertEq(handled.outputs[0].amount, uint256(amount).mulDivUp(10000 + overrideAmt, 10000)); assertEq(handled.outputs[0].recipient, recipient); } @@ -154,7 +169,7 @@ contract ExclusivityLibTest is Test { exclusivity.handleExclusiveOverride(order, exclusive, block.timestamp + 1, overrideAmt); // assert overrideAmt applied for (uint256 i = 0; i < amounts.length; i++) { - assertEq(handled.outputs[i].amount, amounts[i] * (10000 + overrideAmt) / 10000); + assertEq(handled.outputs[i].amount, uint256(amounts[i]).mulDivUp(10000 + overrideAmt, 10000)); assertEq(handled.outputs[i].recipient, recipient); } } diff --git a/test/reactors/ExclusiveDutchOrderReactor.t.sol b/test/reactors/ExclusiveDutchOrderReactor.t.sol index 29cb84fe..daec3ff8 100644 --- a/test/reactors/ExclusiveDutchOrderReactor.t.sol +++ b/test/reactors/ExclusiveDutchOrderReactor.t.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; import {Test} from "forge-std/Test.sol"; +import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol"; import {DeployPermit2} from "../util/DeployPermit2.sol"; import {DutchOrder} from "../../src/reactors/DutchOrderReactor.sol"; import { @@ -28,6 +29,7 @@ import {BaseDutchOrderReactorTest} from "./BaseDutchOrderReactor.t.sol"; contract ExclusiveDutchOrderReactorTest is PermitSignature, DeployPermit2, BaseDutchOrderReactorTest { using OrderInfoBuilder for OrderInfo; using ExclusiveDutchOrderLib for ExclusiveDutchOrder; + using FixedPointMathLib for uint256; function name() public pure override returns (string memory) { return "ExclusiveDutchOrder"; @@ -429,7 +431,7 @@ contract ExclusiveDutchOrderReactorTest is PermitSignature, DeployPermit2, BaseD vm.prank(caller); fillContract.execute(signedOrder); - assertEq(tokenOut.balanceOf(swapper), amountOut * (10000 + overrideAmt) / 10000); + assertEq(tokenOut.balanceOf(swapper), uint256(amountOut).mulDivUp(10000 + overrideAmt, 10000)); assertEq(tokenIn.balanceOf(address(fillContract)), amountIn); } @@ -447,7 +449,7 @@ contract ExclusiveDutchOrderReactorTest is PermitSignature, DeployPermit2, BaseD tokenIn.forceApprove(swapper, address(permit2), type(uint256).max); uint256 amountOutSum = 0; for (uint256 i = 0; i < amountOuts.length; i++) { - amountOutSum += amountOuts[i] * (10000 + overrideAmt) / 10000; + amountOutSum += uint256(amountOuts[i]).mulDivUp(10000 + overrideAmt, 10000); } tokenOut.mint(address(fillContract), uint256(amountOutSum));