Fast Khaki Raccoon
High
_rewardsSwapAmountInOverride
can be overwritten to REWARDS_SWAP_OVERRIDE_MIN
which if a bigger value would cause insolvency
The catch overrides _rewardsSwapAmountInOverride
to be REWARDS_SWAP_OVERRIDE_MIN
, when we are _amountIn / 2 < REWARDS_SWAP_OVERRIDE_MIN
} catch {
_rewardsSwapAmountInOverride = _amountIn / 2 < REWARDS_SWAP_OVERRIDE_MIN
? REWARDS_SWAP_OVERRIDE_MIN
: _amountIn / 2;
IERC20(PAIRED_LP_TOKEN).safeDecreaseAllowance(address(DEX_ADAPTER), _amountIn);
emit RewardSwapError(_amountIn);
}
However if we are way bellow this value it can turn out REWARDS_SWAP_OVERRIDE_MIN > _amountIn
. And since we have set _rewardsSwapAmountInOverride
already, the next time we invoke _swapForRewards
we would enter the bellow case and possably fail the swap if REWARDS_SWAP_OVERRIDE_MIN
is still bigger than our initial _amountIn
.
function _swapForRewards(uint256 _amountIn, uint256 _amountOut, uint256 _adminAmt) internal {
if (_rewardsSwapAmountInOverride > 0) {
_adminAmt = (_adminAmt * _rewardsSwapAmountInOverride) / _amountIn;
_amountOut = (_amountOut * _rewardsSwapAmountInOverride) / _amountIn;
_amountIn = _rewardsSwapAmountInOverride;
}
Even worse than a failed TX would be the case of insolvency, where there are enough balances to go for the swap, but the non-distributed rewards, aka _amountIn
is smaller than _rewardsSwapAmountInOverride
, which would pass the swap, but spend some of the rewards, which were accrued prev. cycles.
No response
No response
- We calculate
_amountTkn
to be 40
uint256 _unclaimedPairedLpTkns = rewardsDeposited[PAIRED_LP_TOKEN] - rewardsDistributed[PAIRED_LP_TOKEN];
uint256 _amountTkn = IERC20(PAIRED_LP_TOKEN).balanceOf(address(this)) - _unclaimedPairedLpTkns;
- Perform a swap, but fail, entering the
catch
and saving the new_rewardsSwapAmountInOverride
to 100 (we are on ETH and gas may be a few bucks so, it won't be profitable if we swap 10 or 20 USD worth of tokens)
} catch {
_rewardsSwapAmountInOverride = _amountIn / 2 < REWARDS_SWAP_OVERRIDE_MIN
? REWARDS_SWAP_OVERRIDE_MIN
: _amountIn / 2;
IERC20(PAIRED_LP_TOKEN).safeDecreaseAllowance(address(DEX_ADAPTER), _amountIn);
emit RewardSwapError(_amountIn);
}
-
Next time when
depositFromPairedLpToken
calculates_amountTkn
to be 90 tokens -
We enter
_swapForRewards
and set the new swapped amount to_rewardsSwapAmountInOverride
- 100 tokens -
The initial calculation for this was that we had 1000 LP tokens, but 910 were unclaimed, meaning that we have the balance to execute the swap
// 1000 - 910 = 90
uint256 _amountTkn = IERC20(PAIRED_LP_TOKEN).balanceOf(address(this)) - _unclaimedPairedLpTkns;
- The swap is executed, which causes insolvency in our
PAIRED_LP_TOKEN
as we have swapped more of it than there are_unclaimedPairedLpTkns
ones, meaning that if all of the users who have it as a reward token try to claim it, they won't be able to, as contract balance is 900, but_unclaimedPairedLpTkns
is 910.
This scenario will prob. occur multiple times, and can even be provoked by a malicious user if he just calls depositFromPairedLpToken
2 times in a row and reverts to 1st swap to enter the catch (can be pool price manipulation or anything else, doesn't matter how he reverts it).
Insolvency, last user/users not being able to claim their rewards.
No response
Consider redesigning this whole function. The concept of min swap is useful, but make sure to check our existing amount if they are enough to perform the swap.