Skip to content

Real-time Cauldron tracking API

cauldron.contract.subscribe

Method: cauldron.contract.subscribe

Description: Subscribe to real-time notifications for Cauldron contract changes for a specific token. This is an Electrum API method that provides both initial state and ongoing updates when contracts are created, modified, or withdrawn.

Parameters

  • contract_version (integer): The contract version to subscribe to. Currently only version 2 is supported.
  • token_id (string): The 32-byte token ID (category) to monitor for contract changes.

Response

Initial Response

When first subscribing, the server returns the current state of all active contracts for the specified token:

{
  "utxos": [
    {
      "pkh": "36c0020dd39e7cd66c21f237dc53d384661a557f",
      "is_withdrawn": false,
      "spent_utxo_hash": "0000000000000000000000000000000000000000000000000000000000000000",
      "new_utxo_hash": "a1b2c3d4e5f6789012345678901234567890123456789012345678901234567890",
      "new_utxo_txid": "94a933a0fa55093a0965eb867f1b9cac2bb07488ced4825bc31f86c9371f76aa",
      "new_utxo_n": 0,
      "token_id": "b79bfc8246b5fc4707e7c7dedcb6619ef1ab91f494a790c20b0f4c422ed95b92",
      "sats": 776661580,
      "token_amount": 16
    }
  ],
  "type": "initial"
}

Update Notifications

After the initial response, the client will receive JSON-RPC notifications whenever contracts change:

{
  "jsonrpc": "2.0",
  "method": "cauldron.contract.subscribe",
  "params": {
    "utxos": [
      {
        "pkh": "36c0020dd39e7cd66c21f237dc53d384661a557f",
        "is_withdrawn": false,
        "spent_utxo_hash": "0000000000000000000000000000000000000000000000000000000000000000",
        "new_utxo_hash": "a1b2c3d4e5f6789012345678901234567890123456789012345678901234567890",
        "new_utxo_txid": "94a933a0fa55093a0965eb867f1b9cac2bb07488ced4825bc31f86c9371f76aa",
        "new_utxo_n": 0,
        "token_id": "b79bfc8246b5fc4707e7c7dedcb6619ef1ab91f494a790c20b0f4c422ed95b92",
        "sats": 776661580,
        "token_amount": 16
      }
    ],
    "type": "update"
  }
}

Field Descriptions

Contract Object Fields

  • pkh (string): The public key hash of the contract owner in hex format
  • is_withdrawn (boolean): Whether the contract has been withdrawn
  • spent_utxo_hash (string): Hash of the UTXO that was spent to create this contract (all zeros for new contracts)
  • new_utxo_hash (string): Hash of the UTXO containing this contract
  • new_utxo_txid (string): Transaction ID of the transaction containing this contract
  • new_utxo_n (integer): Output index of the contract in the transaction
  • token_id (string): The 32-byte token ID this contract is for
  • sats (integer): Amount of satoshis locked in the contract
  • token_amount (integer): Amount of tokens locked in the contract

UTXO Hash Calculation

Both spent_utxo_hash and new_utxo_hash are computed using the same algorithm:

utxo_hash = sha256(txid + n)

Where: - txid is the transaction ID (32 bytes, in internal byte order) - n is the output index as a little-endian 32-bit unsigned integer (4 bytes) - The result is a single SHA-256 hash (not double-SHA256)

Examples

Example 1: New Contract

For a newly created contract: - spent_utxo_hash = "0000000000000000000000000000000000000000000000000000000000000000" (all zeros, indicating no previous UTXO) - new_utxo_hash is calculated from the contract's UTXO: - txid: 94a933a0fa55093a0965eb867f1b9cac2bb07488ced4825bc31f86c9371f76aa - output index (n): 0 - Calculate: sha256(txid_bytes + little_endian_u32(0))

Example 2: Modified Contract

When a contract is modified (e.g., liquidity added/removed): - spent_utxo_hash = hash of the previous contract UTXO (the one being spent) - new_utxo_hash = hash of the new contract UTXO (the one being created)

Code Example

Python:

import hashlib
import struct

def calculate_utxo_hash(txid_hex: str, output_index: int) -> str:
    """Calculate UTXO hash from txid and output index.

    Args:
        txid_hex: Transaction ID as hex string (64 chars)
        output_index: Output index (0-based)

    Returns:
        UTXO hash as hex string (64 chars)
    """
    # Convert txid from hex to bytes (internal byte order)
    txid_bytes = bytes.fromhex(txid_hex)

    # Convert output index to little-endian 32-bit unsigned int
    index_bytes = struct.pack('<I', output_index)

    # Concatenate and hash
    combined = txid_bytes + index_bytes
    utxo_hash = hashlib.sha256(combined).digest()

    return utxo_hash.hex()

# Example usage:
txid = "94a933a0fa55093a0965eb867f1b9cac2bb07488ced4825bc31f86c9371f76aa"
output_index = 0
hash_result = calculate_utxo_hash(txid, output_index)
print(f"UTXO hash: {hash_result}")

Important Notes

  • Byte Order: The txid must be in internal byte order (as stored in blocks/transactions), not display/RPC order. Most libraries handle this correctly when parsing hex txids.
  • Index Encoding: The output index must be encoded as a little-endian 32-bit unsigned integer (4 bytes).
  • Single SHA-256: Use SHA-256 once, not double-SHA256 (which is used elsewhere in Bitcoin Cash).
  • All Zeros: A spent_utxo_hash of all zeros (0000...0000) indicates a newly created contract with no previous UTXO.

Client-Side UTXO Tracking

Important: You must track UTXOs client-side and update your local state from the notifications. The server does not topologically sort changes, so you need to process updates in two steps:

  1. First, add all new UTXOs from the notification
  2. Then, remove all used UTXOs (those with spent_utxo_hash not all zeros)

This two-step process ensures that UTXOs that are created and used within the same update are properly created and removed from local state.

Unsubscribing

To stop receiving notifications, use the cauldron.contract.unsubscribe method:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "cauldron.contract.unsubscribe",
  "params": [2, "b79bfc8246b5fc4707e7c7dedcb6619ef1ab91f494a790c20b0f4c422ed95b92"]
}

Available Electrum Servers

You can connect to the following Electrum server that supports this API:

  • wss://rostrum.riften.net:443

Notes

  • This is an Electrum API method that uses WebSocket connections
  • The server maintains subscription limits per connection to prevent abuse
  • Notifications are sent in real-time as transactions are seen in the mempool.
  • The type field distinguishes between initial state ("initial") and updates ("update")
  • Contract withdrawals will have is_withdrawn: true in update notifications
  • Only contracts for the specified token ID will be included in notifications
  • Important: Process UTXO updates in two steps: add new UTXOs first, then remove spent UTXOs

DApp Integration

If your dapp uses this API, please let us know. We need to know if the API should be maintained.

We're also interested to hear who would wants to host a Rostrum server with Cauldron subscription API. This feedback will be used as grounds open-sourcing such server software.

Error Handling

Common error responses:

  • Invalid contract version: Only version 2 is currently supported
  • Invalid token ID: The provided token ID is not a valid 32-byte hex string
  • Subscription limit exceeded: Too many active subscriptions for this connection