Funding the pool

How the liquidity pool works — depositing from an admin wallet, withdrawing, the capital basis every P&L figure is measured against, and why the rebalance button reports rather than converts.

6 min readUpdated 3 August 2026pool, liquidity, deposits, withdrawals, rebalance

The pool is real money. Its two balances — base and quote — are the only thing between an admin's ecosystem wallet and the market's inventory. A deposit takes from the wallet and raises the pool. A withdrawal lowers the pool and credits the wallet. Every real user fill settles against those same two balances, in the same transaction that pays the counterparty.

The Pool tab on a market's detail screen is where all of this happens.

What a pool holds

Field Meaning
baseCurrencyBalance Units of the market's base asset held now
quoteCurrencyBalance Units of the quote asset held now
initialBaseBalance / initialQuoteBalance The capital basis — everything you have put in, less everything you have taken out
totalValueLocked (base x price) + quote, valued in the quote asset
realizedPnL Profit and loss from fills against real users
unrealizedPnL Mark-to-market on the inventory currently held

totalValueLocked is a plain sum in the pool's quote denomination. Where two of your markets quote in different assets, the dashboard's total has no unit at all and does not print one — a sum across USDT and BTC pools is a number, not an amount of money. Where every market shares a quote asset, the ticker is named once beside the figure.

Depositing

  1. Open the market's Pool tab. The panel shows both pool balances and your own ecosystem wallet balance for each side.

  2. Pick a side — BASE or QUOTE — and an amount. The amount must be greater than zero and cannot exceed your wallet balance; the refusal names both figures.

  3. Submit. The deposit debits your ecosystem wallet, credits the pool, recalculates TVL against the market's target price and writes a DEPOSIT history entry. It is one database transaction: nothing moves if any part fails.

Funding is an internal transfer between two balances the platform already holds. It needs no deposit address and no configured chain, and it reads the wallet directly. An admin holding a good balance in a token whose chain is not configured on that server can still fund the market.

Deposits and withdrawals are ordinary repeatable operations — you fund the same pool many times over its life — so the wallet ledger key is unique per request. A client that retries a submit and wants exactly-once behaviour must send the same idempotencyKey on both attempts. Without one, two identical requests are two deposits.

An older build derived that key from (pool, currency) alone, which meant a pool could be funded exactly once per currency, ever. Every top-up after the first answered "Duplicate operation detected", permanently. If you are on a build before v6.1.5, that is what you are seeing.

The capital basis accumulates

initialBaseBalance and initialQuoteBalance rise on every deposit and fall on every withdrawal. They are the denominator of the pool's return, so getting them wrong misstates performance rather than losing money: an older build recorded them on the first deposit only, so a pool funded ten times reported its return on a tenth of the money, and a drained pool still reported its original capital.

Withdrawing

Withdraws from the pool back to the admin's ecosystem wallet

Two guards:

  • The market maker must not be ACTIVE. Pause or stop it first. A withdrawal from a quoting market would race its own settlement.
  • The amount cannot exceed the pool balance on that side. The refusal names the available figure.

Because withdrawal refuses an active market, a market that is stuck ACTIVE locks its pool. If the engine has lost a market and the admin screens cannot stop it, see Troubleshooting.

How much a market needs to start

Starting a market maker checks two things:

  • totalValueLocked must be greater than zero"Cannot start market maker without liquidity. Please deposit funds first."
  • If aiMarketMakerMinLiquidity is set, the quote balance must clear it. The refusal quotes both the requirement and what the pool actually holds.

The same minimum is re-checked by the engine when it loads the market, so a market that passes the admin screen and then fails the engine's check will fail to start with the reason in the log.

Note that neither check applies to trading once real liquidity is off. With Real Liquidity at 0% the pool is not touched by bot-to-bot trades at all — but you still cannot start the market with an empty pool.

Rebalancing

Over time a pool is pushed to one side of the book: absorbing user sells leaves it long the base asset, absorbing buys leaves it long quote. The dashboard reports this as inventory skew — the share of pool value now held in base, against the share it was funded with, both valued at the current price so the market's own price move does not contaminate the reading.

The rebalance control has two modes.

REPORT — the default, and what the button does

Calculate rebalance sizes the trade a target ratio would require and changes nothing. It returns the required movement in each currency. The market maker must be paused or stopped even for this: a report taken while the AI is quoting is stale before it renders.

EXECUTE — a real trade against the real book

mode: "EXECUTE" places a genuine limit order against real order-backed depth in the Ecosystem book and lets the matching engine settle it. Every unit that enters the pool leaves a counterparty's wallet. It refuses outright — HTTP 409 — rather than partially filling, when the real book cannot cover the move or when covering it would push the price further than maxSlippagePercent (default 2).

An older build calculated the balances a requested ratio would need and simply wrote them onto the pool, under a comment describing it as a simulated rebalance. Those balances are not a projection. The exploit was three clicks:

deposit 20 BASE          -> pool holds 20 BASE, 0 QUOTE
rebalance to ratio 0     -> pool "holds" 20 x target price in QUOTE
withdraw QUOTE           -> a real credit on a real ecosystem wallet

Both the target price and the price range are operator-settable, so that was a conversion between any two ecosystem tokens at any rate the operator chose, with no counterparty. The automatic rebalancer had always refused to do it; the admin action now matches.

The supported way to shift a pool's composition without EXECUTE is to move real assets: withdraw the surplus side, trade it wherever you normally would, and deposit the proceeds back.

The automatic rebalancer

processAiPoolRebalancer runs hourly. It reports drift; it does not convert balances. Like every other scheduled job in the addon it treats an unset global trading switch as on — two of them used to require the switch to have been explicitly saved once, and reported completed on every pass while doing nothing at all on a fresh install.

Reading P&L honestly

A trade between two of the platform's own bots has no profit or loss — both sides are the house. Only fills against real users produce a number, which means:

  • On a market running at 0% real liquidity, realised P&L is legitimately zero however busy the tape looks.
  • Bot statistics show the real count of fills against real users and the real profitable count, and show nothing where there is nothing to measure. A confident win rate on a bot that has never met a counterparty is a symptom of a build before v6.1.5, not a measurement.

The P&L report separates its sources: the all-time figure comes from each bot's lifetime accumulator, while daily, weekly and monthly come from a per-fill ledger that only began recording in v6.1.0. The report states when that ledger begins, so a large all-time figure beside three small ones reads as a short ledger rather than as a collapse in performance.

Unrealised P&L values the pool's inventory at the current price. An older build valued the opening inventory at a price of 1 — a pool funded with 40 base on a market at 100 had its opening capital valued at 40 instead of 4,000, and the engine wrote a roughly +3,960 "unrealised profit" to it every minute for a position that had never traded.