Platform: Code4rena
Start Date: 09/09/2022
Pot Size: $42,000 USDC
Total HM: 2
Participants: 101
Period: 3 days
Judge: hickuphh3
Total Solo HM: 2
Id: 161
League: ETH
Rank: 31/101
Findings: 1
Award: $33.67
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: GalloDaSballo
Also found by: 0x040, 0x1f8b, 0x4non, 0x52, 0x85102, 0xNazgul, 0xSky, 0xSmartContract, Aymen0909, Bnke0x0, CertoraInc, Chandr, Chom, CodingNameKiki, Deivitto, Diana, Funen, JC, Jeiwan, Junnon, KIntern_NA, Lambda, Mohandes, Noah3o6, Ocean_Sky, Picodes, R2, Randyyy, RaymondFam, ReyAdmirado, Rohan16, Rolezn, Samatak, Sm4rty, SnowMan, SooYa, StevenL, Tagir2003, Tointer, TomJ, Tomo, V_B, Waze, _Adam, __141345__, a12jmx, ajtra, ak1, asutorufos, bharg4v, bobirichman, brgltd, c3phas, cccz, cryptonue, cryptostellar5, cryptphi, csanuragjain, d3e4, datapunk, delfin454000, dipp, djxploit, durianSausage, erictee, fatherOfBlocks, gogo, got_targ, hansfriese, horsefacts, hyh, ignacio, innertia, izhuer, karanctf, ladboy233, leosathya, lucacez, lukris02, mics, oyc_109, pashov, pauliax, prasantgupta52, rbserver, ret2basic, rfa, robee, rokinot, rotcivegaf, rvierdiiev, sach1r0, scaraven, sikorico, simon135, smiling_heretic, sorrynotsorry, unforgiven, wagmi, yixxas
33.6679 USDC - $33.67
RariMerkleRedeemer.sol#L81-L86
In the previewRedeem
function in RariMerkleRedeemer.sol
the amount of cToken sent to the contract is used to calculate the amount of baseToken
to be received by the user. If a user enters an amount without adding decimals and the exchange rate is low enough then they may lose the amount of cTokens sent to the contract.
Since the amount of cTokens must be low enough for the previewRedeem
calculations to return 0, the amount of funds lost would realistically not be too much.
previewRedeem
function in RariMerkleRedeemer.sol
:
function previewRedeem(address cToken, uint256 amount) public view override returns (uint256 baseTokenAmount) { // Each ctoken exchange rate is stored as how much you should get for 1e18 of the particular cToken // Thus, we divide by 1e18 when returning the amount that a person should get when they provide // the amount of cTokens they're turning into the contract return (cTokenExchangeRates[cToken] * amount) / 1e18; }
Since the only requirement for the exchange rate is to be > 1e10, it could have a value of 2e10. The user would need to input an amount of atleast 5e7 so that previewRedeem
does not return 0. If a user forgets to include the decimals and enters an amount of 10 for example then the returned amount will be 0.
_redeem
function in RariMerkleRedeemer.sol
:
function _redeem(address cToken, uint256 cTokenAmount) internal virtual { // check: amount must be greater than 0 require(cTokenAmount != 0, "Invalid amount"); // check: verify that the user's claimedAmount+amount of this cToken doesn't exceed claimableAmount for this cToken require( redemptions[msg.sender][cToken] + cTokenAmount <= claims[msg.sender][cToken], "Amount exceeds available remaining claim." ); // effect: increment the user's claimedAmount redemptions[msg.sender][cToken] += cTokenAmount; uint256 baseTokenAmountReceived = previewRedeem(cToken, cTokenAmount); // interaction: safeTransferFrom the user "amount" of "cToken" to this contract IERC20(cToken).safeTransferFrom(msg.sender, address(this), cTokenAmount); IERC20(baseToken).safeTransfer(msg.sender, baseTokenAmountReceived); emit Redeemed(msg.sender, cToken, cTokenAmount, baseTokenAmountReceived); }
In the _redeem
function, the amount of cToken sent by the user is non-zero while the amount of baseToken received is zero. The user loses the cToken amount.
Consider adding a sanity check in the _redeem
and _multiRedeem
functions to ensure the amount redeemed is not 0.
redeemBase
value that is too large could break redeemingIf the redeemBase
variable in TribeRedeemer.sol
is too large (redeemBase > amountIn*balance
) then the amountsOut
to be sent to the redeemer could be 0 for some or all tokens.
The redeemer could lose their redeemedToken
amount sent to the contract. This could be true if the redeemBase
is set too high in comparison to the balance of a tokensReceived
token multiplied by the amount of redeemedToken
sent by the redeemer.
previewRedeem
in TribeRedeemer.sol
:
function previewRedeem(uint256 amountIn) public view returns (address[] memory tokens, uint256[] memory amountsOut) { tokens = tokensReceivedOnRedeem(); amountsOut = new uint256[](tokens.length); uint256 base = redeemBase; for (uint256 i = 0; i < tokensReceived.length; i++) { uint256 balance = IERC20(tokensReceived[i]).balanceOf(address(this)); require(balance != 0, "ZERO_BALANCE"); // @dev, this assumes all of `tokensReceived` and `redeemedToken` // have the same number of decimals uint256 redeemedAmount = (amountIn * balance) / base; amountsOut[i] = redeemedAmount; } }
If amountIn*balance < base
the redeemedAmount for that token will be 0. If this is the case for all tokens, the user will receive nothing for the Tribe amount sent to the contract.
Check that at least 1 amountsOut
is more than 0 when redeem
is called.