Skip to main content

AmmalgamPair

Git Source

Inherits: IAmmalgamPair, TokenController

State Variables

ZERO_DEPOSIT_DUE_TO_NETTING

uint256 private constant ZERO_DEPOSIT_DUE_TO_NETTING = 0;

UNLOCKED

uint256 private constant UNLOCKED = 0;

LOCKED

uint256 private constant LOCKED = 1;

locked

uint256 private transient locked;

activeBorrower

address private transient activeBorrower;

Functions

lock

modifier lock();

_lock

function _lock() private;

_unlock

function _unlock() private;

_revertNestedBorrow

function _revertNestedBorrow() private view;

mint

function mint(
address to
) external virtual lock returns (uint256 liquidityShares);

burn

function burn(
address to
) external virtual lock returns (uint256 amountXAssets, uint256 amountYAssets);

swap

function swap(uint256 amountXOut, uint256 amountYOut, address to, bytes calldata data) external virtual lock;

calculateAmountIn

helper method to calculate amountIn for swap

Adds jump, saves on runtime size. Must check that reserve > amountOut, which happens in swap where function is called.

function calculateAmountIn(
uint256 amountOut,
uint256 balance,
uint256 reserve
) private pure returns (uint256 amountIn);

Parameters

NameTypeDescription
amountOutuint256the amount out
balanceuint256the balance
reserveuint256the reserve

calculateBalanceAfterFees

helper method to calculate balance after fees

Note that amountIn + reserve does not always equal balance if amountOut > 0. In the depleted case the balance is scaled by BUFFER_NUMERATOR; the matching scaling is applied on the reserve side in calculateReserveAdjustmentsForMissingAssets so the K comparison stays division-free on both branches.

function calculateBalanceAfterFees(
uint256 amountIn,
uint256 balance,
uint256 reserve,
uint256 referenceReserve,
uint256 missing
) private pure returns (uint256 calculatedBalance);

Parameters

NameTypeDescription
amountInuint256the swap amount in
balanceuint256the balance
reserveuint256the reserve
referenceReserveuint256the reference reserve for the block
missinguint256the missing assets, zero if deposits > borrows of X or Y

deposit

function deposit(
address to
) external virtual lock;

withdraw

withdraw X and/or Y

function withdraw(
address to
) external virtual lock;

updateWithdrawShares

function updateWithdrawShares(
address to,
uint256 depositedTokenType,
uint256 _reserve
) private returns (uint256 withdrawnAssets);

borrow

function borrow(address to, uint256 amountXAssets, uint256 amountYAssets, bytes calldata data) external virtual lock;

borrowHelper

function borrowHelper(
address to,
uint256 amountAssets,
uint256 reserve,
uint256 depositedTokenType,
uint256 borrowedTokenType
) private returns (uint256 amountShares);

updateBorrowOrDepositSharesHelper

function updateBorrowOrDepositSharesHelper(
address to,
uint256 tokenType,
uint256 amountAssets,
bool isRoundingUp
) private returns (uint256 amountShares);

borrowLiquidity

function borrowLiquidity(
address to,
uint256 borrowAmountLAssets,
bytes calldata data
) external virtual lock returns (uint256 borrowedLXAssets, uint256 borrowedLYAssets);

repay

function repay(
address onBehalfOf
) external virtual lock returns (uint256 repayXAssets, uint256 repayYAssets);

_repay

Internal version to allow for direct calls during liquidations

function _repay(
address onBehalfOf,
uint256 repayXAssets,
uint256 repayYAssets
) private returns (uint256 actualRepayXAssets, uint256 actualRepayYAssets);

repayHelper

function repayHelper(
address onBehalfOf,
uint256 repayInAssets,
uint256 borrowTokenType
) private returns (uint256 actualRepayInAssets);

repayLiquidity

function repayLiquidity(
address onBehalfOf
) external virtual lock returns (uint256 repaidXAssets, uint256 repaidYAssets, uint256 repayLiquidityAssets);

_repayLiquidity

