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.vyExamples 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.
| Input | Type | Description |
|---|---|---|
i | uint256 | Input token index (0 = borrowed, 1 = collateral) |
j | uint256 | Output token index |
in_amount | uint256 | Amount of input token |
min_amount | uint256 | Minimum output amount (slippage protection) |
_for | address | Address 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.
| Input | Type | Description |
|---|---|---|
i | uint256 | Input token index |
j | uint256 | Output token index |
out_amount | uint256 | Desired output amount |
max_amount | uint256 | Maximum input amount (slippage protection) |
_for | address | Address 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: viewCalculates the output amount for a given input amount (i.e., a swap quote).
| Input | Type | Description |
|---|---|---|
i | uint256 | Input token index |
j | uint256 | Output token index |
in_amount | uint256 | Input 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: viewCalculates the input amount needed to receive a given output amount.
| Input | Type | Description |
|---|---|---|
i | uint256 | Input token index |
j | uint256 | Output token index |
out_amount | uint256 | Desired 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]: viewReturns both the input amount used and the output amount for a given swap.
| Input | Type | Description |
|---|---|---|
i | uint256 | Input token index |
j | uint256 | Output token index |
in_amount | uint256 | Input 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]: viewReturns both the output amount and the input amount needed for a given desired output.
| Input | Type | Description |
|---|---|---|
i | uint256 | Input token index |
j | uint256 | Output token index |
out_amount | uint256 | Desired 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): viewReturns the amount and swap direction needed to move the AMM price to _p.
| Input | Type | Description |
|---|---|---|
_p | uint256 | Target 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: viewReturns 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: viewReturns 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: viewReturns 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: viewReturns 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: viewReturns 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: viewReturns 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: viewReturns 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: viewReturns 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: viewReturns the upper price boundary of band _n, accounting for the current state of the band.
| Input | Type | Description |
|---|---|---|
_n | int256 | Band 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: viewReturns the lower price boundary of band _n, accounting for the current state of the band.
| Input | Type | Description |
|---|---|---|
_n | int256 | Band 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: viewReturns 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.
| Input | Type | Description |
|---|---|---|
_n | int256 | Band 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: viewReturns 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.
| Input | Type | Description |
|---|---|---|
_n | int256 | Band 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: viewReturns the amount of collateral token a user would have if the price goes up (full de-liquidation scenario).
| Input | Type | Description |
|---|---|---|
_user | address | User 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: viewReturns the amount of borrowed token a user would have if the price goes down (full soft-liquidation scenario).
| Input | Type | Description |
|---|---|---|
_user | address | User 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]: viewReturns the total amounts of borrowed token and collateral token held in a user's bands.
| Input | Type | Description |
|---|---|---|
_user | address | User 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[]: viewReturns the per-band breakdown of a user's position — the amount of borrowed and collateral tokens in each band.
| Input | Type | Description |
|---|---|---|
_user | address | User 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]: viewReturns the upper and lower band indices of a user's position.
| Input | Type | Description |
|---|---|---|
_user | address | User 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: viewReturns whether a user has any liquidity deposited in the AMM.
| Input | Type | Description |
|---|---|---|
_user | address | User 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: viewReturns the total amount of borrowed token in band _n, normalized to 18 decimals (not the token's native decimals).
| Input | Type | Description |
|---|---|---|
_n | int256 | Band 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: viewReturns the total amount of collateral token in band _n, normalized to 18 decimals (not the token's native decimals).
| Input | Type | Description |
|---|---|---|
_n | int256 | Band 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: viewReturns a user's share information across their deposited bands.
| Input | Type | Description |
|---|---|---|
_user | address | User 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: viewReturns 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: viewReturns 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: viewReturns 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)This function is only callable by the current admin (the LendController).
Transfers AMM admin to a new address.
| Input | Type | Description |
|---|---|---|
_admin | address | New 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)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.
| Input | Type | Description |
|---|---|---|
_user | address | User address |
_amount | uint256 | Collateral amount |
_n1 | int256 | Upper band index |
_n2 | int256 | Lower 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]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.
| Input | Type | Description |
|---|---|---|
_user | address | User address |
_frac | uint256 | Fraction 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) -> uint256This function is only callable by the admin (LendController).
Sets the interest rate in the AMM and returns the updated rate multiplier.
| Input | Type | Description |
|---|---|---|
_rate | uint256 | New 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)This function is only callable by the admin (LendController).
Sets the swap fee.
| Input | Type | Description |
|---|---|---|
_fee | uint256 | New 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)This function is only callable by the admin (LendController).
Sets the external price oracle contract.
| Input | Type | Description |
|---|---|---|
_price_oracle | address | New 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)This function is only callable by the admin (LendController).
Sets the liquidity mining callback (gauge) address.
| Input | Type | Description |
|---|---|---|
_liquidity_mining_callback | address | Callback 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: viewReturns the token address at index _i (0 = borrowed token, 1 = collateral token).
| Input | Type | Description |
|---|---|---|
_i | uint256 | Token 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: viewReturns 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: viewReturns 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: viewReturns whether bands up to _n_end can be skipped (are empty) during traversal.
| Input | Type | Description |
|---|---|---|
_n_end | int256 | Target 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: viewReturns 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()