Basic Lilac Marmot
High
function claimReward(address _wallet) external override {
_processFeesIfApplicable();
_distributeReward(_wallet);
emit ClaimReward(_wallet);
}
function _processFeesIfApplicable() internal {
IDecentralizedIndex(INDEX_FUND).processPreSwapFeesAndSwap();
}
Anyone can call the processPreSwapFeesAndSwap
function of INDEX_FUND
through the claimReward
function.
/// @notice The ```processPreSwapFeesAndSwap``` function allows the rewards CA for the pod to process fees as needed
function processPreSwapFeesAndSwap() external override lock {
require(_msgSender() == IStakingPoolToken(lpStakingPool).POOL_REWARDS(), "R");
_processPreSwapFeesAndSwap();
}
/// @notice The ```_feeSwap``` function processes built up fees by converting to pairedLpToken
/// @param _amount Number of pTKN being processed for yield
function _feeSwap(uint256 _amount) internal {
_approve(address(this), address(DEX_HANDLER), _amount);
address _rewards = IStakingPoolToken(lpStakingPool).POOL_REWARDS();
uint256 _pairedLpBalBefore = IERC20(PAIRED_LP_TOKEN).balanceOf(_rewards);
**DEX_HANDLER.swapV2Single(address(this), PAIRED_LP_TOKEN, _amount, 0, _rewards);**
if (PAIRED_LP_TOKEN == lpRewardsToken) {
uint256 _newPairedLpTkns = IERC20(PAIRED_LP_TOKEN).balanceOf(_rewards) - _pairedLpBalBefore;
if (_newPairedLpTkns > 0) {
ITokenRewards(_rewards).depositRewardsNoTransfer(PAIRED_LP_TOKEN, _newPairedLpTkns);
}
} else if (IERC20(PAIRED_LP_TOKEN).balanceOf(_rewards) > 0) {
ITokenRewards(_rewards).depositFromPairedLpToken(0);
}
}
When the processPreSwapFeesAndSwap
function is executed, it triggers the swapV2Single
function within the _feeSwap
function of DEX_HANDLER
. This function likely calls the Uniswap V2 swap function to perform a token swap.
function swapV2Single(
address _tokenIn,
address _tokenOut,
uint256 _amountIn,
uint256 _amountOutMin,
address _recipient
) external
The fourth parameter of the swapV2Single function is used to validate the minimum amount of tokens expected after the swap. However, in the _feeSwap function, this parameter is being passed as 0, which effectively means there is no minimum amount check.
Through this, a malicious user could exploit the lack of a minimum amount check (by passing 0 as the fourth parameter) to steal fees.
in DecentralizedIndex.sol:232
amountOutMin is set to zero.
No response
No response
- The attacker calculates the swap amount of the DecentralizedIndex contract and adjusts the liquidity of the POOL.
- By calling the claimReward function, the attacker causes the DecentralizedIndex contract to swap, resulting in a loss of _rewards worth of tokens and returning tokens close to zero.
The affected party continuously loses tokens equivalent to _rewards.
No response
Even if the claimReward function is restricted to authorized users, a malicious actor could still exploit the system via front-running to steal fees.
To prevent this, it is essential to validate the minimum amount during the swap. This would ensure that the swap cannot proceed unless the expected minimum amount of tokens is received, preventing a malicious user from benefiting from an unfavorable swap rate.