FEI and TRIBE Redemption contest - dipp's results

A new DeFi primitive that allows any token to become productive and provide FEI liquidity at no cost to the markets that need it most.

General Information

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

Tribe

Findings Distribution

Researcher Performance

Rank: 31/101

Findings: 1

Award: $33.67

🌟 Selected for report: 0

🚀 Solo Findings: 0

[L-01] User could lose redeem tokens if the amount of cTokens given is too little

Line References

RariMerkleRedeemer.sol#L81-L86

Description

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.

Impact

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.

Proof of Concept

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.

[L-02] A redeemBase value that is too large could break redeeming

Line References

TribeRedeemer.sol#L44-L61

Description

If 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.

Impact

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.

Proof of Concept

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.

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter