LendController
The LendController is the primary user-facing contract for each lending market. Borrowers interact with it to create loans, manage collateral, borrow more, repay, and get liquidated. It wraps the core controller.vy module — which contains all shared loan logic — and extends it with lending-specific features: borrow caps, vault token transfers, and available balance tracking.
Each lending market gets its own LendController instance, deployed by the LendFactory.
LendController.vyThe source code for the LendController.vy contract can be found on GitHub. The core module is controller.vy. 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.
The LendController exports most of its functions from the controller.vy module. Functions documented below include both module-exported functions and lending-specific extensions. The module pattern means the core loan logic is shared with MintController (used for crvUSD mint markets).
Loan Management
create_loan
LendController.create_loan(_collateral: uint256, _debt: uint256, _N: uint256, _for: address = msg.sender, _callbacker: address = empty(address), _calldata: Bytes[CALLDATA_MAX_SIZE] = b"")Creates a new loan by depositing collateral and borrowing tokens. The collateral is distributed across _N bands in the AMM.
| Input | Type | Description |
|---|---|---|
_collateral | uint256 | Amount of collateral to deposit |
_debt | uint256 | Amount of borrowed tokens to receive |
_N | uint256 | Number of bands to distribute collateral across (4–50) |
_for | address | Address that owns the new loan |
_callbacker | address | Optional callback contract for leveraged operations |
_calldata | Bytes[CALLDATA_MAX_SIZE] | Data passed to the callback contract |
Emits: Borrow event.
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
def create_loan(
_collateral: uint256,
_debt: uint256,
_N: uint256,
_for: address = msg.sender,
_callbacker: address = empty(address),
_calldata: Bytes[CALLDATA_MAX_SIZE] = b"",
):
"""
@notice Create loan but pass borrowed tokens to a callback first so that it can build leverage
@param _collateral Amount of collateral to use
@param _debt Borrowed asset debt to take
@param _N Number of bands to deposit into (to do autoliquidation-deliquidation),
can be from MIN_TICKS to MAX_TICKS
@param _for Address to create the loan for
@param _callbacker Address of the callback contract
@param _calldata Any data for callbacker
"""
assert self._has_approval(_for)
more_collateral: uint256 = 0
if _callbacker != empty(address):
tkn.transfer(BORROWED_TOKEN, _callbacker, _debt)
# If there is any unused debt, callbacker can send it to the user
cb: IController.CallbackData = self._execute_callback(
_callbacker,
CALLBACK_DEPOSIT,
_for,
0,
_collateral,
_debt,
_calldata,
)
assert cb.borrowed == 0 # dev: Not available
more_collateral = cb.collateral
total_collateral: uint256 = _collateral + more_collateral
# … the remaining implementation is linked above.
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, signer)
const tx = await contract.create_loan(
/* _collateral: uint256 */ 0n,
/* _debt: uint256 */ 0n,
/* _N: uint256 */ 0n,
/* _for: address */ "0x0000000000000000000000000000000000000000",
/* _callbacker: address */ "0x0000000000000000000000000000000000000000",
/* _calldata: Bytes[CALLDATA_MAX_SIZE] */ 0n,
)
await tx.wait()
borrow_more
LendController.borrow_more(_collateral: uint256, _debt: uint256, _for: address = msg.sender, _callbacker: address = empty(address), _calldata: Bytes[CALLDATA_MAX_SIZE] = b"")Adds additional collateral and/or borrows more tokens against an existing loan.
| Input | Type | Description |
|---|---|---|
_collateral | uint256 | Additional collateral to deposit (can be 0) |
_debt | uint256 | Additional debt to take on (can be 0) |
_for | address | Address that owns the loan |
_callbacker | address | Optional callback contract for leveraged operations |
_calldata | Bytes[CALLDATA_MAX_SIZE] | Data passed to the callback contract |
Emits: Borrow event.
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
def borrow_more(
_collateral: uint256,
_debt: uint256,
_for: address = msg.sender,
_callbacker: address = empty(address),
_calldata: Bytes[CALLDATA_MAX_SIZE] = b"",
):
"""
@notice Borrow more borrowed tokens while adding more collateral using a callback (to leverage more)
@param _collateral Amount of collateral to add
@param _debt Amount of borrowed asset debt to take
@param _for Address to borrow for
@param _callbacker Address of the callback contract
@param _calldata Any data for callbacker
"""
if _debt == 0:
return
assert self._has_approval(_for)
more_collateral: uint256 = 0
if _callbacker != empty(address):
tkn.transfer(BORROWED_TOKEN, _callbacker, _debt)
# If there is any unused debt, callbacker can send it to the user
cb: IController.CallbackData = self._execute_callback(
_callbacker,
CALLBACK_DEPOSIT,
_for,
0,
_collateral,
_debt,
_calldata,
)
assert cb.borrowed == 0 # dev: Not available
more_collateral = cb.collateral
rate_mul: uint256 = self._add_collateral_borrow(
_collateral + more_collateral, _debt, _for, False
# … the remaining implementation is linked above.
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, signer)
const tx = await contract.borrow_more(
/* _collateral: uint256 */ 0n,
/* _debt: uint256 */ 0n,
/* _for: address */ "0x0000000000000000000000000000000000000000",
/* _callbacker: address */ "0x0000000000000000000000000000000000000000",
/* _calldata: Bytes[CALLDATA_MAX_SIZE] */ 0n,
)
await tx.wait()
add_collateral
LendController.add_collateral(_collateral: uint256, _for: address = msg.sender)Adds collateral to an existing loan without borrowing more. The borrower must call it directly or authorize the caller.
| Input | Type | Description |
|---|---|---|
_collateral | uint256 | Amount of collateral to add |
_for | address | Address of the borrower to add collateral for |
Emits: Borrow event.
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
def add_collateral(_collateral: uint256, _for: address = msg.sender):
"""
@notice Add extra collateral to avoid bad liquidations
@param _collateral Amount of collateral to add
@param _for Address to add collateral for
"""
if _collateral == 0:
return
assert self._has_approval(_for)
self._add_collateral_borrow(_collateral, 0, _for, False)
tkn.transfer_from(COLLATERAL_TOKEN, msg.sender, AMM.address, _collateral)
self._save_rate()
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, signer)
const tx = await contract.add_collateral(
/* _collateral: uint256 */ 0n,
/* _for: address */ "0x0000000000000000000000000000000000000000",
)
await tx.wait()
remove_collateral
LendController.remove_collateral(_collateral: uint256, _for: address = msg.sender)Removes collateral from an existing loan. Reverts if the resulting health would be too low.
| Input | Type | Description |
|---|---|---|
_collateral | uint256 | Amount of collateral to remove |
_for | address | Address that owns the loan; the caller must be authorized |
Emits: RemoveCollateral event.
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
def remove_collateral(_collateral: uint256, _for: address = msg.sender):
"""
@notice Remove some collateral without repaying the debt
@param _collateral Amount of collateral to remove
@param _for Address to remove collateral for
"""
if _collateral == 0:
return
assert self._has_approval(_for)
self._add_collateral_borrow(_collateral, 0, _for, True)
tkn.transfer_from(COLLATERAL_TOKEN, AMM.address, _for, _collateral)
self._save_rate()
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, signer)
const tx = await contract.remove_collateral(
/* _collateral: uint256 */ 0n,
/* _for: address */ "0x0000000000000000000000000000000000000000",
)
await tx.wait()
repay
LendController.repay(_wallet_d_debt: uint256, _for: address = msg.sender, _max_active_band: int256 = max_value(int256), _callbacker: address = empty(address), _calldata: Bytes[CALLDATA_MAX_SIZE] = b"", _shrink: bool = False)Repays debt for a loan. If _wallet_d_debt exceeds the current debt, only the outstanding debt is repaid. The borrower must call it directly or authorize the caller.
| Input | Type | Description |
|---|---|---|
_wallet_d_debt | uint256 | Amount of debt to repay from the wallet (use max_value(uint256) to repay all) |
_for | address | Address of the borrower to repay for |
_max_active_band | int256 | Maximum active band accepted for the repayment |
_callbacker | address | Optional callback contract |
_calldata | Bytes[CALLDATA_MAX_SIZE] | Data passed to the callback contract |
_shrink | bool | Whether to shrink a soft-liquidated position |
Emits: Repay event.
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
def repay(
_wallet_d_debt: uint256,
_for: address = msg.sender,
_max_active_band: int256 = max_value(int256),
_callbacker: address = empty(address),
_calldata: Bytes[CALLDATA_MAX_SIZE] = b"",
_shrink: bool = False
):
"""
@notice Repay debt (partially or fully)
@param _wallet_d_debt The amount of debt to repay from user's wallet.
If it's max_value(uint256) or just higher than the current debt - will do full repayment.
@param _for The user to repay the debt for
@param _max_active_band Don't allow active band to be higher than this (to prevent front-running the repay)
@param _callbacker Address of the callback contract
@param _calldata Any data for callbacker
@param _shrink Whether shrink soft-liquidated part of the position or not
"""
assert self._has_approval(_for)
debt: uint256 = 0
rate_mul: uint256 = 0
debt, rate_mul = self._debt(_for)
self._check_loan_exists(debt)
xy: uint256[2] = staticcall AMM.get_sum_xy(_for)
cb: IController.CallbackData = empty(IController.CallbackData)
if _callbacker != empty(address):
xy = extcall AMM.withdraw(_for, WAD)
tkn.transfer_from(COLLATERAL_TOKEN, AMM.address, _callbacker, xy[1])
cb = self._execute_callback(
_callbacker, CALLBACK_REPAY, _for, xy[0], xy[1], debt, _calldata
)
d_debt: uint256 = min(min(_wallet_d_debt, debt) + xy[0] + cb.borrowed, debt)
assert d_debt > 0 # dev: no coins to repay
if d_debt == debt:
# … the remaining implementation is linked above.
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, signer)
const tx = await contract.repay(
/* _wallet_d_debt: uint256 */ 0n,
/* _for: address */ "0x0000000000000000000000000000000000000000",
/* _max_active_band: int256 */ 0n,
/* _callbacker: address */ "0x0000000000000000000000000000000000000000",
/* _calldata: Bytes[CALLDATA_MAX_SIZE] */ 0n,
/* _shrink: bool */ false,
)
await tx.wait()
liquidate
LendController.liquidate(_user: address, _min_x: uint256, _frac: uint256 = 10**18, _callbacker: address = empty(address), _calldata: Bytes[CALLDATA_MAX_SIZE] = b"")Liquidates an unhealthy loan (health < 0). The caller repays the debt and receives the remaining collateral. Supports partial liquidation if the position is partially in soft liquidation.
| Input | Type | Description |
|---|---|---|
_user | address | Address of the borrower to liquidate |
_min_x | uint256 | Minimum amount of collateral to receive (slippage protection) |
_frac | uint256 | Fraction of the position to liquidate, where 10**18 is 100% |
_callbacker | address | Optional callback contract |
_calldata | Bytes[CALLDATA_MAX_SIZE] | Data passed to the callback contract |
Emits: Liquidate event.
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
def liquidate(
_user: address,
_min_x: uint256,
_frac: uint256 = 10**18,
_callbacker: address = empty(address),
_calldata: Bytes[CALLDATA_MAX_SIZE] = b"",
):
"""
@notice Perform a bad liquidation (or self-liquidation) of user if health is not good
@param _user Address of the user to liquidate
@param _min_x Minimal amount of borrowed asset to receive (to avoid liquidators being sandwiched)
@param _frac Fraction to liquidate; 100% = 10**18
@param _callbacker Address of the callback contract
@param _calldata Any data for callbacker
"""
approval: bool = self._has_approval(_user)
liquidation_discount: uint256 = self.liquidation_discounts[_user]
debt: uint256 = 0
rate_mul: uint256 = 0
debt, rate_mul = self._debt(_user)
health_before: int256 = self._health(_user, debt, True, liquidation_discount)
health_limit: uint256 = 0
if not approval:
assert health_before < 0, "Not enough rekt"
health_limit = liquidation_discount
final_debt: uint256 = debt
assert _frac <= WAD, "frac>100%"
debt = unsafe_div(debt * _frac + (WAD - 1), WAD)
assert debt > 0
final_debt = unsafe_sub(final_debt, debt)
# If liquidating entire debt, ensure full collateral withdrawal
f_remove: uint256 = self._get_f_remove(_frac, health_limit)
if final_debt == 0:
f_remove = WAD
# … the remaining implementation is linked above.
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, signer)
const tx = await contract.liquidate(
/* _user: address */ "0x0000000000000000000000000000000000000000",
/* _min_x: uint256 */ 0n,
/* _frac: uint256 */ 0n,
/* _callbacker: address */ "0x0000000000000000000000000000000000000000",
/* _calldata: Bytes[CALLDATA_MAX_SIZE] */ 0n,
)
await tx.wait()
Loan Info
debt
LendController.debt(_user: address) -> uint256: viewReturns the current debt of a user, including accrued interest.
| Input | Type | Description |
|---|---|---|
_user | address | Borrower address |
Returns: current debt (uint256).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
def debt(_user: address) -> uint256:
"""
@notice Get the value of debt without changing the state
@param _user User address
@return Value of debt
"""
return self._debt(_user)[0]
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.debt(
/* _user: address */ "0x0000000000000000000000000000000000000000",
)
health
LendController.health(_user: address, _full: bool = False) -> int256: viewReturns the health of a user's loan. Health > 0 means the loan is safe; health < 0 means it can be liquidated. If _full is true, the calculation also accounts for an oracle-price difference above the user's highest band when the position is not in soft liquidation. If false, it calculates health as for a user in soft-liquidation mode.
| Input | Type | Description |
|---|---|---|
_user | address | Borrower address |
_full | bool | If true, use full (pessimistic) health calculation |
Returns: health value (int256).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
def health(_user: address, _full: bool = False) -> int256:
"""
@notice Returns position health normalized to 1e18 for the user.
Liquidation starts when < 0, however devaluation of collateral doesn't cause liquidation
@param _user Address of the user
@param _full If True, use the full health calculation including bad debt discounts
@return Health value normalized to 1e18
"""
return self._health(
_user, self._debt(_user)[0], _full, self.liquidation_discounts[_user]
)
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.health(
/* _user: address */ "0x0000000000000000000000000000000000000000",
/* _full: bool */ false,
)
loan_exists
LendController.loan_exists(_user: address) -> bool: viewReturns whether a loan exists for the given user.
| Input | Type | Description |
|---|---|---|
_user | address | Borrower address |
Returns: whether the loan exists (bool).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
def loan_exists(_user: address) -> bool:
"""
@notice Check whether there is a loan of `user` in existence
@param _user Address of the user to check
@return True if the user has an active loan, False otherwise
"""
return self.loan[_user].initial_debt > 0
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.loan_exists(
/* _user: address */ "0x0000000000000000000000000000000000000000",
)
user_state
LendController.user_state(_user: address) -> uint256[4]: viewReturns the full state of a user's loan: [collateral, borrowed, debt, N].
| Input | Type | Description |
|---|---|---|
_user | address | Borrower address |
Returns: [collateral, borrowed, debt, N] (uint256[4]).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
def user_state(_user: address) -> uint256[4]:
"""
@notice Return the user state in one call
@param _user User to return the state for
@return (collateral, borrowed, debt, N)
"""
return staticcall self._view.user_state(_user)
@internal
def _configure(
_loan_discount: uint256,
_liquidation_discount: uint256,
_monetary_policy: IMonetaryPolicy,
_view_blueprint: address,
_fee: uint256,
_price_oracle: IPriceOracle,
_liquidity_mining_callback: ILMCallback,
):
if _loan_discount != SKIP_CONFIG_UINT256 and _liquidation_discount != SKIP_CONFIG_UINT256:
self.loan_discount = _loan_discount
self.liquidation_discount = _liquidation_discount
if _monetary_policy.address != SKIP_CONFIG_ADDRESS:
self._monetary_policy = _monetary_policy
if _view_blueprint != SKIP_CONFIG_ADDRESS:
view: address = create_from_blueprint(
_view_blueprint,
self,
SQRT_BAND_RATIO,
LOGN_A_RATIO,
AMM,
A,
COLLATERAL_TOKEN,
COLLATERAL_PRECISION,
BORROWED_TOKEN,
BORROWED_PRECISION,
# … the remaining implementation is linked above.
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.user_state(
/* _user: address */ "0x0000000000000000000000000000000000000000",
)
user_prices
LendController.user_prices(_user: address) -> uint256[2]: viewReturns the upper and lower price bounds of a user's collateral bands in the AMM.
| Input | Type | Description |
|---|---|---|
_user | address | Borrower address |
Returns: [price_upper, price_lower] (uint256[2]).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
def user_prices(_user: address) -> uint256[2]: # Upper, lower
"""
@notice Lowest price of the lower band and highest price of the upper band the user has deposit in the AMM
@param _user User address
@return (upper_price, lower_price)
"""
return staticcall self._view.user_prices(_user)
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.user_prices(
/* _user: address */ "0x0000000000000000000000000000000000000000",
)
users_to_liquidate
LendController.users_to_liquidate(_from: uint256 = 0, _limit: uint256 = 0) -> IController.Position[]: viewReturns a list of user positions that can be liquidated, paginated.
| Input | Type | Description |
|---|---|---|
_from | uint256 | Starting index |
_limit | uint256 | Maximum number of positions to return |
Returns: array of liquidatable positions (IController.Position[]).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
def users_to_liquidate(
_from: uint256 = 0, _limit: uint256 = 0
) -> DynArray[IController.Position, 1000]:
"""
@notice Returns a dynamic array of users who can be "hard-liquidated".
This method is designed for convenience of liquidation bots.
@param _from Loan index to start iteration from
@param _limit Number of loans to look over
@return Dynamic array with detailed info about positions of users
"""
return staticcall self._view.users_to_liquidate(_from, _limit)
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.users_to_liquidate(
/* _from: uint256 */ 0n,
/* _limit: uint256 */ 0n,
)
tokens_to_liquidate
LendController.tokens_to_liquidate(_user: address, _frac: uint256 = 10**18) -> uint256: viewReturns the amount of borrowed tokens needed to fully liquidate a user's position.
| Input | Type | Description |
|---|---|---|
_user | address | Borrower address |
_frac | uint256 | Fraction to liquidate, where 10**18 is 100% |
Returns: tokens needed for liquidation (uint256).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
def tokens_to_liquidate(_user: address, _frac: uint256 = WAD) -> uint256:
"""
@notice Calculate the amount of borrowed asset to have in liquidator's wallet to liquidate a user
@param _user Address of the user to liquidate
@param _frac Fraction to liquidate; 100% = 10**18
@return The amount of borrowed asset needed
"""
assert _frac <= WAD, "frac>100%"
health_limit: uint256 = 0
if not self._has_approval(_user):
health_limit = self.liquidation_discounts[_user]
borrowed: uint256 = unsafe_div(
(staticcall AMM.get_sum_xy(_user))[0]
* self._get_f_remove(_frac, health_limit),
WAD,
)
debt: uint256 = unsafe_div(self._debt(_user)[0] * _frac + (WAD - 1), WAD)
return crv_math.sub_or_zero(debt, borrowed)
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.tokens_to_liquidate(
/* _user: address */ "0x0000000000000000000000000000000000000000",
/* _frac: uint256 */ 0n,
)
total_debt
LendController.total_debt() -> uint256: viewReturns the total outstanding debt across all loans in this market, including accrued interest.
Returns: total debt (uint256).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
@reentrant
def total_debt() -> uint256:
"""
@notice Total debt of this controller
@dev Marked as reentrant because used by monetary policy
@return Total outstanding debt with accrued interest
"""
return self._get_total_debt()
@internal
@pure
def _get_y_effective(
_collateral: uint256,
_N: uint256,
_discount: uint256,
_SQRT_BAND_RATIO: uint256,
_A: uint256,
) -> uint256:
"""
@notice Intermediary method which calculates y_effective defined as x_effective / p_base,
however discounted by loan_discount.
x_effective is an amount which can be obtained from collateral when liquidating
@param _collateral Amount of collateral with 18 decimals to get the value for
@param _N Number of bands the deposit is made into
@param _discount Loan discount at 1e18 base (e.g. 1e18 == 100%)
@param _SQRT_BAND_RATIO Square root of the band ratio sqrt((A-1)/A) at 1e18 base
@param _A Band width factor
@return y_effective
"""
# x_effective = sum_{i=0..N-1}(y / N * p(n_{n1+i})) =
# = y / N * p_oracle_up(n1) * sqrt((A - 1) / A) * sum_{0..N-1}(((A-1) / A)**k)
# === d_y_effective * p_oracle_up(n1) * sum(...) === y_effective * p_oracle_up(n1)
# d_y_effective = y / N / sqrt(A / (A - 1))
# d_y_effective: uint256 = collateral * unsafe_sub(10**18, discount) / (SQRT_BAND_RATIO * N)
# Make some extra discount to always deposit lower when we have DEAD_SHARES rounding
# … the remaining implementation is linked above.
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.total_debt()
n_loans
LendController.n_loans() -> uint256: viewReturns the total number of active loans.
Returns: number of loans (uint256).
<>Source code▼
The implementation is in lending/LendController.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('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, signer)
const tx = await contract.n_loans()
await tx.wait()
loans
LendController.loans(_index: uint256) -> address: viewReturns the borrower address at a given loan index.
| Input | Type | Description |
|---|---|---|
_index | uint256 | Loan index |
Returns: borrower address (address).
<>Source code▼
The implementation is in lending/LendController.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('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, signer)
const tx = await contract.loans(
/* _index: uint256 */ 0n,
)
await tx.wait()
loan_ix
LendController.loan_ix(_user: address) -> uint256: viewReturns the index of a user's loan in the loans array.
| Input | Type | Description |
|---|---|---|
_user | address | Borrower address |
Returns: loan index (uint256).
<>Source code▼
The implementation is in lending/LendController.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('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, signer)
const tx = await contract.loan_ix(
/* _user: address */ "0x0000000000000000000000000000000000000000",
)
await tx.wait()
Health Previews
These functions allow UIs to show the health impact of operations before the user submits a transaction.
create_loan_health_preview
LendController.create_loan_health_preview(_collateral: uint256, _debt: uint256, _N: uint256, _for: address, _full: bool) -> int256: viewPreviews the health of a loan that would result from calling create_loan.
| Input | Type | Description |
|---|---|---|
_collateral | uint256 | Collateral amount |
_debt | uint256 | Debt amount |
_N | uint256 | Number of bands |
_for | address | Borrower address |
_full | bool | Full (pessimistic) health |
Returns: predicted health (int256).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
def create_loan_health_preview(
_collateral: uint256,
_debt: uint256,
_N: uint256,
_for: address,
_full: bool,
) -> int256:
"""
@notice Calculates health after calling create_loan with the same params
@param _collateral Amount of collateral to use (from wallet + callback).
Note: the collateral amount coming from the callback should be included.
@param _debt Borrowed asset debt to take
@param _N Number of bands to deposit into (to do autoliquidation-deliquidation),
can be from MIN_TICKS to MAX_TICKS
@param _for Address of the user the loan is being created for
@param _full Whether it's a 'full' health or not
@return Signed health value
"""
return staticcall self._view.create_loan_health_preview(
_collateral, _debt, _N, _for, _full
)
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.create_loan_health_preview(
/* _collateral: uint256 */ 0n,
/* _debt: uint256 */ 0n,
/* _N: uint256 */ 0n,
/* _for: address */ "0x0000000000000000000000000000000000000000",
/* _full: bool */ false,
)
borrow_more_health_preview
LendController.borrow_more_health_preview(_collateral: uint256, _debt: uint256, _for: address, _full: bool) -> int256: viewPreviews the health after borrowing more.
| Input | Type | Description |
|---|---|---|
_collateral | uint256 | Additional collateral |
_debt | uint256 | Additional debt |
_for | address | Borrower address |
_full | bool | Full (pessimistic) health |
Returns: predicted health (int256).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
def borrow_more_health_preview(
_collateral: uint256,
_debt: uint256,
_for: address,
_full: bool,
) -> int256:
"""
@notice Calculates health after calling borrow_more with the same params
@param _collateral Amount of collateral to add (from wallet + callback).
Note: the collateral amount coming from the callback should be included.
@param _debt Amount of borrowed asset debt to take
@param _for Address to borrow for
@param _full Whether it's a 'full' health or not
@return Signed health value
"""
return staticcall self._view.borrow_more_health_preview(
_collateral, _debt, _for, _full
)
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.borrow_more_health_preview(
/* _collateral: uint256 */ 0n,
/* _debt: uint256 */ 0n,
/* _for: address */ "0x0000000000000000000000000000000000000000",
/* _full: bool */ false,
)
add_collateral_health_preview
LendController.add_collateral_health_preview(_collateral: uint256, _for: address, _full: bool) -> int256: viewPreviews the health after adding collateral.
| Input | Type | Description |
|---|---|---|
_collateral | uint256 | Collateral to add |
_for | address | Borrower address |
_full | bool | Full (pessimistic) health |
Returns: predicted health (int256).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
def add_collateral_health_preview(
_collateral: uint256,
_for: address,
_full: bool,
) -> int256:
"""
@notice Calculates health after calling add_collateral with the same args
@param _collateral Amount of collateral to add
@param _for The user to add collateral for
@param _full Whether it's a 'full' health or not
@return Signed health value
"""
return staticcall self._view.add_collateral_health_preview(_collateral, _for, _full)
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.add_collateral_health_preview(
/* _collateral: uint256 */ 0n,
/* _for: address */ "0x0000000000000000000000000000000000000000",
/* _full: bool */ false,
)
remove_collateral_health_preview
LendController.remove_collateral_health_preview(_collateral: uint256, _for: address, _full: bool) -> int256: viewPreviews the health after removing collateral.
| Input | Type | Description |
|---|---|---|
_collateral | uint256 | Collateral to remove |
_for | address | Borrower address |
_full | bool | Full (pessimistic) health |
Returns: predicted health (int256).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
def remove_collateral_health_preview(
_collateral: uint256,
_for: address,
_full: bool,
) -> int256:
"""
@notice Calculates health after calling remove_collateral with the same args
@param _collateral Amount of collateral to remove
@param _for Address to remove collateral from
@param _full Whether it's a 'full' health or not
@return Signed health value
"""
return staticcall self._view.remove_collateral_health_preview(
_collateral, _for, _full
)
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.remove_collateral_health_preview(
/* _collateral: uint256 */ 0n,
/* _for: address */ "0x0000000000000000000000000000000000000000",
/* _full: bool */ false,
)
repay_health_preview
LendController.repay_health_preview(_d_collateral: uint256, _d_debt: uint256, _for: address, _shrink: bool, _full: bool) -> int256: viewPreviews the health after repaying debt.
| Input | Type | Description |
|---|---|---|
_d_collateral | uint256 | Collateral amount removed through the callback |
_d_debt | uint256 | Debt to repay |
_for | address | Borrower address |
_shrink | bool | Whether the repayment shrinks a soft-liquidated position |
_full | bool | Full (pessimistic) health |
Returns: predicted health (int256).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
def repay_health_preview(
_d_collateral: uint256,
_d_debt: uint256,
_for: address,
_shrink: bool,
_full: bool,
) -> int256:
"""
@notice Calculates health after calling repay with the same params
@dev Works only for partial repay, reverts for full repay
@param _d_collateral Amount of collateral to remove (goes to callback)
@param _d_debt The amount of debt to repay (from wallet + callback).
Note: the borrowed amount coming from the callback should be included.
@param _for The user to repay the debt for
@param _shrink Whether shrink soft-liquidated part of the position or not
@param _full Whether it's a 'full' health or not
@return Signed health value
"""
return staticcall self._view.repay_health_preview(
_d_collateral, _d_debt, _for, _shrink, _full
)
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.repay_health_preview(
/* _d_collateral: uint256 */ 0n,
/* _d_debt: uint256 */ 0n,
/* _for: address */ "0x0000000000000000000000000000000000000000",
/* _shrink: bool */ false,
/* _full: bool */ false,
)
liquidate_health_preview
LendController.liquidate_health_preview(_user: address, _caller: address, _frac: uint256, _full: bool) -> int256: viewPreviews what a user's health would be after liquidation.
| Input | Type | Description |
|---|---|---|
_user | address | Borrower address |
_caller | address | Address that would submit the liquidation |
_frac | uint256 | Fraction of the position to liquidate, where 10**18 is 100% |
_full | bool | Full (pessimistic) health |
Returns: predicted health (int256).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
def liquidate_health_preview(
_user: address,
_caller: address,
_frac: uint256,
_full: bool,
) -> int256:
"""
@notice Calculates health after calling liquidate with the same args
@param _user User to liquidate
@param _caller Address from which liquidate tx is going to be sent.
Depending on this address liquidation_discount will be changed or not.
@param _frac Fraction to liquidate; 100% = 10**18
@param _full Whether it's a 'full' health or not
@return Signed health value
"""
return staticcall self._view.liquidate_health_preview(
_user, _caller, _frac, _full
)
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.liquidate_health_preview(
/* _user: address */ "0x0000000000000000000000000000000000000000",
/* _caller: address */ "0x0000000000000000000000000000000000000000",
/* _frac: uint256 */ 0n,
/* _full: bool */ false,
)
Lending-Specific
These functions are unique to LendController and not part of the shared controller.vy module.
available_balance
LendController.available_balance() -> uint256: viewReturns the amount of borrowed tokens currently available for new loans — i.e., tracked lender deposits minus amounts lent out. Direct token donations are not included in this accounting.
Returns: available balance (uint256).
<>Source code▼
Excerpt from lending/LendController.vy at 0d726b1:
@external
@view
@reentrant
def available_balance() -> uint256:
return self._available_balance
# https://github.com/vyperlang/vyper/issues/4721
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.available_balance()
borrow_cap
LendController.borrow_cap() -> uint256: viewReturns the maximum total debt allowed for this market. It is initialized to 0, which prevents new borrowing; the LendConfigurator must raise it above 0 (for example, through a DAO action) before borrowing can be enabled.
Returns: borrow cap (uint256).
<>Source code▼
The implementation is in lending/LendController.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('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, signer)
const tx = await contract.borrow_cap()
await tx.wait()
vault
LendController.vault() -> address: viewReturns the address of the associated ERC4626 vault.
Returns: vault address (address).
<>Source code▼
Excerpt from lending/LendController.vy at 0d726b1:
@external
@view
@reentrant
def vault() -> address:
"""
@notice Address of the vault
@return Address of the vault contract
"""
return VAULT.address
@deploy
def __init__(
_vault: IVault,
_amm: IAMM,
_borrowed_token: IERC20,
_collateral_token: IERC20,
_monetary_policy: IMonetaryPolicy,
_loan_discount: uint256,
_liquidation_discount: uint256,
_view_blueprint: address,
_configurator: core.IConfigurator,
):
"""
@notice Lend Controller constructor
@param _vault Address of the vault this controller belongs to
@param _amm AMM address (already deployed from blueprint)
@param _borrowed_token Token which is being borrowed
@param _collateral_token Token to use for collateral
@param _monetary_policy Address of monetary policy
@param _loan_discount Discount of the maximum loan size compare to get_x_down() value
@param _liquidation_discount Discount of the maximum loan size compare to
get_x_down() for "bad liquidation" purposes
@param _view_blueprint Address of the controller view blueprint
@param _configurator Address of the configurator contract
"""
VAULT = _vault
# … the remaining implementation is linked above.
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.vault()
configure_lend
LendController.configure_lend(_borrow_cap: uint256, _admin_percentage: uint256)This function is only callable by the LendConfigurator contract. Governance normally invokes it through the configurator's administrative methods.
Configures the market's borrow cap and admin-fee share. Either parameter can be left unchanged by passing the protocol's SKIP_CONFIG_UINT256 sentinel.
| Input | Type | Description |
|---|---|---|
_borrow_cap | uint256 | New maximum total debt (0 disables new borrowing) |
_admin_percentage | uint256 | New admin-fee share, scaled so that 10**18 is 100% |
Updates the supplied configuration values.
<>Source code▼
Excerpt from lending/LendController.vy at 0d726b1:
@external
def configure_lend(_borrow_cap: uint256, _admin_percentage: uint256):
assert msg.sender == core.CONFIGURATOR.address, "Only configurator"
if _borrow_cap != core.SKIP_CONFIG_UINT256:
self.borrow_cap = _borrow_cap
if _admin_percentage != core.SKIP_CONFIG_UINT256:
rate_mul: uint256 = staticcall core.AMM.get_rate_mul()
core._update_total_debt(0, rate_mul, False)
core.admin_percentage = _admin_percentage
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, signer)
const tx = await contract.configure_lend(
/* _borrow_cap: uint256 */ 0n,
/* _admin_percentage: uint256 */ 0n,
)
await tx.wait()
Calculations
max_borrowable
LendController.max_borrowable(_d_collateral: uint256, _N: uint256, _user: address = empty(address)) -> uint256: viewReturns the maximum amount that can be borrowed given a collateral amount and number of bands, respecting the borrow cap and available balance.
| Input | Type | Description |
|---|---|---|
_d_collateral | uint256 | Collateral amount |
_N | uint256 | Number of bands |
_user | address | Borrower address (for existing loan context) |
Returns: max borrowable amount (uint256).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
def max_borrowable(
_d_collateral: uint256, _N: uint256, _user: address = empty(address)
) -> uint256:
"""
@notice Calculation of maximum which can be borrowed.
Returns the maximum additional amount to be borrowed in case the user has a position.
@param _d_collateral Collateral amount against which to borrow
(additional amount if the user has a position)
@param _N Number of bands to have the deposit into (to be ignored if the user has a position)
@param _user User to calculate the value for
(can be zero address for create_loan if the user doesn't have extra_health)
@return Maximum (additional) amount of borrowed asset to borrow
"""
return staticcall self._view.max_borrowable(_d_collateral, _N, _user)
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.max_borrowable(
/* _d_collateral: uint256 */ 0n,
/* _N: uint256 */ 0n,
/* _user: address */ "0x0000000000000000000000000000000000000000",
)
min_collateral
LendController.min_collateral(_debt: uint256, _N: uint256, _user: address = empty(address)) -> uint256: viewReturns the minimum collateral required for a given debt amount and number of bands.
| Input | Type | Description |
|---|---|---|
_debt | uint256 | Desired debt amount |
_N | uint256 | Number of bands |
_user | address | User address, needed only when the user has nonzero extra health |
Returns: minimum collateral required (uint256).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
def min_collateral(
_debt: uint256, _N: uint256, _user: address = empty(address)
) -> uint256:
"""
@notice Calculation of minimum collaterl amount required for given debt amount
@param _debt The amount of debt for which calculation should be done
@param _N number of bands to have the deposit into
@param _user User to calculate the value for (only necessary for nonzero extra_health)
@return Minimum amount of collateral asset to provide
"""
return staticcall self._view.min_collateral(_debt, _N, _user)
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.min_collateral(
/* _debt: uint256 */ 0n,
/* _N: uint256 */ 0n,
/* _user: address */ "0x0000000000000000000000000000000000000000",
)
calculate_debt_n1
LendController.calculate_debt_n1(_collateral: uint256, _debt: uint256, _N: uint256, _user: address = empty(address)) -> int256: viewCalculates the upper band number (n1) for a loan with the given parameters. Used to determine where collateral will be placed in the AMM.
| Input | Type | Description |
|---|---|---|
_collateral | uint256 | Collateral amount |
_debt | uint256 | Debt amount |
_N | uint256 | Number of bands |
_user | address | User address, needed only when the user has nonzero extra health |
Returns: upper band number (int256).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
def calculate_debt_n1(
_collateral: uint256,
_debt: uint256,
_N: uint256,
_user: address = empty(address),
) -> int256:
"""
@notice Calculate the upper band number for the deposit to sit in to support
the given debt. Reverts if requested debt is too high.
@param _collateral Amount of collateral (at its native precision)
@param _debt Amount of requested debt
@param _N Number of bands to deposit into
@param _user User to calculate n1 for (only necessary for nonzero extra_health)
@return Upper band n1 (n1 <= n2) to deposit into. Signed integer
"""
assert _N > MIN_TICKS_UINT - 1 # dev: Need more ticks
assert _N < MAX_TICKS_UINT + 1 # dev: Need less ticks
return self._calculate_debt_n1(_collateral, _debt, _N, _user)
@internal
@view
def _calculate_debt_n1(
_collateral: uint256,
_debt: uint256,
_N: uint256,
_user: address,
) -> int256:
assert _debt > 0 # dev: No loan
n0: int256 = staticcall AMM.active_band()
p_base: uint256 = staticcall AMM.p_oracle_up(n0)
# x_effective = y / N * p_oracle_up(n1) * sqrt((A - 1) / A) * sum_{0..N-1}(((A-1) / A)**k)
# === d_y_effective * p_oracle_up(n1) * sum(...) === y_effective * p_oracle_up(n1)
# d_y_effective = y / N / sqrt(A / (A - 1))
y_effective: uint256 = self._get_y_effective(
# … the remaining implementation is linked above.
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.calculate_debt_n1(
/* _collateral: uint256 */ 0n,
/* _debt: uint256 */ 0n,
/* _N: uint256 */ 0n,
/* _user: address */ "0x0000000000000000000000000000000000000000",
)
Configuration
configure
LendController.configure(_loan_discount: uint256, _liquidation_discount: uint256, _monetary_policy: address, _view_blueprint: address, _fee: uint256, _price_oracle: address, _liquidity_mining_callback: address)This function is only callable by the LendConfigurator contract.
Updates shared-controller settings. Governance normally invokes it through the LendConfigurator rather than calling the controller directly. Parameters that should remain unchanged use the protocol's SKIP_CONFIG_UINT256 or SKIP_CONFIG_ADDRESS sentinel, as applicable.
| Input | Type | Description |
|---|---|---|
_loan_discount | uint256 | Loan discount for LTV calculations |
_liquidation_discount | uint256 | Discount used in liquidation calculations |
_monetary_policy | address | Monetary policy contract |
_view_blueprint | address | Controller-view blueprint |
_fee | uint256 | Base AMM fee |
_price_oracle | address | Price oracle contract |
_liquidity_mining_callback | address | Liquidity-mining callback contract |
Updates the supplied configuration values.
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
def configure(
_loan_discount: uint256,
_liquidation_discount: uint256,
_monetary_policy: IMonetaryPolicy,
_view_blueprint: address,
_fee: uint256,
_price_oracle: IPriceOracle,
_liquidity_mining_callback: ILMCallback,
):
assert msg.sender == CONFIGURATOR.address # dev: Only configurator
self._configure(
_loan_discount,
_liquidation_discount,
_monetary_policy,
_view_blueprint,
_fee,
_price_oracle,
_liquidity_mining_callback,
)
@internal
@view
def _admin_fees() -> uint256:
return self._stored_admin_fees + self._preview_total_debt(staticcall AMM.get_rate_mul(), self._total_debt)[1]
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.configure(
/* _loan_discount: uint256 */ 0n,
/* _liquidation_discount: uint256 */ 0n,
/* _monetary_policy: address */ "0x0000000000000000000000000000000000000000",
/* _view_blueprint: address */ "0x0000000000000000000000000000000000000000",
/* _fee: uint256 */ 0n,
/* _price_oracle: address */ "0x0000000000000000000000000000000000000000",
/* _liquidity_mining_callback: address */ "0x0000000000000000000000000000000000000000",
)
Other Methods
amm
LendController.amm() -> address: viewReturns the AMM (LLAMMA) address for this market.
Returns: AMM address (address).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
@reentrant
def amm() -> IAMM:
"""
@notice Address of the AMM
@return Address of the AMM contract
"""
return AMM
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.amm()
monetary_policy
LendController.monetary_policy() -> address: viewReturns the current monetary policy address.
Returns: monetary policy address (address).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
@reentrant
def monetary_policy() -> IMonetaryPolicy:
"""
@notice Address of the monetary policy
@return Address of the monetary policy contract
"""
return self._monetary_policy
approval: public(HashMap[address, HashMap[address, bool]])
extra_health: public(reentrant(HashMap[address, uint256]))
loan: HashMap[address, IController.Loan]
liquidation_discounts: public(HashMap[address, uint256])
_total_debt: IController.Loan
# Enumerate existing loans
loans: public(address[2**64 - 1])
# Position of the loan in the list
loan_ix: public(HashMap[address, uint256])
# Number of nonzero loans
n_loans: public(uint256)
# cumulative amount of borrowed assets ever lent
lent: uint256
# cumulative amount of borrowed assets ever repaid
repaid: uint256
# cumulative amount of borrowed assets ever collected as admin fees
collected: uint256
# Admin fees yet to be collected. Goes to zero when collected.
_stored_admin_fees: uint256
admin_percentage: public(uint256)
# … the remaining implementation is linked above.
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.monetary_policy()
liquidation_discount
LendController.liquidation_discount() -> uint256: viewReturns the current liquidation discount.
Returns: liquidation discount (uint256).
<>Source code▼
The implementation is in lending/LendController.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('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, signer)
const tx = await contract.liquidation_discount()
await tx.wait()
loan_discount
LendController.loan_discount() -> uint256: viewReturns the current loan discount.
Returns: loan discount (uint256).
<>Source code▼
The implementation is in lending/LendController.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('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, signer)
const tx = await contract.loan_discount()
await tx.wait()
admin_fees
LendController.admin_fees() -> uint256: viewReturns the amount of uncollected admin fees.
Returns: admin fees (uint256).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
@reentrant
def admin_fees() -> uint256:
"""
@notice Pending admin fees which can be claimed if the controller has enough balance
@return Amount of pending admin fees in borrowed token units
"""
return self._admin_fees()
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.admin_fees()
admin_percentage
LendController.admin_percentage() -> uint256: viewReturns the current admin fee percentage, scaled so that 10**18 is 100%.
Returns: admin percentage (uint256).
<>Source code▼
The implementation is in lending/LendController.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('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, signer)
const tx = await contract.admin_percentage()
await tx.wait()
collect_fees
LendController.collect_fees()Collects accumulated admin fees and sends them to the fee receiver set in the factory.
Emits: CollectFees event.
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
def collect_fees() -> uint256:
"""
@notice Collect the fees charged as interest.
@return Amount of fees collected and transferred to the fee receiver
"""
rate_mul: uint256 = staticcall AMM.get_rate_mul()
self._update_total_debt(0, rate_mul, False)
# self._stored_admin_fees == self.admin_fees() after _update_total_debt
pending_admin_fees: uint256 = self._stored_admin_fees
self.collected += pending_admin_fees
self._stored_admin_fees = 0
extcall VIRTUAL.on_borrowed_token_transfer_out(pending_admin_fees)
tkn.transfer(BORROWED_TOKEN, staticcall FACTORY.fee_receiver(), pending_admin_fees)
self._save_rate()
log IController.CollectFees(amount=pending_admin_fees)
return pending_admin_fees
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, signer)
const tx = await contract.collect_fees()
await tx.wait()
save_rate
LendController.save_rate()Updates the stored interest rate from the monetary policy. This is called automatically during loan operations but can also be called externally to keep the rate fresh.
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
def save_rate():
"""
@notice Save current rate
"""
self._save_rate()
@internal
@view
def _debt(_user: address) -> (uint256, uint256):
"""
@notice Get the value of debt and rate_mul without changing the state
@param _user User address
@return (debt, rate_mul)
"""
rate_mul: uint256 = staticcall AMM.get_rate_mul()
loan: IController.Loan = self.loan[_user]
if loan.initial_debt == 0:
return (0, rate_mul)
else:
# Let user repay 1 smallest decimal more so that the system doesn't lose on precision
# Use ceil div
debt: uint256 = math._ceil_div(loan.initial_debt * rate_mul, loan.rate_mul)
return (debt, rate_mul)
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.save_rate()
version
LendController.version() -> String[10]: viewReturns the contract version string (e.g., "2.0.0-lend").
Returns: version string (String[10]).
<>Source code▼
Excerpt from lending/LendController.vy at 0d726b1:
@external
@view
@reentrant
def version() -> String[10]:
"""
@notice Version of this controller
@return Version string of the form "<core_version>-lend"
"""
return concat(core.version, "-lend")
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.version()
factory
LendController.factory() -> address: viewReturns the factory that deployed this controller.
Returns: factory address (address).
<>Source code▼
Excerpt from Controller.vy at 0d726b1:
@external
@view
@reentrant
def factory() -> IFactory:
"""
@notice Address of the factory
@return Address of the factory contract
"""
return FACTORY
▶Example▼
const contract = new Contract('0xc77d97cf01737eb7ace46cab7cd9f60ec51a40c0', LendControllerAbi, provider)
const result = await contract.factory()