Skip to content

feat(mm-bot): LVR AMM simulator integration#30

Open
rndrntwrk wants to merge 29 commits intodevelopfrom
feature/pm-amm-integration-v1
Open

feat(mm-bot): LVR AMM simulator integration#30
rndrntwrk wants to merge 29 commits intodevelopfrom
feature/pm-amm-integration-v1

Conversation

@rndrntwrk
Copy link
Collaborator

@rndrntwrk rndrntwrk commented Mar 20, 2026

Summary

  • Full lifecycle LVR AMM integration into the market-maker-bot simulator, running in parallel with existing CLOB market-making
  • Ports Gaussian-CDF bonding curve math (Q64.64 fixed-point) from Rust to TypeScript for offline price computation
  • Adds AMM trade decision logic, Solana + EVM runtime types, position storage, and 6 adversarial AMM scenarios
  • Extends simulator with SIM_MODE=clob|amm|both and chain registry with marketType + mUsdTokenAddress
  • NEW: Local e2e sim harness deploys real contracts to anvil and runs CLOB+AMM market-making with on-chain transactions
  • NEW: Game API compatibility layer on sim dashboard so the real betting frontend can connect to live simulations

Changes

  • amm-math.ts — Gaussian CDF bonding curve, Q64.64 fixed-point, WAD pricing
  • index.ts — AMM market-making cycle (EVM + Solana), position tracking, inventory with WAD normalization
  • local-sim.ts — E2e harness: deploys Oracle + GoldClob + LvrMarket to anvil, runs full CLOB+AMM simulation
  • chain-registry — Propagate marketType through lifecycle record normalizer
  • simulation-dashboard/server.ts — Game API endpoints (SSE, polling, prediction markets, duel context, config) with CORS
  • scripts/sim-frontend.sh — Startup script: sim dashboard → fetch config → write .env.local → start Vite frontend

AMM Fixes (local-sim debugging)

  • Use getMarketDetails() instead of non-existent individual reserve getters
  • Fix MarketState enum: RESOLVED=4 not 3
  • Normalize WAD (1e18) token balances in exposure/inventory
  • Fix mUSD parseUnits from 6 to 18 decimals
  • Add lastStreamAtMs/lastOracleAtMs to prevent stale-stream circuit breaker trips
  • Read actual on-chain token balances after AMM trades

Game API Endpoints Added

Endpoint Purpose
GET /api/config Contract addresses, RPC, chain info
GET /api/streaming/state/events SSE with StreamingStateUpdate
GET /api/streaming/state Poll fallback
GET /api/streaming/duel-context Agent HP, phase, timing
GET /api/arena/prediction-markets/active Market lifecycle

Test plan

  • 80/80 market-maker-bot tests pass
  • 15/15 chain-registry tests pass
  • Typecheck clean
  • All Game API endpoints return correct shapes verified against frontend consumer types
  • Frontend blank screen on connect — React <App> crash under investigation (pre-existing config/wagmi issue unrelated to new endpoints)

29 files from lvr_amm EVM contracts, Solana program, and test.
PM-core contracts (DuelOutcomeOracle, GoldClob, fight_oracle, gold_clob_market) unchanged.
C-1: declare isDynamic as immutable state variable in LvrMarket
C-2: add AccessControl + onlyRole(DEFAULT_ADMIN_ROLE) to setFeeConfig, 10% fee cap
H-1: add minAmountOut slippage protection to all buy/sell functions
H-2: add z-score bounds validation in SwapMath entry point
H-3: add ReentrancyGuard (nonReentrant) to all Router buy/sell functions
G-7: fix getPriceYes to use time-decayed liquidity matching _swap execution

Also: market allowlist on Router callbacks, 6 exploit regression tests
Rewrites entire math.rs to use Q64.64 fixed-point (i128) arithmetic.
Removes libm dependency entirely.

- Polynomial erf approximation (Abramowitz & Stegun 7.1.28)
- Taylor series exp(-x) with repeated squaring
- Integer sqrt via Newton's method
- Gaussian CDF/PDF from erf, not f64 stdlib
- All public API unchanged (u64 scaled by 1e6)
- 6 unit tests including symmetry and determinism verification

Solana validators will now produce identical results regardless of
hardware floating-point implementation.
…pplied fees (G-2, G-4, G-6)

- Add AmmConfig PDA (singleton): authority, treasury, market_maker, fee_bps, config_frozen, paused
- Add initialize_config, freeze_config, set_paused instructions
- create_bet now reads fee_bps and treasury from AmmConfig, not caller inputs
- Add pause guard on create_bet
- Add error variants: InvalidAddress, FeeTooHigh, MarketPaused, ConfigFrozen
- Removes per-market fee/treasury injection attack vector
Cherry-pick deploy-amm.ts and amm-test-helpers.ts from
feat/amm-swap-fees, updated for hardened interfaces:
- Router constructor now takes 4 params (mUSD, treasury, feeBps, admin)
- Solana create_bet reads fee/treasury from AmmConfig PDA
- Test helpers gain ensureAmmConfig() for protocol config setup
Thread AmmConfig PDA into Buy and Sell account contexts.
Both instructions now check !amm_config.paused before executing,
matching create_bet's existing pause guard and EVM Router parity.
EVM: settleFromOracle() reads DuelOutcomeOracle.getDuel() to resolve
market from oracle state. Handles Resolved and Cancelled statuses.

Solana: settle_bet accepts optional duel_state account from
fight_oracle. Winner deserialized from oracle at known byte offsets
rather than trusting caller side_won argument.
get_price now calls calc_liquidity for dynamic markets, matching
the execution path in buy/sell. Prevents price read/execution
divergence that could be exploited for arbitrage.
… export

- Chain registry: add goldAmmMarketProgramId (Solana), goldAmmRouterAddress (EVM), amm feature flag
- Solana app: wire AMM program ID into config.ts and programIds.ts with VITE env override
- BSC app: wire goldAmmRouterAddress per chain into config.ts
- Solana keeper: add GOLD_AMM_MARKET_PROGRAM_ID resolver
- EVM: export hardened Router ABI as goldAmmRouterAbi.ts
Bump anchor-lang/anchor-spl 0.30.1→0.32.1 to match workspace, add
lvr_amm to all 5 build config files (Cargo workspace, Anchor.toml,
build-workspace.sh, sync-anchor-artifacts.mjs), and fix operator
precedence bug in math.rs to_q function.
Full lifecycle AMM integration across Solana (lvr_amm) and EVM
(Router/LvrMarket) chains, running in parallel with existing CLOB
market-making.

- Port Gaussian-CDF bonding curve math (Q64.64) to TypeScript bigint
- Add AMM trade decision logic to mm-core (buildAmmTradeDecision)
- Wire AMM runtimes (Solana + EVM) into CrossChainMarketMaker
- Add AMM position storage (in-memory + postgres)
- Extend simulator with SIM_MODE=clob|amm|both
- Add 6 AMM adversarial scenarios (sandwich, reserve manipulation,
  stale price arb, slippage griefing, token drain, expiry race)
- Extend chain registry with marketType and mUsdTokenAddress
- Add AMM PDA helpers for lvr_amm program accounts
- Generate and distribute lvr_amm IDL
Without this, AMM markets were silently dropped when the frontend
filtered by marketType — the field was present on the raw candidate
but not forwarded through normalizePredictionMarketLifecycleRecord().
- Use getMarketDetails() instead of individual reserve getters that
  don't exist on LvrMarket
- Fix MarketState enum: RESOLVED is 4 not 3 (OPEN=0,CLOSED=1,
  PENDING=2,DISPUTED=3,RESOLVED=4)
- Normalize WAD (1e18) token balances in exposure and inventory
- Fix mUSD parseUnits from 6 to 18 decimals
- Add lastStreamAtMs/lastOracleAtMs to AMM snapshot to prevent
  stale-stream circuit breaker trips
- Read actual on-chain token balances after AMM trades
Standalone simulation that deploys Oracle, GoldClob, and LvrMarket
contracts to a local anvil, opens a duel, and runs the market maker
against both CLOB and AMM markets with real on-chain transactions.

Includes nonce tracker with invalidation for mixed forge/ethers
deploys and try/catch resilience for cross-market nonce conflicts.
…ntend

Add SSE and HTTP endpoints that translate simulation state into the
format the Vite+React betting frontend expects, so starting the sim
dashboard drives the real UI (order book, fight overlay, trades).

Endpoints added:
- GET /api/config — contract addresses, RPC, chain info
- GET /api/streaming/state/events — SSE with StreamingStateUpdate
- GET /api/streaming/state — poll fallback
- GET /api/streaming/duel-context — agent HP, phase, timing
- GET /api/arena/prediction-markets/active — market lifecycle

Also adds CORS headers and OPTIONS preflight handling on all /api/*
routes for cross-origin frontend access.
Starts the simulation dashboard, waits for readiness, fetches deployed
contract addresses from /api/config, writes .env.local for the EVM
betting frontend, then starts the Vite dev server.

Usage: ./scripts/sim-frontend.sh
JS BigInt has no overflow, so (a * b) >> 64n is exact. The old
(a >> 32n) * (b >> 32n) approximation lost 32 bits per operand,
producing materially different prices from the on-chain Rust math.

Tightens test tolerance from ±1% to ±0.1%.
- EVM AMM: compute minAmountOut via estimateSlippage() with configurable
  maxSlippageBps (default 2%). All buyYes/buyNo/sellYes/sellNo now pass
  slippage-protected floor instead of 0.
- EVM AMM: all trades + approvals routed through sendEvmTransaction()
  nonce tracker, preventing conflicts with concurrent CLOB transactions.
- Solana AMM: read actual token balances via getTokenAccountBalance()
  after each trade, enabling maxPositionSize guard. Previously
  yesBalance/noBalance stayed at 0 forever.
- Solana AMM snapshot: set lastStreamAtMs/lastOracleAtMs to Date.now()
  so circuit breaker doesn't treat all Solana AMM as permanently stale.
- AmmMarketMakerConfig: add maxSlippageBps field (default 200 = 2%).
Add explicit CLOB_STATUS and AMM_STATUS constants with comments
documenting the enum value difference (CLOB RESOLVED=3, AMM RESOLVED=4).
Current sim uses GoldClob (CLOB) so runtime constants are unchanged,
but the mapping is now visible for when AMM simulation is added.
@rndrntwrk rndrntwrk marked this pull request as ready for review March 21, 2026 09:46
@rndrntwrk rndrntwrk requested a review from lalalune March 21, 2026 09:47
C-8: Add redactUrl() utility to Solana keeper common.ts that strips
api-key query parameters before logging. Prevents Helius API key
exposure in error traces and diagnostics.

M-12: BSC config now reads AVAX addresses from chain registry defaults
(goldClobAddress, goldAmmRouterAddress, goldTokenAddress) instead of
hardcoding empty strings.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant