Simulation environment for Solana's Prop AMMs (SolFi, HumidiFi, Tessera, GoonFi, BisonFi, ..)
pmm-sim
Simulation & Benchmark environment for Solana's Proprietary AMMs. The setup relies on Litesvm for local, consistent and expedited execution.
Supported Prop AMMs:
- [x] HumidiFi (swap v1/v2/v3)
- [x] SolFiV2
- [x] ObricV2
- [x] ZeroFi
- [x] TesseraV
- [x] GoonFi
- [x] BisonFi
The swaps and benchmarks can be done with the local static accounts/programs stored at ./cfg/ or with the current live ones by fetching them on-the-go. By default all swaps & benchmark simulations are done with real-time accounts/programs. The markets for each Prop AMM are specified in ./cfg/setup.toml.
Figure 1: Exchange rates for WSOL -> USDC at discrete slot 401101387, with spoofed CPI call as Jupiter.
Possible modes of execution include:
- single - Run a single swap route across one or more Prop AMMs with specified weights. The route can go through an arbitrary combination of Prop AMMs.
- multi - Execute swaps across nested Prop AMM routes. Each inner list represents a single route, each route possibly going through multiple Prop AMMs.
- direct - Execute a direct, non-cpi swap with some of the Prop AMMs.
- benchmark - Benchmark swaps for any of the implemented Prop AMMs by specifying, optionally, spoofing, the src/dst tokens and range size. Benchmark data can be visualised with plot.py.
- fetch-accounts - Fetch accounts for specified PMMs via RPC and save them locally (presumably for later usage).
- fetch-programs - Fetch programs for specified PMMs via RPC and save them locally (presumably for later usage).
| Prop AMM | Exchange Rate | Compute Units | | ---------------- | --------------------------------------- | ------------------------------------- | | HumidiFi |
|
| | HumidiFi Swap V2 |
|
| | HumidiFi Swap V3 |
|
| | SolFi V2 |
|
| | BisonFi |
|
| | Tessera |
|
| | Obric V2 |
|
| | GoonFi |
|
|
To explicitly specify the market the operation should execute against, for a particular prop AMM, suffix the Prop AMM's name with a substring of the address of the market. If no market is specified explicitly, we'll default to the first one defined in ./cfg/setup.toml.
Examples
Build the project
cargo build --release
Single-route swaps
Swap 15K USDC for WSOL using HumidiFi's swap-v1.
./target/release/pmm-sim single --amount-in=15000 --pmms=humidifi --weights=100 \
--src-token=USDC --dst-token=WSOL
Swap 15,345 USDT for WSOL using GoonFi, spoofed as Jupiter.
./target/release/pmm-sim single --amount-in=15345 --pmms=goonfi --weights=100 --src-token=usdc --dst-token=wsol --jit-accounts=false --spoof=jupiter
Swap 69K USDC for WSOL using HumidiFi (swap-v2 instruction on the Fk market) and BisonFi, in one route, split 25%,75% accordingly.
./target/release/pmm-sim single --amount-in=69000 --pmms=humidifi-swap-v2_Fk,bisonfi --weights=25,75 \
--src-token=USDC --dst-token=WSOL
Swap 375 WSOL for USDC using Tessera and SolFiV2's 65Z market, in one route, split evenly - 187,5 WSOL per Prop AMM, spoofed as DFlow.
./target/release/pmm-sim single --spoof=dflow --amount-in=375 --pmms=tessera,solfi-v2_65Z \
--weights=50,50 --src-token=WSOL --dst-token=USDC
Swap 100 WSOL for USDC using SolFiV2, HumidiFi, and Tessera, in one route, split 33,33,34 WSOL per Prop AMM.
./target/release/pmm-sim single --amount-in=100 --pmms=solfi-v2,humidifi,tessera \
--weights=33,33,34 \
--src-token=WSOL --dst-token=USDC \
--jit-accounts=false --jit-programs=false
Swaps 10,000 USDC for USDT using ObricV2.
./target/release/pmm-sim single --amount-in=10000 --pmms=obric-v2 --weights=100 \
--src-token=USDC --dst-token=USDT
Multi-route swaps
Swap 103 WSOL for USDC in a multi-route swap, 100 WSOL via HumidiFi and SolFiV2 (split 92%/8%) in one route, and 3 WSOL via Tessera in another route.
./target/release/pmm-sim multi --amount-in=100,3 --pmms="[[humidifi,solfi-v2],[tessera]]" \
--weights="[[92,8],[100]]"
Execute two routes, the first swapping 150,000 USDC for WSOL using HumidiFi and SolFiV2 (split 25%/75%), the second swapping 1000 USDC for WSOL using BisonFi.
RUST_LOG=debug ./target/release/pmm-sim multi --amount-in=150000,1000 --pmms="[[humidifi,solfi-v2],[bisonfi]]" --weights="[[25,75],[100]]" --src-token=USDC --dst-token=WSOL
Direct calls
Execute a direct offchain call towards HumidiFi's swap-v3 instruction, swapping 350 WSOL for USDC.
RUST_LOG=debug ./target/release/pmm-sim direct --pmm=humidifi-swap-v3 --amount-in=350 --src-token=WSOL --dst-token=USDC
Execute a direct offchain call towards BisonFi's FC9 market, swapping 35K USDT for WSOL.
./target/release/pmm-sim direct --pmm=bisonfi_FC9 --amount-in=35000 --src-token=USDT --dst-token=WSOL
Benchmark swaps
Benchmark swaps on HumidiFi,Tessera,SolFiV2 and GoonFi, from 1 to 4000 WSOL to USDC, in increments of 1 WSOL, using the accounts & programs from ./cfg. The results are saved at ./datasets.
./target/release/pmm-sim benchmark --pmms=humidifi,tessera,solfi-v2,goonfi \
--range=1.0,4000.0,1.0 --src-token=wsol --dst-token=usdc \
--jit-accounts=false --jit-programs=false
Benchmark swaps on Tessera and SolFiV2, from 1 to 250 WSOL, in increments of 0.01 WSOL. The results are saved at ./datasets.
./target/release/pmm-sim benchmark --pmms=tessera,solfi-v2 \
--range=1.0,250.0,0.01 --src-token=wsol --dst-token=usdc
Benchmark swaps (USDC->WSOL) on HumidiFi and SolFiV2, from 10K to 100K USDC, in increments of 100 USDC. The results are saved at ./datasets.
./target/release/pmm-sim benchmark --pmms=humidifi,solfi-v2 \
--range=10000,100000,100 --src-token=usdc --dst-token=wsol
Generated benchmark data can be plotted through ./scripts/plot.py, like so:
Plot the datasets for slot 389141713.
./scripts/plot.py ./datasets/389141713*
Fetch current accounts
Locally sync the current (live) accounts for BisonFi and HumidiFi's swap-v3.
./target/release/pmm-sim fetch-accounts --pmms=bisonfi,humidifi-swap-v3
Locally sync the current (live) accounts for Tessera and SolFiV2.
./target/release/pmm-sim fetch-accounts --pmms=tessera,solfi-v2
Fetch current programs
Locally sync the current (live) programs for all supported Prop AMMs.
./target/release/pmm-sim fetch-programs
Locally sync the current (live) programs for BisonFi and Tessera.
./target/release/pmm-sim fetch-programs --pmms=bisonfi,tessera
All datasets are saved as parquet and available at datasets. To peek at the data through cli:
duckdb -csv \
-c "SELECT * FROM 'datasets/datasets/401101387magnusbisonfi51FQwjrvo8J8zXUaKyAznJ5NYpoiTCuqAqCu3HAMB9NZ20260218-205826.parquet'" \
| column -t -s ,
Accounts are by default loaded (saved) from (at) cfg/accounts. Tweaking the source/destination is possible via --accounts-path or ACCOUNTSPATH env variable.
Programs are by default loaded (saved) from (at) cfg/programs. Tweaking the source/destination is possible via --programs-path or PROGRAMSPATH env variable.
Datasets are by default loaded (saved) from (at) datasets. Tweaking the source/destination is possible via --datasets-path or DATASETSPATH env variable.
The supported tokens are defined in cfg/setup.toml under [[tokens]] entries. The markets are defined in cfg/setup.toml under the corresponding PMM.
Check out the CLI subcommands for additional clues (i.e pmm-sim single --help)
$ pmm-sim --help
Simulation environment for Solana's Proprietary AMMs.
Simulate swaps and Benchmark performance across any of the major Solana Prop AMMs.
Usage: pmm-sim <COMMAND>
Commands: direct Initialize an environment for a single PMM and execute a direct swap. router-single Run a single swap route across one or more Prop AMMs with specified weights. router-multi Execute multiple swap routes across nested Prop AMM routes. Each inner list represents a single route, each route possibly going through multiple Prop AMMs. benchmark Benchmark swaps for any one of the implemented Prop AMMs by specifying, optionally, the accounts, src/dst tokens and step size fetch-accounts Fetch accounts from the specified Pmms via RPC and save them locally (presumably for later usage). fetch-programs Fetch programs from the specified Pmms via RPC and save them locally (presumably for later usage). help Print this message or the help of the given subcommand(s)
Options: -h, --help Print help -V, --version Print version
License: MIT