Contents

Contents

Contents

Constants

Git Source

ONE

The initial value of Lender's borrowIndex

uint256 constant ONE = 1e12;

BORROWS_SCALER

An additional scaling factor applied to borrowed amounts before dividing by borrowIndex and storing. 72 matches the type of borrowIndex in Ledger to guarantee that the stored borrow units fit in uint256.

uint256 constant BORROWS_SCALER = ONE << 72;

MAX_RATE

The maximum percentage yield per second, scaled up by 1e12. The current value is equivalent to ((1 + 706354 / 1e12) ** (24 * 60 * 60)) - 1 β‡’ +6.3% per day or +53% per week. If the rate is consistently at this maximum value, the Lender will function for 1 year before borrowIndex overflows.

uint256 constant MAX_RATE = 706354;

DEFAULT_ANTE

The default amount of Ether required to take on debt in a Borrower. The Factory can override this value on a per-market basis. Incentivizes calls to Borrower.warn.

uint208 constant DEFAULT_ANTE = 0.01 ether;

DEFAULT_N_SIGMA

The default number of standard deviations of price movement used to determine probe prices for Borrower solvency. The Factory can override this value on a per-market basis. Expressed x10, e.g. 50 β†’ 5Οƒ

uint8 constant DEFAULT_N_SIGMA = 50;

DEFAULT_MANIPULATION_THRESHOLD_DIVISOR

Assume someone is manipulating the Uniswap TWAP oracle. To steal money from the protocol and create bad debt, they would need to change the TWAP by a factor of (1 / LTV), where the LTV is a function of volatility. We have a manipulation metric that increases as an attacker tries to change the TWAP. If this metric rises above a certain threshold, certain functionality will be paused, e.g. no new debt can be created. The threshold is calculated as follows: \( \text{manipulationThreshold} = \frac{log_{1.0001}\left( \frac{1}{\text{LTV}} \right)}{\text{MANIPULATION_THRESHOLD_DIVISOR}} \)

uint8 constant DEFAULT_MANIPULATION_THRESHOLD_DIVISOR = 12;

DEFAULT_RESERVE_FACTOR

The default portion of interest that will accrue to a Lender's RESERVE address. Expressed as a reciprocal, e.g. 16 β†’ 6.25%

uint8 constant DEFAULT_RESERVE_FACTOR = 16;

CONSTRAINT_N_SIGMA_MIN

The lowest number of standard deviations of price movement allowed for determining Borrower probe prices. Expressed x10, e.g. 40 β†’ 4Οƒ

uint8 constant CONSTRAINT_N_SIGMA_MIN = 40;

CONSTRAINT_N_SIGMA_MAX

The highest number of standard deviations of price movement allowed for determining Borrower probe prices. Expressed x10, e.g. 80 β†’ 8Οƒ

uint8 constant CONSTRAINT_N_SIGMA_MAX = 80;

CONSTRAINT_MANIPULATION_THRESHOLD_DIVISOR_MIN

The minimum value of the manipulationThresholdDivisor, described above

uint8 constant CONSTRAINT_MANIPULATION_THRESHOLD_DIVISOR_MIN = 10;

CONSTRAINT_MANIPULATION_THRESHOLD_DIVISOR_MAX

The maximum value of the manipulationThresholdDivisor, described above

uint8 constant CONSTRAINT_MANIPULATION_THRESHOLD_DIVISOR_MAX = 16;

CONSTRAINT_RESERVE_FACTOR_MIN

The lower bound on what any Lender's reserve factor can be. Expressed as reciprocal, e.g. 4 β†’ 25%

uint8 constant CONSTRAINT_RESERVE_FACTOR_MIN = 4;

CONSTRAINT_RESERVE_FACTOR_MAX

The upper bound on what any Lender's reserve factor can be. Expressed as reciprocal, e.g. 20 β†’ 5%

uint8 constant CONSTRAINT_RESERVE_FACTOR_MAX = 20;

CONSTRAINT_ANTE_MAX

The maximum amount of Ether that Borrowers can be required to post before taking on debt

uint216 constant CONSTRAINT_ANTE_MAX = 0.5 ether;

MAX_LEVERAGE

\( 1 + \frac{1}{\text{MAX_LEVERAGE}} \) should be greater than the maximum feasible single-block accrualFactor so that liquidators have time to respond to interest updates

uint256 constant MAX_LEVERAGE = 200;

LIQUIDATION_INCENTIVE

The minimum discount that a healthy Borrower should be able to offer a liquidator when swapping assets. Expressed as reciprocal, e.g. 20 β†’ 5%

uint256 constant LIQUIDATION_INCENTIVE = 20;

LIQUIDATION_GRACE_PERIOD

The minimum time that must pass between calls to Borrower.warn and Borrower.liquidate.

uint256 constant LIQUIDATION_GRACE_PERIOD = 5 minutes;

TERMINATING_CLOSE_FACTOR

The minimum closeFactor necessary to conclude a liquidation auction. To actually conclude the auction, Borrower.liquidate must result in a healthy balance sheet (in addition to this closeFactor requirement). Expressed in basis points. NOTE: The ante is depleted after just 4 Borrower.warnings. By requiring that each auction repay at least 68%, we ensure that after 4 auctions, no more than 1% of debt remains ((1 - 0.6838)^4). Increasing the threshold would reduce that further, but we don't want to prolong individual auctions unnecessarily since the incentive (and loss to Borrowers) increases with time.

uint256 constant TERMINATING_CLOSE_FACTOR = 6837;

PROBE_SQRT_SCALER_MIN

The minimum scaling factor by which sqrtMeanPriceX96 is multiplied or divided to get probe prices

uint256 constant PROBE_SQRT_SCALER_MIN = 1.026248453011e12;

PROBE_SQRT_SCALER_MAX

The maximum scaling factor by which sqrtMeanPriceX96 is multiplied or divided to get probe prices

uint256 constant PROBE_SQRT_SCALER_MAX = 3.078745359035e12;

LTV_NUMERATOR

Equivalent to \( \frac{10^{36}}{1 + \frac{1}{liquidationIncentive} + \frac{1}{maxLeverage}} \)

uint256 constant LTV_NUMERATOR = uint256(LIQUIDATION_INCENTIVE * MAX_LEVERAGE * 1e36)
    / (LIQUIDATION_INCENTIVE * MAX_LEVERAGE + LIQUIDATION_INCENTIVE + MAX_LEVERAGE);

LTV_MIN

The minimum loan-to-value ratio. Actual ratio is based on implied volatility; this is just a lower bound. Expressed as a 1e12 percentage, e.g. 0.10e12 β†’ 10%. Must be greater than TickMath.MIN_SQRT_RATIO because we reuse a base 1.0001 logarithm in BalanceSheet

uint256 constant LTV_MIN = LTV_NUMERATOR / (PROBE_SQRT_SCALER_MAX * PROBE_SQRT_SCALER_MAX);

LTV_MAX

The maximum loan-to-value ratio. Actual ratio is based on implied volatility; this is just a upper bound. Expressed as a 1e12 percentage, e.g. 0.90e12 β†’ 90%

uint256 constant LTV_MAX = LTV_NUMERATOR / (PROBE_SQRT_SCALER_MIN * PROBE_SQRT_SCALER_MIN);

IV_SCALE

The timescale of implied volatility, applied to measurements and calculations. When BalanceSheet detects that an nSigma event would cause insolvency in this time period, it enables liquidations. So if you squint your eyes and wave your hands enough, this is (in expectation) the time liquidators have to act before the protocol accrues bad debt.

uint32 constant IV_SCALE = 24 hours;

IV_COLD_START

The initial value of implied volatility, used when VolatilityOracle.prepare is called for a new pool. Expressed as a 1e12 percentage at IV_SCALE, e.g. {0.12e12, 24 hours} β†’ 12% daily β†’ 229% annual. Error on the side of making this too large (resulting in low LTV).

uint104 constant IV_COLD_START = 0.127921282726e12;

IV_CHANGE_PER_SECOND

The maximum rate at which (reported) implied volatility can change. Raw samples in VolatilityOracle.update are clamped (before being stored) so as not to exceed this rate. Expressed in 1e12 percentage points at IV_SCALE per second, e.g. {115740, 24 hours} means daily IV can change by 0.0000116 percentage points per second β†’ 1 percentage point per day.

uint256 constant IV_CHANGE_PER_SECOND = 115740;

IV_CHANGE_PER_UPDATE

The maximum amount by which (reported) implied volatility can change with a single VolatilityOracle.update call. If updates happen as frequently as possible (every FEE_GROWTH_SAMPLE_PERIOD), this cap is no different from IV_CHANGE_PER_SECOND alone.

