Sigil’s native DEX is a deterministic constant-product AMM implemented in the executor and guarded by the sigil.system.dex system contract. All AMM math is integer-only; no floats appear in consensus settlement.

Pool model

A pool is identified by a canonical id derived from (asset_a, asset_b, fee_bps):
pool_id = blake3("dex/pool/v1\n" || sorted(asset_a, asset_b) || fee_bps)[..32]
The canonical asset order is lexicographic. The fee bps tier is one of 5, 30, 100, or 1000 (0.05%, 0.30%, 1.0%, 10.0%).

Transactions

VariantPurpose
DexCreatePoolCreate a new pool with initial liquidity.
DexAddLiquidityAdd proportional liquidity, mint LP shares.
DexRemoveLiquidityBurn LP shares, return proportional assets.
DexSwapExactInSwap a known input amount for at least min_out.
DexSwapExactOutSwap up to max_in for an exact output amount.

Pool creation

use sigil_sdk::dex::create_pool;

let tx = create_pool(
    &wallet,
    /* asset_a = */ AssetClass::Mint,
    /* asset_b = */ AssetClass::CustomToken(token_id),
    /* fee_bps = */ 30,
    /* amount_a = */ 100_000_000_000,
    /* amount_b = */ 1_000_000_000_000,
)?;
let receipt = client.submit_and_wait(tx).await?;
let pool_id = receipt.events[0].as_pool_created().pool_id;
Initial LP shares are minted to the pool creator as floor(sqrt(amount_a * amount_b)). Subsequent adds are proportional.

Swap

use sigil_sdk::dex::swap_exact_in;

let tx = swap_exact_in(
    &wallet,
    pool_id,
    /* amount_in = */ 1_000_000_000,
    /* min_out = */ 9_800_000_000, // 2% slippage tolerance
)?;
let receipt = client.submit_and_wait(tx).await?;
The executor:
  1. Debits the input asset from the swapper.
  2. Computes the output: out = amount_in × reserve_b × (10000 − fee_bps) / (reserve_a × 10000 + amount_in × (10000 − fee_bps)).
  3. Asserts out >= min_out.
  4. Credits the output asset to the swapper.
  5. Updates the reserves.
  6. Verifies the constant-product invariant did not decrease.
If any step fails, the entire transaction reverts.

Quotes

Read-only quotes are available without sending a transaction:
curl -s https://rpc.sigil.ml/rpc \
  -H 'content-type: application/json' \
  -d '{
    "jsonrpc":"2.0","id":1,
    "method":"sigil_quoteDexSwapExactIn",
    "params":{
      "pool_id":"0xabc...",
      "amount_in":"1000000000"
    }
  }' | jq

Determinism

  • All math is integer-only. No floats.
  • Pool ids are deterministic BLAKE3-derived ids over the canonical asset pair and fee tier.
  • expiration_height is a deterministic block-height guard. 0 in the system-contract ABI means no deadline; native transaction data uses None.
  • MINT debits and credits reuse the native account-balance ledger. Non-MINT DEX asset balances are stored in the DEX state partition.
Durable DEX state is stored in AkashaKV under dex/: pools, LP positions, non-native asset balances, and events survive replay and restart.

RPC surface

MethodReturns
sigil_getDexPoolPool record by id.
sigil_listDexPoolsPaginated pool list.
sigil_quoteDexSwapExactInExact-in quote.
sigil_quoteDexSwapExactOutExact-out quote.
sigil_getDexPositionLP position for a DID and pool.
sigil_listDexEventsPool events filtered by id or DID.

Subscriptions

  • dex topic emits per-pool events (create, swap, add, remove) with optional pool_id filter.

Implementation

  • Types: node/sigil-core/src/dex.rs.
  • Executor: node/sigil-node/src/executor_dex.rs.
  • System contract: pinned at genesis as sigil.system.dex.

See also