|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | +pragma solidity ^0.8.24; |
| 3 | + |
| 4 | +import {IEVault, IEulerSwap, EulerSwapTestBase, EulerSwap, TestERC20} from "./EulerSwapTestBase.t.sol"; |
| 5 | +import {IRMTestFixed} from "evk-test/mocks/IRMTestFixed.sol"; |
| 6 | +import {Errors as EVKErrors} from "evk/EVault/shared/Errors.sol"; |
| 7 | +import "evk/EVault/shared/Constants.sol" as EVKConstants; |
| 8 | + |
| 9 | +contract DepositFailuresTest is EulerSwapTestBase { |
| 10 | + EulerSwap public eulerSwap; |
| 11 | + address public griefer = makeAddr("griefer"); |
| 12 | + |
| 13 | + function setUp() public virtual override { |
| 14 | + super.setUp(); |
| 15 | + |
| 16 | + eulerSwap = createEulerSwap(50e18, 50e18, 0, 1e18, 1e18, 0.4e18, 0.85e18); |
| 17 | + } |
| 18 | + |
| 19 | + function test_griefing() public monotonicHolderNAV { |
| 20 | + // Make a borrow to push exchange rate > 1 |
| 21 | + |
| 22 | + eTST2.setInterestRateModel(address(new IRMTestFixed())); |
| 23 | + |
| 24 | + mintAndDeposit(griefer, eTST, 100e18); |
| 25 | + |
| 26 | + vm.prank(griefer); |
| 27 | + evc.enableCollateral(griefer, address(eTST)); |
| 28 | + vm.prank(griefer); |
| 29 | + evc.enableController(griefer, address(eTST2)); |
| 30 | + |
| 31 | + vm.prank(griefer); |
| 32 | + eTST2.borrow(1e18, griefer); |
| 33 | + skip(1); |
| 34 | + |
| 35 | + // Do a swap |
| 36 | + |
| 37 | + uint256 amountIn = 1e18; |
| 38 | + uint256 amountOut = |
| 39 | + periphery.quoteExactInput(address(eulerSwap), address(assetTST), address(assetTST2), amountIn); |
| 40 | + assertApproxEqAbs(amountOut, 0.9974e18, 0.0001e18); |
| 41 | + |
| 42 | + // Honest deposit |
| 43 | + assetTST.mint(address(this), amountIn); |
| 44 | + assetTST.transfer(address(eulerSwap), amountIn); |
| 45 | + |
| 46 | + // Griefer front-runs with 1 wei deposit, which rounds down to 0 shares |
| 47 | + assetTST2.mint(address(this), 1); |
| 48 | + assetTST2.transfer(address(eulerSwap), 1); |
| 49 | + |
| 50 | + // Naive deposit() would fail with E_ZeroShares |
| 51 | + eulerSwap.swap(0, amountOut, address(this), ""); |
| 52 | + |
| 53 | + assertEq(assetTST2.balanceOf(address(this)), amountOut); |
| 54 | + |
| 55 | + assertEq(assetTST2.balanceOf(address(eulerSwap)), 1); // griefing transfer was untouched |
| 56 | + } |
| 57 | + |
| 58 | + function test_depositFailure() public monotonicHolderNAV { |
| 59 | + // Do a swap |
| 60 | + |
| 61 | + uint256 amountIn = 1e18; |
| 62 | + uint256 amountOut = |
| 63 | + periphery.quoteExactInput(address(eulerSwap), address(assetTST), address(assetTST2), amountIn); |
| 64 | + assertApproxEqAbs(amountOut, 0.9974e18, 0.0001e18); |
| 65 | + |
| 66 | + // Honest deposit |
| 67 | + assetTST.mint(address(this), amountIn); |
| 68 | + assetTST.transfer(address(eulerSwap), amountIn); |
| 69 | + |
| 70 | + // Griefer front-runs with 1 wei deposit, which rounds down to 0 shares |
| 71 | + assetTST2.mint(address(this), 1); |
| 72 | + assetTST2.transfer(address(eulerSwap), 1); |
| 73 | + |
| 74 | + // Force deposits to fail |
| 75 | + eTST2.setHookConfig(address(0), EVKConstants.OP_DEPOSIT); |
| 76 | + |
| 77 | + vm.expectRevert( |
| 78 | + abi.encodeWithSelector( |
| 79 | + EulerSwap.DepositFailure.selector, abi.encodeWithSelector(EVKErrors.E_OperationDisabled.selector) |
| 80 | + ) |
| 81 | + ); |
| 82 | + eulerSwap.swap(0, amountOut, address(this), ""); |
| 83 | + |
| 84 | + assertEq(assetTST2.balanceOf(address(this)), 0); |
| 85 | + |
| 86 | + assertEq(assetTST2.balanceOf(address(eulerSwap)), 1); // griefing transfer was untouched |
| 87 | + } |
| 88 | +} |
0 commit comments