Skip to content

Add Llamalend v2 developer documentation#122

Open
mo-anon wants to merge 2 commits into
mainfrom
feat/llamalend-v2-docs
Open

Add Llamalend v2 developer documentation#122
mo-anon wants to merge 2 commits into
mainfrom
feat/llamalend-v2-docs

Conversation

@mo-anon

@mo-anon mo-anon commented Mar 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds a new Llamalend v2 section to the developer docs covering the core lending infrastructure contracts
  • Overview page with architecture diagram (Mermaid), new features, security improvements vs v1, Vyper module system explanation, and audit placeholder
  • 5 contract reference pages: LendFactory, Vault, LendController, LendControllerView, AMM (LLAMMA) — all with function signatures, parameter tables, and return descriptions
  • Enables Mermaid diagram rendering site-wide (markdown.mermaid: true in docusaurus config)
  • Adds sidebar entry for the new section

Status: Work in Progress

This PR is not final. The contracts are still being finalized as audit findings are being addressed. Specifically:

  • Source code blocks (<SourceCode>) are intentionally left empty — they will be filled once the contract code is finalized and deployed
  • Example blocks (<Example>) are also empty — will be added with live <ContractCall> components once deployment addresses are available
  • ABI blocks are not yet included — will be added from the final deployed contracts
  • Deployment addresses are placeholders — will be updated post-deployment
  • The Audits section is a placeholder pending public release of audit reports

Once the code is finalized and deployed, a follow-up pass will fill in all source code, examples, ABIs, and deployment info.

Test plan

  • yarn build passes with no new errors
  • Review overview page content for accuracy
  • Verify Mermaid diagram renders correctly
  • Check all sidebar links work

🤖 Generated with Claude Code

New docs section covering the core lending infrastructure contracts
for Llamalend v2: LendFactory, Vault, LendController, LendControllerView,
and AMM (LLAMMA). Includes an overview page with architecture diagram,
new features, security improvements, and Vyper module system explanation.

Source code blocks and example blocks are left empty as the contracts
are still being finalized (audit fixes ongoing).

Also enables Mermaid diagram rendering site-wide.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Mar 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Mar 20, 2026 1:15pm

Request Review

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| `max_amount` | `uint256` | Maximum input amount (slippage protection) |
| `_for` | `address` | Address to receive the output tokens |

Returns: `[in_amount, out_amount_done]` (`uint256[2]`).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out_amount_done can be less than out_amount if there is no enough liquidity in the AMM

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a clarification

| `j` | `uint256` | Output token index |
| `in_amount` | `uint256` | Input amount |

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here


::::description[`AMM.get_amount_for_price(_p: uint256) -> uint256: view`]

Returns the amount of token 0 (borrowed token) needed to move the AMM price to `_p`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's wrong. It returns (amount, is_pump)

  1. If is_pump=True, it means that we do borrowed->collateral exchange (pumping collateral). In this case amount is the borrowed token amount needed to pump the price to the passed _p value.

  2. If is_pump=False, it means that we do collateral->borrowed exchange (dumping collateral). In this case amount is the collateral token amount needed to dump the price to the passed _p value.


::::description[`AMM.price_oracle() -> uint256: view`]

Returns the current price from the external price oracle, smoothed by the AMM's internal EMA.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not smoothed, it's clamped by MAX_P_O_CHG: constant(uint256) = 12500 * 10**14 # <= 2**(1/3) - max relative change to have fee < 50%


::::description[`AMM.p_oracle_up(_n: int256) -> uint256: view`]

Returns the upper oracle price boundary of band `_n` (based on the oracle price, not the current AMM state).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It just gives a price grid we use. Like uniswap ticks. For the band n there are p_oracle_up(n) and p_oracle_down(n) - upper and lower borders of the band. They are constants and are calculated like:

    # 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)

Actually p_grid_up/down naming would be much better.

Also it worths to mention that band number can be negative. And it's counterintuitive: it's positive to the left from p_base and negative to the right. The higher n the lower the price.


