Skip to content

The AGORA Exchange

An order book where the listings are organizations, the shares are a registry ledger, and every cent of every trade moves through a single audited escrow endpoint. A real central-limit order book built on top of a token economy whose first commandment is "supply never drifts." This is how you run a stock exchange without ever letting the auditor's delta leave zero.

Why It Matters

Chapter 02 gave you AVT — balances, transfers, the supply invariant. Chapter 20 gave you organizations — teams of agents under one banner. AGORA is what happens when an organization wants to raise capital and let the market price it: it lists, sells an IPO float, and from then on its shares trade continuously against resting bids and asks. Price discovery, dividends, the whole apparatus.

The hard part isn't the order book — central-limit order books are a solved problem. The hard part is doing it on a ledger that audits itself to zero every second. A naive exchange mints and burns and moves money in a dozen code paths; each one is a place where supply can drift and the auditor (chapter 07) goes red. AGORA's central design decision is the opposite: shares live in their own registry-local ledger and never touch the TEG, while every single money leg — deposits, fills, fees, dividends, refunds — flows through ONE escrow endpoint that is supply-neutral by construction. One money surface. One replay key. One floor gate. The auditor never even notices the exchange exists.

AGORA began as a bare order book, and has since grown into a full corporate-finance venue: federated stock cards, org treasuries, dividends, buybacks, re-floats, governance-gated dilution, stock splits, maker-taker rebates, advanced order types, a signed solvency attestation, and cross-frame shareholder voting — every one of them shipped under the same iron rule that supply never drifts. It runs live on all three sovereign venues at once, each settling in its own frame's currency — Frame A in AVT, Frame B in JDAY, Frame C in BVT — with the cloud-operator registries carrying the code but venue-dark (no local listings, so the exchange paths stay inert until one hosts a listing). Δ=0 holds across all three frames throughout every deploy, with escrow draining to exactly 0E-18. The venue code never names a currency: each book settles in whatever its frame's TEG calls money, so the same engine runs a three-currency exchange without one line of per-currency logic.

The Two-Ledger Split — The Idea Everything Hangs On

Read the diagram as two boxes that barely talk:

  • Shares are registry-local rows. A position is a row in exchange_positions keyed by a plain DID string. An order is a row in exchange_orders. None of it is a TEG balance. Migration 0088_agora_core created these tables; they are boot-replay-idempotent (the migration bridge re-stamps every boot, so every CREATE is IF NOT EXISTS).
  • Money is a single endpoint. Every leg that moves currency calls POST /api/v1/admin/exchange/move on the TEG (teg_core_service/api/v1/endpoints_exchange_admin.py). It is a clone of the proven /admin/fx/move: one side of every move must be teg:system:exchange_escrow; the call carries an exref:{key} idempotency token in the transaction's attached_message; and when escrow is the source, a solvency floor refuses to overdraw. Under the hood it's a plain execute_transfer — the same balance-journal trigger and outbox that powers every other transfer fires, emitting LedgerBalanceChanged with kind routed to transit_net. That is why the supply invariant never moves: an exchange trade is, to the auditor, just another supply-neutral transfer.

Because shares never enter the TEG and money never enters the share tables, the two ledgers can each be audited independently and neither can corrupt the other. The exchange's own four (now five) invariants check the seam between them.

The Order Lifecycle — Crash-Safety by State Machine

Three order shapes, each a deliberate state machine designed so that a crash at any instant is recoverable by simply running again (services/exchange_service.py):

BUY  : insert(funding) → deposit leg (cash → escrow) → advisory-lock tx (open → match → trades pending)
SELL : ONE advisory-lock tx (lock shares → insert open → match)              [single-DB ACID, no money at risk]
IPO  : insert(funding) → deposit → lock allocate-or-refund → worker proceeds leg (escrow → org treasury)

The asymmetry is the whole trick. A sell risks no cash — it locks shares (a registry row update) and matches inside one ACID transaction, so it's atomic and needs no recovery. A buy must move money before it can rest on the book, so it splits into a durable funding row, then a deposit leg through the mover, then the lock-and-match — and if the process dies between the deposit and the open, the funding row is the recovery anchor (the settlement worker re-fires it). Money is escrow-held in the gap; nothing is lost, only delayed.

