Malicious users could block liquidation or perform DOS
The current implementation uses a "push" approach where reward tokens are sent to the recipient during every update, which introduces additional attack surfaces that the attackers can exploit. An attacker could intentionally affect the outcome of the transfer to gain a certain advantage or carry out certain attack.\\nThe worst-case scenario is that malicious users might exploit this trick to intentionally trigger a revert when someone attempts to liquidate their unhealthy accounts to block the liquidation, leaving the protocol with bad debts and potentially leading to insolvency if it accumulates.\\nPer the Audit Scope Documentation provided by the protocol team on the contest page, the reward tokens can be any arbitrary ERC20 tokens\\nWe are extending this functionality to allow nTokens to be incentivized by a secondary reward token. On Arbitrum, this will be ARB as a result of the ARB STIP grant. In the future, this may be any arbitrary ERC20 token\\nLine 231 of the `_claimRewards` function below might revert due to various issues such as:\\ntokens with blacklisting features such as USDC (users might intentionally get into the blacklist to achieve certain outcomes)\\ntokens with hook, which allow the target to revert the transaction intentionally\\nunexpected error in the token's contract\\n```\\nFile: SecondaryRewarder.sol\\n    function _claimRewards(address account, uint256 nTokenBalanceBefore, uint256 nTokenBalanceAfter) private { \\n        uint256 rewardToClaim = _calculateRewardToClaim(account, nTokenBalanceBefore, accumulatedRewardPerNToken); \\n\\n        // Precision here is:\\n        //  nTokenBalanceAfter (INTERNAL_TOKEN_PRECISION) \\n        //  accumulatedRewardPerNToken (INCENTIVE_ACCUMULATION_PRECISION) \\n        // DIVIDE BY\\n        //  INTERNAL_TOKEN_PRECISION \\n        //  => INCENTIVE_ACCUMULATION_PRECISION (1e18) \\n        rewardDebtPerAccount[account] = nTokenBalanceAfter \\n            .mul(accumulatedRewardPerNToken)\\n            .div(uint256(Constants.INTERNAL_TOKEN_PRECISION))\\n            .toUint128(); \\n\\n        if (0 < rewardToClaim) { \\n            GenericToken.safeTransferOut(REWARD_TOKEN, account, rewardToClaim); \\n            emit RewardTransfer(REWARD_TOKEN, account, rewardToClaim);\\n        }\\n    }\\n```\\n\\nIf a revert occurs, the following functions are affected:\\n```\\n_claimRewards -> claimRewardsDirect\\n\\n_claimRewards -> claimRewards -> Incentives.claimIncentives\\n_claimRewards -> claimRewards -> Incentives.claimIncentives -> BalancerHandler._finalize\\n_claimRewards -> claimRewards -> Incentives.claimIncentives -> BalancerHandler._finalize -> Used by many functions\\n\\n_claimRewards -> claimRewards -> Incentives.claimIncentives -> BalancerHandler.claimIncentivesManual\\n_claimRewards -> claimRewards -> Incentives.claimIncentives -> BalancerHandler.claimIncentivesManual -> nTokenAction.nTokenClaimIncentives (External)\\n_claimRewards -> claimRewards -> Incentives.claimIncentives -> BalancerHandler.claimIncentivesManual -> nTokenAction.nTokenClaimIncentives (External) -> claimNOTE (External)\\n```\\n
The current implementation uses a "push" approach where reward tokens are sent to the recipient during every update, which introduces additional attack surfaces that the attackers can exploit.\\nConsider adopting a pull method for users to claim their rewards instead so that the transfer of reward tokens is disconnected from the updating of reward balances.
Many of the core functionalities of the protocol will be affected by the revert. Specifically, the `BalancerHandler._finalize` has the most impact as this function is called by almost every critical functionality of the protocol, including deposit, withdrawal, and liquidation.\\nThe worst-case scenario is that malicious users might exploit this trick to intentionally trigger a revert when someone attempts to liquidate their unhealthy accounts to block the liquidation, leaving the protocol with bad debts and potentially leading to insolvency if it accumulates.
```\\nFile: SecondaryRewarder.sol\\n    function _claimRewards(address account, uint256 nTokenBalanceBefore, uint256 nTokenBalanceAfter) private { \\n        uint256 rewardToClaim = _calculateRewardToClaim(account, nTokenBalanceBefore, accumulatedRewardPerNToken); \\n\\n        // Precision here is:\\n        //  nTokenBalanceAfter (INTERNAL_TOKEN_PRECISION) \\n        //  accumulatedRewardPerNToken (INCENTIVE_ACCUMULATION_PRECISION) \\n        // DIVIDE BY\\n        //  INTERNAL_TOKEN_PRECISION \\n        //  => INCENTIVE_ACCUMULATION_PRECISION (1e18) \\n        rewardDebtPerAccount[account] = nTokenBalanceAfter \\n            .mul(accumulatedRewardPerNToken)\\n            .div(uint256(Constants.INTERNAL_TOKEN_PRECISION))\\n            .toUint128(); \\n\\n        if (0 < rewardToClaim) { \\n            GenericToken.safeTransferOut(REWARD_TOKEN, account, rewardToClaim); \\n            emit RewardTransfer(REWARD_TOKEN, account, rewardToClaim);\\n        }\\n    }\\n```\\n