# RenzoLibrary

[Git Source](https://github.com/Ion-Protocol/ion-protocol/blob/88cc595825f1dc2eb738fb93e172a3e8ab7a5c43/src/libraries/lrt/RenzoLibrary.sol)

A helper library for Renzo-related conversions.

\*The behaviour in minting ezETH is quite strange, so for the sake of the maintenance of this code, we document the behaviour at block 19387902. The following function is invoked to calculate the amount of ezETH to mint given an `ethAmount` to deposit: `calculateMintAmount(totalTVL, ethAmount, totalSupply)`.

```
function calculateMintAmount(uint256 _currentValueInProtocol, uint256 _newValueAdded, uint256 _existingEzETHSupply)
external pure returns (uint256) {
...
// Calculate the percentage of value after the deposit
uint256 inflationPercentaage = SCALE_FACTOR * _newValueAdded / (_currentValueInProtocol + _newValueAdded);
// Calculate the new supply
uint256 newEzETHSupply = (_existingEzETHSupply * SCALE_FACTOR) / (SCALE_FACTOR - inflationPercentaage);
// Subtract the old supply from the new supply to get the amount to mint
uint256 mintAmount = newEzETHSupply - _existingEzETHSupply;
if(mintAmount == 0) revert InvalidTokenAmount();
...
}
```

The first thing to note here is the increments by which you can mint ezETH. To mint a non-zero amount of ezETH, `newEzETHSupply` must not be equal to `_existingEzETHSupply`. For this to happen, `inflationPercentage` must be non-zero. At block 19387902, the `totalTVL` or (`_currentValueInProtocol`) is `227527390751192406096375`. So the smallest value for `_newValueAdded` (or the ETH deposited) that will produce an `inflationPercentage` of 1 is `227528`. Any deposit amount less than this will not mint any ezETH (in fact, it will revert). This is the first piece of strange behaviour; the minimum amount to deposit to mint any ezETH is `227528` wei. This will mint `226219` ezETH. The second piece of strange behaviour can be noted when increasing the deposit. If it is increased from `227528` to `227529`, the amount of ezETH minted REMAINS `226219`. This is the case all the way until `455054`. This means that if a user deposits anywhere between `226219` and `455054` wei, they will mint `226219` ezETH. This is because the `inflationPercentage` remains at 1. At `455055` wei, the `inflationPercentage` finally increases to 2, and the amount of ezETH minted increases to `452438`. This also means that it is impossible to mint an ezETH value between `226219` and `452438` wei even though the transfer granularity remains 1 wei. One side effect of this second behaviour is the cost of acquisition can be optimized. It's a really small difference but to acquire `226219` ezETH a user should pay `227528` wei instead of any other value between `227528` and `455054` wei. We will call a mintable amount of ezETH a "mintable amount" (recall that at block 19387902, a user cannot mint between `226219` and `452438` ezETH). So `226219` and `452438` are mint amounts. We will call the range of values that produce the same amount of ezETH a "mint range". The mint range for `0` ezETH is `0` to `227527` wei and the mint range for `226219` ezETH is `227528` to `455054` wei.\*

### [Functions](broken://pages/FAKKsQTxX2ZoXCYuM0Q2) <a href="#functions" id="functions"></a>

#### [getEthAmountInForLstAmountOut](broken://pages/FAKKsQTxX2ZoXCYuM0Q2) <a href="#getethamountinforlstamountout" id="getethamountinforlstamountout"></a>

Returns the amount of ETH required to mint at least `minAmountOut` ezETH and the actual amount of ezETH minted when depositing that amount of ETH.

*The goal here is to mint at least `minAmountOut` ezETH. So first, we must find the "mintable amount" right above `minAmountOut`. This ensures that we mint at least `minAmountOut`. Then we find the minimum amount of ETH required to mint that "mintable amount". Essentially, we want to find the lower bound of the "mint range" of the "mintable amount" right above `minAmountOut`. There exists an edge case where `minAmountOut` is an exact "mintable amount". Continuing with the example from block 19387902, if `minAmountOut` is `226218`, the `inflationPercentage` below would be 0. It would then be incremented to 1 and then when deriving the true `amountOut` from the incremented `inflationPercentage`, it would get `amountOut = 226219`. However, if `minAmountOut` is `226219`, the `inflationPercentage` below would be 1 and it would be incremented to 2. Then, true `amountOut` would then be `452438` which is unnecessarily minting more when the initial "mintable amount" was perfect. In this case, the inflationPercentage that the `_calculateDepositAmount`'s `ethAmountIn` maps to may not be the most optimal and users may incur the cost of paying extra dust for the same mint amount. However, we have empirically observed via fuzzing that 90% of the time, the ethAmountIn calculated through this function will be the most optimal eth amount in, and one less the `ethAmountIn` will result in a mint amount out lower than the minimum.*

```
function getEthAmountInForLstAmountOut(uint256 minAmountOut)
    internal
    view
    returns (uint256 ethAmountIn, uint256 amountOut);
```

**Parameters**

| Name           | Type      | Description                     |
| -------------- | --------- | ------------------------------- |
| `minAmountOut` | `uint256` | Minimum amount of ezETH to mint |

**Returns**

| Name          | Type      | Description                                                |
| ------------- | --------- | ---------------------------------------------------------- |
| `ethAmountIn` | `uint256` | Amount of ETH required to mint the desired amount of ezETH |
| `amountOut`   | `uint256` | Actual output amount of ezETH                              |

#### [getLstAmountOutForEthAmountIn](broken://pages/FAKKsQTxX2ZoXCYuM0Q2) <a href="#getlstamountoutforethamountin" id="getlstamountoutforethamountin"></a>

Returns the amount of ezETH that will be minted with the provided `ethAmount` and the optimal amount of ETH to acquire the same amount of ezETH.

```
function getLstAmountOutForEthAmountIn(uint256 ethAmount)
    internal
    view
    returns (uint256 amount, uint256 optimalAmount);
```

**Parameters**

| Name        | Type      | Description                  |
| ----------- | --------- | ---------------------------- |
| `ethAmount` | `uint256` | amount of eth to use to mint |

**Returns**

| Name            | Type      | Description                                                              |
| --------------- | --------- | ------------------------------------------------------------------------ |
| `amount`        | `uint256` | of ezETH minted                                                          |
| `optimalAmount` | `uint256` | optimal amount of ETH required to mint (at the bottom of the mint range) |

#### [depositForLrt](broken://pages/FAKKsQTxX2ZoXCYuM0Q2) <a href="#depositforlrt" id="depositforlrt"></a>

```
function depositForLrt(uint256 ethAmount) internal returns (uint256 ezEthAmountToMint);
```

#### [\_calculateDepositAmount](broken://pages/FAKKsQTxX2ZoXCYuM0Q2) <a href="#calculatedepositamount" id="calculatedepositamount"></a>

Returns the amount of ETH required to mint amountOut ezETH.

*This function does NOT account for the rounding errors in the ezETH. It simply performs the minting calculation in reverse. To use this function properly, `amountOut` should be a "mintable amount" (an amount of ezETH that is actually possible to mint).*

```
function _calculateDepositAmount(
    uint256 _currentValueInProtocol,
    uint256 _existingEzETHSupply,
    uint256 amountOut
)
    private
    pure
    returns (uint256);
```

**Parameters**

| Name                      | Type      | Description                      |
| ------------------------- | --------- | -------------------------------- |
| `_currentValueInProtocol` | `uint256` | Total TVL in the system.         |
| `_existingEzETHSupply`    | `uint256` | Total supply of ezETH.           |
| `amountOut`               | `uint256` | Desired amount of ezETH to mint. |

#### [\_calculateMintAmount](broken://pages/FAKKsQTxX2ZoXCYuM0Q2) <a href="#calculatemintamount" id="calculatemintamount"></a>

Calculates the amount of ezETH that will be minted.

*This function emulates the calculations in the Renzo contract (including rounding errors).*

```
function _calculateMintAmount(
    uint256 _currentValueInProtocol,
    uint256 _existingEzETHSupply,
    uint256 _newValueAdded
)
    private
    pure
    returns (uint256);
```

**Parameters**

| Name                      | Type      | Description                             |
| ------------------------- | --------- | --------------------------------------- |
| `_currentValueInProtocol` | `uint256` | The TVL in the protocol (in ETH terms). |
| `_existingEzETHSupply`    | `uint256` | The current supply of ezETH.            |
| `_newValueAdded`          | `uint256` | The amount of ETH to deposit.           |

**Returns**

| Name     | Type      | Description                              |
| -------- | --------- | ---------------------------------------- |
| `<none>` | `uint256` | The amount of ezETH that will be minted. |

### [Errors](broken://pages/FAKKsQTxX2ZoXCYuM0Q2) <a href="#errors" id="errors"></a>

#### [InvalidAmountOut](broken://pages/FAKKsQTxX2ZoXCYuM0Q2) <a href="#invalidamountout" id="invalidamountout"></a>

```
error InvalidAmountOut(uint256 amountOut);
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.ionprotocol.io/devs/smart-contract-architecture/libraries/lrt/renzolibrary.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
