Skip to content

Yolomarkets/simulations

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

8 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Yolo Markets Simulation Suite

1) Purpose

This repository is a standalone simulation and stress-testing suite for Yolo Markets.

It focuses on two technical areas:

  1. Pricing/accounting/solvency under an LMSR-style market maker and proportional settlement.
  2. Termination timing robustness under adversarial behavior (ordering games, trade splitting, and last-mover strategies).

The suite is organized so results are reproducible from seeded runs and directly inspectable in CSV + chart outputs.

2) Technical Review Mapping

The simulation suites map to common review questions as follows:

  1. Pricing mechanics, slippage, and execution behavior:

    • scripts/mev_sandwich.py
    • scripts/mev_competition.py
    • scripts/trade_splitting.py
  2. Solvency, worst-case loss, and bond sufficiency:

    • scripts/solvency_checks.py
    • sim/runner.py
    • sim/lmsr.py
  3. Termination randomness and manipulation resistance:

    • sim/termination.py
    • scripts/manipulation_curves.py
    • scripts/trade_splitting.py
    • scripts/last_mover.py
    • scripts/last_mover_normal_only.py
  4. Sensitivity and manipulation cost curves:

    • scripts/manipulation_curves.py

3) Repository Structure

simulations/
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ README.md
β”œβ”€β”€ sim/
β”‚   β”œβ”€β”€ lmsr.py                 # core LMSR cost/price/trade primitives
β”‚   β”œβ”€β”€ termination.py          # stochastic termination clock
β”‚   β”œβ”€β”€ fees.py                 # protocol fee model (base + convex surcharge, capped)
β”‚   β”œβ”€β”€ agents.py               # honest + attacker trade generators
β”‚   β”œβ”€β”€ runner.py               # end-to-end market lifecycle simulator
β”‚   └── experiments.py          # config builders for generic experiment sweeps
β”œβ”€β”€ scripts/
β”‚   β”œβ”€β”€ mev_sandwich.py         # ordering + slippage sandwich scenarios
β”‚   β”œβ”€β”€ mev_competition.py      # two-attacker competition and profit compression
β”‚   β”œβ”€β”€ trade_splitting.py      # split invariance + split slippage scenarios
β”‚   β”œβ”€β”€ manipulation_curves.py  # manipulation cost and end-prob sensitivity curves
β”‚   β”œβ”€β”€ solvency_checks.py      # bound checks and sponsor-bond residuals
β”‚   β”œβ”€β”€ last_mover.py           # broad last-mover scenario sweeps
β”‚   β”œβ”€β”€ last_mover_normal_only.py # one-shot last-mover profile used for reviewer-facing outputs
β”‚   └── run_mechanism_analysis.py # convenience wrapper for manipulation+solvency suites
└── out/
    β”œβ”€β”€ results_*.csv
    β”œβ”€β”€ summary_*.csv
    └── plots/*.png

4) Core Model

4.1 LMSR Pricing and Trade Accounting (sim/lmsr.py)

Binary LMSR is used:

  • Cost function:
    • C(qY, qN) = b * ln(exp(qY/b) + exp(qN/b))
  • Marginal YES price:
    • pY = exp(qY/b) / (exp(qY/b) + exp(qN/b))
  • Trade cost:
    • Ξ”C = C(after) - C(before)

b is calibrated from configured max-loss:

  • b = max_loss / ln(2)
  • LMSR worst-case bound:
    • worst_case_loss = b * ln(2) = max_loss

Implementation uses a numerically stable log-sum-exp path to avoid overflow.

4.2 Termination Clock (sim/termination.py)

Termination threshold:

  • T ~ Exponential(alpha) via inverse-CDF sampling.

Running clock:

  • S += max(cost_paid, 0) / b after each trade.
  • Market terminates when S >= T.

Important properties:

  1. Termination depends on economic spend, not raw trade count.
  2. Splitting one spend amount into many small trades does not change the expected S increment materially.
  3. The stochastic source in this simulation is seeded PRNG for reproducibility; the same statistical model is compatible with onchain VRF-driven termination in production.

4.3 Settlement and Liability (sim/termination.py, sim/runner.py)

At termination, settlement uses final price p*:

  • YES payout per share: p*
  • NO payout per share: 1 - p*
  • Total payout:
    • p* * QY + (1 - p*) * QN

This gives deterministic proportional settlement from terminal market state.

4.4 Fee Model (sim/fees.py)

Current protocol fee model:

  1. Base fee: 0.10% of positive-spend trade cost.
  2. Convex surcharge (enabled in all active suites):
    • turns on after progress > 0.85,
    • scales with how much the trade pushes price farther from 0.5,
    • scales with per-trade termination intensity proxy 1 - exp(-alpha * dS).
  3. Hard cap:
    • total fee rate capped at 7.00% of trade spend.

Observed effective fee rates in current outputs:

  • min: 0.10%
  • median: 0.10%
  • p95: 7.00%
  • max: 7.00%

4.5 Agent Model (sim/agents.py)

Honest flow:

  1. Random side (YES/NO).
  2. Random direction (buy/sell).
  3. Lognormal size, depth-scaled to ~2% of b.

Attacker flows:

  1. Last-mover directional pushes.
  2. Sandwich-style front-run/back-run.
  3. Multi-attacker competition.

4.6 Runner and End-to-End Accounting (sim/runner.py)

run_single tracks:

  1. Collateral in/out from trades.
  2. Protocol fee accumulation.
  3. Termination state and final price.
  4. Settlement payout and net without bond.
  5. Bound checks and attacker PnL fields.

This is the accounting backbone used by solvency and stress scripts.

5) Environment Setup

cd simulations
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
export MPLCONFIGDIR=.mpl_cache

MPLCONFIGDIR avoids matplotlib cache permission warnings and improves run stability in restricted environments.

6) How to Run the Suites

6.1 Reproduce the current reviewer-facing output set

cd simulations
source .venv/bin/activate
export MPLCONFIGDIR=.mpl_cache

python scripts/mev_sandwich.py --quick --seeds 300 --no-progress --out-dir out
python scripts/mev_competition.py --quick --seeds 300 --include-no-termination --no-progress --out-dir out
python scripts/trade_splitting.py --quick --seeds 300 --no-progress --out-dir out
python scripts/run_mechanism_analysis.py --out-dir out/mechanism_analysis --solvency-seeds 300
python scripts/last_mover_normal_only.py --seeds 200 --no-progress --out-dir out/last_mover_normal_only

6.2 Optional quick smoke checks

python scripts/mev_sandwich.py --quick --seeds 10 --out-dir out/smoke
python scripts/mev_competition.py --quick --seeds 10 --include-no-termination --out-dir out/smoke
python scripts/trade_splitting.py --quick --seeds 10 --out-dir out/smoke
python scripts/run_mechanism_analysis.py --quick --solvency-seeds 20 --out-dir out/smoke_mech
python scripts/last_mover_normal_only.py --seeds 20 --out-dir out/smoke_last_mover

7) Script-by-Script Details

7.1 scripts/mev_sandwich.py

What it tests:

  1. Front-run + victim execution + unwind path.
  2. Victim slippage protection behavior.
  3. Impact of probabilistic termination on attacker ability to unwind.

Key outputs:

  1. out/results_mev_sandwich.csv
  2. out/summary_mev_sandwich.csv
  3. out/plots/mev_sandwich_rates_vs_slippage.png

Quick grid (used in current output):

  1. max_loss: [500, 2000]
  2. alpha: [0.01, 0.05]
  3. mode: no_termination, termination
  4. start_progress (termination): [0.95]
  5. victim_kind: [YES, NO]
  6. victim_size_pct_b: [0.01, 0.02, 0.05]
  7. slippage_tol: [0, 0.001, 0.0025, 0.005, 0.01]
  8. attacker_ratio: [0.5, 1.0, 2.0]
  9. seeds: 300

Total runs: 216,000.

7.2 scripts/mev_competition.py

What it tests:

  1. Single attacker vs coordinated attacker vs two competing attackers.
  2. Profit compression from competition in the same opportunity window.

Key outputs:

  1. out/results_mev_competition.csv
  2. out/summary_mev_competition.csv
  3. out/plots/mev_competition_profit_compression.png

Quick grid (used in current output):

  1. max_loss: [500, 2000]
  2. alpha: [0.01, 0.05]
  3. mode: termination + no_termination (via --include-no-termination)
  4. start_progress (termination): [0.95]
  5. victim_kind: [YES, NO]
  6. victim_size_pct_b: [0.01, 0.02, 0.05]
  7. slippage_tol: [0.0025, 0.005, 0.01]
  8. attacker_ratio_each: [0.5, 1.0]
  9. seeds: 300

Total runs: 86,400.

7.3 scripts/trade_splitting.py

What it tests:

  1. Split invariance for termination and post-trade state.
  2. Split behavior in slippage/sandwich scenarios.

Key outputs:

  1. out/results_trade_split_invariance.csv
  2. out/summary_trade_split_invariance.csv
  3. out/deltas_trade_split_invariance.csv
  4. out/plots/trade_split_invariance_deltas.png
  5. out/results_trade_split_slippage.csv
  6. out/summary_trade_split_slippage.csv

Quick grid (used in current output):

Invariance leg:

  1. max_loss: [500, 2000]
  2. alpha: [0.005, 0.05]
  3. start_progress: [0.0, 0.95]
  4. trade_kind: [YES, NO]
  5. total_shares_pct_b: [0.01, 0.02]
  6. split_n: [1, 20]
  7. seeds: 300

Slippage leg:

  1. max_loss: [500, 2000]
  2. alpha: [0.01, 0.05]
  3. start_progress: [0.95]
  4. victim_kind: [YES, NO]
  5. victim_size_pct_b: [0.01, 0.02]
  6. slippage_tol: [0.0025, 0.005, 0.01]
  7. attacker_ratio: [0.5, 1.0]
  8. split_n: [1, 20]
  9. seeds: 300

Run counts:

  1. Invariance: 19,200
  2. Slippage: 57,600

7.4 scripts/manipulation_curves.py

What it tests:

  1. Cost to push price by target dp.
  2. Sensitivity to market depth (max_loss -> b) and alpha.
  3. Per-trade termination probability contribution from a manipulation trade.

Key outputs:

  1. out/mechanism_analysis/results_manipulation_cost.csv
  2. out/mechanism_analysis/summary_manipulation_cost.csv
  3. out/mechanism_analysis/plots/manipulation_cost_curve_by_depth.png
  4. out/mechanism_analysis/plots/manipulation_endprob_curve_by_alpha.png

Full grid (used in current output):

  1. max_loss: [250, 500, 1000, 2000, 5000]
  2. alpha: [0.005, 0.01, 0.05]
  3. p0: [0.4, 0.5, 0.6]
  4. dp: [0.01, 0.02, 0.05, 0.10, 0.15, 0.20]
  5. direction: [up, down]
  6. split_n: [1, 5, 20, 100]
  7. progress: [0.85, 0.95, 0.99]

Total runs: 6,480.

7.5 scripts/solvency_checks.py

What it tests:

  1. Whether realized deficits stay within LMSR bound.
  2. Whether sponsor bond equal to max_loss clears all payouts.
  3. Baseline vs attacker-stress scenario margins.

Key outputs:

  1. out/mechanism_analysis/results_solvency_checks.csv
  2. out/mechanism_analysis/summary_solvency_checks.csv
  3. out/mechanism_analysis/plots/solvency_deficit_over_bound_cdf.png
  4. out/mechanism_analysis/plots/solvency_bond_residual_by_scenario.png

Full grid (used in current output):

  1. max_loss: [250, 500, 1000, 2000, 5000]
  2. alpha: [0.005, 0.01, 0.05]
  3. scenario: [baseline, attacker_stress]
  4. seeds: 300

Total runs: 9,000.

7.6 scripts/last_mover.py and scripts/last_mover_normal_only.py

last_mover.py:

  1. Broad grid, supports split attacks and configurable reaction/fee settings.

last_mover_normal_only.py:

  1. Fixed one-shot attack (split_n = 1) profile for a cleaner baseline.
  2. Uses the same convex fee policy and stricter reactive flow.

Current output generated with:

  1. max_loss: [500, 2000]
  2. alpha: [0.01, 0.05]
  3. start_progress: [0.95, 0.99]
  4. hold_kind: [YES, NO]
  5. hold_shares_pct_b: 0.05
  6. attack_budget_pct_b: [0.005, 0.01, 0.02, 0.05]
  7. split_n: 1
  8. reaction_steps: 25
  9. reaction_strength: 1.3
  10. reaction_trigger_abs_dp: 0.001
  11. seeds: 200

Total runs: 12,800.

Outputs:

  1. out/last_mover_normal_only/results_last_mover_normal_only.csv
  2. out/last_mover_normal_only/summary_last_mover_normal_only.csv
  3. out/last_mover_normal_only/plots/last_mover_normal_only_budget.png

8) Current Output Snapshot (from out/)

8.1 Run counts

  1. mev_sandwich: 216,000
  2. mev_competition: 86,400
  3. trade_split_invariance: 19,200
  4. trade_split_slippage: 57,600
  5. manipulation_cost: 6,480
  6. solvency_checks: 9,000
  7. last_mover_normal_only: 12,800

8.2 Chart-by-chart interpretation

  1. out/plots/mev_sandwich_rates_vs_slippage.png

    • X-axis: victim slippage tolerance.
    • Curves: victim revert rate and attacker profitable rate.
    • Current behavior:
      • tighter slippage -> high victim reverts;
      • looser slippage -> more attacker opportunities;
      • mean attacker profit remains negative across buckets (~-2.15 to -2.11).
  2. out/plots/mev_competition_profit_compression.png

    • X-axis: slippage tolerance.
    • Curves: single attacker, coordinated size, two competing attackers.
    • Current behavior:
      • all mean profit curves are below zero;
      • competition remains net-unprofitable.
  3. out/plots/trade_split_invariance_deltas.png

    • X-axis: split factor split_n.
    • Y-axis: delta vs split_n=1.
    • Current behavior:
      • delta_terminated_rate = 0.0;
      • delta_p and delta_S are near zero;
      • supports trade-splitting resistance for termination mechanics.
  4. out/mechanism_analysis/plots/manipulation_cost_curve_by_depth.png

    • X-axis: target move dp.
    • Y-axis: total manipulation cost.
    • Current behavior:
      • cost grows nonlinearly with dp;
      • higher depth (max_loss) raises manipulation cost.
  5. out/mechanism_analysis/plots/manipulation_endprob_curve_by_alpha.png

    • X-axis: dp.
    • Y-axis: per-trade termination probability increment.
    • Current behavior:
      • monotonic in dp;
      • higher alpha gives higher per-trade end probability.
  6. out/mechanism_analysis/plots/solvency_deficit_over_bound_cdf.png

    • X-axis: deficit / LMSR bound.
    • Current behavior:
      • bound check passes on terminated runs:
        • bound_ok_rate = 1.0
        • solvency_with_bond_rate = 1.0
        • deficit_over_bound_max = 0.94398
  7. out/mechanism_analysis/plots/solvency_bond_residual_by_scenario.png

    • Bars show p05/mean/p95 bond residual.
    • Current behavior:
      • residual remains positive in both baseline and stress;
      • indicates bond coverage margin after payout.
  8. out/last_mover_normal_only/plots/last_mover_normal_only_budget.png

    • X-axis: attack budget as % of b.
    • Curves: mean incremental attacker profit and profitable rate.
    • Current behavior:
      • mean incremental attacker profit is negative at every tested budget:
        • 0.5% b: -0.085
        • 1.0% b: -0.335
        • 2.0% b: -1.224
        • 5.0% b: -2.412

9) Determinism and Seeds

Every script uses explicit integer seeds and deterministic scenario generation.

Implications:

  1. Re-running with identical commands reproduces row-level CSV outputs.
  2. Changing seed counts primarily tightens confidence intervals.
  3. Grid expansion changes runtime linearly with scenario count.

10) Notes on Scope

  1. This repository is simulation-only and chain-agnostic.
  2. It models mechanism-level behavior (pricing, termination, settlement, solvency, adversarial strategies).
  3. It does not model production infra details (RPC latency, mempool specifics, or execution relayers).
  4. Termination randomness in simulation is seeded PRNG; production deployment can source randomness from verifiable onchain randomness while keeping the same hazard-style termination model.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages