Summary
Vulnerability Details
For users to be able to add liquidity to the pools for any certain collateral, it has to be registered via AaveDIVAWrapper::registerCollateralToken() / AaveDIVAWrapperCore::_registerCollateralToken(). AaveDIVAWrapperCore::_registerCollateralToken() performs checks to ensure that
token isn't registered already
Aave V3's aToken associated with the provided _collateralToken is not address(0).
#AaveDIVAWrapper::registerCollateralToken()
# https:
function registerCollateralToken(
address _collateralToken
) external override onlyOwner nonReentrant returns (address) {
return _registerCollateralToken(_collateralToken);
}
# AaveDIVAWrapperCore::_registerCollateralToken()
#https:
function _registerCollateralToken(address _collateralToken) internal returns (address) {
if (_collateralTokenToWToken[_collateralToken] != address(0)) {
revert CollateralTokenAlreadyRegistered();
}
address _aToken = _getAToken(_collateralToken);
if (_aToken == address(0)) {
revert UnsupportedCollateralToken(); @audit2
}
IERC20Metadata _collateralTokenContract = IERC20Metadata(_collateralToken);
WToken _wTokenContract = new WToken(
string(abi.encodePacked("w", _collateralTokenContract.symbol())),
_collateralTokenContract.decimals(),
address(this)
);
address _wToken = address(_wTokenContract);
_collateralTokenToWToken[_collateralToken] = _wToken;
_wTokenToCollateralToken[_wToken] = _collateralToken;
_wTokenContract.approve(_diva, type(uint256).max);
_collateralTokenContract.approve(_aaveV3Pool, type(uint256).max);
emit CollateralTokenRegistered(_collateralToken, _wToken);
return _wToken;
}
Now, each time a user wants to deposit liquidity via AaveDIVAWrapper::addLiquidity() which calls AaveDIVAWrapperCore::_addLiquidity() which in turn checks that _collateralToken retrieved from poolId is not an address(0). It also calls AaveDIVAWrapperCore::_handleTokenOperations() which transfers the amount of collateralToken from msg.sender to AaveDIVAWrapperCore before providing to Aave via IAave(_aaveV3Pool).supply(). And finally IDIVA(_diva).addLiquidity() which adds collateral to an existing pool. Mints new long and short position tokens with supply equal to collateral amount added.
#AaveDIVAWrapper::addLiquidity()
#https:
function addLiquidity(
bytes32 _poolId,
uint256 _collateralAmount,
address _longRecipient,
address _shortRecipient
) external override nonReentrant {
_addLiquidity(_poolId, _collateralAmount, _longRecipient, _shortRecipient);
}
#AaveDIVAWrapperCore::_addLiquidity()
#https:
function _addLiquidity(
bytes32 _poolId,
uint256 _collateralAmount,
address _longRecipient,
address _shortRecipient
) internal {
IDIVA.Pool memory _pool = IDIVA(_diva).getPoolParameters(_poolId);
address _collateralToken = _wTokenToCollateralToken[_pool.collateralToken];
if (_collateralToken == address(0)) {
revert CollateralTokenNotRegistered();
}
_handleTokenOperations(_collateralToken, _collateralAmount, _pool.collateralToken);
IDIVA(_diva).addLiquidity(_poolId, _collateralAmount, _longRecipient, _shortRecipient);
}
#AaveDIVAWrapperCore::_handleTokenOperations()
function _handleTokenOperations(address _collateralToken, uint256 _collateralAmount, address _wToken) private {
IERC20Metadata(_collateralToken).safeTransferFrom(msg.sender, address(this), _collateralAmount);
IAave(_aaveV3Pool).supply(
_collateralToken,
_collateralAmount,
address(this),
0
);
IWToken(_wToken).mint(address(this), _collateralAmount);
}
Impact
Users can lose their supplied collateral via AaveDIVAWrapper::addLiquidity() if Aave deprecates the collateral token after it has been registered on DIVA via AaveDIVAWrapperCore::_registerCollateralToken().
If between registration of collateral token and a call to add liquidity to pool Aave decides to deprecate a token the AaveDIVAWrapper::registerCollateralToken() / AaveDIVAWrapperCore::_registerCollateralToken() calls will pass, since the collateral's aToken can be retrieved from Aave, but the AaveDIVAWrapper::addLiquidity() doesn't check if the aToken for the collateralToken is still retrievable at time of adding liquidity, hence the supplier's collateral amount might get trapped in the AaveDIVAWrapperCore without them getting their positionTokens. Or maybe they will get their positionTokens,but at a loss to the protocol since they won't get their yield from Aave.
Tools Used
Manual Review.
Recommendations
Always check in AaveDIVAWrapper::addLiquidity() / AaveDIVAWrapperCore::_addLiquidity() that the aTokens for the collateralToken are retrievable from Aave.