uint104 constant IV_CHANGE_PER_UPDATE = uint104(IV_CHANGE_PER_SECOND * FEE_GROWTH_SAMPLE_PERIOD);

IV_EMA_GAIN_POS

The gain on the EMA update when IV is increasing. Expressed as reciprocal, e.g. 20 β†’ 0.05

int256 constant IV_EMA_GAIN_POS = 20;

IV_EMA_GAIN_NEG

The gain on the EMA update when IV is decreasing. Expressed as reciprocal, e.g. 100 β†’ 0.01

int256 constant IV_EMA_GAIN_NEG = 100;

FEE_GROWTH_AVG_WINDOW

To estimate volume, we need 2 samples. One is always at the current block, the other is from FEE_GROWTH_AVG_WINDOW seconds ago, +/- FEE_GROWTH_SAMPLE_PERIOD / 2. Larger values make the resulting volume estimate more robust, but may cause the oracle to miss brief spikes in activity.

uint256 constant FEE_GROWTH_AVG_WINDOW = 72 hours;

FEE_GROWTH_ARRAY_LENGTH

The length of the circular buffer that stores feeGrowthGlobals samples. Must be in interval \( \left[ \frac{\text{FEE_GROWTH_AVG_WINDOW}}{\text{FEE_GROWTH_SAMPLE_PERIOD}}, 256 \right) \)

uint256 constant FEE_GROWTH_ARRAY_LENGTH = 32;

FEE_GROWTH_SAMPLE_PERIOD

The minimum number of seconds that must elapse before a new feeGrowthGlobals sample will be stored. This controls how often the oracle can update IV.

uint256 constant FEE_GROWTH_SAMPLE_PERIOD = 4 hours;

UNISWAP_AVG_WINDOW

To compute Uniswap mean price & liquidity, we need 2 samples. One is always at the current block, the other is from UNISWAP_AVG_WINDOW seconds ago. Larger values make the resulting price/liquidity values harder to manipulate, but also make the oracle slower to respond to changes.

uint32 constant UNISWAP_AVG_WINDOW = 30 minutes;

Constants

Git Source

Q8

uint256 constant Q8 = 1 << 8;

Q16

uint256 constant Q16 = 1 << 16;

Q24

uint256 constant Q24 = 1 << 24;

Q32

uint256 constant Q32 = 1 << 32;

Q40

uint256 constant Q40 = 1 << 40;

Q48

uint256 constant Q48 = 1 << 48;

Q56

uint256 constant Q56 = 1 << 56;

Q64

uint256 constant Q64 = 1 << 64;

Q72

uint256 constant Q72 = 1 << 72;

Q80

uint256 constant Q80 = 1 << 80;

Q88

uint256 constant Q88 = 1 << 88;

Q96

uint256 constant Q96 = 1 << 96;

Q104

uint256 constant Q104 = 1 << 104;

Q112

uint256 constant Q112 = 1 << 112;

Q120

uint256 constant Q120 = 1 << 120;

Q128

uint256 constant Q128 = 1 << 128;

BalanceSheet

Git Source

Author: Aloe Labs, Inc.

Provides functions for computing a Borrower's health

State Variables

_Q

uint256 private constant _Q = 22.8811827075e18;

_R

uint256 private constant _R = 103567.889099532e12;

_S

uint256 private constant _S = 0.95e12;

_M

uint256 private constant _M = 20.405429e6;

_N

uint256 private constant _N = 7 days - LIQUIDATION_GRACE_PERIOD;

Functions

auctionTime

function auctionTime(uint256 warnTime) internal view returns (uint256);

auctionCurve

function auctionCurve(uint256 t) internal pure returns (uint256);

computeAuctionAmounts

function computeAuctionAmounts(
    uint160 sqrtPriceX96,
    uint256 assets0,
    uint256 assets1,
    uint256 liabilities0,
    uint256 liabilities1,
    uint256 t,
    uint256 closeFactor
) internal pure returns (AuctionAmounts memory amounts);

isHealthy

Checks whether a Borrower is healthy given the probe prices and its current assets and liabilities. Should be used when assets at prices.a differ from those at prices.b (due to Uniswap positions).

function isHealthy(
    Prices memory prices,
    Assets memory assets,
    uint256 liabilities0,
    uint256 liabilities1
) internal pure returns (bool);

isHealthy

Checks whether a Borrower is healthy given the probe prices and its current assets and liabilities. Can be used when assets at prices.a are the same as those at prices.b (no Uniswap positions).

function isHealthy(
    Prices memory prices,
    uint256 assets0,
    uint256 assets1,
    uint256 liabilities0,
    uint256 liabilities1
) internal pure returns (bool);

isSolvent

function isSolvent(
    uint160 sqrtPriceX96,
    uint256 assets0,
    uint256 assets1,
    uint256 liabilities0,
    uint256 liabilities1
) internal pure returns (bool);

computeProbePrices

Given data from the ORACLE (first 3 args) and parameters from the FACTORY (last 2 args), computes the probe prices at which to check the account's health

function computeProbePrices(
    uint56 metric,
    uint256 sqrtMeanPriceX96,
    uint256 iv,
    uint8 nSigma,
    uint8 manipulationThresholdDivisor
) internal pure returns (uint160 a, uint160 b, bool seemsLegit);

Parameters

NameTypeDescription
metricuint56The manipulation metric (from oracle)
sqrtMeanPriceX96uint256The current TWAP, expressed as a sqrtPriceX96 (from oracle)
ivuint256The estimated implied volatility, expressed as a 1e12 percentage (from oracle)
nSigmauint8The number of standard deviations of price movement to account for (from factory)
manipulationThresholdDivisoruint8Helps compute the manipulation threshold (from factory). See Constants.sol

Returns

NameTypeDescription
auint160\( \text{TWAP} \cdot e^{-n \cdot \sigma} \) expressed as a sqrtPriceX96
buint160\( \text{TWAP} \cdot e^{+n \cdot \sigma} \) expressed as a sqrtPriceX96
seemsLegitboolWhether the Uniswap TWAP has been manipulated enough to create bad debt at the effective LTV

_manipulationThreshold

Equivalent to \( \frac{log_{1.0001} \left( \frac{10^{12}}{ltv} \right)}{\text{MANIPULATION_THRESHOLD_DIVISOR}} \)

function _manipulationThreshold(uint160 ltv, uint8 manipulationThresholdDivisor) private pure returns (uint24);

_ltv

The effective LTV implied by sqrtScaler. This LTV is accurate for fixed assets and out-of-range Uniswap positions, but not for in-range Uniswap positions (impermanent losses make their effective LTV slightly smaller).

function _ltv(uint256 sqrtScaler) private pure returns (uint160 ltv);

LiquidityAmounts

Git Source

Authors: Aloe Labs, Inc., Modified from Uniswap

Provides functions for computing liquidity amounts from token amounts and prices

Functions

getAmountsForLiquidity

Computes the token0 and token1 value for a given amount of liquidity, the current pool prices and the prices at the tick boundaries

function getAmountsForLiquidity(
    uint160 sqrtRatioX96,
    uint160 sqrtRatioAX96,
    uint160 sqrtRatioBX96,
    uint128 liquidity
) internal pure returns (uint256 amount0, uint256 amount1);

Parameters

NameTypeDescription
sqrtRatioX96uint160A sqrt price representing the current pool prices
sqrtRatioAX96uint160A sqrt price representing the first tick boundary
sqrtRatioBX96uint160A sqrt price representing the second tick boundary
liquidityuint128The liquidity being valued

Returns

NameTypeDescription
amount0uint256The amount of token0
amount1uint256The amount of token1

getValuesOfLiquidity

Computes the value of each portion of the liquidity in terms of token1

Each return value can fit in a uint192 if necessary

function getValuesOfLiquidity(
    uint160 sqrtRatioX96,
    uint160 sqrtRatioAX96,
    uint160 sqrtRatioBX96,
    uint128 liquidity
) internal pure returns (uint256 value0, uint256 value1);

Parameters

NameTypeDescription
sqrtRatioX96uint160A sqrt price representing the current pool prices
sqrtRatioAX96uint160A sqrt price representing the lower tick boundary
sqrtRatioBX96uint160A sqrt price representing the upper tick boundary
liquidityuint128The liquidity being valued

Returns

NameTypeDescription
value0uint256The value of amount0 underlying liquidity, in terms of token1
value1uint256The amount of token1

getValueOfLiquidity

Computes the value of the liquidity in terms of token1

The return value can fit in a uint192 if necessary

