Target architecture
This page is a summary of the target design in the root file ARCHITECTURE.md (draft, 13 October 2026). It then lists where the current build differs.
Target design, not current behavior
Pyth verification, the oracle keeper with Hermes, WebSocket transport, a database, and the automatic UI fallback paths in this design are not implemented. For the implemented system, see the System overview.
Overview of the target
+-------------------------------+
| Web UI (Next.js, wagmi) |
| main wallet + session key |
+--+----------+-----------+-----+
main-wallet txs | | signed | read: book, trades,
(deposit, authorize, | | orders | positions, history
withdraw) | v v
| +----------+ +---------------+
| | Relayer | | Indexer + API |
| | pays gas | | REST + WS |
| +----+-----+ +-------^-------+
v v | events
+-------------------------------------------------------------+
| MONAD |
| SessionRegistry Market (ETH) Market (MON) |
| collateral, book, positions, |
| funding, margin, liquidation |
| | verify price |
| v |
| Pyth contract |
+--------------^------------------------------^---------------+
| submitObservation | liquidate
+-------+--------+ +-------+------------+
| Oracle keeper |<- Hermes | Liquidation keeper |
+----------------+ (Pyth) +--------------------+The contracts enforce all rules. Each backend service only sends transactions that any other person can also send.
Design rules that address open problems
These rules address findings of the economic model review in simulation/MODEL_REVIEW.md.
1. Only one price is valid for each boundary
Pyth has a function, parsePriceFeedUpdatesUnique, which accepts only the first update at or after a given time. The target contract uses the boundary time as that time. No caller can select a better price.
State in this build: not implemented. The test oracle accepts a price that one operator signs.
2. No trade before the observation
After each boundary, no order fills until the observation for that boundary is in the contract. Thus no person can see a move, enter, and still get the payment for it. Cancellation stays available.
State in this build: implemented. See the observation gate in Order book and mark.
3. Matching continues when the mark is frozen
Only withdrawals and liquidations at the stale mark are blocked. During a freeze, a fill that adds exposure must pass the margin check at the last valid mark and at its own price.
State in this build: implemented.
This rule is a partial repair. In the Python simulation over ten seeds, it decreased the mean number of frozen steps in the ETH maker-withdrawal case from 105 to 37 of 360. It did not solve the jump case.
Problems that stay open
- The mark after a jump. When makers disagree, each side of the book can have one owner and a spread of more than 20%. The mark rule then has no valid result. A fallback rule is necessary, and it must resist manipulation with small trades.
- A closed book position keeps its funding claim until the next boundary.
- Liquidation can take longer than the maintenance buffer.
- A shorter observation interval makes these problems smaller. It does not remove them.
Backend services of the target
| Service | Function | If it stops | State in this build |
|---|---|---|---|
| Oracle keeper | Gets the first price update from Pyth Hermes at each boundary and calls submitObservation | Trading pauses until a person submits | A test operator loop signs prices and attaches them to its quotes |
| Relayer | Receives a signed order, simulates it, sends it, and pays the gas | The UI sends orders from the main wallet | Implemented. The automatic UI fallback is not. |
| Liquidation keeper | Monitors accounts and calls liquidate | Any person can call liquidate | A one-action keeper command. No monitor loop. |
| Indexer and API | Reads contract events into a database | The UI reads live state from the contract | A JSON event file. REST and SSE. |
Monad charges for the gas limit, not for the gas used. Thus each sender must set a tight gas limit.
Differences in the contracts
| Topic | Target design | This build |
|---|---|---|
| Order book | Price ticks with a FIFO queue for each tick and a bitmap to find the best tick | Sorted lists of real orders with a price bitmap for inserts, plus parametric maker ladders |
| Oracle | The real Pyth contract | TestOracle with a signed test price |
| Bad debt | A rule, for example a fee-funded insurance balance for each market | No rule. A deficit stays visible. |
| Observation interval | A parameter for each market, with 60 seconds as the start value | A parameter for each market. The scripts use 60, 10, and 300 seconds. |
Repository layout
The target layout has separate service packages. The build has one services package.
| Target | This build |
|---|---|
contracts/ | contracts/ |
services/keeper/, services/relayer/, services/indexer/ | services/src/ in one package |
web/ | web/ |
packages/shared/ | packages/shared/ |
simulation/ | simulation/ |
Items to verify
- Pyth on Monad. The Pyth deployment on Monad must have
parsePriceFeedUpdatesUniqueand a MON/USD feed. This is not confirmed. Rule 1 depends on it. - The observation interval. Select a value for each market only after the sampling research.
- Bad debt. The simulation only records it. The product needs a rule.
- Contract size and gas. Measure the gas of a match with the maximum number of fills.
Decisions of the target design
| Decision | Selected | Not selected | Reason |
|---|---|---|---|
| Delegated signing | Signed orders with a session key | EIP-7702 or smart accounts | Simpler. No dependency on wallet support. |
| Collateral | Each market holds its own collateral | A shared vault | Isolated margin and no shared state |
| Live UI data | Indexer for history, contract for live state as a fallback | Indexer only | The requirements include direct contract access |
| Languages | Solidity with Foundry. TypeScript for services and UI. | One language for all off-chain code |