function _repayLiquidity(
address onBehalfOf,
uint256 repaidXAssets,
uint256 repaidYAssets,
uint256 _reserveXAssets,
uint256 _reserveYAssets
) private returns (uint256 repayLiquidityAssets);

liquidate

accrues interest and determines the amount sent to the contract prior to executing liquidation.

function liquidate(
address borrower,
address to,
uint256 seizedLAssets,
uint256 seizedXAssets,
uint256 seizedYAssets,
uint256 repayXAssets,
uint256 repayYAssets,
uint256 liquidationType
) external virtual lock;

Parameters

NameTypeDescription
borroweraddressThe account being liquidated.
toaddressThe account to send the liquidated deposit to
seizedLAssetsuint256The amount of L tokens to be transferred from the hard deposit.
seizedXAssetsuint256The amount of X tokens to be transferred from the hard deposit.
seizedYAssetsuint256The amount of Y tokens to be transferred from the hard deposit.
repayXAssetsuint256The amount of X assets being repaid on behalf of the borrower.
repayYAssetsuint256The amount of Y assets being repaid on behalf of the
liquidationTypeuint256The type of liquidation to be performed: HARD, SATURATION, LEVERAGE

liquidateHard

LTV based liquidation. The LTV dictates the max premium that can be had by the liquidator. We determine the amount of borrowed liquidity to be repaid by reducing the actual amount transferred prior to calling liquidate() by the amount passed in for the repayXAssets and repayYAssets parameters.

Calculating a Hard Liquidation

Hard liquidations can be partial subset of the borrower's entire position based on tranche saturation composition. Use LiquidationUtils.calculatePartialLiquidationAmount() to compute the partial position, max premium, and the amounts needed for the call. Three prices are in play and each is used at a different stage:

PriceSourceWhere used
Reserve pricereserveX / reserveY_repayLiquidity: splits tokens
into the X/Y ratio the pool needs
to burn BORROW_L.
sqrtPriceMin (TWAP)geometric TWAP low tickVerification converts:
BORROW_X → L (worst-case borrow)
DEPOSIT_Y → L (worst-case dep.)
sqrtPriceMax (TWAP)geometric TWAP high tickVerification converts:
BORROW_Y → L (worst-case borrow)
DEPOSIT_X → L (worst-case dep.)
Verification (verifyHardLiquidation) swaps min and max when calling
getCheckLtvParams(proposed, sqrtPriceMax, sqrtPriceMin). This values deposits at
their highest and borrows at their lowest, favoring the borrower by making the
position appear as healthy as possible. This limits the ability of liquidators to
manipulate premiums.
The reserve price and TWAP prices may diverge. Seized deposit amounts must be
computed using TWAP prices (the verification domain), not reserve prices.

Net Debt Calculation and the BORROW_L Overlap

getBorrowedInL initializes BOTH sides from BORROW_L:

netBorrowedXinL = BORROW_L + convertXToL(BORROW_X, sqrtPriceMin)
netBorrowedYinL = BORROW_L + convertYToL(BORROW_Y, sqrtPriceMax)

getDepositsInL initializes BOTH sides from DEPOSIT_L:

netDepositedXinL = DEPOSIT_L + convertXToL(DEPOSIT_X, sqrtPriceMax)
netDepositedYinL = DEPOSIT_L + convertYToL(DEPOSIT_Y, sqrtPriceMin)

calcDebtAndCollateral then nets these to determine netDebtX:

netDebtX = true  when netDepositedX <= netBorrowedX AND netDepositedY > netBorrowedY
netDebtX = false when netDepositedY <= netBorrowedY AND netDepositedX > netBorrowedX

netDebtX selects the saturation account. A wrong value causes calculatePartialLiquidation to return the wrong tranche set, reverting the liquidation.

Computing Seized amounts Borrow X, Seize Y

For a position with BORROW_X and DEPOSIT_Y, the seized Y only needs to cover the liquidation premium on the repaid debt:

borrowXInL  = ceil(BORROW_X * Q72 / sqrtPriceMax)
premiumInL = borrowXInL * maxPremiumBips / BIPS
seizedY = premiumInL * Q72 / sqrtPriceMax

