Skip to main content

AMM (LLAMMA)

The AMM contract implements LLAMMA — the Lending-Liquidating AMM Algorithm. It holds borrower collateral distributed across discretized price bands and performs soft liquidation: as the collateral price drops into a borrower's band range, the AMM gradually converts their collateral to the borrowed token. If the price recovers, the process reverses (de-liquidation).

The AMM also serves as a regular DEX — arbitrageurs can swap between the collateral and borrowed tokens, which is the mechanism that drives soft liquidation.

Each lending market has its own AMM instance. The associated LendController is the AMM's admin and is the only address allowed to deposit/withdraw collateral.

AMM.vy

The source code for the AMM.vy contract can be found on GitHub. The contract is written in Vyper version 0.4.3.

Deployment addresses will be added once contracts are finalized.

Examples use Ethers v6 with an ABI generated from the pinned source linked in each panel. Replace every zero address and amount placeholder. Read-only calls use the verified Ethereum v2 reference market; execute a write only on a fork first.


Swaps

exchange

AMM.exchange(i: uint256, j: uint256, in_amount: uint256, min_amount: uint256, _for: address) -> uint256[2]

Swaps in_amount of token i for token j. Token index 0 is the borrowed token, index 1 is the collateral token.

InputTypeDescription
iuint256Input token index (0 = borrowed, 1 = collateral)
juint256Output token index
in_amountuint256Amount of input token
min_amountuint256Minimum output amount (slippage protection)
_foraddressAddress to receive the output tokens

Returns: [in_amount_done, out_amount] (uint256[2]).

Emits: TokenExchange event.

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@nonreentrant
def exchange(i: uint256, j: uint256, in_amount: uint256, min_amount: uint256, _for: address = msg.sender) -> uint256[2]:
"""
@notice Exchanges two coins, callable by anyone
@param i Input coin index
@param j Output coin index
@param in_amount Amount of input coin to swap
@param min_amount Minimal amount to get as output
@param _for Address to send coins to
@return Amount of coins given in/out
"""
return self._exchange(i, j, in_amount, min_amount, _for, True)


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.exchange(
/* i: uint256 */ 0n,
/* j: uint256 */ 0n,
/* in_amount: uint256 */ 0n,
/* min_amount: uint256 */ 0n,
/* _for: address */ "0x0000000000000000000000000000000000000000",
)
await tx.wait()

exchange_dy

AMM.exchange_dy(i: uint256, j: uint256, out_amount: uint256, max_amount: uint256, _for: address) -> uint256[2]

Swaps to receive exactly out_amount of token j, paying at most max_amount of token i.

InputTypeDescription
iuint256Input token index
juint256Output token index
out_amountuint256Desired output amount
max_amountuint256Maximum input amount (slippage protection)
_foraddressAddress to receive the output tokens

Returns: [in_amount, out_amount_done] (uint256[2]). out_amount_done can be less than out_amount when the AMM does not have enough liquidity.

Emits: TokenExchange event.

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@nonreentrant
def exchange_dy(i: uint256, j: uint256, out_amount: uint256, max_amount: uint256, _for: address = msg.sender) -> uint256[2]:
"""
@notice Exchanges two coins, callable by anyone
@param i Input coin index
@param j Output coin index
@param out_amount Desired amount of output coin to receive
@param max_amount Maximum amount to spend (revert if more)
@param _for Address to send coins to
@return Amount of coins given in/out
"""
return self._exchange(i, j, out_amount, max_amount, _for, False)


@internal
@view
def get_xy_up(user: address, use_y: bool) -> uint256:
"""
@notice Measure the amount of y (collateral) in the band n if we adiabatically trade near p_oracle on the way up,
or the amount of x (borrowed) if we trade adiabatically down
@param user User the amount is calculated for
@param use_y Calculate amount of collateral if True and of borrowed if False
@return Amount of coins
"""
ns: int256[2] = self._read_user_tick_numbers(user)
ticks: DynArray[uint256, MAX_TICKS_UINT] = self._read_user_ticks(user, ns)
if ticks[0] == 0: # Even dynamic array will have 0th element set here
return 0
p_o: uint256 = self._price_oracle_ro()[0]
assert p_o != 0

n: int256 = ns[0] - 1
n_active: int256 = self.active_band
p_o_down: uint256 = self._p_oracle_up(ns[0])
XY: uint256 = 0

for i: uint256 in range(MAX_TICKS_UINT):
# … the remaining implementation is linked above.
Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.exchange_dy(
/* i: uint256 */ 0n,
/* j: uint256 */ 0n,
/* out_amount: uint256 */ 0n,
/* max_amount: uint256 */ 0n,
/* _for: address */ "0x0000000000000000000000000000000000000000",
)

get_dy

AMM.get_dy(i: uint256, j: uint256, in_amount: uint256) -> uint256: view

Calculates the output amount for a given input amount (i.e., a swap quote).

InputTypeDescription
iuint256Input token index
juint256Output token index
in_amountuint256Input amount

Returns: expected output amount (uint256).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
@nonreentrant
def get_dy(i: uint256, j: uint256, in_amount: uint256) -> uint256:
"""
@notice Method to use to calculate out amount
@param i Input coin index
@param j Output coin index
@param in_amount Amount of input coin to swap
@return Amount of coin j to give out
"""
return self._get_dxdy(i, j, in_amount, True).out_amount


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.get_dy(
/* i: uint256 */ 0n,
/* j: uint256 */ 0n,
/* in_amount: uint256 */ 0n,
)

get_dx

AMM.get_dx(i: uint256, j: uint256, out_amount: uint256) -> uint256: view

Calculates the input amount needed to receive a given output amount.

InputTypeDescription
iuint256Input token index
juint256Output token index
out_amountuint256Desired output amount

Returns: required input amount (uint256).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
@nonreentrant
def get_dx(i: uint256, j: uint256, out_amount: uint256) -> uint256:
"""
@notice Method to use to calculate in amount required to receive the desired out_amount
@param i Input coin index
@param j Output coin index
@param out_amount Desired amount of output coin to receive
@return Amount of coin i to spend
"""
# i = 0: borrowable (USD) in, collateral (ETH) out; going up
# i = 1: collateral (ETH) in, borrowable (USD) out; going down
trade: IAMM.DetailedTrade = self._get_dxdy(i, j, out_amount, False)
assert trade.out_amount == out_amount
return trade.in_amount


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.get_dx(
/* i: uint256 */ 0n,
/* j: uint256 */ 0n,
/* out_amount: uint256 */ 0n,
)

get_dxdy

AMM.get_dxdy(i: uint256, j: uint256, in_amount: uint256) -> uint256[2]: view

Returns both the input amount used and the output amount for a given swap.

InputTypeDescription
iuint256Input token index
juint256Output token index
in_amountuint256Input amount

Returns: [in_amount_done, out_amount] (uint256[2]).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
@nonreentrant
def get_dxdy(i: uint256, j: uint256, in_amount: uint256) -> (uint256, uint256):
"""
@notice Method to use to calculate out amount and spent in amount
@param i Input coin index
@param j Output coin index
@param in_amount Amount of input coin to swap
@return A tuple with in_amount used and out_amount returned
"""
out: IAMM.DetailedTrade = self._get_dxdy(i, j, in_amount, True)
return (out.in_amount, out.out_amount)


@internal
def _exchange(i: uint256, j: uint256, amount: uint256, minmax_amount: uint256, _for: address, use_in_amount: bool) -> uint256[2]:
"""
@notice Exchanges two coins, callable by anyone
@param i Input coin index
@param j Output coin index
@param amount Amount of input/output coin to swap
@param minmax_amount Minimal/maximum amount to get as output/input
@param _for Address to send coins to
@param use_in_amount Whether input or output amount is specified
@return Amount of coins given in and out
"""
assert (i == 0 and j == 1) or (i == 1 and j == 0), "Wrong index"
p_o: uint256[2] = self._price_oracle_w() # Let's update the oracle even if we exchange 0
if amount == 0:
return [0, 0]

lm: ILMCallback = self._liquidity_mining_callback
collateral_shares: DynArray[uint256, MAX_TICKS_UINT] = []

in_coin: IERC20 = BORROWED_TOKEN
out_coin: IERC20 = COLLATERAL_TOKEN
in_precision: uint256 = BORROWED_PRECISION
# … the remaining implementation is linked above.
Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.get_dxdy(
/* i: uint256 */ 0n,
/* j: uint256 */ 0n,
/* in_amount: uint256 */ 0n,
)

get_dydx

AMM.get_dydx(i: uint256, j: uint256, out_amount: uint256) -> uint256[2]: view

Returns both the output amount and the input amount needed for a given desired output.

InputTypeDescription
iuint256Input token index
juint256Output token index
out_amountuint256Desired output amount

Returns: [out_amount_done, in_amount] (uint256[2]). out_amount_done can be less than out_amount when the AMM does not have enough liquidity.

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
@nonreentrant
def get_dydx(i: uint256, j: uint256, out_amount: uint256) -> (uint256, uint256):
"""
@notice Method to use to calculate in amount required and out amount received
@param i Input coin index
@param j Output coin index
@param out_amount Desired amount of output coin to receive
@return A tuple with out_amount received and in_amount returned
"""
# i = 0: borrowable (USD) in, collateral (ETH) out; going up
# i = 1: collateral (ETH) in, borrowable (USD) out; going down
out: IAMM.DetailedTrade = self._get_dxdy(i, j, out_amount, False)
return (out.out_amount, out.in_amount)


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.get_dydx(
/* i: uint256 */ 0n,
/* j: uint256 */ 0n,
/* out_amount: uint256 */ 0n,
)

get_amount_for_price

AMM.get_amount_for_price(_p: uint256) -> (uint256, bool): view

Returns the amount and swap direction needed to move the AMM price to _p.

InputTypeDescription
_puint256Target price, scaled by 1e18

Returns: [amount, is_pump]. If is_pump is true, swap borrowed token for collateral and amount is the required borrowed-token input. If false, swap collateral for borrowed token and amount is the required collateral-token input.

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
@nonreentrant
def get_amount_for_price(p: uint256) -> (uint256, bool):
"""
@notice Amount necessary to be exchanged to have the AMM at the final price `p`
@param p Target price to reach, in units of borrowed token per collateral multiplied by 1e18
@return (amount, is_pump)
"""
min_band: int256 = self.min_band
max_band: int256 = self.max_band
n: int256 = self.active_band
p_o: uint256[2] = self._price_oracle_ro()
p_o_up: uint256 = self._p_oracle_up(n)
p_down: uint256 = unsafe_div(unsafe_div(p_o[0]**2, p_o_up) * p_o[0], p_o_up) # p_current_down
p_up: uint256 = unsafe_div(p_down * A2, Aminus12) # p_crurrent_up
amount: uint256 = 0
y0: uint256 = 0
f: uint256 = 0
g: uint256 = 0
Inv: uint256 = 0
j: uint256 = MAX_TICKS_UINT
pump: bool = True

fee: uint256 = max(self.fee, p_o[1])

for i: uint256 in range(MAX_TICKS_UINT + MAX_SKIP_TICKS_UINT):
assert p_o_up > 0
x: uint256 = self.bands_x[n]
y: uint256 = self.bands_y[n]
if i == 0:
if p < self._get_p(n, x, y):
pump = False
dynamic_fee: uint256 = fee
not_empty: bool = x > 0 or y > 0

if not_empty:
y0 = self._get_y0(x, y, p_o[0], p_o_up)
# … the remaining implementation is linked above.
Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.get_amount_for_price(
/* _p: uint256 */ 0n,
)

Price and Band Info

price_oracle

AMM.price_oracle() -> uint256: view

Returns the external oracle price, clamped to the maximum allowed relative change.

Returns: oracle price (uint256).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
def price_oracle() -> uint256:
"""
@notice Value returned by the external price oracle contract
@return Current price of collateral in units of borrowed token, multiplied by 1e18
"""
return self._price_oracle_ro()[0]


@internal
@view
def _rate_mul() -> uint256:
"""
@notice Rate multiplier which is 1.0 + integral(rate, dt)
@return Rate multiplier in units where 1.0 == 1e18
"""
return unsafe_div(self.rate_mul * (10**18 + self.rate * (block.timestamp - self.rate_time)), 10**18)


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.price_oracle()

price_oracle_contract

AMM.price_oracle_contract() -> address: view

Returns the address of the external price oracle contract.

Returns: oracle address (address).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@view
@external
def price_oracle_contract() -> IPriceOracle:
return self._price_oracle


old_p_o: uint256
old_dfee: uint256
prev_p_o_time: uint256
PREV_P_O_DELAY: constant(uint256) = 2 * 60 # s = 2 min
MAX_P_O_CHG: constant(uint256) = 12500 * 10**14 # <= 2**(1/3) - max relative change to have fee < 50%

bands_x: public(HashMap[int256, uint256])
bands_y: public(HashMap[int256, uint256])

total_shares: HashMap[int256, uint256]
_user_shares: HashMap[address, IAMM.UserTicks]


_liquidity_mining_callback: ILMCallback

# https://github.com/vyperlang/vyper/issues/4721
@view
Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.price_oracle_contract()

get_p

AMM.get_p() -> uint256: view

Returns the current AMM price (the marginal price at the active band).

Returns: current price (uint256).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
@nonreentrant
def get_p() -> uint256:
"""
@notice Get current AMM price in active_band
@return Current price at 1e18 base
"""
n: int256 = self.active_band
return self._get_p(n, self.bands_x[n], self.bands_y[n])


@internal
@view
def _read_user_tick_numbers(user: address) -> int256[2]:
"""
@notice Unpacks and reads user tick numbers
@param user User address
@return Lowest and highest band the user deposited into
"""
ns: int256 = self._user_shares[user].ns
n2: int256 = unsafe_div(ns, 2**128)
n1: int256 = ns % 2**128
if n1 >= 2**127:
n1 = unsafe_sub(n1, 2**128)
n2 = unsafe_add(n2, 1)
return [n1, n2]


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.get_p()

get_base_price

AMM.get_base_price() -> uint256: view

Returns the base price used to calculate band boundaries, adjusted for accumulated interest rate.

Returns: base price (uint256).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
def get_base_price() -> uint256:
"""
@notice Price which corresponds to band 0.
Base price grows with time to account for interest rate (which is 0 by default)
@return Base price in units of borrowed token per collateral, multiplied by 1e18
"""
return self._base_price()


@internal
@view
def _p_oracle_up(n: int256) -> uint256:
"""
@notice Upper oracle price for the band to have liquidity when p = p_oracle
@param n Band number (can be negative)
@return Price at 1e18 base
"""
# p_oracle_up(n) = p_base * ((A - 1) / A) ** n
# p_oracle_down(n) = p_base * ((A - 1) / A) ** (n + 1) = p_oracle_up(n+1)
# return unsafe_div(self._base_price() * self.exp_int(-n * LOG_A_RATIO), 10**18)

power: int256 = -n * LOG_A_RATIO

# ((A - 1) / A) ** n = exp(-n * ln(A / (A - 1))) = exp(-n * LOG_A_RATIO)
exp_result: uint256 = convert(math._wad_exp(power), uint256)

assert exp_result > 1000 # dev: limit precision of the multiplier
return unsafe_div(self._base_price() * exp_result, WAD)