function getValueOfLiquidity(
    uint160 sqrtRatioX96,
    uint160 sqrtRatioAX96,
    uint160 sqrtRatioBX96,
    uint128 liquidity
) internal pure returns (uint256);

Parameters

NameTypeDescription
sqrtRatioX96uint160A sqrt price representing the current pool prices
sqrtRatioAX96uint160A sqrt price representing the lower tick boundary
sqrtRatioBX96uint160A sqrt price representing the upper tick boundary
liquidityuint128The liquidity being valued

Returns

NameTypeDescription
<none>uint256The value of the underlying liquidity, in terms of token1

_getAmount0ForLiquidity

Computes the amount of token0 for a given amount of liquidity and a price range

function _getAmount0ForLiquidity(
    uint160 sqrtRatioAX96,
    uint160 sqrtRatioBX96,
    uint128 liquidity
) private pure returns (uint256 amount0);

Parameters

NameTypeDescription
sqrtRatioAX96uint160A sqrt price representing the first tick boundary
sqrtRatioBX96uint160A sqrt price representing the second tick boundary
liquidityuint128The liquidity being valued

Returns

NameTypeDescription
amount0uint256The amount of token0. Will fit in a uint224 if you need it to

_getAmount1ForLiquidity

Computes the amount of token1 for a given amount of liquidity and a price range

function _getAmount1ForLiquidity(
    uint160 sqrtRatioAX96,
    uint160 sqrtRatioBX96,
    uint128 liquidity
) private pure returns (uint256 amount1);

Parameters

NameTypeDescription
sqrtRatioAX96uint160A sqrt price representing the first tick boundary
sqrtRatioBX96uint160A sqrt price representing the second tick boundary
liquidityuint128The liquidity being valued

Returns

NameTypeDescription
amount1uint256The amount of token1. Will fit in a uint192 if you need it to

square

Git Source

Equivalent to fullMulDiv(x, x, 1 << 64)

function square(uint160 x) pure returns (uint256 result);

mulDiv96

Git Source

Equivalent to fullMulDiv(x, y, 1 << 96). NOTE: Does not check for overflow, so choose x and y carefully.

function mulDiv96(uint256 x, uint256 y) pure returns (uint256 result);

mulDiv128

Git Source

Equivalent to fullMulDiv(x, x, 1 << 128)

function mulDiv128(uint256 x, uint256 y) pure returns (uint256 result);

mulDiv128Up

Git Source

Equivalent to fullMulDivUp(x, x, 1 << 128)

function mulDiv128Up(uint256 x, uint256 y) pure returns (uint256 result);

mulDiv224

Git Source

Equivalent to fullMulDiv(x, y, 1 << 224). NOTE: Does not check for overflow, so choose x and y carefully.

function mulDiv224(uint256 x, uint256 y) pure returns (uint256 result);

Oracle

Git Source

Authors: Aloe Labs, Inc., Modified from Uniswap

Provides functions to integrate with V3 pool oracle

Functions

consult

Calculates time-weighted means of tick and liquidity for a given Uniswap V3 pool

function consult(IUniswapV3Pool pool, uint40 seed) internal view returns (uint56 metric, uint160 sqrtMeanPriceX96);

Parameters

NameTypeDescription
poolIUniswapV3PoolAddress of the pool that we want to observe
seeduint40The indices of pool.observations where we start our search for the 30-minute-old (lowest 16 bits) and 60-minute-old (next 16 bits) observations. Determine these off-chain to make this method more efficient than Uniswap's binary search. If any of the highest 8 bits are set, we fallback to onchain binary search.

Returns

NameTypeDescription
metricuint56If the price was manipulated at any point in the past UNISWAP_AVG_WINDOW seconds, then at some point in that period, this value will spike. It may still be high now, or (if the attacker is smart and well-financed) it may have returned to nominal.
sqrtMeanPriceX96uint160sqrt(TWAP) over the past UNISWAP_AVG_WINDOW seconds

observe

Searches for oracle observations nearest to the target time. If target lies between two existing observations, linearly interpolate between them. If target is newer than the most recent observation, we interpolate between the most recent one and a hypothetical one taken at the current block.

As long as target <= block.timestamp, return values should match what you'd get from Uniswap.

function observe(
    IUniswapV3Pool pool,
    uint32 target,
    uint256 seed,
    int24 tick,
    uint16 observationIndex,
    uint16 observationCardinality
) internal view returns (int56, uint160);

Parameters

NameTypeDescription
poolIUniswapV3PoolThe Uniswap pool to examine
targetuint32The timestamp of the desired observation
seeduint256The index of pool.observations where we start our search. Can be determined off-chain to make this method more efficient than Uniswap's binary search.
tickint24The current tick (from pool.slot0())
observationIndexuint16The current observation index (from pool.slot0())
observationCardinalityuint16The current observation cardinality. Should be determined as follows: solidity (, , uint16 observationIndex, uint16 observationCardinality, , , ) = pool.slot0(); (, , , bool initialized) = pool.observations((observationIndex + 1) % observationCardinality); if (!initialized) observationCardinality = observationIndex + 1; NOTE: If you fail to account for the !initialized case, and target comes before the oldest observation, this may return incorrect data instead of reverting with "OLD".

Returns

NameTypeDescription
<none>int56The tick * time elapsed since pool was first initialized
<none>uint160The time elapsed / max(1, liquidity) since pool was first initialized

getMaxSecondsAgo

Given a pool, returns the number of seconds ago of the oldest stored observation

(, , uint16 observationIndex, uint16 observationCardinality, , , ) = pool.slot0();

function getMaxSecondsAgo(
    IUniswapV3Pool pool,
    uint16 observationIndex,
    uint16 observationCardinality
) internal view returns (uint32 secondsAgo);

Parameters

NameTypeDescription
poolIUniswapV3PoolAddress of Uniswap V3 pool that we want to observe
observationIndexuint16The observation index from pool.slot0()
observationCardinalityuint16The observationCardinality from pool.slot0()

Returns

NameTypeDescription
secondsAgouint32The number of seconds ago that the oldest observation was stored

πŸ—‚οΈ Positions

extract

Git Source

Extracts up to three Uniswap positions from zipped. Each position consists of an int24 lower and int24 upper, and will be included in the output array iff lower != upper. The output array is flattened such that lower and upper ticks are next to each other, e.g. one position may be at indices 0 & 1, and another at indices 2 & 3.

The output array's length will be one of {0, 2, 4, 6}. We do not validate that lower < upper, nor do we check whether positions actually hold liquidity. Also note that this function will revert if zipped contains duplicate positions like [-100, 100, -100, 100].

function extract(uint256 zipped) pure returns (int24[] memory positionsOfNonZeroWidth);

Parameters

NameTypeDescription
zippeduint256Encoded Uniswap positions. Equivalent to the layout of int24[6] storage yourPositions

Returns

NameTypeDescription
positionsOfNonZeroWidthint24[]Flattened array of Uniswap positions that may or may not hold liquidity

zip

Git Source

Compresses positions into zipped. Useful for creating the return value of IManager.callback

function zip(int24[6] memory positions) pure returns (uint144 zipped);

Parameters

NameTypeDescription
positionsint24[6]A flattened array of ticks, each consecutive pair of indices representing one Uniswap position

Rewards

Git Source

Authors: Aloe Labs, Inc., Inspired by Yield Protocol

Implements logic for staking rewards

State Variables

_REWARDS_SLOT

bytes32 private constant _REWARDS_SLOT = keccak256("aloe.ii.rewards");

Functions

setRate

Sets the pool's rewards rate. May be 0.

function setRate(Storage storage store, uint160 accumulated, uint64 rate) internal;

Parameters

NameTypeDescription
storeStorageThe rewards storage pointer
accumulateduint160Up-to-date poolState.accumulated, i.e. the output of _accumulate
rateuint64The rewards rate, specified as [token units per second]. Keep between 10^17 and 10^28 token units per year for smooth operation -- between 0.1 and 10 billion tokens, assuming 18 decimals.

claim

function claim(
    Storage storage store,
    uint160 accumulated,
    address user,
    uint256 balance
) internal returns (uint96 earned);

updatePoolState

Ensures that changes in the pool's totalSupply don't mess up rewards accounting. Should be called anytime totalSupply changes.

Use Rewards.load() to easily obtain the first two arguments

function updatePoolState(Storage storage store, uint160 accumulated) internal;

Parameters

NameTypeDescription
storeStorageThe rewards storage pointer
accumulateduint160Up-to-date poolState.accumulated, i.e. the output of _accumulate

updateUserState

Tracks how much reward a user earned while holding a particular balance. Should be called anytime their balance changes.

Use Rewards.load() to easily obtain the first two arguments