Overlap Case: Borrow X + Borrow L, Seize Y

When BORROW_L is present and BORROW_Y is zero, getBorrowedInL computes:

netBorrowedXinL = BORROW_L + convertXToL(BORROW_X, sqrtPriceMin)
netBorrowedYinL = BORROW_L

The seized Y (in L-terms at TWAP price) must exceed BORROW_L so that netDepositedYinL > netBorrowedYinL, which is required for netDebtX = true. The seized amount includes the BORROW_L overlap plus the liquidation premium:

borrowXInL     = ceil(BORROW_X * Q72 / sqrtPriceMax)
netRepaidInL = BORROW_L + borrowXInL
premiumInL = netRepaidInL * maxPremiumBips / BIPS
seizedYInL = BORROW_L + premiumInL
seizedY = seizedYInL * Q72 / sqrtPriceMax

Token Transfer Amounts

The liquidator must transfer enough tokens to cover both direct borrows and BORROW_L:

repayLX = ceil(BORROW_L * reserveX / activeLiquidity)
repayLY = ceil(BORROW_L * reserveY / activeLiquidity)
totalXTransfer = BORROW_X + repayLX
totalYTransfer = repayLY

These use reserve prices because _repayLiquidity splits tokens by the reserve ratio. The seized Y amount uses TWAP prices because verifyHardLiquidation operates in that domain.

function liquidateHard(
address borrower,
address to,
Validation.InputParams memory inputParams,
uint256[6] memory proposedLiquidation,
uint256 actualRepaidXAssets,
uint256 actualRepaidYAssets
) private;

Parameters

NameTypeDescription
borroweraddressThe account being liquidated
toaddressThe account to send the liquidated deposit to
inputParamsValidation.InputParamsThe input parameters for the liquidation, including reserves and price limits.
proposedLiquidationuint256[6]The inputted amount of deposits to be seized and borrows to be repaid.
actualRepaidXAssetsuint256The actual amount of X assets repaid by the liquidator.
actualRepaidYAssetsuint256The actual amount of Y assets repaid by the liquidator.

resetSaturation

Liquidation based on change of saturation because of time.

function resetSaturation(Validation.InputParams memory inputParams, address borrower, address to) private;

Parameters

NameTypeDescription
inputParamsValidation.InputParams
borroweraddressThe account being liquidated.
toaddressThe account to send the liquidated deposit to

liquidateLeverage

Liquidation based on leverage.

function liquidateLeverage(
Validation.InputParams memory inputParams,
address borrower,
address to,
uint256 actualRepaidXAssets,
uint256 actualRepaidYAssets
) private;

Parameters

NameTypeDescription
inputParamsValidation.InputParamsThe input parameters for the liquidation, including reserves and price.
borroweraddressThe account being liquidated.
toaddressThe account to send the liquidated deposit to.
actualRepaidXAssetsuint256The actual amount of X assets repaid by the liquidator.
actualRepaidYAssetsuint256The actual amount of Y assets repaid by the liquidator.

_liquidationRepayHelper

Repays the borrow legs of a liquidation and verifies the liquidator repaid enough.

Shared by hard and leverage liquidations. The required X/Y repayments must be fully covered by the assets the liquidator sent in; any remainder repays borrowed liquidity. liquidationParams[BORROW_L] carries the minimum liquidity that must be repaid and is overwritten with the liquidity actually repaid so verifyHardLiquidation can read it back.

function _liquidationRepayHelper(
address borrower,
uint256[6] memory liquidationParams,
uint256 actualRepaidXAssets,
uint256 actualRepaidYAssets,
uint256 _reserveXAssets,
uint256 _reserveYAssets
) private;

Parameters

NameTypeDescription
borroweraddressThe account being liquidated.
liquidationParamsuint256[6]Borrow legs to repay, indexed by BORROW_X / BORROW_Y / BORROW_L.
actualRepaidXAssetsuint256The X assets the liquidator transferred in for the repayment.
actualRepaidYAssetsuint256The Y assets the liquidator transferred in for the repayment.
_reserveXAssetsuint256Current X reserves, used to split repaid liquidity by the reserve ratio.
_reserveYAssetsuint256Current Y reserves, used to split repaid liquidity by the reserve ratio.

