# FM\_BC\_Bancor\_Redeeming\_VirtualSupply\_v1.sol

[Git Source](https://github.com/InverterNetwork/inverter-contracts/blob/649b450f02fc8b735c128ff0821467e71966c666/src/modules/fundingManager/bondingCurve/FM_BC_Bancor_Redeeming_VirtualSupply_v1.sol)

**Inherits:** IFM\_BC\_Bancor\_Redeeming\_VirtualSupply\_v1, IFundingManager\_v1, VirtualIssuanceSupplyBase\_v1, VirtualCollateralSupplyBase\_v1, RedeemingBondingCurveBase\_v1

**Author:** Inverter Network

This contract enables the issuance and redeeming of tokens on a bonding curve, using a virtual supply for both the issuance and the collateral as input. It integrates Aragon's {BancorFormula} to manage the calculations for token issuance and redemption rates based on specified reserve ratios.

*Inherits {BondingCurveBase\_v1}, {RedeemingBondingCurveBase\_v1}, {VirtualIssuanceSupplyBase\_v1}, and {VirtualCollateralSupplyBase\_v1}. Implements formulaWrapper functions for bonding curve calculations using the {BancorFormula}. {Orchestrator\_v1} Admin manages configuration such as virtual supplies and reserve ratios. Ensure interaction adheres to defined transactional limits and decimal precision requirements to prevent computational overflows or underflows.*

### State Variables

#### formula

*The interface of the Bancor Formula used to calculate the issuance and redeeming amount.*

```solidity
IBancorFormula public formula;
```

#### eighteenDecimals

*Value is used to convert deposit amount to 18 decimals, which is required by the {BancorFormula}. which is required by the Bancor formula.*

```solidity
uint8 private constant eighteenDecimals = 18;
```

#### PPM

*Parts per million used for calculation the reserve ratio for the Bancor formula.*

```solidity
uint32 internal constant PPM = 1_000_000;
```

#### reserveRatioForBuying

*The reserve ratio for buying determines the rate of price growth. It is a measure of the fraction of the Token's value that is held in reserve. The value is a number between 0 and 100%, expressed in PPM. A higher reserve ratio means slower price growth. See Bancor Formula contract for reference.*

```solidity
uint32 internal reserveRatioForBuying;
```

#### reserveRatioForSelling

*The reserve ratio for selling determines the rate of price growth. It is a measure of the fraction of the Token's value that is held in reserve. The value is a number between 0 and 100%, expressed in PPM. A higher reserve ratio means slower price growth. See Bancor Formula contract for reference.*

```solidity
uint32 internal reserveRatioForSelling;
```

#### \_token

*Token that is accepted by this funding manager for deposits.*

```solidity
IERC20 private _token;
```

#### collateralTokenDecimals

*Token decimals of the Orchestrator token, which is used as collateral and stores within implementation for gas saving.*

```solidity
uint8 internal collateralTokenDecimals;
```

#### issuanceTokenDecimals

*Token decimals of the issuance token, which is stored within the implementation for gas saving.*

```solidity
uint8 internal issuanceTokenDecimals;
```

#### \_\_gap

*Storage gap for future upgrades.*

```solidity
uint[50] private __gap;
```

### Functions

#### supportsInterface

*See {IERC165-supportsInterface}.*

```solidity
function supportsInterface(bytes4 interfaceId)
    public
    view
    virtual
    override(
        VirtualIssuanceSupplyBase_v1,
        VirtualCollateralSupplyBase_v1,
        RedeemingBondingCurveBase_v1
    )
    returns (bool);
```

#### onlyWhenCurveInteractionsAreClosed

*Modifier to guarantee the buying and selling functionalities are closed.*

```solidity
modifier onlyWhenCurveInteractionsAreClosed();
```

#### init

```solidity
function init(
    IOrchestrator_v1 orchestrator_,
    Metadata memory metadata,
    bytes memory configData
) external override(Module_v1) initializer;
```

#### buyFor

Buy tokens on behalf of a specified receiver address. This function is subject to a transactional limit, determined by the deposit token's decimal precision and the underlying bonding curve algorithm.

*Redirects to the internal function `_buyOrder` by passing the receiver address and deposit amount. Important: The {BancorFormula} has an upper computational limit of (10^38). For tokens with 18 decimal places, this effectively leaves a maximum allowable deposit amount of (10^20). While this is substantially large, it is crucial to be aware of this constraint. Transactions exceeding this limit will be reverted.*

```solidity
function buyFor(address _receiver, uint _depositAmount, uint _minAmountOut)
    public
    virtual
    override(BondingCurveBase_v1)
    validReceiver(_receiver)
    buyingIsEnabled;
```

**Parameters**

| Name             | Type      | Description                                                                     |
| ---------------- | --------- | ------------------------------------------------------------------------------- |
| `_receiver`      | `address` | The address that will receive the bought tokens.                                |
| `_depositAmount` | `uint256` | The amount of collateral token depoisited.                                      |
| `_minAmountOut`  | `uint256` | The minimum acceptable amount the user expects to receive from the transaction. |

#### buy

Buy tokens for the sender's address. This function is subject to a transactional limit, determined by the deposit token's decimal precision and the underlying bonding curve algorithm.

*Redirects to the internal function `_buyOrder` by passing the sender's address and deposit amount. Important: The {BancorFormula} has an upper computational limit of (10^38). While this is substantially large, it is crucial to be aware of this constraint. Transactions exceeding this limit will be reverted.*

```solidity
function buy(uint _depositAmount, uint _minAmountOut)
    public
    virtual
    override(BondingCurveBase_v1)
    buyingIsEnabled;
```

**Parameters**

| Name             | Type      | Description                                                                     |
| ---------------- | --------- | ------------------------------------------------------------------------------- |
| `_depositAmount` | `uint256` | The amount of collateral token depoisited.                                      |
| `_minAmountOut`  | `uint256` | The minimum acceptable amount the user expects to receive from the transaction. |

#### sellTo

Redeem tokens and direct the proceeds to a specified receiver address. This function is subject to a transactional limit, determined by the issuing token's decimal precision and the underlying bonding curve algorithm.

*Redirects to the internal function `_sellOrder` by passing the receiver address and deposit amount. Important: The {BancorFormula} has an upper computational limit of (10^26). For tokens with 18 decimal places, this effectively leaves a maximum allowable deposit amount of (10^8), or 100,000,000. Transactions exceeding this limit will be reverted.*

```solidity
function sellTo(address _receiver, uint _depositAmount, uint _minAmountOut)
    public
    virtual
    override(RedeemingBondingCurveBase_v1)
    validReceiver(_receiver)
    sellingIsEnabled;
```

**Parameters**

| Name             | Type      | Description                                                                     |
| ---------------- | --------- | ------------------------------------------------------------------------------- |
| `_receiver`      | `address` | The address that will receive the redeemed tokens.                              |
| `_depositAmount` | `uint256` | The amount of issued token to deposited.                                        |
| `_minAmountOut`  | `uint256` | The minimum acceptable amount the user expects to receive from the transaction. |

#### sell

Redeem collateral for the sender's address. This function is subject to a transactional limit, determined by the issuing token's decimal precision and the underlying bonding curve algorithm.

*Redirects to the internal function `_sellOrder` by passing the sender's address and deposit amount. Important: The {BancorFormula} has an upper computational limit of (10^26). For tokens with 18 decimal places, this effectively leaves a maximum allowable deposit amount of (10^8), or 100,000,000. Transactions exceeding this limit will be reverted.*

```solidity
function sell(uint _depositAmount, uint _minAmountOut)
    public
    virtual
    override(RedeemingBondingCurveBase_v1)
    sellingIsEnabled;
```

**Parameters**

| Name             | Type      | Description                                                                     |
| ---------------- | --------- | ------------------------------------------------------------------------------- |
| `_depositAmount` | `uint256` | The amount of issued token depoisited.                                          |
| `_minAmountOut`  | `uint256` | The minimum acceptable amount the user expects to receive from the transaction. |

#### getReserveRatioForBuying

Returns reserve ratio set for buying, used in the {BancorFormula} contract.

```solidity
function getReserveRatioForBuying() external view returns (uint32);
```

**Returns**

| Name     | Type     | Description               |
| -------- | -------- | ------------------------- |
| `<none>` | `uint32` | Reserve Ratio for buying. |

#### getReserveRatioForSelling

Returns reserve ratio set for selling, used in the {BancorFormula} contract.

```solidity
function getReserveRatioForSelling() external view returns (uint32);
```

**Returns**

| Name     | Type     | Description                |
| -------- | -------- | -------------------------- |
| `<none>` | `uint32` | Reserve Ratio for selling. |

#### getStaticPriceForBuying

Calculates and returns the static price for buying the issuance token. The return value is formatted in PPM.

*Calculates the static price for either selling or buying the issuance token, based on the provided issuance token supply, collateral supply, and buy or sell reserve ratio. Note: The reserve ratio specifies whether the sell or buy price is returned. The formula used is: PPM \* PPM \* collateralSupply / (issuanceTokenSupply \* reserveRatio). The formula is based on Aragon's BatchedBancorMarketMaker, which can be found here: <https://github.com/AragonBlack/fundraising/blob/5ad1332955bab9d36cfad345ae92b7ad7dc0bdbe/apps/batched-bancor-market-maker/contracts/BatchedBancorMarketMaker.sol#L415>*

```solidity
function getStaticPriceForBuying()
    external
    view
    override(BondingCurveBase_v1)
    returns (uint);
```

**Returns**

| Name     | Type      | Description                                          |
| -------- | --------- | ---------------------------------------------------- |
| `<none>` | `uint256` | uint The static price for buying the issuance token. |

#### getStaticPriceForSelling

Calculates and returns the static price for selling the issuance token. The return value is formatted in PPM.

```solidity
function getStaticPriceForSelling()
    external
    view
    override(RedeemingBondingCurveBase_v1)
    returns (uint);
```

**Returns**

| Name     | Type      | Description                                           |
| -------- | --------- | ----------------------------------------------------- |
| `<none>` | `uint256` | uint The static price for selling the issuance token. |

#### token

Returns the token.

```solidity
function token() public view returns (IERC20);
```

**Returns**

| Name     | Type     | Description |
| -------- | -------- | ----------- |
| `<none>` | `IERC20` | The token.  |

#### transferOrchestratorToken

Transfer a specified amount of Tokens to a designated receiver address.

*This function MUST be restricted to be called only by the {Orchestrator\_v1}.*

```solidity
function transferOrchestratorToken(address to, uint amount)
    external
    virtual
    onlyPaymentClient;
```

**Parameters**

| Name     | Type      | Description                               |
| -------- | --------- | ----------------------------------------- |
| `to`     | `address` | The address that will receive the tokens. |
| `amount` | `uint256` | The amount of tokens to be transfered.    |

#### setVirtualIssuanceSupply

Sets the virtual issuance supply to a new value.

*This function calls the internal function `_setVirtualIssuanceSupply`. The function must be implemented by the downstream contract. The downstream contract should manage access control for setting the supply.*

```solidity
function setVirtualIssuanceSupply(uint _virtualSupply)
    external
    virtual
    override(VirtualIssuanceSupplyBase_v1)
    onlyOrchestratorAdmin
    onlyWhenCurveInteractionsAreClosed;
```

**Parameters**

| Name             | Type      | Description                                           |
| ---------------- | --------- | ----------------------------------------------------- |
| `_virtualSupply` | `uint256` | The new value to set for the virtual issuance supply. |

#### setVirtualCollateralSupply

Sets the virtual collateral supply to a new value.

*This function should call the internal function `_setVirtualCollateralSupply`. The function must be implemented by the downstream contract. The downstream contract should manage access control for setting the supply.*

```solidity
function setVirtualCollateralSupply(uint _virtualSupply)
    external
    virtual
    override(VirtualCollateralSupplyBase_v1)
    onlyOrchestratorAdmin
    onlyWhenCurveInteractionsAreClosed;
```

**Parameters**

| Name             | Type      | Description                                             |
| ---------------- | --------- | ------------------------------------------------------- |
| `_virtualSupply` | `uint256` | The new value to set for the virtual collateral supply. |

#### setReserveRatioForBuying

Set the reserve ratio used for issuing tokens on a bonding curve.

*This function can only be called by the {Orchestrator\_v1} admin.*

```solidity
function setReserveRatioForBuying(uint32 _reserveRatio)
    external
    virtual
    onlyOrchestratorAdmin
    onlyWhenCurveInteractionsAreClosed;
```

**Parameters**

| Name            | Type     | Description                                         |
| --------------- | -------- | --------------------------------------------------- |
| `_reserveRatio` | `uint32` | The new reserve ratio for buying, expressed in PPM. |

#### setReserveRatioForSelling

Set the reserve ratio used for redeeming tokens on a bonding curve.

*This function can only be called by the {Orchestrator\_v1} admin.*

```solidity
function setReserveRatioForSelling(uint32 _reserveRatio)
    external
    virtual
    onlyOrchestratorAdmin
    onlyWhenCurveInteractionsAreClosed;
```

**Parameters**

| Name            | Type     | Description                                          |
| --------------- | -------- | ---------------------------------------------------- |
| `_reserveRatio` | `uint32` | The new reserve ratio for selling, expressed in PPM. |

#### \_issueTokensFormulaWrapper

*Calculates the amount of tokens to mint for a given deposit amount using the {BancorFormula}. This internal function is an override of {BondingCurveBase\_v1}'s abstract function. It handles decimal conversions and calculations through the bonding curve.*

```solidity
function _issueTokensFormulaWrapper(uint _depositAmount)
    internal
    view
    override(BondingCurveBase_v1)
    returns (uint mintAmount);
```

**Parameters**

| Name             | Type      | Description                                            |
| ---------------- | --------- | ------------------------------------------------------ |
| `_depositAmount` | `uint256` | The amount of collateral deposited to purchase tokens. |

**Returns**

| Name         | Type      | Description                               |
| ------------ | --------- | ----------------------------------------- |
| `mintAmount` | `uint256` | The amount of tokens that will be minted. |

#### \_redeemTokensFormulaWrapper

*Calculates the amount of collateral to be received when redeeming a given amount of tokens. This internal function is an override of {RedeemingBondingCurveBase\_v1}'s abstract function. It handles decimal conversions and calculations through the bonding curve. Note the {BancorFormula} assumes 18 decimals for all tokens.*

```solidity
function _redeemTokensFormulaWrapper(uint _depositAmount)
    internal
    view
    override(RedeemingBondingCurveBase_v1)
    returns (uint redeemAmount);
```

**Parameters**

| Name             | Type      | Description                                         |
| ---------------- | --------- | --------------------------------------------------- |
| `_depositAmount` | `uint256` | The amount of tokens to be redeemed for collateral. |

**Returns**

| Name           | Type      | Description                                     |
| -------------- | --------- | ----------------------------------------------- |
| `redeemAmount` | `uint256` | The amount of collateral that will be received. |

#### \_setIssuanceToken

*Sets the issuance token for the Bonding Curve Funding Manager. This function overrides the internal function set in {BondingCurveBase\_v1}, adding an input validation specific for the {BancorFormula} utilizing implementation, after which it updates the `issuanceToken` state variable and caches the decimals as `issuanceTokenDecimals`.*

```solidity
function _setIssuanceToken(address _issuanceToken)
    internal
    override(BondingCurveBase_v1);
```

**Parameters**

| Name             | Type      | Description                                          |
| ---------------- | --------- | ---------------------------------------------------- |
| `_issuanceToken` | `address` | The token which will be issued by the Bonding Curve. |

#### \_setVirtualCollateralSupply

*Internal function to directly set the virtual collateral supply to a new value.*

```solidity
function _setVirtualCollateralSupply(uint _virtualSupply)
    internal
    override(VirtualCollateralSupplyBase_v1);
```

**Parameters**

| Name             | Type      | Description                                             |
| ---------------- | --------- | ------------------------------------------------------- |
| `_virtualSupply` | `uint256` | The new value to set for the virtual collateral supply. |

#### \_setVirtualIssuanceSupply

*Internal function to directly set the virtual issuance supply to a new value. Virtual supply cannot be zero, or result in rounded down being zero when conversion is done for use in the Bancor Formulat.*

```solidity
function _setVirtualIssuanceSupply(uint _virtualSupply)
    internal
    override(VirtualIssuanceSupplyBase_v1);
```

**Parameters**

| Name             | Type      | Description                                           |
| ---------------- | --------- | ----------------------------------------------------- |
| `_virtualSupply` | `uint256` | The new value to set for the virtual issuance supply. |

#### \_setReserveRatioForBuying

*Sets the reserve ratio for buying tokens. The function will revert if the ratio is greater than the constant PPM.*

```solidity
function _setReserveRatioForBuying(uint32 _reserveRatio) internal;
```

**Parameters**

| Name            | Type     | Description                                                    |
| --------------- | -------- | -------------------------------------------------------------- |
| `_reserveRatio` | `uint32` | The reserve ratio to be set for buying tokens. Must be <= PPM. |

#### \_setReserveRatioForSelling

*Sets the reserve ratio for selling tokens. Similar to its counterpart for buying, this function sets the reserve ratio for selling tokens. The function will revert if the ratio is greater than the constant PPM.*

```solidity
function _setReserveRatioForSelling(uint32 _reserveRatio) internal;
```

**Parameters**

| Name            | Type     | Description                                                     |
| --------------- | -------- | --------------------------------------------------------------- |
| `_reserveRatio` | `uint32` | The reserve ratio to be set for selling tokens. Must be <= PPM. |

#### \_validateReserveRatio

*Validates the reserve ratio for buying and selling. The function will revert if the ratio is greater than the constant PPM.*

```solidity
function _validateReserveRatio(uint32 _reserveRatio) internal pure;
```

**Parameters**

| Name            | Type     | Description                                        |
| --------------- | -------- | -------------------------------------------------- |
| `_reserveRatio` | `uint32` | The reserve ratio to be validated. Must be <= PPM. |

#### \_checkCurveInteractionClosedModifier

*Checks if the buy and sell functionality is closed.*

```solidity
function _checkCurveInteractionClosedModifier() internal view;
```

#### \_handleCollateralTokensBeforeBuy

Handles incoming collateral tokens by transferring them from the provider.

```solidity
function _handleCollateralTokensBeforeBuy(address _provider, uint _amount)
    internal
    virtual
    override;
```

**Parameters**

| Name        | Type      | Description                                      |
| ----------- | --------- | ------------------------------------------------ |
| `_provider` | `address` | The address that provides the collateral tokens. |
| `_amount`   | `uint256` | The amount of collateral tokens to handle.       |

#### \_handleIssuanceTokensAfterBuy

Handles issuance tokens by minting them to the receiver.

```solidity
function _handleIssuanceTokensAfterBuy(
    address _receiver,
    uint _issuanceTokenAmount
) internal virtual override;
```

**Parameters**

| Name                   | Type      | Description                                      |
| ---------------------- | --------- | ------------------------------------------------ |
| `_receiver`            | `address` | The address that will receive the bought tokens. |
| `_issuanceTokenAmount` | `uint256` | The amount of issuance tokens to handle.         |

#### \_handleCollateralTokensAfterSell

Handles collateral tokens by transferring them to the receiver.

```solidity
function _handleCollateralTokensAfterSell(
    address _receiver,
    uint _collateralTokenAmount
) internal virtual override;
```

**Parameters**

| Name                     | Type      | Description                                          |
| ------------------------ | --------- | ---------------------------------------------------- |
| `_receiver`              | `address` | The address that will receive the collateral tokens. |
| `_collateralTokenAmount` | `uint256` | The amount of collateral tokens to handle.           |