function updateUserState(Storage storage store, uint160 accumulated, address user, uint256 balance) internal;

Parameters

NameTypeDescription
storeStorageThe rewards storage pointer
accumulateduint160Up-to-date poolState.accumulated, i.e. the output of _accumulate
useraddressThe user whose balance (# of shares) is about to change
balanceuint256The user's balance (# of shares) -- before it changes

previewUserState

function previewUserState(
    Storage storage store,
    uint160 accumulated,
    address user,
    uint256 balance
) internal view returns (UserState memory userState);

getRate

function getRate() internal view returns (uint64);

load

Returns arguments to be used in updatePoolState and updateUserState. No good semantic meaning here, just a coincidence that both functions need this information.

function load(uint256 totalSupply) internal view returns (Storage storage store, uint160 accumulator);

_accumulate

Accumulates rewards based on the current rate and time elapsed since last update

function _accumulate(PoolState memory poolState, uint256 totalSupply) private view returns (uint160);

_storage

Diamond-pattern-style storage getter

function _storage() private pure returns (Storage storage store);

Events

RewardsRateSet

event RewardsRateSet(uint64 rate);

RewardsClaimed

event RewardsClaimed(address indexed user, uint96 amount);

Structs

PoolState

struct PoolState {
    uint160 accumulated;
    uint32 lastUpdated;
    uint64 rate;
}

UserState

struct UserState {
    uint96 earned;
    uint160 checkpoint;
}

Storage

struct Storage {
    PoolState poolState;
    mapping(address => UserState) userStates;
}

TickMath

Git Source

Authors: Aloe Labs, Inc., Modified from Uniswap and Aperture Finance

Computes sqrt price for ticks of size 1.0001, i.e. \(\sqrt{1.0001^{tick}}\) as fixed point Q64.96 numbers. Supports prices between \(2^{-128}\) and \(2^{128}\)

State Variables

MIN_TICK

The minimum tick that may be passed to getSqrtRatioAtTick computed from \( log_{1.0001}2^{-128} \)

int24 internal constant MIN_TICK = -887272;

MAX_TICK

The maximum tick that may be passed to getSqrtRatioAtTick computed from \( log_{1.0001}2^{128} \)

int24 internal constant MAX_TICK = 887272;

MIN_SQRT_RATIO

The minimum value that can be returned from getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)

uint160 internal constant MIN_SQRT_RATIO = 4295128739;

MAX_SQRT_RATIO

The maximum value that can be returned from getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)

uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;

MAX_SQRT_RATIO_MINUS_MIN_SQRT_RATIO_MINUS_ONE

A threshold used for optimized bounds check, equals MAX_SQRT_RATIO - MIN_SQRT_RATIO - 1

uint160 private constant MAX_SQRT_RATIO_MINUS_MIN_SQRT_RATIO_MINUS_ONE =
    1461446703485210103287273052203988822378723970342 - 4295128739 - 1;

Functions

getSqrtRatioAtTick

Calculates \( \sqrt{1.0001^{tick}} * 2^{96} \)

Throws if |tick| > max tick

function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96);

Parameters

NameTypeDescription
tickint24The input tick for the above formula

Returns

NameTypeDescription
sqrtPriceX96uint160A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0) at the given tick

getTickAtSqrtRatio

Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio

Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may ever return.

function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick);

Parameters

NameTypeDescription
sqrtPriceX96uint160The sqrt ratio for which to compute the tick as a Q64.96

Returns

NameTypeDescription
tickint24The greatest tick for which the ratio is less than or equal to the input ratio

floor

Rounds down to the nearest tick where tick % tickSpacing == 0

Ensure tick +/- tickSpacing does not overflow or underflow int24

function floor(int24 tick, int24 tickSpacing) internal pure returns (int24);

Parameters

NameTypeDescription
tickint24The tick to round
tickSpacingint24The tick spacing to round to

Returns

NameTypeDescription
<none>int24the floored tick

ceil

Rounds up to the nearest tick where tick % tickSpacing == 0

Ensure tick +/- tickSpacing does not overflow or underflow int24

function ceil(int24 tick, int24 tickSpacing) internal pure returns (int24);

Parameters

NameTypeDescription
tickint24The tick to round
tickSpacingint24The tick spacing to round to

Returns

NameTypeDescription
<none>int24the ceiled tick

Volatility

Git Source

Author: Aloe Labs, Inc.

Provides functions that use Uniswap v3 to compute price volatility

State Variables

_Q224Div1e18

uint256 private constant _Q224Div1e18 = (uint256(1 << 224) * 1e6) / 1e24;

_Q128Div1e18

uint256 private constant _Q128Div1e18 = (uint256(1 << 128) * 1e6) / 1e24;

Functions

estimate

Estimates implied volatility using this math.

The return value can fit in uint128 if necessary

function estimate(
    PoolMetadata memory metadata,
    uint160 sqrtMeanPriceX96,
    FeeGrowthGlobals memory a,
    FeeGrowthGlobals memory b,
    uint32 scale
) internal pure returns (uint256);

Parameters

NameTypeDescription
metadataPoolMetadataThe pool's metadata (may be cached)
sqrtMeanPriceX96uint160sqrt(TWAP) over some period. Likely from Oracle.consult
aFeeGrowthGlobalsThe pool's cumulative feeGrowthGlobals some time in the past
bFeeGrowthGlobalsThe pool's cumulative feeGrowthGlobals as of the current block
scaleuint32The timescale (in seconds) in which IV should be reported, e.g. hourly, daily, annualized

Returns

NameTypeDescription
<none>uint256An estimate of the implied volatility scaled by 1e12

Structs

PoolMetadata

struct PoolMetadata {
    uint24 gamma0;
    uint24 gamma1;
    int24 tickSpacing;
}

FeeGrowthGlobals

struct FeeGrowthGlobals {
    uint256 feeGrowthGlobal0X128;
    uint256 feeGrowthGlobal1X128;
    uint32 timestamp;
}

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
}

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
}

ILiquidator

Git Source

Functions

receive

receive() external payable;

callback

Transfers amounts.out0 and amounts.out1 to the liquidator with the expectation that they'll transfer amounts.repay0 and amounts.repay1 to the appropriate Lenders, executing swaps if necessary. The liquidator can keep leftover funds as a reward.

function callback(bytes calldata data, address caller, AuctionAmounts memory amounts) external;

Parameters

NameTypeDescription
databytesEncoded parameters that were passed to Borrower.liquidate
calleraddressThe address that called Borrower.liquidate
amountsAuctionAmountsThe key amounts involved in the liquidation

IManager

Git Source

Functions

callback

Gives the IManager full control of the Borrower. Called within Borrower.modify.

In most cases, you'll want to verify that msg.sender is, in fact, a Borrower using factory.isBorrower(msg.sender).

function callback(bytes calldata data, address owner, uint208 positions) external returns (uint208);

Parameters

NameTypeDescription
databytesEncoded parameters that were passed to Borrower.modify
owneraddressThe owner of the Borrower
positionsuint208The Borrower's current Uniswap positions. You can convert them to an array using Positions.extract

Returns

NameTypeDescription
<none>uint208Updated positions, encoded using Positions.zip. Return 0 if you don't wish to make any changes.

Factory

Git Source

Author: Aloe Labs, Inc.

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

State Variables

GOVERNOR

The only address that can propose new MarketConfigs and rewards programs

address public immutable GOVERNOR;

ORACLE

The oracle to use for prices and implied volatility

VolatilityOracle public immutable ORACLE;

LENDER_IMPLEMENTATION

The implementation to which all Lender clones will point

address public immutable LENDER_IMPLEMENTATION;

_BORROWER_DEPLOYER

A simple contract that deploys Borrowers to keep Factory bytecode size down

BorrowerDeployer private immutable _BORROWER_DEPLOYER;

DEFAULT_RATE_MODEL

The rate model that Lenders will use when first created

IRateModel public immutable DEFAULT_RATE_MODEL;

getMarket

Returns the Market addresses associated with a Uniswap V3 pool

mapping(IUniswapV3Pool => Market) public getMarket;

getParameters

Returns the borrowing Parameters associated with a Uniswap V3 pool

mapping(IUniswapV3Pool => Parameters) public getParameters;

peer

Returns the other Lender in the Market iff input is itself a Lender, otherwise 0

mapping(address => address) public peer;

isBorrower

Returns whether the given address is a Borrower deployed by this Factory

mapping(address => bool) public isBorrower;

rewardsToken

The token in which rewards are paid out

ERC20 public rewardsToken;

couriers

Returns the Courier for any given ID

mapping(uint32 => Courier) public couriers;

