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: 9/101
Findings: 1
Award: $57.64
🌟 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
57.6399 USDC - $57.64
RariMerkleRedeemer.claimAndRedeem
RELATED TO AMOUNT INPUTS IS MORE LIMITED THAN RariMerkleRedeemer.signAndClaimAndRedeem
When calling the following RariMerkleRedeemer.signAndClaimAndRedeem
function, different amount inputs can be used for calling _multiClaim
and _multiRedeem
. However, when calling the claimAndRedeem
function below, only one amounts
input is used for calling both _multiClaim
and _multiRedeem
. Users, who have signed already, are not able to call claimAndRedeem
if they want to call _multiClaim
and _multiRedeem
with different amount inputs and are forced to call _multiClaim
and _multiRedeem
separately in two different transactions, which costs more gas. To improve the usability of the claimAndRedeem
function, it can be updated to include two different amount inputs that are used for calling _multiClaim
and _multiRedeem
respectively, which is similar to the signAndClaimAndRedeem
function.
function signAndClaimAndRedeem( bytes calldata signature, address[] calldata cTokens, uint256[] calldata amountsToClaim, uint256[] calldata amountsToRedeem, bytes32[][] calldata merkleProofs ) external override hasNotSigned nonReentrant { _sign(signature); _multiClaim(cTokens, amountsToClaim, merkleProofs); _multiRedeem(cTokens, amountsToRedeem); }
function claimAndRedeem( address[] calldata cTokens, uint256[] calldata amounts, bytes32[][] calldata merkleProofs ) external hasSigned nonReentrant { _multiClaim(cTokens, amounts, merkleProofs); _multiRedeem(cTokens, amounts); }
tokensReceived
AND redeemedToken
CAN BE CHECKEDAs mentioned by the comment below, the previewRedeem
function "assumes all of tokensReceived
and redeemedToken
have the same number of decimals". To ensure this, a require
statement can be added in the TribeRedeemer
contract's constructor
to verify that the decimals of tokensReceived
and redeemedToken
are all equal before completing the construction of the contract.
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; } }
MESSAGE
CAN BE UPDATED TO BE MORE SPECIFICThe following MESSAGE
is currently a sample generic message. Because MESSAGE
is used for being signed by users, it can be updated to be more specific for improving user experience and avoiding confusion, especially if MESSAGE
needs to be displayed by the frontend.
/// @notice The message to be signed by any users claiming on cTokens string public constant MESSAGE = "Sample message, please update.";
_redeemBase
CAN BE CHECKED AGAINST 0 IN TribeRedeemer
contract's constructor
As the TribeRedeemer
contract's constructor
shows below, redeemBase
is possible to be set to 0. However, calling the following previewRedeem
function will revert if redeemBase
is 0 due to the division by 0. To prevent this from happening, a require
statement can be added in the contract's constructor
to verify that _redeemBase
is not 0 before executing redeemBase = _redeemBase
.
constructor( address _redeemedToken, address[] memory _tokensReceived, uint256 _redeemBase ) { redeemedToken = _redeemedToken; tokensReceived = _tokensReceived; redeemBase = _redeemBase; }
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; } }
To prevent unintended behaviors, the critical address inputs should be checked against address(0)
.
Please consider checking the addresses of cTokens
in the following constructor
.
https://github.com/code-423n4/2022-09-tribe/blob/main/contracts/shutdown/fuse/RariMerkleRedeemer.sol#L35-L44
constructor( address token, address[] memory cTokens, uint256[] memory rates, bytes32[] memory roots ) { _configureExchangeRates(cTokens, rates); _configureMerkleRoots(cTokens, roots); _configureBaseToken(token); }
Please consider checking _core
in the following constructor
.
https://github.com/code-423n4/2022-09-tribe/blob/main/contracts/shutdown/fuse/MerkleRedeemerDripper.sol#L10-L16
constructor( address _core, address _target, uint256 _dripPeriod, uint256 _amountToDrip, address _token ) ERC20Dripper(_core, _target, _dripPeriod, _amountToDrip, _token) {}
Please consider chekcing _redeemedToken
and addresses of _tokensReceived
in the following constructor
.
https://github.com/code-423n4/2022-09-tribe/blob/main/contracts/shutdown/redeem/TribeRedeemer.sol#L27-L35
constructor( address _redeemedToken, address[] memory _tokensReceived, uint256 _redeemBase ) { redeemedToken = _redeemedToken; tokensReceived = _tokensReceived; redeemBase = _redeemBase; }
The phrase in the comment for the following _claim
function should be "in the" instead of "int he".
https://github.com/code-423n4/2022-09-tribe/blob/main/contracts/shutdown/fuse/RariMerkleRedeemer.sol#L164-L169
/// Should set the user's claim amount int he claims mapping for the provided cToken function _claim( address _cToken, uint256 _amount, bytes32[] calldata _merkleProof ) internal virtual {
Querying events can be optimized with index. Please consider adding index to fields of the following events.
https://github.com/code-423n4/2022-09-tribe/blob/main/contracts/peg/SimpleFeiDaiPSM.sol#L26-L29
/// @notice event emitted upon a redemption event Redeem(address to, uint256 amountFeiIn, uint256 amountAssetOut); /// @notice event emitted when fei gets minted event Mint(address to, uint256 amountIn, uint256 amountFeiOut);
The protocol can benefit from more fixes and gas-efficient features by using a newer version of Solidity. Changes for newer Solidity versions can be found in https://blog.soliditylang.org/category/releases/. Please consider updating the versions for the following files.
contracts\shutdown\fuse\MerkleRedeemerDripper.sol 2: pragma solidity =0.8.10; contracts\shutdown\fuse\RariMerkleRedeemer.sol 2: pragma solidity =0.8.10;