Copy // SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import "forge-std/Test.sol";
import "forge-std/console.sol";
import {AaveV3ARBUSDCStrategy} from "../../strategies/arbitrum/AaveV3ARBUSDCStrategy.sol";
import {IMYTStrategy} from "../../interfaces/IMYTStrategy.sol";
import {IVaultV2} from "../../../lib/vault-v2/src/interfaces/IVaultV2.sol";
import {MockAlchemistAllocator} from "../mocks/MockAlchemistAllocator.sol";
import {MYTTestHelper} from "../libraries/MYTTestHelper.sol";
import {TokenUtils} from "../../libraries/TokenUtils.sol";
// Interface for Aave Rewards Controller
interface IAaveRewardsController {
function getRewardsBalance(address[] calldata assets, address user) external view returns (uint256);
function getAllUserRewards(address[] calldata assets, address user)
external
view
returns (address[] memory rewardsList, uint256[] memory unclaimedAmounts);
function claimAllRewards(address[] calldata assets, address to) external returns (address[] memory rewardsList, uint256[] memory claimedAmounts);
}
// Interface for ERC20
interface IERC20 {
function balanceOf(address) external view returns (uint256);
function transfer(address, uint256) external returns (bool);
}
contract PoC_AaveV3NoRewardsClaimed is Test {
// Arbitrum Mainnet addresses
address public constant USDC = 0xaf88d065e77c8cC2239327C5EDb3A432268e5831;
address public constant AAVE_V3_USDC_ATOKEN = 0x724dc807b04555b71ed48a6896b6F41593b8C637;
address public constant AAVE_V3_USDC_POOL = 0x794a61358D6845594F94dc1DB02A252b5b4814aD;
address public constant PERMIT2 = 0x000000000022d473030f1dF7Fa9381e04776c7c5;
// ARB_TOKEN is used as an example reward token - Aave V3 may distribute various reward tokens
address public constant ARB_TOKEN = 0x912CE59144191C1204E64559FE8253a0e49E6548;
// Aave V3 Rewards Controller on Arbitrum
address public constant AAVE_REWARDS_CONTROLLER = 0x929EC64c34a17401F460460D4B9390518E5B473e;
AaveV3ARBUSDCStrategy public strategy;
address public vault;
address public allocator;
address public admin = address(1);
address public curator = address(2);
address public operator = address(3);
address public user1 = address(4);
function setUp() public {
// Fork Arbitrum at a recent block
uint256 forkId = vm.createFork(vm.envString("ARBITRUM_RPC_URL"), 387_030_683);
vm.selectFork(forkId);
// Setup vault and strategy
vm.startPrank(admin);
vault = address(MYTTestHelper._setupVault(USDC, admin, curator));
IMYTStrategy.StrategyParams memory params = IMYTStrategy.StrategyParams({
owner: admin,
name: "AaveV3ARBUSDC",
protocol: "AaveV3ARBUSDC",
riskClass: IMYTStrategy.RiskClass.LOW,
cap: 10_000e6,
globalCap: 1e18,
estimatedYield: 100e6,
additionalIncentives: true, // Note: strategy indicates it has additional incentives
slippageBPS: 1
});
strategy = new AaveV3ARBUSDCStrategy(vault, params, USDC, AAVE_V3_USDC_ATOKEN, AAVE_V3_USDC_POOL, PERMIT2);
allocator = address(new MockAlchemistAllocator(vault, admin, operator));
vm.stopPrank();
// Configure vault with strategy
vm.startPrank(curator);
_vaultSubmitAndFastForward(abi.encodeCall(IVaultV2.setIsAllocator, (allocator, true)));
IVaultV2(vault).setIsAllocator(allocator, true);
_vaultSubmitAndFastForward(abi.encodeCall(IVaultV2.addAdapter, address(strategy)));
IVaultV2(vault).addAdapter(address(strategy));
bytes memory idData = strategy.getIdData();
_vaultSubmitAndFastForward(abi.encodeCall(IVaultV2.increaseAbsoluteCap, (idData, 10_000e6)));
IVaultV2(vault).increaseAbsoluteCap(idData, 10_000e6);
_vaultSubmitAndFastForward(abi.encodeCall(IVaultV2.increaseRelativeCap, (idData, 1e18)));
IVaultV2(vault).increaseRelativeCap(idData, 1e18);
vm.stopPrank();
// Deposit to vault
_magicDepositToVault(vault, user1, 1_000_000e6); // 1M USDC
}
function _vaultSubmitAndFastForward(bytes memory data) internal {
IVaultV2(vault).submit(data);
bytes4 selector = bytes4(data);
vm.warp(block.timestamp + IVaultV2(vault).timelock(selector));
}
function _magicDepositToVault(address _vault, address depositor, uint256 amount) internal {
deal(USDC, depositor, amount);
vm.startPrank(depositor);
TokenUtils.safeApprove(USDC, _vault, amount);
IVaultV2(_vault).deposit(amount, depositor);
vm.stopPrank();
}
function test_PoC_claimRewards_Returns_Zero_No_Implementation() public {
// Allocate funds to the strategy
uint256 depositAmount = 10_000e6; // 10K USDC
deal(USDC, address(strategy), depositAmount);
vm.startPrank(vault);
bytes memory prevAllocationAmount = abi.encode(0);
strategy.allocate(prevAllocationAmount, depositAmount, "", vault);
vm.stopPrank();
uint256 strategyBalance = strategy.realAssets();
assertGt(strategyBalance, 0, "Strategy should have deposited funds");
// Advance time to simulate reward accrual
vm.warp(block.timestamp + 30 days);
vm.roll(block.number + 216_000);
// Check balances before claiming
uint256 strategyARBBalanceBefore = IERC20(ARB_TOKEN).balanceOf(address(strategy));
uint256 vaultARBBalanceBefore = IERC20(ARB_TOKEN).balanceOf(vault);
// Call claimRewards() - should return 0 and claim nothing
uint256 rewardsClaimed = strategy.claimRewards();
// Check balances after claiming
uint256 strategyARBBalanceAfter = IERC20(ARB_TOKEN).balanceOf(address(strategy));
uint256 vaultARBBalanceAfter = IERC20(ARB_TOKEN).balanceOf(vault);
// Verify the issue: claimRewards() returns 0 and no rewards are transferred
assertEq(rewardsClaimed, 0, "claimRewards() should return 0 (not implemented)");
assertEq(strategyARBBalanceAfter, strategyARBBalanceBefore, "Strategy ARB balance should not change");
assertEq(vaultARBBalanceAfter, vaultARBBalanceBefore, "Vault ARB balance should not change");
}
}