157 lines
6.7 KiB
Markdown
157 lines
6.7 KiB
Markdown
# Slippage Mapping
|
|
|
|
This document describes how `SlippageBps` is derived for each supported swap protocol in this repository.
|
|
|
|
## Unified Fields
|
|
|
|
Each parsed `Swap` may include these normalized fields:
|
|
|
|
- `SwapMode`
|
|
- `FixedAmount`
|
|
- `FixedAmountSide`
|
|
- `FixedMint`
|
|
- `LimitAmountType`
|
|
- `LimitAmount`
|
|
- `LimitAmountSide`
|
|
- `LimitMint`
|
|
- `ActualLimitAmount`
|
|
- `ActualLimitAmountSide`
|
|
- `SlippageBps`
|
|
|
|
## Internal Enum Mapping
|
|
|
|
These fields are stored internally as `uint8` enums and serialized as strings in JSON / debug output.
|
|
|
|
### `SwapMode`
|
|
|
|
| Raw Value | Name | Serialized Value |
|
|
| --- | --- | --- |
|
|
| `0` | `SwapModeUnknown` | `""` |
|
|
| `1` | `SwapModeExactIn` | `"exact_in"` |
|
|
| `2` | `SwapModeExactOut` | `"exact_out"` |
|
|
|
|
### `SwapAmountSide`
|
|
|
|
Used by:
|
|
|
|
- `FixedAmountSide`
|
|
- `LimitAmountSide`
|
|
- `ActualLimitAmountSide`
|
|
|
|
| Raw Value | Name | Serialized Value |
|
|
| --- | --- | --- |
|
|
| `0` | `SwapAmountSideUnknown` | `""` |
|
|
| `1` | `SwapAmountSideBase` | `"base"` |
|
|
| `2` | `SwapAmountSideQuote` | `"quote"` |
|
|
|
|
### `SwapLimitType`
|
|
|
|
Used by:
|
|
|
|
- `LimitAmountType`
|
|
|
|
| Raw Value | Name | Serialized Value |
|
|
| --- | --- | --- |
|
|
| `0` | `SwapLimitTypeUnknown` | `""` |
|
|
| `1` | `SwapLimitTypeMinOut` | `"min_out"` |
|
|
| `2` | `SwapLimitTypeMaxIn` | `"max_in"` |
|
|
|
|
## Calculation Rules
|
|
|
|
- `exact_in`
|
|
- `SlippageBps = (actual_out - min_out) / actual_out * 10000`
|
|
- `exact_out`
|
|
- `SlippageBps = (max_in - actual_in) / max_in * 10000`
|
|
|
|
Interpretation:
|
|
|
|
- Positive: execution is better than the user limit
|
|
- Zero: execution lands exactly on the user limit
|
|
- `10000`: user limit is effectively unbounded on the constrained side (for example `min_out = 0`)
|
|
- Negative raw headroom is clamped to `0` because successful-swap storage uses a non-negative bounded metric
|
|
|
|
This definition makes `SlippageBps` a bounded "remaining headroom to the user's limit" metric for successful swaps:
|
|
|
|
- `exact_in`: how much output headroom remained, measured against the realized output
|
|
- `exact_out`: how much input headroom remained, measured against the allowed max input
|
|
|
|
## Protocol Mapping
|
|
|
|
| Protocol | Method Semantics | `SwapMode` | `FixedAmount` | `LimitAmountType` | `LimitAmount` | `ActualLimitAmount` |
|
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
| `Pump` | `buy` | `exact_out` | target token amount | `max_in` | max SOL in | actual SOL in |
|
|
| `Pump` | `buy_exact_sol_in` | `exact_in` | SOL in | `min_out` | min token out | actual token out |
|
|
| `Pump` | `sell` | `exact_in` | token in | `min_out` | min SOL out | actual SOL out |
|
|
| `PumpAMM` | `buy` | `exact_out` | target base out | `max_in` | max quote in | actual quote in |
|
|
| `PumpAMM` | `buy_exact_quote_in` | `exact_in` | quote in | `min_out` | min base out | actual base out |
|
|
| `PumpAMM` | `sell` | `exact_in` | base in | `min_out` | min quote out | actual quote out |
|
|
| `MeteoraDLMM` | `swap` / `swap2` / `swap_with_price_impact` | `exact_in` | `AmountIn` | `min_out` | instruction min out | event output |
|
|
| `MeteoraDLMM` | `swap_exact_out` / `swap_exact_out2` | `exact_out` | `OutAmount` | `max_in` | `MaxInAmount` | event input |
|
|
| `MeteoraPools` | `swap` | `exact_in` | `InAmount` | `min_out` | `MinimumOutAmount` | actual output side |
|
|
| `MeteoraBondingCurve` | `swap` / `swap2` | `exact_in` | `AmountIn` | `min_out` | `MinimumAmountOut` | actual output side |
|
|
| `MeteoraAmmV2` | `swap` / `swap2` exact-in or partial | `exact_in` | params input side | `min_out` | params output threshold | actual output side |
|
|
| `MeteoraAmmV2` | `swap` / `swap2` exact-out | `exact_out` | params target output | `max_in` | params max input | actual input side |
|
|
| `RaydiumLaunchLab` | `*_ExactIn` | `exact_in` | `Amount` | `min_out` | `OtherAmountThreshold` | actual output side |
|
|
| `RaydiumLaunchLab` | `*_ExactOut` | `exact_out` | `Amount` | `max_in` | `OtherAmountThreshold` | actual input side |
|
|
| `RaydiumCPMM` | `swap_base_input` | `exact_in` | `AmountIn` | `min_out` | `MinimumAmountOut` | actual output side |
|
|
| `RaydiumCPMM` | `swap_base_output` | `exact_out` | `AmountOut` | `max_in` | `MaxAmountIn` | actual input side |
|
|
| `RaydiumCLMM` | `swap` / `swap_v2` | `exact_in` or `exact_out` | `amount` | `min_out` or `max_in` | `other_amount_threshold` | opposite-side actual amount |
|
|
| `RaydiumV4` | `swap_base_in` / `swap_base_in_v2` | `exact_in` | `amount_in` | `min_out` | `minimum_amount_out` | actual output side |
|
|
| `RaydiumV4` | `swap_base_out` / `swap_base_out_v2` | `exact_out` | `amount_out` | `max_in` | `max_amount_in` | actual input side |
|
|
| `OrcaWhirlpool` | `swap` / `swap_v2` | `exact_in` or `exact_out` | `amount` | `min_out` or `max_in` | `other_amount_threshold` | opposite-side actual amount |
|
|
| `OrcaWhirlpool` | `two_hop_swap` / `two_hop_swap_v2` | route-level | route specified amount | `min_out` or `max_in` | route threshold | route final output or total input |
|
|
|
|
## Notes
|
|
|
|
- `Pump` quote side is normalized to `wSOL` in the slippage fields, even when legacy `Swap.QuoteMint` is not populated.
|
|
- `OrcaWhirlpool` two-hop instructions use route-level slippage. The normalized slippage fields are attached to the first returned swap entry.
|
|
- `MeteoraAmmV2` uses `SwapMode.ExactIn`, `SwapMode.PartialFill`, and `SwapMode.ExactOut`. `PartialFill` is treated like exact-in for slippage purposes because it still uses a minimum-output threshold.
|
|
|
|
## DAMM v2 Verification
|
|
|
|
The `MeteoraAmmV2` mapping has been checked against the program IDL for `cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG`.
|
|
|
|
- `swap`
|
|
- instruction arg type: `SwapParameters`
|
|
- fields: `amountIn`, `minimumAmountOut`
|
|
- semantics: exact-in
|
|
- `swap2`:
|
|
- instruction / event arg type: `SwapParameters2`
|
|
- `amount0`: "When it's exact in, partial fill, this will be amount_in. When it's exact out, this will be amount_out"
|
|
- `amount1`: "When it's exact in, partial fill, this will be minimum_amount_out. When it's exact out, this will be maximum_amount_in"
|
|
- `swapMode`: `ExactIn`, `PartialFill`, `ExactOut`
|
|
|
|
The downloaded JSON IDL references `SwapMode` in the field docs but does not inline the enum body itself. In this repository, the raw `swapMode` values are interpreted consistently as:
|
|
|
|
- `0 = ExactIn`
|
|
- `1 = PartialFill`
|
|
- `2 = ExactOut`
|
|
|
|
That means the parser mapping is:
|
|
|
|
- `swap2` + `ExactIn` / `PartialFill`
|
|
- `FixedAmount = amount0`
|
|
- `LimitAmount = amount1`
|
|
- `LimitAmountType = min_out`
|
|
- `swap2` + `ExactOut`
|
|
- `FixedAmount = amount0`
|
|
- `LimitAmount = amount1`
|
|
- `LimitAmountType = max_in`
|
|
|
|
## Source Files
|
|
|
|
- `Swap` normalized fields: `tx.go`
|
|
- Shared slippage mapping helpers: `swap_amounts.go`
|
|
- Protocol parsers:
|
|
- `pump.go`
|
|
- `pumpamm.go`
|
|
- `metaoradlmm.go`
|
|
- `metaorapool.go`
|
|
- `meteora_bonding_curve.go`
|
|
- `meteoradamm.go`
|
|
- `raydiumlaunchlab.go`
|
|
- `raydiumcpmm.go`
|
|
- `raydiumclmm.go`
|
|
- `raydiumv4.go`
|
|
- `orcawhirpool.go`
|