PropAMM Forge Milestone M2 · local validator and devnet · test tokens

Proprietary AMM toolkit for Solana

Run your own proprietary AMM on Solana.

A private vault holding your own capital, priced by your own off-chain engine. Every desk used to rebuild the program, the pricing engine and the integration from scratch — this is that work, packaged.

The engine keeps the quote on the book — and takes it off when the feed goes quiet.

— FEED · SOL/USD stand-in, one event a second ▮ QUOTE · bid–ask on the vault (fixed_spread.py, half-spread 25 bps)
Recorded run: the feed moves seven times by 10 bps and each time the quote on the vault follows one slot later; then the feed goes silent and the quote is withdrawn 1.42 seconds later. 150.75150.50150.25150.00 0 s4 s8 s12 s16 s move −10 bps on chain · 1 slot feed silent · 1.42 s quote withdrawn
p95 1 slot from move to quote · budget 2 · 200 moves · 0 missed feed silent → quote off the book in 1.42 s · bound 2 s
Replay of a recorded run on a local validator with a stand-in price feed that moves on cue — not devnet, not live. The last 17 s of the run, every step from the recording. Recorded 2026-10-03; source: scripts/wsl-build.sh e2e-engine.

What you get today

On the main branch now. Filled tickets are built or measured; dashed ones are not here.

A vault, not a copy of the program

One program, many vaults. Your AMM is a vault derived from your address and the pair; you do not build or pay rent for bytecode. Capital is yours alone — deposits from anyone else are rejected by the program.

No curve, no oracle on chain

The vault stores a mid, a half-spread, an inventory skew and a maximum size; the swap computes the output from those. Every quote carries its slot, and a swap against a stale one is refused.

An engine that keeps the quote alive

It reads Pyth Hermes, prices with a model and posts when a side moves past the threshold or the heartbeat is due. When the feed goes silent it withdraws the quote instead of repeating the last price.

Your model, same engine

The pricing model is the one replaceable part: the built-in spread-and-skew, or your own process in any language over a line protocol. A Python port of the built-in model is the starting point.

Five commands to a quoting vault

From an empty directory, on a local validator. The sixth line is the engine, which takes over from there.

  1. 1
    forge init

    writes a project and its own README

  2. 2
    forge deploy

    creates your vault for the pair

  3. 3
    forge fund --side base

    moves base capital in

  4. 4
    forge fund --side quote

    moves quote capital in

  5. 5
    forge quote

    posts the first quote by hand

  6. then
    propamm-engine --env-file .env

    from here the engine keeps the quote alive

Swapping is not a forge command by design: the counterparty is a third party. Build the swap with the TypeScript SDK, or let an aggregator build it.

Mints whose transfers change the amount — transfer hook, transfer fee, permanent delegate and the like — are refused at deploy, with the extension named.

Measured, not estimated

Every figure is the output of a command in the repository. Where it was measured is part of the figure.

2.43 s 5 commands

Empty directory to a vault that has executed its first swap.

Budget: 15 min, 5 commands
Measured on: local validator
SC-001
22,950 CU

The swap instruction on the worst pair (Token-2022); 18,647 CU on plain SPL.

Budget: 60,000 CU
Measured on: CU benchmark
SC-002
0 of 1,000

Swaps executed against a stale quote; 200 of the 1,000 were deliberately stale.

Budget: 0
Measured on: program tests
SC-004
1 slot p95

From a price move past 5 bps to the new quote on chain. Both models, 200 moves, max 2, none missed.

Budget: 2 slots
Measured on: local validator, stand-in feed — not devnet
SC-003
100 / 100

Same engine binary, only MODEL_COMMAND changed: every quote of each model carries that model's fingerprint on chain.

Budget: proven by the run
Measured on: local validator
SC-011
1.42–1.86 s

Feed went silent → quote off the book. Three recorded runs.

Bound: 2 s of silence
Measured on: local validator
FR-014
0 over 695 partial

Swaps that pushed inventory past its hard bound. The 10,000-swap run with hostile sequences is ahead.

Budget: 0 of 10,000
Measured on: program tests
SC-010
SC-003 — slots from the price move to the quote on chain, p95 ≤ 2:
  built-in         n=100 p50=1 p95=1 max=2 missed=0
  fixed_spread.py  n=100 p50=1 p95=1 max=2 missed=0
SC-011 — one binary, the model swapped by MODEL_COMMAND only:
  built-in         100/100 quotes on chain are this model's
  fixed_spread.py  100/100 quotes on chain are this model's
FR-014 — the feed went quiet: the quote was off the book in 1.42 s (silence bound 2 s)

The run the replay above is taken from, 2026-10-03.

What it does not do — yet, or at all

Named plainly, because a demo without this list creates a false impression of what has been proven.

No measured run on the live feed

The engine has quoted live Pyth prices on devnet, in demo windows only: the free RPC tier does not hold it around the clock. The slot figures are from a local validator with a stand-in feed.

No aggregator adapter, no router

Next milestone. It will be tested against a local router twin, not Jupiter: ready to submit, not listed. Nothing here has been listed by a production router.

No console on real data

The console at /app/ is a screen prototype; every figure on it is drawn.

No risk loop

No emergency halt, no daily-loss limit, no automatic withdrawal on loss yet.

No mainnet, no real capital

Local validator and devnet, test tokens. Nothing here says how a vault behaves under real order flow or MEV.

No trading strategy

A template engine with a spread and an inventory skew. Alpha, calibration and any claim of profit are the desk's own work.

Questions a desk asks first

Do I deploy my own program?

No. One program, many vaults. The cost of that choice: a program upgrade applies to every vault, and the upgrade authority is not the vault owner.

Does the program read a price feed?

No. An off-chain signer posts the quote; the program only checks its age. That is why a swap fits a router's compute budget.

Which tokens work?

SPL and Token-2022 without extensions that change transferred amounts; those are refused at deploy.

Is it on Jupiter?

No. Integration is the next milestone and is tested against a local router twin, not Jupiter.

Can my quant team use Python?

Yes. Point MODEL_COMMAND at your process; the measured run swapped a Python model in with the same engine binary.