@internal
@view
def _p_current_band(n: int256) -> uint256:
"""
@notice Lowest possible price of the band at current oracle price
@param n Band number (can be negative)
# … the remaining implementation is linked above.
Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.get_base_price()

active_band

AMM.active_band() -> int256: view

Returns the index of the currently active band (the band where trading is happening).

Returns: active band index (int256).

<>Source code

The implementation is in AMM.vy at 0d726b1. This public ABI entry is compiler-generated or inherited; inspect the linked contract source and interfaces for its implementation.

Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.active_band()
await tx.wait()

active_band_with_skip

AMM.active_band_with_skip() -> int256: view

Returns the active band, skipping over empty bands for gas efficiency.

Returns: active band index (int256).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
@nonreentrant
def active_band_with_skip() -> int256:
n0: int256 = self.active_band
n: int256 = n0
min_band: int256 = self.min_band
for i: uint256 in range(MAX_SKIP_TICKS_UINT):
if n < min_band:
n = n0 - MAX_SKIP_TICKS
break
if self.bands_x[n] != 0:
break
n -= 1
return n


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.active_band_with_skip()

min_band

AMM.min_band() -> int256: view

Returns the lowest band index that has ever been used.

Returns: minimum band index (int256).

<>Source code

The implementation is in AMM.vy at 0d726b1. This public ABI entry is compiler-generated or inherited; inspect the linked contract source and interfaces for its implementation.

Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.min_band()
await tx.wait()

max_band

AMM.max_band() -> int256: view

Returns the highest band index that has ever been used.

Returns: maximum band index (int256).

<>Source code

The implementation is in AMM.vy at 0d726b1. This public ABI entry is compiler-generated or inherited; inspect the linked contract source and interfaces for its implementation.

Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.max_band()
await tx.wait()

p_current_up

AMM.p_current_up(_n: int256) -> uint256: view

Returns the upper price boundary of band _n, accounting for the current state of the band.

InputTypeDescription
_nint256Band index

Returns: upper price boundary (uint256).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
def p_current_up(n: int256) -> uint256:
"""
@notice Highest possible price of the band at current oracle price
@param n Band number (can be negative)
@return Price at 1e18 base
"""
return self._p_current_band(n + 1)


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.p_current_up(
/* _n: int256 */ 0n,
)

p_current_down

AMM.p_current_down(_n: int256) -> uint256: view

Returns the lower price boundary of band _n, accounting for the current state of the band.

InputTypeDescription
_nint256Band index

Returns: lower price boundary (uint256).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
def p_current_down(n: int256) -> uint256:
"""
@notice Lowest possible price of the band at current oracle price
@param n Band number (can be negative)
@return Price at 1e18 base
"""
return self._p_current_band(n)


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.p_current_down(
/* _n: int256 */ 0n,
)

p_oracle_up

AMM.p_oracle_up(_n: int256) -> uint256: view

Returns the upper boundary of band _n in the AMM's fixed price grid. Band numbers may be negative; higher band numbers correspond to lower prices, and positive bands lie to the left of the base price.

InputTypeDescription
_nint256Band index

Returns: upper oracle price (uint256).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
def p_oracle_up(n: int256) -> uint256:
"""
@notice Highest oracle price for the band to have liquidity when p = p_oracle
@param n Band number (can be negative)
@return Price at 1e18 base
"""
return self._p_oracle_up(n)


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.p_oracle_up(
/* _n: int256 */ 0n,
)

p_oracle_down

AMM.p_oracle_down(_n: int256) -> uint256: view

Returns the lower boundary of band _n in the AMM's fixed price grid. The boundaries are p_base * ((A - 1) / A) ** n and p_base * ((A - 1) / A) ** (n + 1) respectively.

InputTypeDescription
_nint256Band index

Returns: lower oracle price (uint256).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
def p_oracle_down(n: int256) -> uint256:
"""
@notice Lowest oracle price for the band to have liquidity when p = p_oracle
@param n Band number (can be negative)
@return Price at 1e18 base
"""
return self._p_oracle_up(n + 1)


@internal
@view
def _get_y0(x: uint256, y: uint256, p_o: uint256, p_o_up: uint256) -> uint256:
"""
@notice Calculate y0 for the invariant based on current liquidity in band.
The value of y0 has a meaning of amount of collateral when band has no borrowed tokens
but current price is equal to both oracle price and upper band price.
@param x Amount of borrowed in band
@param y Amount of collateral in band
@param p_o External oracle price
@param p_o_up Upper boundary of the band
@return y0
"""
assert p_o != 0
# solve:
# p_o * A * y0**2 - y0 * (p_oracle_up/p_o * (A-1) * x + p_o**2/p_oracle_up * A * y) - xy = 0
b: uint256 = 0
# p_o_up * unsafe_sub(A, 1) * x / p_o + A * p_o**2 / p_o_up * y / 10**18
if x != 0:
b = unsafe_div(p_o_up * Aminus1 * x, p_o)
if y != 0:
b += unsafe_div(A * p_o**2 // p_o_up * y, 10**18)
if x > 0 and y > 0:
D: uint256 = b**2 + unsafe_div((unsafe_mul(4, A) * p_o) * y, 10**18) * x
return unsafe_div((b + self.sqrt_int(D)) * 10**18, unsafe_mul(unsafe_mul(2, A), p_o))
else:
return unsafe_div(b * 10**18, unsafe_mul(A, p_o))
# … the remaining implementation is linked above.
Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.p_oracle_down(
/* _n: int256 */ 0n,
)

User Position Info

get_y_up

AMM.get_y_up(_user: address) -> uint256: view

Returns the amount of collateral token a user would have if the price goes up (full de-liquidation scenario).

InputTypeDescription
_useraddressUser address

Returns: collateral amount (uint256).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
@nonreentrant
def get_y_up(user: address) -> uint256:
"""
@notice Measure the amount of y (collateral) in the band n if we adiabatically trade near p_oracle on the way up
@param user User the amount is calculated for
@return Amount of coins
"""
return self.get_xy_up(user, True)


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.get_y_up(
/* _user: address */ "0x0000000000000000000000000000000000000000",
)

get_x_down

AMM.get_x_down(_user: address) -> uint256: view

Returns the amount of borrowed token a user would have if the price goes down (full soft-liquidation scenario).

InputTypeDescription
_useraddressUser address

Returns: borrowed token amount (uint256).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
@nonreentrant
def get_x_down(user: address) -> uint256:
"""
@notice Measure the amount of x (borrowed) if we trade adiabatically down
@param user User the amount is calculated for
@return Amount of coins
"""
return self.get_xy_up(user, False)

@internal
@view
def _get_xy(user: address, is_sum: bool) -> DynArray[uint256, MAX_TICKS_UINT][2]:
"""
@notice A low-gas function to measure amounts of borrowed and collateral tokens which user currently owns
@param user User address
@param is_sum Return sum or amounts by bands
@return Amounts of (borrowed, collateral) in a tuple
"""
xs: DynArray[uint256, MAX_TICKS_UINT] = []
ys: DynArray[uint256, MAX_TICKS_UINT] = []
if is_sum:
xs.append(0)
ys.append(0)
ns: int256[2] = self._read_user_tick_numbers(user)
ticks: DynArray[uint256, MAX_TICKS_UINT] = self._read_user_ticks(user, ns)
if ticks[0] != 0:
for i: uint256 in range(MAX_TICKS_UINT):
total_shares: uint256 = self.total_shares[ns[0]] + DEAD_SHARES
ds: uint256 = ticks[i]
dx: uint256 = unsafe_div((self.bands_x[ns[0]] + 1) * ds, total_shares)
dy: uint256 = unsafe_div((self.bands_y[ns[0]] + 1) * ds, total_shares)
if is_sum:
xs[0] += dx
ys[0] += dy
else:
xs.append(unsafe_div(dx, BORROWED_PRECISION))
# … the remaining implementation is linked above.
Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.get_x_down(
/* _user: address */ "0x0000000000000000000000000000000000000000",
)

get_sum_xy

AMM.get_sum_xy(_user: address) -> uint256[2]: view

Returns the total amounts of borrowed token and collateral token held in a user's bands.

InputTypeDescription
_useraddressUser address

Returns: [sum_x (borrowed), sum_y (collateral)] (uint256[2]).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
@nonreentrant
def get_sum_xy(user: address) -> uint256[2]:
"""
@notice A low-gas function to measure amounts of borrowed and collateral tokens which user currently owns
@param user User address
@return Amounts of (borrowed, collateral) in a tuple
"""
xy: DynArray[uint256, MAX_TICKS_UINT][2] = self._get_xy(user, True)
return [xy[0][0], xy[1][0]]

Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.get_sum_xy(
/* _user: address */ "0x0000000000000000000000000000000000000000",
)

get_xy

AMM.get_xy(_user: address) -> IController.UserTicks[]: view

Returns the per-band breakdown of a user's position — the amount of borrowed and collateral tokens in each band.

InputTypeDescription
_useraddressUser address

Returns: array of per-band positions (IController.UserTicks[]).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
@nonreentrant
def get_xy(user: address) -> DynArray[uint256, MAX_TICKS_UINT][2]:
"""
@notice A low-gas function to measure amounts of borrowed and collateral tokens by bands which user currently owns
@param user User address
@return Amounts of (borrowed, collateral) by bands in a tuple
"""
return self._get_xy(user, False)


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.get_xy(
/* _user: address */ "0x0000000000000000000000000000000000000000",
)

read_user_tick_numbers

AMM.read_user_tick_numbers(_user: address) -> int256[2]: view

Returns the upper and lower band indices of a user's position.

InputTypeDescription
_useraddressUser address

Returns: [n1, n2] (int256[2]), where n1 < n2 and the corresponding upper boundary is at a higher price than the lower boundary.

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
@nonreentrant
def read_user_tick_numbers(user: address) -> int256[2]:
"""
@notice Unpacks and reads user tick numbers
@param user User address
@return Lowest and highest band the user deposited into
"""
return self._read_user_tick_numbers(user)


@internal
@view
def _read_user_ticks(user: address, ns: int256[2]) -> DynArray[uint256, MAX_TICKS_UINT]:
"""
@notice Unpacks and reads user ticks (shares) for all the ticks user deposited into
@param user User address
@param ns Pair of band indices [n1, n2] defining the user's position range
@return Array of shares the user has
"""
ticks: DynArray[uint256, MAX_TICKS_UINT] = []
size: uint256 = convert(ns[1] - ns[0] + 1, uint256)
for i: uint256 in range(MAX_TICKS_UINT // 2):
if len(ticks) == size:
break
tick: uint256 = self._user_shares[user].ticks[i]
ticks.append(tick & (2**128 - 1))
if len(ticks) == size:
break
ticks.append(tick >> 128)
return ticks


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.read_user_tick_numbers(
/* _user: address */ "0x0000000000000000000000000000000000000000",
)

has_liquidity

AMM.has_liquidity(_user: address) -> bool: view

Returns whether a user has any liquidity deposited in the AMM.

InputTypeDescription
_useraddressUser address

Returns: has liquidity (bool).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
@nonreentrant
def has_liquidity(user: address) -> bool:
"""
@notice Check if `user` has any liquidity in the AMM
@param user Address of the user to check
@return True if the user has an active position, False otherwise
"""
return self._user_shares[user].ticks[0] != 0


@internal
def save_user_shares(user: address, user_shares: DynArray[uint256, MAX_TICKS_UINT]):
ptr: uint256 = 0
for j: uint256 in range(MAX_TICKS_UINT // 2):
if ptr >= len(user_shares):
break
tick: uint256 = user_shares[ptr]
ptr = unsafe_add(ptr, 1)
if len(user_shares) != ptr:
tick = tick | (user_shares[ptr] << 128)
ptr = unsafe_add(ptr, 1)
self._user_shares[user].ticks[j] = tick


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.has_liquidity(
/* _user: address */ "0x0000000000000000000000000000000000000000",
)

bands_x

AMM.bands_x(_n: int256) -> uint256: view

Returns the total amount of borrowed token in band _n, normalized to 18 decimals (not the token's native decimals).

InputTypeDescription
_nint256Band index

Returns: borrowed token amount in band (uint256).

<>Source code

The implementation is in AMM.vy at 0d726b1. This public ABI entry is compiler-generated or inherited; inspect the linked contract source and interfaces for its implementation.

Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.bands_x(
/* _n: int256 */ 0n,
)
await tx.wait()

bands_y

AMM.bands_y(_n: int256) -> uint256: view

Returns the total amount of collateral token in band _n, normalized to 18 decimals (not the token's native decimals).

InputTypeDescription
_nint256Band index

Returns: collateral token amount in band (uint256).

<>Source code

The implementation is in AMM.vy at 0d726b1. This public ABI entry is compiler-generated or inherited; inspect the linked contract source and interfaces for its implementation.

Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.bands_y(
/* _n: int256 */ 0n,
)
await tx.wait()

user_shares

AMM.user_shares(_user: address) -> UserTicks: view

Returns a user's share information across their deposited bands.

InputTypeDescription
_useraddressUser address

Returns: user tick/share info (UserTicks).

<>Source code

The implementation is in AMM.vy at 0d726b1. This public ABI entry is compiler-generated or inherited; inspect the linked contract source and interfaces for its implementation.

Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.user_shares(
/* _user: address */ "0x0000000000000000000000000000000000000000",
)
await tx.wait()

Rate and Fee

rate

AMM.rate() -> uint256: view

Returns the current interest rate stored in the AMM, set by the controller from the monetary policy.

Returns: current rate (uint256).

<>Source code

The implementation is in AMM.vy at 0d726b1. This public ABI entry is compiler-generated or inherited; inspect the linked contract source and interfaces for its implementation.

Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.rate()
await tx.wait()

get_rate_mul

AMM.get_rate_mul() -> uint256: view

Returns the current rate multiplier — a cumulative value that tracks how much the base price has shifted due to interest accrual.

Returns: rate multiplier (uint256).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
def get_rate_mul() -> uint256:
"""
@notice Rate multiplier which is 1.0 + integral(rate, dt)
@return Rate multiplier in units where 1.0 == 1e18
"""
return self._rate_mul()


@internal
@view
def _base_price() -> uint256:
"""
@notice Price which corresponds to band 0.
Base price grows with time to account for interest rate (which is 0 by default)
@return Base price in units of borrowed token per collateral, multiplied by 1e18
"""
return unsafe_div(BASE_PRICE * self._rate_mul(), 10**18)


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.get_rate_mul()

fee

AMM.fee() -> uint256: view

Returns the base AMM swap fee (the minimum fee before any dynamic component).

Returns: fee (uint256).

<>Source code

The implementation is in AMM.vy at 0d726b1. This public ABI entry is compiler-generated or inherited; inspect the linked contract source and interfaces for its implementation.

Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.fee()
await tx.wait()

Admin Methods

These functions are restricted to the AMM's admin, which is the LendController.

set_admin

AMM.set_admin(_admin: address)
Guarded Method

This function is only callable by the current admin (the LendController).

Transfers AMM admin to a new address.

InputTypeDescription
_adminaddressNew admin address
<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
def set_admin(_admin: address):
"""
@notice Set admin of the AMM. Typically it's a controller (unless it's tests)
@param _admin Admin address
"""
assert self.admin == empty(address)
self.admin = _admin
tkn.max_approve(BORROWED_TOKEN, _admin)
tkn.max_approve(COLLATERAL_TOKEN, _admin)


@internal
@pure
def sqrt_int(_x: uint256) -> uint256:
"""
@notice Wrapping isqrt builtin because otherwise it will be repeated every time instead of calling
@param _x Square root's input in "normal" units, e.g. sqrt_int(1) == 1
@return Integer square root of _x
"""
return isqrt(_x)


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.set_admin(
/* _admin: address */ "0x0000000000000000000000000000000000000000",
)
await tx.wait()

deposit_range

AMM.deposit_range(_user: address, _amount: uint256, _n1: int256, _n2: int256)
Guarded Method

This function is only callable by the admin (LendController). It is called internally when a loan is created or collateral is added.

Deposits collateral for a user across bands _n1 to _n2.

InputTypeDescription
_useraddressUser address
_amountuint256Collateral amount
_n1int256Upper band index
_n2int256Lower band index

Emits: Deposit event.

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@nonreentrant
def deposit_range(user: address, amount: uint256, n1: int256, n2: int256):
"""
@notice Deposit for a user in a range of bands. Only admin contract (Controller) can do it
@param user User address
@param amount Amount of collateral to deposit
@param n1 Lower band in the deposit range
@param n2 Upper band in the deposit range
"""
assert msg.sender == self.admin

user_shares: DynArray[uint256, MAX_TICKS_UINT] = []
collateral_shares: DynArray[uint256, MAX_TICKS_UINT] = []

n0: int256 = self.active_band

# We assume that n1,n2 area already sorted (and they are in Controller)
assert n2 < 2**127
assert n1 > -2**127

n_bands: uint256 = unsafe_add(convert(unsafe_sub(n2, n1), uint256), 1)
assert n_bands <= MAX_TICKS_UINT

y_per_band: uint256 = unsafe_div(amount * COLLATERAL_PRECISION, n_bands)
assert y_per_band > 100, "Amount too low"

assert self._user_shares[user].ticks[0] == 0 # dev: User must have no liquidity
self._user_shares[user].ns = unsafe_add(n1, unsafe_mul(n2, 2**128))

lm: ILMCallback = self._liquidity_mining_callback

# Autoskip bands if we can
for i: uint256 in range(MAX_SKIP_TICKS_UINT + 1):
if n1 > n0:
if i != 0:
self.active_band = n0
break
# … the remaining implementation is linked above.
Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.deposit_range(
/* _user: address */ "0x0000000000000000000000000000000000000000",
/* _amount: uint256 */ 0n,
/* _n1: int256 */ 0n,
/* _n2: int256 */ 0n,
)
await tx.wait()

withdraw

AMM.withdraw(_user: address, _frac: uint256) -> uint256[2]
Guarded Method

This function is only callable by the admin (LendController). It is called internally during repayment and liquidation.

Withdraws a fraction of a user's position from the AMM. A _frac of 10**18 means full withdrawal.

InputTypeDescription
_useraddressUser address
_fracuint256Fraction to withdraw (scaled by 1e18)

Returns: [withdrawn_borrowed, withdrawn_collateral] (uint256[2]).

Emits: Withdraw event.

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@nonreentrant
def withdraw(user: address, frac: uint256) -> uint256[2]:
"""
@notice Withdraw liquidity for the user. Only admin contract can do it
@param user User who owns liquidity
@param frac Fraction to withdraw (1e18 being 100%)
@return Amount of [borrowed, collateral] withdrawn
"""
assert msg.sender == self.admin
assert frac <= 10**18

lm: ILMCallback = self._liquidity_mining_callback

ns: int256[2] = self._read_user_tick_numbers(user)
n: int256 = ns[0]
old_user_shares: DynArray[uint256, MAX_TICKS_UINT] = self._read_user_ticks(user, ns)
user_shares: DynArray[uint256, MAX_TICKS_UINT] = old_user_shares
assert user_shares[0] > 0, "No deposits"

total_x: uint256 = 0
total_y: uint256 = 0
min_band: int256 = self.min_band
old_min_band: int256 = min_band
old_max_band: int256 = self.max_band
max_band: int256 = n - 1

for i: uint256 in range(MAX_TICKS_UINT):
x: uint256 = self.bands_x[n]
y: uint256 = self.bands_y[n]
ds: uint256 = unsafe_div(frac * user_shares[i], 10**18)
user_shares[i] = unsafe_sub(user_shares[i], ds) # Can ONLY zero out when frac == 10**18
s: uint256 = self.total_shares[n]
new_shares: uint256 = s - ds
self.total_shares[n] = new_shares
s += DEAD_SHARES # after this s is guaranteed to be bigger than 0
dx: uint256 = unsafe_div((x + 1) * ds, s)
dy: uint256 = unsafe_div((y + 1) * ds, s)
# … the remaining implementation is linked above.
Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.withdraw(
/* _user: address */ "0x0000000000000000000000000000000000000000",
/* _frac: uint256 */ 0n,
)
await tx.wait()

set_rate

AMM.set_rate(_rate: uint256) -> uint256
Guarded Method

This function is only callable by the admin (LendController).

Sets the interest rate in the AMM and returns the updated rate multiplier.

InputTypeDescription
_rateuint256New rate value

Returns: updated rate multiplier (uint256).

Emits: SetRate event.

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@nonreentrant
def set_rate(rate: uint256) -> uint256:
"""
@notice Set interest rate. That affects the dependence of AMM base price over time
@param rate New rate in units of int(fraction * 1e18) per second
@return rate_mul multiplier (e.g. 1.0 + integral(rate, dt))
"""
assert msg.sender == self.admin
rate_mul: uint256 = self._rate_mul()
self.rate_mul = rate_mul
self.rate_time = block.timestamp
self.rate = rate
log IAMM.SetRate(rate=rate, rate_mul=rate_mul, time=block.timestamp)
return rate_mul


@internal
def _set_fee(_fee: uint256):
assert _fee >= MIN_FEE and _fee <= MAX_FEE # dev: fee is out of bounds
self.fee = _fee


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.set_rate(
/* _rate: uint256 */ 0n,
)
await tx.wait()

set_fee

AMM.set_fee(_fee: uint256)
Guarded Method

This function is only callable by the admin (LendController).

Sets the swap fee.

InputTypeDescription
_feeuint256New fee value

Emits: SetFee event.

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@nonreentrant
def set_fee(fee: uint256):
"""
@notice Set AMM fee
@param fee Fee where 1e18 == 100%
"""
assert msg.sender == self.admin
self._set_fee(fee)


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.set_fee(
/* _fee: uint256 */ 0n,
)
await tx.wait()

set_price_oracle

AMM.set_price_oracle(_price_oracle: address)
Guarded Method

This function is only callable by the admin (LendController).

Sets the external price oracle contract.

InputTypeDescription
_price_oracleaddressNew oracle address

Emits: SetPriceOracle event.

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@nonreentrant
def set_price_oracle(_price_oracle: IPriceOracle):
"""
@notice Set a new price oracle contract. Can only be called by admin (Controller)
@param _price_oracle New price oracle contract
"""
assert msg.sender == self.admin
self._price_oracle = _price_oracle

Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.set_price_oracle(
/* _price_oracle: address */ "0x0000000000000000000000000000000000000000",
)
await tx.wait()

set_callback

AMM.set_callback(_liquidity_mining_callback: address)
Guarded Method

This function is only callable by the admin (LendController).

Sets the liquidity mining callback (gauge) address.

InputTypeDescription
_liquidity_mining_callbackaddressCallback address
<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@nonreentrant
def set_callback(liquidity_mining_callback: ILMCallback):
"""
@notice Set a gauge address with callbacks for liquidity mining for collateral
@param liquidity_mining_callback Gauge address
"""
assert msg.sender == self.admin # dev: admin only
self._liquidity_mining_callback = liquidity_mining_callback


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.set_callback(
/* _liquidity_mining_callback: address */ "0x0000000000000000000000000000000000000000",
)
await tx.wait()

Other Methods

coins

AMM.coins(_i: uint256) -> address: view

Returns the token address at index _i (0 = borrowed token, 1 = collateral token).

InputTypeDescription
_iuint256Token index (0 or 1)

Returns: token address (address).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
def coins(i: uint256) -> address:
return [BORROWED_TOKEN.address, COLLATERAL_TOKEN.address][i]


@internal
@view
def limit_p_o(p: uint256) -> uint256[2]:
"""
@notice Limits oracle price to avoid losses at abrupt changes, as well as calculates a dynamic fee.
If we consider oracle_change such as:
ratio = p_new / p_old
(let's take for simplicity p_new < p_old, otherwise we compute p_old / p_new)
Then if the minimal AMM fee will be:
fee = (1 - ratio**3),
AMM will not have a loss associated with the price change.
However, over time fee should still go down (over PREV_P_O_DELAY), and also ratio should be limited
because we don't want the fee to become too large (say, 50%) which is achieved by limiting the instantaneous
change in oracle price.
@param p Current oracle price
@return (limited_price_oracle, dynamic_fee)
"""
p_new: uint256 = p
dt: uint256 = unsafe_sub(PREV_P_O_DELAY, min(PREV_P_O_DELAY, block.timestamp - self.prev_p_o_time))
ratio: uint256 = 0

# ratio = 1 - (p_o_min / p_o_max)**3

if dt > 0:
old_p_o: uint256 = self.old_p_o
# ratio = p_o_min / p_o_max
if p > old_p_o:
ratio = unsafe_div(old_p_o * 10**18, p)
if ratio < 10**36 // MAX_P_O_CHG:
p_new = unsafe_div(old_p_o * MAX_P_O_CHG, 10**18)
ratio = 10**36 // MAX_P_O_CHG
else:
# … the remaining implementation is linked above.
Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.coins(
/* _i: uint256 */ 0n,
)

A

AMM.A() -> uint256: view

Returns the band-width factor. Band width is approximately 1/A.

Returns: band-width factor (uint256).

<>Source code

The implementation is in AMM.vy at 0d726b1. This public ABI entry is compiler-generated or inherited; inspect the linked contract source and interfaces for its implementation.

Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.A()
await tx.wait()

admin

AMM.admin() -> address: view

Returns the admin address (the LendController).

Returns: admin address (address).

<>Source code

The implementation is in AMM.vy at 0d726b1. This public ABI entry is compiler-generated or inherited; inspect the linked contract source and interfaces for its implementation.

Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, signer)
const tx = await contract.admin()
await tx.wait()

can_skip_bands

AMM.can_skip_bands(_n_end: int256) -> bool: view

Returns whether bands up to _n_end can be skipped (are empty) during traversal.

InputTypeDescription
_n_endint256Target band index

Returns: whether bands can be skipped (bool).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@external
@view
@nonreentrant
def can_skip_bands(n_end: int256) -> bool:
"""
@notice Check that we have no liquidity between active_band and `n_end`
@param n_end Band index to check up to (not inclusive)
@return True if no liquidity exists between active_band and n_end, False otherwise
"""
n: int256 = self.active_band
for i: uint256 in range(MAX_SKIP_TICKS_UINT):
if n_end > n:
if self.bands_y[n] != 0:
return False
n = unsafe_add(n, 1)
else:
if self.bands_x[n] != 0:
return False
n = unsafe_sub(n, 1)
if n == n_end: # not including n_end
return True
raise "Too deep"
# Actually skipping bands:
# * change self.active_band to the new n
# * change self.p_base_mul
# to do n2-n1 times (if n2 > n1):
# out.base_mul = unsafe_div(out.base_mul * Aminus1, A)


Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.can_skip_bands(
/* _n_end: int256 */ 0n,
)

liquidity_mining_callback

AMM.liquidity_mining_callback() -> address: view

Returns the liquidity mining callback (gauge) address.

Returns: callback address (address).

<>Source code

Excerpt from AMM.vy at 0d726b1:

@view
@external
def liquidity_mining_callback() -> ILMCallback:
return self._liquidity_mining_callback


@deploy
def __init__(
_borrowed_token: IERC20,
_borrowed_precision: uint256,
_collateral_token: IERC20,
_collateral_precision: uint256,
_A: uint256,
_sqrt_band_ratio: uint256,
_log_A_ratio: int256,
_base_price: uint256,
_fee: uint256,
_admin_fee: uint256,
_price_oracle: IPriceOracle,
):
"""
@notice LLAMMA constructor
@param _borrowed_token Token which is being borrowed
@param _borrowed_precision Precision of borrowed token: we pass it because we want the blueprint to fit into bytecode
@param _collateral_token Token used as collateral
@param _collateral_precision Precision of collateral: we pass it because we want the blueprint to fit into bytecode
@param _A "Amplification coefficient" which also defines density of liquidity and band size. Relative band size is 1/_A
@param _sqrt_band_ratio Precomputed int(sqrt(A / (A - 1)) * 1e18)
@param _log_A_ratio Precomputed int(ln(A / (A - 1)) * 1e18)
@param _base_price Typically the initial crypto price at which AMM is deployed. Will correspond to band 0
@param _fee Relative fee of the AMM: int(fee * 1e18)
@param _admin_fee DEPRECATED, left for backward compatibility
@param _price_oracle External price oracle which has price() and price_w() methods
which both return current price of collateral multiplied by 1e18
"""
BORROWED_TOKEN = _borrowed_token
BORROWED_PRECISION = _borrowed_precision
COLLATERAL_TOKEN = _collateral_token
# … the remaining implementation is linked above.
Example
const contract = new Contract('0xbf6f64b741164c26023f97faaea8e02453c27442', AMMAbi, provider)
const result = await contract.liquidity_mining_callback()