Borrower

Git Source

Inherits: IUniswapV3MintCallback

Author: Aloe Labs, Inc.

"Test everything; hold fast what is good." - 1 Thessalonians 5:21

State Variables

SLOT0_MASK_POSITIONS

uint256 private constant SLOT0_MASK_POSITIONS = 0x000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff;

SLOT0_MASK_USERSPACE

uint256 private constant SLOT0_MASK_USERSPACE = 0x000000000000ffffffffffffffff000000000000000000000000000000000000;

SLOT0_MASK_AUCTION

uint256 private constant SLOT0_MASK_AUCTION = 0x00ffffffffff0000000000000000000000000000000000000000000000000000;

SLOT0_MASK_STATE

uint256 private constant SLOT0_MASK_STATE = 0x7f00000000000000000000000000000000000000000000000000000000000000;

SLOT0_DIRT

uint256 private constant SLOT0_DIRT = 0x8000000000000000000000000000000000000000000000000000000000000000;

FACTORY

The factory that created this contract

Factory public immutable FACTORY;

ORACLE

The oracle to use for prices and implied volatility

VolatilityOracle public immutable ORACLE;

UNISWAP_POOL

The Uniswap pair in which this Borrower can manage positions

IUniswapV3Pool public immutable UNISWAP_POOL;

TOKEN0

The first token of the Uniswap pair

ERC20 public immutable TOKEN0;

TOKEN1

The second token of the Uniswap pair

ERC20 public immutable TOKEN1;

LENDER0

The lender of TOKEN0

Lender public immutable LENDER0;

LENDER1

The lender of TOKEN1

Lender public immutable LENDER1;

slot0

The Borrower's only mutable storage. Lowest 144 bits store the lower/upper bounds of up to 3 Uniswap positions, encoded by Positions.zip. Next 64 bits are unused within the Borrower and available to users as "free" storage - no additional sstore's. These 208 bits (144 + 64) are passed to IManager.callback, and get updated when the callback returns a non-zero value. The next 40 bits are either 0 or the warning time. The highest 8 bits represent the current State enum, plus 128. We add 128 (i.e. set the highest bit to 1) so that the slot is always non-zero, even in the absence of Uniswap positions - this saves gas.

uint256 public slot0;

Functions

onlyInModifyCallback

modifier onlyInModifyCallback();

constructor

constructor(VolatilityOracle oracle, IUniswapV3Pool pool, Lender lender0, Lender lender1);

receive

receive() external payable;

owner

function owner() public pure returns (address);

warn

Warns the borrower that they're about to be liquidated

function warn(uint40 oracleSeed) external;

Parameters

NameTypeDescription
oracleSeeduint40The indices of UNISWAP_POOL.observations where we start our search for the 30-minute-old (lowest 16 bits) and 60-minute-old (next 16 bits) observations when getting TWAPs. If any of the highest 8 bits are set, we fallback to onchain binary search.

clear

Clears the warning state if the account is healthy and has a full ante

If you bring the account back to health via a modify call, the warning state is cleared automatically. However, if borrowing is paused and modify is restricted, you may want to repay the Lender(s) directly and use this to clear the warning.

function clear(uint40 oracleSeed) external payable;

Parameters

NameTypeDescription
oracleSeeduint40The indices of UNISWAP_POOL.observations where we start our search for the 30-minute-old (lowest 16 bits) and 60-minute-old (next 16 bits) observations when getting TWAPs. If any of the highest 8 bits are set, we fallback to onchain binary search.

liquidate

Liquidates the borrower, using all available assets to pay down liabilities. callee must transfer at least amounts.repay0 and amounts.repay1 to LENDER0 and LENDER1, respectively. amounts.out0 and amounts.out1 start at 0 and increase over time. Once their value exceeds what must be repaid, the excess acts as a liquidation incentive.

The amounts out are 0 for the entirety of the LIQUIDATION_GRACE_PERIOD. They start rising afterwards, reaching 105% of the repay value after 5 minutes and 112% after 55 minutes.

