diff --git a/.gitmodules b/.gitmodules index c96f8a8..2ccadf4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,4 @@ [submodule "lib/openzeppelin"] path = lib/openzeppelin url = https://github.com/OpenZeppelin/openzeppelin-contracts + branch = release-v5.0 diff --git a/lib/openzeppelin b/lib/openzeppelin index fd81a96..dbb6104 160000 --- a/lib/openzeppelin +++ b/lib/openzeppelin @@ -1 +1 @@ -Subproject commit fd81a96f01cc42ef1c9a5399364968d0e07e9e90 +Subproject commit dbb6104ce834628e473d2173bbc9d47f81a9eec3 diff --git a/lib/uniswap-v2-core b/lib/uniswap-v2-core index 4dd5906..ee547b1 160000 --- a/lib/uniswap-v2-core +++ b/lib/uniswap-v2-core @@ -1 +1 @@ -Subproject commit 4dd59067c76dea4a0e8e4bfdda41877a6b16dedc +Subproject commit ee547b17853e71ed4e0101ccfd52e70d5acded58 diff --git a/src/ConstantProduct.sol b/src/ConstantProduct.sol index 1e3fe6d..fb3948c 100644 --- a/src/ConstantProduct.sol +++ b/src/ConstantProduct.sol @@ -269,6 +269,6 @@ contract ConstantProduct is IERC1271 { * @param spender The address that can transfer on behalf of this contract. */ function approveUnlimited(IERC20 token, address spender) internal { - OZIERC20(address(token)).safeApprove(spender, type(uint256).max); + OZIERC20(address(token)).forceApprove(spender, type(uint256).max); } } diff --git a/src/libraries/GetTradeableOrder.sol b/src/libraries/GetTradeableOrder.sol index a273cf8..546ed92 100644 --- a/src/libraries/GetTradeableOrder.sol +++ b/src/libraries/GetTradeableOrder.sol @@ -57,12 +57,12 @@ library GetTradeableOrder { sellToken = params.token0; buyToken = params.token1; sellAmount = selfReserve0 / 2 - Math.ceilDiv(selfReserve1TimesPriceNumerator, 2 * params.priceDenominator); - buyAmount = Math.mulDiv(sellAmount, selfReserve1, selfReserve0 - sellAmount, Math.Rounding.Up); + buyAmount = Math.mulDiv(sellAmount, selfReserve1, selfReserve0 - sellAmount, Math.Rounding.Ceil); } else { sellToken = params.token1; buyToken = params.token0; sellAmount = selfReserve1 / 2 - Math.ceilDiv(selfReserve0TimesPriceDenominator, 2 * params.priceNumerator); - buyAmount = Math.mulDiv(sellAmount, selfReserve0, selfReserve1 - sellAmount, Math.Rounding.Up); + buyAmount = Math.mulDiv(sellAmount, selfReserve0, selfReserve1 - sellAmount, Math.Rounding.Ceil); } order_ = GPv2Order.Data( diff --git a/src/oracles/BalancerWeightedPoolPriceOracle.sol b/src/oracles/BalancerWeightedPoolPriceOracle.sol index 7000cb0..fa22da8 100644 --- a/src/oracles/BalancerWeightedPoolPriceOracle.sol +++ b/src/oracles/BalancerWeightedPoolPriceOracle.sol @@ -137,8 +137,8 @@ contract BalancerWeightedPoolPriceOracle is IPriceOracle { } else { (max, min) = (num2, num1); } - uint256 logMax = Math.log2(max, Math.Rounding.Up); - uint256 logMin = Math.log2(min, Math.Rounding.Down); + uint256 logMax = Math.log2(max, Math.Rounding.Ceil); + uint256 logMin = Math.log2(min, Math.Rounding.Floor); if ((logMax <= 128) || (logMin <= TOLERANCE)) { return (num1, num2); diff --git a/test/ConstantProduct/ConstantProductTestHarness.sol b/test/ConstantProduct/ConstantProductTestHarness.sol index d6a07e7..5dcb8cc 100644 --- a/test/ConstantProduct/ConstantProductTestHarness.sol +++ b/test/ConstantProduct/ConstantProductTestHarness.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.24; import {BaseComposableCoWTest} from "lib/composable-cow/test/ComposableCoW.base.t.sol"; -import {ConstantProduct, GPv2Order, IERC20} from "src/ConstantProduct.sol"; +import {ConstantProduct, GPv2Order, IERC20, SafeERC20} from "src/ConstantProduct.sol"; import {UniswapV2PriceOracle, IUniswapV2Pair} from "src/oracles/UniswapV2PriceOracle.sol"; import {ISettlement} from "src/interfaces/ISettlement.sol"; diff --git a/test/ConstantProduct/DeploymentParamsTest.sol b/test/ConstantProduct/DeploymentParamsTest.sol index 82ade02..40187fe 100644 --- a/test/ConstantProduct/DeploymentParamsTest.sol +++ b/test/ConstantProduct/DeploymentParamsTest.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.24; -import {ConstantProductTestHarness, ConstantProduct, IERC20} from "./ConstantProductTestHarness.sol"; +import {ConstantProductTestHarness, ConstantProduct, IERC20, SafeERC20} from "./ConstantProductTestHarness.sol"; abstract contract DeploymentParamsTest is ConstantProductTestHarness { function testSetsDeploymentParameters() public { @@ -40,7 +40,8 @@ abstract contract DeploymentParamsTest is ConstantProductTestHarness { mockZeroAllowance(token, expectedDeploymentAddress(), spenderBadApproval); vm.mockCallRevert( address(token), - abi.encodeCall(IERC20.approve, (spenderBadApproval, type(uint256).max)), + // Notice: we intentionally don't match the approved amount. + abi.encodeWithSelector(IERC20.approve.selector, spenderBadApproval), "mock revert on approval" ); vm.mockCallRevert(address(token), hex"", abi.encode("Unexpected call to token contract")); @@ -93,7 +94,7 @@ abstract contract DeploymentParamsTest is ConstantProductTestHarness { ); vm.prank(defaultDeployer()); - vm.expectRevert("SafeERC20: ERC20 operation did not succeed"); + vm.expectRevert(abi.encodeWithSelector(SafeERC20.SafeERC20FailedOperation.selector, falseOnApproval)); new ConstantProduct(solutionSettler, falseOnApproval, regular); } diff --git a/test/ConstantProductFactory/ConstantProductFactoryTestHarness.sol b/test/ConstantProductFactory/ConstantProductFactoryTestHarness.sol index 2e73919..3476cc9 100644 --- a/test/ConstantProductFactory/ConstantProductFactoryTestHarness.sol +++ b/test/ConstantProductFactory/ConstantProductFactoryTestHarness.sol @@ -1,7 +1,14 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.24; -import {ConstantProductFactory, ConstantProduct, GPv2Order, ISettlement, IERC20} from "src/ConstantProductFactory.sol"; +import { + ConstantProductFactory, + ConstantProduct, + GPv2Order, + ISettlement, + IERC20, + SafeERC20 +} from "src/ConstantProductFactory.sol"; import {ConstantProductTestHarness} from "test/ConstantProduct/ConstantProductTestHarness.sol"; diff --git a/test/ConstantProductFactory/Deposit.sol b/test/ConstantProductFactory/Deposit.sol index 1f3d74d..076e143 100644 --- a/test/ConstantProductFactory/Deposit.sol +++ b/test/ConstantProductFactory/Deposit.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.24; import {IERC20} from "src/ConstantProductFactory.sol"; -import {ConstantProductFactoryTestHarness} from "./ConstantProductFactoryTestHarness.sol"; +import {ConstantProductFactoryTestHarness, SafeERC20} from "./ConstantProductFactoryTestHarness.sol"; abstract contract Deposit is ConstantProductFactoryTestHarness { function testAnyoneCanDeposit() public { @@ -54,7 +54,7 @@ abstract contract Deposit is ConstantProductFactoryTestHarness { abi.encode(false) ); - vm.expectRevert("SafeERC20: ERC20 operation did not succeed"); + vm.expectRevert(abi.encodeWithSelector(SafeERC20.SafeERC20FailedOperation.selector, token1)); constantProductFactory.deposit(constantProduct, amount0, amount1); } diff --git a/test/ConstantProductFactory/Withdraw.sol b/test/ConstantProductFactory/Withdraw.sol index 7938420..8b09987 100644 --- a/test/ConstantProductFactory/Withdraw.sol +++ b/test/ConstantProductFactory/Withdraw.sol @@ -5,7 +5,8 @@ import {ConstantProductFactory, IERC20} from "src/ConstantProductFactory.sol"; import { EditableOwnerConstantProductFactory, - ConstantProductFactoryTestHarness + ConstantProductFactoryTestHarness, + SafeERC20 } from "./ConstantProductFactoryTestHarness.sol"; abstract contract Withdraw is ConstantProductFactoryTestHarness { @@ -64,7 +65,7 @@ abstract contract Withdraw is ConstantProductFactoryTestHarness { token1, abi.encodeCall(IERC20.transferFrom, (address(constantProduct), owner, amount1)), abi.encode(false) ); - vm.expectRevert("SafeERC20: ERC20 operation did not succeed"); + vm.expectRevert(abi.encodeWithSelector(SafeERC20.SafeERC20FailedOperation.selector, token1)); vm.prank(owner); factory.withdraw(constantProduct, amount0, amount1); }