> For the complete documentation index, see [llms.txt](https://docs.riskprotocol.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.riskprotocol.io/protocol-design-and-specifications/risk-marketplace/providing-liquidity.md).

# Providing Liquidity

Liquidity providers (LPs) deposit tokens into Risk Marketplace pools and receive pool share tokens representing their proportional ownership. LPs earn LP fees generated by trading activity in the pool.

### **Pool Shares**

When providing liquidity, users receive pool shares calculated based on their contribution relative to the existing pool value. These shares:

* Represent proportional ownership of all tokens in the pool
* Accumulate value as LP fees are retained in the pool
* Can be redeemed for underlying tokens at any time (subject to circuit breakers)

### Fees

Single-asset joins and exits incur two fees that proportional joins and exits do not. Single-asset exits also incur a third, small fee on the pool shares themselves.

**LP Fee (dynamic).** Paid on the rebalancing portion of the implicit swap and **retained in the pool**, accruing to existing LPs. The LP fee is dynamic: each single-asset call must include a `feeData` payload signed off-chain by an authorized signer. The contract validates:

* ECDSA signature against the set of authorized signers
* Domain binding (`pool` matches the calling pool, `chainId` matches `block.chainid`)
* Freshness (`timestamp` within the configured `stalenessThreshold`)
* Bounds (`fee` lies within the configured `[minFee, maxFee]`)

If validation fails, the call reverts.

**Protocol Fee.** Taken on the **gross input** for joins and the **gross output** for exits. The fee is transferred directly to `protocolAddress` and is **not** retained in the pool. The rate is read from `bPool.getProtocolFee()`. If `protocolAddress` is unset, the fee is waived for that call and a `ProtocolFeeSkipped` event is emitted.

**Emergency Mode.** If signing infrastructure is unavailable, the pool owner can enable emergency mode. While enabled, single-asset joins and exits accept an empty `feeData` and fall back to a pre-configured `emergencyFee`. Outside emergency mode, calls with empty `feeData` revert with `BPOOL_Missing_Fee_Data`.

## 1.  Joining a Pool

### *1 a)  Proportional Join (Multi-Asset Deposit)*

Deposit all pool tokens in their current ratio. This method incurs no LP fees since it maintains the pool balance.

Calculation:

$$tokenAmountIn\_i = \frac{poolAmountOut}{poolSupply} \times B\_i$$

Where:

* $$poolAmountOut$$ = Pool shares to receive
* $$poolSupply$$ = Current total pool shares
* $$B\_i$$ = Current balance of token (i)

#### Key Functions

* **joinPool Method**: Handles depositing multiple tokens proportionally in exchange for the pool\
  shares.
  * Parameters:
    1. `poolAmountOut:` The amount of pool shares  to receive
    2. `maxAmountsIn[]`: Maximum amounts of each token willing to deposit (slippage protection)

#### Process

1. Ratio Calculation
   * The system calculates the ratio of requested pool shares to total supply.
   * This ratio determines how much of each token is required
2. Token Transfer
   * For each token in the pool, the required amount is calculated: `tokenAmountIn = ratio × tokenBalance`.
   * Tokens are transferred from the user to the pool; If any calculated amount exceeds `maxAmountsIn`, the transaction reverts
3. Share Minting
   * Pool shares are minted to the user equal to `poolAmountOut`

*Example*: A pool contains 1,000 ETH and 2,000,000 USDC with a total supply of 100 pool share tokens. To receive 10 pool share tokens (10% of supply):

* ETH required: 10% × 1,000 = 100 ETH
* USDC required: 10% × 2,000,000 = 200,000 USDC

### *1 b)  Single-Asset Join (Single Token Deposit)*

Deposit only one token. The pool implicitly swaps part of the deposit into the other pool tokens; the rebalancing portion incurs an LP fee. The protocol fee is taken on the full deposit amount before share math runs.

$$
poolAmountOut = \left( \left( \frac{B\_i + A\_i \times (1 - (1 - W\_i^n) \times LPFee)}{B\_i} \right)^{W\_i^n} - 1 \right) \times poolSupply
$$

Where:

* $$`A_i`$$= Amount of token credited to the pool (= `tokenAmountIn − protocolFee`)
* $$`B_i`$$ = Current balance of deposit token
* $$`W_i^n`$$ = Normalized weight of deposit token
* $$`LPFee`$$= Validated dynamic LP fee from the signed `feeData` payload

**Key Functions**

**joinswapExternAmountIn Method**: Deposit an exact amount of one token, receive calculated pool shares.

| Parameter          | Type    | Description                                                                                                                   |
| ------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `tokenIn`          | address | Address of the token being deposited                                                                                          |
| `tokenAmountIn`    | uint    | Total amount transferred from the LP. The protocol fee is taken out of this amount and the remainder is credited to the pool. |
| `minPoolAmountOut` | uint    | Minimum pool shares to receive (slippage protection)                                                                          |
| `feeData`          | bytes   | ABI-encoded `(fee, timestamp, pool, chainId)` from an authorized signer                                                       |
| `signature`        | bytes   | ECDSA signature over `feeData`                                                                                                |

**joinswapPoolAmountOut Method**: Specify exact pool shares desired; the system calculates the required deposit.

| Parameter       | Type    | Description                                                                         |
| --------------- | ------- | ----------------------------------------------------------------------------------- |
| `tokenIn`       | address | Address of the token being deposited                                                |
| `poolAmountOut` | uint    | Exact amount of pool shares to receive                                              |
| `maxAmountIn`   | uint    | Maximum tokens willing to pay, **including the protocol fee** (slippage protection) |
| `feeData`       | bytes   | ABI-encoded `(fee, timestamp, pool, chainId)` from an authorized signer             |
| `signature`     | bytes   | ECDSA signature over `feeData`                                                      |

**Process**

1. **Fee Validation** - `feeData` and `signature` are verified; the dynamic LP fee is extracted.
2. **Protocol Fee** - Computed on `tokenAmountIn` (or the implied input for `joinswapPoolAmountOut`) and routed to `protocolAddress`. Pool-share math runs on the **post-protocol-fee** amount.
3. **Pool Shares Calculation** - Uses weighted math on the net amount. The LP fee applies only to the portion that "rebalances" the pool.
4. **Execution** - Net deposit transferred from the user to the pool. Pool shares minted to the user.

{% hint style="warning" %}
**Fee Logic**: Only the portion that rebalances the pool pays the LP fee. If a token has 25% weight, depositing that token implicitly trades 75% of it for other tokens — only that 75% incurs the LP fee. The protocol fee, by contrast, is taken on the entire input.
{% endhint %}

{% hint style="info" %}
**Example**: Single-asset join with 1,000 USDC into a pool where USDC has 20% weight, LP fee 0.3%, protocol fee 0.05%:

* Protocol fee taken from input: 0.05% × 1,000 = 0.5 USDC → sent to `protocolAddress`
* Net amount credited to pool: 999.5 USDC
* Implicit swap portion: 80% × 999.5 ≈ 799.6 USDC
* LP fee paid (retained in pool): 0.3% × 799.6 ≈ 2.4 USDC
* Net contribution used for share calculation: \~997.1 USDC equivalent
  {% endhint %}

## 2.  Exiting a Pool

### *2 a)  Proportional Exit (Multi-Asset Withdrawal)*

Redeem pool shares for all tokens proportionally. This method incurs no LP fees.

Calculation:

$$tokenAmountOut\_i = \frac{poolAmountIn}{poolSupply} \times B\_i$$

Where:

* $$poolAmountIn$$ = Pool shares being redeemed
* $$poolSupply$$ = Current total pool shares
* $$B\_i$$ = Current balance of token (i)

#### Key Functions

* **exitPool Method**: Burn pool shares and receive all underlying tokens proportionally.
  * Parameters:
    1. `minAmountsOut`: Minimum amounts of each token to receive (slippage protection)
    2. `poolAmountIn`: Amount of pool shares to redeem

#### Process

1. Ratio Calculation
   * The system calculates the ratio of redeemed shares to total supply, which determines how much of each token the user receives
2. Share Burning
   * Pool shares are pulled from the user's balance and are burned, reducing the total supply
3. Token Distribution
   * For each token: tokenAmountOut = ratio × tokenBalance, and if any calculated amount is below minAmountsOut, the transaction reverts
   * Tokens are transferred from the pool to the user

*Example*: Redeeming 10 BPT from a pool with 100 BPT supply, 1,000 ETH, and 2,000,000 USDC:

* ETH received: 10% × 1,000 = 100 ETH
* USDC received: 10% × 2,000,000 = 200,000 USDC

### *2 b)  Single-Asset Exit (Single Token Withdrawal)*

Redeem pool shares for only one token. The pool implicitly sells the other tokens for the desired token; the rebalancing portion incurs an LP fee. The protocol fee is taken from the gross output before delivery, and the `EXIT_FEE` (if set) is taken on pool shares.

**Tokens Received (net of protocol fee):**

$$
tokenAmountOut = B\_o \times \left( 1 - \left( \frac{poolSupply - poolAmountIn}{poolSupply} \right)^{\frac{1}{W\_o^n}} \right) \times \left( 1 - (1 - W\_o^n) \times LPFee \right) \times \left( 1 - ProtocolFee \right)
$$

Where:

* $$`B_o`$$ = Current balance of withdrawal token
* $$`W_o^n`$$ = Normalized weight of withdrawal token
* $$`poolAmountIn`$$ = Pool shares being redeemed (before `EXIT_FEE` on shares)
* $$`LPFee`$$ = Validated dynamic LP fee from the signed `feeData` payload
* $$`ProtocolFee`$$ = `bPool.getProtocolFee()`

**Key Functions**

**exitswapPoolAmountIn Method**: Burn exact pool shares, receive calculated token amount.

| Parameter      | Type    | Description                                                                    |
| -------------- | ------- | ------------------------------------------------------------------------------ |
| `tokenOut`     | address | Address of the token to receive                                                |
| `poolAmountIn` | uint    | Exact amount of pool shares to redeem                                          |
| `minAmountOut` | uint    | Minimum **net** tokens to receive after the protocol fee (slippage protection) |
| `feeData`      | bytes   | ABI-encoded `(fee, timestamp, pool, chainId)` from an authorized signer        |
| `signature`    | bytes   | ECDSA signature over `feeData`                                                 |

**exitswapExternAmountOut Method**: Specify the exact net token amount desired; the system calculates the shares to burn.

| Parameter         | Type    | Description                                                                                                               |
| ----------------- | ------- | ------------------------------------------------------------------------------------------------------------------------- |
| `tokenOut`        | address | Address of the token to receive                                                                                           |
| `tokenAmountOut`  | uint    | Exact **net** amount of tokens to receive                                                                                 |
| `maxPoolAmountIn` | uint    | Maximum pool shares willing to burn. Must cover the gross calculation (`tokenAmountOut + protocolFee`), not just the net. |
| `feeData`         | bytes   | ABI-encoded `(fee, timestamp, pool, chainId)` from an authorized signer                                                   |
| `signature`       | bytes   | ECDSA signature over `feeData`                                                                                            |

**Process**

1. **Fee Validation** - `feeData` and `signature` are verified; the dynamic LP fee is extracted.
2. **Output Calculation** - Uses weighted math to determine fair gross token output.
3. **Protocol Fee** - Protocol fee is computed on the gross output and routed to `protocolAddress`. The user receives `grossAmountOut − protocolFee`.
4. **Exit Fee on Pool Shares** - `EXIT_FEE × poolAmountIn` of pool shares is sent to the factory. The remainder of the redeemed shares is burned.
5. **Execution** - Net token amount transferred from the pool to the user.

{% hint style="warning" %}
**Fee Logic**: The LP fee applies to the portion being implicitly swapped. Withdrawing a 20% weight token means 80% of the value comes from selling other tokens — that portion pays the LP fee. The protocol fee is taken on the entire gross output. The `EXIT_FEE` is taken on pool shares regardless of which token is withdrawn.
{% endhint %}

{% hint style="info" %}
**Example**: Single-asset exit for 1 BPT from a pool with 100 BPT supply, 1,000 ETH, and 2,000,000 USDC, withdrawing USDC at 80% weight, LP fee 0.3%, protocol fee 0.05%, EXIT\_FEE 0%:

* Gross USDC released by weighted math: \~25,000 USDC (illustrative)
* LP fee retained in pool: 0.3% × (1 − 0.8) × 25,000 = 15 USDC
* Net of LP fee: \~24,985 USDC
* Protocol fee: 0.05% × 24,985 ≈ 12.5 USDC → sent to `protocolAddress`
* USDC delivered to LP: \~24,972.5 USDC
  {% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.riskprotocol.io/protocol-design-and-specifications/risk-marketplace/providing-liquidity.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
