> For the complete documentation index, see [llms.txt](https://docs.efficientdex.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.efficientdex.com/integrate/deposits-and-exits-for-apps.md).

# Deposits and exits for apps

The calls, approvals and reverts behind each way into and out of an Efficient pool: proportional, single-asset, the entry market and tranches.

**Apps move depositors in and out of an Efficient pool through the pool itself or the contracts around it.** The pool has no ERC-4626 `deposit`, `mint`, `withdraw` or `redeem`. The table lists the entry and exit calls for each route.

[Provide liquidity](/use-efficient/provide-liquidity.md) explains each route from the depositor's side, including what can stop a deposit or an exit.

| Route          | Contract             | Entry                             | Exit                                |
| -------------- | -------------------- | --------------------------------- | ----------------------------------- |
| Proportional   | Pool                 | `depositProRata` or `mintProRata` | `redeemProRata`                     |
| Single asset   | Asset router         | `depositFromAsset`                | `redeemToAsset`                     |
| By request     | Entry market         | `requestDeposit`                  | `requestRedeem`                     |
| Senior tranche | Senior tranche token | `deposit` or `mint`               | `requestRedeem`, then `claimRedeem` |
| Junior tranche | Junior tranche token | `requestDeposit`                  | `requestRedeem`                     |

## Reads before any route

These reads sit on the pool itself, not on the read-only lens:

1. `loanCount()` returns the number of loan assets. A loan asset is the other token in the pool's pair, which the pool can borrow. In an Efficient pool that trades BTC against USDC, the loan asset is USDC. Any extra asset the pool can borrow is a loan asset too. The asset router and the entry market's `fillPar` and `crank` work only when the count is one. Otherwise they revert with `MultiLoan`.
2. `depositAllowlist()` returns the allowlist contract. Its `isDepositAllowed(address)` answers for one receiver. When no allowlist is bound, `depositAllowlist()` returns the zero address, and the pool admits every receiver.
3. `maxDepositProRata(receiver)` and `maxRedeemProRata(owner)` return the largest `depositProRata` and `redeemProRata` sizes the pool admits now. The pool sets no cap on `depositProRata`. So `maxDepositProRata` reads `type(uint256).max` unless a lending-market leg bounds the deposit. On a pool that uses a lending market, a deposit of the maximum can still revert there. A flow that's closed now reads zero.
4. `previewDepositProRata(poolAssets)` and `previewRedeemProRata(shares)` quote the shares or the payout. They also quote the leg at each lending market the pool uses, and the net amount of each loan asset paid in and out.
5. `maxDepositProRata` ignores `mintProRataCap`. It reads zero on a book that holds no pool asset, though `mintProRata` can still enter that book if the book owes nothing. The room for `mintProRata` is `limits().mintProRataCap` less `totalSupply()`, and a performance fee the pool mints first takes from that room. The pool has no preview for `mintProRata`, so an app bounds its pay-in with `maxPoolAssetIn` and `maxLoanAssetIn`.

## Proportional entry and exit

```solidity
function depositProRata(
    uint256 poolAssets,
    address receiver,
    uint256[] calldata maxLoanAssetIn,
    uint256[] calldata minLoanAssetOut,
    uint256 minSharesOut,
    uint256 deadline
) external returns (uint256 shares, uint256 loanAssetIn, uint256 loanAssetOut);

function redeemProRata(
    uint256 shares,
    address receiver,
    address owner,
    uint256[] calldata maxLoanAssetIn,
    uint256[] calldata minLoanAssetOut,
    uint256 minPoolAssetOut,
    uint256 deadline
) external returns (uint256 poolAssetOut, uint256 loanAssetIn, uint256 loanAssetOut);
```

**Each call moves the shares' slice of every leg of the book.** It settles one net amount per loan asset. The caller either pays that amount in or receives it. [The pool and its book](/how-pools-work/the-pool-and-its-book.md) follows both calls through an example book.

|                 | `depositProRata`                                           | `redeemProRata`                                               |
| --------------- | ---------------------------------------------------------- | ------------------------------------------------------------- |
| Who can call it | Anyone                                                     | The share owner, or an address the owner has approved         |
| The caller pays | The pool asset, and any net loan asset                     | Any net loan asset                                            |
| Paid out        | Shares to `receiver`, and any net loan asset to the caller | The pool asset, and any net loan-asset surplus, to `receiver` |
| Floor           | `minSharesOut`                                             | `minPoolAssetOut`                                             |

The caller approves the pool for every token it pays in. Each array takes exactly one entry per loan asset, in the pool's order. An array of any other length reverts with `InvalidAmount`.

`maxLoanAssetIn` caps what the caller pays in each loan asset. `minLoanAssetOut` sets the least it accepts back. The returned loan amounts report the first loan asset only, and so do the pool's `ProRataDeposit` and `ProRataRedeem` events.

Either call reverts with `Expired` past its deadline, and with `Slippage` below its floor. The pool first mints any performance fee it owes. Both previews price at the share supply after that fee.

```solidity
function mintProRata(
    uint256 shares,
    address receiver,
    uint256[] calldata maxLoanAssetIn,
    uint256[] calldata minLoanAssetOut,
    uint256 maxPoolAssetIn,
    uint256 deadline
) external returns (uint256 poolAssetIn, uint256 loanAssetIn, uint256 loanAssetOut);
```

`mintProRata` is the proportional entry sized in shares. It enters only a book that owes nothing, and otherwise reverts with `BookHasDebt`. It sizes an entry where `depositProRata` can't, on a book that holds little or no pool asset.

It mints exactly `shares` for their slice of every leg, each rounded up, and never borrows. `maxPoolAssetIn` caps the pool asset it takes, and the call reverts with `Slippage` above that cap. `loanAssetOut` is always zero.

It passes the same feature, pause and allowlist checks as `depositProRata`. It runs a fee charge first. While a performance or protocol fee rate is on, it reverts with `PriceUnchecked` unless that charge read the pool's mark. This holds only on a pool with a price band, since a pool without one charges neither fee.

The share supply after the call can't exceed `mintProRataCap`, or the call reverts with `DepositCapExceeded`. The cap starts at zero, so the entry stays closed until the pool operator raises it.

**A redemption never pays out in part.** So an app sizes it from `maxRedeemProRata`. That read allows for the free cash at each lending market the pool uses. A position with debt is unhealthy past its liquidation LTV, or while its market oracle can't be read. While a position is unhealthy, only a redemption that clears that position's whole debt goes through. `maxRedeemProRata` then reads zero, or a size to redeem exactly.

When a lending market the pool uses nears full utilisation, the maximum can burn shares for no pool asset. So an app checks `previewRedeemProRata` at that size. It then holds and approves the `netLoanAssetIn` the preview returns.

## Conversion legs

**The asset router and the entry market's crank convert between the pool asset and the first loan asset.** The caller builds each leg offchain. Every leg runs through the pool's DEX aggregator.

```
leg          = abi.encode(uint8 kind, uint256 amount, bytes adapterRoute)
adapterRoute = abi.encode(uint8 dexIndex, bytes dexCalldata)
```

* Kind 0 sells exactly `amount`, and the DEX must spend all of it.
* Kind 1 buys what the pool requires, spending at most `amount`. Only a leg that funds that requirement can use kind 1.
* Empty bytes mean no conversion. Any other kind reverts with `BadLeg`.

`dexIndex` picks a DEX router that the pool operator has whitelisted on the aggregator. `dexCalldata` targets that router and names the aggregator as its recipient. In the first Everlong vault, index 0 is 1inch and index 1 is Velora.

Each leg must return at least its input's value at the pool's checked feed price, less a tolerance. The tolerance is 1% on the asset router. On the crank, it's the request's current discount. No leg runs without a checked feed price.

## Single-asset deposits and exits

**The asset router makes the pool's proportional deposit or exit for a depositor who deals in one token.** It converts the rest through the aggregator.

```solidity
function depositFromAsset(
    address assetIn,
    uint256 poolAssets,
    uint256 maxAssetIn,
    uint256 minSharesOut,
    address receiver,
    uint256 deadline,
    bytes calldata routeIn,
    bytes calldata routeRebate
) external returns (uint256 shares, uint256 assetInUsed);

function redeemToAsset(
    address assetIn,
    address assetOut,
    uint256 shares,
    uint256 maxAssetIn,
    uint256 minAssetOut,
    address receiver,
    address owner,
    uint256 deadline,
    bytes calldata routeIn,
    bytes calldata routeOut
) external returns (uint256 assetOutAmount, uint256 assetInUsed);
```

`assetIn` and `assetOut` each name the pool asset or the first loan asset. Any other token reverts with `BadAsset`. The caller sizes each leg from the pool's preview, plus a slippage margin of its own.

A `depositFromAsset` call deposits exactly `poolAssets` and mints the shares to `receiver`. The router pulls `maxAssetIn` from the caller and returns everything it didn't spend. `assetInUsed` is `maxAssetIn` less what came back in `assetIn`.

| Argument      | What it converts                                                                                                           |
| ------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `routeIn`     | `assetIn` into what the deposit requires. Selling the pool asset when the book needs no loan asset reverts with `Oversold` |
| `routeRebate` | The other token left after the deposit, back into `assetIn`. Exact input only                                              |

Only the share owner can call `redeemToAsset`, and a call from anyone else reverts with `NotOwner`. When the book has net debt, the pool takes the shares' net loan asset (`netLoanAssetIn`) before it releases anything. So the exit runs in this order:

1. The owner approves the router for the shares, and for `maxAssetIn` of the token it fronts.
2. The router takes the front in either of the pool's assets. It sells a pool-asset front for the loan asset on `routeIn`. When `assetIn` is the loan asset, `routeIn` goes unused.
3. It redeems the shares, and the front pays the net loan asset the pool's call takes.
4. It returns the unspent front to the owner, with any loan asset bought beyond what the pool took.
5. It converts the proceeds to `assetOut` on `routeOut`, an exact-input leg, and pays them to `receiver`.

A leg that leaves the router short of what the pool requires reverts with `RouteShort`. Spending past `maxAssetIn` reverts with `MaxAssetIn`. Anything a rebate or proceeds leg leaves unsold is paid out in kind.

On a deposit, the router passes `minSharesOut` through. On an exit, it redeems with a zero floor, so `minAssetOut` is the only floor. When `assetIn` and `assetOut` are the same token, `minAssetOut` applies to the payout less the front spent.

[Deposits and withdrawals](https://docs.foreverlong.io/everlong/deposits_and_withdrawals) follows an Instant deposit and exit through the router on the first Everlong vault.

## Entry market

**The entry market holds deposit and exit requests for one pool.** Each request waits until a settlement call fills it. A request escrows the pool asset or the shares, so the requester approves the market for that token first.

```solidity
function requestDeposit(uint256 assets, uint256 minShares, uint16 maxBps, uint32 rampSeconds, uint48 expiry)
    external returns (uint256 id);
function requestRedeem(uint256 shares, uint256 minAssets, uint16 maxBps, uint32 rampSeconds, uint48 expiry)
    external returns (uint256 id);
```

A request reverts with `BadParams` unless its arguments sit inside these bounds:

* a minimum output above zero
* a `maxBps` from 1 up to the market's `maxBpsCap()`, which starts at 100 and which the pool operator can set up to 1,000
* a `rampSeconds` from 60 seconds to seven days
* an `expiry` within 30 days and no earlier than the end of the ramp

A deposit request also reverts with `NotAllowed` for a requester the allowlist refuses. Any new request reverts with `MarketPaused` while the market is paused.

`IntentOpened` announces each request, and `intentAt(id)` returns it. `toleranceBps(id)` gives the discount the request can fill at now.

| Call                                   | Who can call it             | What happens                                                                                                                    | Moves the pool's book |
| -------------------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| `net(depositId, redeemId)`             | Anyone                      | Settles a deposit request against an exit request at the pool's value per share, with no discount                               | No                    |
| `fill(id, amount)`                     | Anyone except the requester | The maker delivers the other side from its own inventory, at value per share less the current discount, and receives the escrow | No                    |
| `fillPar(id, amount, assetIn, loanIn)` | Anyone except the requester | Settles through the pool's proportional calls, with the maker fronting what the pool's call needs                               | Yes                   |
| `crank(id, amount, route)`             | Anyone                      | Settles through the pool's proportional calls, converting through the DEX aggregator on a route the caller builds               | Yes                   |

With `fill`, the maker approves the market for what it delivers: pool shares to a deposit requester, or the pool asset to an exit requester.

With `fillPar`, the maker sends `loanIn` of the loan asset, at least what the pool's call takes. It can add `assetIn` of the pool asset, and it approves the market for both first.

The requester gets at least their discounted value and their minimum. The market sweeps the rest to the maker, including any loan asset paid out.

`previewFillPar(id, amount, assetIn)` quotes what the requester receives, and what the maker pays and gets back. It skips the pool's gates and the self-fill rule. It's exact only with no performance fee pending and nothing above escrow.

**With `crank`, the requester receives the whole settlement, and the caller gets back only any loan asset it fronted.** The `route` argument is one [conversion leg](#conversion-legs).

* **On a deposit,** the leg sells part of the escrow for the loan asset the pool requires, or sells the deposit's loan-asset payout.
* **On an exit,** the caller approves the market for the `netLoanAssetIn` that `previewRedeemProRata` returns, then fronts it. The leg sells part of the proceeds to repay that front in full, or sells a loan-asset payout.

Anything the leg doesn't sell goes to the requester in kind. On an exit, the market checks the requester's minimum against the payout's value at the feed price. On a deposit, it checks the minimum against the shares minted, and the in-kind part counts only toward the discounted value.

A sale that funds the pool's requirement reverts with `RouteShort` if it delivers less than the requirement. It reverts with `Oversold` if it sells more than the requirement is worth at the feed price plus the discount.

Every settlement follows these rules:

* It can't run in the block the request was posted in (`SameBlock`), at or after its expiry (`Expired`), or once the request is closed (`NotOpen`).
* An `amount` of zero, or above what's left, settles the whole remainder. A smaller one shrinks the requester's minimum in proportion.
* It reverts with `Slippage` if it would pay the requester less than their minimum, or less than value per share less the current discount.
* A deposit request settles only while its requester still passes the allowlist.
* The market first has the pool mint any performance fee it owes, and needs a readable value per share.

The requester can `cancel(id)` at any time. Anyone can cancel once the request expires. Anyone can also cancel a deposit request once the allowlist stops admitting the requester. Either way, the escrow returns to the requester. Anyone can `skim()` the market's balance above escrow to the pool's fee receiver.

## Tranches

**Depositors call the senior and junior tranche tokens, whose asset is the pool share.** So every tranche flow moves pool shares. The controller holds those shares, but a depositor approves the tranche token it calls. That token moves the shares to the controller on entry. An allowance on the controller, or on the other tranche token, funds nothing.

| Lane         | Calls                                                                                                                          | Who settles it                                       |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------- |
| Senior entry | `deposit(assets, receiver)` or `mint(shares, receiver)`, or `depositWithDeadline` and `mintWithDeadline`                       | Settles at once                                      |
| Senior exit  | `requestRedeem(shares, receiver, owner)`, then `claimRedeem(id)` from day seven, or `cancelRedeemRequest(id)` until it settles | The owner, or the operator that filed it             |
| Junior entry | `requestDeposit(assets, receiver, deadline)`                                                                                   | Anyone, through the controller's `settleForward(id)` |
| Junior exit  | `requestRedeem(shares, receiver, owner)`                                                                                       | Anyone, through the controller's `settleForward(id)` |

In `requestRedeem`, the second argument is the payout receiver, unlike in ERC-7540. A caller other than the owner spends the owner's allowance, must name the owner as receiver, and becomes the request's operator.

An app that fills junior requests reads `fwdState(id)`. Once the state reads `Fillable`, the app calls `settleForward(id)` inside the window that [Forward pricing](/use-efficient/provide-liquidity/tranches.md#forward-pricing) describes. Before then, the call reverts with `PrintNotFresh`. It reverts with `CapBreached` when the coverage cap admits nothing.

`cancelForward(id)` cancels a junior request in two calls. The controller's `previewSettle`, `previewCancel` and `previewFill` quote requests.

On the junior token, `deposit` and `mint` serve only the pool operator's seed. Before the seed, a call from anyone else reverts with `NotCurator`. After it, every call reverts with `ForwardPriced`.

Neither token follows ERC-7540, and `redeem` and `withdraw` revert on both. [Tranches](/use-efficient/provide-liquidity/tranches.md) covers the caps, timing and pricing of each lane. [Smart contracts](/reference/smart-contracts.md) lists the events every route emits.