Functions

constructor

constructor(
    address governor,
    address reserve,
    VolatilityOracle oracle,
    BorrowerDeployer borrowerDeployer,
    IRateModel defaultRateModel
);

pause

function pause(IUniswapV3Pool pool, uint40 oracleSeed) external;

createMarket

function createMarket(IUniswapV3Pool pool) external;

createBorrower

function createBorrower(IUniswapV3Pool pool, address owner, bytes12 salt) external returns (Borrower borrower);

claimRewards

function claimRewards(Lender[] calldata lenders, address beneficiary) external returns (uint256 earned);

enrollCourier

Enrolls msg.sender in the referral program. This allows frontends/wallets/apps to credit themselves for a given user's deposit, and receive a portion of their interest. Note that after enrolling, msg.sender will not be eligible for REWARDS_TOKEN rewards.

See Lender.creditCourier

function enrollCourier(uint32 id, uint16 cut) external;

Parameters

NameTypeDescription
iduint32A unique identifier for the courier
cutuint16The portion of interest the courier will receive. Should be in the range [0, 10000), with 10000 being 100%.

governRewardsToken

function governRewardsToken(ERC20 rewardsToken_) external;

governRewardsRate

function governRewardsRate(Lender lender, uint64 rate) external;

governMarketConfig

function governMarketConfig(IUniswapV3Pool pool, MarketConfig memory config) external;

_setMarketConfig

function _setMarketConfig(IUniswapV3Pool pool, MarketConfig memory config, uint32 pausedUntilTime) private;

_newBorrower

function _newBorrower(IUniswapV3Pool pool, Lender lender0, Lender lender1) private returns (Borrower);

Events

CreateMarket

event CreateMarket(IUniswapV3Pool indexed pool, Lender lender0, Lender lender1);

CreateBorrower

event CreateBorrower(IUniswapV3Pool indexed pool, address indexed owner, Borrower account);

EnrollCourier

event EnrollCourier(uint32 indexed id, address indexed wallet, uint16 cut);

SetMarketConfig

event SetMarketConfig(IUniswapV3Pool indexed pool, MarketConfig config);

Structs

Market

struct Market {
    Lender lender0;
    Lender lender1;
    Borrower borrowerImplementation;
}

Parameters

struct Parameters {
    uint208 ante;
    uint8 nSigma;
    uint8 manipulationThresholdDivisor;
    uint32 pausedUntilTime;
}

MarketConfig

struct MarketConfig {
    uint208 ante;
    uint8 nSigma;
    uint8 manipulationThresholdDivisor;
    uint8 reserveFactor0;
    uint8 reserveFactor1;
    IRateModel rateModel0;
    IRateModel rateModel1;
}

Courier

struct Courier {
    address wallet;
    uint16 cut;
}

Lender

Git Source

Inherits: Ledger

Author: Aloe Labs, Inc.

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

Functions

constructor

constructor(address reserve) Ledger(reserve);

initialize

function initialize() external;

setRateModelAndReserveFactor

Sets the rateModel and reserveFactor. Only the FACTORY can call this.

function setRateModelAndReserveFactor(IRateModel rateModel_, uint8 reserveFactor_) external;

setRewardsRate

Sets the rewards rate. May be 0. Only the FACTORY can call this.

function setRewardsRate(uint64 rate) external;

Parameters

NameTypeDescription
rateuint64The rewards rate, specified in [token units per second]. If non-zero, keep between 10^17 and 10^28 token units per year for smooth operation. Assuming FACTORY.rewardsToken() has 18 decimals, this is between 0.1 and 10 billion tokens per year.

whitelist

Allows borrower to call borrow. One the FACTORY can call this.

function whitelist(address borrower) external;

claimRewards

function claimRewards(address owner) external returns (uint96 earned);

deposit

Mints shares to beneficiary by depositing exactly amount of underlying tokens

deposit is more efficient than mint and is the recommended way of depositing. Also supports the additional flow where you prepay amount instead of relying on approve/transferFrom.

function deposit(uint256 amount, address beneficiary, uint32 courierId) public returns (uint256 shares);

Parameters

NameTypeDescription
amountuint256The amount of underlying tokens to deposit
beneficiaryaddressThe receiver of shares
courierIduint32The ID of the courier (or 0, to indicate lack thereof) that will receive a cut of beneficiary's future interest. Only takes effect when balanceOf(beneficiary) == 0. In all other cases, pass 0 to avoid wasting gas on courier-related checks.

Returns

NameTypeDescription
sharesuint256The number of shares (banknotes) minted to beneficiary

deposit

function deposit(uint256 amount, address beneficiary) external returns (uint256 shares);

mint

function mint(uint256 shares, address beneficiary) external returns (uint256 amount);

redeem

Burns shares from owner and sends amount of underlying tokens to receiver. If owner has a courier, additional shares will be transferred from owner to the courier as a fee.

redeem is more efficient than withdraw and is the recommended way of withdrawing

function redeem(uint256 shares, address recipient, address owner) public returns (uint256 amount);

Parameters

NameTypeDescription
sharesuint256The number of shares to burn in exchange for underlying tokens. To burn all your shares, you can pass maxRedeem(owner). If maxRedeem(owner) is changing over time (due to a courier or high utilization) you can pass type(uint256).max and it will be computed in-place.
recipientaddressThe receiver of amount of underlying tokens
owneraddressThe user from whom shares are taken (for both the burn and possible fee transfer)

Returns

NameTypeDescription
amountuint256The number of underlying tokens transferred to recipient

withdraw

function withdraw(uint256 amount, address recipient, address owner) external returns (uint256 shares);

borrow

Sends amount of asset to recipient and increases msg.sender's debt by units

function borrow(uint256 amount, address recipient) external returns (uint256 units);

repay

Reduces beneficiary's debt by units, assuming someone has pre-paid amount of asset. To repay all debt for some account, call repay(borrowBalance(account), account).

To avoid frontrunning, amount should be pre-paid in the same transaction as the repay call.

function repay(uint256 amount, address beneficiary) external returns (uint256 units);

accrueInterest

function accrueInterest() public returns (uint72);

approve

function approve(address spender, uint256 shares) external returns (bool);

transfer

function transfer(address to, uint256 shares) external returns (bool);

transferFrom

function transferFrom(address from, address to, uint256 shares) external returns (bool);

permit

function permit(
    address owner,
    address spender,
    uint256 value,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external;

_transfer

Transfers shares from from to to, iff neither of them have a courier

function _transfer(address from, address to, uint256 shares) private;

_mint

Make sure to do something with the return value, newTotalSupply!

function _mint(
    address to,
    uint256 shares,
    uint256 amount,
    uint256 totalSupply_,
    uint32 courierId
) private returns (uint256 newTotalSupply);

_burn

Make sure to do something with the return value, newTotalSupply!

function _burn(
    address from,
    uint256 shares,
    uint256 inventory,
    uint256 totalSupply_
) private returns (uint256 newTotalSupply);

_load

function _load() private returns (Cache memory cache, uint256 inventory);

_save

function _save(Cache memory cache, bool didChangeBorrowBase) private;

Events

Approval

event Approval(address indexed owner, address indexed spender, uint256 amount);

Transfer

event Transfer(address indexed from, address indexed to, uint256 amount);

Deposit

event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);

Withdraw

event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares);

Borrow

event Borrow(address indexed caller, address indexed recipient, uint256 amount, uint256 units);

Repay

event Repay(address indexed caller, address indexed beneficiary, uint256 amount, uint256 units);

CreditCourier

event CreditCourier(uint32 indexed id, address indexed account);

Lender

Git Source

Inherits: Ledger

Author: Aloe Labs, Inc.

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

Functions

constructor

constructor(address reserve) Ledger(reserve);

initialize

function initialize() external;

setRateModelAndReserveFactor

Sets the rateModel and reserveFactor. Only the FACTORY can call this.

function setRateModelAndReserveFactor(IRateModel rateModel_, uint8 reserveFactor_) external;

setRewardsRate

Sets the rewards rate. May be 0. Only the FACTORY can call this.

function setRewardsRate(uint64 rate) external;

Parameters

NameTypeDescription
rateuint64The rewards rate, specified in [token units per second]. If non-zero, keep between 10^17 and 10^28 token units per year for smooth operation. Assuming FACTORY.rewardsToken() has 18 decimals, this is between 0.1 and 10 billion tokens per year.

whitelist

Allows borrower to call borrow. One the FACTORY can call this.

function whitelist(address borrower) external;

claimRewards

function claimRewards(address owner) external returns (uint96 earned);

deposit

Mints shares to beneficiary by depositing exactly amount of underlying tokens

