BalancerFlashloanDirectMintHandler

Git Source

Inherits: IonHandlerBase, IFlashLoanRecipient

This contract allows for easy creation of leverage positions through Balancer flashloans and LST mints through the LST provider.

There are a couple things to consider here from a security perspective. The first one is that the flashloan callback must only be callable from the Balancer vault. This ensures that nobody can pass arbitrary data to the callback. The second one is that the flashloan must only be initialized from this contract. This is a trickier one to enforce since Balancer flashloans are not EIP-3156 compliant and do not pass on the initiator through the callback. To get around this, an inverse reentrancy lock of sorts is used. The lock is set to 2 when a flashloan is initiated and set to 1 once the callback execution terminates. If the lock is not 2 when the callback is called, then the flashloan was not initiated by this contract and the tx is reverted. This contract currently deposits directly into LST contract 1:1. It should be noted that a more favorable trade could be possible via DEXs.

State Variables

flashloanInitiated

uint256 private flashloanInitiated = 1;

Functions

flashLeverageCollateral

Transfer collateral from user + flashloan collateral from balancer -> deposit all collateral into IonPool -> borrow WETH from IonPool -> mint collateral using WETH -> repay Balancer flashloan.

Code assumes Balancer flashloans remain free.

function flashLeverageCollateral(
    uint256 initialDeposit,
    uint256 resultingAdditionalCollateral,
    uint256 maxResultingDebt,
    bytes32[] calldata proof
)
    external
    onlyWhitelistedBorrowers(proof);

Parameters

NameTypeDescription

initialDeposit

uint256

in collateral terms. [WAD]

resultingAdditionalCollateral

uint256

in collateral terms. [WAD]

maxResultingDebt

uint256

in WETH terms. While it is unlikely that the exchange rate changes from when a transaction is submitted versus when it is executed, it is still possible so we want to allow for a bound here, even though it doesn't pose the same level of threat as slippage. [WAD]

proof

bytes32[]

used to validate the user is whitelisted.

_flashLeverageCollateral

Assumes that the caller has already transferred the deposit asset. Can be called internally by a wrapper that needs additional logic to obtain the LST. Ex) Zapping stEth to wstETH.

function _flashLeverageCollateral(
    uint256 initialDeposit,
    uint256 resultingAdditionalCollateral,
    uint256 maxResultingDebt
)
    internal;

flashLeverageWeth

Transfer collateral from user + flashloan WETH from balancer -> mint collateral using WETH -> deposit all collateral into IonPool -> borrow WETH from IonPool -> repay Balancer flashloan.

Code assumes Balancer flashloans remain free.

function flashLeverageWeth(
    uint256 initialDeposit,
    uint256 resultingAdditionalCollateral,
    uint256 maxResultingDebt,
    bytes32[] calldata proof
)
    external
    payable
    onlyWhitelistedBorrowers(proof);

Parameters

NameTypeDescription

initialDeposit

uint256

in collateral terms. [WAD]

resultingAdditionalCollateral

uint256

in collateral terms. [WAD]

maxResultingDebt

uint256

in WETH terms. While it is unlikely that the exchange rate changes from when a transaction is submitted versus when it is executed, it is still possible so we want to allow for a bound here, even though it doesn't pose the same level of threat as slippage. [WAD]

proof

bytes32[]

used to validate the user is whitelisted.

_flashLeverageWeth

Assumes that the caller has already transferred the deposit asset. Can be called internally by a wrapper that needs additional logic to obtain the LST. Ex) Zapping stEth to wstETH.

function _flashLeverageWeth(
    uint256 initialDeposit,
    uint256 resultingAdditionalCollateral,
    uint256 maxResultingDebt
)
    internal;

receiveFlashLoan

This function is never intended to be called directly.

Code assumes Balancer flashloans remain free. This function is intended to never be called directly. It should only be called by the Balancer VAULT during a flashloan initiated by this contract. This callback logic only handles the creation of leverage positions by minting. Since atomic withdrawals are not possible, deleveraging with a flashloan directly through an LST provider is not possible.

function receiveFlashLoan(
    IERC20Balancer[] memory tokens,
    uint256[] memory amounts,
    uint256[] memory,
    bytes memory userData
)
    external
    override;

Parameters

NameTypeDescription

tokens

IERC20Balancer[]

Array of tokens flashloaned.

amounts

uint256[]

Amounts flashloaned.

<none>

uint256[]

userData

bytes

Arbitrary data passed from initiator of flash loan.

_depositWethForLst

Unwraps weth into eth and deposits into lst contract.

Unwraps weth into eth and deposits into lst contract.

function _depositWethForLst(uint256 amountWeth) internal virtual returns (uint256);

Parameters

NameTypeDescription

amountWeth

uint256

The WETH amount to deposit. [WAD]

Returns

NameTypeDescription

<none>

uint256

Amount of lst received. [WAD]

_getEthAmountInForLstAmountOut

Calculates the amount of eth required to receive amountLst.

Calculates the amount of eth required to receive amountLst.

function _getEthAmountInForLstAmountOut(uint256 amountLst) internal view virtual returns (uint256);

Parameters

NameTypeDescription

amountLst

uint256

Desired output amount. [WAD]

Returns

NameTypeDescription

<none>

uint256

Eth required for desired lst output. [WAD]

Errors

ReceiveCallerNotVault

error ReceiveCallerNotVault(address unauthorizedCaller);

FlashLoanedTooManyTokens

error FlashLoanedTooManyTokens(uint256 amountTokens);

FlashloanedInvalidToken

error FlashloanedInvalidToken(address tokenAddress);

ExternalBalancerFlashloanNotAllowed

error ExternalBalancerFlashloanNotAllowed();