Skip to content
This repository has been archived by the owner on Dec 17, 2023. It is now read-only.

Latest commit

 

History

History
72 lines (54 loc) · 3.7 KB

122.md

File metadata and controls

72 lines (54 loc) · 3.7 KB

sl1

medium

IronBank._getExchangeRate calculations are wrong.

Summary

_getExchangeRate uses wrong formula for calculating the exchangeRate.

Vulnerability Detail

Each market has a totalReserves variable that hold the amount of excess ibTokens which will be used as an additional liquidity for the protocol. absorbToReserves function is used to increase reserves by absorbing the slurpus cash.

uint256 ibTokenAmount = (amount * 1e18) / _getExchangeRate(m);
            // Update internal cash, and total reserves.
            m.totalCash += amount;
            m.totalReserves += ibTokenAmount;

It updates internal cash and m.totalReserves but does not increment m.totalSupply as excess ibTokens should not be added to totalSupply. The problem arises when using redeem function. This function calculates the amount to redeem in exchange for ibTokens. It calculates the exchangeRate using _getExchangeRate function.

return ((m.totalCash + m.totalBorrow) * 1e18) / totalSupplyPlusReserves;

The exchange rate here is based on totalCash + totalBorrow / totalSupplyPlusReserves, meaning that this excess of ibTokens is used in calculations while it should not be because it is held separately to provide additional liquidity The proper way would be to store not only the excess of ibTokens but also the excess of underlying asset, and calculate the exchangeRate usign formula: (totalUnderlying - excessUnderlying) / totalSupply. This approach accurately reflects the real liquidity available in the lending protocol, and does not allow users to access protocol's reserves

Assume 2 cases:

  1. Protocol reserves are used in calculations Market state: totalCash = 1000 totalBorrow = 500 totalSupply = 1000 totalReserves = 200

ExchangeRate is calculated as follows = (totalCash + totalBorrow) / totalSupplyPlusReserves; This leads to exchangeRate being = (1000 + 500) / (1000 + 200) = 1500 / 1200 = 1.25

Now user wants to redeem 100 of underlying asset, he calls redeem. Redeem function calcualtes the amount of ibToken that will be redeem as: amountUnderlying / exchangeRate, this leaves us with 100 / 1.25 = 80 ibTokens that will be redeemd.

  1. Second scenario where additional liquidity is not being used in calculations. Market state: totalCash = 1000 totalBorrow = 500 totalSupply = 1000 totalReserves = 200 excessUnderlying = 50

ExchangeRate here is = (totalCash + totalBorrow - excessUnderying) / totalSupply (1000 + 500 - 50) / 1000 = 1450 / 1000 = 1.45;

User wants to redeem 100 of underlying tokens, redeem function calcualtes the amount of ibTokens that will be redeemed as follows: amount / exchangeRate = 100 / 1.45 = 69 ibToken that will be redeemed.

This shows how wrong calculations affect the amount to be redeemed. When additional liquidity is used in calculations every user will redeem more than he should be able to essentially draining protocol liquidity.

Impact

Because of the wrong calculations when users redeem they can actually redeem a part of the totalReserves because they are used in calculation while they shouldn't be, which also means that protocol is not functioning as it supposed to.

Code Snippet

https://github.com/sherlock-audit/2023-05-ironbank/blob/main/ib-v2/src/protocol/pool/IronBank.sol#L662C12-L666 https://github.com/sherlock-audit/2023-05-ironbank/blob/main/ib-v2/src/protocol/pool/IronBank.sol#L406-L451 https://github.com/sherlock-audit/2023-05-ironbank/blob/main/ib-v2/src/protocol/pool/IronBank.sol#L805-L811

Tool used

Manual Review

Recommendation

Change calculations so they don't include the excess of underlying token and excess of ibTokens (which should be used as additional liquidity)