Skip to content

tx.build

Build an unsigned swap transaction for a route. Re-routes over the current snapshot (never stale), assembles the transaction, and returns everything the wallet needs to sign and broadcast.

For a tx that stays current as pools move, subscribe with tx.subscribe instead — it pushes a freshly assembled tx whenever the route changes.

Request

{
  "id": 1,
  "method": "tx.build",
  "params": {
    "sell": "bch",
    "buy": "b79bfc8246b5fc4707e7c7dedcb6619ef1ab91f494a790c20b0f4c422ed95b92",
    "amount": "1",
    "side": "buy",
    "funding": [
      {
        "txid": "aabbccdd...eeff",
        "vout": 0,
        "value": "60000000",
        "script_hex": "76a914...88ac"
      }
    ],
    "receive_addr": "bitcoincash:qz...",
    "change_addr": "bitcoincash:qz...",
  }
}

Parameters

Field Type Required Description
sell string yes Sold asset ("bch" or 64-char hex)
buy string yes Bought asset ("bch" or 64-char hex)
amount string yes Exact-in amount in base units
funding array yes Funding UTXOs (1–500 entries)
receive_addr string yes CashAddr for bought tokens / token change
change_addr string yes CashAddr for BCH change
min_output string no Slippage floor (integer string, base units). Applies to side: "sell" only — in buy mode the output is the amount you asked for, so nothing is held to this.

See the full JSON Schema for request parameters.

Funding Input

Field Type Required Description
txid string yes UTXO txid (display-order hex)
vout integer yes Output index
value string yes Sats value (integer string)
script_hex string yes scriptPubKey hex
token object no CashToken payload ({category, amount})

Response

{
  "id": 1,
  "result": {
    "unsigned_tx_hex": "02000000...",
    "source_outputs": [
      {
        "value": "60000000",
        "locking_script_hex": "76a914...88ac"
      }
    ],
    "inputs_to_sign": [0],
    "expected_output": "1",
    "fee_sats": "3000",
    "fee_token_amount": "0",
    "miner_fee_sats": "1234",
    "route": {
      "kind": "cauldron",
      "..."
    }
  }
}

Response Fields

Field Type Description
unsigned_tx_hex string The unsigned transaction (hex). Sign and broadcast this.
source_outputs array Prevouts index-aligned to inputs (WizardConnect whole-tx signing).
inputs_to_sign array Input indices the client signs (its own funding inputs).
expected_output string Expected bought amount (slippage reference).
fee_sats string Router fee in sats (token↔BCH). "0" if fee in tokens or none.
fee_token_amount string Router fee in sold token units (token↔token). "0" if fee in BCH or none.
miner_fee_sats string Estimated miner fee in sats.
route object The route the build was assembled for — the same coarse view a quote returns.

See the full JSON Schema for the response format.

Signing

Every response carries both aids, so a wallet can use whichever suits it: source_outputs (prevouts index-aligned to all inputs, for signing the whole transaction) and inputs_to_sign (the indices of the funding inputs the client owns).

Broadcasting

The response is an unsigned transaction, and the router never broadcasts it — sending it is the client's step. Sign unsigned_tx_hex, then POST the signed transaction to the transaction broadcast API:

curl -X POST https://broadcast.cauldron.quest/broadcast \
  -H 'Content-Type: application/json' \
  -d '{"tx": "<signed transaction hex>"}'
{ "txid": "94a933a0fa55093a0965eb867f1b9cac2bb07488ced4825bc31f86c9371f76aa" }

Prefer it over broadcasting to a single node: trades against the same pools chain on one another, so a transaction that reaches only part of the network is how double-spend conflicts start.

Transaction Fee Output

Each built transaction carries a router fee as one of its outputs, currently 10 basis points (0.1%) of the trade. This is the on-chain fee for the trade itself, separate from the terms for using the service.

The rate may change during the beta, so read what the build actually pays rather than hard-coding it: fee_sats for a BCH fee, fee_token_amount for a token one, "0" where neither applies.

Build Safety

The assembler runs a safety gate before returning the transaction:

  1. No token burn — every token category is conserved (Σ in == Σ out)
  2. Sane miner fee — fee is between the relay floor and a max-overpay band
  3. Fee output present — when a fee was charged, the output must exist at the fee address
  4. No unspendable outputs — all outputs have non-empty scripts and meet dust thresholds

If any check fails, the build returns a build_failed error instead of an unsafe transaction.

Errors

Code Cause
bad_request Malformed params, invalid asset, too many funding inputs (>500)
route_failed No pools or no fill at this amount
insufficient_funds Funding inputs cannot cover outputs + miner fee
build_failed Safety gate violation (token burn, insane fee, etc.)
slippage Expected output below min_output