Skip to content
CTRL K

    Swaps

    Use this page to build a trade / swap screen: get a firm quote the user can review (amounts, slippage, costs), then execute and follow the ExecutionHandle until it settles.

    routing.quote → easy.swap → ExecutionHandle

    Signing uses a Wallet adapter. If the handle is not yet confirmed or failed, poll settlement.track.

    routing.quote

    Obtain a firm quote before execution.

    const quote = await sdk.routing.quote({
      pair: '42-USDT',
      intent: 'sell',
      side: 'exactIn',
      amount: '1.5',
      ledgers: ['infinite-mainnet'],
      slippageBps: 50,
    })

    Parameters — QuoteRequest

    Provide exactly one of pair or venue (not both, not neither). Prefer pair in UI flows.

    FieldTypeDescription
    pairstringMarket label (e.g. 42-USDT). Mutually exclusive with venue.
    venueVenueId | stringPool id when you already know it. Mutually exclusive with pair.
    intent'buy' | 'sell'Direction relative to the pair base (buy = pay quote for base; sell = pay base for quote). See Choosing intent and side.
    side'exactIn' | 'exactOut'Which amount is fixed: exactIn = what you spend; exactOut = what you want to receive.
    amountstringThat fixed amount as a display decimal (e.g. "1.5"), not raw/smallest-unit.
    ledgersLedgerScope[]Optional. Limit to these ledgers (id or alias, e.g. infinite-mainnet). Omit to let Nutrimatic choose among configured ledgers.
    slippageBpsnumberMax price movement you accept, in bps (e.g. 50 = 0.50%). Optional — default 50. The quote echoes the effective value.
    deadlinenumberOptional. Unix time in milliseconds after which this quote request should not be used.

    Returns — Quote

    FieldTypeDescription
    idstringOpaque quote id. Pass it to easy.swap as quoteId.
    pairLabelstringResolved pair label for display (e.g. 42-USDT).
    intent'buy' | 'sell'Same intent you sent — direction relative to the pair base.
    amountInQuoteLegWhat you spend: instrument + display amount. See legs below.
    amountOutQuoteLegWhat you receive: instrument + display amount. See legs below.
    slippageBpsnumberEffective slippage bound for this quote, in bps (from the request, or 50 if you omitted it).
    expiresAtnumberUnix time in milliseconds. Do not call easy.swap after this — you will get QUOTE_EXPIRED.
    costsQuoteCost[]Cost lines for this quote — see Fees and costs.
    pathPathOptional. Ordered plan when the route is more than one hop — for your UI. After swap, poll settlement.track until confirmed or failed. Field meanings: Settlement — Path.
    ledgerLedgerIdCanonical ledger ID for this quote (never an alias).
    interface QuoteLeg {
      readonly instrumentId: InstrumentId
      readonly amount: string
    }

    amountIn and amountOut are legs in the trade direction (not pair order): In = what you spend, Out = what you receive. Each leg’s amount is a display decimal string in that instrument’s units — not raw/smallest-unit. Nutrimatic handles on-chain conversion. Instrument decimals are in the catalog if your UI needs them for input masks or checks.

    Costs

    A successful quote includes Quote.costs — the cost breakdown for your UI (gas, trade, service; bridge when needed). Other writes can still cost money, but only swap quotes return this list before execute — Fees and costs.

    Example response (sell 1.5 of 42 → receive USDT):

    {
      "id": "quote_01HZX…",
      "pairLabel": "42-USDT",
      "intent": "sell",
      "amountIn": {
        "instrumentId": "evm:421018:instrument:42",
        "amount": "1.5"
      },
      "amountOut": {
        "instrumentId": "evm:421018:instrument:usdt",
        "amount": "3.72"
      },
      "slippageBps": 50,
      "expiresAt": 1719799200000,
      "ledger": "evm:421018",
      "costs": [
        {
          "kind": "trade",
          "amount": "0.0045",
          "instrumentId": "evm:421018:instrument:42"
        },
        {
          "kind": "gas",
          "amount": "0.0007",
          "instrumentId": "evm:421018:instrument:42",
          "estimated": true
        },
        {
          "kind": "service",
          "amount": "0.0001",
          "instrumentId": "evm:421018:instrument:42"
        }
      ]
    }

    Choosing intent and side

    These two fields on QuoteRequest define the trade.

    On a pair label like 42-USDT, the first symbol (42) is the base — the asset you are mainly buying or selling. The second (USDT) is the quote — what you usually pay with or receive. You do not have to memorize DeFi jargon: pick buy/sell for the base, then say whether the number the user typed is “I spend this much” or “I want to receive this much”.

    • intent'sell' (give base, get quote) or 'buy' (give quote, get base)
    • side'exactIn' (the amount is what you spend) or 'exactOut' (the amount is what you want to receive)
    You want…intentsideamount isQuote legs
    Sell a fixed amount of 42sellexactInHow much 42 you spendamountIn = 42, amountOut = USDT
    Receive a fixed amount of USDTsellexactOutHow much USDT you want outamountIn = 42, amountOut = USDT
    Spend a fixed amount of USDTbuyexactInHow much USDT you spendamountIn = USDT, amountOut = 42
    Receive a fixed amount of 42buyexactOutHow much 42 you want outamountIn = USDT, amountOut = 42
    // 1) Sell exactly 1.5 of 42 → amountIn is 42, amountOut is USDT
    await sdk.routing.quote({
      pair: '42-USDT',
      intent: 'sell',
      side: 'exactIn',
      amount: '1.5',
      ledgers: ['infinite-mainnet'],
      slippageBps: 50,
    })
    
    // 2) Get exactly 100 USDT by selling 42 → amountIn is 42, amountOut is USDT
    await sdk.routing.quote({
      pair: '42-USDT',
      intent: 'sell',
      side: 'exactOut',
      amount: '100',
      ledgers: ['infinite-mainnet'],
      slippageBps: 50,
    })
    
    // 3) Spend exactly 100 USDT to buy 42 → amountIn is USDT, amountOut is 42
    await sdk.routing.quote({
      pair: '42-USDT',
      intent: 'buy',
      side: 'exactIn',
      amount: '100',
      ledgers: ['infinite-mainnet'],
      slippageBps: 50,
    })
    
    // 4) Get exactly 1.5 of 42 by paying USDT → amountIn is USDT, amountOut is 42
    await sdk.routing.quote({
      pair: '42-USDT',
      intent: 'buy',
      side: 'exactOut',
      amount: '1.5',
      ledgers: ['infinite-mainnet'],
      slippageBps: 50,
    })

    Do not infer the asset from pairLabel alone — read each leg’s instrumentId and show amount as-is in the UI. In a typical swap screen: Buy/Sell maps to intent; whichever amount the user typed as fixed (spend vs receive) maps to side — that value is always display in QuoteRequest.amount.

    easy.swap

    Execute a swap. Provide exactly one of quoteId or request. Prefer quoteId after routing.quote so the user reviews a firm quote (including costs) first.

    const handle = await sdk.easy.swap({
      quoteId: quote.id,
    })

    Parameters — SwapRequest

    FieldTypeDescription
    quoteIdstringId from a prior routing.quote. Mutually exclusive with request.
    requestQuoteRequestInline quote+swap in one call (same rules as QuoteRequest). Mutually exclusive with quoteId.
    slippageBpsnumberOptional tighter bound in bps. Default: the quote’s slippageBps. If set, must be that value (you may only tighten; a wider bound is rejected).
    deadlinenumberOptional. Unix time in milliseconds after which execution should not proceed.

    The SDK may call your WalletAdapter.sign with purpose: 'swap' before submitting.

    Returns — ExecutionHandle

    FieldTypeDescription
    idstringOpaque execution id. Pass to settlement.track while status is still running (pending / submitted / in_progress).
    statusExecutionStatusWhere the swap is now: pending | submitted | in_progress | confirmed | failed. Stop when confirmed or failed — see Settlement — Status.
    ledgerLedgerIdCanonical ledger ID where this execution is anchored.
    txRefstringOptional. Ledger-native tx / reference when Nutrimatic already has one (e.g. EVM hash).
    receiptExecutionReceiptOptional. Extra confirmation details when status is confirmed.

    Example response:

    {
      "id": "exec_01HZY…",
      "status": "confirmed",
      "ledger": "evm:421018",
      "txRef": "0xabc…",
      "receipt": { "txRef": "0xabc…" }
    }

    Typical sequence

    const quote = await sdk.routing.quote({
      pair: '42-USDT',
      intent: 'sell',
      side: 'exactIn',
      amount: '1.5',
      ledgers: ['infinite-mainnet'],
      slippageBps: 50,
    })
    
    const handle = await sdk.easy.swap({ quoteId: quote.id })
    
    if (handle.status === 'confirmed' || handle.status === 'failed') {
      // Done — refresh reads on success
    } else {
      // Still running — poll until confirmed or failed
      const status = await sdk.settlement.track(handle.id)
    }

    Errors

    READ_ONLY_MODE, CAPABILITY_NOT_AVAILABLE, WALLET_REQUIRED, USER_REJECTED, QUOTE_EXPIRED, SLIPPAGE_EXCEEDED, INSUFFICIENT_ALLOWANCE, PAIR_NOT_FOUND, VENUE_NOT_FOUND, LEDGER_NOT_SUPPORTED.

    Fees and costs · Write operations · Settlement · Types — Execution