function liquidate(ILiquidator callee, bytes calldata data, uint256 closeFactor, uint40 oracleSeed) external;

Parameters

NameTypeDescription
calleeILiquidatorThe smart contract responsible for swapping and repaying
databytesEncoded parameters that get forwarded to callee
closeFactoruint256The fraction of liabilities to repay, expressed in basis points
oracleSeeduint40The indices of UNISWAP_POOL.observations where we start our search for the 30-minute-old (lowest 16 bits) and 60-minute-old (next 16 bits) observations when getting TWAPs. If any of the highest 8 bits are set, we fallback to onchain binary search.

modify

Allows the owner to manage their account by handing control to some callee. Inside the callback callee has access to all sub-commands (uniswapDeposit, uniswapWithdraw, transfer, borrow, repay, and withdrawAnte). Whatever callee does, the account MUST be healthy after the callback.

function modify(IManager callee, bytes calldata data, uint40 oracleSeed) external payable;

Parameters

NameTypeDescription
calleeIManagerThe smart contract that will get temporary control of this account
databytesEncoded parameters that get forwarded to callee
oracleSeeduint40The indices of UNISWAP_POOL.observations where we start our search for the 30-minute-old (lowest 16 bits) and 60-minute-old (next 16 bits) observations when getting TWAPs. If any of the highest 8 bits are set, we fallback to onchain binary search.

uniswapV3MintCallback

Callback for Uniswap V3 pool; necessary for uniswapDeposit to work

function uniswapV3MintCallback(uint256 amount0, uint256 amount1, bytes calldata) external;

Parameters

NameTypeDescription
amount0uint256The amount of TOKEN0 owed to the UNISWAP_POOL
amount1uint256The amount of TOKEN1 owed to the UNISWAP_POOL
<none>bytes

uniswapDeposit

Allows the owner() to add liquidity to a Uniswap position (or create a new one). Only works within the modify callback.

The LiquidityAmounts library can help convert underlying amounts to units of liquidity. NOTE: Depending on your use-case, it may be more gas-efficient to call UNISWAP_POOL.mint in your own contract, instead of doing uniswapDeposit inside of modify's callback. As long as you set this Borrower as the recipient in UNISWAP_POOL.mint, the result is the same.

function uniswapDeposit(
    int24 lower,
    int24 upper,
    uint128 liquidity
) external onlyInModifyCallback returns (uint256 amount0, uint256 amount1);

Parameters

NameTypeDescription
lowerint24The tick at the position's lower bound
upperint24The tick at the position's upper bound
liquidityuint128The amount of liquidity to add, in Uniswap's internal units

Returns

NameTypeDescription
amount0uint256The precise amount of TOKEN0 that went into the Uniswap position
amount1uint256The precise amount of TOKEN1 that went into the Uniswap position

uniswapWithdraw

Allows the owner() to withdraw liquidity from one of their Uniswap positions. Only works within the modify callback.

The LiquidityAmounts library can help convert underlying amounts to units of liquidity

function uniswapWithdraw(
    int24 lower,
    int24 upper,
    uint128 liquidity,
    address recipient
) external onlyInModifyCallback returns (uint256 burned0, uint256 burned1, uint256 collected0, uint256 collected1);

Parameters

NameTypeDescription
lowerint24The tick at the position's lower bound
upperint24The tick at the position's upper bound
liquidityuint128The amount of liquidity to remove, in Uniswap's internal units. Pass 0 to collect fees without burning any liquidity.
recipientaddressReceives the tokens from Uniswap. Usually the address of this Borrower account.

Returns

NameTypeDescription
burned0uint256The amount of TOKEN0 that was removed from the Uniswap position
burned1uint256The amount of TOKEN1 that was removed from the Uniswap position
collected0uint256Equal to burned0 plus any earned TOKEN0 fees that hadn't yet been claimed
collected1uint256Equal to burned1 plus any earned TOKEN1 fees that hadn't yet been claimed

transfer

The most flexible sub-command. Allows the owner() to transfer amounts of TOKEN0 and TOKEN1 to any recipient they want. Only works within the modify callback.