deposit is more efficient than mint and is the recommended way of depositing. Also supports the additional flow where you prepay amount instead of relying on approve/transferFrom.

function deposit(uint256 amount, address beneficiary, uint32 courierId) public returns (uint256 shares);

Parameters

NameTypeDescription
amountuint256The amount of underlying tokens to deposit
beneficiaryaddressThe receiver of shares
courierIduint32The ID of the courier (or 0, to indicate lack thereof) that will receive a cut of beneficiary's future interest. Only takes effect when balanceOf(beneficiary) == 0. In all other cases, pass 0 to avoid wasting gas on courier-related checks.

Returns

NameTypeDescription
sharesuint256The number of shares (banknotes) minted to beneficiary

deposit

function deposit(uint256 amount, address beneficiary) external returns (uint256 shares);

mint

function mint(uint256 shares, address beneficiary) external returns (uint256 amount);

redeem

Burns shares from owner and sends amount of underlying tokens to receiver. If owner has a courier, additional shares will be transferred from owner to the courier as a fee.

redeem is more efficient than withdraw and is the recommended way of withdrawing

function redeem(uint256 shares, address recipient, address owner) public returns (uint256 amount);

Parameters

NameTypeDescription
sharesuint256The number of shares to burn in exchange for underlying tokens. To burn all your shares, you can pass maxRedeem(owner). If maxRedeem(owner) is changing over time (due to a courier or high utilization) you can pass type(uint256).max and it will be computed in-place.
recipientaddressThe receiver of amount of underlying tokens
owneraddressThe user from whom shares are taken (for both the burn and possible fee transfer)

Returns

NameTypeDescription
amountuint256The number of underlying tokens transferred to recipient

withdraw

function withdraw(uint256 amount, address recipient, address owner) external returns (uint256 shares);

borrow

Sends amount of asset to recipient and increases msg.sender's debt by units

function borrow(uint256 amount, address recipient) external returns (uint256 units);

repay

Reduces beneficiary's debt by units, assuming someone has pre-paid amount of asset. To repay all debt for some account, call repay(borrowBalance(account), account).

To avoid frontrunning, amount should be pre-paid in the same transaction as the repay call.

function repay(uint256 amount, address beneficiary) external returns (uint256 units);

accrueInterest

function accrueInterest() public returns (uint72);

approve

function approve(address spender, uint256 shares) external returns (bool);

transfer

function transfer(address to, uint256 shares) external returns (bool);

transferFrom

function transferFrom(address from, address to, uint256 shares) external returns (bool);

permit

function permit(
    address owner,
    address spender,
    uint256 value,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external;

_transfer

Transfers shares from from to to, iff neither of them have a courier

function _transfer(address from, address to, uint256 shares) private;

_mint

Make sure to do something with the return value, newTotalSupply!

function _mint(
    address to,
    uint256 shares,
    uint256 amount,
    uint256 totalSupply_,
    uint32 courierId
) private returns (uint256 newTotalSupply);

_burn

Make sure to do something with the return value, newTotalSupply!

function _burn(
    address from,
    uint256 shares,
    uint256 inventory,
    uint256 totalSupply_
) private returns (uint256 newTotalSupply);

_load

function _load() private returns (Cache memory cache, uint256 inventory);

_save

function _save(Cache memory cache, bool didChangeBorrowBase) private;

Events

Approval

event Approval(address indexed owner, address indexed spender, uint256 amount);

Transfer

event Transfer(address indexed from, address indexed to, uint256 amount);

Deposit

event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);

Withdraw

event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares);

Borrow

event Borrow(address indexed caller, address indexed recipient, uint256 amount, uint256 units);

Repay

event Repay(address indexed caller, address indexed beneficiary, uint256 amount, uint256 units);

CreditCourier

event CreditCourier(uint32 indexed id, address indexed account);

Ledger

Git Source

State Variables

FACTORY

Factory public immutable FACTORY;

RESERVE

address public immutable RESERVE;

totalSupply

Doesn't include reserve inflation. If you want that, use stats()

uint112 public totalSupply;

lastBalance

Used in lieu of asset.balanceOf to prevent inflation attacks

uint112 public lastBalance;

lastAccrualTime

The last block.timestamp at which interest accrued

uint32 public lastAccrualTime;

borrowBase

The principle of all outstanding loans as if they were taken out at borrowIndex = ONE

uint184 public borrowBase;

borrowIndex

Tracks all-time growth of borrow interest. Starts at ONE and increases monotonically over time

uint72 public borrowIndex;

borrows

The principle of a given user's loan as if it was taken out at borrowIndex = ONE

mapping(address => uint256) public borrows;

balances

Highest 32 bits are the referral code, next 112 are the principle, lowest 112 are the shares.

mapping(address => uint256) public balances;

allowance

mapping(address => mapping(address => uint256)) public allowance;

nonces

mapping(address => uint256) public nonces;

rateModel

rateModel.getYieldPerSecond is given 100000 gas, and the output is clamped to MAX_RATE. If the call reverts, it's treated the same as if it returned 0.

IRateModel public rateModel;

reserveFactor

The portion of interest that accrues to the RESERVE. Expressed as a reciprocal, e.g. 16 β†’ 6.25%

uint8 public reserveFactor;

Functions

constructor

constructor(address reserve);

supportsInterface

Returns true if this contract implements the interface defined by interfaceId

function supportsInterface(bytes4 interfaceId) external pure returns (bool);

name

The name of the banknote.

function name() external view returns (string memory);

symbol

The symbol of the banknote.

function symbol() external view returns (string memory);

decimals

The number of decimals the banknote uses. Matches the underlying token.

function decimals() external view returns (uint8);

asset

The address of the underlying token.

function asset() public pure returns (ERC20);

peer

The address of the other Lender in the market

function peer() public view returns (address);

DOMAIN_SEPARATOR

The domain separator for EIP-2612

function DOMAIN_SEPARATOR() public view returns (bytes32);

stats

Gets basic lending statistics as if accrueInterest were just called.

function stats() external view returns (uint72, uint256, uint256, uint256);

Returns

NameTypeDescription
<none>uint72The updated borrowIndex
<none>uint256The sum of all banknote balances, in underlying units (i.e. totalAssets)
<none>uint256The sum of all outstanding debts, in underlying units
<none>uint256The sum of all banknote balances. Will differ from totalSupply due to reserves inflation

rewardsRate

The rewards rate, specified as [token units per second]

function rewardsRate() external view returns (uint64 rate);

rewardsOf

All rewards earned by account that have not yet been paid out

function rewardsOf(address account) external view returns (uint96);

courierOf

The ID of the referrer associated with account's deposit. If 0, they have no courier.

function courierOf(address account) external view returns (uint32);

principleOf

The lending principle of account. Only tracked if they have a courier.

function principleOf(address account) external view returns (uint256);

balanceOf

The number of shares held by account

function balanceOf(address account) public view returns (uint256);

underlyingBalance

The amount of asset owed to account after accruing the latest interest, i.e. the value that maxWithdraw would return if outstanding borrows weren't a constraint. Fees owed to couriers are automatically subtracted from this value in real-time, but couriers themselves won't receive earnings until users redeem or withdraw.

Because of the fees, βˆ‘underlyingBalances != totalAssets

function underlyingBalance(address account) external view returns (uint256);

underlyingBalanceStored

The amount of asset owed to account before accruing the latest interest. See underlyingBalance for details.

An underestimate; more gas efficient than underlyingBalance

function underlyingBalanceStored(address account) external view returns (uint256);

borrowBalance

The amount of asset owed by account after accruing the latest interest. If one calls repay(borrowBalance(account), account), the account will be left with a borrow balance of 0.

function borrowBalance(address account) external view returns (uint256);

borrowBalanceStored

The amount of asset owed by account before accruing the latest interest.

function borrowBalanceStored(address account) external view returns (uint256);

totalAssets

The total amount of asset under management

convertToShares(totalAssets()) != totalSupply() due to reserves inflation. If you need the up-to-date supply, use stats()

function totalAssets() external view returns (uint256);

convertToShares

function convertToShares(uint256 assets) public view returns (uint256);

convertToAssets

function convertToAssets(uint256 shares) public view returns (uint256);

previewDeposit

function previewDeposit(uint256 assets) public view returns (uint256);

previewMint

function previewMint(uint256 shares) public view returns (uint256);

previewRedeem

function previewRedeem(uint256 shares) public view returns (uint256);

previewWithdraw

function previewWithdraw(uint256 assets) public view returns (uint256);

maxDeposit

Returns a conservative estimate of the maximum amount of asset() that can be deposited into the Vault for receiver, through a deposit call.

