Metadata-Version: 2.4
Name: meteora-dlmm
Version: 0.5.0
Summary: Lamport-exact Meteora DLMM swap-quote library, validated against the on-chain program.
Author: nirkt
License: MIT
Project-URL: Homepage, https://github.com/nirkt/meteora-dlmm-py
Project-URL: Repository, https://github.com/nirkt/meteora-dlmm-py
Project-URL: Issues, https://github.com/nirkt/meteora-dlmm-py/issues
Project-URL: Changelog, https://github.com/nirkt/meteora-dlmm-py/blob/main/CHANGELOG.md
Keywords: solana,meteora,dlmm,defi,amm,quote,liquidity,token-2022
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: rpc
Requires-Dist: solana>=0.30; extra == "rpc"
Dynamic: license-file

# meteora-dlmm

Prices Meteora DLMM swaps exactly, down to the lamport. Give it a pool's on-chain account bytes
and it returns the same `amount_out` the program would: the bin walk, the fee ramp, on-chain
limit orders, and Token-2022 transfer fees.

Pure standard library, no dependencies. The reference capture ships inside the package, so an
installed copy proves the claim with no RPC key:

```bash
python -m meteora_dlmm.selftest
```
```
          in_raw          sdk_out          lib_out     diff
      1000000000         79109650         79109650        0
     10000000000        790983110        790983110        0
    100000000000       7901542802       7901542802        0
   1000000000000      58859103727      58859103727        0

max |diff| = 0 lamports  ->  PASS: library reproduces the on-chain program exactly.
```

## Install

```bash
pip install meteora-dlmm            # no third-party dependencies
pip install "meteora-dlmm[rpc]"     # adds a Solana client, for the RPC example only
```

## Use

```python
from meteora_dlmm import PoolState, quote

# bytes from getAccountInfo(pool) and getMultipleAccounts(bin_arrays)
pool = PoolState.from_accounts(lb_pair_bytes, bin_array_byte_list, decimals_x=9, decimals_y=6)
result = quote(pool, amount_in=1_000_000_000, swap_for_y=True)   # sell 1 SOL for USDC
print(result.amount_out, result.bins_crossed)
```

`swap_for_y=True` spends token X. `timestamp` (unix seconds) sets the fee decay reference and
defaults to now. See [examples/](https://github.com/nirkt/meteora-dlmm-py/blob/main/examples).

## Fetch enough BinArrays

`quote()` only sees the bins you pass in. If the walk would leave that window it raises
`InsufficientBinArrays` with `bin_id`, `remaining_in` and `partial`, rather than a number that
is too small. Fetch `array_index_of(e.bin_id)` and re-quote.

- `strict=False` returns the partial instead; `complete` is `False` and `amount_out` is a lower
  bound.
- `exhaustive=True` says you loaded every array the pool has, so a short fill means the pool is
  drained and `complete` stays `True`.

| `complete` | `remaining_in` | Meaning |
|---|---|---|
| `True` | `0` | Full fill, exact. |
| `True` | `> 0` | Pool drained, exact. |
| `False` | `> 0` | Ran out of data, not liquidity. Lower bound. |

## Token-2022

```python
from meteora_dlmm import parse_mint, quote_with_mints

mint_x = parse_mint(mint_x_bytes, owner_x)      # raises UnsupportedMint if unquotable
result = quote_with_mints(pool, amount_in, True, mint_x, mint_y)
```

Transfer fees are taken from the input before the pool sees it and from the output after. Mints
with a transfer hook, or any other extension that changes what a transfer moves, raise
`UnsupportedMint`: their effect cannot be computed off-chain, so refusing is the correct answer.

## API

- `PoolState.from_accounts(lb_pair, bin_arrays, decimals_x, decimals_y, lb_pair_key=None, exhaustive=False)`
- `quote(pool, amount_in, swap_for_y, timestamp=None, support_limit_order=True, strict=True, fee_in=None, fee_out=None)`
  -> `Quote(amount_out, bins_crossed, complete, remaining_in, missing_bin_id, transfer_fee_in, transfer_fee_out, gross_amount_out)`
- `quote_with_mints(pool, amount_in, swap_for_y, mint_x_info, mint_y_info, ...)`
- `parse_mint(mint_bytes, owner)` -> `MintInfo`, or raises `UnsupportedMint`
- `TransferFee(basis_points, max_fee).fee_on(amount)`
- `array_index_of(bin_id)`, `PoolState.is_loaded()`, `PoolState.loaded_bin_range()`
- `decode_lb_pair()`, `decode_bin_arrays()`, `DecodeError`

## Accuracy

| Check | Coverage | Result |
|---|---|---|
| vs SDK `swapQuote` | 85 pools, 22 bin steps, both directions, 905 complete fills | **0 lamports** |
| vs real executed swaps | 10 swaps, both directions | **median 0.0001%** |
| Token-2022 | fee math, cap, every refusal path | **12/12** |

Not yet backed by a fixture: the `processed_order` limit-order tier, which the captured pools
barely exercise.

Transfer-fee pools are priced exactly. Pools whose tokens use a transfer hook are refused rather
than mis-quoted. Known gaps are in [LIMITATIONS.md](https://github.com/nirkt/meteora-dlmm-py/blob/main/LIMITATIONS.md); per-release changes in
[CHANGELOG.md](https://github.com/nirkt/meteora-dlmm-py/blob/main/CHANGELOG.md).

## Verify

```bash
python -m meteora_dlmm.selftest               # from an install, no key
python3 validation/check_quote.py             # vs the SDK's swapQuote
python3 validation/check_token2022.py         # transfer fees and refusals
python3 validation/check_collect_fee_mode.py  # fee-on-input vs fee-on-output pools
```

To capture your own pool you need Node 20 and a key in `RPC_URL`; see
[validation/README.md](https://github.com/nirkt/meteora-dlmm-py/blob/main/validation/README.md).

Not affiliated with Meteora.
