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

Inability to Remove Liquidity In `AaveDIVAWrapper::removeLiquidity` Due to Blacklisted Recipient

Summary

An issue has been identified in the AaveDIVAWrapper::removeLiquidity function of the AaveDIVAWrapper Contract 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, preventing the liquidity provider (LP) from accessing their collateral.

Vulnerability Details

When an LP attempts to remove liquidity, 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 function AaveDIVAWrapperCore::_removeLiquidity call AaveDIVAWrapperCore::_redeemWTokenPrivate to handle the withdrawal of collateral from Aave:

A LP 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 470 in AaveDIVAWrappeeCore::_redeemWTokenPrivate may revert, as is the case with USDC:

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

In AaveDIVAWrappeeCore::_removeLiquidity

// Withdraw collateral token from Aave, burn wTokens owned by this contract and transfer collateral token to `_recipient`.
uint256 _amountReturned = _redeemWTokenPrivate(
_pool.collateralToken, // wToken
_wTokenAmountReturned,
@> _recipient, // blacklisted
address(this)
);

In AaveDIVAWrappeeCore::_redeemWTokenPrivate

uint256 _amountReturned = IAave(_aaveV3Pool).withdraw(
_collateralToken, // Address of the underlying asset (e.g., USDT), not the aToken.
_wTokenAmount, // Amount to withdraw.
@> _recipient // Address that will receive the underlying asset. // blacklisted
);

Impact

The bug prevents liquidity providers from withdrawing their collateral if the recipient is blacklisted, effectively locking their funds and hindering liquidity management.

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: 100 * 10**USDC.decimals(),
collateralToken: address(USDC),
dataProvider: address(0x11),
capacity: type(uint256).max,
longRecipient: trader, // In this case, the trader is the long recipient
shortRecipient: trader, // In this case, the trader is the short recipient
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 testRemoveLiquidity() external createPool addliquidity{
IDIVA.Pool memory _pool = IDIVA(_diva).getPoolParameters(poolId);
IERC20 shorttoken = IERC20(_pool.shortToken);
IERC20 longtoken = IERC20(_pool.longToken);
vm.startPrank(trader);
shorttoken.approve(address(wrapper), type(uint256).max);
longtoken.approve(address(wrapper), type(uint256).max);
vm.expectRevert("Blacklistable: account is blacklisted"); // expected revert
wrapper.removeLiquidity(poolId, type(uint256).max , blacklistedUser);
vm.stopPrank();
}
}

Run This command :

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

TEST PASS:

[⠒] Compiling...
[⠑] Compiling 1 files with Solc 0.8.26
[⠘] Solc 0.8.26 finished in 2.53s
Compiler run successful!
Ran 1 test for test/AaveDivaWrapper.t.sol:AaveDIVAWrapperTest
[PASS] testRemoveLiquidity() (gas: 1460053)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 21.54s (13.99s CPU time)
Ran 1 test suite in 22.17s (21.54s CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)

Tools Used

  • Manuial Review

  • Foundry

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 9 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Appeal created

bube Lead Judge 8 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.