Should return the precise maximum. In this case that'd be on the order of 2^112 with constraints coming from both lastBalance and totalSupply, which changes during interest accrual. Instead of doing complicated math, we provide a constant conservative estimate of 2^96.

function maxDeposit(address) external pure returns (uint256);

Returns

NameTypeDescription
<none>uint256The maximum amount of asset() that can be deposited

maxMint

Returns a conservative estimate of the maximum number of Vault shares that can be minted for receiver, through a mint call.

Should return the precise maximum. In this case that'd be on the order of 2^112 with constraints coming from both lastBalance and totalSupply, which changes during interest accrual. Instead of doing complicated math, we provide a constant conservative estimate of 2^96.

function maxMint(address) external pure returns (uint256);

Returns

NameTypeDescription
<none>uint256The maximum number of Vault shares that can be minted

maxRedeem

Returns the maximum number of Vault shares that can be redeemed in the Vault by owner, through a redeem call.

function maxRedeem(address owner) public view returns (uint256);

Parameters

NameTypeDescription
owneraddressThe address that would burn Vault shares when redeeming

Returns

NameTypeDescription
<none>uint256The maximum number of Vault shares that can be redeemed

maxWithdraw

Returns the maximum amount of asset() that can be withdrawn from the Vault by owner, through a withdraw call.

function maxWithdraw(address owner) external view returns (uint256);

Parameters

NameTypeDescription
owneraddressThe address that would burn Vault shares when withdrawing

Returns

NameTypeDescription
<none>uint256The maximum amount of asset() that can be withdrawn

_previewInterest

Accrues interest up to the current block.timestamp. Updates and returns cache, but doesn't write anything to storage.

function _previewInterest(Cache memory cache) internal view returns (Cache memory, uint256, uint256);

_convertToShares

function _convertToShares(
    uint256 assets,
    uint256 inventory,
    uint256 totalSupply_,
    bool roundUp
) internal pure returns (uint256);

_convertToAssets

function _convertToAssets(
    uint256 shares,
    uint256 inventory,
    uint256 totalSupply_,
    bool roundUp
) internal pure returns (uint256);

_nominalShares

The account's balance, minus any shares earned by their courier

function _nominalShares(
    address account,
    uint256 inventory,
    uint256 totalSupply_
) private view returns (uint256 balance);

_getCache

function _getCache() internal view returns (Cache memory);

Structs

Cache

struct Cache {
    uint256 totalSupply;
    uint256 lastBalance;
    uint256 lastAccrualTime;
    uint256 borrowBase;
    uint256 borrowIndex;
}

πŸ“ IFlashBorrower

RateModel

Git Source

Inherits: IRateModel

Author: Aloe Labs, Inc.

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

State Variables

_A

uint256 private constant _A = 6.1010463348e20;

_B

uint256 private constant _B = _A / 1e18;

Functions

getYieldPerSecond

Specifies the percentage yield per second for a lender. Need not be a pure function of utilization. To convert to APY: (1 + returnValue / 1e12) ** secondsPerYear - 1

function getYieldPerSecond(uint256 utilization, address) external pure returns (uint256);

Parameters

NameTypeDescription
utilizationuint256The lender's total borrows divided by total assets, scaled up by 1e18
<none>address

Returns

NameTypeDescription
<none>uint256The percentage yield per second, scaled up by 1e12

RateModel

Git Source

Inherits: IRateModel

Author: Aloe Labs, Inc.

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

State Variables

_A

uint256 private constant _A = 6.1010463348e20;

_B

uint256 private constant _B = _A / 1e18;

Functions

getYieldPerSecond

Specifies the percentage yield per second for a lender. Need not be a pure function of utilization. To convert to APY: (1 + returnValue / 1e12) ** secondsPerYear - 1

function getYieldPerSecond(uint256 utilization, address) external pure returns (uint256);

Parameters

NameTypeDescription
utilizationuint256The lender's total borrows divided by total assets, scaled up by 1e18
<none>address

Returns

NameTypeDescription
<none>uint256The percentage yield per second, scaled up by 1e12

SafeRateLib

Git Source

Functions

getAccrualFactor

function getAccrualFactor(IRateModel rateModel, uint256 utilization, uint256 dt) internal view returns (uint256);

_computeAccrualFactor

function _computeAccrualFactor(uint256 rate, uint256 dt) private pure returns (uint256);

IRateModel

Git Source

Functions

getYieldPerSecond

Specifies the percentage yield per second for a lender. Need not be a pure function of utilization. To convert to APY: (1 + returnValue / 1e12) ** secondsPerYear - 1

function getYieldPerSecond(uint256 utilization, address lender) external view returns (uint256);

Parameters

NameTypeDescription
utilizationuint256The lender's total borrows divided by total assets, scaled up by 1e18
lenderaddressThe Lender to examine

Returns

NameTypeDescription
<none>uint256The percentage yield per second, scaled up by 1e12

VolatilityOracle

Git Source

Author: Aloe Labs, Inc.

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

State Variables

cachedMetadata

mapping(IUniswapV3Pool => Volatility.PoolMetadata) public cachedMetadata;

feeGrowthGlobals

mapping(IUniswapV3Pool => Volatility.FeeGrowthGlobals[FEE_GROWTH_ARRAY_LENGTH]) public feeGrowthGlobals;

lastWrites

mapping(IUniswapV3Pool => LastWrite) public lastWrites;

Functions

prepare

function prepare(IUniswapV3Pool pool) external;

update

function update(IUniswapV3Pool pool, uint40 seed) external returns (uint56, uint160, uint256);

consult

function consult(IUniswapV3Pool pool, uint40 seed) external view returns (uint56, uint160, uint256);

_ema

function _ema(int256 oldIV, int256 estimate) private pure returns (uint104);

_interpolateIV

function _interpolateIV(LastWrite memory lastWrite) private view returns (uint256);

_getPoolMetadata

function _getPoolMetadata(IUniswapV3Pool pool) private view returns (Volatility.PoolMetadata memory metadata);

_getFeeGrowthGlobalsNow

function _getFeeGrowthGlobalsNow(IUniswapV3Pool pool) private view returns (Volatility.FeeGrowthGlobals memory);

_getFeeGrowthGlobalsOld

function _getFeeGrowthGlobalsOld(
    Volatility.FeeGrowthGlobals[FEE_GROWTH_ARRAY_LENGTH] storage arr,
    uint256 index
) private view returns (Volatility.FeeGrowthGlobals memory);

_binarySearch

function _binarySearch(
    Volatility.FeeGrowthGlobals[FEE_GROWTH_ARRAY_LENGTH] storage arr,
    uint256 l,
    uint256 target
) private view returns (Volatility.FeeGrowthGlobals memory);

_isInInterval

function _isInInterval(uint256 min, uint256 x, uint256 max) private pure returns (bool);

Events

Update

event Update(IUniswapV3Pool indexed pool, uint160 sqrtMeanPriceX96, uint104 iv);

Structs

LastWrite

struct LastWrite {
    uint8 index;
    uint40 time;
    uint104 oldIV;
    uint104 newIV;
}

Contents

Contents

Uniswap

Git Source

State Variables

_INIT_CODE_HASH

bytes32 private constant _INIT_CODE_HASH = 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54;

Functions

info

Wrapper around IUniswapV3Pool.positions() that assumes positions is owned by this

function info(Position memory position, IUniswapV3Pool pool) internal view returns (PositionInfo memory positionInfo);

info

Wrapper around IUniswapV3Pool.positions().

function info(
    Position memory position,
    IUniswapV3Pool pool,
    address owner
) internal view returns (PositionInfo memory positionInfo);

fees

function fees(
    Position memory position,
    IUniswapV3Pool pool,
    PositionInfo memory positionInfo,
    FeeComputationCache memory c
) internal view returns (uint256 amount0, uint256 amount1);

liquidityForAmount0

function liquidityForAmount0(Position memory position, uint256 amount0) internal pure returns (uint128);

liquidityForAmount0

Computes the amount of liquidity received for a given amount of token0 and price range

Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower))

function liquidityForAmount0(
    uint160 sqrtRatioAX96,
    uint160 sqrtRatioBX96,
    uint256 amount0
) internal pure returns (uint128 liquidity);

Parameters

NameTypeDescription
sqrtRatioAX96uint160A sqrt price representing the first tick boundary
sqrtRatioBX96uint160A sqrt price representing the second tick boundary
amount0uint256The amount0 being sent in

Returns

NameTypeDescription
liquidityuint128The amount of returned liquidity

liquidityForAmount1

