HardhatDeFi
15,000 USDC
View results
Submission Details
Severity: low
Invalid

Inability to claim Yeild In `AaveDIVAWrapper::claimYield` Due to Blacklisted Recipient

Summary

An issue has been identified in the AaveDIVAWrapper::claimYield function , when the recipient of the collateral is blacklisted by the issuer of the collateral token (e.g., USDC). This results in a transaction failure during the withdrawal process from Aave.

Vulnerability Details

When an Owner attempts to claim Yield , the process involves withdrawing the underlying collateral from Aave and transferring it to the specified recipient. If this recipient is blacklisted by the collateral token issuer, the transaction will revert .

The Owner can set recipent to a blacklisted/prohibited address for the underlying token, such as 0x0E6b8E34dC115a2848F585851AF23D99D09b8463, which is blacklisted in polygon USDC contract. the withdraw operation on line 344 in AaveDIVAWrappeeCore::_claimYield may revert, as is the case with USDC:

https://github.com/Cyfrin/2025-01-diva/blob/1b6543768c341c2334cdff87b6dd627ee2f62c89/contracts/src/AaveDIVAWrapperCore.sol#L344

In AaveDIVAWrappeeCore::_claimYield

function _claimYield(address _collateralToken, address _recipient) internal returns (uint256) {
// Confirm that the collateral token is registered
if (_collateralTokenToWToken[_collateralToken] == address(0)) {
revert CollateralTokenNotRegistered();
}
if (_recipient == address(0)) revert ZeroAddress();
// Redeem aToken for collateral token at Aave Protocol and send collateral token to recipient.
@> uint256 _amountReturned = IAave(_aaveV3Pool).withdraw(
_collateralToken, // Address of the underlying asset (e.g., USDT), not the aToken.
_getAccruedYieldPrivate(_collateralToken), // Amount to withdraw.
@> _recipient //@audit blacklisted
);
emit YieldClaimed(owner(), _recipient, _collateralToken, _amountReturned);
return _amountReturned;
}

Impact

  • Owner cannot claim yield when setting a blacklisted recipient :