::::description[`AMM.p_oracle_down(_n: int256) -> uint256: view`]

Returns the lower oracle price boundary of band `_n`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same


::::

### `dynamic_fee`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this finally


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

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The order is [n1, n2]. n1 < n2 while p1 > p2


::::description[`AMM.bands_x(_n: int256) -> uint256: view`]

Returns the total amount of borrowed token in band `_n`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With 18 decimals, it's not converted to real token decimals


::::description[`AMM.bands_y(_n: int256) -> uint256: view`]

Returns the total amount of collateral token in band `_n`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same


::::description[`AMM.fee() -> uint256: view`]

Returns the current swap fee.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's default fee without the dynamic part (min possible)


::::description[`AMM.A() -> uint256: view`]

Returns the amplification coefficient. Band width is approximately `1/A`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not "the amplification coefficient". It's "the band width factor"


::::description[`LendControllerView.liquidate_health_preview(_user: address, _full: bool) -> int256: view`]

Previews health after liquidation.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After partial liquidation


### `create_loan`

::::description[`LendController.create_loan(_collateral: uint256, _debt: uint256, _N: uint256)`]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's changed:

def create_loan(
    _collateral: uint256,
    _debt: uint256,
    _N: uint256,
    _for: address = msg.sender,
    _callbacker: address = empty(address),
    _calldata: Bytes[CALLDATA_MAX_SIZE] = b"",
):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same about many other methods

@@ -0,0 +1,342 @@
# LendControllerView

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update methods' signatures. It's changed


::::description[`LendController.add_collateral(_d_collateral: uint256, _for: address)`]

Adds collateral to an existing loan without borrowing more. Can be called by anyone on behalf of a borrower.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's permissioned now. There are no permissionless methods anymore (except liquidationg unhealthy users)


::::description[`LendController.health(_user: address, _full: bool) -> int256: view`]

Returns 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, returns health assuming the worst-case scenario where all collateral has been soft-liquidated.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If _full is true it takes into account the collateral price
If _full is false it calculates the health like a user in the soft-liquidation mode


::::

### `borrow_more_health_preview`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the health_preview signatures have been changed


::::description[`LendController.available_balance() -> uint256: view`]

Returns the amount of borrowed tokens currently available for new loans — i.e., the tokens deposited by lenders minus what's already lent out.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't count donations which is important


::::description[`LendController.borrow_cap() -> uint256: view`]

Returns the maximum total debt allowed for this market. If 0, there is no cap.

@Macket Macket Jun 19, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would mention that it's 0 by default and requires admin action (DAO vote) to become > 0


::::

### `amm_price`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's removed


::::description[`LendController.admin_percentage() -> uint256: view`]

Returns the current admin fee percentage.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10**18 == 100%

| `_liquidation_discount` | `uint256` | Discount at which liquidation can occur |
| `_price_oracle` | `address` | Initialized price oracle contract |
| `_monetary_policy` | `address` | Initialized monetary policy contract |
| `_name` | `String[64]` | Name for the vault token |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name has been removed

| --- | --- | --- |
| `_n` | `uint256` | Market index (0-based) |

Returns: market struct containing vault, controller, amm, collateral token, borrowed token, and market index (`Market`).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returns: vault, controller, amm, collateral token, borrowed token, price oracle and monetary policy addresses


::::description[`LendFactory.vaults_index(_vault: IVault) -> uint256: view`]

Returns the index of a vault in the factory registry. Uses a `2^128` offset internally — a return value of `0` means the vault is not registered.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the second sentence. 0 desn't mean that


n = factory.market_count()
for i in range(n):
vault_addr = factory.vaults(i)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

factory.vaults(i) has been removed from LendFactory. Use factory.markets(i) instead


## New Features

- **Any token as borrowed asset** — crvUSD is no longer the only allowed borrowable token. Any ERC20-compliant token can be used to create a lending market.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Any token pair" would be more correct. crvUSD was required to be in each pair either as borrowed or as collateral.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants