Borrower
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
Name | Type | Description |
---|---|---|
oracleSeed | uint40 | The 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
Name | Type | Description |
---|---|---|
oracleSeed | uint40 | The 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
Name | Type | Description |
---|---|---|
callee | ILiquidator | The smart contract responsible for swapping and repaying |
data | bytes | Encoded parameters that get forwarded to callee |
closeFactor | uint256 | The fraction of liabilities to repay, expressed in basis points |
oracleSeed | uint40 | The 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
Name | Type | Description |
---|---|---|
callee | IManager | The smart contract that will get temporary control of this account |
data | bytes | Encoded parameters that get forwarded to callee |
oracleSeed | uint40 | The 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
Name | Type | Description |
---|---|---|
amount0 | uint256 | The amount of TOKEN0 owed to the UNISWAP_POOL |
amount1 | uint256 | The 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
Name | Type | Description |
---|---|---|
lower | int24 | The tick at the position's lower bound |
upper | int24 | The tick at the position's upper bound |
liquidity | uint128 | The amount of liquidity to add, in Uniswap's internal units |
Returns
Name | Type | Description |
---|---|---|
amount0 | uint256 | The precise amount of TOKEN0 that went into the Uniswap position |
amount1 | uint256 | The 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
Name | Type | Description |
---|---|---|
lower | int24 | The tick at the position's lower bound |
upper | int24 | The tick at the position's upper bound |
liquidity | uint128 | The amount of liquidity to remove, in Uniswap's internal units. Pass 0 to collect fees without burning any liquidity. |
recipient | address | Receives the tokens from Uniswap. Usually the address of this Borrower account. |
Returns
Name | Type | Description |
---|---|---|
burned0 | uint256 | The amount of TOKEN0 that was removed from the Uniswap position |
burned1 | uint256 | The amount of TOKEN1 that was removed from the Uniswap position |
collected0 | uint256 | Equal to burned0 plus any earned TOKEN0 fees that hadn't yet been claimed |
collected1 | uint256 | Equal 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
Name | Type | Description |
---|---|---|
amount0 | uint256 | The amount of TOKEN0 to transfer |
amount1 | uint256 | The amount of TOKEN1 to transfer |
recipient | address | Receives 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
Name | Type | Description |
---|---|---|
amount | uint256 | The amount of ETH to transfer |
recipient | address payable | Receives 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
Name | Type | Description |
---|---|---|
amount0 | uint256 | The amount of TOKEN0 to borrow |
amount1 | uint256 | The amount of TOKEN1 to borrow |
recipient | address | Receives 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
Name | Type | Description |
---|---|---|
amount0 | uint256 | The amount of TOKEN0 to repay |
amount1 | uint256 | The 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
Name | Type | Description |
---|---|---|
token | ERC20 | The ERC20 token to transfer |
amount | uint256 | The amount to transfer |
recipient | address | Receives 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
Name | Type | Description |
---|---|---|
oracleSeed | uint40 | The 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
Name | Type | Description |
---|---|---|
<none> | Prices | The probe prices currently being used to evaluate account health |
<none> | bool | Whether the Uniswap TWAP seems to have been manipulated or not |
<none> | bool | Whether the factory has paused this market |
<none> | uint208 | The 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 warn
ed. 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 liquidate
d
event Liquidate();
Enums
State
enum State {
Ready,
Locked,
InModifyCallback
}