function liquidityForAmount1(Position memory position, uint256 amount1) internal pure returns (uint128);

liquidityForAmount1

Computes the amount of liquidity received for a given amount of token1 and price range

Calculates amount1 / (sqrt(upper) - sqrt(lower)).

function liquidityForAmount1(
    uint160 sqrtRatioAX96,
    uint160 sqrtRatioBX96,
    uint256 amount1
) internal pure returns (uint128 liquidity);

Parameters

NameTypeDescription
sqrtRatioAX96uint160A sqrt price representing the first tick boundary
sqrtRatioBX96uint160A sqrt price representing the second tick boundary
amount1uint256The amount1 being sent in

Returns

NameTypeDescription
liquidityuint128The amount of returned liquidity

liquidityForAmounts

function liquidityForAmounts(
    Position memory position,
    uint160 sqrtPriceX96,
    uint256 amount0,
    uint256 amount1
) internal pure returns (uint128);

liquidityForAmounts

Computes the maximum amount of liquidity received for a given amount of token0, token1, the current pool prices and the prices at the tick boundaries

function liquidityForAmounts(
    uint160 sqrtRatioX96,
    uint160 sqrtRatioAX96,
    uint160 sqrtRatioBX96,
    uint256 amount0,
    uint256 amount1
) internal pure returns (uint128 liquidity);

Parameters

NameTypeDescription
sqrtRatioX96uint160A sqrt price representing the current pool prices
sqrtRatioAX96uint160A sqrt price representing the first tick boundary
sqrtRatioBX96uint160A sqrt price representing the second tick boundary
amount0uint256The amount of token0 being sent in
amount1uint256The amount of token1 being sent in

Returns

NameTypeDescription
liquidityuint128The maximum amount of liquidity received

amountsForLiquidity

Wrapper around LiquidityAmounts.getAmountsForLiquidity().

function amountsForLiquidity(
    Position memory position,
    uint160 sqrtPriceX96,
    uint128 liquidity
) internal pure returns (uint256, uint256);

valueOfLiquidity

Wrapper around LiquidityAmounts.getValueOfLiquidity()

function valueOfLiquidity(
    Position memory position,
    uint160 sqrtPriceX96,
    uint128 liquidity
) internal pure returns (uint256);

computePoolAddress

function computePoolAddress(
    address factory,
    address token0,
    address token1,
    uint24 fee
) internal pure returns (IUniswapV3Pool pool);

_fees

function _fees(
    PositionInfo memory positionInfo,
    uint256 feeGrowthInside0X128,
    uint256 feeGrowthInside1X128
) private pure returns (uint256 amount0, uint256 amount1);

Structs

Position

struct Position {
    int24 lower;
    int24 upper;
}

PositionInfo

struct PositionInfo {
    uint128 liquidity;
    uint256 feeGrowthInside0LastX128;
    uint256 feeGrowthInside1LastX128;
    uint128 tokensOwed0;
    uint128 tokensOwed1;
}

FeeComputationCache

struct FeeComputationCache {
    int24 currentTick;
    uint256 feeGrowthGlobal0X128;
    uint256 feeGrowthGlobal1X128;
}

πŸ—‚οΈ helpers

πŸ“ƒ LenderAccrualHelper

πŸ“ƒ OracleUpdateHelper

Contents

BoostManager

Git Source

Inherits: IManager, IUniswapV3SwapCallback

State Variables

FACTORY

Factory public immutable FACTORY;

BORROWER_NFT

address public immutable BORROWER_NFT;

UNISWAP_NFT

IUniswapPositionNFT public immutable UNISWAP_NFT;

Functions

constructor

constructor(Factory factory, address borrowerNft, IUniswapPositionNFT uniswapNft);

uniswapV3SwapCallback

function uniswapV3SwapCallback(int256 amount0, int256 amount1, bytes calldata data) external;

callback

function callback(bytes calldata data, address owner, uint208 positions) external override returns (uint208);

_action0Mint

function _action0Mint(Borrower borrower, address owner, bytes memory args) private returns (uint208);

_action2Burn

function _action2Burn(
    Borrower borrower,
    address owner,
    bytes memory args,
    uint208 positions
) private returns (uint208);

_withdrawFromUniswapNFT

function _withdrawFromUniswapNFT(
    uint256 tokenId,
    uint128 liquidity,
    address recipient
) private returns (uint256 burned0, uint256 burned1);

FrontendManager

Git Source

Inherits: IManager, IUniswapV3SwapCallback

State Variables

FACTORY

Factory public immutable FACTORY;

Functions

constructor

constructor(Factory factory);

uniswapV3SwapCallback

function uniswapV3SwapCallback(int256 amount0, int256 amount1, bytes calldata data) external;

callback

function callback(bytes calldata data, address owner, uint208) external returns (uint208 positions);

Events

Modify

event Modify(address indexed borrower, int24 tick);

SimpleManager

Git Source

Inherits: IManager

Functions

callback

function callback(bytes calldata data, address, uint208) external override returns (uint208);

UniswapNFTManager

Git Source

Inherits: IManager

State Variables

FACTORY

Factory public immutable FACTORY;

BORROWER_NFT

address public immutable BORROWER_NFT;

UNISWAP_NFT

IUniswapPositionNFT public immutable UNISWAP_NFT;

Functions

constructor

constructor(Factory factory, address borrowerNft, IUniswapPositionNFT uniswapNft);

callback

function callback(bytes calldata data, address owner, uint208) external override returns (uint208 positions);

_withdrawFromNFT

function _withdrawFromNFT(uint256 tokenId, uint128 liquidity, address recipient) private;

BorrowerLens

Git Source

Functions

predictBorrowerAddress

function predictBorrowerAddress(
    IUniswapV3Pool pool,
    address owner,
    bytes12 salt,
    address caller,
    Factory factory
) external view returns (address borrower);

getHealth

Mirrors the logic in BalanceSheet.isHealthy, but returns numbers instead of a boolean

function getHealth(Borrower account) external view returns (uint256 healthA, uint256 healthB);

isInUse

function isInUse(Borrower borrower) external view returns (bool, IUniswapV3Pool);

getUniswapPositions

function getUniswapPositions(Borrower account)
    external
    view
    returns (int24[] memory positions, uint128[] memory liquidity, uint256[] memory fees);

_health

function _health(
    uint160 sqrtPriceX96,
    uint256 assets0,
    uint256 assets1,
    uint256 liabilities0,
    uint256 liabilities1
) private pure returns (uint256 health);

LenderLens

Git Source

Functions

readBasics

function readBasics(Lender lender)
    external
    view
    returns (
        ERC20 asset,
        uint256 interestRate,
        uint256 utilization,
        uint256 inventory,
        uint256 totalBorrows,
        uint256 totalSupply,
        uint8 reserveFactor,
        uint64 rewardsRate
    );

isMaxRedeemDynamic

Indicates whether lender.maxRedeem(owner) is dynamic, i.e. whether it's changing over time or not

In most cases, lender.maxRedeem(owner) returns a static number of shares, and a standard lender.redeem call can successfully redeem everything. However, if the user has a courier or if utilization is too high, the number of shares may change block by block. In that case, to redeem the maximum value, you can pass type(uint256).max to lender.redeem.

function isMaxRedeemDynamic(Lender lender, address owner) external view returns (bool);

Router

Git Source

State Variables

PERMIT2

IPermit2 public immutable PERMIT2;

Functions

constructor

constructor(IPermit2 permit2);

depositWithPermit2

Deposits amount of lender.asset() to lender using {nonce, deadline, signature} for Permit2, and gives courierId a cut of future interest earned by msg.sender. v, r, and s are used with lender.permit in order to (a) achieve 0 balance if necessary and (b) set the courier.

This innoculates Lender against a potential courier frontrunning attack by redeeming all shares (if any are present) before assigning the new courierId. Lender then clears the permited allowance in deposit, meaning this contract is left with no special permissions.

function depositWithPermit2(
    Lender lender,
    uint256 amount,
    uint16 transmittance,
    uint256 nonce,
    uint256 deadline,
    bytes calldata signature,
    uint32 courierId,
    uint8 v,
    bytes32 r,
    bytes32 s
) external payable returns (uint256 shares);

depositWithPermit2

function depositWithPermit2(
    Lender lender,
    uint256 amount,
    uint16 transmittance,
    uint256 nonce,
    uint256 deadline,
    bytes calldata signature
) external payable returns (uint256 shares);

repayWithPermit2

function repayWithPermit2(
    Lender lender,
    bool max,
    uint256 amount,
    address beneficiary,
    uint256 nonce,
    uint256 deadline,
    bytes calldata signature
) external returns (uint256 units);