Open c4-submissions opened 9 months ago
0xleastwood marked the issue as primary issue
0xleastwood marked the issue as selected for report
elmutt (sponsor) confirmed
@0xleastwood I've covered these cases in L-13 and L-14 of my QA report
Note that the ERC20 transfer issue is also already covered by the automated findings https://gist.github.com/romeroadrian/a2045e828aa87418a66e9ab47d811292
Honestly, I interpreted this issue as more than just L-13 and L-14. I thought there was something also being outlined about the onlyRewarder
role making arbitrary approvals which can be used to rug reward tokens whenever. I guess that's not the case so glad you raised this. Will downgrade to QA.
0xleastwood marked the issue as not selected for report
0xleastwood changed the severity to QA (Quality Assurance)
Lines of code
https://github.com/code-423n4/2023-09-asymmetry/blob/main/contracts/strategies/votium/VotiumStrategyCore.sol#L215-L220 https://github.com/code-423n4/2023-09-asymmetry/blob/main/contracts/strategies/votium/VotiumStrategyCore.sol#L280-L291
Vulnerability details
Bug Description
In
VotiumStrategyCore.sol
, thewithdrawStuckTokens()
function is used by the owner to withdraw ERC20 tokens from the Votium contract that are not distributed as reward:VotiumStrategyCore.sol#L215-L220
As seen from above, it uses Openzeppelin's
IERC20
interface to calltransfer()
:IERC20.sol#L41
However, as the interface expects
transfer()
to return abool
,withdrawStuckTokens()
cannot be used to withdraw ERC20 tokens that do not return abool
ontransfer()
. Some examples would include USDT and BNB.When
transfer()
is called, Solidity will attempt to decode the data returned bytransfer()
into abool
due to its interface's definition. However, since these tokens do not have any return value, the data returned will be empty, causingwithdrawStuckTokens()
to revert when attempting to decode its return data.The
applyRewards()
function is used to sell ERC20 tokens from the Votium contract for ETH and distribute them as rewards:VotiumStrategyCore.sol#L280-L291
As seen from above, if the spender's allowance is not
uint256
max, it callsapprove()
to set the spender's allowance to 0 before approving it touint256
max.However, such an implementation will not work for ERC20 tokens that revert on zero value approvals, such as BNB. If
applyRewards()
is called for such a token, the first call toapprove()
would revert, causingapplyRewards()
to revert.Impact
withdrawStuckTokens()
andapplyRewards()
are not be callable for certain ERC20 tokens that do not adhere to the ERC20 standard, which could cause them to become permanently stuck in theVotiumStrategy
contract. This includes widely used tokens such as USDT and BNB.Note that the likelihood of such a token being used as rewards from Votium is not low according to the contest's README:
Recommended Mitigation
Consider using Openzeppelin's SafeERC20 library to handle token transfers and approvals.
Note to judge
I am aware that "Unsafe ERC20 Operations" has been flagged out in the bot report under L-3. However, I have decided to raise it to medium severity, given that Votium might eventually use a weird ERC20 token for rewards in the future, and it will be permanently stuck in the
VotiumStrategy
contract.Note that the C4 docs explicitly states that raising issues from bot reports to a higher severity is fair game, as seen here:
Assessed type
Token-Transfer