|
| 1 | +// SPDX-License-Identifier: AGPLv3 |
| 2 | +pragma solidity ^0.8.23; |
| 3 | + |
| 4 | +import { YieldBackendUnitTestBase } from "./YieldBackendUnitTestBase.sol"; |
| 5 | +import { AaveETHYieldBackend } from "../../../../contracts/superfluid/AaveETHYieldBackend.sol"; |
| 6 | +import { IYieldBackend } from "../../../../contracts/interfaces/superfluid/IYieldBackend.sol"; |
| 7 | +import { IERC20 } from "../../../../contracts/interfaces/superfluid/ISuperfluid.sol"; |
| 8 | +import { IPool } from "aave-v3/src/contracts/interfaces/IPool.sol"; |
| 9 | + |
| 10 | +/** |
| 11 | + * @title tests for AaveETHYieldBackend with ETH/WETH on Base |
| 12 | + * Tests the backend in isolation using delegatecall |
| 13 | + */ |
| 14 | +contract AaveETHYieldBackendUnitTest is YieldBackendUnitTestBase { |
| 15 | + uint256 internal constant CHAIN_ID = 8453; |
| 16 | + string internal constant RPC_URL = "https://mainnet.base.org"; |
| 17 | + |
| 18 | + address internal constant AAVE_POOL = 0xA238Dd80C259a72e81d7e4664a9801593F98d1c5; |
| 19 | + address internal constant WETH = 0x4200000000000000000000000000000000000006; |
| 20 | + |
| 21 | + AaveETHYieldBackend internal aaveETHBackend; |
| 22 | + |
| 23 | + function getRpcUrl() internal pure override returns (string memory) { |
| 24 | + return RPC_URL; |
| 25 | + } |
| 26 | + |
| 27 | + function getChainId() internal pure override returns (uint256) { |
| 28 | + return CHAIN_ID; |
| 29 | + } |
| 30 | + |
| 31 | + /// @notice toUnderlyingAmount for ETH (18 decimals) - uses base implementation |
| 32 | + /// @dev No override needed, ETH has 18 decimals like SuperToken |
| 33 | + |
| 34 | + function createBackend() internal override returns (IYieldBackend) { |
| 35 | + aaveETHBackend = new AaveETHYieldBackend( |
| 36 | + IPool(AAVE_POOL), |
| 37 | + SURPLUS_RECEIVER |
| 38 | + ); |
| 39 | + return IYieldBackend(address(aaveETHBackend)); |
| 40 | + } |
| 41 | + |
| 42 | + function getAssetToken() internal pure override returns (IERC20) { |
| 43 | + // For AaveETHYieldBackend, the asset token is WETH |
| 44 | + return IERC20(WETH); |
| 45 | + } |
| 46 | + |
| 47 | + function fundTestContract() internal override { |
| 48 | + // Fund with ETH (will be wrapped to WETH on deposit) |
| 49 | + vm.deal(address(this), 10_000 ether); |
| 50 | + } |
| 51 | + |
| 52 | + function getAssetDecimals() internal pure override returns (uint8) { |
| 53 | + return 18; // ETH/WETH has 18 decimals |
| 54 | + } |
| 55 | + |
| 56 | + function _getProtocolAddress() internal pure override returns (address) { |
| 57 | + return AAVE_POOL; |
| 58 | + } |
| 59 | + |
| 60 | + /// @notice Override _boundAmount to ensure minimum viable amounts for ETH |
| 61 | + /// @dev Aave may have minimum deposit requirements, so we use a higher minimum |
| 62 | + function _boundAmount(uint256 amount) internal pure override returns (uint256) { |
| 63 | + // Minimum: 0.001 ETH (1e15 wei) to avoid issues with very small amounts |
| 64 | + // Maximum: 1000 ETH |
| 65 | + uint256 minAmount = 1e15; // 0.001 ETH |
| 66 | + uint256 maxAmount = 1000 * 1e18; // 1000 ETH |
| 67 | + return bound(amount, minAmount, maxAmount); |
| 68 | + } |
| 69 | + |
| 70 | + /// @notice Override _fundAsset to handle ETH (native token) |
| 71 | + function _fundAsset(uint256 amount) internal override { |
| 72 | + // Ensure we have at least the amount in ETH |
| 73 | + uint256 currentBalance = address(this).balance; |
| 74 | + if (currentBalance < amount) { |
| 75 | + vm.deal(address(this), amount); |
| 76 | + } |
| 77 | + } |
| 78 | + |
| 79 | + /// @notice Override _getAssetBalance to handle ETH balance |
| 80 | + /// @dev For ETH backend, we track ETH balance (not WETH) |
| 81 | + /// @dev Before deposit: ETH balance |
| 82 | + /// @dev After deposit: ETH is wrapped and deposited, so ETH balance decreases |
| 83 | + /// @dev After withdraw: ETH is unwrapped back, so ETH balance increases |
| 84 | + function _getAssetBalance() internal view override returns (uint256) { |
| 85 | + // Track ETH balance directly (the native token) |
| 86 | + // WETH is just an intermediate step in the deposit/withdraw process |
| 87 | + return address(this).balance; |
| 88 | + } |
| 89 | + |
| 90 | + /// @notice Override _getSurplusReceiverBalance for WETH |
| 91 | + function _getSurplusReceiverBalance() internal view override returns (uint256) { |
| 92 | + // Note: Surplus is paid in WETH, not ETH |
| 93 | + // Use assetToken (IERC20) which has balanceOf |
| 94 | + return assetToken.balanceOf(SURPLUS_RECEIVER); |
| 95 | + } |
| 96 | + |
| 97 | + /// @notice Allow the test contract to receive ETH |
| 98 | + /// @dev Required for unwrapWETHAndForwardETH to send ETH back to the test contract |
| 99 | + receive() external payable { } |
| 100 | +} |
| 101 | + |
0 commit comments