function transfer(uint256 amount0, uint256 amount1, address recipient) external onlyInModifyCallback;

Parameters

NameTypeDescription
amount0uint256The amount of TOKEN0 to transfer
amount1uint256The amount of TOKEN1 to transfer
recipientaddressReceives the transferred tokens

transferEth

Allows the owner() to transfer an amount of ETH to any recipient they want. Only works within the modify callback.

function transferEth(uint256 amount, address payable recipient) external onlyInModifyCallback;

Parameters

NameTypeDescription
amountuint256The amount of ETH to transfer
recipientaddress payableReceives the ETH

borrow

Allows the owner() to borrow funds from LENDER0 and LENDER1. Only works within the modify callback.

If amount0 > 0 and interest hasn't yet accrued in this block for LENDER0, it will accrue prior to processing your new borrow. Same goes for amount1 > 0 and LENDER1.

function borrow(uint256 amount0, uint256 amount1, address recipient) external onlyInModifyCallback;

Parameters

NameTypeDescription
amount0uint256The amount of TOKEN0 to borrow
amount1uint256The amount of TOKEN1 to borrow
recipientaddressReceives the borrowed tokens. Usually the address of this Borrower account.

repay

Allows the owner() to repay debts to LENDER0 and LENDER1. Only works within the modify callback.

This is technically unnecessary since you could call Lender.repay directly, specifying this contract as the beneficiary and using the transfer sub-command to make payments. We include it because it's convenient and gas-efficient for common use-cases.

function repay(uint256 amount0, uint256 amount1) external onlyInModifyCallback;

Parameters

NameTypeDescription
amount0uint256The amount of TOKEN0 to repay
amount1uint256The amount of TOKEN1 to repay

rescue

Allows the owner() to perform arbitrary transfers. Useful for rescuing misplaced funds. Only works within the modify callback.

function rescue(ERC20 token, uint256 amount, address recipient) external onlyInModifyCallback;

Parameters

NameTypeDescription
tokenERC20The ERC20 token to transfer
amountuint256The amount to transfer
recipientaddressReceives the transferred tokens

getUniswapPositions

function getUniswapPositions() external view returns (int24[] memory);

getAssets

function getAssets() external view returns (Assets memory);

getLiabilities

function getLiabilities() public view returns (uint256 amount0, uint256 amount1);

getPrices

Summarizes all oracle data pertinent to account health

If seemsLegit == false, you can call Factory.pause to temporarily disable borrows

function getPrices(uint40 oracleSeed) public view returns (Prices memory, bool, bool, uint208);

Parameters

NameTypeDescription
oracleSeeduint40The indices of UNISWAP_POOL.observations where we start our search for the 30-minute-old (lowest 16 bits) and 60-minute-old (next 16 bits) observations when getting TWAPs. If any of the highest 8 bits are set, we fallback to onchain binary search.

Returns

NameTypeDescription
<none>PricesThe probe prices currently being used to evaluate account health
<none>boolWhether the Uniswap TWAP seems to have been manipulated or not
<none>boolWhether the factory has paused this market
<none>uint208The current ante that must be posted before borrowing

_getAssets

function _getAssets(uint256 slot0_, Prices memory prices) private view returns (Assets memory assets);

_uniswapWithdraw

function _uniswapWithdraw(uint256 slot0_) private;

_uniswapWithdraw

function _uniswapWithdraw(
    int24 lower,
    int24 upper,
    uint128 liquidity,
    address recipient
) private returns (uint256 burned0, uint256 burned1, uint256 collected0, uint256 collected1);

Events

Warn

Emitted when the account gets warned. The liquidation incentive will be 0 for 5 minutes, giving the account owner time to regain health on their own. After this LIQUIDATION_GRACE_PERIOD, the incentive starts increasing (following the Dutch Auction curve in BalanceSheet).

Simply regaining health is not enough. To clear the warning, you must replenish the ante and call modify.

event Warn();

Liquidate

Emitted when the account gets liquidated

event Liquidate();

Enums

State

enum State {
    Ready,
    Locked,
    InModifyCallback
}