_revertNotEnoughRepaidForLiquidation

function _revertNotEnoughRepaidForLiquidation() private pure;

_burnBadDebt

function _burnBadDebt(address borrower, uint256[6] memory userAssets) private;

finalizeLiquidation

function finalizeLiquidation(
address borrower,
address to,
uint256 depositLToBeTransferredInLAssets,
uint256 depositXToBeTransferredInXAssets,
uint256 depositYToBeTransferredInYAssets,
bool isBadDebt
) private;

liquidationTransfer

Transfer deposit to the liquidator from the borrower (==from).

function liquidationTransfer(
address from,
address to,
uint256 depositToTransferInAssets,
uint256 tokenType,
bool isBadDebt
) private;

Parameters

NameTypeDescription
fromaddressThe account the deposit is being transferred from.
toaddressThe account the deposit is being transferred to.
depositToTransferInAssetsuint256The amount being transferred to the liquidator.
tokenTypeuint256The deposit token type being transferred.
isBadDebtbool

skim

function skim(
address to
) external virtual lock;

sync

function sync() external virtual lock;

accrueSaturationPenaltiesAndInterest

function accrueSaturationPenaltiesAndInterest(
address affectedAccount,
uint256 minimumTimeBeforeUpdate
) private returns (uint256 _reserveXAssets, uint256 _reserveYAssets, uint256 balanceXAssets, uint256 balanceYAssets);

updateObservation

function updateObservation(
uint256 _reserveXAssets,
uint256 _reserveYAssets,
uint32 currentTimestamp,
uint32 deltaUpdateTimestamp
) private;

validateOnUpdate

function validateOnUpdate(address validate, address update, bool alwaysUpdate) public virtual;

validateSolvency

function validateSolvency(address validate, bool alwaysUpdate) private;

updateSaturationIfNeeded

Update saturation state for an account if it already exists in saturation.

*Note that during a repay of debt, we may not have an entry in saturation if

  1. The position is a straddle with a payout that never reaches zero
  2. Repay is occurring during a callback of a flash loan, saturation will not be updated until the end of the borrow call after the callback concludes.*
function updateSaturationIfNeeded(
address toUpdate
) private;

Parameters

NameTypeDescription
toUpdateaddressThe account to update saturation for.

getInputParams

function getInputParams(
address toCheck,
bool includeLongTermPrice
) internal view returns (Validation.InputParams memory inputParams);

transferAssets

function transferAssets(address to, uint256 amountXAssets, uint256 amountYAssets) private;

calculateMinimumLiquidityAssets

function calculateMinimumLiquidityAssets(
uint256 amountXAssets,
uint256 amountYAssets,
uint256 _reserveXAssets,
uint256 _reserveYAssets,
uint256 liquidityAssetsNumerator,
bool isRoundingUp
) private pure returns (uint256 liquidityAssets);

checkMaxBorrowForLiquidity

function checkMaxBorrowForLiquidity(
uint256 reserveX,
uint256 reserveY,
uint256 totalDepositedLAssets,
uint256 totalBorrowedLAssets,
uint256 newBorrowLAssets
) private view;

checkMaxBorrow

function checkMaxBorrow(
uint256 depositedAssets,
uint256 borrowedAssets,
uint256 reserve,
uint256 totalDepositedLAssets,
uint256 totalBorrowedLiquidityAssets
) private pure;

Errors

Locked

error Locked();

InsufficientLiquidityMinted

error InsufficientLiquidityMinted();

InsufficientLiquidityBurned

error InsufficientLiquidityBurned();

InsufficientOutputAmount

error InsufficientOutputAmount();

InsufficientInputAmount

error InsufficientInputAmount();

InsufficientLiquidity

error InsufficientLiquidity();

InvalidToAddress

error InvalidToAddress();

K

error K();

InsufficientRepayLiquidity

error InsufficientRepayLiquidity();