From 1b4e825f0c195180b1f13e9bf5be14a4a5c8c0e3 Mon Sep 17 00:00:00 2001 From: Jean-Grimal Date: Mon, 23 Oct 2023 17:22:43 +0200 Subject: [PATCH] fix: issue 23 --- src/ERC4626Bundler.sol | 4 +-- src/MorphoBundler.sol | 9 +++-- src/Permit2Bundler.sol | 3 +- src/PermitBundler.sol | 3 +- src/TransferBundler.sol | 3 +- src/WNativeBundler.sol | 6 ++-- src/ethereum/EthereumPermitBundler.sol | 3 +- .../ICompoundV2MigrationBundler.sol | 7 ++++ src/interfaces/IWNativeBundler.sol | 7 ++++ src/migration/AaveV2MigrationBundler.sol | 3 +- src/migration/AaveV3MigrationBundler.sol | 3 +- .../AaveV3OptimizerMigrationBundler.sol | 12 ++++--- src/migration/CompoundV2MigrationBundler.sol | 3 +- src/migration/CompoundV3MigrationBundler.sol | 9 +++-- test/forge/ERC4626BundlerLocalTest.sol | 10 ++++++ test/forge/MorphoBundlerLocalTest.sol | 15 ++++++++ test/forge/PermitBundlerLocalTest.sol | 11 ++++++ test/forge/TransferBundlerLocalTest.sol | 7 ++++ .../EthereumPermitBundlerEthereumTest.sol | 11 ++++++ .../ethereum/Permit2BundlerEthereumTest.sol | 8 +++++ .../ethereum/WNativeBundlerEthereumTest.sol | 15 ++++++++ ...V2EthereumMigrationBundlerEthereumTest.sol | 7 ++++ .../AaveV3MigrationBundlerEthereumTest.sol | 7 ++++ ...3OptimizerMigrationBundlerEthereumTest.sol | 36 +++++++++++++++++++ ...BorrowableMigrationBundlerEthereumTest.sol | 8 +++++ ...CompoundV3MigrationBundlerEthereumTest.sol | 25 +++++++++++++ 26 files changed, 214 insertions(+), 21 deletions(-) create mode 100644 src/interfaces/ICompoundV2MigrationBundler.sol create mode 100644 src/interfaces/IWNativeBundler.sol diff --git a/src/ERC4626Bundler.sol b/src/ERC4626Bundler.sol index 22219e9d..9ee44f9d 100644 --- a/src/ERC4626Bundler.sol +++ b/src/ERC4626Bundler.sol @@ -60,10 +60,10 @@ abstract contract ERC4626Bundler is BaseBundler { /// @notice Withdraws the given amount of `assets` from the given ERC4626 `vault`, transferring assets to /// `receiver`. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Pass `type(uint256).max` as `assets` to withdraw max. /// @dev Assumes the given `vault` implements EIP-4626. function erc4626Withdraw(address vault, uint256 assets, address receiver) external payable { + _checkInitiated(); require(receiver != address(0), ErrorsLib.ZERO_ADDRESS); /// Do not check `receiver != address(this)` to allow the bundler to receive the underlying asset. @@ -77,10 +77,10 @@ abstract contract ERC4626Bundler is BaseBundler { } /// @notice Redeems the given amount of `shares` from the given ERC4626 `vault`, transferring assets to `receiver`. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Pass `type(uint256).max` as `shares` to redeem max. /// @dev Assumes the given `vault` implements EIP-4626. function erc4626Redeem(address vault, uint256 shares, address receiver) external payable { + _checkInitiated(); require(receiver != address(0), ErrorsLib.ZERO_ADDRESS); /// Do not check `receiver != address(this)` to allow the bundler to receive the underlying asset. diff --git a/src/MorphoBundler.sol b/src/MorphoBundler.sol index 00aa7bb4..d71fe38f 100644 --- a/src/MorphoBundler.sol +++ b/src/MorphoBundler.sol @@ -111,12 +111,13 @@ abstract contract MorphoBundler is BaseBundler, IMorphoBundler { } /// @notice Borrows `amount` of `asset` on behalf of the sender. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Initiator must have previously authorized the bundler to act on their behalf on Morpho. function morphoBorrow(MarketParams calldata marketParams, uint256 amount, uint256 shares, address receiver) external payable { + _checkInitiated(); + MORPHO.borrow(marketParams, amount, shares, initiator(), receiver); } @@ -142,22 +143,24 @@ abstract contract MorphoBundler is BaseBundler, IMorphoBundler { } /// @notice Withdraws `amount` of the loan asset on behalf of `onBehalf`. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Initiator must have previously authorized the bundler to act on their behalf on Morpho. function morphoWithdraw(MarketParams calldata marketParams, uint256 amount, uint256 shares, address receiver) external payable { + _checkInitiated(); + MORPHO.withdraw(marketParams, amount, shares, initiator(), receiver); } /// @notice Withdraws `amount` of the collateral asset on behalf of sender. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Initiator must have previously authorized the bundler to act on their behalf on Morpho. function morphoWithdrawCollateral(MarketParams calldata marketParams, uint256 amount, address receiver) external payable { + _checkInitiated(); + MORPHO.withdrawCollateral(marketParams, amount, initiator(), receiver); } diff --git a/src/Permit2Bundler.sol b/src/Permit2Bundler.sol index 7be7d88e..3b9ebcdf 100644 --- a/src/Permit2Bundler.sol +++ b/src/Permit2Bundler.sol @@ -18,12 +18,13 @@ abstract contract Permit2Bundler is BaseBundler { /* ACTIONS */ /// @notice Permits and performs a transfer from the initiator to the recipient via Permit2. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Pass `permit.permitted.amount = type(uint256).max` to transfer all. function permit2TransferFrom(ISignatureTransfer.PermitTransferFrom memory permit, bytes memory signature) external payable { + _checkInitiated(); + address initiator = initiator(); uint256 amount = Math.min(permit.permitted.amount, ERC20(permit.permitted.token).balanceOf(initiator)); diff --git a/src/PermitBundler.sol b/src/PermitBundler.sol index ee916336..45aa6268 100644 --- a/src/PermitBundler.sol +++ b/src/PermitBundler.sol @@ -12,12 +12,13 @@ import {BaseBundler} from "./BaseBundler.sol"; abstract contract PermitBundler is BaseBundler { /// @notice Permits the given `amount` of `asset` from sender to be spent by the bundler via EIP-2612 Permit with /// the given `deadline` & EIP-712 signature's `v`, `r` & `s`. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Pass `skipRevert == true` to avoid reverting the whole bundle in case the signature expired. function permit(address asset, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s, bool skipRevert) external payable { + _checkInitiated(); + try IERC20Permit(asset).permit(initiator(), address(this), amount, deadline, v, r, s) {} catch (bytes memory returnData) { if (!skipRevert) _revert(returnData); diff --git a/src/TransferBundler.sol b/src/TransferBundler.sol index 4b3e5169..5ccd4e4c 100644 --- a/src/TransferBundler.sol +++ b/src/TransferBundler.sol @@ -46,9 +46,10 @@ abstract contract TransferBundler is BaseBundler { } /// @notice Transfers the given `amount` of `asset` from sender to this contract via ERC20 transferFrom. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Pass `amount = type(uint256).max` to transfer all. function erc20TransferFrom(address asset, uint256 amount) external payable { + _checkInitiated(); + address initiator = initiator(); amount = Math.min(amount, ERC20(asset).balanceOf(initiator)); diff --git a/src/WNativeBundler.sol b/src/WNativeBundler.sol index 88d64525..c9cd1352 100644 --- a/src/WNativeBundler.sol +++ b/src/WNativeBundler.sol @@ -38,9 +38,10 @@ abstract contract WNativeBundler is BaseBundler { /* ACTIONS */ /// @notice Wraps the given `amount` of the native token to wNative. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Pass `amount = type(uint256).max` to wrap all. function wrapNative(uint256 amount) external payable { + _checkInitiated(); + amount = Math.min(amount, address(this).balance); require(amount != 0, ErrorsLib.ZERO_AMOUNT); @@ -49,9 +50,10 @@ abstract contract WNativeBundler is BaseBundler { } /// @notice Unwraps the given `amount` of wNative to the native token. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Pass `amount = type(uint256).max` to unwrap all. function unwrapNative(uint256 amount) external payable { + _checkInitiated(); + amount = Math.min(amount, ERC20(WRAPPED_NATIVE).balanceOf(address(this))); require(amount != 0, ErrorsLib.ZERO_AMOUNT); diff --git a/src/ethereum/EthereumPermitBundler.sol b/src/ethereum/EthereumPermitBundler.sol index 780d88f9..f6e75e6c 100644 --- a/src/ethereum/EthereumPermitBundler.sol +++ b/src/ethereum/EthereumPermitBundler.sol @@ -14,12 +14,13 @@ import {PermitBundler} from "../PermitBundler.sol"; abstract contract EthereumPermitBundler is PermitBundler { /// @notice Permits DAI from sender to be spent by the bundler with the given `nonce`, `expiry` & EIP-712 /// signature's `v`, `r` & `s`. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Pass `skipRevert = true` to avoid reverting the whole bundle in case the signature expired. function permitDai(uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s, bool skipRevert) external payable { + _checkInitiated(); + try IDaiPermit(MainnetLib.DAI).permit(initiator(), address(this), nonce, expiry, allowed, v, r, s) {} catch (bytes memory returnData) { if (!skipRevert) _revert(returnData); diff --git a/src/interfaces/ICompoundV2MigrationBundler.sol b/src/interfaces/ICompoundV2MigrationBundler.sol new file mode 100644 index 00000000..b04b4edb --- /dev/null +++ b/src/interfaces/ICompoundV2MigrationBundler.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + +interface ICompoundV2MigrationBundler { + function compoundV2Repay(address cToken, uint256 amount) external payable; + function compoundV2Redeem(address cToken, uint256 amount) external payable; +} diff --git a/src/interfaces/IWNativeBundler.sol b/src/interfaces/IWNativeBundler.sol new file mode 100644 index 00000000..91b2be8d --- /dev/null +++ b/src/interfaces/IWNativeBundler.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + +interface IWNativeBundler { + function wrapNative(uint256 amount) external; + function unwrapNative(uint256 amount) external; +} diff --git a/src/migration/AaveV2MigrationBundler.sol b/src/migration/AaveV2MigrationBundler.sol index a52ba9ae..4f2e2c70 100644 --- a/src/migration/AaveV2MigrationBundler.sol +++ b/src/migration/AaveV2MigrationBundler.sol @@ -27,9 +27,10 @@ contract AaveV2MigrationBundler is MigrationBundler { /* ACTIONS */ /// @notice Repays `amount` of `asset` on AaveV2, on behalf of the initiator. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Pass `amount = type(uint256).max` to repay all. function aaveV2Repay(address asset, uint256 amount, uint256 interestRateMode) external payable { + _checkInitiated(); + amount = Math.min(amount, ERC20(asset).balanceOf(address(this))); require(amount != 0, ErrorsLib.ZERO_AMOUNT); diff --git a/src/migration/AaveV3MigrationBundler.sol b/src/migration/AaveV3MigrationBundler.sol index 270f49bf..9d8309e1 100644 --- a/src/migration/AaveV3MigrationBundler.sol +++ b/src/migration/AaveV3MigrationBundler.sol @@ -26,9 +26,10 @@ contract AaveV3MigrationBundler is MigrationBundler { /* ACTIONS */ /// @notice Repays `amount` of `asset` on AaveV3, on behalf of the initiator. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Pass `amount = type(uint256).max` to repay all. function aaveV3Repay(address asset, uint256 amount, uint256 interestRateMode) external payable { + _checkInitiated(); + amount = Math.min(amount, ERC20(asset).balanceOf(address(this))); require(amount != 0, ErrorsLib.ZERO_AMOUNT); diff --git a/src/migration/AaveV3OptimizerMigrationBundler.sol b/src/migration/AaveV3OptimizerMigrationBundler.sol index 6bd25279..a752f51c 100644 --- a/src/migration/AaveV3OptimizerMigrationBundler.sol +++ b/src/migration/AaveV3OptimizerMigrationBundler.sol @@ -27,9 +27,10 @@ contract AaveV3OptimizerMigrationBundler is MigrationBundler { /* ACTIONS */ /// @notice Repays `amount` of `underlying` on the AaveV3 Optimizer, on behalf of the initiator. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Pass `amount = type(uint256).max` to repay all. function aaveV3OptimizerRepay(address underlying, uint256 amount) external payable { + _checkInitiated(); + amount = Math.min(amount, ERC20(underlying).balanceOf(address(this))); require(amount != 0, ErrorsLib.ZERO_AMOUNT); @@ -41,34 +42,37 @@ contract AaveV3OptimizerMigrationBundler is MigrationBundler { /// @notice Repays `amount` of `underlying` on the AaveV3 Optimizer, on behalf of the initiator, transferring funds /// to `receiver`. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Initiator must have previously approved the bundler to manage their AaveV3 Optimizer position. /// @dev Pass `amount = type(uint256).max` to withdraw all. function aaveV3OptimizerWithdraw(address underlying, uint256 amount, address receiver, uint256 maxIterations) external payable { + _checkInitiated(); + AAVE_V3_OPTIMIZER.withdraw(underlying, amount, initiator(), receiver, maxIterations); } /// @notice Repays `amount` of `underlying` on the AaveV3 Optimizer, on behalf of the initiator, transferring funds /// to `receiver`. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Initiator must have previously approved the bundler to manage their AaveV3 Optimizer position. /// @dev Pass `amount = type(uint256).max` to withdraw all. function aaveV3OptimizerWithdrawCollateral(address underlying, uint256 amount, address receiver) external payable { + _checkInitiated(); + AAVE_V3_OPTIMIZER.withdrawCollateral(underlying, amount, initiator(), receiver); } /// @notice Approves the bundler to act on behalf of the initiator on the AaveV3 Optimizer, given a signed EIP-712 /// approval message. - /// @notice Warning: should only be called via the bundler's `multicall` function. function aaveV3OptimizerApproveManagerWithSig( bool isApproved, uint256 nonce, uint256 deadline, Types.Signature calldata signature ) external payable { + _checkInitiated(); + AAVE_V3_OPTIMIZER.approveManagerWithSig(initiator(), address(this), isApproved, nonce, deadline, signature); } } diff --git a/src/migration/CompoundV2MigrationBundler.sol b/src/migration/CompoundV2MigrationBundler.sol index b5a46cbf..28b84a99 100644 --- a/src/migration/CompoundV2MigrationBundler.sol +++ b/src/migration/CompoundV2MigrationBundler.sol @@ -36,9 +36,10 @@ contract CompoundV2MigrationBundler is WNativeBundler, MigrationBundler { /* ACTIONS */ /// @notice Repays `amount` of `cToken`'s underlying asset, on behalf of the initiator. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Pass `amount = type(uint256).max` to repay all. function compoundV2Repay(address cToken, uint256 amount) external payable { + _checkInitiated(); + if (cToken == C_ETH) { amount = Math.min(amount, address(this).balance); diff --git a/src/migration/CompoundV3MigrationBundler.sol b/src/migration/CompoundV3MigrationBundler.sol index 9bd7fd97..e4aaf2a6 100644 --- a/src/migration/CompoundV3MigrationBundler.sol +++ b/src/migration/CompoundV3MigrationBundler.sol @@ -20,10 +20,11 @@ contract CompoundV3MigrationBundler is MigrationBundler { /* ACTIONS */ /// @notice Repays `amount` of `asset` on the CompoundV3 `instance`, on behalf of the initiator. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Assumes the given instance is a CompoundV3 instance. /// @dev Pass `amount = type(uint256).max` to repay all. function compoundV3Repay(address instance, address asset, uint256 amount) external payable { + _checkInitiated(); + amount = Math.min(amount, ERC20(asset).balanceOf(address(this))); require(amount != 0, ErrorsLib.ZERO_AMOUNT); @@ -43,17 +44,17 @@ contract CompoundV3MigrationBundler is MigrationBundler { } /// @notice Withdraws `amount` of `asset` from the CompoundV3 `instance`, on behalf of the initiator. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Initiator must have previously approved the bundler to manage their CompoundV3 position. /// @dev Assumes the given `instance` is a CompoundV3 instance. /// @dev Pass `amount = type(uint256).max` to withdraw all. function compoundV3WithdrawFrom(address instance, address asset, uint256 amount) external payable { + _checkInitiated(); + ICompoundV3(instance).withdrawFrom(initiator(), address(this), asset, amount); } /// @notice Approves the bundler to act on behalf of the initiator on the CompoundV3 `instance`, given a signed /// EIP-712 approval message. - /// @notice Warning: should only be called via the bundler's `multicall` function. /// @dev Assumes the given `instance` is a CompoundV3 instance. function compoundV3AllowBySig( address instance, @@ -64,6 +65,8 @@ contract CompoundV3MigrationBundler is MigrationBundler { bytes32 r, bytes32 s ) external payable { + _checkInitiated(); + ICompoundV3(instance).allowBySig(initiator(), address(this), isAllowed, nonce, expiry, v, r, s); } } diff --git a/test/forge/ERC4626BundlerLocalTest.sol b/test/forge/ERC4626BundlerLocalTest.sol index 2b05fc5e..8299c38a 100644 --- a/test/forge/ERC4626BundlerLocalTest.sol +++ b/test/forge/ERC4626BundlerLocalTest.sol @@ -47,6 +47,11 @@ contract ERC4626BundlerLocalTest is LocalTest { bundler.multicall(bundle); } + function test4626DepositUninitiated(uint256 assets) public { + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + ERC4626BundlerMock(address(bundler)).erc4626Withdraw(address(vault), assets, RECEIVER); + } + function testErc4626WithdrawZeroAdressVault(uint256 assets) public { bundle.push(_erc4626Withdraw(address(0), assets, RECEIVER)); @@ -61,6 +66,11 @@ contract ERC4626BundlerLocalTest is LocalTest { bundler.multicall(bundle); } + function test4626RedeemUninitiated(uint256 assets) public { + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + ERC4626BundlerMock(address(bundler)).erc4626Redeem(address(vault), assets, RECEIVER); + } + function testErc4626RedeemZeroAdressVault(uint256 assets) public { bundle.push(_erc4626Redeem(address(0), assets, RECEIVER)); diff --git a/test/forge/MorphoBundlerLocalTest.sol b/test/forge/MorphoBundlerLocalTest.sol index 4a652e9e..c5109a24 100644 --- a/test/forge/MorphoBundlerLocalTest.sol +++ b/test/forge/MorphoBundlerLocalTest.sol @@ -215,6 +215,11 @@ contract MorphoBundlerLocalTest is LocalTest { _testSupplyCollateral(amount, onBehalf); } + function testWithdrawUninitiated(uint256 withdrawnShares) public { + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + MorphoBundlerMock(address(bundler)).morphoWithdraw(marketParams, 0, withdrawnShares, RECEIVER); + } + function testWithdraw(uint256 privateKey, uint256 amount, uint256 withdrawnShares) public { address user; (privateKey, user) = _boundPrivateKey(privateKey); @@ -247,6 +252,11 @@ contract MorphoBundlerLocalTest is LocalTest { assertEq(morpho.borrowShares(id, user), 0, "borrowShares(user)"); } + function testBorrowUnititiated(uint256 borrowedAssets) public { + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + MorphoBundlerMock(address(bundler)).morphoBorrow(marketParams, borrowedAssets, 0, RECEIVER); + } + function _testSupplyCollateralBorrow(address user, uint256 amount, uint256 collateralAmount) internal { assertEq(collateralToken.balanceOf(RECEIVER), 0, "collateral.balanceOf(RECEIVER)"); assertEq(loanToken.balanceOf(RECEIVER), amount, "loan.balanceOf(RECEIVER)"); @@ -316,6 +326,11 @@ contract MorphoBundlerLocalTest is LocalTest { _testSupplyCollateralBorrow(user, amount, collateralAmount); } + function testWithdrawCollateralUninitiated(uint256 collateralAmount) public { + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + MorphoBundlerMock(address(bundler)).morphoWithdrawCollateral(marketParams, collateralAmount, RECEIVER); + } + function _testRepayWithdrawCollateral(address user, uint256 collateralAmount) internal { assertEq(collateralToken.balanceOf(RECEIVER), collateralAmount, "collateral.balanceOf(RECEIVER)"); assertEq(loanToken.balanceOf(RECEIVER), 0, "loan.balanceOf(RECEIVER)"); diff --git a/test/forge/PermitBundlerLocalTest.sol b/test/forge/PermitBundlerLocalTest.sol index b3722cf6..da754556 100644 --- a/test/forge/PermitBundlerLocalTest.sol +++ b/test/forge/PermitBundlerLocalTest.sol @@ -35,6 +35,17 @@ contract PermitBundlerLocalTest is LocalTest { assertEq(permitToken.allowance(user, address(bundler)), amount, "allowance(user, bundler)"); } + function testPermitUninitiated(uint256 amount) public { + amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT); + + uint8 v; + bytes32 r; + bytes32 s; + + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + PermitBundlerMock(address(bundler)).permit(address(loanToken), amount, SIGNATURE_DEADLINE, v, r, s, true); + } + function testPermitRevert(uint256 amount, uint256 privateKey, uint256 deadline) public { amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT); deadline = bound(deadline, block.timestamp, type(uint48).max); diff --git a/test/forge/TransferBundlerLocalTest.sol b/test/forge/TransferBundlerLocalTest.sol index 3b3d0dbf..683d86d2 100644 --- a/test/forge/TransferBundlerLocalTest.sol +++ b/test/forge/TransferBundlerLocalTest.sol @@ -93,6 +93,13 @@ contract TransferBundlerLocalTest is LocalTest { assertEq(loanToken.balanceOf(USER), 0, "loan.balanceOf(USER)"); } + function testTransferFromUninitiated(uint256 amount) public { + amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT); + + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + TransferBundlerMock(address(bundler)).erc20TransferFrom(address(loanToken), amount); + } + function testTranferFromZeroAddress(uint256 amount) public { amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT); diff --git a/test/forge/ethereum/EthereumPermitBundlerEthereumTest.sol b/test/forge/ethereum/EthereumPermitBundlerEthereumTest.sol index 30fde51e..2f5360eb 100644 --- a/test/forge/ethereum/EthereumPermitBundlerEthereumTest.sol +++ b/test/forge/ethereum/EthereumPermitBundlerEthereumTest.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; +import {ErrorsLib} from "../../../src/libraries/ErrorsLib.sol"; + import {DaiPermit} from "../helpers/SigUtils.sol"; import "../../../src/mocks/bundlers/ethereum/EthereumPermitBundlerMock.sol"; @@ -32,6 +34,15 @@ contract EthereumPermitBundlerEthereumTest is EthereumTest { assertEq(ERC20(DAI).allowance(user, address(bundler)), type(uint256).max, "allowance(user, bundler)"); } + function testPermitDaiUninitiated() public { + uint8 v; + bytes32 r; + bytes32 s; + + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + EthereumPermitBundlerMock(address(bundler)).permitDai(0, SIGNATURE_DEADLINE, true, v, r, s, true); + } + function testPermitDaiRevert(uint256 privateKey, uint256 expiry) public { expiry = bound(expiry, block.timestamp, type(uint48).max); privateKey = bound(privateKey, 1, type(uint160).max); diff --git a/test/forge/ethereum/Permit2BundlerEthereumTest.sol b/test/forge/ethereum/Permit2BundlerEthereumTest.sol index 659951d4..bd9641d2 100644 --- a/test/forge/ethereum/Permit2BundlerEthereumTest.sol +++ b/test/forge/ethereum/Permit2BundlerEthereumTest.sol @@ -40,6 +40,14 @@ contract Permit2BundlerEthereumTest is EthereumTest { assertEq(ERC20(marketParams.loanToken).balanceOf(address(bundler)), amount, "loan.balanceOf(bundler)"); } + function testPermtestPermit2TransferFromUninitiated() public { + ISignatureTransfer.PermitTransferFrom memory permit; + bytes memory signature; + + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + Permit2BundlerMock(address(bundler)).permit2TransferFrom(permit, signature); + } + function testPermit2TransferFromZeroAmount(uint256 seed, uint256 privateKey, uint256 amount) public { privateKey = bound(privateKey, 1, type(uint160).max); amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT); diff --git a/test/forge/ethereum/WNativeBundlerEthereumTest.sol b/test/forge/ethereum/WNativeBundlerEthereumTest.sol index 2b3bc7c0..c52a9df3 100644 --- a/test/forge/ethereum/WNativeBundlerEthereumTest.sol +++ b/test/forge/ethereum/WNativeBundlerEthereumTest.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.0; import {ErrorsLib} from "../../../src/libraries/ErrorsLib.sol"; import "../../../src/mocks/bundlers/WNativeBundlerMock.sol"; +import "../../../src/interfaces/IWNativeBundler.sol"; import "./helpers/EthereumTest.sol"; @@ -17,6 +18,13 @@ contract WNativeBundlerEthereumTest is EthereumTest { ERC20(WETH).approve(address(bundler), type(uint256).max); } + function testWrapUninitiated(uint256 amount) public { + amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT); + + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + IWNativeBundler(address(bundler)).wrapNative(amount); + } + function testWrapZeroAmount() public { bundle.push(abi.encodeCall(WNativeBundler.wrapNative, (0))); @@ -45,6 +53,13 @@ contract WNativeBundlerEthereumTest is EthereumTest { assertEq(RECEIVER.balance, 0, "Receiver's native token balance"); } + function testUnwrapUninitiated(uint256 amount) public { + amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT); + + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + IWNativeBundler(address(bundler)).unwrapNative(amount); + } + function testUnwrapZeroAmount() public { bundle.push(abi.encodeCall(WNativeBundler.unwrapNative, (0))); diff --git a/test/forge/ethereum/migration/AaveV2EthereumMigrationBundlerEthereumTest.sol b/test/forge/ethereum/migration/AaveV2EthereumMigrationBundlerEthereumTest.sol index 7b11204d..b2586530 100644 --- a/test/forge/ethereum/migration/AaveV2EthereumMigrationBundlerEthereumTest.sol +++ b/test/forge/ethereum/migration/AaveV2EthereumMigrationBundlerEthereumTest.sol @@ -31,6 +31,13 @@ contract AaveV2EthereumMigrationBundlerEthereumTest is EthereumMigrationTest { bundler = new AaveV2EthereumMigrationBundler(address(morpho)); } + function testAaveV2RepayUninitiated(uint256 amount) public { + amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT); + + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + AaveV2EthereumMigrationBundler(address(bundler)).aaveV2Repay(marketParams.loanToken, amount, 1); + } + function testAaveV2RepayZeroAmount() public { bundle.push(_aaveV2Repay(marketParams.loanToken, 0)); diff --git a/test/forge/ethereum/migration/AaveV3MigrationBundlerEthereumTest.sol b/test/forge/ethereum/migration/AaveV3MigrationBundlerEthereumTest.sol index b8632637..c4154d53 100644 --- a/test/forge/ethereum/migration/AaveV3MigrationBundlerEthereumTest.sol +++ b/test/forge/ethereum/migration/AaveV3MigrationBundlerEthereumTest.sol @@ -31,6 +31,13 @@ contract AaveV3MigrationBundlerEthereumTest is EthereumMigrationTest { vm.label(address(bundler), "Aave V3 Migration Bundler"); } + function testAaveV3RepayUninitiated(uint256 amount) public { + amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT); + + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + AaveV3MigrationBundler(address(bundler)).aaveV3Repay(marketParams.loanToken, amount, 1); + } + function testAaveV3RepayZeroAmount() public { bundle.push(_aaveV3Repay(marketParams.loanToken, 0)); diff --git a/test/forge/ethereum/migration/AaveV3OptimizerMigrationBundlerEthereumTest.sol b/test/forge/ethereum/migration/AaveV3OptimizerMigrationBundlerEthereumTest.sol index 2d6eb90d..d863e3c5 100644 --- a/test/forge/ethereum/migration/AaveV3OptimizerMigrationBundlerEthereumTest.sol +++ b/test/forge/ethereum/migration/AaveV3OptimizerMigrationBundlerEthereumTest.sol @@ -31,6 +31,13 @@ contract AaveV3OptimizerMigrationBundlerEthereumTest is EthereumMigrationTest { bundler = new AaveV3OptimizerMigrationBundler(address(morpho), address(AAVE_V3_OPTIMIZER)); } + function testAaveV3OptimizerRepayUninitiated(uint256 amount) public { + amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT); + + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + AaveV3OptimizerMigrationBundler(address(bundler)).aaveV3OptimizerRepay(marketParams.loanToken, amount); + } + function testAaveV3Optimizer3RepayZeroAmount() public { bundle.push(_aaveV3OptimizerRepay(marketParams.loanToken, 0)); @@ -153,6 +160,17 @@ contract AaveV3OptimizerMigrationBundlerEthereumTest is EthereumMigrationTest { /* ACTIONS */ + function testAaveV3OptimizerApproveManagerUninitiated(uint256 amount) public { + amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT); + + Types.Signature memory sig; + + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + AaveV3OptimizerMigrationBundler(address(bundler)).aaveV3OptimizerApproveManagerWithSig( + true, 0, SIGNATURE_DEADLINE, sig + ); + } + function _aaveV3OptimizerApproveManager(uint256 privateKey, address manager, bool isAllowed, uint256 nonce) internal view @@ -176,6 +194,15 @@ contract AaveV3OptimizerMigrationBundlerEthereumTest is EthereumMigrationTest { return abi.encodeCall(AaveV3OptimizerMigrationBundler.aaveV3OptimizerRepay, (underlying, amount)); } + function testAaveV3OptimizerWithdrawUninitiated(uint256 amount) public { + amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT); + + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + AaveV3OptimizerMigrationBundler(address(bundler)).aaveV3OptimizerWithdraw( + marketParams.loanToken, amount, RECEIVER, MAX_ITERATIONS + ); + } + function _aaveV3OptimizerWithdraw(address underlying, uint256 amount, address receiver) internal pure @@ -186,6 +213,15 @@ contract AaveV3OptimizerMigrationBundlerEthereumTest is EthereumMigrationTest { ); } + function testAaveV3OptimizerWithdrawCollateralUninitiated(uint256 amount) public { + amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT); + + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + AaveV3OptimizerMigrationBundler(address(bundler)).aaveV3OptimizerWithdrawCollateral( + marketParams.loanToken, amount, RECEIVER + ); + } + function _aaveV3OptimizerWithdrawCollateral(address underlying, uint256 amount, address receiver) internal pure diff --git a/test/forge/ethereum/migration/CompoundV2EthBorrowableMigrationBundlerEthereumTest.sol b/test/forge/ethereum/migration/CompoundV2EthBorrowableMigrationBundlerEthereumTest.sol index cc697ca9..7f9841b7 100644 --- a/test/forge/ethereum/migration/CompoundV2EthBorrowableMigrationBundlerEthereumTest.sol +++ b/test/forge/ethereum/migration/CompoundV2EthBorrowableMigrationBundlerEthereumTest.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.0; import {IComptroller} from "../../../../src/migration/interfaces/IComptroller.sol"; import "../../../../src/migration/CompoundV2MigrationBundler.sol"; +import "../../../../src/interfaces/ICompoundV2MigrationBundler.sol"; import "./helpers/EthereumMigrationTest.sol"; @@ -26,6 +27,13 @@ contract CompoundV2EthLoanMigrationBundlerEthereumTest is EthereumMigrationTest enteredMarkets.push(C_DAI_V2); } + function testCompoundV2RepayUninitiated(uint256 amount) public { + amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT); + + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + ICompoundV2MigrationBundler(address(bundler)).compoundV2Repay(C_DAI_V2, amount); + } + function testCompoundV2RepayCEthZeroAmount() public { bundle.push(_compoundV2Repay(C_ETH_V2, 0)); diff --git a/test/forge/ethereum/migration/CompoundV3MigrationBundlerEthereumTest.sol b/test/forge/ethereum/migration/CompoundV3MigrationBundlerEthereumTest.sol index ecb7930e..1918aada 100644 --- a/test/forge/ethereum/migration/CompoundV3MigrationBundlerEthereumTest.sol +++ b/test/forge/ethereum/migration/CompoundV3MigrationBundlerEthereumTest.sol @@ -24,6 +24,13 @@ contract CompoundV3MigrationBundlerEthereumTest is EthereumMigrationTest { bundler = new CompoundV3MigrationBundler(address(morpho)); } + function testCompoundV3RepayUninitiated(uint256 amount) public { + amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT); + + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + CompoundV3MigrationBundler(address(bundler)).compoundV3Repay(C_WETH_V3, marketParams.loanToken, amount); + } + function testCompoundV3RepayZeroAmount() public { bundle.push(_compoundV3Repay(C_WETH_V3, marketParams.loanToken, 0)); @@ -173,6 +180,17 @@ contract CompoundV3MigrationBundlerEthereumTest is EthereumMigrationTest { /* ACTIONS */ + function testCompoundV3AllowUninitiated() public { + uint8 v; + bytes32 r; + bytes32 s; + + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + CompoundV3MigrationBundler(address(bundler)).compoundV3AllowBySig( + C_WETH_V3, true, 0, SIGNATURE_DEADLINE, v, r, s + ); + } + function _compoundV3Allow(uint256 privateKey, address instance, address manager, bool isAllowed, uint256 nonce) internal view @@ -203,6 +221,13 @@ contract CompoundV3MigrationBundlerEthereumTest is EthereumMigrationTest { return abi.encodeCall(CompoundV3MigrationBundler.compoundV3Withdraw, (instance, asset, amount)); } + function testCompoundV3WithdrawFromUninitiated(uint256 amount) public { + amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT); + + vm.expectRevert(bytes(ErrorsLib.UNINITIATED)); + CompoundV3MigrationBundler(address(bundler)).compoundV3WithdrawFrom(C_WETH_V3, marketParams.loanToken, amount); + } + function _compoundV3WithdrawFrom(address instance, address asset, uint256 amount) internal pure