Here is a buy crossing a resting ask, end to end:

The match itself (_match) is price-time priority: best price first, oldest order first at a price. Crossing the spread executes; price-improved fills go to the maker's price (the taker gets the better deal). Fills produce exchange_trades rows in pending_settlement — the shares move at match time (a registry row update, instant), but the cash settles on the worker's next pass. That gap is the only place escrow holds money mid-trade, and invariant I-X3 accounts for every cent of it.

INFO

Why shares-now, cash-later? Because moving shares is a local DB write (cheap, ACID, can't fail half-way) while moving cash is a TEG call (a network hop to a separate service that can convoy under load). Decoupling them means a slow money layer never blocks price discovery — the book stays liquid, and settlement drains in the background with its own back-pressure. It's the same CQRS instinct as the rest of the platform: the command (match) is fast and synchronous; the financial projection (settle) is eventually-consistent and idempotent.

Fees — Taker Pays, Seller's Cut, Maker's Rebate

Fees are 30 bps of the taker's notional, deducted from the seller's proceeds — the buyer's escrow deposit stays exact (no surprise top-up). The fee splits 1/3 to fee_collector, 2/3 to the org's treasury agent, with a per-listing override from 0 to 100 bps. The split is deliberate: the protocol takes a thin cut, but the organization whose shares are trading earns the majority — listing on AGORA is a revenue stream for the org, not a tax on it.

The Maker Rebate — Subsidising Liquidity Without Minting a Cent

A healthy book needs resting orders. So AGORA can pay the maker — the resting side of a fill, the one that was already on the book at the matched price — a rebate. The question that makes or breaks this feature is: where does the rebate money come from? If it's minted, supply drifts and the whole edifice falls. AGORA's answer is that the rebate is carved out of the taker fee that's already being collected — nothing new is created.

The arithmetic is the load-bearing part. At match time the matcher computes fee_total as before, takes the org's slice fee_org as before, and then carves the rebate out of what's left (the protocol's slice): fee_maker_rebate = min(fee_total − fee_org, notional · rebate_bps/10000). The protocol slice is then re-derived as fee_proto = fee_total − fee_org − fee_maker_rebate — non-negative by the min bound. So the four settlement legs — the seller's payout (notional − fee_total), fee_org, fee_proto, and the rebate — sum to exactly the notional, every time. The escrow nets to zero, I-X3 is unchanged, and compute_invariants doesn't even need to know rebates exist (it sums notionals, never the fee breakdown). The taker still pays exactly fee_total; the network gives up part of its cut to subsidise the maker; the org's share is untouched.

The rebate settles as a fourth leg beside the fee legs — escrow → maker for a local maker, or parked on the gateway and repatriated home (with its own exref replay key) for a foreign passport maker.

::: warn Rebates can't be farmed. A naive rebate is an arbitrage magnet — wash-trade with yourself, collect the rebate forever. AGORA gates it: the rebate fires only if the maker holds a registered, active market-maker seat for that listing (granted and revoked by the org admin), unless the org explicitly drops that requirement. Production posture is registration required — only vetted liquidity providers earn rebates — until automated trade-surveillance ships to police it the other way. :::

Advanced Order Types — TIF and Post-Only

Beyond a plain resting limit order, the book understands the time-in-force vocabulary a real trader expects, plus a maker-only flag:

  • GTC (good-til-cancelled, the default) — rest on the book until filled or cancelled.
  • IOC (immediate-or-cancel) — take whatever can fill right now against resting liquidity, then cancel the unfilled remainder instead of resting it.
  • FOK (fill-or-kill) — all-or-nothing: the order is dry-run against the book and rejected outright before any escrow moves unless it can fill completely.
  • post-only — never cross the spread. If the limit price would take liquidity, the order is rejected pre-escrow — guaranteeing the order rests as a pure maker. This is the natural partner to the rebate: post-only is how a market-maker guarantees it stays on the rebate-earning side.

These are additive and opt-in — the defaults (tif=gtc, post_only=false) are byte-for-byte the original behaviour, so no feature flag was needed. They're Δ-safe by the same discipline as everything else: a buy still escrows its full qty·cap; FOK and post-only do their rejection before any money moves; IOC's remainder cancellation drains through the same idempotent refund path the worker already runs.

IPO → Secondary Market — Where New Shares Stop and Trading Begins

A listing is born with a fixed IPO float: the org keeps total_shares − ipo_float (granted to its treasury position at approval), and offers ipo_float shares to the market at a fixed ipo_price. The IPO is the primary issuance — the only place shares enter circulation at a fixed price.

The question developers always ask — "once the IPO target is reached, can you still buy?" — has a precise answer in services/exchange_service.py:

  • ipo_buy checks if listing.ipo_sold + qty > listing.ipo_float: raise 409 "IPO float remaining: N". Once ipo_sold == ipo_float, the primary is exhausted and /ipo/buy returns 409.
  • But the listing stays status=trading, and place_order only blocks if status != "trading". So the secondary market keeps working — you buy from other holders on the order book, matched against resting asks, at whatever price the market makes.

So: yes, you can always still buy — just not new shares at the fixed IPO price. Price discovery moves to the book. This is exactly how a real IPO→secondary transition works, and the invariant I-X1 guarantees shares are conserved across the boundary: Σ positions == (total − float)·approved + ipo_sold.

Federated Stock Cards — Every Venue's Catalogue, Everywhere

A venue is useless if nobody can find what trades on it. The naive answer is a central directory — one server everyone queries. AGORA's answer is the opposite, and it reuses the federation machinery chapter 18 built for registry cards: every venue publishes a signed catalogue at /.well-known/stock-card.json, and those catalogues ride the existing registry-card fan-out across the entire federation. The result is that any registry on the network can show you every listing on every other venue — without ever needing a direct connection to it.

The card itself is small and EdDSA-signed by the venue's own registry keystore (the same keystore that signs its Registry Card v0.3 in chapter 18). It carries the venue's SPIFFE id, its settlement currency, and a content digest over the catalogue — and it's linked from the registry card via fees.exchange.stock_card.{url, digest}. So far, ordinary federation.

The clever part is the fan-out carry. When registries gossip their cached view of the network (the /federation/registry-cards relay), each relayed peer card now ships that peer's stock-card catalogue inline (RegistryCardSyncData.stock_card). A registry that has never spoken to frame-c directly still receives frame-c's catalogue, second-hand, inside a card it did receive — and it trusts the catalogue because the digest is signed into the relayed card it can verify, not against frame-c's keys it may never have seen. The ingest path (_ingest_carried_stock_card) is fail-closed and digest-gated, with a strict direct-wins rule: a catalogue you fetched first-hand always overrides one carried to you second-hand. The whole thing is backed by the federated_stock_cards table (migration 0094).

This is why Stock Discovery (the public listings browser) shows you the whole network, not just your home venue's tickers — and why each foreign listing carries a "View on <venue>" deep-link straight to the venue that hosts it. A listing's digest includes its total_shares, so the moment a corporate action changes the share count (a dilution or a split, below), the digest changes, the card re-signs on its next serve, and the new catalogue propagates — no manual push, no stale cache.

Corporate Actions — A Cap Table That Behaves Like One

The payoff of putting shares in their own registry-local ledger (rather than minting them as TEG tokens) is that they can behave like a real cap table — issued, retired, re-floated, split — and every one of those actions is Δ-neutral, because shares were never money in the first place. The auditor's invariant lives on the TEG; the share ledger has its own invariant, I-X1, and corporate actions are designed to keep it balanced by construction.

All of these are org-admin operations on a listing (chapter 20's role hierarchy decides who counts as an org admin), and all of them route through the org treasury described in the next section.

  • Re-float — an org keeps total_shares − ipo_float retained in its treasury at IPO. Re-float sells some of that retained block back to the market (re-listing it into the float / secondary book). No new shares; the treasury's position shrinks, the public float grows, I-X1 is untouched.
  • Treasury-sell — the keyless treasury places an ordinary sell order on the book on its own behalf. Same conservation: shares move from the treasury position to a buyer, cash flows the other way through the standard mover.
  • Treasury market-making — the treasury can quote both sides to tighten the spread (TreasuryMMConfig, per-listing, default OFF). The subtle bug it had to avoid: a naive maker cancels and re-posts every tick, and each cancel-replace churns the escrow that I-X3 audits. So it was refined to re-quote only when the price has drifted — no drift, no order churn, and I-X3 stays flat-zero continuously whether the simulator is running or idle.
  • Dilution — issuing new shares. This is the one corporate action that can't be unilateral, because it dilutes existing holders — so it is governance-gated: an org-admin opens a dilution proposal naming new_shares, the shareholders vote (below), and only a passed proposal can be executed. Execution mints total_shares += N and credits the treasury position += N — the exact dual of a re-float, so I-X1 stays balanced with both sides growing by N. It emits ExchangeSharesIssued, is idempotent (a second execute → 409), and lands new shares in the treasury (the org then distributes them via re-float or treasury-sell). Because the stock-card digest includes total_shares, the dilution re-signs and re-propagates the catalogue automatically.
  • Stock split — a forward N:1 split (factor 2–1000; reverse splits are deferred pending a fractional-share policy). A split is purely proportional — it rescales every holder and the price together, so market cap is unchanged and no holder is advantaged. Because it's administrative rather than dilutive, it needs no governance vote — but it requires no open orders on the listing (the org halts and clears the book first), because rescaling a resting order's price on the tick grid would drift its escrow notional. Under a listing lock it multiplies every position's qty, the total_shares/ipo_float/ipo_sold counts, and the ipo_price (tick-snapped) all by N. It emits ExchangeSharesSplit; I-X1 stays balanced with both sides scaled by N.

Governance — Shareholders Vote Their Shares

A listing's shareholders govern it the same way the network's stakers govern the protocol (chapter 06) — by weighted vote — but the weight here is one share, one vote, taken from a frozen snapshot of the cap table at proposal time (the treasury's own holdings are excluded). The lifecycle mirrors chapter 06's: an org-admin opens a proposal (advisory for a signalling vote, or dilution to authorise new issuance), shareholder agents vote (agent JWT, not developer JWT — the same boundary governance draws), the proposal is tallied, and a passed dilution proposal is executed to mint the shares it authorised. The snapshot tables (ExchangeProposal / ExchangeProposalHolder / ExchangeProposalVote) freeze each holder's weight when the proposal opens, so buying more shares mid-vote doesn't retroactively change a ballot.

Cross-Frame Governance — Nobody Is Disenfranchised by Geography

There's a trap hiding in "shareholders vote." A listing on Frame A can have shareholders whose home is Frame B — passport holders who bought in across the currency border. If voting required authenticating on the listing's home registry, those foreign-homed holders would be 401'd, couldn't vote, and a passport-heavy listing might never reach quorum. So AGORA mirrors the veToken federation pattern from chapter 06's federation governance, with one inversion:

A foreign shareholder votes through their own home frame, which vouches for them over peer mTLS — but here the listing's home frame is the hub (not the mainframe EventStore). That works because the share weights are already frozen in the listing's proposal snapshot, so the home venue is the natural authority — no EventStore round-trip, no trust-discount, a clean one-share-one-vote. The home frame relays the ballot over the same peer-vouched mTLS channel the passport already uses (POST /api/v1/federation/agora-vote), stamping the voter's home-frame SPIFFE identity onto it. The tally then reports distinct_registries, so you can see the vote spanned frames.

The Org Treasury — Where a Listing's Money Lives

Every listing is born with a keyless treasury agent (did:theprotocol:org-{ticker}-treasury) created at listing time — its client-secret is generated and immediately discarded, so no human ever holds its keys; it is operated only by org-admin endpoints, server-side. Into it flow the IPO proceeds and the organization's share of every trading fee (the 2/3 org cut described above). Out of it flow dividends, buybacks, transfers, and the shares for re-floats and treasury-sells.

GET /organizations/{org_id}/treasury gives an org member the consolidated roll-up — the treasury's live TEG balance plus lifetime raised / fees_earned / dividends_paid, across all of the org's listings. And org-admins spend it through a small family of server-side movers — dividend, buyback, transfer, same-org sweep — each of which is, like everything else on the venue, a supply-neutral escrow move stamped exchange_treasury_*. There is no key to leak and no path that mints; the treasury can only move money it already holds, and the auditor's delta never twitches.

The Settlement Worker — One Drain Loop, Nine Idempotent Batches

Everything deferred — seller payouts, stuck-buy recovery, refunds, IPO proceeds, dividends, parked fees, TTL expiry, cross-frame funding, repatriation — drains through a single leader-elected worker (background_tasks/exchange_settlement.py), 2s busy / 10s idle. Each batch is its own try/except so one failing class never starves the others, and every drained operation is exref-replay-idempotent on the TEG side, so a crash at any point is recovered by running again. Money is escrow-held in the meantime; I-X3 accounts for it, I-X4 alarms if it stalls.

The worker is built to stay inside its own lease. run_cycle is deadline-bounded at 12 seconds — comfortably inside the 30-second leader lease, so it renews before lapsing and a second worker can never pick up an overlapping batch onto the single escrow hot row. Each settlement leg carries a 5-second timeout, and a failure-storm back-off (≥8 consecutive fails → sleep 20s) keeps a transient downstream stall from turning into a re-hammering convoy. The result is a settlement layer that drains smoothly under sustained order flow and degrades gracefully, never catastrophically.

The Invariants — The Venue Checks Its Own Seam

GET /api/v1/exchange/admin/invariant (admin) runs compute_invariants and returns a verdict. These are the load-bearing safety properties — the seam between the share ledger and the money ledger:

Statement
I-X1Σ positions.qty == (total_shares − ipo_float)·approved + ipo_sold (shares conserved, per listing)
I-X2Σ positions.locked_qty == Σ open SELL remaining (lock honesty, per listing)
I-X3TEG escrow balance == Σ buy holds + unsettled trade notionals + funded-pot unpaid dividend legs + IPO in-flight + parked listing fees — exact, to 18 decimal places
I-X4no trade pending_settlement older than EXCHANGE_SETTLE_SLO_SEC (settlement liveness)
I-X5gateway solvency: gateway float == Σ credited foreign holders (passport repatriation)

I-X3 is the crown jewel: it says the escrow account holds exactly the money the books say is in flight, to the cent, at all times. It was proven holding 0E-18 mid-trading, with hundreds of BVT in open-order holds in flight. The one legitimate transient is funding_orders_in_transition — a buy that has deposited but not yet opened; the sweeper converges it in ~30s. An I-X3.delta != 0 with funding=0 is a real incident: global-halt the venue and reconcile exchange_trades.settle_tx_refs against the TEG's attached_message LIKE 'exref:%'.

INFO

The one read-skew to know about. I-X3 is computed in two queries — the escrow balance, and the sum of open-order notionals — and they aren't snapshotted atomically. On a busy venue (the frame-c simulator under load), a fill can land between those two reads and momentarily show ix3=false. That is cosmetic read-skew, not drift — the single-statement atomic delta is the truth, and it's zero. The same caveat the supply auditor carries (chapter 07). The lesson for operators: confirm a non-zero I-X3 against the auditor's atomic delta and a re-read before treating it as an insolvency event.

Credibility — The Signed Solvency Card

Invariants the venue checks for itself are one thing; a counterparty wanting to trust an org's stock before buying its shares is another. So alongside the stock-card catalogue, every venue can publish a second signed document at /.well-known/solvency-card.json — a verifiable attestation that the books actually add up. It's an EdDSA-signed, read-only clone of the stock-card machinery (the simple registry-signed path was chosen over a zero-knowledge proof precisely because the attested facts are all public anyway), and it federates the same way — peers fetch and verify it through the fan-out, and the registry card links it via fees.exchange.solvency_card.

Per listing, the card attests three things:

  • Float integrity — does the share ledger balance? It stamps I-X1: the positions sum versus the expected share count.
  • Treasury solvency — can the org treasury cover what it owes? It reports the treasury's balance against its obligations (the sum of declared-but-unpaid dividend legs, open buyback escrow, and any market-maker cash floor) and a backed boolean.
  • Dividend coverage — is the latest declared dividend actually funded?

And venue-wide it stamps the global invariants — I-X3, I-X4, I-X5, and the auditor delta — with an as_of timestamp. The builder is defensive by construction: any read that fails degrades to a zero/null value with an *_unavailable note rather than throwing, so the card always serves. Because it's a pure read-and-sign with no money, share, or balance mutation, it is entirely Δ-irrelevant.

The honest framing matters here, and the card is careful about it: backed=false is a disclosure, not a halt. An org can legitimately be mid-funding a dividend it just declared; the card's job is to say so transparently, not to freeze trading. It's a credibility and disclosure signal — the market reads it and prices accordingly — not an enforcement mechanism. (And because a transient I-X3 read-skew could otherwise flash a misleading red on a credibility surface, the card re-checks I-X3 once on a transient-false before stamping it — a real drift still reports, a read-skew clears.)

Idempotency Is Not Optional — The Two Backstops

A replay lookup on the exref: key is not the same as a uniqueness constraint, and the difference is load-bearing: under a pooled-TEG lock queue a timed-out mover attempt can still commit later, so a naive lookup-then-retry could let concurrent or queued attempts double-execute. Two backstops make the replay key idempotent by construction:

  • TEG migration 0004_exref_unique — a partial UNIQUE index on exref rows where status IN (pending, completed). The create_transfer commits the PENDING row before the balance txn, so a duplicate dies on the index before any money moves; the loser is converted to a winner/409 no-op. (FAILED rows free the key, so a genuine retry of a failed leg still works.)
  • TEG migration 0005_attached_message_index — a plain index on teg_transactions.attached_message, so the exref: replay lookup stays O(log n) instead of back-scanning the full transaction history on every move. The migration makes the index permanent and fleet-uniform across every frame, keeping the mover fast and lock-contention-free under sustained load.

The doctrine is simple: every replay-keyed money endpoint needs both a uniqueness constraint and a usable index on the replay-lookup column. The fx/move fxref: path shares the pattern and inherits both.

AGORA Passport — Trading Across the Currency Border

Every venue settles in exactly one currency — its own frame's. An org listed on Frame C trades in BVT, one on Frame A in AVT, one on Frame B in JDAY; and the FX triangle from chapter 18 (AVT ↔ JDAY ↔ BVT, all six directions, a closed loop with no arbitrage) makes any one of them reachable from any other. So the question the Passport answers is the general one: how does an agent whose money is in one currency become a verified shareholder of an org priced in another, without the venue's order book ever holding more than its own single currency? The answer introduces the platform's third card type (chapter 18 had the registry card; chapter 01 had the agent card).

A developer (owner-identity) card: minimal-disclosure, home-registry-EdDSA-signed (it reuses the Registry-Card-v0.3 keystore, so it verifies against the home's federated /.well-known/registry-jwks.json). It is lazy and consent-bound — never bulk-synced. It is built and signed only when the dev's own agent opts into a foreign venue (PUSHED with the order = the purest form of consent), and every build writes a dev_card_disclosures row (who, which agent, when, why). That audit row is GDPR purpose-binding by construction. This is AGORA's KYC story — it extends the "no anonymous ghosts" principle across the federation without a central registry of identities.

The genius is FX at the border, single currency in the book. The foreign buyer's home currency is swapped to the venue's currency the moment it funds the gateway agent; the gateway then funds escrow in the venue's pure currency through the standard mover. The order book never sees a second currency — the swap lives entirely at the edge, on the FX triangle, where chapter 18's pools already price every pair. The diagram above traces one edge of that triangle (an AVT buyer into a BVT venue); a JDAY buyer into the same venue — or any of the six directions — takes the identical path, just through a different pool.

Repatriation — Bringing the Money Home

When a foreign holder earns a dividend, a maker rebate, or a buy refund, that money lands in the venue's currency for their DID. Repatriation (migration 0091_gateway_credits + worker batch I) writes each such credit to a per-buyer sub-ledger (exchange_gateway_credits) instead of parking it anonymously, then drains each row home over the same /teg/send rail (auto-FX venue currency → home currency at the edge, exref:repat-{id} replay key). I-X5 audits it: gateway float must equal the sum of credited foreigners.

The one operational hazard is the gateway running dry: deposits, order-funding, and repatriations all share one cross-frame float, and FX spread quietly bleeds it. So a Gateway Float Keeper tops it up — a MOVE-only refill from the treasury to the gateway, targeted at the sum of pending repatriations plus a buffer, that never mints (it only relocates money the treasury already holds, via the reward-funding waterfall). Repatriations never strand for lack of float, and the supply invariant never moves to keep them flowing.

Liquidity — Funding the Market

A market needs participants with balances. On the canary, liquidity comes from a fleet of simulated trader agents funded through the canonical treasury chain — never DB surgery, always the API:

  • Local traders (agents on a venue's own mainframe) are funded treasury → agent via POST /api/v1/teg/treasury/fund-agent (the reward-funding waterfall: fee_collector → treasury).
  • Cross-frame / operator traders are funded through the chain the frame doc (chapter 18) describes: mint on the mainframe if the treasury is short → POST /teg/treasury/cross-teg-fund (treasury → operator treasury, capped at 10M/call so bulk moves chunk) → fund-agent on the operator. Minting raises tokens_issued and tokens_circulating equally, so Δ stays 0 even as supply grows.

Every funding leg is a supply-neutral or mint-balanced transfer; the auditor's delta never moves. This is the same property that lets the exchange itself run at Δ=0 — funding the market and running the market are the same kind of conservative operation.

Market Data — Reading the Market

Beyond the per-listing book, trades, and OHLCV candles, two public reads make the market legible at a glance:

  • The cap-table (GET /listings/{ref}/holders) — the external shareholders of a listing, paginated, each with their share count and percentage, plus the totals (holder_count, treasury_qty). It deliberately excludes the keyless org treasury, so you see the real outside ownership, not the founder's retained block. This is the same transparency a public company's share register provides, served from the registry-local share ledger.
  • The AGORA-10 index (GET /index) — a market-cap-weighted index over the top-N listings across the venue, where each constituent's market cap is last_price · total_shares (falling back to the IPO price for a listing that hasn't traded yet). It returns the index_value plus the constituents with their weights — a single number for "how is the whole market doing," computed on serve with a 30-second cache.

The Exchange Desk — Where Humans Trade

The frontend (/ui#/exchange, route exchange, requiresAgent, ambient cyan) is a full trading terminal built without a single charting dependency:

  • A markets rail with live Δ% · a custom CandleChart.vue (canvas OHLCV + volume + crosshair, hand-drawn) · an order-book ladder (click-to-prefill, flash-on-change) · a live tape over the same-origin Event Store WebSocket (typed channel events:ExchangeTradeExecuted, poll fallback with a LIVE/POLL badge) · an IPO progress bar · a trade panel with notional + fee preview, a TIF selector (GTC / IOC / FOK) and a post-only toggle, and a ticker-match confirmation for orders over 10k · a portfolio with P&L and dividends · and a top-traders board.
  • A solvency panel rendering the signed Solvency Card — backed status, float-integrity, dividend-coverage, the venue invariants, and a SIGNED badge — so a trader sees the disclosure in the same place they place the order.
  • A cap-table panel (the holders read above) showing who owns the listing.

On the Stock Discovery browser, the federated listings (your venue's tickers unioned with every catalogue carried in from across the federation) carry their "View on <venue>" deep-links, and an AGORA-10 ticker strip runs the index across the top.

Org-admins get their controls on the Organization Dashboard's Treasury tab: the consolidated treasury cards and per-listing table, the Re-float / Sell / market-maker actions, the maker-rebate config, market-maker-seat grants, and fee edits, and a committed-MM panel.

The exchange events — ExchangeListingCreated/Approved, ExchangeOrderPlaced/Cancelled, ExchangeTradeExecuted, ExchangeDividendDeclared/Paid, ExchangeListingHalted, plus the corporate-action and governance events (ExchangeShareRefloated, ExchangeSharesIssued, ExchangeSharesSplit, ExchangeProposalOpened/Tallied, ExchangeVoteCast) — all carry aggregate_id = listing_id, which gives every listing a free per-symbol live channel on the Event Store WebSocket. They are skip_in_projection=true — they are the narrative of the market; the money trail is the TEG legs' LedgerBalanceChanged stream, counted exactly once.

Operations & Monitoring

  • Enable / disable a venue with EXCHANGE_ENABLED on the registry (orders 503 when off; reads stay up). Instant no-deploy freeze: POST /api/v1/exchange/admin/global-halt {"halted": true}.
  • Feature flags, all env, all instant-off: EXCHANGE_ENABLED (master) · EXCHANGE_PASSPORT_ENABLED (cross-frame trading, fleet-wide on) · EXCHANGE_CROSSFRAME_VOTE_ENABLED (cross-frame governance) · EXCHANGE_SOLVENCY_CARD_ENABLED (the signed card) · EXCHANGE_MAKER_REBATE_ENABLED (the rebate). Dilution, splits, fee-edits, the order types, the cap-table, and the index carry no flag — they're either inherently gated (org-admin plus a passed vote) or additive-with-current-defaults, so there's nothing to switch on.
  • The rollback ladder: flag off → global-halt → delist (cancel-all + refund-all, idempotent) → restore the pre-roll image (every feature ships behind its own pre-roll image tag). Tables are additive; escrow funds stay ledger-safe across restores because every leg replays.
  • The throughput governor is the settlement worker keeping pace with order flow. The market-simulation controller (scripts/sim_eigentrust.py, --mode market) holds a placement-latency SLO of ≤2500 ms as an AIMD governor — push pressure with concurrency, never with a higher target (a higher peg drives in-flight up until the escrow mover convoys, which lags the whole frame).
  • Monitoring: a family of agora_* Prometheus series (core/exchange_metrics.py) — counters at order placement and fills, gauges refreshed every 60s by the worker via compute_invariants (escrow balance, invariant delta, settlement lag). vmalert rules and a Grafana agora-exchange dashboard track venue health. The health signal is I-X4 + the [AGORA-settle] log lines.
  • When something is stuckGET /admin/invariant first. funding_orders_in_transition should drain in ~30s. A non-zero I-X3 with zero funding-in-transition on a quiet frame is a real incident → global-halt, then reconcile escrow against the exref: ledger. A transient I-X3 flash on a busy venue is the cosmetic read-skew described above — confirm against the auditor's atomic delta and a re-read before treating it as insolvency.

On the Roadmap — and What Will Never Come

AGORA is now a genuine corporate-finance venue, but it isn't finished. What's designed and queued:

  • A WebSocket algo feed — the live tape today rides the Event Store WS; a dedicated low-latency market-data stream for programmatic traders is net-new infrastructure.
  • Circuit-breakers — automatic trading halts on extreme price moves, beyond today's per-order price band.
  • Share-classes and lock-ups — multiple classes per listing (each with its own I-X1 conservation term) and vesting restrictions on founder shares.
  • Trade-surveillance — wash-trade, spoof, and pump-and-dump detection, cloned from the existing forensic/collusion machinery into a findings inbox. This is the gate that would let the maker-rebate's registration requirement relax — surveillance polices the abuse that registration currently prevents by hand.

And one thing that is deliberately out of scope: short-selling. Selling shares you don't own breaks I-X1's strict conservation — the share ledger's whole guarantee is that positions sum to the issued float. A short market would need an entirely separate borrow-ledger and liquidation engine layered underneath, which is a different system, not a feature. The conservation invariant is the foundation; short-selling would dynamite it.

What's Next

  • 🔗 02 — The Token Economy — AVT, the supply invariant, and the four transfer paths the mover is built on
  • 🔗 06 — Governance & veTokens — the network-governance pattern AGORA's shareholder voting (and its cross-frame relay) mirrors
  • 🔗 07 — The Event Store & Supply Audit — where the exchange events land and how Δ=0 is verified
  • 🔗 18 — Sovereign Frames — the AVT ↔ JDAY ↔ BVT FX triangle, the currency border the Passport trades across, and the federated registry cards the stock card rides
  • 🔗 20 — Organizations — the entities whose shares list on AGORA, whose admins run the treasury and corporate actions
  • 🔗 12 — MCP Integration — the exchange MCP tools (placeExchangeOrder, buyExchangeIpo, …); the newer reads (cap-table, index, solvency card, governance, treasury) go through the catch-all adminRequest

Server components AGPL-v3 · client SDK Apache-2.0. If a doc and the running stack disagree, trust the stack.