In `test/AaveDIVAWrapper.t.sol`

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import "forge-std/Test.sol";
import {IAaveDIVAWrapper} from "../src/interfaces/IAaveDIVAWrapper.sol";
import {IAave} from "../src/interfaces/IAave.sol";
import {IDIVA} from "../src/interfaces/IDIVA.sol";
import "../src/AaveDIVAWrapper.sol";
import "../src/interfaces/IDIVA.sol";
import "lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol";
interface IUSDC {
function approve(address spender, uint256 amount) external;
function transfer(address recipient, uint256 amount) external;
function mint(address account, uint256 amount) external;
function balanceOf(address) external view returns (uint256);
function transferFrom(address sender, address recipient, uint256 amount) external;
function decimals() external view returns (uint8);
}
contract AaveDIVAWrapperTest is Test {
AaveDIVAWrapperCore wrapper;
address trader = address(0x4D8336bDa6C11BD2a805C291Ec719BaeDD10AcB9); // in polygon
address blacklistedUser = address(0x0E6b8E34dC115a2848F585851AF23D99D09b8463); // in polygon USDC token
address shortRecipient;
address longRecipient;
bytes32 poolId;
IAave _aavePool = IAave(0x794a61358D6845594F94dc1DB02A252b5b4814aD); // in polygon
IDIVA _diva = IDIVA(0x2C9c47E7d254e493f02acfB410864b9a86c28e1D); // in polygon
IUSDC USDC = IUSDC(0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359); // in polygon
function setUp() public {
// Deploy or connect to the necessary contracts
wrapper = new AaveDIVAWrapper(address(_diva),address(_aavePool),address(this));
shortRecipient = address(0x1); // short recipent address
longRecipient = address(0x2); // log recipent address
vm.startPrank(trader);
IUSDC(USDC).approve(address(this), type(uint256).max);
vm.stopPrank();
IUSDC(USDC).transferFrom(trader, address(this), 100* 10**USDC.decimals());
wrapper.registerCollateralToken(address(USDC));
}
modifier createPool {
// Create a pool
USDC.approve(address(wrapper), type(uint256).max);
poolId = wrapper.createContingentPool(IAaveDIVAWrapper.PoolParams({
referenceAsset: "BTC/USD",
expiryTime: uint96(block.timestamp + 86400),
floor: 100,
inflection: 150,
cap: 200,
gradient: uint256(5 * 10 ** (USDC.decimals()-1)),
collateralAmount: 10 * 10**USDC.decimals(),
collateralToken: address(USDC),
dataProvider: address(0x11),
capacity: type(uint256).max,
longRecipient: longRecipient,
shortRecipient: shortRecipient,
permissionedERC721Token: address(0)
}));
_;
}
modifier addliquidity {
vm.startPrank(trader);
USDC.approve(address(wrapper), type(uint256).max);
wrapper.addLiquidity(poolId,100 *10**USDC.decimals() , longRecipient, shortRecipient);
vm.stopPrank();
_;
}
function testClaimYieldRevertInBlacklistedRecipient() external createPool addliquidity{
// Expected Revert with
// vm.expectRevert("AaveDIVAWrapper: Recipient is blacklisted");
wrapper.claimYield(address(USDC),blacklistedUser);
}

Run This Command :

$ forge test --mt testClaimYieldRevertInBlacklistedRecipient --fork-url https://polygon-mainnet.g.alchemy.com/v2/Yn7tIZfhjHHmJQbJ4SeXkpuRju0udqkR -vvv

Output :

├─ [71586] AaveDIVAWrapper::claimYield(0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359, 0x0E6b8E34dC115a2848F585851AF23D99D09b8463)
│ ├─ [12291] 0x794a61358D6845594F94dc1DB02A252b5b4814aD::getReserveData(0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359) [staticcall]
│ │ ├─ [11693] 0x5DFb8c777C19d3cEdcDc7398d2EeF1FB0b9b05c9::getReserveData(0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359) [delegatecall]
│ │ │ ├─ [2488] 0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb::getAddress(0x4d4f434b5f535441424c455f4445425400000000000000000000000000000000) [staticcall]
│ │ │ │ └─ ← [Return] 0x000000000000000000000000d94112b5b62d53c9402e7a60289c6810def1dc9b
│ │ │ └─ ← [Return] ReserveDataLegacy({ configuration: ReserveConfigurationMap({ data: 7237005577332262213973186942896412476039334390506525738199614521317852192076 [7.237e75] }), liquidityIndex: 1093702697531922623236877552 [1.093e27], currentLiquidityRate: 71642763956374963462186029 [7.164e25], variableBorrowIndex: 1115727771297863082559753035 [1.115e27], currentVariableBorrowRate: 103023020768912840293438392 [1.03e26], currentStableBorrowRate: 0, lastUpdateTimestamp: 1738316247 [1.738e9], id: 20, aTokenAddress: 0xA4D94019934D8333Ef880ABFFbF2FDd611C762BD, stableDebtTokenAddress: 0xd94112B5B62d53C9402e7A60289c6810dEF1dC9B, variableDebtTokenAddress: 0xE701126012EC0290822eEA17B794454d1AF8b030, interestRateStrategyAddress: 0x56076f960980d453b5B749CB6A1c4D2E4e138B1A, accruedToTreasury: 161681639 [1.616e8], unbacked: 0, isolationModeTotalDebt: 0 })
│ │ └─ ← [Return] ReserveDataLegacy({ configuration: ReserveConfigurationMap({ data: 7237005577332262213973186942896412476039334390506525738199614521317852192076 [7.237e75] }), liquidityIndex: 1093702697531922623236877552 [1.093e27], currentLiquidityRate: 71642763956374963462186029 [7.164e25], variableBorrowIndex: 1115727771297863082559753035 [1.115e27], currentVariableBorrowRate: 103023020768912840293438392 [1.03e26], currentStableBorrowRate: 0, lastUpdateTimestamp: 1738316247 [1.738e9], id: 20, aTokenAddress: 0xA4D94019934D8333Ef880ABFFbF2FDd611C762BD, stableDebtTokenAddress: 0xd94112B5B62d53C9402e7A60289c6810dEF1dC9B, variableDebtTokenAddress: 0xE701126012EC0290822eEA17B794454d1AF8b030, interestRateStrategyAddress: 0x56076f960980d453b5B749CB6A1c4D2E4e138B1A, accruedToTreasury: 161681639 [1.616e8], unbacked: 0, isolationModeTotalDebt: 0 })
│ ├─ [5306] 0xA4D94019934D8333Ef880ABFFbF2FDd611C762BD::balanceOf(AaveDIVAWrapper: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f]) [staticcall]
│ │ ├─ [4698] 0xCf85FF1c37c594a10195F7A9Ab85CBb0a03f69dE::balanceOf(AaveDIVAWrapper: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f]) [delegatecall]
│ │ │ ├─ [1419] 0x794a61358D6845594F94dc1DB02A252b5b4814aD::getReserveNormalizedIncome(0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359) [staticcall]
│ │ │ │ ├─ [867] 0x5DFb8c777C19d3cEdcDc7398d2EeF1FB0b9b05c9::getReserveNormalizedIncome(0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359) [delegatecall]
│ │ │ │ │ └─ ← [Return] 0x00000000000000000000000000000000000000000388b08e092eab1a5d0b2cf0
│ │ │ │ └─ ← [Return] 0x00000000000000000000000000000000000000000388b08e092eab1a5d0b2cf0
│ │ │ └─ ← [Return] 110000001 [1.1e8]
│ │ └─ ← [Return] 110000001 [1.1e8]
│ ├─ [477] WToken::totalSupply() [staticcall]
│ │ └─ ← [Return] 110000000 [1.1e8]
│ ├─ [40665] 0x794a61358D6845594F94dc1DB02A252b5b4814aD::withdraw(0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359, 1, 0x0E6b8E34dC115a2848F585851AF23D99D09b8463)
│ │ ├─ [40088] 0x5DFb8c777C19d3cEdcDc7398d2EeF1FB0b9b05c9::withdraw(0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359, 1, 0x0E6b8E34dC115a2848F585851AF23D99D09b8463) [delegatecall]
│ │ │ ├─ [2402] 0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb::getPriceOracle() [staticcall]
│ │ │ │ └─ ← [Return] 0x000000000000000000000000b023e699f5a33916ea823a16485e259257ca8bd1
│ │ │ ├─ [31573] 0x2b22E425C1322fbA0DbF17bb1dA25d71811EE7ba::186dea44(00000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003702d183c14bea6b53d1a60b293e9416ed749f2af0faddac5a251f02731f788fbe0000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000e6b8e34dc115a2848f585851af23d99d09b84630000000000000000000000000000000000000000000000000000000000000015000000000000000000000000b023e699f5a33916ea823a16485e259257ca8bd10000000000000000000000000000000000000000000000000000000000000000) [delegatecall]
│ │ │ │ ├─ [1024] 0xE701126012EC0290822eEA17B794454d1AF8b030::scaledTotalSupply() [staticcall]
│ │ │ │ │ ├─ [419] 0x79b5e91037AE441dE0d9e6fd3Fd85b96B83d4E93::scaledTotalSupply() [delegatecall]
│ │ │ │ │ │ └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000223647f85ce8
│ │ │ │ │ └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000223647f85ce8
│ │ │ │ ├─ [1299] 0xA4D94019934D8333Ef880ABFFbF2FDd611C762BD::scaledBalanceOf(AaveDIVAWrapper: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f]) [staticcall]
│ │ │ │ │ ├─ [691] 0xCf85FF1c37c594a10195F7A9Ab85CBb0a03f69dE::scaledBalanceOf(AaveDIVAWrapper: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f]) [delegatecall]
│ │ │ │ │ │ └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000005feaa23
│ │ │ │ │ └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000005feaa23
│ │ │ │ ├─ [3705] 0x56076f960980d453b5B749CB6A1c4D2E4e138B1A::b90db31b(0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000262bdb846d9d00000000000000000000000000000000000000000000000000000000000003e80000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c3359000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000b3af838ff17) [staticcall]
│ │ │ │ │ └─ ← [Return] 0x0000000000000000000000000000000000000000003b42f20426e5f05c8e57da0000000000000000000000000000000000000000005537f9258d124cfabb8eca
│ │ │ │ ├─ emit ReserveDataUpdated(param0: 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359, param1: 71642763956377601377720282 [7.164e25], param2: 0, param3: 103023020768914736968077002 [1.03e26], param4: 1093702697531922623236877552 [1.093e27], param5: 1115727771297863082559753035 [1.115e27])
│ │ │ │ ├─ [14339] 0xA4D94019934D8333Ef880ABFFbF2FDd611C762BD::burn(AaveDIVAWrapper: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], 0x0E6b8E34dC115a2848F585851AF23D99D09b8463, 1, 1093702697531922623236877552 [1.093e27])
│ │ │ │ │ ├─ [13703] 0xCf85FF1c37c594a10195F7A9Ab85CBb0a03f69dE::burn(AaveDIVAWrapper: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], 0x0E6b8E34dC115a2848F585851AF23D99D09b8463, 1, 1093702697531922623236877552 [1.093e27]) [delegatecall]
│ │ │ │ │ │ ├─ [1371] 0x929EC64c34a17401F460460D4B9390518E5B473e::handleAction(AaveDIVAWrapper: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], 49663891005477 [4.966e13], 100575779 [1.005e8])
│ │ │ │ │ │ │ ├─ [717] 0x5f4d15d761528c57a5C30c43c1DAb26Fc5452731::handleAction(AaveDIVAWrapper: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], 49663891005477 [4.966e13], 100575779 [1.005e8]) [delegatecall]
│ │ │ │ │ │ │ │ └─ ← [Stop]
│ │ │ │ │ │ │ └─ ← [Return]
│ │ │ │ │ │ ├─ emit Transfer(from: AaveDIVAWrapper: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], to: 0x0000000000000000000000000000000000000000, value: 1)
│ │ │ │ │ │ ├─ emit Burn(param0: AaveDIVAWrapper: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], param1: 0x0E6b8E34dC115a2848F585851AF23D99D09b8463, param2: 1, param3: 0, param4: 1093702697531922623236877552 [1.093e27])
│ │ │ │ │ │ ├─ [3777] 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359::transfer(0x0E6b8E34dC115a2848F585851AF23D99D09b8463, 1)
│ │ │ │ │ │ │ ├─ [3058] 0x235AE97b28466Db30469b89A9fe4cFf0659f82Cb::transfer(0x0E6b8E34dC115a2848F585851AF23D99D09b8463, 1) [delegatecall]
│ │ │ │ │ │ │ │ └─ ← [Revert] revert: Blacklistable: account is blacklisted // REVERT WITH BLACKLISTED

Tools Used

  • Foundry

  • Manuial Review

Recommendations

  • Implement pre-transfer checks to verify whether the recipient is blacklisted before initiating the withdrawal process. This can prevent the transaction from reverting due to blacklist issues.

Updates

Lead Judging Commences

bube Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.