# Cloud API Source: https://docs.utexo.com/access-token-authorization/cloud-api Manage Utexo Cloud RLN nodes programmatically over a REST JSON API. ## Overview The Utexo Cloud API allows you to manage RGB Lightning Node instances programmatically — creating, querying, upgrading, destroying nodes, and managing their settings. ## Base URL ```text theme={null} https://cloud-api.thunderstack.org ``` ## Authentication All endpoints require bearer token authentication. First [create an API token](/access-token-authorization/create-api-token), then export it: ```bash theme={null} export CLOUD_API_TOKEN="" ``` Include the token in every request: ```bash theme={null} -H "Authorization: Bearer ${CLOUD_API_TOKEN}" ``` ## Endpoints ### List Nodes `GET /api/nodes` Returns all nodes and their build history. ```bash theme={null} curl -s \ -H "Authorization: Bearer ${CLOUD_API_TOKEN}" \ "https://cloud-api.thunderstack.org/api/nodes" ``` ```json theme={null} { "nodes": [ { "nodeId": "", "name": "", "network": "regtest", "status": "RUNNING", "initialized": true, "invoke_url": "", "settings": { "webhookUrl": "" }, "builds": [{ "buildNumber": 1, "buildStatus": "SUCCESS", "buildComplete": true, "timestamp": "" }] } ] } ``` ### Create a Node `POST /api/nodes` | Parameter | Type | Required | Description | | --------------------- | ------ | -------- | ----------------------------- | | `name` | string | Yes | Unique name for the node | | `network` | string | Yes | `regtest` or `testnet` | | `settings.webhookUrl` | string | No | URL to receive webhook events | ```bash theme={null} curl -s \ -H "Authorization: Bearer ${CLOUD_API_TOKEN}" \ -H "Content-Type: application/json" \ -d '{"name":"my-node","network":"regtest","settings":{"webhookUrl":"https://example.com/webhooks/thunderstack"}}' \ "https://cloud-api.thunderstack.org/api/nodes" ``` ```json theme={null} { "data": { "nodeId": "", "name": "my-node", "network": "regtest", "status": "STARTING" }, "message": "" } ``` ### Get a Node `GET /api/nodes/{id}` ```bash theme={null} curl -s \ -H "Authorization: Bearer ${CLOUD_API_TOKEN}" \ "https://cloud-api.thunderstack.org/api/nodes/" ``` ### Destroy a Node `DELETE /api/nodes` This action is irreversible. Ensure you have a backup before destroying a node. ```bash theme={null} curl -s -X DELETE \ -H "Authorization: Bearer ${CLOUD_API_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "destroyNodeId": "" }' \ "https://cloud-api.thunderstack.org/api/nodes" ``` ### Update Node Settings `POST /api/nodes/{id}/settings` Update node settings, such as the webhook URL. ```bash theme={null} curl -s -X POST \ -H "Authorization: Bearer ${CLOUD_API_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "settings": { "webhookUrl": "https://example.com/webhooks/thunderstack" } }' \ "https://cloud-api.thunderstack.org/api/nodes//settings" ``` ### Node Lifecycle: Start `POST /api/nodes/{id}/start` ```bash theme={null} curl -s -X POST \ -H "Authorization: Bearer ${CLOUD_API_TOKEN}" \ "https://cloud-api.thunderstack.org/api/nodes//start" ``` ### Node Lifecycle: Stop `POST /api/nodes/{id}/stop` ```bash theme={null} curl -s -X POST \ -H "Authorization: Bearer ${CLOUD_API_TOKEN}" \ "https://cloud-api.thunderstack.org/api/nodes//stop" ``` ### Upgrade Node `POST /api/nodes/{id}/upgrade` Upgrades the node to the latest RLN image version. ```bash theme={null} curl -s -X POST \ -H "Authorization: Bearer ${CLOUD_API_TOKEN}" \ "https://cloud-api.thunderstack.org/api/nodes//upgrade" ``` ### Get Latest RLN Image Version `GET /api/nodes/latest-rln-image` ```bash theme={null} curl -s \ -H "Authorization: Bearer ${CLOUD_API_TOKEN}" \ "https://cloud-api.thunderstack.org/api/nodes/latest-rln-image" ``` ### Webhooks: Get Public Key `GET /api/webhook-public-key` Returns the public key used to verify webhook signatures. See [Webhooks](/cloud/webhooks) for details. ```bash theme={null} curl -s \ -H "Authorization: Bearer ${CLOUD_API_TOKEN}" \ "https://cloud-api.thunderstack.org/api/webhook-public-key" ``` ### Logs: Trigger Export `POST /api/nodes/{id}/logs` Starts a log export job for a node. Returns a `taskId`. ```bash theme={null} curl -s -X POST \ -H "Authorization: Bearer ${CLOUD_API_TOKEN}" \ "https://cloud-api.thunderstack.org/api/nodes//logs" ``` ### Logs: Get Download URLs `GET /api/nodes/{id}/logs?taskId={taskId}` ```bash theme={null} curl -s \ -H "Authorization: Bearer ${CLOUD_API_TOKEN}" \ "https://cloud-api.thunderstack.org/api/nodes//logs?taskId=" ``` # Create API Token Source: https://docs.utexo.com/access-token-authorization/create-api-token Generate an access token to authenticate requests to the Utexo Cloud API. ## Overview Access tokens are used to authenticate requests to the [Cloud API](/access-token-authorization/cloud-api). Tokens do not expire and remain valid until manually revoked, so treat them like passwords. ## Creating a Token 1. **Navigate to the API Tokens page** \ Go to the API Tokens page in your Utexo Cloud dashboard and click **"Create Access Token"**. 2. **Provide a token name** \ Enter a descriptive name for the token. Using meaningful names (e.g., `production-server`, `dev-laptop`) helps you identify and manage multiple tokens. 3. **Copy and store the token securely** \ The token is shown once. Store it in a secrets manager or environment variable immediately. ## Using the Token Export the token as an environment variable and include it in API requests: ```bash theme={null} export CLOUD_API_TOKEN="" curl -H "Authorization: Bearer ${CLOUD_API_TOKEN}" \ "https://cloud-api.thunderstack.org/api/nodes" ``` See the [Cloud API reference](/access-token-authorization/cloud-api) for all available endpoints. ## Revoking a Token Revoking a token immediately deactivates it and prevents any further API access using that token. To revoke a token: 1. Return to the **API Tokens** section in your dashboard. 2. Find the token item you want to revoke. 3. Click the **"Revoke"** button for that token. # API Reference Overview Source: https://docs.utexo.com/api-reference/overview Choose the API reference for the Utexo service you are integrating. Utexo does not expose one global API contract. The Mint service, RGB Node, RGB Lightning Node and Utexo Cloud have separate endpoints, authentication models and release lifecycles. Each product has its own API contract. Use the reference for the specific service you are integrating. Transfer status, bridge-in signatures, verification, and transaction submission. Wallet-scoped RGB asset issuance, receive, send, and balance operations. RGB, Lightning, channel, peer, swap, and node lifecycle operations. Cloud node provisioning and management with access-token authorization. ## Specification Status | Product | Published reference | Specification or implementation | | ------------------ | -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | RGB Lightning Node | [RGB Lightning Node API](/rgb-lightning-node/rgb-lightning-node-api) | [OpenAPI specification](https://github.com/UTEXO-Protocol/rgb-lightning-node/blob/dev/openapi.yaml) | | Mint | [Mint API Reference](/product-suite/mint-api-reference) | Not currently published | | RGB Node | [RGB Node API Reference](/cloud/rgb-node/api-reference) | [Reference implementation](https://github.com/UTEXO-Protocol/rgb-node-api) | | Utexo Cloud | [Cloud API Reference](/access-token-authorization/cloud-api) | Not currently published | Where a public specification or reference implementation is not available, use the published API reference as the supported integration guide. ## Developer Resources * [RGB Lightning Node interactive API reference](https://utexo-protocol.github.io/rgb-lightning-node) * [RGB Lightning Node OpenAPI specification](https://github.com/UTEXO-Protocol/rgb-lightning-node/blob/dev/openapi.yaml) * [RGB Lightning Node source repository](https://github.com/UTEXO-Protocol/rgb-lightning-node) * [RGB Node reference implementation](https://github.com/UTEXO-Protocol/rgb-node-api) # Node Management Source: https://docs.utexo.com/cloud/getting-started Create, connect, upgrade, back up, and destroy RGB Lightning Nodes on Utexo Cloud. ## Overview Utexo Cloud (powered by Thunderstack) provides a managed environment for running RGB Lightning Nodes (RLN). These guides cover the full lifecycle of an RLN node — from creation through decommissioning. ## Guides Provision a new RGB Lightning Node on the Cloud dashboard. Connect securely via mTLS or API token. Update your node to the latest RLN image. Back up and restore node state. Permanently decommission a node. ## Prerequisites Before creating a node, ensure you have: 1. An active Utexo Cloud account at [cloud.utexo.com](https://cloud.utexo.com) 2. A [Cloud API token](/access-token-authorization/create-api-token) (required for API-based operations) # Connect to RLN Node Source: https://docs.utexo.com/cloud/rln-node/connect-rln-node Connect securely to your RGB Lightning Node via mTLS or API token. Once your RLN node is in `RUNNING` status, you can connect to it using one of two methods: **mTLS** (certificate-based) or **API token** (bearer authentication). ## Option 1: Connect via mTLS ### 1. Access Node Connection Details Navigate to the Connect page for your node: ``` https://www.thunderstack.org/{nodeId}/connect ``` This page displays the unique endpoint URL for your node, along with the private key and certificate required for the mTLS connection. These credentials are automatically generated for your session. ### 2. Obtain Connection Credentials From the `/connect` page, download: * **Private Key**: a `.key` file (e.g., `privateKey.key`) containing your private key * **Certificate**: a `.pem` file (e.g., `certificate.pem`) containing your public key certificate * **Endpoint URL**: formatted as `https://{userId}.thunderstack.org/nodes/{userId}/{nodeId}/` Store your private key in a secure location. Do not share it or commit it to version control. ### 3. Make a Request Use the downloaded credentials with `curl`: ```bash theme={null} curl --key /path/to/privateKey.key \ --cert /path/to/certificate.pem \ https://{userId}.thunderstack.org/nodes/{userId}/{nodeId}/ ``` Replace the paths and endpoint with the values from your `/connect` page. ## Option 2: Connect via API Token API token authentication is simpler to use for programmatic integrations. ```bash theme={null} export CLOUD_API_TOKEN= curl -H 'Authorization: Bearer ${CLOUD_API_TOKEN}' \ https://node-api.thunderstack.org// ``` To obtain a `CLOUD_API_TOKEN`, see [Create API Token](/access-token-authorization/create-api-token). Both mTLS and API token authentication give equivalent access to the node's REST API. mTLS is preferred in production environments where certificate-based trust is required. # Create RLN Node Source: https://docs.utexo.com/cloud/rln-node/create-rln-node Provision a new RGB Lightning Node on the Utexo Cloud dashboard. ## Prerequisites Before creating a node, ensure you have: 1. An active Utexo Cloud account at [cloud.utexo.com](https://cloud.utexo.com) 2. A [Cloud API token](/access-token-authorization/create-api-token) (required for API-based operations) ## Steps ### 1. Initiate Node Creation Navigate to the `/nodes` page. You will see an overview of your current nodes and the option to create new ones. Click the **Create Node** button to open the node creation form. ### 2. Configure Your RLN Node Enter a unique name for your new node. This name identifies the node in your dashboard. Click **Create** to submit the form and begin provisioning. ### 3. Monitor Node Creation Status After submitting, a new entry appears in the nodes table with a status of `IN_PROGRESS`. During this phase, no operations can be performed on the node. Visit `/nodes/{nodeId}` to view detailed information: current status, build progress, endpoint details, and configuration options. | Status | Meaning | | ------------- | ---------------------------------------------------------- | | `IN_PROGRESS` | Node is under construction. No interactions are available. | | `RUNNING` | Node is fully operational. | | `PAUSED` | Node has been paused. | | `FAILED` | Node encountered an error during provisioning. | ### 4. Final Verification Once the status changes to `RUNNING`, verify the node appears correctly in your dashboard and that you can access its features and settings. After a node reaches `RUNNING` status, connect to it via mTLS or API token. See [Connect to RLN Node](/cloud/rln-node/connect-rln-node) for details. ## Regtest Network (Testing Only) The following applies only to nodes on the **Regtest** network for development and testing. Do not use these commands on Mainnet nodes. On Regtest, blocks are not mined automatically. Use your node's Bitcoin Core RPC endpoint to advance the chain manually. To mine blocks: ```bash theme={null} curl --location '{YOUR_NODE_RPC_ENDPOINT}/execute' \ --header 'Content-Type: application/json' \ --data '{ "args": "mine 10" }' ``` To get test BTC (local faucet), send to an address and mine a block to confirm: ```bash theme={null} curl --location '{YOUR_NODE_RPC_ENDPOINT}/execute' \ --header 'Content-Type: application/json' \ --data '{ "args": "sendtoaddress
0.1" }' ``` Replace `{YOUR_NODE_RPC_ENDPOINT}` with the RPC endpoint visible on your node's dashboard page. # Destroy your Node Source: https://docs.utexo.com/cloud/rln-node/destroy-rln-node Permanently decommission an RLN node on Utexo Cloud. Node destruction is **permanent and irreversible**. All associated resources will be cleaned up and cannot be recovered. Back up your node state before proceeding. See [Node Backup / Restore](/cloud/rln-node/node-backup-restore). ## Steps ### 1. Navigate to the Node Page Access the node you want to destroy at: ``` /nodes/{nodeId} ``` ### 2. Check Node Status Ensure the node is in `RUNNING` status. Only nodes in a running state are eligible for destruction. ### 3. Destroy the Node Click the **Destroy** button on the node page. This action initiates the destruction process and the node's status changes to `IN_PROGRESS`. ### 4. Confirm Destruction Once the node has been successfully destroyed, the status updates to `DESTROYED`. This confirms that the node has been decommissioned and all associated resources have been cleaned up. # Node Backup / Restore Source: https://docs.utexo.com/cloud/rln-node/node-backup-restore Back up and restore your RLN node state on Utexo Cloud. ## Node Backup ### 1. Access Backup Functionality Navigate to the backup page for your node: ``` nodes/{nodeId}/backup ``` ### 2. Create a Backup If no backup has been previously created, the page displays a **Create Backup** button. Clicking the button triggers an AWS Lambda function that communicates with the node's `/backup` API endpoint. Once the backup is successfully created, it is automatically uploaded to an Amazon S3 bucket. ### 3. Download the Backup A pre-signed URL is generated that allows direct download from S3. The URL expires **30 minutes** after being issued. Download and store the backup file securely before the pre-signed URL expires. After 30 minutes, you will need to create a new backup to obtain a fresh download URL. ## Node Restore ### 1. Access Restore Functionality Navigate to the backup page for the node you want to restore: ``` nodes/{nodeId}/backup ``` Locate the **Restore node** section. ### 2. Upload the Backup File Click **Upload** to generate an S3 upload URL. Select the backup file from your local device. The upload begins automatically. ### 3. Restore the Node After the upload completes, a **Restore** button becomes active. Click **Restore** to start the restoration process via the node's `/restore` API endpoint. The restore process will overwrite the current node state. Ensure you are restoring the correct backup file before proceeding. # Node UI Actions Source: https://docs.utexo.com/cloud/rln-node/node-ui-actions Interactive actions available on the RLN node page: init, lock, unlock, and nodeInfo. On the Node Page (`/nodes/{nodeId}`), the following interactive actions are available: ## /nodeinfo Automatically retrieves and displays the node's current status each time the node page is opened. * **Error handling**: If the node is locked or encounters issues, the UI displays an appropriate error message. * **Use case**: Provides real-time visibility into the node's operational state. ## /init Initializes the node after its creation, making it ready for operation. * **Process**: During initialization, the system generates a mnemonic and provides it to the user. * **Security**: The mnemonic must be securely saved. It is the only way to recover the node's wallet. * **Use case**: Mandatory step after node creation to enable further actions. Save your mnemonic immediately during the `/init` step. It will not be shown again. Loss of the mnemonic means loss of access to the node's funds. ## /lock Secures the node by locking it, preventing unauthorized access. * **Process**: The user enters a password to lock the node. * **Use case**: Protects sensitive node operations when the node is not actively in use. ## /unlock Unlocks the node, allowing it to resume normal operations. * **Process**: The user enters the correct password to reverse the lock status. * **Use case**: Required to access and manage the node after it has been secured via `/lock` or after an upgrade. # Upgrade RLN Node Source: https://docs.utexo.com/cloud/rln-node/upgrade-rln-node Update your RGB Lightning Node to the latest RLN image version. ## UI Upgrade Flow When an RLN node is outdated, a notification block appears at the top of the Node Page prompting you to upgrade. The notification reads: > Please note: Your current RLN image version is no longer supported. Update your node to the latest version. ### Steps 1. **Click the Upgrade button** — Navigate to the node page where the notification block appears and click **Update** to trigger the upgrade process. This initiates an upgrade to the latest RLN image. 2. **Wait for the upgrade to complete** — The process may take a few minutes. During this time, the node will be **locked** and unavailable. 3. **Unlock the node** — Once the upgrade is complete, the node remains locked. To resume using it: * Navigate to the Node Page for that node. * Click the **Unlock** button. * The node will be fully operational on the updated image. ## Automatic Bulk Upgrade (Scale or Wallet Plan) For users on the Scale or Wallet Plan, the system provides automatic bulk upgrades. ### How It Works When a new RLN image version is released, all user nodes are **automatically upgraded** to the latest version. Manual triggering is not required. ### Post-Upgrade: Unlock Nodes After an automatic bulk upgrade, all upgraded nodes are locked. To continue using each node: 1. Navigate to the Node Page for the respective node. 2. Click the **Unlock** button. Automatic upgrades ensure all nodes stay up-to-date without user intervention. However, **manual unlocking is required for each upgraded node** to resume functionality. ## Upgrade via API You can also check node version status and trigger upgrades programmatically using the Cloud API. Refer to the [Cloud API](/access-token-authorization/cloud-api) reference for the relevant endpoints. # Webhooks Source: https://docs.utexo.com/cloud/webhooks Receive real-time event notifications from your Utexo Cloud RLN nodes. ## Overview Utexo Cloud supports webhooks to notify your application about events occurring in your RLN nodes. When an event is triggered, Utexo Cloud sends a `POST` request to your configured endpoint with a JSON payload and a cryptographic signature header for verification. ## Setting Up a Webhook ### Option 1: Via Node Settings 1. Navigate to your node page and click **Settings**. 2. Locate the **Webhook URL** field. 3. Enter the HTTPS endpoint where you want to receive events. 4. Save the settings. Your public key for signature verification is shown in the same section. ### Option 2: Via API at Node Creation When creating a node via the Cloud API, include `webhookUrl` in the `settings` object: ```bash theme={null} curl -s \ -H "Authorization: Bearer ${CLOUD_API_TOKEN}" \ -H "Content-Type: application/json" \ -d '{"name":"my-node","network":"regtest","settings":{"webhookUrl":"https://example.com/webhooks/thunderstack"}}' \ "https://cloud-api.thunderstack.org/api/nodes" ``` ## How Webhooks Work When a node state changes or an operation completes, Utexo Cloud sends a `POST` request to your endpoint including: * A **JSON payload** with the event data and `nodeId` * An **`X-Utexo-Signature` header** containing a cryptographic signature ## Node Status Values Webhook events reflect the following node status transitions: | Status | Description | | ------------- | ------------------------------------- | | `RUNNING` | Node is fully operational | | `STARTING` | Node is starting up | | `PAUSED` | Node has been paused | | `FAILED` | Node encountered an error | | `IN_PROGRESS` | An operation is currently in progress | ## Verifying Webhook Signatures All webhook requests include a `X-Utexo-Signature` header that should be validated to confirm authenticity. ### Step 1: Retrieve the Public Key ```bash theme={null} curl -s \ -H "Authorization: Bearer ${CLOUD_API_TOKEN}" \ "https://cloud-api.thunderstack.org/api/webhook-public-key" ``` This returns the public key used to sign all webhook payloads from your account. ### Step 2: Validate the Signature Use the public key to verify the `X-Utexo-Signature` header on each incoming request. ### Step 3: Validate the Payload Ensure the `nodeId` in the payload matches the expected node to prevent spoofing. ## Security Best Practices Always verify the `X-Utexo-Signature` header before processing any webhook payload. 1. **Use HTTPS** — Your webhook endpoint must use HTTPS to protect data in transit. 2. **Verify the signature** — Validate the `X-Utexo-Signature` header using the public key on every request. 3. **Validate the node ID** — Confirm the `nodeId` in the payload matches the node you expect. # Architecture Source: https://docs.utexo.com/getting-started/architecture How Bitcoin, the Lightning Network, RGB, the Utexo execution layer, the Mint, and Swap fit together as a unified stablecoin settlement stack. Utexo is built on a layered stack. Each layer has a distinct and non-overlapping role. Together they deliver the properties that make Bitcoin-native stablecoin settlement viable for production payment systems: deterministic costs, settlement privacy, and Bitcoin-backed security. The Mint and Swap layers extend this stack outward, connecting external EVM-based networks and enabling non-custodial BTC/USDT exchange on Bitcoin. Screenshot 2026 05 28 At 19 41 21 ## Stack Overview | Layer | Role | What Utexo Uses It For | | ----------------- | ----------------------------------------- | ------------------------------------------------------------------------------------ | | Bitcoin | Settlement anchor and finality | Double-spend prevention, dispute resolution, irreversible state | | Lightning Network | Off-chain execution and value transfer | High-throughput payments, near-instant finality, predictable latency | | RGB | Asset issuance and client-side validation | Stablecoin creation, privacy-preserving transfers, Bitcoin-secured ownership | | Utexo | Execution and coordination layer | Routing, liquidity, fee management, SDK/API abstraction | | Mint | USDT Cross-chain connectivity | Inbound and outbound transfers between Ethereum, Tron and the RGB layer | | Swap | Cross-chain swap | Cross-chain BTC ↔ USDT swaps on Bitcoin and Lightning via the HotPot intent protocol | In the Utexo model, ownership proofs are validated locally by users' wallets (client-side validation), while actual payments occur through bidirectional Lightning channels. There is no global state to synchronise. Each transaction is a direct peer-to-peer exchange verified by cryptographic commitments. ## Bitcoin Bitcoin serves as the settlement and finality anchor for the entire Utexo system. It handles correctness, finality and dispute resolution, acting as the foundational layer that grants irreversible settlement and strong security. This allows Utexo to decouple settlement guarantees from execution cost volatility. **What this means in practice:** * Individual payments, asset transfers, and balances are not recorded on-chain. Only compact cryptographic commitments derived from Utexo activity are anchored to Bitcoin in the form of UTXOs, indistinguishable from other ordinary metadata. * By anchoring state commitments to Bitcoin via RGB, Utexo ensures that execution taking place off-chain cannot be arbitrarily rewritten or manipulated without detection. * This model minimises on-chain footprint while preserving the ability to prove that off-chain execution followed the agreed rules, remaining accountable to a globally verifiable settlement layer. If off-chain execution were to fail, stall, or behave maliciously, participants retain the ability to fall back to Bitcoin-backed guarantees. This approach allows Utexo to scale payment activity without compromising on the long-term trust model that Bitcoin provides. ## Lightning Network The Lightning Network provides the off-chain execution environment for Utexo payments. Utexo adds pooled liquidity and routing access through its APIs, so applications do not need to manage channels directly. All channel management, rebalancing, and routing are handled internally. **What this means in practice:** * Payments settle off-chain in milliseconds with near-instant finality. * Utexo pre-funds channels and manages liquidity so that routing never fails due to insufficient capacity. * Fixed latency and predictable fees make payment behaviour deterministic for application developers. ## RGB RGB is the smart contract and asset issuance protocol running on top of Bitcoin that enables Utexo to issue and transfer USDT natively on-chain. RGB uses a client-side validation model: contract state is maintained locally by the asset owner, not broadcast to a public ledger. Ownership proofs are committed to Bitcoin UTXOs without revealing transfer details on-chain. **What this means in practice:** * Asset transfers are private by default. There is no public ledger of individual RGB transfers. * USDT issued via RGB is a real Bitcoin-layer asset with Bitcoin-backed finality, not a wrapped token on a separate chain. * The RGB protocol enforces asset supply integrity: issuance, transfer, and destruction are cryptographically verifiable by any participant holding the relevant contract history. ## Utexo Execution Layer The Utexo execution layer is the payment execution environment for USDT. It sits above Bitcoin, Lightning, and RGB and provides the coordination logic that makes the stack usable at the application level. **Role in the stack:** * Routes payments through Lightning channels with pre-funded liquidity. * Manages RGB asset state and channel balances internally. * Abstracts away the complexity of Lightning channel management, RGB state transitions, and fee estimation. **Performance characteristics:** * By combining RGB's client-side validation architecture with Lightning's routing network, Utexo achieves transaction times of around 200 ms latency, comparable to Visa speeds. * Utexo makes Bitcoin usable as a stablecoin settlement network for high-throughput, private-by-default payments that behave predictably regardless of network conditions. **Integration surface:** * REST API and SDK for application-level integration * Abstracts all channel management, routing, and liquidity operations internally * No protocol-specific knowledge required in application code ## Mint The Utexo Mint connects external EVM-based and Non-EVM-based networks to the Bitcoin RGB layer, enabling cross-chain USDT transfers in both directions. It is built around Arbitrum as the single EVM settlement hub, with USDT from EVM networks, Tron and Solana supported transparently via the USDT0 / LayerZero protocol. Minted USDT is represented on Bitcoin as RGB USDT, a real on-chain asset with Bitcoin-backed settlement guarantees. The Mint is composed of five coordinated components: 1. **Mint orchestrator** that tracks all in-flight transfers; stateless chain-specific. 2. **Connectors** that monitor smart contracts and issue on-chain transactions; three independent. 3. **Federated Signer Nodes**, each running inside an AWS Nitro Enclave, that jointly sign transactions using a TEE-federation with threshold scheme — ensuring no single node can act unilaterally. 4. **RGB Multisig Mint** that coordinates multi-party custody of RGB assets with its own threshold scheme 5. **BTC Relay** that streams Bitcoin block headers into the TEE for in-enclave SPV verification. For full component details, supported networks, transfer flow, and security properties, see [Mint](/product-suite/mint). ## Swap The Utexo Swap enables cross-chain swaps, with BTC ↔ USDT exchange directly on Bitcoin, also on Solana, Ethereum, Tron powered by the [HotPot](https://docs.hotpot.tech) intent protocol. It provides internal BTC/USDT execution for settlement, treasury management and payments, reducing reliance on centralised venues for rebalancing and conversion. **How it works:** Swap uses an intent-based execution model with two participants: the **user**, who initiates the swap and a **resolver**, who executes it. 1. **Quote** - The user requests a quote for their desired currency pair and amount via the HotPot Quote API. The API returns a time-limited execution estimate with all pricing information. 2. **Intent creation** - The user creates a structured intent specifying their addresses and the agreed quote identifier, representing their intention to execute the swap under the quoted conditions. 3. **Signing** - The user signs the intent off-chain, cryptographically authorising resolvers to execute the swap according to the quoted conditions. 4. **Execution** - HotPot notifies the winning resolver, who deposits assets into a per-swap escrow contract. Funds are only released once fulfillment is verified on-chain. The swap either completes in full or reverts, there is no partial execution risk. **Key properties:** | Property | Description | | ------------------ | ----------------------------------------------------------------- | | Non-custodial | Users maintain control of assets throughout the swap process | | Atomic settlement | Swaps complete in full or revert safely — no partial fills | | Smart routing | Best-execution path across all available liquidity | | Privacy-preserving | Front-running is prevented by design via off-chain signed intents | | Instant finality | Trades settle with predictable fees on Bitcoin | For full component details, supported networks, transfer flow and security properties, see [SWAP](product-suite/swap/swap). ## Further Reading Why existing payment infrastructure fails and what Utexo solves. Product overview and integration paths. Full Mint component reference, supported networks, and security model. Cross-chain BTC/USDT exchange on Bitcoin. # Glossary Source: https://docs.utexo.com/getting-started/glossary Key terms used throughout the Utexo documentation. Key terms used throughout the Utexo documentation. ## B **Bitcoin** The base settlement layer used by Utexo. All RGB asset state is ultimately anchored to Bitcoin UTXOs, and Bitcoin provides double-spending prevention and final settlement guarantees. **BIP-39** Bitcoin Improvement Proposal 39. The standard for generating human-readable mnemonic seed phrases (12 or 24 words) that can be used to derive all wallet keys. The Utexo SDK uses BIP-39 mnemonics for wallet initialisation and recovery. **Blinded Invoice** A privacy-preserving RGB payment request. The receiver generates a blinded UTXO reference that hides their address from the sender while still allowing the asset transfer to be verified client-side. Generated via `wallet.blindReceive()`. **Mint Connector** A stateless gRPC microservice that monitors a specific blockchain's smart contract for `FundsIn` events and issues `FundsOut` transactions on the destination chain. Each supported network has its own Connector implementation. Connectors are stateless and reboot-resistant; all transfer state is held by the Mint orchestrator. ## C **CFA (Collectible Fungible Asset)** An RGB asset type for tokens with a fixed supply cap per issuance batch. CFAs are used for assets such as stablecoins and limited-edition tokens. Unlike NIA assets, multiple CFA issuances can be made by the same issuer up to a defined global cap. **Channel (Lightning)** A bidirectional payment channel opened between two Lightning Network nodes. Channels allow off-chain USDT and BTC transfers with instant settlement. Utexo manages channel lifecycle, routing, and liquidity on behalf of integrators. **Client-Side Validation** The RGB protocol's core security model. Instead of verifying asset state on a public blockchain, the recipient validates the full chain of ownership locally using cryptographic proofs. This preserves privacy and removes the need for global consensus on asset balances. **Commitment** A compact cryptographic hash anchored to a Bitcoin UTXO that represents off-chain RGB state. Commitments are indistinguishable from ordinary Bitcoin transaction metadata on-chain. ## E **EIP-712** An Ethereum standard for typed structured data signing. The Utexo Mint Enclave Signer uses EIP-712 to sign `FundsOut` authorisation messages for EVM-bound transfers, allowing smart contracts to verify the signer's intent without exposing raw private keys. **Enclave Signer** The cryptographic microservice responsible for signing all Mint transactions. It runs exclusively inside an AWS Nitro Enclave — a hardware-isolated Trusted Execution Environment (TEE) — where private keys are generated and held. Keys never exist outside the enclave boundary. See also: *Trusted Execution Environment (TEE)*. ## F **FundsIn** An on-chain event emitted by a Mint smart contract when a user deposits assets on the source chain. The Mint Connector detects this event and notifies the Mint orchestrator to begin routing the transfer to the destination chain. **FundsOut** A transaction issued by the Mint Connector on the destination chain to release assets to the recipient, following a validated `FundsIn` event. The Enclave Signer signs the `FundsOut` payload inside the TEE before it is broadcast. ## H **HODL Invoice** A Lightning invoice that does not immediately settle upon payment. The funds are held ("HODLed") in a Hash Time-Locked Contract (HTLC) until the recipient explicitly accepts or the invoice expires. Used in atomic swap protocols and escrow flows to coordinate cross-chain payments. ## L **Lightning Invoice** A standard BOLT-11 or BOLT-12 payment request used to receive BTC or RGB assets over Lightning channels. Generated via `wallet.createLightningInvoice()`. **Lightning Network** A Bitcoin Layer 2 payment protocol that enables instant, low-cost transfers via off-chain payment channels. Utexo uses Lightning as the execution layer for RGB asset transfers, providing near-instant settlement and predictable fees. **LDK (Lightning Development Kit)** An open-source library by Spiral (Block) that implements the Lightning Network protocol in Rust. The Utexo RGB Lightning Node is built on top of LDK, enabling it to manage payment channels and route Lightning payments for RGB assets. **LSP (Lightning Service Provider)** A node operator that provides channel liquidity and routing services to wallet users. Utexo acts as an LSP, opening inbound channels on behalf of users so they can receive Lightning payments without running their own node. ## M **Mnemonic** A 12 or 24-word BIP-39 seed phrase that represents the root key of a wallet. Store it securely offline — it is the only way to recover a wallet. Never share it. ## N **NIA (Non-Inflationary Asset)** An RGB asset type with a fixed total supply that cannot be inflated after issuance. USDT issued via Utexo is an NIA asset. Issued via `wallet.issueAssetNia()`. ## P **PSBT (Partially Signed Bitcoin Transaction)** A standard format (BIP-174) for Bitcoin transactions that have not yet been fully signed. The Utexo SDK uses PSBTs as an intermediate step in the send flow, allowing keys to be held separately from transaction construction. The Mint Enclave Signer uses Taproot Schnorr PSBTs for RGB → EVM direction transfers. Signed via `wallet.signPsbt()`. ## R **RGB** A smart contract protocol built on Bitcoin that uses client-side validation. RGB enables the issuance and transfer of assets (such as USDT) natively on Bitcoin without modifying the Bitcoin protocol. Asset state is held off-chain; only cryptographic commitments are anchored on-chain. **RGB Invoice** A payment request specific to the RGB protocol. Contains the asset ID, expected amount, and a blinded or witness UTXO reference for the recipient. Used as the destination address when bridging assets from Ethereum to the Bitcoin RGB layer. Generated via `wallet.blindReceive()` or `wallet.witnessReceive()`. **RGB Transport** The communication layer used to exchange RGB state between sender and receiver during a transfer. The Utexo SDK connects to RGB proxy endpoints (e.g. `rpcs://rgb-proxy-mainnet.utexo.com/json-rpc`) to facilitate this exchange. ## S **Single-Use Seal** A core RGB primitive. A single-use seal binds an asset state transition to a specific Bitcoin UTXO, ensuring it can only be "opened" (spent) once. This prevents double-spending without requiring global ledger consensus. ## T **TEE (Trusted Execution Environment)** A hardware-isolated compute environment that provides confidentiality and integrity guarantees for the code and data running inside it. The Utexo Mint uses an AWS Nitro Enclave as its TEE. Code running in the enclave cannot be inspected or tampered with from the host operating system. See also: *Enclave Signer*. **TUSDT** The RGB-layer representation of USDT received when bridging from Ethereum or Tron to Bitcoin via the Utexo Mint. TUSDT is a native RGB asset held in IRIS Wallet and can be transferred or exchanged against BTC with on-chain settlement guarantees. The "T" prefix denotes the token's origin as a Tether-backed minted asset on the RGB layer. ## U **UDA (Unique Digital Asset)** An RGB asset type for non-fungible tokens (NFTs) on Bitcoin. Each UDA has a unique token ID and represents a one-of-a-kind digital item. UDAs are issued and transferred using the RGB protocol with client-side validation. **USDT (RGB)** Tether's USDT stablecoin issued natively on Bitcoin using the RGB protocol. Distinct from ERC-20 USDT (Ethereum) and TRC-20 USDT (Tron). RGB USDT is transferred over Lightning channels and validated client-side. **UTEXOWallet** The primary class exported by the `@utexo/rgb-sdk-rn` and `@utexo/rgb-sdk-web` packages. It encapsulates wallet operations including initialization, asset transfers, Lightning invoice creation and payment, balance checking, and backup/restore. Node.js integrations use `@utexo/wdk-rgb-lightning` (`WalletManagerRgbLightning`) instead of `UTEXOWallet`. **UTXO (Unspent Transaction Output)** A unit of Bitcoin that has been received but not yet spent. In RGB, UTXOs serve as anchors for asset state — each RGB asset allocation is bound to a specific UTXO. ## V **VSS (Verifiable Secret Sharing)** A cloud-based backup mechanism used by the Utexo SDK to store encrypted wallet recovery data. Enables wallet restoration without requiring the user to manually store the mnemonic locally. Used via `wallet.restoreUtxoWalletFromVss()`. ## W **Witness Invoice** An alternative to a blinded invoice for receiving RGB assets. Uses a witness UTXO reference rather than a blinded one. Less privacy-preserving than a blinded invoice but may be required in certain integration scenarios. Generated via `wallet.witnessReceive()`. # Product Suite Source: https://docs.utexo.com/getting-started/product-suite The Utexo product suite is a composable set of stablecoin-native primitives for execution, settlement, liquidity access, and asset movement on Bitcoin. The Utexo product suite packages execution, settlement, liquidity access, and asset exchange into a unified stack for stablecoin payments on Bitcoin. Each component addresses a distinct layer of the payment infrastructure and can be used independently or together through a single API integration. By grouping these components under a common execution model, Utexo reduces the need for custom orchestration between settlement, exchange, and routing layers, allowing operators to deliver consistent and predictable payment experiences without managing the underlying Bitcoin, Lightning, or RGB infrastructure directly. REST API and client library for native USDT transfers and RGB asset operations on Bitcoin. Managed infrastructure for running RGB-enabled Lightning nodes without self-hosting. Cross-chain USDT transfers from EVM and Non-EVM networks to native Bitcoin RGB USDT. Non-custodial BTC ↔ USDT swaps with instant finality and LP functionality. ## SDK The Utexo SDK and REST API allows applications to support native USDT transfers and other RGB assets on Bitcoin without operating Bitcoin nodes, managing Lightning liquidity, or maintaining RGB state infrastructure. The SDK provides programmatic access to: * **RGB asset operations** — privacy-preserving asset issuance, transfers, and state transitions * **Lightning execution** — routing, payment lifecycle, and failure recovery * **Balance and audit** — balance tracking, transaction status, and transfer history The SDK enables non-custodial, client-side validated flows without requiring developers to operate Lightning nodes or manage RGB infrastructure directly. All API calls execute with predefined costs and latency characteristics. See the [SDK reference](/product-suite/sdk) for installation, method reference, and integration examples. ## Cloud Utexo Cloud Modules provide managed execution infrastructure for operators who need RGB-enabled Lightning node capabilities without running self-hosted infrastructure. It acts as a control plane for running and managing RGB-enabled Lightning nodes. Capabilities include: * **Node lifecycle management** — provisioning, upgrades, and teardown * **Health and status monitoring** — real-time node diagnostics * **Managed backup and recovery** — encrypted state backups with point-in-time restore * **VSS integration** — Verifiable Secret Sharing for non-custodial cloud key management See the [Cloud documentation](/product-suite/cloud) for setup and configuration. ## Mint The Utexo Mint acts as the liquidity gateway for native USDT on Bitcoin. It enables cross-chain stablecoin transfers from external EVM-based and Non-EVM networks to the RGB protocol on Bitcoin. USDT minted to Bitcoin is represented as native RGB USDT — the same asset used across all Utexo payment flows. No wrapped or synthetic representations are introduced. Key properties: * **Cross-chain transfers** — no custodian or intermediary holds funds during the mint process * **EVM and Non-EVM support** — compatible with the networks where most USDT supply exists today * **Native RGB output** — minted assets are immediately usable in Utexo payment and swap flows See the [Mint documentation](/product-suite/mint-getting-started) for supported networks and integration steps. ## Swap The Utexo Swap DEX provides non-custodial BTC ↔ USDT exchange on Bitcoin with instant finality. It enables operators and users to rebalance between BTC and stablecoin positions without leaving the RGB/Lightning stack. Key properties: * **Native BTC ↔ USDT swaps** — settled directly on the RGB protocol with Lightning execution * **Privacy-preserving** — swap activity uses the same client-side validation model as standard RGB transfers * **LP functionality** — liquidity providers can supply RGB-native assets and earn fees * **Instant finality** — trades settle without waiting for on-chain confirmations See the [Swap documentation](/product-suite/swap) for trading and liquidity provider guides. ## Further Reading * [Architecture](/getting-started/architecture) — How Bitcoin, Lightning, and RGB work together as the underlying stack. * [What is Utexo?](/what-utexo-is) — The four core design principles of the Utexo framework. * [Quickstart](/getting-started/quickstart) — Integrate Utexo and process your first stablecoin payment. # Node.js Quickstart Source: https://docs.utexo.com/getting-started/quickstart/node-js Initialize a server wallet and prepare an RGB transfer using @utexo/rgb-sdk. This guide covers Node.js server applications. For mobile, see the [React Native guide](/getting-started/quickstart/react-native). For browser applications, see the [Web guide](/getting-started/quickstart/web). The [`@utexo/rgb-sdk` source repository](https://github.com/UTEXO-Protocol/rgb-sdk) was archived on July 28, 2026 and is read-only. This guide documents the last committed package version, `1.0.0-beta.9`. **New Node.js integrations should use [`@utexo/wdk-rgb-lightning`](/sdk/wdk-rgb-lightning)** instead of this package. ## Prerequisites * Node.js 20, the version used by the package's publish and end-to-end workflows * Bitcoin test funds for transaction fees * A separately initialized sender wallet that already holds the RGB asset for an end-to-end transfer * Secure server-side storage for the mnemonic and wallet data This guide uses the Node.js package's `testnet` profile. Never use mainnet keys or real funds while following this guide. ## Step 1: Install the SDK ```bash theme={null} npm install @utexo/rgb-sdk ``` The package is designed for Node.js and uses filesystem and native cryptographic dependencies. It is not browser-compatible. ## Step 2: Generate Wallet Keys ```javascript theme={null} const { generateKeys } = require('@utexo/rgb-sdk'); const keys = await generateKeys('testnet'); ``` Store the mnemonic securely. Do not log it in production or commit it to source control. ## Step 3: Initialize the Wallet The archived `1.0.0-beta.9` Node.js package retains its legacy constructor and lifecycle: ```javascript theme={null} const { UTEXOWallet } = require('@utexo/rgb-sdk'); const wallet = new UTEXOWallet(keys.mnemonic, { network: 'testnet', dataDir: './wallet-data', }); await wallet.initialize(); ``` Do not copy the Web or React Native `init()` and `unlock()` lifecycle into this guide. The archived Node.js source did not migrate to that runtime surface. Use a persistent, access-controlled data directory. A mnemonic is necessary for key recovery, but it does not replace a backup of all wallet state required by RGB. ## Step 4: Fund the Wallet ```javascript theme={null} const address = await wallet.getAddress(); console.log('Deposit address:', address); ``` Send testnet BTC to this address and wait for the required confirmation before creating RGB UTXOs. ## Step 5: Create RGB UTXOs ```javascript theme={null} await wallet.createUtxos({ num: 5, size: 1000 }); await wallet.refreshWallet(); ``` `size` is denominated in satoshis. ## Step 6: Resolve the Asset From the Sender `listAssets()` returns an object grouped by asset schema. NIA assets are in the `nia` array and use the `assetId` field. ```javascript theme={null} const { nia } = await senderWallet.listAssets(); const usdt = nia.find((asset) => asset.ticker === 'USDT'); if (!usdt) { throw new Error('The sender wallet does not hold the requested NIA asset'); } const usdtAssetId = usdt.assetId; const amount = 10 ** usdt.precision; // one displayed unit in base units ``` A new receiver wallet will not list an asset it has never received. Resolve the ID and precision from the funded sender or an authoritative asset registry. The previous `assets.find(...).id` example used the wrong response shape and field name. ## Step 7: Create a Receive Invoice Run this on the receiver wallet initialized above: ```javascript theme={null} const receiveData = await wallet.blindReceive({ assetId: usdtAssetId, amount, minConfirmations: 1, durationSeconds: 3600, }); console.log('RGB invoice:', receiveData.invoice); ``` The `amount` is an integer in asset base units. One displayed unit equals `10 ** precision` base units; it is not always equal to `1`. ## Step 8: Send From the Funded Wallet The archived Node.js package's `1.0.0-beta.9` API uses the legacy `send()` method. ```javascript theme={null} const sendResult = await senderWallet.send({ invoice: receiveData.invoice, assetId: usdtAssetId, amount, donation: false, feeRate: 7, minConfirmations: 1, }); console.log('Transfer transaction:', sendResult.txid); ``` The sender wallet must be a separately initialized `UTEXOWallet` with sufficient testnet BTC and a spendable asset balance. ## Step 9: Refresh and Verify ```javascript theme={null} await senderWallet.refreshWallet(); await wallet.refreshWallet(); const receiverAssets = await wallet.listAssets(); const receivedAsset = receiverAssets.nia.find( (asset) => asset.assetId === usdtAssetId ); console.log('Receiver asset balance:', receivedAsset?.balance); ``` A transfer can remain pending while its consignment is delivered and its Bitcoin anchor reaches the required confirmation state. ## Lightning Payments The archived `1.0.0-beta.9` Node.js package pins `@utexo/rgb-sdk-core` `1.0.0-beta.3`; the current Web and React Native packages pin `1.0.0-beta.5`. Its Lightning request and status types therefore differ from the current cross-platform conformance interface. Do not copy the Web or React Native `getLightningSendStatus()` example into a Node.js integration without first checking the installed package's type declarations. Lightning also requires configured peer and channel state; wallet initialization alone does not make a payment route available. This Quickstart does not include a Lightning code sample because the archived Node.js package does not implement the current conformance contract. Check the installed package's type declarations before building a version-pinned integration. ## Troubleshooting | Issue | Likely cause | Check | | ----------------------- | ---------------------------------------------- | -------------------------------------------------------------------- | | `initialize()` fails | Data directory or endpoint problem | Confirm the directory is writable and network services are reachable | | `createUtxos()` fails | Insufficient confirmed BTC | Fund the wallet and wait for confirmation | | Asset cannot be found | Wrong response shape or unfunded sender | Read `listAssets().nia` and use `assetId` | | `send()` fails | Invoice, amount, balance, or transport problem | Confirm the invoice is unexpired and the amount is in base units | | Balance does not update | Transfer is pending or wallet is stale | Refresh both wallets and check transfer status | ## Implementation References * [Node.js wallet implementation](https://github.com/UTEXO-Protocol/rgb-sdk/blob/dev/src/utexo/utexo-wallet.ts) * [Node.js package manifest](https://github.com/UTEXO-Protocol/rgb-sdk/blob/dev/package.json) * [Node.js package's pinned core wallet models](https://github.com/UTEXO-Protocol/rgb-sdk-core/blob/v1.0.0-beta.3/src/types/wallet-model.ts) * [Current shared conformance contract](https://github.com/UTEXO-Protocol/rgb-sdk-core/blob/dev/src/conformance/index.ts) ## Next Steps * [SDK Reference](/product-suite/sdk) * [Architecture](/getting-started/architecture) * [Glossary](/getting-started/glossary) # Quickstart Overview Source: https://docs.utexo.com/getting-started/quickstart/overview Choose the Utexo SDK package and lifecycle for your application runtime. The Utexo SDK has current Web, React Native, and WDK (Node.js / Bare) packages. `@utexo/rgb-sdk` is archived. Choose the guide for your runtime before copying any initialization or payment code. New server-side applications using `@utexo/wdk-rgb-lightning`. iOS and Android applications using `@utexo/rgb-sdk-rn`. Browser applications using `@utexo/rgb-sdk-web`. The [`@utexo/rgb-sdk` source repository](https://github.com/UTEXO-Protocol/rgb-sdk) was archived on July 28, 2026 and is read-only; its last committed package version is `1.0.0-beta.9`. **New Node.js integrations should use [`@utexo/wdk-rgb-lightning`](/sdk/wdk-rgb-lightning).** The remaining packages share models from `@utexo/rgb-sdk-core`, but they do not expose an identical runtime API. Use the platform-specific guide and check the installed package version before copying code. ## Platform API Differences | Package | Wallet startup | On-chain RGB send | | ------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------- | | `@utexo/wdk-rgb-lightning` (Node.js / Bare) | `WalletManagerRgbLightning` + `getAccount(0)` + `unlock()` | `sendRgbAsset()` / `transfer()` | | `@utexo/rgb-sdk` (legacy; source archived) | Construct with a mnemonic and call `initialize()` | `send()` | | `@utexo/rgb-sdk-rn` | Construct with node parameters and a signer, then call `init()` and `unlock()` | `onchainSend()` | | `@utexo/rgb-sdk-web` | Construct with one parameter object, then call `init()` and `unlock()` | `onchainSend()` | The Web and React Native packages implement a shared `UTEXOWallet` conformance contract. `@utexo/wdk-rgb-lightning` uses WDK manager/account types — do not copy `UTEXOWallet` method names into WDK code. The archived Node.js package uses its legacy wallet core; do not substitute `onchainSend()` for `send()` in that package. ## How RGB Transfers Work 1. The receiver generates a blinded or witness RGB invoice. 2. The sender submits the invoice with the platform's on-chain send method. 3. Both wallets refresh their state while the transfer moves through the RGB and Bitcoin confirmation flow. 4. The receiver verifies the asset balance after settlement. All RGB state is validated client-side. The Bitcoin UTXO anchors the state transition; the transport service delivers consignments but does not replace client-side validation. New to RGB or UTXOs? See the [Glossary](/getting-started/glossary) and [Architecture](/getting-started/architecture). ## Asset IDs and Amounts `listAssets()` returns assets grouped by schema. NIA assets are in `listAssets().nia`, and the identifier field is `assetId`. `amount` values are integer base units. One displayed unit equals `10 ** precision` base units; it is not always equal to `1`. ```typescript theme={null} const { nia } = await senderWallet.listAssets(); const asset = nia.find((item) => item.ticker === 'USDT'); if (!asset) { throw new Error('The sender wallet does not hold the requested NIA asset'); } const assetId = asset.assetId; const oneDisplayUnit = 10 ** asset.precision; ``` A newly created receiver wallet will not discover an asset it has never received. Obtain the asset ID and precision from the funded sender wallet or another authoritative asset registry. The documentation does not publish a hard-coded test asset ID because no canonical ID is committed in the SDK repositories. ## Lightning Payments The Web and React Native packages use `createLightningInvoice()`, `payLightningInvoice()`, and `getLightningSendStatus()`. `@utexo/wdk-rgb-lightning` uses `createInvoice()` / `createLightningInvoice()` and `sendPayment()`. Omit the `asset` field when creating a BTC-only invoice on the application SDKs. Lightning payments also require usable peer and channel state. Wallet initialization alone does not create a channel or fund the node. ## Network Selection The hosted Web and React Native examples use the `utexo` network profile, which resolves to Utexo's signet infrastructure. `@utexo/wdk-rgb-lightning` takes `network` plus explicit indexer/proxy (or bitcoind RPC) at `unlock()`. The archived Node.js package uses its package-specific `testnet` profile. Do not reuse a constructor or endpoint configuration across packages without checking the platform implementation. Never use mainnet keys or real funds while following a Quickstart. Test and signet assets have no monetary value. ## Implementation References These files are the reviewed sources for the API distinctions above: * [Shared SDK conformance contract](https://github.com/UTEXO-Protocol/rgb-sdk-core/blob/dev/src/conformance/index.ts) * [Shared wallet models](https://github.com/UTEXO-Protocol/rgb-sdk-core/blob/dev/src/types/wallet-model.ts) * [wdk-rgb-lightning](https://github.com/UTEXO-Protocol/wdk-rgb-lightning/blob/dev/README.md) * [React Native wallet implementation](https://github.com/UTEXO-Protocol/rgb-sdk-rn/blob/dev/src/wallet/utexo-wallet.ts) * [Web wallet implementation](https://github.com/UTEXO-Protocol/rgb-sdk-web/blob/dev/src/utexo/utexo-wallet.ts) ## Common Prerequisites * A separate sender and receiver wallet for an end-to-end transfer * Bitcoin test funds for transaction fees * A funded sender that already holds the RGB asset being transferred * Secure mnemonic and password storage appropriate for the runtime The platform guides cover package-specific initialization and method names. End-to-end settlement time depends on funding, channel state, transport availability, and Bitcoin confirmations. # React Native Quickstart Source: https://docs.utexo.com/getting-started/quickstart/react-native Initialize a mobile wallet and prepare an RGB transfer using @utexo/rgb-sdk-rn. This guide covers iOS and Android applications. For Node.js, see the [Node.js guide](/getting-started/quickstart/node-js). For browser applications, see the [Web guide](/getting-started/quickstart/web). ## Prerequisites * React Native with a working iOS or Android native build environment * Node.js for the development toolchain * A persistent, writable application directory * Bitcoin test funds for transaction fees * A separately initialized sender wallet that already holds the RGB asset for an end-to-end transfer This guide uses the `utexo` network profile for Utexo's hosted signet infrastructure. Never use mainnet keys or real funds while following this guide. ## Step 1: Install the SDK ```bash theme={null} npm install @utexo/rgb-sdk-rn react-native-fs ``` For iOS, install the native dependencies after adding the package: ```bash theme={null} cd ios && pod install ``` The package includes native bindings and is not interchangeable with the Node.js or Web packages. ## Step 2: Generate Wallet Keys ```javascript theme={null} import { generateKeys } from '@utexo/rgb-sdk-rn'; const keys = await generateKeys('utexo'); ``` Store the mnemonic in platform-backed secure storage. Do not log it in production or persist it in AsyncStorage. ## Step 3: Initialize and Unlock the Wallet The React Native constructor requires node parameters and a signer. Create the storage directory before initializing the wallet. ```javascript theme={null} import { PasswordRLNSigner, UTEXOWallet, } from '@utexo/rgb-sdk-rn'; import RNFS from 'react-native-fs'; const storageDirPath = `${RNFS.DocumentDirectoryPath}/utexo-wallet`; await RNFS.mkdir(storageDirPath); const password = await getPasswordFromSecureInput(); const wallet = new UTEXOWallet( { storageDirPath, daemonListeningPort: 21250, ldkPeerListeningPort: 21251, network: 'utexo', enableVirtualChannelsV0: false, }, new PasswordRLNSigner(password, keys.mnemonic) ); await wallet.init(); await wallet.unlock({}); ``` `getPasswordFromSecureInput()` represents an application-owned secure prompt. The empty unlock object allows the SDK to resolve the indexer and RGB proxy from the `utexo` network defaults. Use unused listening ports. If two wallet instances run in the same app process, give each instance different ports and a different storage directory. The older `new UTEXOWallet(mnemonic, { network, dataDir })` form does not match the current React Native implementation. The mnemonic and password belong in the signer, and startup requires both `init()` and `unlock()`. ## Step 4: Fund the Wallet ```javascript theme={null} const address = await wallet.getAddress(); console.log('Deposit address:', address); ``` Send signet BTC to the address and wait for the required confirmation before creating RGB UTXOs. ## Step 5: Create RGB UTXOs ```javascript theme={null} await wallet.createUtxos({ num: 5, size: 1000 }); await wallet.refreshWallet(); ``` `size` is denominated in satoshis. ## Step 6: Resolve the Asset From the Sender `listAssets()` returns arrays grouped by schema. NIA assets are in `nia` and use `assetId`. ```javascript theme={null} const { nia } = await senderWallet.listAssets(); const usdt = nia.find((asset) => asset.ticker === 'USDT'); if (!usdt) { throw new Error('The sender wallet does not hold the requested NIA asset'); } const usdtAssetId = usdt.assetId; const amount = 10 ** usdt.precision; // one displayed unit in base units ``` A new receiver wallet will not list an asset it has never received. Resolve the ID and precision from the funded sender or an authoritative asset registry. ## Step 7: Create a Receive Invoice Run this on the receiver wallet initialized above: ```javascript theme={null} const receiveData = await wallet.blindReceive({ assetId: usdtAssetId, amount, minConfirmations: 1, durationSeconds: 3600, }); console.log('RGB invoice:', receiveData.invoice); ``` The `amount` is an integer in asset base units. One displayed unit equals `10 ** precision` base units. ## Step 8: Send From the Funded Wallet The current React Native API uses `onchainSend()`, not `send()`. ```javascript theme={null} const sendResult = await senderWallet.onchainSend({ invoice: receiveData.invoice, assetId: usdtAssetId, amount, donation: false, feeRate: 7, minConfirmations: 1, }); console.log('Transfer transaction:', sendResult.txid); ``` The sender wallet must be a separately initialized `UTEXOWallet` with its own storage directory and ports, sufficient signet BTC, and a spendable asset balance. ## Step 9: Refresh and Verify ```javascript theme={null} await senderWallet.refreshWallet(); await wallet.refreshWallet(); const receiverAssets = await wallet.listAssets(); const receivedAsset = receiverAssets.nia.find( (asset) => asset.assetId === usdtAssetId ); console.log('Receiver asset balance:', receivedAsset?.balance); ``` A transfer can remain pending while its consignment is delivered and its Bitcoin anchor reaches the required confirmation state. ## Lightning Payments Lightning requires usable peer and channel state. Wallet initialization does not open or fund a channel. For a BTC-only invoice, omit the `asset` field. ```javascript theme={null} const invoice = await wallet.createLightningInvoice({ amountSats: 3000, expirySeconds: 900, }); const payment = await senderWallet.payLightningInvoice({ lnInvoice: invoice.lnInvoice, }); const status = await senderWallet.getLightningSendStatus(payment.txid); console.log('Lightning payment status:', status); ``` For an RGB-asset invoice, pass `asset: { assetId, amount }` when creating the invoice. Do not pass an empty asset object for BTC-only payments. ## React Native-Specific Notes * Store the wallet database in a persistent application document directory, not a cache directory. * Keep the mnemonic and password in platform-backed secure storage. * Give concurrent node instances distinct storage directories and listening ports. * Plan for application lifecycle changes. Shut down or dispose of the wallet according to the SDK lifecycle before replacing an instance. * Network access is required for indexer, RGB transport, and Lightning operations. ## Troubleshooting | Issue | Likely cause | Check | | --------------------- | ---------------------------------------------- | ------------------------------------------------------------ | | Native build fails | Missing platform dependencies | Reinstall pods or rebuild the Android native project | | `init()` fails | Storage, port, or signer problem | Confirm the directory exists and ports are unused | | `unlock()` fails | Endpoint or credential problem | Check network defaults and signer credentials | | Asset cannot be found | Wrong response shape or unfunded sender | Read `listAssets().nia` and use `assetId` | | `onchainSend()` fails | Invoice, amount, balance, or transport problem | Confirm the invoice is unexpired and amount is in base units | ## Implementation References * [React Native wallet implementation](https://github.com/UTEXO-Protocol/rgb-sdk-rn/blob/dev/src/wallet/utexo-wallet.ts) * [React Native network defaults](https://github.com/UTEXO-Protocol/rgb-sdk-rn/blob/dev/src/wallet/network-defaults.ts) * [React Native signer implementations](https://github.com/UTEXO-Protocol/rgb-sdk-rn/blob/dev/src/wallet/rln-signers.ts) * [Maintained React Native lifecycle harness](https://github.com/UTEXO-Protocol/rgb-sdk-rn-sandbox/blob/main/e2e/harness.ts) * [Shared wallet models](https://github.com/UTEXO-Protocol/rgb-sdk-core/blob/dev/src/types/wallet-model.ts) ## Next Steps * [SDK Reference](/product-suite/sdk) * [Architecture](/getting-started/architecture) * [Glossary](/getting-started/glossary) # Web Quickstart Source: https://docs.utexo.com/getting-started/quickstart/web Initialize a browser wallet and prepare an RGB transfer using @utexo/rgb-sdk-web. This guide covers browser applications. For Node.js, see the [Node.js guide](/getting-started/quickstart/node-js). For iOS and Android, see the [React Native guide](/getting-started/quickstart/react-native). ## Prerequisites * A modern browser with WebAssembly support * A bundler that supports WebAssembly, such as Vite * Bitcoin test funds for transaction fees * A separately initialized sender wallet that already holds the RGB asset for an end-to-end transfer This guide uses the `utexo` network profile for Utexo's hosted signet infrastructure. Never use mainnet keys or real funds while following this guide. ## Step 1: Install the SDK ```bash theme={null} npm install @utexo/rgb-sdk-web ``` The package targets browser environments and stores wallet state in browser storage. It is not interchangeable with `@utexo/wdk-rgb-lightning` or `@utexo/rgb-sdk-rn`. ## Step 2: Initialize the Wallet Initialize the RLN WebAssembly module once, generate keys, then create and unlock the wallet. ```javascript theme={null} import { generateKeys, initRlnWasm, UTEXOWallet, } from '@utexo/rgb-sdk-web'; await initRlnWasm(); const keys = await generateKeys('utexo'); const password = await getPasswordFromSecureInput(); const wallet = new UTEXOWallet({ mnemonic: keys.mnemonic, password, network: 'utexo', }); await wallet.init(); await wallet.unlock(); ``` `getPasswordFromSecureInput()` represents an application-owned password prompt. Do not hard-code the password, log the mnemonic, or store either value unencrypted in `localStorage`. The current Web constructor accepts one parameter object. The older `new UTEXOWallet(mnemonic, options)` form and `initialize()` lifecycle shown in previous versions of this page do not match the current implementation. ## Step 3: Fund the Wallet Get a Bitcoin address and send signet BTC to it for transaction fees. ```javascript theme={null} const address = await wallet.getAddress(); console.log('Deposit address:', address); ``` Wait for the required confirmation before creating RGB UTXOs. ## Step 4: Create RGB UTXOs ```javascript theme={null} await wallet.createUtxos({ num: 5, size: 1000 }); await wallet.refreshWallet(); ``` Both `num` and `size` are integers. `size` is denominated in satoshis. ## Step 5: Resolve the Asset From the Sender `listAssets()` returns an object grouped by asset schema. NIA assets are in the `nia` array and use the `assetId` field. ```javascript theme={null} const { nia } = await senderWallet.listAssets(); const usdt = nia.find((asset) => asset.ticker === 'USDT'); if (!usdt) { throw new Error('The sender wallet does not hold the requested NIA asset'); } const usdtAssetId = usdt.assetId; const amount = 10 ** usdt.precision; // one displayed unit in base units ``` A new receiver wallet will not list an asset it has never received. Resolve the asset ID and precision from the funded sender or an authoritative asset registry. Do not use the removed `assets.find(...).id` pattern. ## Step 6: Create a Receive Invoice Run this on the receiver wallet initialized in Step 2: ```javascript theme={null} const receiveData = await wallet.blindReceive({ assetId: usdtAssetId, amount, minConfirmations: 1, durationSeconds: 3600, }); console.log('RGB invoice:', receiveData.invoice); ``` The `amount` is an integer in asset base units. One displayed unit is `10 ** precision` base units. ## Step 7: Send From the Funded Wallet The current Web API uses `onchainSend()`, not `send()`. ```javascript theme={null} const sendResult = await senderWallet.onchainSend({ invoice: receiveData.invoice, assetId: usdtAssetId, amount, donation: false, feeRate: 7, minConfirmations: 1, }); console.log('Transfer transaction:', sendResult.txid); ``` The sender wallet must be a separately initialized `UTEXOWallet` with sufficient signet BTC and a spendable balance of the asset. ## Step 8: Refresh and Verify ```javascript theme={null} await senderWallet.refreshWallet(); await wallet.refreshWallet(); const receiverAssets = await wallet.listAssets(); const receivedAsset = receiverAssets.nia.find( (asset) => asset.assetId === usdtAssetId ); console.log('Receiver asset balance:', receivedAsset?.balance); ``` A transfer can remain pending while its consignment is delivered and its Bitcoin anchor reaches the required confirmation state. Refresh both wallets before treating a missing settled balance as a failure. ## Lightning Payments Lightning requires usable peer and channel state in addition to an initialized wallet. For a BTC-only invoice, omit the `asset` field. ```javascript theme={null} const invoice = await wallet.createLightningInvoice({ amountSats: 3000, expirySeconds: 900, }); const payment = await senderWallet.payLightningInvoice({ lnInvoice: invoice.lnInvoice, }); const status = await senderWallet.getLightningSendStatus(payment.txid); console.log('Lightning payment status:', status); ``` For an RGB-asset Lightning invoice, pass `asset: { assetId, amount }` when creating the invoice. Do not pass an empty asset object for a BTC-only invoice. ## Web-Specific Notes * Call `initRlnWasm()` before constructing a wallet. * Persist wallet state and secrets according to the SDK's backup guidance. Clearing site data can remove local wallet state. * Use HTTPS in production so browser storage and secure-context APIs are available. * Endpoint defaults are resolved by the `utexo` network profile. Override them only when operating compatible infrastructure. ## Troubleshooting | Issue | Likely cause | Check | | ---------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------- | | WebAssembly fails to load | Bundler or MIME configuration | Verify the generated `.wasm` asset is served and allowed by CSP | | `init()` or `unlock()` fails | Endpoint, password, or stored-state problem | Check the browser console and network requests without exposing secrets | | `createUtxos()` fails | Insufficient confirmed BTC | Fund the wallet and wait for confirmation | | Asset cannot be found | Wrong response shape or unfunded sender | Read `listAssets().nia` and use `assetId` | | `onchainSend()` fails | Invoice, amount, balance, or transport problem | Confirm the invoice is unexpired and the amount is in base units | ## Implementation References * [Web wallet implementation](https://github.com/UTEXO-Protocol/rgb-sdk-web/blob/dev/src/utexo/utexo-wallet.ts) * [Web network defaults](https://github.com/UTEXO-Protocol/rgb-sdk-web/blob/dev/src/binding/RlnDefaults.ts) * [Shared wallet models](https://github.com/UTEXO-Protocol/rgb-sdk-core/blob/dev/src/types/wallet-model.ts) * [Shared on-chain transfer interface](https://github.com/UTEXO-Protocol/rgb-sdk-core/blob/dev/src/interfaces/wallet/IOnchainTransfers.ts) ## Next Steps * [SDK Reference](/product-suite/sdk) * [Architecture](/getting-started/architecture) * [Glossary](/getting-started/glossary) # The Problem Source: https://docs.utexo.com/getting-started/the-problem Why existing stablecoin payment infrastructure fails for business settlement, and what properties Bitcoin uniquely provides to solve it. Stablecoins are already used at global scale for payments, treasury operations, remittances, and internal settlement. USDT has become the dominant settlement asset across both crypto-native and cross-border payment flows. But the infrastructure carrying those stablecoins was not designed for business-grade settlement. It introduces three structural failure modes that make it operationally unsuitable for payment providers, exchanges, and financial operators. ## Unpredictable Execution Costs Most stablecoin activity today runs on public blockchains with dynamic fee markets. Transaction costs are determined by congestion and blockspace demand, making execution costs unpredictable by design. Fees change continuously and cannot be fixed in advance. During periods of high usage, costs can increase by orders of magnitude. For payment providers, this breaks the basic requirements of a payment rail: * No fixed unit economics * No deterministic pricing model * No ability to offer flat fees to merchants or users Blockchain networks with variable fee markets are structurally unsuitable as primary settlement infrastructure for payment businesses. Unit economics cannot be modelled or guaranteed. ## No Settlement Privacy All major stablecoin networks operate on transparent public ledgers. Every transaction exposes balances, counterparties, and payment flows to any observer. For businesses, this means: * Supplier relationships, customer volumes, treasury movements, and internal settlement activity are publicly visible * Payroll, B2B payments, PSP settlement, and enterprise treasury operations leak commercially sensitive data * Competitive intelligence can be extracted directly from on-chain activity This level of transparency is incompatible with the operational requirements of financial operators handling confidential business flows. ## Forced Dependency on Alternative Chains Bitcoin offers properties that payment operators already value: deterministic finality, strong censorship resistance, regulatory clarity, and the deepest global liquidity base of any blockchain network. But there is currently no way to use USDT natively on Bitcoin in a form that is suitable for production payment systems. The required properties, predictable execution costs, private settlement, and enterprise-grade security, are absent. Stablecoin settlement is therefore forced onto alternative chains or custodial platforms, introducing: * Additional trust assumptions * Counterparty risk * External execution dependencies * Loss of Bitcoin’s security guarantees ## What Utexo Solves Utexo exists to make stablecoin settlement costs predictable and private, independent of blockspace congestion, while preserving Bitcoin’s security model. It brings USDT settlement natively to Bitcoin without requiring alternative chains, custodians, or smart contract platforms. The three failure modes above are addressed directly by the Utexo architecture: | Failure Mode | Utexo Response | | ---------------------------- | --------------------------------------------------- | | Unpredictable fees | Fixed, protocol-level fee schedule | | Public execution | Off-chain settlement with cryptographic privacy | | Alternative chain dependency | Bitcoin + RGB + Lightning — no external L1 required | ## Further Reading * [Architecture](/getting-started/architecture) - How Bitcoin, the Lightning Network, RGB, and Utexo address these failure modes at the protocol level. * [What is Utexo?](/what-utexo-is) - The Utexo framework and its four core design principles. * [Quickstart](/getting-started/quickstart) - Integrate Utexo and process your first stablecoin payment. # Getting Started Source: https://docs.utexo.com/mint/getting-started Transfer USDT between Ethereum and the Bitcoin RGB layer using the Utexo Mint. This guide is a **UI walkthrough** for using the Utexo Mint interface. If you want to initiate a mint programmatically using the SDK or REST API, see the [Mint API Reference](/product-suite/mint-api-reference) instead. This guide walks you through both directions of a mint transfer: depositing USDT from an EVM wallet onto the Bitcoin RGB layer and withdrawing it back. USDT from EVM, Tron, and Solana is supported — under the hood, it is routed through the USDT0 / LayerZero protocol to Arbitrum before being locked and minted as RGB USDT on Bitcoin. This routing is handled transparently; from your wallet, the experience is the same regardless of which network you connect from. For now, the only tested and available route is Arbitrum (mainnet) to Bitcoin (Utexo signet). Bitcoin mainnet is not available yet. Signing authority is distributed across three independent Federated Signer Nodes, each running inside an AWS Nitro Enclave, using a threshold scheme — no single node can produce a valid signature unilaterally. ## Prerequisites Before initiating a transfer, ensure you have the following ready. **EVM wallet (browser extension)** * ETH balance to cover Arbitrum gas fees. * USDT balance for the amount you want to mint. **Utexo SDK** powered Wallets * BTC balance to cover the RGB transaction fee on the Bitcoin side. * Your Utexo Wallet connected to the Mint. You can connect it in two ways: * Click **CONNECT RGB WALLET** at the bottom of the Mint form. * Open the wallet list in the top-right corner of the mint page and click the power button next to **RGBWallet**. *** ## Ethereum → Bitcoin (RGB) This direction moves USDT from your EVM wallet to the Bitcoin RGB layer, where you receive an equivalent RGB USDT token. ### Step 1 — Enter the transfer details On [transfer.stage.utexo.com](https://transfer.stage.utexo.com), set: * **Send:** Blockchain – Ethereum (or Tron / Solana), Token – USDT. * **Receive:** Blockchain – Bitcoin (RGB), Token – USDT. In the **Amount** field, enter the number of USDT tokens to transfer. In the **Destination** field, paste an RGB invoice generated in Utexo SDK Wallet: 1. Open Utexo SDK Wallet and ensure your BTC balance can cover the network fee. 2. Select **Receive assets**. 3. Generate an invoice for the USDT asset and copy it. 4. Paste the invoice into the **Destination** field on the Mint protocol. ### Step 2 — Review and confirm After filling in the form, a **Transaction Preview** appears with: * **You will receive** — estimated USDT amount after fees. * **Estimated gas fee** — live Arbitrum network gas cost. * **Mint commission** — fixed percentage fee charged by Utexo. Click **Transfer**. EVM wallet will prompt you through two confirmation steps: 1. **Approve token spending** — Authorises the Mint contract to spend your USDT. Click **Confirm**. 2. **Confirm the transaction** — Wait 2–10 seconds for the second MetaMask prompt. Review the details and click **Confirm** to submit. ### Step 3 — Wait for USDT to arrive Open Utexo SDK Wallet and monitor your USDT balance. Settlement time depends on Bitcoin network congestion. During periods of high congestion, confirmation may take longer than usual. In Utexo SDK Wallets, a completed Ethereum → Bitcoin transfer is highlighted in **green** (asset credit). *** ## Bitcoin (RGB) → Ethereum This direction burns USDT on the Bitcoin RGB layer and releases the equivalent USDT on Ethereum. ### Step 1 — Enter the transfer details On [transfer.stage.utexo.com](https://transfer.stage.utexo.com), set: * **Send:** Blockchain – Bitcoin (RGB), Token – USDT. * **Receive:** Blockchain – Ethereum (or Tron / Solana), Token – USDT. In the **Amount** field, enter the amount of USDT you want to withdraw. In the **Destination address** field, enter your EVM wallet address (for example, from MetaMask). Review the **Transaction Preview**: * **You will receive** — estimated USDT amount after fees. * **Estimated gas fee** and **Commission**. Click **Transfer**. ### Step 2 — Pay the RGB invoice The Mint generates an RGB invoice displayed as a popup with a QR code. Open Utexo SDK Wallet: 1. Navigate to your **USDT** token. 2. Tap **Send**. 3. Tap the **QR scanner** icon and scan the QR code from the Mint popup. 4. Review the transfer details and tap **Send** to confirm. ### Step 3 — Monitor the transaction status After sending, the transaction appears in Utexo SDK Wallet with the status **WAITING\_COUNTERPARTY**. Refresh your wallet (tap the refresh icon). Once the Bitcoin network picks up the transaction, the status changes to **WAITING\_CONFIRMATIONS**. When confirmations are complete, the USDT is released to your EVM address. In Utexo SDK Wallet, a completed Bitcoin → Ethereum transfer is highlighted in **red** (asset deduction from the RGB layer). *** ## Fees | Fee type | Description | | -------------------- | ------------------------------------------------------------------------------------------------------------------ | | **Arbitrum gas fee** | Variable; priced at live market rates at the time of signing. | | **Mint commission** | Fixed percentage of the transferred amount, charged by Utexo. Shown in the Transaction Preview before you confirm. | | **Bitcoin RGB fee** | Small BTC amount deducted from your Utexo SDK Wallet to settle the RGB transaction on-chain. | **Utexo SDK** powered Wallets * BTC balance to cover the RGB transaction fee on the Bitcoin side. * Your Utexo SDK Wallet connected to the Mint. You can connect it in two ways: * Click **CONNECT RGB WALLET** at the bottom of the mint form. * Open the wallet list in the top-right corner of the Mint page and click the power button next to **RGBWallet**. This direction moves USDT from your EVM wallet to the Bitcoin RGB layer, where you receive an equivalent RGB USDT token. 1. Open Utexo SDK Wallet and ensure your BTC balance can cover the network fee. 2. Select **Receive assets**. 3. Generate an invoice for the USDT asset and copy it. 4. Paste the invoice into the **Destination** field on the Mint. * **You will receive** — estimated USDT amount after fees. * **Estimated gas fee** — live Arbitrum network gas cost. * **Mint commission** — fixed percentage fee charged by Utexo. 1. **Approve token spending** — Authorises the Mint contract to spend your USDT. Click **Confirm**. 2. **Confirm the transaction** — Wait 2–10 seconds for the second MetaMask prompt. Review the details and click **Confirm** to submit. In Utexo SDK Wallet, a completed Ethereum → Bitcoin transfer is highlighted in **green** (asset credit). This direction burns USDT on the Bitcoin RGB layer and releases the equivalent USDT on Ethereum. The Mint generates an RGB invoice displayed as a popup with a QR code. Open Utexo SDK Wallet: 1. Navigate to your **USDT** token. 2. Tap **Send**. 3. Tap the **QR scanner** icon and scan the QR code from the Mint popup. 4. Review the transfer details and tap **Send** to confirm. After sending, the transaction appears in Utexo SDK Wallet with the status **WAITING\_COUNTERPARTY**. Refresh your wallet (tap the refresh icon). Once the Bitcoin network picks up the transaction, the status changes to **WAITING\_CONFIRMATIONS**. When confirmations are complete, the USDT is released to your EVM address. In Utexo SDK Wallet, a completed Bitcoin → Ethereum transfer is highlighted in **red** (asset deduction from the RGB layer). | Fee type | Description | | -------------------- | ------------------------------------------------------------------------------------------------------------------ | | **Arbitrum gas fee** | Variable; priced at live market rates at the time of signing. | | **Mint commission** | Fixed percentage of the transferred amount, charged by Utexo. Shown in the Transaction Preview before you confirm. | | **Bitcoin RGB fee** | Small BTC amount deducted from your Utexo SDK Wallet to settle the RGB transaction on-chain. | # Node Overview Source: https://docs.utexo.com/overview Understand how one RGB Lightning Node supports on-chain RGB and Lightning, and choose between self-hosted and Utexo Cloud deployments. Running an **RGB Lightning Node (RLN)** enables both direct, on-chain RGB operations and RGB-enabled Lightning payments through one node runtime and REST API. You do not need a separate on-chain node integration. Utexo supports **on-chain RGB on mainnet** today. **Lightning is beta and testnet-only** for now. On testnet, you can test both paths; on mainnet, use RLN for on-chain RGB operations only. Canonical source repository: [UTEXO-Protocol/rgb-lightning-node](https://github.com/UTEXO-Protocol/rgb-lightning-node) ## Supported execution paths | Path | What RLN provides | Current Utexo support | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------ | | **On-chain RGB** | Asset issuance, RGB invoices, direct RGB transfers, balances, transactions, transfer tracking, and RGB-capable UTXO management | **Mainnet**; also available in test environments | | **RGB over Lightning** | Peer and channel management, Lightning and RGB invoices, and Lightning payment execution and routing | **Testnet only**; beta | The node's `--network` option selects its Bitcoin network. This technical option does not change the supported deployment matrix above. ## Core runtime RLN is an RGB-enabled Lightning daemon built on LDK. Its REST API combines: * **On-chain RGB operations**, including asset issuance, invoices, direct transfers, balances, transactions, UTXOs, and backups. * **Lightning operations**, including peer connections, RGB channels, invoices, payments, and routing. * **Node lifecycle and security operations**, including initialization, locking, authentication, backup, restore, and shutdown. Applications use the relevant endpoints for the selected execution path. On mainnet, restrict the integration to the on-chain RGB endpoints. On testnet, the same integration can exercise both on-chain and Lightning flows. ## Deployment models RLN can be self-hosted or operated through Utexo Cloud. Utexo Cloud is a managed control plane for RLN instances, not a separate node implementation. | Model | Infrastructure responsibility | Use when | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | | **Self-hosted RLN** | Your team installs, configures, secures, monitors, upgrades, backs up, and recovers the node and its dependencies | You need direct infrastructure control and can operate the complete node stack | | **Utexo Cloud** | Utexo provides RLN provisioning and lifecycle management; your application connects to the managed node and control-plane APIs | You want managed node operations without maintaining the underlying servers | ## Architecture and data flow ```text theme={null} Application | +-- RGB Lightning Node API --------> RGB Lightning Node | | | +-- Bitcoin chain backend | +-- RGB indexer | +-- RGB proxy / transport | +-- Lightning peers (testnet only) | +-- Cloud API ----------------------> Utexo Cloud control plane | +-- Provisions and manages RLN instances ``` The **RGB Lightning Node API** performs on-chain RGB and Lightning operations on a running node. The **Cloud API** manages hosted RLN lifecycle operations; it does not replace the runtime API. ## Choosing an integration model Most wallet and client applications should integrate through the [Utexo SDK](/product-suite/sdk) instead of operating node infrastructure directly. Choose **self-hosted RLN** when your team needs direct control over runtime configuration, network exposure, authentication, storage, upgrades, and recovery. Choose **Utexo Cloud** when you want Utexo to provide node provisioning and lifecycle management while your application integrates with the RLN runtime and Cloud APIs. In either model, the RLN integration covers both on-chain and Lightning functionality. Do not build a second integration for on-chain RGB. ## Signing and trust boundaries * **RLN** maintains security-sensitive wallet and Lightning state and performs signing operations. Remote external-signer support is experimental and must be validated for each deployment. * **Self-hosted operators** are responsible for API authentication, TLS or private networking, data protection, backups, dependency security, and incident recovery. * **Utexo Cloud** adds a separate control-plane trust boundary. Cloud API tokens and RLN runtime credentials serve different purposes and must be managed independently. ## External dependencies A self-hosted RLN deployment requires: * A Bitcoin chain backend: bitcoind or Esplora * An Electrum or Esplora indexer for RGB wallet operations * An RGB proxy or transport endpoint for consignment exchange * Persistent storage for wallet and channel state * Network access to Lightning peers when testing Lightning functionality Utexo Cloud may manage some of these infrastructure concerns, but it does not change the underlying node protocol model or the supported mainnet/testnet split. ## Next steps * Read [Self-Hosted RGB Lightning Node](/rgb-lightning-node/self-hosted-rgb-lightning-node) to install and operate RLN on your own infrastructure. * Use the [RGB Lightning Node API](/rgb-lightning-node/rgb-lightning-node-api) for the runtime REST endpoints. * Review [Remote Signer](/security/rln-remote-signer) before evaluating an external signing architecture. * Use **Utexo Cloud → Node Management** and **Access Token Authorization** for managed RLN lifecycle operations. # Utexo Cloud Overview Source: https://docs.utexo.com/product-suite/RLN-overview Managed infrastructure for running RGB Lightning Nodes in production environments. Utexo Cloud provides a managed control plane for deploying and operating RGB Lightning Nodes (RLNs). It is designed for applications that require direct control over node-level infrastructure, channel management, asset issuance, backups, and observability, without building or maintaining that infrastructure themselves. Cloud is optional and complementary to the SDK. Applications can combine Cloud-managed nodes with the Utexo SDK depending on their deployment model and trust requirements. ## What Utexo Cloud Provides | Capability | Description | | ---------------------------- | --------------------------------------------------------------------------------- | | Node lifecycle management | Create, start, stop, upgrade, and destroy RLN nodes via dashboard or API | | Health and status monitoring | Real-time node status (`RUNNING`, `PAUSED`, `FAILED`) and build progress tracking | | Controlled access | mTLS and API-token–based authentication for secure remote connections | | Versioned deployments | Upgrade nodes to the latest RLN image with a single operation | | Backup and restore | Snapshot node state and restore from backup at any time | | Webhook events | Receive real-time notifications when node state transitions occur | ## When to Use Cloud Use Utexo Cloud to provision and operate RGB Lightning Nodes directly from the dashboard. The node lifecycle — creation, upgrade, backup, teardown — is managed via a control plane API, not raw server access. Once a node is running, it exposes a REST JSON API for all Lightning and RGB operations: channel management, asset issuance, payments, and more. See [RGB Lightning Node API](/rgb-lightning-node/rgb-lightning-node-api). Configure webhooks on your node to receive `POST` callbacks whenever node status transitions occur (`RUNNING`, `FAILED`, `IN_PROGRESS`). See [Webhooks](/cloud/webhooks). ## Get Started Create, connect, upgrade, back up, and destroy RLN nodes. Full REST endpoint reference for your running node. Receive real-time event notifications from your nodes. Access the Utexo Cloud dashboard. # Mint Source: https://docs.utexo.com/product-suite/mint Cross-chain stablecoin transfers between supported EVM networks, Tron and the Bitcoin RGB layer. Mint Transfer Flow Supported Sources To Bitcoin Drawio The Utexo Mint is a cross-chain minting service that moves USDT between supported source networks and the Bitcoin RGB layer. It is built around Arbitrum as the single EVM settlement hub, integrating with the USDT0 / LayerZero protocol so that USDT arriving from supported EVM networks or Tron is transparently converted to USDT0 on Arbitrum before being locked and minted as USDT on Bitcoin. Minted USDT is represented as USDT on Bitcoin — a real on-chain asset that can be transferred or exchanged against BTC with on-chain settlement guarantees, without relying on centralised exchanges or custodial intermediaries. ## How It Works The Mint is composed of modular, stateless components that together coordinate a fully cross-chain transfer: | Component | Role | | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Mint orchestrator** | Tracks all in-flight transfers, routes events between connectors, and drives transfers to completion or cancellation | | **Connectors** | Chain-specific gRPC services that monitor smart contracts for `FundsIn` events and issue `FundsOut` transactions on the destination chain | | **Federated Signer Nodes** | A set of three independent listener nodes, each running inside an AWS Nitro Enclave, that jointly sign transactions using a TEE-federation with threshold scheme | | **Enclave Signer** | Cryptographic microservice running inside an AWS Nitro Enclave; derives and holds private keys in a Trusted Execution Environment (TEE) so they never leave the hardware boundary | | **BTC Relay** | Lightweight Bitcoin header relay service that feeds block headers into the TEE for in-enclave SPV verification | | **REST Gateway** | Public API used by the web UI and external integrations | ### Mint Orchestrator The Mint orchestrator is the central coordinator. It tracks all in-flight transfers in a persistent database, processes `FundsIn` events reported by Connectors, and instructs the appropriate destination Connector to issue a`FundsOut` transaction. If a transfer cannot be completed, the orchestrator drives it to safe cancellation. ### Connectors Each supported chain has a dedicated Connector, a stateless gRPC service that watches the chain for `FundsIn` smart contract events and issues`FundsOut` transactions on the destination chain. Connectors do not hold keys or funds. All signing is delegated to the Federated Signer Nodes. ### Federated Signer Nodes Transaction signing is distributed across three independent listener nodes, each running inside its own **AWS Nitro Enclave**. A valid signature requires agreement from the **TEE- federation nodes** (threshold scheme). No single node and no external party can unilaterally produce a valid signature. Key properties: * **Threshold signing.** All EVM (EIP-712) and Bitcoin (PSBT Taproot Schnorr) signatures require threshold scheme quorum across independent TEE instances. * **Keys never leave the TEE.** BIP-39 key generation and all signing operations happen inside each enclave, with no persistent storage or shell access. * **In-enclave RGB validation.** Every RGB consignment is validated inside the enclave before signing, cross-checking amounts against calldata and commission. * **In-enclave SPV verification.** Bitcoin block headers are relayed into the TEE via the BTC Relay service, enabling the enclave to independently verify transaction inclusion without trusting any external data source. * **Memory safety.** Secrets are zeroized on drop; the codebase enforces `#![deny(unsafe_code)]`. ### Enclave Signer The Enclave Signer (`utexo-mint-enclave-signer`) is the base cryptographic microservice from which each Federated Signer Node is derived. It runs inside an **AWS Nitro Enclave** — an isolated compute environment with no persistent storage, no shell access and network access limited to a vsock proxy allowlisted to an Esplora indexer and the BTC Relay. ### BTC Relay The BTC Relay (`btc-relayer`) streams Bitcoin block headers to the Federated Signer Nodes. Inside each enclave, headers are validated against a hardcoded checkpoint block and the signet challenge script, both baked in at compile time and bound to the enclave's PCR0 attestation measurement. This allows the TEE to perform SPV proofs without relying on any external indexer for header data. ## Transfer Flow The following steps describe a complete cross-chain transfer: 1. User deposits funds on the source chain (`FundsIn`). 2. The source Connector detects the on-chain event and notifies the Mint orchestrator. 3. The Mint orchestrator instructs the destination Connector to release funds (`FundsOut`). 4. The Federated Signer Nodes sign the `FundsOut` transaction inside their respective TEEs; athreshold scheme is required before broadcast. 5. Transfer is marked complete once finality is confirmed. **Example — Ethereum → Bitcoin RGB layer:** 1. User submits a USDT transfer from their Ethereum wallet. The USDT0 / LayerZero protocol mints it to USDT0 on Arbitrum transparently. 2. User submits a `FundsIn` transaction on the Arbitrum smart contract, locking USDT0. 3. The Arbitrum Connector detects the event and notifies the orchestrator. 4. The orchestrator instructs the Bitcoin Connector to prepare a `FundsOut` PSBT. 5. The Bitcoin Connector creates and validates the RGB consignment and PSBT. 6. The Federated Signer Nodes validate the signing payload; a threshold of nodes signs the PSBT using Taproot Schnorr. 7. The signed transaction is broadcast to Bitcoin. Once confirmed, USDT on Bitcoin appears in the user's compatible RGB wallet. ## Supported Networks | Network | Type | Direction | | ------------------- | ---------------- | ------------------ | | Bitcoin (RGB layer) | Schnorr / Segwit | Inbound & Outbound | | Arbitrum | EVM (secp256k1) | Inbound & Outbound | | Plasma | EVM (secp256k1) | Inbound & Outbound | | Polygon PoS | EVM (secp256k1) | Inbound & Outbound | | Ethereum | EVM (secp256k1) | Inbound & Outbound | | Tron | EVM (secp256k1) | Inbound & Outbound | | Lightning | Schnorr / Segwit | **Coming soon** | Additional USDT0-supported networks can be enabled based on business need. See [USDT0's contract deployments](https://docs.usdt0.to/technical-documentation/deployments) for its current network coverage. ## Supported Assets | Asset | Source Network | Representation on Bitcoin | | ----- | ---------------------------------------------------------- | ------------------------- | | USDT | Bitcoin (RGB layer); Lightning (coming soon) | USDT on Bitcoin | | USDT0 | Arbitrum (native hub), Ethereum, Plasma, Polygon PoS, Tron | USDT on Bitcoin | ## Fees Commissions are managed on-chain through the `CommissionManager` contract. For token transfers (USDT, USDT0), fees can be applied on both `FundsIn` and `FundsOut`. For native currency, fees are only taken on `FundsIn` — charging on `FundsOut` is not applicable since that leg is triggered by the protocol rather than the user. The current fee rate is **0.03%** across supported networks. ## Security The Utexo Mint is designed so that assets cannot be stolen even if individual operators are compromised. The trust model distributes signing authority and performs all sensitive operations inside hardware-isolated Trusted Execution Environments (TEEs), minimising the need to trust any single party. **Distributed signing authority.** Signing authority is distributed across three independent Federated Signer Nodes, each running inside its own AWS Nitro Enclave. No single node can produce a valid signature unilaterally — a threshold scheme is required for every EVM and Bitcoin transaction. This eliminates single-point-of-failure risks for key compromise, infrastructure access, and operator collusion. **TEE-enforced key isolation.** Private keys are generated inside each enclave using BIP-39 and never leave the TEE hardware boundary. There is no persistent storage, no shell access, and all network access is restricted to a vsock proxy allowlisted only to an Esplora indexer and the BTC Relay. The enclave code is reproducibly buildable and bound to a verifiable PCR0 measurement. **In-enclave RGB validation.** Before co-signing any `FundsOut` transaction, each Federated Signer Node validates the RGB consignment inside the enclave — confirming the burn amount and commission against the calldata. This ensures that the TEE independently verifies the on-Bitcoin burn before authorising any EVM release of funds. **In-enclave SPV verification.** Bitcoin block headers are streamed into each enclave via the BTC Relay against a compile-time checkpoint block, allowing the TEE to independently verify transaction inclusion via SPV proofs without relying on any external indexer. This prevents eclipse attacks where an operator might attempt to present a fake burn against an alternative chain. **Burn replay protection.** The TEE extracts a `burnId` from each RGB consignment before signing. This identifier is passed as a `FundsOut` parameter and stored by the smart contract, which rejects any `FundsOut` call reusing a previously seen `burnId`. **Public attestation.** The enclave binary is reproducibly buildable, and each node publishes a verifiable attestation binding its public key to the PCR0 measurement of the deployed code. A `VERIFY.md` document provides step-by-step guidance for independently confirming that the keys held inside the EVM smart contract were generated and remain inside a genuine Nitro Enclave. ## Guide Mint USDT between Ethereum and the Bitcoin RGB layer. # Mint API Reference Source: https://docs.utexo.com/product-suite/mint-api-reference Network-agnostic REST API for discovering supported networks, estimating fees, initiating transfers, and tracking settlement across EVM, RGB, and RGB Lightning networks. ## Overview The **Utexo Mint API** is a network-agnostic REST interface for cross-network asset transfers. Clients must discover the networks currently connected to an environment with `GET /networks` instead of hardcoding network availability. USDT0 settles natively on Arbitrum, which acts as the hub; other EVM networks reach that hub through LayerZero. Bitcoin mainnet is not available yet. **Base URL (testnet / dev):** `https://transfer.gateway.dev.utexo.com/api/v0` All paths in this reference are relative to the base URL. A mainnet base URL will be provided separately. Contact the Utexo team for production endpoint access. **Interactive API docs:** [https://transfer.gateway.dev.utexo.com/api/v0/docs/](https://transfer.gateway.dev.utexo.com/api/v0/docs/) The API is stateless and JSON-based. Most `GET` endpoints are public; `GET /transfers/history/{signature-hex}/{pub-key-hex}` is the exception and carries the signature and public key in the path. The `POST /transfers/verify-bridge-in` and `POST /transfers/submit-transaction` endpoints need a signature in the request body (see [Authentication](#authentication)). *** ## Transfer Flows Understanding the transfer direction is essential before making any API calls. The API supports two directions: **RGB and Lightning destinations:** The RGB-side destination is selected by `networkId`. Use `36` (mainnet) or `91` (testnet) for plain RGB, and `94` (mainnet) or `95` (testnet) for RGB Lightning. The destination accepts an RGB invoice (`rgb:…`) for plain RGB or a Lightning invoice string for RGB Lightning. Network ID `96` identifies Utexo and is not a Lightning network ID. **RGB Lightning is work in progress.** The API surface is in place and documented throughout this reference, but Lightning destinations are not available for use yet. This section will be updated once they go live. ### EVM → RGB or RGB Lightning Move assets from an EVM network to a plain RGB or RGB Lightning destination. `GET /networks` — list all connected networks; take the `id` of your source and destination. `GET /networks/{network-id}/supported-tokens` — list tokens on that network and take the `id` of the one you want to bridge. USDT is the only token bridged today. `GET /transfers/estimate/{sender-network}/{recipient-network}/{token-id}/{amount}` — preview the transfer before committing: fees and the amount the recipient will receive. `POST /transfers/bridge-in-signature` — registers the transfer and returns the data needed to call `fundsIn()` on the EVM bridge contract: `transferId`, `token`, `amount`, `gasCommission`, `deadline`, `nonce` and the fee `estimation`. In this direction the `signature` field carries no signature and is returned as `0x`. If the route goes through the entrypoint contract, the response also includes an `entrypoint` object — call that contract with its `depositParams` instead. The user calls the contract identified in Step 3 — `fundsIn()` on the EVM bridge contract, or the entrypoint contract with its `depositParams`. This step happens **client-side** — the API does not broadcast this transaction. `POST /transfers/verify-bridge-in` — notify the mint with the on-chain tx hash to confirm the transfer. `GET /transfers/history/{signature-hex}/{pub-key-hex}` — poll history until the transfer reaches a terminal status (`FINISHED` or `FAILED`). ### RGB or RGB Lightning → EVM Move assets from a plain RGB or RGB Lightning wallet to an EVM network. Same as EVM → RGB Step 1. Same as EVM → RGB Step 2. `POST /transfers/bridge-in-signature` — returns the invoice for the selected RGB-side network in the `signature` field: an RGB invoice for plain RGB or a Lightning invoice for RGB Lightning. Keep the returned `transferId` — you need it in Step 5. The user pays the invoice string returned in Step 3 with the wallet appropriate for the selected RGB or RGB Lightning network. `POST /transfers/verify-bridge-in` — notify the mint that the RGB or Lightning invoice payment has been completed. `GET /transfers/invoice/{tx-id}/{network-id}` — returns the invoice the bridge issued in Step 3, in case the user lost it before paying. *** ## Authentication Most `GET` endpoints and `POST /transfers/bridge-in-signature` require no authentication. Three endpoints authenticate the caller the same way, differing only in where the signature travels — in the path for `GET /transfers/history/{signature-hex}/{pub-key-hex}`, in the request body for `POST /transfers/verify-bridge-in` and `POST /transfers/submit-transaction`: | Field | Description | | ------------------------- | -------------------------------------------------------------------------- | | `authenticationSignature` | Hex-encoded signature over the fixed message `Bridge Authentication Proof` | | `publicKey` | Sender address or public key encoded for `networkId` | **Signing procedure.** The signed message is the constant string `Bridge Authentication Proof`. Verification depends on the network type: * **EVM and Tron** — the public key is recovered from the signature, converted to an address, and compared against `publicKey`. * **RGB and RGB Lightning** — authentication is handled inside those networks; no signature check happens at this layer. A `401` response indicates an invalid authentication signature. A `403` response indicates the derived sender address does not match the pre-registered transfer. *** ## Endpoints ### Networks #### `GET /networks` — List Connected Networks Returns all connected networks. Optionally filter by token, source network, or name. **Query Parameters** | Parameter | Type | Required | Description | | ------------------- | --------- | -------- | --------------------------------------------------------------------------------------------------- | | `token-id` | `integer` | No | Filter results to networks that support this token ID. Cannot be combined with `source-network-id`. | | `source-network-id` | `integer` | No | Return networks supported by the specified source network. Cannot be combined with `token-id`. | | `search` | `string` | No | Filter results by network name (partial match) | **Response `200`** — Array of `Network` objects ```json theme={null} [ { "id": 42161, "name": "ARBITRUM-ONE", "displayName": "Arbitrum One", "type": "NT_EVM", "bridgeContract": "0x...", "gasLimit": 200000, "iconLink": "https://...", "active": true, "explorerBaseUrl": "https://arbiscan.io" } ] ``` *** #### `GET /networks/{network-id}/supported-tokens` — List Supported Tokens Returns a paginated list of tokens supported on a given network. If `token-id` is provided as a query parameter, returns a single `Token` object instead of a paginated response. **Path Parameters** | Parameter | Type | Required | Description | | ------------ | --------- | -------- | -------------- | | `network-id` | `integer` | Yes | The network ID | **Query Parameters** | Parameter | Type | Required | Description | | ---------- | --------- | -------- | ------------------------------------------------------------------- | | `token-id` | `integer` | No | If set, returns a single `Token` object instead of a paginated list | | `search` | `string` | No | Filter tokens by name or symbol | | `limit` | `integer` | No | Number of results per page | | `page` | `integer` | No | Page number (1-indexed) | **Response `200`** — `SupportedTokensResponse` ```json theme={null} { "tokens": [...], "limit": 20, "offset": 0, "pageCount": 3, "currentPage": 1, "totalCount": 45 } ``` *** #### `GET /networks/{network-id}/balance/{token-id}/{user-address}` — Get User Token Balance Returns the token balance for a specific user address on a given network. **Path Parameters** | Parameter | Type | Required | Description | | -------------- | --------- | -------- | -------------------------------------------------------------------------------------------- | | `network-id` | `integer` | Yes | The network ID | | `token-id` | `integer` | Yes | The token ID | | `user-address` | `string` | Yes | User address. For EVM networks, provide a hex-encoded address (with or without `0x` prefix). | **Response `200`** — `string` Balance as a human-readable decimal string in token units (e.g., `"100.50"`). *** ### Transfers #### `GET /transfers/estimate/{sender-network}/{recipient-network}/{token-id}/{amount}` — Estimate Transfer Fees Returns a fee and confirmation time estimate for a proposed transfer. Call this before pre-registering to give users a cost preview. **Path Parameters** | Parameter | Type | Required | Description | | ------------------- | --------- | -------- | -------------------------------------------------- | | `sender-network` | `string` | Yes | Sender network name (e.g., `ARBITRUM-ONE`, `RGB`) | | `recipient-network` | `string` | Yes | Recipient network name | | `token-id` | `integer` | Yes | Token ID — the same token is bridged on both sides | | `amount` | `string` | Yes | Human-readable amount (e.g., `100.5`) | **Query Parameters** | Parameter | Type | Required | Description | | ------------------- | -------- | -------- | -------------------------------------------- | | `sender-address` | `string` | Yes | Sender's address on the sender network | | `recipient-address` | `string` | Yes | Recipient's address on the recipient network | **Response `200`** — `Estimation` ```json theme={null} { "fee": "0.50", "feePercentage": "0.5", "stableFee": "0.10", "estimatedConfirmationTime": "5 minutes", "resultAmount": "99.40", "nativeFee": "0.0002", "networkFee": "0.0001", "nativeStableFee": "0.0001", "totalNativeCommission": "0.0004", "nativeTokenSymbol": "ETH", "swapResultAmount": "99.40", "effectiveAvailableOutflow": "10000" } ``` | Field | Description | | --------------------------- | ---------------------------------------------------------------------- | | `fee` | Gas fee denominated in the transfer token | | `stableFee` | Fixed protocol fee in transfer token units | | `feePercentage` | Protocol fee as a percentage string | | `resultAmount` | Amount the recipient will receive after fees | | `nativeFee` | Gas fee in the sender's native token (multi-token transfers) | | `networkFee` | Source-network execution fee in the sender's native token | | `nativeStableFee` | Stable fee in the sender's native token (multi-token transfers) | | `totalNativeCommission` | Sum of the native fee components | | `nativeTokenSymbol` | Symbol of the native token used for commissions | | `swapResultAmount` | Human-readable result amount in recipient token units | | `effectiveAvailableOutflow` | Remaining destination outflow allowance; omitted when no limit applies | *** #### `POST /transfers/bridge-in-signature` — Pre-Register Transfer Pre-registers a transfer and returns the data needed for the user to initiate the on-chain action. * **EVM → RGB or RGB Lightning**: Returns `transferId`, fee `estimation`, and an empty `signature` field (`0x`). The user then calls `fundsIn()` on the EVM bridge contract. * **RGB or RGB Lightning → EVM**: Returns the invoice string for the selected RGB-side network in the `signature` field. The user pays that RGB or Lightning invoice. **Request Body** — `BridgeInSignatureRequest` ```json theme={null} { "sender": { "networkId": 42161, "networkName": "ARBITRUM-ONE", "address": "0xYourEvmAddress" }, "tokenId": 42, "amount": "100.5", "destination": { "networkId": 36, "networkName": "RGB", "address": "rgb:..." }, "additionalAddresses": [] } ``` | Field | Type | Required | Description | | --------------------- | ---------- | -------- | ---------------------------------------------------------- | | `sender` | `Address` | Yes | Sender network, ID, and address | | `tokenId` | `integer` | Yes | Token ID (same token on both chains) | | `amount` | `string` | Yes | Human-readable amount (e.g., `"100.5"`) | | `destination` | `Address` | Yes | Recipient network, ID, and address | | `additionalAddresses` | `string[]` | No | Additional addresses (use case: TBD — validation required) | **Response `200`** — `BridgeInSignatureData` ```json theme={null} { "token": "0xTokenContractAddress", "amount": "100500000", "gasCommission": "50000", "destination": { ... }, "deadline": "1719999999", "nonce": 7, "transferId": 1024, "signature": "0x", "transferType": "LP", "estimation": { ... }, "totalCommission": "600000" } ``` | Field | Description | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `token` | EVM token contract address | | `amount` | Transfer amount in **smallest token units** (not human-readable) | | `gasCommission` | Gas commission in smallest token units | | `destination` | Destination network and address selected for the transfer | | `deadline` | EVM: UNIX timestamp expiry. RGB: always `"0"` | | `nonce` | Nonce for the EVM bridge contract call | | `transferId` | Internal transfer ID — store this for use in `verify-bridge-in` | | `signature` | EVM → RGB/RGB Lightning: `"0x"` (empty). RGB/RGB Lightning → EVM: RGB or Lightning invoice string selected by destination network ID | | `transferType` | Transfer routing type — see [Transfer Types](#transfer-types) | | `estimation` | Fee and result-amount estimation using the same fields as the estimate endpoint | | `entrypoint` | Ready-to-call entrypoint contract data; present only when the selected route uses the entrypoint contract | | `totalCommission` | Total commission in smallest token units | *** #### `POST /transfers/verify-bridge-in` — Confirm Bridge-In Transaction Notifies the bridge that the user has completed the on-chain or off-chain send action. Must be called after: * The EVM `fundsIn()` transaction is broadcast (EVM → RGB/RGB Lightning), or * The RGB or Lightning invoice payment is complete (RGB/RGB Lightning → EVM) **Request Body** — `VerifyBridgeInRequest` ```json theme={null} { "transferId": 1024, "networkId": 42161, "txHash": "abcdef1234...", "publicKey": "0xYourPublicKeyOrAddress", "authenticationSignature": "hex-encoded-signature" } ``` | Field | Type | Required | Description | | ------------------------- | --------- | ----------- | ---------------------------------------------------------------------------------------------------------------- | | `transferId` | `integer` | Yes | Transfer ID from `bridge-in-signature` response | | `networkId` | `integer` | Yes | Sender's network ID | | `txHash` | `string` | Conditional | Network-encoded transaction hash. May be empty when the RGB-side confirmation has no transaction hash to submit. | | `publicKey` | `string` | Yes | Sender public key or address | | `authenticationSignature` | `string` | Yes | Hex-encoded signature proving address ownership | **Response `200`** — Empty body (`null`). Accepted. **Error Responses** | Status | Meaning | | ------ | ------------------------------------------------------------------------------------ | | `401` | Authentication signature is invalid | | `403` | Sender address derived from the signature does not match the pre-registered transfer | | `500` | Internal server error | *** #### `POST /transfers/submit-transaction` — Submit Signed Transaction Submits signed transaction data for a pre-registered transfer and returns the resulting transaction hash. **Request Body** | Field | Type | Required | Description | | ------------------------- | --------- | ----------- | -------------------------------------------------------------------------------------------------------- | | `transferId` | `integer` | Yes | Transfer ID from `POST /transfers/bridge-in-signature` | | `networkId` | `integer` | Yes | Network on which the transaction is submitted | | `txData` | `string` | Conditional | Base64-encoded signed transaction data. Populate this field only when required for the selected network. | | `publicKey` | `string` | Yes | Sender address or public key encoded for `networkId` | | `authenticationSignature` | `string` | Yes | Hex-encoded signature proving sender ownership | **Response `200`** ```json theme={null} { "txHash": "network-encoded-transaction-hash" } ``` **Error Responses** | Status | Meaning | | ------ | ------------------------------------------------------------------------------------------------------------------------- | | `400` | Invalid network, sender address, signature encoding, transaction encoding, or unsupported non-empty `txData` network type | | `401` | Authentication signature is invalid | | `403` | Sender address does not match the pre-registered transfer | | `500` | Transaction submission failed | *** #### `GET /transfers/history/{signature-hex}/{pub-key-hex}` — Get Transfer History Returns a paginated list of transfers associated with a user's address. Identity is proven by providing a signature. **Path Parameters** | Parameter | Type | Required | Description | | --------------- | -------- | -------- | ------------------------------------------------------ | | `signature-hex` | `string` | Yes | Hex-encoded signature proving address ownership | | `pub-key-hex` | `string` | Yes | Public key or address encoded for the selected network | **Query Parameters** | Parameter | Type | Required | Description | | ------------ | --------- | -------- | ---------------------------------------------------- | | `offset` | `integer` | Yes | Pagination offset (number of records to skip) | | `limit` | `integer` | Yes | Number of records to return (must be > 0) | | `network-id` | `integer` | Yes | Network ID to filter history by | | `address` | `string` | No | User address — required for Bitcoin native addresses | **Response `200`** — `Page` ```json theme={null} { "transfers": [...], "offset": 0, "limit": 20, "totalCount": 142 } ``` **Transfer Status Values** | Status | Description | | ------------ | ---------------------------------------------------------------- | | `WAITING` | Transfer registered, awaiting on-chain confirmation | | `CONFIRMING` | On-chain transaction detected, awaiting sufficient confirmations | | `FINISHED` | Transfer completed successfully | | `FAILED` | Transfer failed — check `outboundTx` for details | Poll history at a reasonable interval (e.g., every 5–10 seconds). Avoid aggressive polling — the bridge requires Bitcoin confirmations for RGB-leg completions, which may take several minutes. *** #### `GET /transfers/invoice/{tx-id}/{network-id}` — Get RGB or Lightning Invoice Returns the invoice associated with a completed or pending transfer. The `network-id` selects plain RGB (`36` mainnet, `91` testnet) or RGB Lightning (`94` mainnet, `95` testnet). **Path Parameters** | Parameter | Type | Required | Description | | ------------ | --------- | -------- | ---------------------------------------------------------- | | `tx-id` | `integer` | Yes | Internal transfer ID (from `bridge-in-signature` response) | | `network-id` | `integer` | Yes | RGB or RGB Lightning network ID | **Response `200`** — `InvoiceResponse` ```json theme={null} { "invoice": "rgb:..." } ``` For an RGB Lightning network ID, `invoice` contains the Lightning invoice string instead. *** ## Transfer Types The `transferType` field in `BridgeInSignatureData` indicates the internal routing mechanism selected for the transfer. Known values: | Value | Description | | ----- | --------------------- | | `LP` | Liquidity pool route | | `WU` | Wrap/unwrap route | | `NTV` | Native token transfer | The bridge selects the routing classification. Clients should treat this field as informational unless a transfer flow explicitly requires route-specific handling. *** ## Error Responses All endpoints return a consistent error envelope on failure. ```json theme={null} { "error": "human-readable error message", "code": 1 } ``` **Error Codes** | Code | Meaning | | ------- | --------------------------------------------- | | `1` | RGB protocol error | | `2` | User balance error (insufficient funds) | | `3` | System balance error (bridge liquidity issue) | | `4` | Destination outflow limit exceeded | | `65535` | Other / unclassified error | *** ## Data Models ### `Address` ```json theme={null} { "networkId": 42161, "networkName": "ARBITRUM-ONE", "address": "0x..." } ``` ### `Network` ```json theme={null} { "id": 42161, "name": "ARBITRUM-ONE", "displayName": "Arbitrum One", "type": "NT_EVM", "bridgeContract": "0x...", "gasLimit": 200000, "iconLink": "https://...", "active": true, "explorerBaseUrl": "https://arbiscan.io" } ``` ### `Token` ```json theme={null} { "id": 42, "shortName": "USDT", "longName": "Tether USD", "smartContractAddress": "0x...", "decimals": 6, "iconLink": "https://...", "active": true, "native": false } ``` *** ## Glossary | Term | Definition | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **RGB** | A client-side validated smart contract protocol built on Bitcoin. Assets are issued and transferred using Bitcoin UTXOs as state anchors. | | **RGB Invoice** | A blinded payment request string used to receive RGB assets. Contains blinded UTXO data to preserve receiver privacy. | | **EVM** | Ethereum Virtual Machine — the execution environment used by Arbitrum and other compatible chains. | | **Bridge Contract** | The EVM smart contract that locks or releases assets on the EVM side of a cross-chain transfer. | | **`fundsIn()`** | The method on the EVM bridge contract the sender calls to deposit assets for minting. | | **transferId** | The mint's internal identifier for a pre-registered transfer. Used in `verify-bridge-in` and invoice retrieval. | | **Triggering Tx** | The EVM deposit transaction that initiates an EVM → RGB or EVM → RGB Lightning mint. | | **Entrypoint contract** | A per-network contract that forwards a deposit to the Arbitrum hub through LayerZero. When a route uses it, `bridge-in-signature` returns an `entrypoint` object and the user calls that contract instead of `fundsIn()`. | | **UTXO** | Unspent Transaction Output — the fundamental unit of Bitcoin accounting. RGB asset state is anchored to UTXOs. | # General Overview Source: https://docs.utexo.com/product-suite/sdk Overview of the Utexo SDK family — Web, React Native, and WDK (Node.js / Bare) client libraries for RGB asset operations and Lightning. The Utexo SDK provides programmatic access to the Utexo execution layer, enabling applications to issue, transfer, and receive RGB assets on Bitcoin without operating nodes, managing channels, or handling protocol-level infrastructure. It exposes a clean set of async methods organised around wallet management, RGB asset operations, on-chain Bitcoin interactions, and Lightning payments. All operations are performed locally using client-side validation — no shared state is sent to a central server during normal execution. ## SDK Family The Utexo SDK is available across three application platforms. `@utexo/rgb-sdk` (Node.js) is archived; new Node.js integrations should use `@utexo/wdk-rgb-lightning`. A separate Wallet Development Kit (WDK) layer is available for builders who need lower-level wallet abstractions: | Package | Platform | Use case | | -------------------------- | ------------------ | ----------------------------------------------------------------------------- | | `@utexo/wdk-rgb-lightning` | Node.js & Bare | Current Node.js / Bare path — RGB Lightning channels, invoices, payments, LSP | | `@utexo/rgb-sdk-web` | Browser / JS/TS | Web apps, embedded wallets, in-browser RLN via WASM | | `@utexo/rgb-sdk-rn` | React Native | iOS and Android — full on-device Lightning node via RLN | | `@utexo/wdk-wallet-rgb` | Node.js & Bare | WDK-compatible on-chain RGB asset management | | `@utexo/rgb-sdk` | Node.js (archived) | Legacy server-side SDK — do not use for new integrations | `@utexo/rgb-sdk-rn` and `@utexo/rgb-sdk-web` ship with full Lightning support via an on-device / in-browser RLN node. The archived `@utexo/rgb-sdk` Node.js package does not. The Web and React Native SDKs share `@utexo/rgb-sdk-core`, which contains common interfaces, base classes, unified types, transport configuration, and UTEXO network mappings. This page covers the SDK family. Refer to the platform reference pages for method-level details. ## What the SDK Provides * **Wallet management** — key generation, derivation, initialisation, backup, and restore (including VSS cloud backup); address rotation following HD wallet best practices * **RGB asset operations** — asset issuance, blinded and witness invoices, asset transfers, and balance queries * **Lightning payments** — invoice creation, synchronous payment execution (begin → sign → end flow), HODL invoice support for offline recipients, Lightning Address integration, and payment status queries * **Async payments** — LSP-routed delivery so recipients can collect payments when they come online; inbound leg fully operational, outbound leg in active development * **On-chain interactions** — deposit address generation, BTC balance queries, on-chain withdrawal * **UTXO management** — UTXO creation, listing, and state sync ## Key Concepts ### Vanilla vs Colored Addresses The SDK operates two distinct address and key derivation paths: * **Vanilla** — the standard Bitcoin derivation path. Vanilla outputs hold regular BTC and are used for fee payments, on-chain withdrawals, and funding operations. `getAddress()` returns a vanilla bech32 receive address. * **Colored** — the RGB-specific derivation path. Colored outputs carry RGB asset allocations anchored to Bitcoin UTXOs. This path is used internally when creating UTXOs for RGB operations. `getXpub()` returns both the vanilla xpub (`accountXpubVanilla`) and the colored xpub (`accountXpubColored`). `getBtcBalance()` returns separate balances for each path, each with `settled`, `future`, and `spendable` fields. Before issuing or receiving RGB assets, the wallet must have colored UTXOs prepared. Call `createUtxos()` after funding the vanilla address to set up the UTXO structure required for RGB allocations. ### Invoice Types: Blinded vs Witness RGB receive flows support two invoice styles: * **Blinded invoice** — most common. The receiver creates a blinded endpoint; the sender pays the invoice directly. Use this for standard app-to-app RGB transfers. * **Witness invoice** — the receiver binds the transfer to witness data. The sender must provide `witnessData` (at minimum `amountSat` on Web/RN, `amountSats` on WDK) when sending. Use this when the integration requires witness-bound receive semantics. On Web and React Native, receive with `onchainReceive({ witness: false })` for blinded or the default witness invoice, then send with `onchainSend()`. On `@utexo/wdk-rgb-lightning`, receive with `createRgbInvoice({ witness: false | true, ... })` and send with `transfer()`. ### Backup and Restore The SDK provides two backup mechanisms for wallet state. Backups are recommended after every significant state change (UTXO creation, asset issuance, transfer): * **File backup** (`createBackup`) — creates an encrypted local backup containing both `layer1` and `utexo` state files. Restore with `restoreUtxoWalletFromBackup()`. * **VSS backup** (`vssBackup`) — pushes wallet state to a remote Verifiable Secret Sharing server. The backup is keyed to the wallet mnemonic. Restore with `restoreUtxoWalletFromVss()`. Call `vssBackupInfo()` to check backup existence and whether a new backup is required. ### Private Key Export The SDK exposes `getXprivFromMnemonic(network, mnemonic)` to derive the extended private key (`xpriv`) from a mnemonic. This is the account root private key material from which all child keys can be derived. Treat `xpriv` with the same sensitivity as the mnemonic itself — do not log or transmit it in production. ## Execution Model New Node.js integrations use `@utexo/wdk-rgb-lightning`. The primary entry point is `WalletManagerRgbLightning`, which takes the seed mnemonic at construction and unlocks a single Lightning account: ```ts theme={null} const manager = new WalletManagerRgbLightning(mnemonic, { network: 'utexo', dataDir: './wallet', lspBaseUrl: '...', // optional — enables async payments lspBearerToken: '...' // optional — required when lspBaseUrl is set }) const account = await manager.getAccount(0) await account.unlock({ indexer_url, proxy_endpoint, announce_addresses: [], announce_alias: 'my-node' }) ``` The Web and React Native packages use `UTEXOWallet` (`init()` then `unlock()`). See the platform reference pages for that lifecycle. Key execution properties: * All operations are **non-custodial** — the SDK never transmits private keys or mnemonics * All API calls execute with **predefined costs and latency** — no fee auction or gas estimation required * **Web** uses `@utexo/rgb-sdk-web` (WASM); **React Native** uses `@utexo/rgb-sdk-rn`; **Node.js** uses `@utexo/wdk-rgb-lightning` * **External signer support** — the Lightning node runs in external-signer mode; the mnemonic stays in the host secret manager * **Async payments** are opt-in via `lspBaseUrl` and `lspBearerToken` ## Networks The SDK supports three environments. Pass the identifier in the `network` field of the init config. | Environment | Identifier | RGB Transport | Bitcoin Indexer | | -------------- | ---------- | ---------------------------------------------- | ------------------------------------- | | Mainnet | `mainnet` | `rpcs://rgb-proxy-mainnet.utexo.com/json-rpc` | `ssl://electrum.iriswallet.com:50003` | | Testnet | `testnet` | `rpcs://rgb-proxy-testnet3.utexo.com/json-rpc` | `ssl://electrum.iriswallet.com:50013` | | Utexo (Signet) | `utexo` | `rpcs://rgb-proxy.utexo.com/json-rpc` | `https://esplora-api.utexo.com` | The `utexo` identifier maps to the Utexo-operated signet environment. It is the default network for development and testing. ## In This Section Platform references for `@utexo/wdk-rgb-lightning` (Node.js / Bare), `@utexo/rgb-sdk-web` (browser), `@utexo/rgb-sdk-rn` (iOS and Android), and the WDK on-chain module `@utexo/wdk-wallet-rgb`. ## Further Reading * [Product Suite](/getting-started/product-suite) — How the SDK fits into the full Utexo product surface. * [Architecture](/getting-started/architecture) — The Bitcoin + RGB stack the SDK operates on. * [Quickstart](/getting-started/quickstart) — Step-by-step guide to your first Utexo integration. ## Platform SDKs | Page | Package | Platform | | ------------------------------------------- | -------------------------- | ----------------------------------------------- | | [wdk-rgb-lightning](/sdk/wdk-rgb-lightning) | `@utexo/wdk-rgb-lightning` | Node.js & Bare — current RGB Lightning module | | [React Native SDK](/sdk/react-native-sdk) | `@utexo/rgb-sdk-rn` | iOS and Android — full on-device Lightning node | | [Web SDK](/sdk/web-sdk) | `@utexo/rgb-sdk-web` | Browser — WASM RLN, including Lightning | ## Wallet Development Kit (WDK) The WDK packages expose RGB capabilities through standard wallet abstraction interfaces for builders who already use WDK-compatible account and signing layers. | Page | Package | Status | | ------------------------------------------- | -------------------------- | -------------------------------------------------- | | [WDK Overview](/sdk/wdk-overview) | — | Shared architecture and `dataDir` coordination | | [wdk-wallet-rgb](/sdk/wdk-wallet-rgb) | `@utexo/wdk-wallet-rgb` | Stable — RGB asset management | | [wdk-rgb-lightning](/sdk/wdk-rgb-lightning) | `@utexo/wdk-rgb-lightning` | Pre-1.0 beta — RGB Lightning channels and payments | # Swap Overview Source: https://docs.utexo.com/product-suite/swap How Utexo coordinates resolver-based cross-chain swaps through RFQ pricing, signed intents, and non-custodial settlement. ## Overview Utexo Swap provides execution infrastructure for wallets, applications, exchanges, and other integration partners. It coordinates cross-chain swaps through resolver-based request-for-quote (RFQ) pricing, signed intents, and chain-specific settlement mechanisms. Resolvers compete to price and fulfill each swap. Utexo coordinates quote discovery, intent validation, execution, and settlement without taking custody of user funds or acting as the swap counterparty. Utexo Swap currently supports Ethereum and other EVM networks, Tron, Solana, and Bitcoin. Use `GET /networks` and `GET /tokens` to discover the networks and assets available to your integration instead of hardcoding availability. ### Core properties * **RFQ execution:** Distributed resolvers provide pricing and liquidity. * **Intent-based authorization:** A signed intent defines the asset pair, amount, source network, destination network, recipient, and execution constraints. * **Atomic settlement:** Each swap completes under the signed conditions or enters the applicable refund or revert path. * **Non-custodial design:** Utexo does not custody user funds. * **Unified integration:** A single REST API supports all available networks and their chain-specific approval mechanisms. ## Architecture and settlement Utexo uses cryptographic time constraints and network-native escrow mechanisms to coordinate cross-chain settlement. | Network | Settlement mechanism | | ------------------------------- | ----------------------------------------------- | | Bitcoin | Taproot hash time-locked contract (HTLC) escrow | | Ethereum and other EVM networks | Dedicated escrow smart contract per swap | | Solana | Program escrow | | Tron | Contract escrow | Each swap uses an isolated settlement mechanism. Ethereum, other EVM networks, and Tron use a dedicated escrow instance for each swap. Swap-level isolation prevents funds associated with one swap from being exposed to another. Resolvers provide liquidity and perform the on-chain operations required to fulfill signed intents. Protocol rules restrict a resolver to the assets, amount, destination, and time constraints authorized by the user. ## Documentation map * [**Integration**](/product-suite/swap/integration/overview) explains access, authentication, and the end-to-end user flow. * [**Security Model**](/product-suite/swap/security-model) defines escrow isolation, resolver permissions, and refund behavior. * [**API Reference**](/product-suite/swap/api/networks-and-tokens) documents discovery, quotes, intents, swaps, and affiliates. * [**Resolver Integration**](/product-suite/swap/resolver-integration/overview) documents resolver responsibilities, protocol-facing endpoints, webhook lifecycle events, and chain-specific settlement requirements. * [**On-chain Helpers**](/product-suite/swap/on-chain-helpers/wrap-native-tokens) covers native-token wrapping and Permit2 token allowance. ## Glossary | Term | Definition | | ------------ | ------------------------------------------------------------------------------------------------------- | | **Intent** | A signed, machine-verifiable request to execute a swap under defined conditions. | | **Resolver** | A liquidity provider that prices and fulfills swap intents. | | **RFQ** | Request for quote; the process through which resolvers return competing prices. | | **Permit2** | An approval mechanism that combines an on-chain token allowance with an off-chain typed-data signature. | | **PSBT** | Partially Signed Bitcoin Transaction. Utexo uses it to authorize Bitcoin HTLC deposits. | | **HTLC** | Hash time-locked contract; an escrow mechanism controlled by a hash condition and timeout. | | **Lots** | Integer token amounts expressed in the smallest-unit representation used by the API. | # Affiliates Source: https://docs.utexo.com/product-suite/swap/api/affiliates Create and retrieve affiliate payout configurations for the authenticated integration. ## Affiliates Affiliate records configure fee payout destinations associated with the authenticated API key. ### `POST /affiliates` Creates an affiliate payout configuration. **Authentication:** `X-API-Key` | Body field | Type | Description | | -------------------- | ------- | --------------------------------------- | | `affiliateName` | string | Affiliate name. | | `payoutAddress` | string | Address for affiliate fee payouts. | | `payoutNetworkId` | integer | Network used for affiliate fee payouts. | | `payoutTokenAddress` | string | Token used for affiliate fee payouts. | ```json theme={null} { "affiliateName": "integration-partner", "payoutAddress": "0x0000000000000000000000000000000000000000", "payoutNetworkId": 1, "payoutTokenAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7" } ``` ### `GET /affiliates` Returns affiliate payout configurations associated with the authenticated API key. **Authentication:** `X-API-Key` | Response field | Type | Description | | --------------------------------- | ------- | ----------------------------------------------- | | `affiliates` | array | Affiliate configurations. | | `affiliates[].affiliateName` | string | Affiliate name. | | `affiliates[].apiKeyName` | string | API key name associated with the configuration. | | `affiliates[].payoutAddress` | string | Payout address. | | `affiliates[].payoutNetworkId` | integer | Payout network ID. | | `affiliates[].payoutTokenAddress` | string | Payout token address. | # Intents and Approvals Source: https://docs.utexo.com/product-suite/swap/api/intents-and-approvals Create swap intents, submit chain-specific approvals, and monitor intent status. ## Overview An intent is a signed, machine-verifiable request to execute a swap under the constraints of an accepted quote. ### `POST /intents` Creates an intent from a valid quote and user addresses. Utexo creates the intent off-chain and returns chain-specific approval data. **Authentication:** `X-API-Key` | Body field | Type | Required | Description | | -------------------- | ------ | -------- | --------------------------------------------------------------------------- | | `quoteId` | string | Yes | Quote ID returned by `POST /quote`. | | `refundAddress` | string | Yes | Address that receives refunded funds after an unsuccessful or expired swap. | | `destinationAddress` | string | Yes | Address that receives the destination asset. | | `sourceAddress` | string | Yes | Address from which the source asset is transferred. | | `sourcePublicKey` | string | No | Source public key. Bitcoin and Solana source networks can require it. | ```json theme={null} { "destinationAddress": "0x2222222222222222222222222222222222222222", "quoteId": "bea66e69-64c3-4b88-96ac-29f1ce7d454d", "refundAddress": "0x1111111111111111111111111111111111111111", "sourceAddress": "0x1111111111111111111111111111111111111111" } ``` The response identifies the required `approvalMechanism`. Exactly one of `permit2`, `htlc`, or `cosign` contains approval data in a successful response. ### `POST /intents/{id}/approvals` Attaches signed approval data to an existing intent and authorizes execution. Exactly one approval payload must be provided. **Authentication:** `X-API-Key` | Parameter or body field | Type | Required | Description | | ----------------------- | ------ | ----------- | -------------------------------------------------------------------- | | `id` | string | Yes | Intent ID in UUID format. | | `permit2` | string | Conditional | Permit2 signature when `approvalMechanism` is `permit2`. | | `psbt` | string | Conditional | Signed PSBT when `approvalMechanism` is `htlc`. | | `cosign` | object | Conditional | Signed Solana transaction data when `approvalMechanism` is `cosign`. | | `cosign.transaction` | string | Conditional | Signed versioned transaction. | | `cosign.userAddress` | string | Conditional | Address that signed the Solana transaction. | Permit2 example: ```json theme={null} { "permit2": "SIGNATURE_PLACEHOLDER" } ``` See [Chain-specific intent approval](#chain-specific-intent-approval) for signing requirements. ### `GET /intents/{id}/status` Returns the combined progress of an intent and its related swap. **Authentication:** `X-API-Key` | Path parameter | Type | Required | Description | | -------------- | ------ | -------- | ------------------------- | | `id` | string | Yes | Intent ID in UUID format. | ```json theme={null} { "status": "Initiated" } ``` ## Status lifecycle | Status | Meaning | | ----------------- | ------------------------------------------ | | `Initiated` | Utexo created the intent. | | `ApprovalAdded` | Utexo received the required user approval. | | `Accepted` | A resolver accepted the swap. | | `Declined` | A resolver declined the swap. | | `UserDeposited` | The user deposited the source funds. | | `Fulfilled` | The resolver fulfilled the swap. | | `Expired` | The swap reached its expiration deadline. | | `RefundRequested` | The protocol recorded a refund request. | | `Refunded` | The protocol completed the refund path. | ## Chain-specific intent approval Always use the approval mechanism returned by `POST /intents`. Do not convert approval data between network types. ### EVM networks EVM networks use Permit2. Before submitting the off-chain Permit2 signature, ensure that the ERC-20 token allowance for the Permit2 contract is sufficient. 1. Confirm that `approvalMechanism` is `permit2`. 2. Read the payload from the `permit2` response object. 3. Create and sign the EIP-712 Permit2 payload locally. 4. Submit the signature as the `permit2` value to `POST /intents/{id}/approvals`. The TypeScript integration uses `preparePermit2Approval` from `@hot-pot/hotpot-sdk-ts`. ```ts theme={null} import { privateKeyToAccount } from "viem/accounts"; import { preparePermit2Approval, type Permit2ApprovalToSign, } from "@hot-pot/hotpot-sdk-ts"; type Quote = Parameters[1]; type Permit2Intent = { approvalMechanism: "permit2"; deadlineSecs: number; intentId: string; permit2: Permit2ApprovalToSign; }; async function signAndSubmitPermit2Approval( quote: Quote, intent: Permit2Intent, account: ReturnType, baseUrl: string, apiKey: string, ): Promise { const payload = preparePermit2Approval( intent.permit2, quote, account.address, intent.deadlineSecs, ); const signature = await account.signTypedData(payload); const response = await fetch(`${baseUrl}/intents/${intent.intentId}/approvals`, { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json", "X-API-Key": apiKey, }, body: JSON.stringify({ permit2: signature }), }); if (!response.ok) { throw new Error(`Approval submission failed: ${response.status}`); } } ``` ### Tron Tron also uses Permit2, but the user signs a TIP-712 payload with TronWeb. 1. Confirm that `approvalMechanism` is `permit2`. 2. Read the payload from the `permit2` response object. 3. Derive the user source address from the signing key. 4. Create and sign the TIP-712 Permit2 payload. 5. Submit the signature as `permit2`. ```ts theme={null} import { TronWeb } from "tronweb"; import { preparePermit2Approval } from "@hot-pot/hotpot-sdk-ts"; const tronWeb = new TronWeb({ fullHost: "https://api.trongrid.io", privateKey, }); const userSourceAddress = tronWeb.address.fromPrivateKey(privateKey); if (!userSourceAddress) { throw new Error("The private key does not produce a valid Tron address"); } const payload = preparePermit2Approval( intent.permit2, quote, userSourceAddress, intent.deadlineSecs, ); const signature = tronWeb.trx.signTypedData( payload.domain, payload.types, payload.message, privateKey, ); ``` Submit the resulting signature to `POST /intents/{id}/approvals` in the same `{ "permit2": "..." }` shape used for EVM approvals. ### Solana Solana uses a cosigned versioned transaction. Utexo returns a hex-encoded transaction in `cosign.transaction`. The signing process must preserve signature ordering: * Resolver signature: position `0` * User signature: position `1` * Optional backend signature: position `2` ```ts theme={null} import { Keypair, VersionedTransaction } from "@solana/web3.js"; import bs58 from "bs58"; const keypair = Keypair.fromSecretKey(bs58.decode(privateKey)); const bytes = Uint8Array.from(Buffer.from(intent.cosign.transaction, "hex")); const transaction = VersionedTransaction.deserialize(bytes); const resolverSignature = transaction.signatures[0]; const backendSignature = transaction.signatures[2]; if (!resolverSignature) { throw new Error("The resolver signature is missing"); } transaction.sign([keypair]); transaction.signatures[0] = resolverSignature; if (backendSignature) { transaction.signatures[2] = backendSignature; } const signedTransaction = Buffer.from(transaction.serialize()).toString("hex"); const approval = { cosign: { transaction: signedTransaction, userAddress: keypair.publicKey.toBase58(), }, }; ``` Submit `approval` to `POST /intents/{id}/approvals`. ### Bitcoin Bitcoin uses a PSBT to authorize a Taproot HTLC deposit. 1. Confirm that `approvalMechanism` is `htlc`. 2. Read the Base64-encoded PSBT from `htlc.psbt`. 3. Read the required input indexes from `htlc.inputs`. 4. Sign only those inputs. 5. Preserve unrelated transaction data and existing partial signatures. 6. Serialize the updated PSBT in Base64 format. 7. Submit it as the `psbt` value to `POST /intents/{id}/approvals`. The following example signs the input indexes returned by `POST /intents`. ```go theme={null} package main import ( "fmt" "log" "os" "github.com/BoostyLabs/hotpot-sdk-go/crypto/bitcoin" ) type HtlcApprovalData struct { Psbt string `json:"psbt"` Inputs []int `json:"inputs"` } type IntentResponse struct { ApprovalMechanism string `json:"approvalMechanism"` IntentID string `json:"intentId"` Htlc HtlcApprovalData `json:"htlc"` } func signBitcoinApproval( intent IntentResponse, privateKeyHex string, ) (string, error) { if intent.ApprovalMechanism != "htlc" { return "", fmt.Errorf("the intent does not require HTLC approval") } signer, err := bitcoin.NewSigner(privateKeyHex) if err != nil { return "", fmt.Errorf("failed to create signer: %w", err) } signedPsbtBase64, err := bitcoin.SignDepositTx( signer, intent.Htlc.Psbt, intent.Htlc.Inputs, ) if err != nil { return "", fmt.Errorf("failed to sign deposit transaction: %w", err) } return signedPsbtBase64, nil } func main() { privateKeyHex := os.Getenv("PRIVATE_KEY") if privateKeyHex == "" { log.Fatal("PRIVATE_KEY environment variable is not set") } intent := IntentResponse{ ApprovalMechanism: "htlc", IntentID: "00000000-0000-0000-0000-000000000000", Htlc: HtlcApprovalData{ Psbt: "PSBT_BASE64_PLACEHOLDER", Inputs: []int{0, 1, 2}, }, } signedPsbtBase64, err := signBitcoinApproval(intent, privateKeyHex) if err != nil { log.Fatal(err) } fmt.Println("Signed PSBT:", signedPsbtBase64) } ``` For Taproot inputs, the signer must use the referenced UTXO data to calculate the required signature hash and produce the applicable Schnorr witness signature. # Networks and Tokens Source: https://docs.utexo.com/product-suite/swap/api/networks-and-tokens Discover Utexo Swap availability, supported networks, and supported tokens. ## Overview Use these endpoints before requesting a quote. Network and token availability can differ by environment. ### `GET /healthcheck` Checks whether the Utexo API can accept requests. **Authentication:** `X-API-Key` The endpoint accepts no path, query, or body parameters and does not support pagination. ```bash theme={null} curl -X GET \ 'BASE_URL_PLACEHOLDER/healthcheck' \ -H 'accept: application/json' \ -H 'X-API-Key: API_KEY_PLACEHOLDER' ``` A successful request returns `200 OK` with an empty body. A `503 Service Unavailable` response can return: ```json theme={null} { "code": 0, "message": "string" } ``` ### `GET /networks` Returns the blockchain networks available through Utexo. **Authentication:** `X-API-Key` | Query parameter | Type | Required | Description | | --------------- | ------ | -------- | ------------------------------------------- | | `token` | string | No | Filters networks by token contract address. | ```bash theme={null} curl -X GET \ 'BASE_URL_PLACEHOLDER/networks?token=0xdac17f958d2ee523a2206206994597c13d831ec7' \ -H 'accept: application/json' \ -H 'X-API-Key: API_KEY_PLACEHOLDER' ``` | Response field | Type | Description | | ------------------------------------------- | ------- | --------------------------------------------- | | `networks` | array | Supported blockchain networks. | | `networks[].id` | integer | Network identifier. | | `networks[].name` | string | Network name. | | `networks[].type` | enum | `EVM`, `TRON`, `BITCOIN`, or `SOLANA`. | | `networks[].iconUrl` | string | Network icon URL. | | `networks[].features` | object | Network feature settings. | | `networks[].features.supportsCustomTokens` | boolean | Whether the network supports custom tokens. | | `networks[].features.supportsOptimizedSwap` | boolean | Whether the network supports optimized swaps. | ### `GET /tokens` Returns a paginated list of tokens available for swaps. **Authentication:** `X-API-Key` | Query parameter | Type | Required | Description | | --------------- | ------- | -------- | --------------------------------------------- | | `limit` | integer | No | Maximum number of results to return. | | `offset` | integer | No | Number of results to skip. | | `q` | string | No | Searches by token symbol or contract address. | | `network-id` | integer | No | Filters tokens by network ID. | For example, request the second page of 20 results with `limit=20&offset=20`. # Quotes Source: https://docs.utexo.com/product-suite/swap/api/quotes Request resolver-based cross-chain pricing and execution constraints from Utexo Swap. ## Overview A quote is a time-limited RFQ offer used to create an intent. Do not create an intent after the quote expires. ### `POST /quote` Requests an optimal cross-chain quote for a token pair and amount. A quote remains valid until its `expiry` value. **Authentication:** `X-API-Key` | Body field | Type | Description | | ---------------------- | ------- | --------------------------------------------------------------------- | | `amount` | decimal | Source amount in decimal-adjusted token units. | | `depositType` | string | Deposit type, such as `escrowed`. | | `destChain` | integer | Destination network ID. | | `destToken` | string | Destination token address or identifier. | | `fees` | array | Affiliate fee settings. | | `fees[].affiliateName` | string | Affiliate name. | | `fees[].feeBps` | string | Affiliate fee in basis points, such as `10`. | | `retailUserId` | string | Optional retail user identifier for analytics or user-level tracking. | | `slippageBps` | string | Maximum slippage in basis points, such as `50`. | | `sourceChain` | integer | Source network ID. | | `sourceToken` | string | Source token address or identifier. | | `swapType` | string | Swap type, such as `standard`. | ```json theme={null} { "amount": 0.5, "depositType": "escrowed", "destChain": 0, "destToken": "string", "fees": [], "slippageBps": "50", "sourceChain": 0, "sourceToken": "string", "swapType": "standard" } ``` The response contains pricing, execution constraints, affiliate fee data, token amount ranges, the quote ID, and metadata required for intent creation. # Swaps Source: https://docs.utexo.com/product-suite/swap/api/swaps Retrieve swap history, inspect swap records, and interpret lifecycle states. ## Overview The Swaps API exposes historical records and detailed execution metadata for a specific intent. ### `GET /swaps` Returns a paginated list of historical swaps. **Authentication:** `X-API-Key` | Query parameter | Type | Required | Description | | --------------- | ------- | -------- | -------------------------------------------------------------------- | | `limit` | integer | No | Maximum number of results to return. | | `offset` | integer | No | Number of results to skip. | | `status` | array | No | Filters by status. Repeat the parameter for multiple values. | | `network` | integer | No | Filters by network ID. | | `from` | long | No | Start of the range as a Unix timestamp in seconds. | | `to` | long | No | End of the range as a Unix timestamp in seconds. | | `token` | string | No | Filters by token contract address. | | `wallet` | array | No | Filters by wallet address. Repeat the parameter for multiple values. | | `retail-id` | string | No | Filters by retail ID. | ```bash theme={null} curl -X GET \ 'BASE_URL_PLACEHOLDER/swaps?limit=10&offset=0&status=Initiated' \ -H 'accept: application/json' \ -H 'X-API-Key: API_KEY_PLACEHOLDER' ``` ### `GET /swaps/{id}` Returns the swap associated with an intent ID. **Authentication:** `X-API-Key` | Path parameter | Type | Required | Description | | -------------- | ------ | -------- | ------------------------- | | `id` | string | Yes | Intent ID in UUID format. | | Response field | Type | Description | | ---------------------------- | ------- | ------------------------------------------------ | | `intentId` | string | Intent ID in UUID format. | | `sourceChain` | integer | Source network ID. | | `sourceToken` | object | Source token and amount data. | | `sourceToken.address` | string | Source token address or identifier. | | `sourceToken.amountLots` | string | Source amount in token lots. | | `sourceToken.decimals` | integer | Source token decimal precision. | | `destChain` | integer | Destination network ID. | | `destToken` | object | Destination token and amount-range data. | | `destToken.address` | string | Destination token address or identifier. | | `destToken.decimals` | integer | Destination token decimal precision. | | `destToken.maxAmountLots` | string | Maximum destination amount in token lots. | | `destToken.minAmountLots` | string | Minimum destination amount in token lots. | | `fees` | array | Affiliate fee records. | | `fees[].feeAmountDecimals` | integer | Fee amount decimal precision. | | `fees[].feeAmountLots` | string | Fee amount in token lots. | | `fees[].feeBps` | string | Fee in basis points. | | `fees[].networkId` | integer | Fee network ID. | | `fees[].status` | string | Fee status. | | `fees[].subAffiliateId` | string | Associated sub-affiliate ID. | | `fees[].token` | string | Fee token. | | `metadata` | object | Transaction references and lifecycle timestamps. | | `metadata.createdAt` | string | Swap creation timestamp. | | `metadata.fulfillTx` | string | Fulfillment transaction reference. | | `metadata.fulfilledAt` | string | Fulfillment timestamp. | | `metadata.proxyAddress` | string | Proxy address. | | `metadata.refundRequestedAt` | string | Refund-request timestamp. | | `metadata.refundedAt` | string | Refund timestamp. | | `metadata.swapTx` | string | Swap transaction reference. | | `metadata.swappedAt` | string | Swap transaction timestamp. | | `metadata.userDepositTx` | string | User-deposit transaction reference. | | `metadata.userDepositedAt` | string | User-deposit timestamp. | | `status` | enum | Current swap status. | ## Status lifecycle | Status | Meaning | | ----------------- | ------------------------------------------ | | `Initiated` | Utexo created the intent. | | `ApprovalAdded` | Utexo received the required user approval. | | `Accepted` | A resolver accepted the swap. | | `Declined` | A resolver declined the swap. | | `UserDeposited` | The user deposited the source funds. | | `Fulfilled` | The resolver fulfilled the swap. | | `Expired` | The swap reached its expiration deadline. | | `RefundRequested` | The protocol recorded a refund request. | | `Refunded` | The protocol completed the refund path. | # Authorization Source: https://docs.utexo.com/product-suite/swap/integration/authorization Authenticate protected Utexo Swap API requests with the API key assigned to your integration. ## API key authentication Send the assigned API key in the `X-API-Key` request header for every protected request: ```http theme={null} X-API-Key: API_KEY_PLACEHOLDER ``` Utexo rejects requests with a missing or invalid API key. Examples use `BASE_URL_PLACEHOLDER`. Obtain the environment-specific API base URL and API key from the Utexo team before integration. The base URL includes the `/v1` version prefix. ## Request requirements Include `X-API-Key` on every protected endpoint. Utexo rejects requests with a missing or invalid key. Do not expose the API key in client-side applications or public repositories. # Integration Overview Source: https://docs.utexo.com/product-suite/swap/integration/overview Integrate Utexo Swap through the REST API, supported SDKs, and the recommended request sequence. ## Overview Partners use the REST API to request quotes, create intents, submit approvals, and monitor execution. Utexo limits protected API access to approved integration partners. ### Recommended request sequence 1. Call `GET /healthcheck` to verify API availability. 2. Discover supported networks with `GET /networks`. 3. Discover supported assets with `GET /tokens`. 4. Request pricing with `POST /quote`. 5. Create an intent with `POST /intents`. 6. Generate the approval required by `approvalMechanism`. 7. Submit the signed approval with `POST /intents/{id}/approvals`. 8. Monitor the intent and resulting swap until it reaches a terminal status. ## Resources The following integration resources are available: * Swagger and Swagger UI for endpoint discovery and direct request testing. * TypeScript, Go, and Rust SDKs. * `@hot-pot/hotpot-sdk-ts` is the legacy package namespace used by the current TypeScript Permit2 examples. Confirm with the Utexo team that this package name and supported version remain current before integrating. Obtain the current Swagger or Swagger UI URL and the supported SDK distribution links and versions from the Utexo team. # User Flow Source: https://docs.utexo.com/product-suite/swap/integration/user-flow Follow the quote, intent, approval, execution, and settlement flow used by Utexo Swap. ## Swap workflow The execution flow includes three participants: | Participant | Responsibility | | ------------ | ---------------------------------------------------------------------------------------------------------- | | **Partner** | Integrates a wallet, application, exchange, or service with the Utexo API. | | **User** | Owns the source assets, approves the swap conditions, and signs the required chain-specific authorization. | | **Resolver** | Provides liquidity and fulfills the swap under the signed intent conditions. | The user selects the source asset, destination asset, and amount. The partner calls `POST /quote`. Competing resolvers return a time-limited RFQ offer with pricing, fees, and execution constraints. After the user accepts a quote, the partner calls `POST /intents` with the quote ID and the user's source, destination, and refund addresses. Utexo returns an intent ID and the approval mechanism required by the source network. The user signs the approval data locally: * EVM and Tron use Permit2. * Bitcoin uses a Partially Signed Bitcoin Transaction (PSBT) for an HTLC deposit. * Solana uses a cosigned versioned transaction. The partner submits the signed approval with `POST /intents/{id}/approvals`. Utexo notifies the selected resolver. The resolver executes the source-chain settlement action and transfers the destination assets to the user under the signed conditions. The wallet verifies the destination settlement. The partner can monitor progress with `GET /intents/{id}/status`, `GET /swaps`, or `GET /swaps/{id}`. # Approve for Permit2 Source: https://docs.utexo.com/product-suite/swap/on-chain-helpers/approve-for-permit2 Grant the Permit2 contract sufficient ERC-20 allowance before submitting a signed intent approval. ## Overview Before submitting an off-chain Permit2 signature, grant the Permit2 contract sufficient allowance on the source ERC-20 token. The on-chain allowance transaction is separate from the signed approval submitted to the Utexo API. ```ts theme={null} import { ethers } from "ethers"; const ERC20_ABI = [ "function approve(address spender, uint256 value) external returns (bool)", ]; async function approvePermit2( tokenAddress: string, permit2Address: string, signer: ethers.Signer, ): Promise { const token = new ethers.Contract(tokenAddress, ERC20_ABI, signer); const transaction = await token.approve(permit2Address, ethers.MaxUint256); const receipt = await transaction.wait(); if (!receipt) { throw new Error("The Permit2 approval transaction did not produce a receipt"); } return receipt; } ``` Check the existing allowance before submitting a new approval transaction and wait for confirmation before signing the Permit2 payload. # Wrap Native Tokens Source: https://docs.utexo.com/product-suite/swap/on-chain-helpers/wrap-native-tokens Wrap native blockchain assets into token contracts before Utexo Swap execution. ## Overview For source inputs, Utexo Swap interacts with token contracts rather than native blockchain assets. Wrap the source asset before execution, for example, wrap ETH into WETH on Ethereum, and use the wrapped-token contract address as `sourceToken`. This requirement applies to source assets. On EVM destination chains, settlement can return native ETH by having the resolver supply WETH and the protocol unwrap it before transfer to the user. ```ts theme={null} import { ethers } from "ethers"; const WETH_ABI = ["function deposit() external payable"]; async function wrapNative( wrappedTokenAddress: string, amount: bigint, signer: ethers.Signer, ): Promise { const wrappedToken = new ethers.Contract( wrappedTokenAddress, WETH_ABI, signer, ); const transaction = await wrappedToken.deposit({ value: amount }); const receipt = await transaction.wait(); if (!receipt) { throw new Error("The wrapping transaction did not produce a receipt"); } return receipt; } ``` Confirm the wrapped-token contract address for the selected network. The wrapping transaction requires enough native currency for both the wrapped amount and network fees. # Bitcoin Settlement Source: https://docs.utexo.com/product-suite/swap/resolver-integration/bitcoin-settlement Settle Utexo Bitcoin swaps with Taproot HTLC PSBTs, script-path withdrawals, and cooperative fast refunds. Bitcoin settlement uses Taproot (P2TR) outputs and BIP 174 PSBTs. No smart contract is deployed on Bitcoin. ## HTLC lock output Every deposit locks funds to a unique Taproot output with three script leaves: | Leaf | Script | | ----------------- | ------------------------------------------------------------------------- | | Resolver withdraw | `OP_HASH256 OP_EQUALVERIFY OP_CHECKSIG` | | Timelock refund | ` OP_CLTV OP_DROP OP_CHECKSIG` | | Fast refund | ` OP_CHECKSIG OP_CHECKSIGADD 2 OP_EQUAL` | * `secretHash` is double SHA-256 of the 32-byte secret. * The internal key may be a NUMS point or a resolver-selected key, per source. * The resolver returns the refund and fast-refund control blocks to Utexo and keeps the withdraw control block internally. ## Deposit transaction ### Intent tagging Every deposit contains an `OP_RETURN` output that tags the intent: ```text theme={null} OP_RETURN ``` ### PSBT inputs | Field | Value | | ------------------ | ------------------------- | | `WITNESS_UTXO` | Required for every input. | | Sighash | `SIGHASH_ALL` (`0x01`). | | `TAP_INTERNAL_KEY` | User's x-only public key. | | Sequence | `0xFFFFFFFF` (no RBF). | ### Outputs | Index | Output | | ----- | ------------------------------------------------------------------------------------- | | `0` | `OP_RETURN` with `0` sats. | | `1` | P2TR HTLC lock. The amount is the deposit minus a proportional share of network fees. | The source states there are exactly two or three outputs, but does not define the optional third output. Do not invent change behavior; see [Validation Gaps](/product-suite/swap/resolver-integration/validation-gaps). ## Spend paths ### Key-spend path Used for deposit input signing, fulfillment, and native transfers. Witness: ```text theme={null} [schnorr_signature] ``` ### Resolver withdraw (script-path) Witness: ```text theme={null} [schnorr_signature, secret_preimage, tap_script, control_block] ``` ### Fast refund (script-path) Cooperative script-path spend co-signed by the protocol and the resolver. ### Timelock refund Script-path refund after `deadline`. The source does not document the final witness stack for the timelock refund path. Confirm with the current implementation before constructing this witness. ## Fee model The resolver computes fees from a header plus per-input and per-output costs: ```text theme={null} header = 11 vBytes size = header + sum(input_size + witness_size) * count + sum(output_size) * count fee = size * fee_rate ``` Default fee rate: `3 sat/vB`. ### Size table | Type | Input | Witness | Output | | -------------- | ----- | ------- | ------ | | P2TR | 41 | 17 | 43 | | P2WPKH | 41 | 27 | 31 | | P2SH (2-of-3) | 43 | 254 | 32 | | P2PKH | 41 | 107 | 34 | | P2WSH (2-of-3) | 41 | 64 | 43 | # EVM and Tron Settlement Source: https://docs.utexo.com/product-suite/swap/resolver-integration/evm-tron-settlement Deploy resolver executors and settle Utexo swaps on EVM chains and Tron, including single-chain, cross-chain, DEX, and fast refund paths. Utexo supports four settlement paths on EVM: * Cross-chain swap * Cross-chain swap with DEX * Single-chain atomic swap * Fast refund Users sign Permit2 approvals. The resolver submits every on-chain transaction and pays gas. ## Onboarding A protocol administrator registers each resolver in the `ResolversWhitelist` contract with: * Executor contract address * `depositAddresses` allow list * `withdrawAddresses` allow list The same resolver must own the authorized deposit and withdraw roles. The on-chain `checkSameResolver` check enforces this. ## Executor contract Each resolver deploys an Executor implementing the `IExecutor` interface: ```solidity theme={null} function fulfill( address token, uint256 minAmount, uint256 maxAmount, bytes data ) external returns (uint256 amount); function swap( address outputToken, uint256 minOutputAmount, uint256 maxOutputAmount, address inputToken, uint256 inputAmount, bytes data ) external returns (uint256 amount); function dexSwap( address outputToken, uint256 minOutputAmount, uint256 maxOutputAmount, address inputToken, uint256 inputAmount, bytes data ) external returns (uint256 amount); ``` The protocol verifies that its own ERC-20 balance increased by exactly the amount returned by `IExecutor`. ### Method responsibilities * `fulfill` transfers between `minAmount` and `maxAmount` to the caller and returns the actual transferred amount. * `swap` receives input tokens already transferred to the Executor and returns a bounded output to `EscrowRouter`. * `dexSwap` uses only deposited user tokens with non-empty routing `data`. `dexSwap` must trade the deposited user tokens through the DEX. Do not fund the output from your own treasury liquidity. ## Fulfillment contract The protocol deploys a Fulfillment contract once per resolver per destination chain. The resolver supplies: * Executor address * Authorized caller/operator addresses ## Cross-chain swap `EscrowRouter.deposit` deploys a deterministic CREATE2 proxy and transfers the user's input tokens into it using Permit2. On the destination chain, the resolver's Executor `fulfill` pays the user the destination amount within `[minAmount, maxAmount]`. After Utexo verifies fulfillment and reveals the secret, the resolver withdraws from the source-chain escrow. The source does not fully document the withdraw signature and parameters. See [Validation Gaps](/product-suite/swap/resolver-integration/validation-gaps). ## Cross-chain swap with DEX Source-chain deposit transfers the user's input token to the Executor, calls `dexSwap`, validates the output against the declared bounds, and locks the resulting `tokenOut` in the proxy. The follow-on Order then uses `tokenOut` and `minAmountOut` on the destination. ## Single-chain atomic swap `EscrowRouter.swap` atomically transfers the user's input to the Executor and sends a bounded output amount directly to the user. When the destination token is native ETH, the Executor supplies WETH and the protocol unwraps it before paying the user. ## Fast refund Backend and resolver co-sign the following EIP-712 message in the `EscrowImplementation` domain: ```text theme={null} FastRefund(bytes32 orderHash) ``` The resolver signer must match `order.resolverDeposit`. ## Tron Tron is architecturally aligned with EVM but uses TIP-712 with these differences: * No `version` field in the domain. * Domain type string: `EIP712Domain(string name,uint256 chainId,address verifyingContract)`. * `chainId` is masked with `chainId & 0xffffffff`. These rules apply to the deposit witness, fulfillment, and refund signing. # Resolver Overview Source: https://docs.utexo.com/product-suite/swap/resolver-integration/overview Understand resolver responsibilities, intent lifecycle, and how Utexo coordinates quoting, settlement, and refunds. ## What a resolver is A resolver is a permissioned liquidity provider that competes to quote user swaps on Utexo and, when assigned an intent, executes that swap end to end across the source and destination chains. Resolvers hold and route their own liquidity, sign settlement transactions, and pay gas. For the user-facing side of quotes, intents, and swaps, see the [Swap API Reference](/product-suite/swap/api/quotes). This section covers only what resolver operators must implement. ## Intents and quotes An **intent** is an off-chain user instruction containing: * Source and destination networks and tokens * Amount * Slippage tolerance * Deadline An accepted intent produces an on-chain **swap execution record** that both Utexo and the assigned resolver track through settlement. A **quote** is a resolver's response to a quote callback. Quotes are: * Time-limited by an expiry expressed in milliseconds * Bounded by a destination amount minimum and maximum * Associated with affiliate fee information supplied by Utexo * Optionally routed through an intermediate token (typically USDC) for cross-chain paths Utexo does not publish a canonical quote response schema. Return the destination bounds, expiry, and affiliate/intermediate routing data your resolver has agreed with Utexo, and validate against the current integration contract before going live. ## Lifecycles Actual signing and settlement differ by chain. See [EVM and Tron Settlement](/product-suite/swap/resolver-integration/evm-tron-settlement), [Solana Settlement](/product-suite/swap/resolver-integration/solana-settlement), and [Bitcoin Settlement](/product-suite/swap/resolver-integration/bitcoin-settlement) for chain-specific details. ### Standard escrowed swap Utexo assigns the intent to your resolver over a signed webhook. Broadcast the user-authorized deposit into the chain-specific escrow. Call `POST /v1/intents/{id}/deposit` with the deposit transaction hash. Utexo confirms the deposit and delivers the fulfillment request over webhook. Pay the destination amount to the user's destination address before the fulfillment deadline. Call `POST /v1/intents/{id}/fulfill` with the destination transaction hash. Utexo reveals the secret. Withdraw the source-chain escrow. Report the withdrawal transaction hash through the withdrawal reporting endpoint. ### Optimized single-chain swap A single atomic step. Utexo signals completion with `SwapConfirmed`; no further resolver action is required. ### Refund `RefundConfirmed` is terminal. The user has been refunded and your resolver must stop any in-flight fulfillment attempts for that intent. ## Resolver responsibilities * Maintain sufficient liquidity on every supported destination chain and token. * Return executable quotes within your agreed latency and pricing bounds. * Verify signed webhooks before acting on them. * Meet the assigned deposit and fulfillment deadlines. * Report transaction hashes in order: deposit, fulfill, then withdraw for standard swaps. * Make webhook and API processing idempotent by intent ID. * Never act on an expired or refunded intent. # Protocol API Source: https://docs.utexo.com/product-suite/swap/resolver-integration/protocol-api Endpoints resolvers call on Utexo to discover networks, retrieve intents, and report deposit, fulfillment, and withdrawal transactions. The Protocol API is the direction resolvers call **on Utexo**. Callbacks Utexo makes on the resolver are documented in the [Resolver API](/product-suite/swap/resolver-integration/resolver-api). ## Authentication Every request must include your resolver API key: ```http theme={null} X-API-Key: ``` Requests with missing or invalid keys are rejected. ## Error envelope Protocol errors use this envelope: ```json theme={null} { "code": 1, "message": "Internal server error", "entity": "Intent" } ``` ## Discovery ### `GET /v1/networks` Lists supported networks. Response items include: | Field | Description | | ------------------------- | ----------------------------------------------------------------------------- | | `id` | Numeric network identifier. | | `name` | Human-readable network name. | | `type` | Network family. | | `supports_optimized_swap` | Whether the network supports optimized single-chain swaps. | | `icon_url` | Icon asset URL. | | `supports_custom_tokens` | If `true`, the token list is not exhaustive and custom tokens may be swapped. | ### `GET /v1/tokens` Lists supported tokens. Query parameters: | Parameter | Type | Description | | ------------ | ------- | ---------------------------------- | | `limit` | integer | Page size. | | `offset` | integer | Page offset. | | `q` | string | Symbol or contract address filter. | | `network_id` | integer | Restrict to a network. | Response: ```json theme={null} { "data": [ { "network_id": "", "name": "", "contract_address": "", "symbol": "", "icon_url": "", "wrapped_token_address": null } ], "pagination": { "limit": "", "offset": "", "pages": "", "total": "" } } ``` ### `GET /v1/resolvers/webhooks/public-key` Returns the Ed25519 public key used to verify webhook signatures. ```json theme={null} { "public_key": "" } ``` ## Intents and swaps ### `GET /v1/intents/{id}` Retrieves an intent. Statuses: | Status | Meaning | | --------------- | --------------------------------------------------- | | `Initiated` | Intent created; awaiting user approval. | | `ApprovalAdded` | User approval received. | | `Accepted` | Intent accepted by the resolver and being executed. | | `Declined` | Intent declined; will not execute. | Notable fields (non-exhaustive): chain and token identifiers, source and destination addresses, `resolver_id`, `deadline`, `nonce`, amount lots and decimals, `quote_id`, `slippage_tolerance_bps`, intermediate-token bounds, `affiliate_id`, `swap_type` (`standard` or `optimized`), `resolver_deposit_address`, `deposit_type` (`escrowed` or `direct`), and lifecycle timestamps. ### `GET /v1/swaps/{intent_id}/swap` Retrieves the on-chain execution record for an intent. Notable fields: `status`, `proxy_address`, deposit/fulfill/withdraw/swap transaction hashes, intermediate-token data, and lifecycle timestamps. ## Reporting transactions Resolvers must report each on-chain step. For standard swaps, report in order: **Deposit → Fulfill → Withdraw**. ### `POST /v1/intents/{id}/deposit` ```json theme={null} { "tx_hash": "" } ``` ### `POST /v1/intents/{id}/fulfill` ```json theme={null} { "tx_hash": "", "signature": "" } ``` `signature` is optional for EVM, Solana, and Tron. It is required for Bitcoin. ### `POST /v1/intents/batch/withdraw` Batched withdrawal reporting. The source does not document the request or response schema for this endpoint. Confirm the payload with Utexo before implementing. Optimized swaps report only the `Swap` step, but the source does not document the optimized swap reporting endpoint. See [Validation Gaps](/product-suite/swap/resolver-integration/validation-gaps). ## Secret retrieval ### `GET /v1/intents/{id}/reveal-secret` ```json theme={null} { "secret": "<32-byte secret>" } ``` ### `POST /v1/intents/batch/reveal-secrets` Request: ```json theme={null} { "intent_ids": [""] } ``` Response: ```json theme={null} { "secrets": { "": "" } } ``` ## Health ### `GET /v1/system/live` * `200` — healthy * `500` — unhealthy No response body is documented. # Resolver API Source: https://docs.utexo.com/product-suite/swap/resolver-integration/resolver-api Callbacks and endpoints resolvers must expose so Utexo can request quotes, PSBTs, and co-signed settlement transactions. The Resolver API is the direction Utexo calls **on the resolver**. Each resolver defines and configures its own callback URLs; the source documentation does not prescribe paths. The source does not specify an authentication mechanism for resolver callbacks other than webhook signatures. Do not assume `X-API-Key` protects this direction. Agree the transport authentication with Utexo before exposing endpoints. ## Quote callback Utexo calls the resolver to request a quote for a user swap. ### Request fields | Field | Type | Required | Description | | ---------------- | ------- | -------- | -------------------------------------------------------------------------------- | | `source_chain` | integer | yes | Source network ID. | | `source_token` | string | yes | Source token identifier. | | `dest_chain` | integer | yes | Destination network ID. | | `dest_token` | string | yes | Destination token identifier. | | `amount` | string | yes | Amount in decimal-adjusted format. | | `slippage_bps` | string | yes | Slippage tolerance in basis points, range `0..10000`. | | `swap_type` | string | yes | `standard` or `optimized`. | | `affiliate_id` | string | yes | Affiliate identifier. | | `retail_user_id` | string | no | Optional retail user identifier. | | `affiliate_fees` | object | no | Keyed by sub-affiliate ID; each entry contains `fee_bps`, `network_id`, `token`. | | `deposit_type` | string | yes | `escrowed` or `direct`. | ### Response The source describes expected destination minimum and maximum, expiry in milliseconds, and affiliate and intermediate routing data, but does not publish a canonical quote response schema. Confirm the exact shape with Utexo. ### Error responses Use `400` for invalid or unsupported requests and `500` for unexpected resolver failures. Envelope: ```json theme={null} { "error_code": 1, "msg": "swap amount is below the minimum threshold" } ``` | Code | Constant | | ---- | -------------------------------- | | `0` | `INTERNAL_SERVER_ERROR` | | `1` | `SWAP_AMOUNT_TOO_SMALL` | | `2` | `SWAP_AMOUNT_TOO_LARGE` | | `3` | `UNSUPPORTED_SOURCE_NETWORK` | | `4` | `UNSUPPORTED_DEST_NETWORK` | | `5` | `UNSUPPORTED_SOURCE_TOKEN` | | `6` | `UNSUPPORTED_DEST_TOKEN` | | `7` | `INVALID_SLIPPAGE_TOLERANCE_BPS` | ## Bitcoin deposit PSBT callback Utexo requests a PSBT for the user's Bitcoin deposit. ### Request | Field | Description | | ------------------ | --------------------------------- | | `intent_id` | Intent identifier. | | `quote_id` | Quote identifier. | | `protocol_pub_key` | Protocol public key for the HTLC. | | `user_address` | User's Bitcoin address. | | `user_pub_key` | User's public key. | | `secret_hash` | Double SHA-256 secret hash. | | `deadline` | Refund timelock deadline. | | `deposit_type` | `escrowed`. | ### Response | Field | Description | | --------------------------- | ------------------------------------------- | | `psbt` | Base64-encoded PSBT. | | `x_only_public_key` | Taproot x-only key. | | `refund_control_block` | Control block for the timelock refund leaf. | | `fast_refund_control_block` | Control block for the fast refund leaf. | `x_only_public_key`, `refund_control_block`, and `fast_refund_control_block` are only meaningful for `deposit_type=escrowed`. ## Solana co-signed transaction callback Utexo asks the resolver to co-sign a Solana transaction. ### Request `request_type` is one of: * `DepositSwap` * `Fulfill` * `WithdrawToUser` Source fields: * `intent_id` * `quote_id` * `user_address` * `nonce` * `resolver_deposit` * `token_in` * `token_out` * `secret_hash` * `amount_in` * `deadline` * `resolver_id` * `intermediate_token_out` and its bounds (optional) * `min_amount_out` * `max_amount_out` * `swap_type` * `recent_blockhash` (optional) * `deposit_type` = `escrowed` ### Response The source does not document the Solana co-signed callback response schema. Confirm the response shape with Utexo before implementing. ## Fast-refund signing callback Utexo requests a resolver signature for a fast refund. ### Request | Field | Description | | ----------- | -------------------------------------------------------------- | | `intent_id` | Intent identifier. | | `chain` | Source chain identifier. | | `btc_data` | Object containing `psbt`, `tapscipt`, and `input` for Bitcoin. | ### Response ```json theme={null} { "signature": "" } ``` The source spells the Bitcoin script field `tapscipt`. This appears to be a typo of `tapscript` and must be validated against the current implementation before you wire it up. # Solana Settlement Source: https://docs.utexo.com/product-suite/swap/resolver-integration/solana-settlement Settle Utexo swaps on Solana using unified vault PDAs, packed DEX instructions, and co-signed deposit, fulfill, and withdraw transactions. Solana settlement uses program-derived addresses (PDAs) and horizontally packed instructions. No Executor or Fulfillment contract is deployed; resolvers interact directly with the Utexo program. ## Onboarding A protocol administrator registers each resolver in the `ProtocolState` PDA with: * Executor/admin authority `Pubkey` * Authorized deposit and withdraw addresses ## Accounts ### Unified vault PDA ```text theme={null} seeds = ["vault", token_mint] ``` Pools escrowed tokens of the same mint in one vault. Deposits increase its balance; withdrawals, refunds, and fulfillments decrease it. ### `EscrowCheck` PDA ```text theme={null} seeds = ["escrow", order_hash] ``` Stores order, intent, resolver, deposit authority, user, mint, amount, secret hash, nonce, and deadline. ### `FulfilledIntent` PDA ```text theme={null} seeds = ["fulfilled", intent_id] ``` Provides replay protection for fulfillment. The PDA is closable after a seven-day grace period to reclaim rent through the single or batch close instructions. ## Cross-chain swap ### Deposit * **Signers:** user + `resolver_deposit_address`. * Uses the accounts and parameters supplied in the co-signed deposit transaction. ### Fulfill * **Signers:** `caller_authority` + `backend_signer`. * Fulfillment amount must be in `[min_amount, min(max_amount, resolver_max_amount)]`. ### Withdraw * **Signer:** `resolver_withdraw_address`. * Requires the full order and revealed secret. Closes the `EscrowCheck` PDA on success. ## Horizontal packing with DEX Solana settlements pack protocol instructions around resolver-supplied DEX instructions inside a single atomic transaction. Ordering is strict. ### Deposit with DEX ```text theme={null} deposit_dex_start -> resolver DEX instructions deposit_dex_finish ``` Intermediary DEX instructions must not reference the user's public key. ### Fulfill with DEX ```text theme={null} fulfill_start -> resolver instructions fulfill_finish // or fulfill_finish_native for native SOL ``` Use `fulfill_finish_native` when paying out native SOL. ## Single-chain atomic swap * **Signers:** user + `resolver_deposit_address` + `backend_signer`. ### DEX path ```text theme={null} swap_start -> resolver instructions swap_finish // or swap_finish_native for native SOL ``` ## Fast refund Fast refund is co-signed by `backend_signer` and `resolver_deposit_address`. The resolver signer must match the `resolver_deposit_authority` stored in the `EscrowCheck` PDA. # Validation Gaps Source: https://docs.utexo.com/product-suite/swap/resolver-integration/validation-gaps Open items and undocumented behaviors in the resolver integration source that must be resolved before this section is implementation-complete. This page is an internal-review checklist. It is **not implementation-complete** and must be reconciled with the current Utexo implementation, OpenAPI, and resolver SDK before publishing to external resolvers. ## Missing environments and paths * **Environment and base URLs** for the Protocol API are absent from the source. * **Resolver callback paths** and any callback authentication outside signed webhooks are absent. ## Undocumented schemas * **Canonical quote response schema** is absent, even though the source prose describes destination minimum/maximum, expiry in milliseconds, affiliate fee data, and intermediate-token routing. * **`POST /v1/intents/batch/withdraw`** request and response schemas are absent. * **Optimized Swap transaction-reporting endpoint** is not documented; only the ordered reporting for standard swaps is specified. * **Solana co-signed callback response** schema is absent. ## Partial chain coverage * The **EVM cross-chain source** stops before detailed fulfill and withdraw parameter coverage. * The **Bitcoin PSBT source** says a deposit has exactly two or three outputs but does not define the optional third output or change handling. ## Field-level issues * The Bitcoin fast-refund signing callback uses the field name **`tapscipt`**. This is preserved verbatim from the source but appears to be a typo of `tapscript`. Confirm the spelling against the implementation before wiring. * **Webhook timestamp acceptance and replay window** is not documented. Confirm the acceptable freshness window with Utexo before enforcing it. ## Documentation hygiene * **Swagger and resolver SDK links** are missing or placeholders in the source. * Example addresses in the **legacy quote page** mix network formats and should not be reused as normative examples on any resolver page. ## Freshness Several source pages are partial and were last modified approximately four months before this port. Validate every claim on the Resolver Integration pages against current code and the OpenAPI specification before publishing. # Webhooks and Lifecycle Source: https://docs.utexo.com/product-suite/swap/resolver-integration/webhooks-and-lifecycle Verify Utexo signed webhooks and act on the intent lifecycle events that drive resolver settlement. Utexo notifies resolvers of lifecycle transitions through signed webhook events. Webhook events are separate from the transaction-reporting calls resolvers make through the [Protocol API](/product-suite/swap/resolver-integration/protocol-api). ## Envelope Every event uses the same envelope: ```json theme={null} { "type": "IntentAssigned", "data": { } } ``` ## Signature verification Each request carries two headers: | Header | Value | | ------------- | ------------------------------ | | `X-Signature` | Hex-encoded Ed25519 signature. | | `X-Timestamp` | Unix timestamp string. | Verify the signature over the concatenation `timestamp_bytes + raw_body_bytes` using the public key returned by [`GET /v1/resolvers/webhooks/public-key`](/product-suite/swap/resolver-integration/protocol-api). * Verify against the **raw request bytes** before JSON parsing. Re-serialization changes the signed payload. * Reject any request with an invalid signature. * Enforce a timestamp freshness and replay window. The acceptable window is not documented in the source; confirm the exact policy with Utexo. * Use the event type and intent identifier (`id` or `intent_id`, depending on the event) as the idempotency key, and persist processed lifecycle transitions. ## Events ### `IntentAssigned` The intent has been assigned to your resolver. **Data fields:** `id`, `secret_hash`, `user_source_address`, `user_destination_address`, `user_approval` (approval mechanism and chain-specific data), `deadline`, `quote_id`, `deposit_type`, `signature_details`. **Action:** validate the deadline and assignment, then begin constructing and broadcasting the source-chain deposit. ### `DepositConfirmed` The source-chain deposit is confirmed and Utexo is releasing the fulfillment request. **Data fields:** `intent_id`, `deposit_tx`, `fulfillment_deadline`, `fulfillment_signature`, `cosign_transaction`, `fulfillment_request` containing `intent_id`, `user_destination_address`, `to_token`, `min_amount`, `max_amount`, `deadline`. **Action:** execute fulfillment on the destination chain before `fulfillment_deadline`, then report through `POST /v1/intents/{id}/fulfill`. ### `WithdrawReady` Fulfillment has been verified and the secret is available. **Data fields:** `intent_id`, `secret`. **Action:** withdraw the escrowed source-chain funds using the revealed secret, then report the withdrawal transaction hash. ### `SwapConfirmed` Terminal event for optimized single-chain swaps. **Data fields:** `intent_id`, `swap_tx`. **Action:** none. The swap is complete. ### `RefundConfirmed` Terminal event for refunded intents. **Data fields:** `intent_id`, `refund_tx`. **Action:** stop any in-flight fulfillment for this intent. ## Flow overview ### Standard escrowed swap ```text theme={null} IntentAssigned -> deposit tx (resolver broadcasts) -> POST /v1/intents/{id}/deposit DepositConfirmed -> fulfill tx (resolver broadcasts) -> POST /v1/intents/{id}/fulfill WithdrawReady (secret revealed) -> withdraw tx (resolver broadcasts) -> withdrawal reporting ``` ### Optimized single-chain swap ```text theme={null} IntentAssigned -> swap tx (resolver broadcasts) -> swap reporting SwapConfirmed (terminal) ``` ### Refund ```text theme={null} RefundConfirmed (terminal) -> stop fulfillment attempts ``` Webhook events signal state transitions. Transaction reporting through the Protocol API is what advances the intent through those transitions. Treat them as two separate channels. # Swap Security Model Source: https://docs.utexo.com/product-suite/swap/security-model Understand escrow isolation, resolver permissions, settlement conditions, and refund paths. ## Overview Utexo does not hold user funds in custody. Signed intent parameters, deterministic protocol rules, and chain-specific settlement mechanisms control asset movement throughout execution. ### Resolver permissions A resolver can: * Transfer user-approved assets into the settlement mechanism associated with the swap. * Execute the swap under the signed intent parameters. * Withdraw escrowed assets only after fulfillment verification confirms compliance with the swap conditions. A resolver cannot: * Withdraw escrowed assets before fulfillment verification. * Access assets associated with another swap. * Transfer user assets outside the authorized execution flow. * Modify the conditions defined in the signed intent. If execution does not complete within the applicable time constraints, the swap enters its network-specific refund or revert path. ## Architecture and settlement Utexo uses cryptographic time constraints and network-native escrow mechanisms to coordinate cross-chain settlement. | Network | Settlement mechanism | | ------------------------------- | ----------------------------------------------- | | Bitcoin | Taproot hash time-locked contract (HTLC) escrow | | Ethereum and other EVM networks | Dedicated escrow smart contract per swap | | Solana | Program escrow | | Tron | Contract escrow | Each swap uses an isolated settlement mechanism. Ethereum, other EVM networks, and Tron use a dedicated escrow instance for each swap. Swap-level isolation prevents funds associated with one swap from being exposed to another. Resolvers provide liquidity and perform the on-chain operations required to fulfill signed intents. Protocol rules restrict a resolver to the assets, amount, destination, and time constraints authorized by the user. # RGB Lightning Node API Source: https://docs.utexo.com/rgb-lightning-node/rgb-lightning-node-api REST JSON API reference for interacting with running RGB Lightning Node instances. ## Overview A running RGB Lightning Node (RLN) exposes a REST JSON API that can be called directly to perform Lightning and RGB operations: channel management, asset issuance, payments, peer connections and more. The endpoint reference below applies to nodes managed by Utexo Cloud and to self-hosted nodes; the connection and authentication settings differ and are covered separately. Available endpoints and request schemas follow the RLN release a node is running — check the OpenAPI specification for your version. ### Base URL — Utexo Cloud Each node has a unique endpoint URL visible on its dashboard page (`/nodes/{nodeId}`). Connections can be made via mTLS or API token. See [Connect to RLN Node](/cloud/rln-node/connect-rln-node) for details. ```bash theme={null} curl -X POST \ -H "Content-type: application/json" \ -d '{"ticker": "USDT", "name": "Tether", "amounts": [666], "precision": 0}' \ https://{userId}.thunderstack.org/nodes/{userId}/{nodeId}/issueassetnia ``` ### Base URL — self-hosted The API listens on the port passed to `--daemon-listening-port` (default `3001`). Authenticate with a Biscuit token — see [Authentication](/rgb-lightning-node/self-hosted-rgb-lightning-node#authentication) for issuing and revoking tokens. ```bash theme={null} curl -X POST \ -H "Content-type: application/json" \ -H "Authorization: Bearer " \ -d '{"ticker": "USDT", "name": "Tether", "amounts": [666], "precision": 0}' \ http://localhost:3001/issueassetnia ``` ## Available Endpoints The node exposes the following REST endpoints, all using `POST` unless noted: ### Wallet & Balances | Endpoint | Method | Description | | --------------- | ------ | ------------------------------- | | `/address` | POST | Generate a new on-chain address | | `/btcbalance` | POST | Get BTC balance | | `/assetbalance` | POST | Get RGB asset balance | | `/listunspents` | POST | List unspent outputs | | `/createutxos` | POST | Create UTXOs for RGB use | ### Asset Management | Endpoint | Method | Description | | ------------------- | ------ | ---------------------------------- | | `/issueassetnia` | POST | Issue a NIA (non-inflatable) asset | | `/issueassetcfa` | POST | Issue a CFA (collectible) asset | | `/issueassetuda` | POST | Issue a UDA (unique digital asset) | | `/listassets` | POST | List all RGB assets | | `/assetmetadata` | POST | Get metadata for an asset | | `/getassetmedia` | POST | Retrieve asset media | | `/postassetmedia` | POST | Upload asset media | | `/sendrgb` | POST | Send RGB assets on-chain | | `/listtransfers` | POST | List RGB transfers | | `/refreshtransfers` | POST | Refresh pending transfers | | `/failtransfers` | POST | Mark transfers as failed | ### Payments & Invoices | Endpoint | Method | Description | | ------------------- | ------ | -------------------------- | | `/lninvoice` | POST | Create a Lightning invoice | | `/rgbinvoice` | POST | Create an RGB invoice | | `/decodelninvoice` | POST | Decode a Lightning invoice | | `/decodergbinvoice` | POST | Decode an RGB invoice | | `/invoicestatus` | POST | Check invoice status | | `/sendpayment` | POST | Send a Lightning payment | | `/keysend` | POST | Send a keysend payment | | `/listpayments` | GET | List all payments | | `/listtransactions` | POST | List on-chain transactions | ### Channels | Endpoint | Method | Description | | --------------- | ------ | ------------------------- | | `/openchannel` | POST | Open a Lightning channel | | `/closechannel` | POST | Close a Lightning channel | | `/listchannels` | GET | List all channels | | `/getchannelid` | POST | Get channel ID | ### Peers & Network | Endpoint | Method | Description | | --------------------- | ------ | ---------------------------- | | `/connectpeer` | POST | Connect to a peer | | `/disconnectpeer` | POST | Disconnect from a peer | | `/listpeers` | GET | List connected peers | | `/networkinfo` | GET | Get network information | | `/nodeinfo` | GET | Get node information | | `/checkindexerurl` | POST | Verify indexer URL | | `/checkproxyendpoint` | POST | Verify proxy endpoint | | `/estimatefee` | POST | Estimate transaction fee | | `/signmessage` | POST | Sign a message with node key | | `/sendonionmessage` | POST | Send an onion message | ### Swaps | Endpoint | Method | Description | | --------------- | ------ | ------------------------- | | `/makerinit` | POST | Initialize as swap maker | | `/makerexecute` | POST | Execute swap as maker | | `/taker` | POST | Participate as swap taker | | `/listswaps` | GET | List all swaps | ### Node Lifecycle | Endpoint | Method | Description | | ----------------- | ------ | ------------------------------ | | `/init` | POST | Initialize node after creation | | `/unlock` | POST | Unlock node with password | | `/lock` | POST | Lock node | | `/changepassword` | POST | Change node password | | `/backup` | POST | Trigger a node backup | | `/restore` | POST | Restore node from backup | | `/sync` | POST | Sync node state | | `/shutdown` | POST | Shut down the node | ## Full API Reference For complete parameter definitions and response schemas, see the OpenAPI specification and interactive Swagger UI: [https://utexo-protocol.github.io/rgb-lightning-node](https://utexo-protocol.github.io/rgb-lightning-node) # Self-Hosted RGB Lightning Node Source: https://docs.utexo.com/rgb-lightning-node/self-hosted-rgb-lightning-node Run one self-hosted RGB Lightning Node for on-chain RGB operations and RGB-enabled Lightning payments. The RGB Lightning Node (RLN) is Utexo's self-hosted runtime for both direct, on-chain RGB operations and RGB-enabled Lightning payments. A single RLN daemon and REST API provides both paths, so integrators do not need a second on-chain node service. Utexo supports on-chain RGB operations on mainnet. Lightning functionality is beta and testnet-only for now. Test your deployment on regtest or testnet before handling mainnet funds. The maintainers take no responsibility for loss of funds. Source repository: [https://github.com/UTEXO-Protocol/rgb-lightning-node](https://github.com/UTEXO-Protocol/rgb-lightning-node) Full OpenAPI / Swagger reference: [https://utexo-protocol.github.io/rgb-lightning-node](https://utexo-protocol.github.io/rgb-lightning-node) ## One node, two execution paths | Path | RLN capabilities | Current Utexo support | | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | | **On-chain RGB** | Issue assets, create RGB invoices, transfer assets directly on Bitcoin, and inspect balances, transactions, transfers, and UTXOs | **Mainnet**; also available in test environments | | **RGB over Lightning** | Connect peers, open RGB channels, create invoices, and send or route payments through Lightning | **Testnet only**; beta | The `--network` option selects the Bitcoin network for the entire node. It does not change Utexo's support policy: use a mainnet deployment for on-chain RGB operations only. On testnet, you can exercise both the on-chain and Lightning paths through the same integration. ## Prerequisites Before starting, make sure you have the following available: | Dependency | Purpose | | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | | [**bitcoind**](https://github.com/bitcoin/bitcoin/tree/master/doc) or [Esplora](https://github.com/Blockstream/esplora) | Chain backend used for Lightning chain synchronization | | [**Electrum**](https://github.com/romanz/electrs) or [Esplora](https://github.com/Blockstream/esplora) indexer | Indexer forwarded to `rgb-lib` for RGB wallet operations | | **RGB Proxy Server** | Relay for RGB state transitions (see [rgb-proxy-server](https://github.com/RGB-Tools/rgb-proxy-server)) | | **Rust toolchain** (stable) | Needed to build from source | | **Docker** (optional) | For the containerized setup and regtest helper scripts | The `/unlock` request selects one Lightning chain backend: provide all four `bitcoind_rpc_*` fields, or provide `indexer_url` without bitcoind fields to use Esplora or Electrum. When bitcoind is the chain backend, an optional Electrum `indexer_url` can still be forwarded to `rgb-lib`. Do not combine bitcoind fields with an Esplora URL; RLN rejects that configuration as ambiguous. ## Installation ### Build from Source Clone the repository with its submodules: ```sh theme={null} git clone https://github.com/UTEXO-Protocol/rgb-lightning-node \ --recurse-submodules --shallow-submodules ``` Install the `rgb-lightning-node` binary: ```sh theme={null} cargo install --locked --path . ``` ### Docker Image Build the Docker image locally: ```sh theme={null} docker build -t rgb-lightning-node . ``` ## Running the Node Each RLN daemon is started with `rgb-lightning-node` and requires the following arguments: | Flag | Description | | --------------------------- | ------------------------------------------------------------------------------- | | `` | Directory where node state is persisted | | `--daemon-listening-port` | Port for the REST API | | `--ldk-peer-listening-port` | Port for Lightning peer connections | | `--network` | One of `regtest`, `signet`, `signetcustom`, `testnet`, `testnet4`, or `mainnet` | | `--disable-authentication` | Skip token auth (development only) | | `--root-public-key` | Public key used to verify Biscuit tokens (production) | ### Regtest (Local Development) Start the required Docker services (bitcoind, electrs, proxy): ```sh theme={null} ./regtest.sh start ``` Launch three nodes in separate shells: ```sh theme={null} # Shell 1 rgb-lightning-node dataldk0/ \ --daemon-listening-port 3001 \ --ldk-peer-listening-port 9735 \ --network regtest \ --disable-authentication # Shell 2 rgb-lightning-node dataldk1/ \ --daemon-listening-port 3002 \ --ldk-peer-listening-port 9736 \ --network regtest \ --disable-authentication # Shell 3 rgb-lightning-node dataldk2/ \ --daemon-listening-port 3003 \ --ldk-peer-listening-port 9737 \ --network regtest \ --disable-authentication ``` **Regtest unlock parameters:** ```text theme={null} bitcoind_rpc_username: user bitcoind_rpc_password: password bitcoind_rpc_host: localhost bitcoind_rpc_port: 18443 indexer_url: 127.0.0.1:50001 proxy_endpoint: rpc://127.0.0.1:3000/json-rpc ``` #### Regtest Helper Commands ```sh theme={null} # Fund a node — first get an address via POST /address, then: ./regtest.sh sendtoaddress
# Mine blocks ./regtest.sh mine # Stop services and clean data ./regtest.sh stop # Full help ./regtest.sh -h ``` ### Regtest with Docker To run a node inside Docker while using the shared regtest network: ```sh theme={null} docker run \ --rm -it \ -p 3001:3001 \ -v RLNdata1:/RLNdata \ --network rgb-lightning-node_default \ rgb-lightning-node \ --daemon-listening-port 3001 \ --ldk-peer-listening-port 9735 \ --network regtest \ --disable-authentication \ RLNdata ``` Data is persisted in the `RLNdata1` volume. To start fresh: ```sh theme={null} docker volume rm RLNdata1 ``` When unlocking a node in this mode use: ```text theme={null} bitcoind_rpc_host: bitcoind bitcoind_rpc_port: 18443 indexer_url: electrs:50001 proxy_endpoint: rpc://proxy:3000/json-rpc ``` ### Testnet3 No local Docker services needed — the node uses public infrastructure: ```sh theme={null} rgb-lightning-node dataldk0/ \ --daemon-listening-port 3001 \ --ldk-peer-listening-port 9735 \ --network testnet \ --disable-authentication ``` **Testnet3 unlock parameters:** ```text theme={null} bitcoind_rpc_username: user bitcoind_rpc_password: password bitcoind_rpc_host: electrum.iriswallet.com bitcoind_rpc_port: 18332 indexer_url: ssl://electrum.iriswallet.com:50013 proxy_endpoint: rpcs://proxy.iriswallet.com/0.2/json-rpc ``` ### Testnet4 Same as testnet3, with the following differences: ```text theme={null} --network testnet4 bitcoind_rpc_port: 18443 indexer_url: ssl://electrum.iriswallet.com:50053 ``` ## On-chain RGB operations The on-chain path uses the same RLN process and authentication model as the Lightning path. Use the following REST endpoints instead of integrating a separate on-chain service: | Operation | Endpoints | | ------------------------------ | ------------------------------------------------------------------------------------------ | | Prepare the wallet | `POST /address`, `POST /btcbalance`, `POST /createutxos`, `POST /listunspents` | | Issue assets | `POST /issueassetnia`, `POST /issueassetcfa`, `POST /issueassetifa`, `POST /issueassetuda` | | Receive and inspect RGB assets | `POST /rgbinvoice`, `POST /decodergbinvoice`, `POST /listassets`, `POST /assetbalance` | | Transfer and track RGB assets | `POST /sendrgb`, `POST /listtransfers`, `POST /refreshtransfers`, `POST /failtransfers` | | Inspect on-chain activity | `POST /listtransactions` | | Back up or restore node state | `POST /backup`, `POST /restore` | RLN does not use xPub request headers or a client-side `*begin`/`*end` PSBT flow. Authenticate to RLN with Biscuit tokens as described below. If your custody model requires an external signer, see [Remote Signer](/security/rln-remote-signer); support remains experimental and requires deployment-specific validation. For complete request and response schemas, see the [RGB Lightning Node API](/rgb-lightning-node/rgb-lightning-node-api). ## Authentication RLN uses [Biscuit tokens](https://www.biscuitsec.org/) for API authentication. For production deployments **never** use `--disable-authentication`. ### One-Time Setup Install the Biscuit CLI and generate a root keypair: ```sh theme={null} cargo install biscuit-cli # Generate a keypair (prints both public and private keys) biscuit keypair # Or export only the private key to a file biscuit keypair --only-private-key > private-key-file # Derive the public key later biscuit keypair --from-file private-key-file --only-public-key ``` Store your private key in a secret manager (e.g. HashiCorp Vault, AWS Secrets Manager). Anyone with the private key can mint valid tokens. Start the node with the public key: ```sh theme={null} rgb-lightning-node dataldk0/ \ --daemon-listening-port 3001 \ --ldk-peer-listening-port 9735 \ --network testnet \ --root-public-key ``` ### Minting Tokens Three built-in roles are available: **Admin** (full access): ```sh theme={null} echo 'role("admin");' \ | biscuit generate --private-key-file private-key-file - ``` **Read-only** (GET endpoints only): ```sh theme={null} echo 'role("read-only");' \ | biscuit generate --private-key-file private-key-file - ``` **Custom** (specific endpoints only): ```sh theme={null} echo 'role("custom"); right("api", "/nodeinfo"); right("api", "/networkinfo");' \ | biscuit generate --private-key-file private-key-file - ``` Add an expiry date to any token. Replace the timestamp with your own — the node rejects a token once its expiry has passed: ```sh theme={null} echo 'role("admin"); check if time($t), $t <= 2027-12-31T00:00:00Z;' \ | biscuit generate --private-key-file private-key-file - ``` For short-lived tokens, generate the timestamp at issue time rather than hardcoding it — `date -u -d '+30 days' +%Y-%m-%dT%H:%M:%SZ` with GNU coreutils, or `date -u -v+30d +%Y-%m-%dT%H:%M:%SZ` on macOS. ### Using Tokens Pass the token in the `Authorization` header: ```sh theme={null} curl -H "Authorization: Bearer " \ http://localhost:3001/nodeinfo ``` In the Swagger UI click the **Authorize** (lock) button, paste the token, and click **Authorize**. ### Revoking Tokens To revoke a token before its expiry: ```sh theme={null} curl -X POST \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"token": ""}' \ http://localhost:3001/revoketoken ``` ## Using the REST API Once a daemon is running, interact with it via its REST API. Example — issue an RGB asset: ```bash theme={null} curl -X POST \ -H "Content-Type: application/json" \ -d '{"ticker": "USDT", "name": "Tether", "amounts": [666], "precision": 0}' \ http://localhost:3001/issueassetnia ``` ### Key Endpoints | Endpoint | Method | Description | | ---------------- | ------ | -------------------------------- | | `/init` | POST | Initialise and unlock the node | | `/unlock` | POST | Unlock a locked node | | `/lock` | POST | Lock the node | | `/nodeinfo` | GET | Return node identity and status | | `/networkinfo` | GET | Return network-level info | | `/btcbalance` | POST | Get on-chain BTC balance | | `/address` | POST | Generate a new Bitcoin address | | `/openchannel` | POST | Open an RGB payment channel | | `/closechannel` | POST | Close a channel | | `/listchannels` | GET | List all channels | | `/connectpeer` | POST | Connect to a Lightning peer | | `/listpeers` | GET | List connected peers | | `/lninvoice` | POST | Create a Lightning invoice | | `/sendpayment` | POST | Pay a Lightning invoice | | `/rgbinvoice` | POST | Create an RGB invoice | | `/sendrgb` | POST | Send RGB assets on-chain | | `/issueassetnia` | POST | Issue a new NIA RGB asset | | `/issueassetcfa` | POST | Issue a CFA RGB asset | | `/listassets` | POST | List all RGB assets | | `/assetbalance` | POST | Get balance of a specific asset | | `/backup` | POST | Create an encrypted backup | | `/restore` | POST | Restore from an encrypted backup | | `/shutdown` | POST | Gracefully stop the daemon | The complete list of endpoints with request/response schemas is available in the interactive Swagger UI at [https://utexo-protocol.github.io/rgb-lightning-node](https://utexo-protocol.github.io/rgb-lightning-node). ### Running a Local Swagger UI You can also expose the OpenAPI spec locally: ```sh theme={null} docker run -it \ -p 8246:8080 \ -e SWAGGER_JSON=/var/specs/openapi.yaml \ -v $PWD/openapi.yaml:/var/specs/openapi.yaml \ swaggerapi/swagger-ui ``` Open `http://localhost:8246` in your browser. If a daemon is running on one of the example ports you can call the APIs directly from the UI. ## Running Tests Integration tests use the same regtest services as `regtest.sh` (they cannot run simultaneously): ```sh theme={null} cargo test ``` ## Production Checklist Store the Biscuit issuer private key in a dedicated secret manager. Never commit it to version control. Remove `--disable-authentication` and pass `--root-public-key` when starting the daemon. Expose only the daemon REST port (default `3001`) to trusted clients. Firewall the LN peer port (`9735`) as appropriate. Mount the node data directory on durable storage (e.g. a named Docker volume or a cloud disk) to survive container restarts. Poll `GET /nodeinfo` and `GET /networkinfo` periodically to verify the node is reachable and in sync. Call `POST /backup` on a schedule and store the encrypted backup off-node. Issue short-lived tokens with expiry dates and rotate them regularly. Revoke compromised tokens immediately via `POST /revoketoken`. ## References * [UTEXO RGB Lightning Node repository](https://github.com/UTEXO-Protocol/rgb-lightning-node) * [OpenAPI Swagger UI](https://utexo-protocol.github.io/rgb-lightning-node) * [RGB on the Lightning Network — docs.rgb.info](https://docs.rgb.info/lightning-network-compatibility) * [RGB Proxy Server](https://github.com/RGB-Tools/rgb-proxy-server) * [Biscuit token specification](https://www.biscuitsec.org/) # React Native SDK Reference Source: https://docs.utexo.com/sdk/react-native-sdk Reference for @utexo/rgb-sdk-rn — on-device Lightning node, RGB assets, and Lightning payments for iOS and Android. The `@utexo/rgb-sdk-rn` package is the React Native SDK for iOS and Android. It embeds a full **RGB Lightning Node (RLN)** on-device — a native LDK node that runs locally. React Native (iOS and Android) only. New Architecture (TurboModule `Rgb`) is required. For Node.js use [`@utexo/wdk-rgb-lightning`](/sdk/wdk-rgb-lightning); for browsers use [`@utexo/rgb-sdk-web`](/sdk/web-sdk). Beta release — APIs may change between releases. ## What You Can Do * Run a full Lightning node on-device via RLN * Open Lightning channels and send/receive BTC or RGB asset payments * LSP integration: receive RGB via Lightning, send RGB to on-chain recipients, Lightning Address * Async payments (APay) and virtual channels * Issue, transfer, and manage RGB assets (NIA, CFA, IFA, UDA) * Manage UTXOs and on-chain BTC sends * Use a hardware-wallet-style **external signer** or a **password signer** * Restart the node on the same `UTEXOWallet` instance without recreating it * VSS encrypted remote backup of LDK state ## Installation ```bash theme={null} npm install @utexo/rgb-sdk-rn ``` ### iOS Setup The native framework (`RGBLightningNode.xcframework`) is downloaded during `postinstall`. ```bash theme={null} cd ios && pod install ``` ### Android Setup Requires `minSdkVersion` 24. The native binding (`com.utexo:rgb-lightning-node-android`) resolves from Maven Central — no extra repository configuration. At unlock time the node needs an Electrum indexer and/or bitcoind RPC, plus an RGB proxy. Known networks supply defaults. ## Primary Class: `UTEXOWallet` `UTEXOWallet` implements `IUTEXOProtocol`, owns the on-device RLN lifecycle, and abstracts both signer types. The mnemonic and password live on the signer, not on the config object. ### Construction ```typescript theme={null} import { UTEXOWallet, NativeExternalRLNSigner, PasswordRLNSigner, generateKeys, type UTEXOWalletNodeParams, } from '@utexo/rgb-sdk-rn'; const keys = await generateKeys('regtest'); const wallet = new UTEXOWallet( { storageDirPath: '/path/to/node-storage', daemonListeningPort: 9735, ldkPeerListeningPort: 9736, network: 'regtest', }, new NativeExternalRLNSigner(keys.mnemonic, 'regtest'), ); ``` xpubs and master fingerprint are **not** constructor fields. The signer supplies key material at `init()`. #### `UTEXOWalletNodeParams` | Field | Type | Description | | ------------------------- | ------------------- | --------------------------------------------------------------------------------------------------------- | | `storageDirPath` | `string` | Directory where the node persists its data | | `daemonListeningPort` | `number` | RLN daemon HTTP port | | `ldkPeerListeningPort` | `number` | LDK peer-to-peer port | | `network` | `string` | Bitcoin network (`'utexo'`, `'regtest'`, `'testnet'`, `'mainnet'`, …) | | `maxMediaUploadSizeMb` | `number?` | Max media upload size in MB (default 20) | | `enableVirtualChannelsV0` | `boolean?` | Enable virtual channels | | `virtualPeerPubkeys` | `string[]? \| null` | Host pubkeys allowed to open inbound virtual channels. `null`/`[]` = accept from anyone | | `vssUrl` | `string? \| null` | VSS server URL for encrypted remote backup | | `vssAllowHttp` | `boolean?` | Allow plain HTTP VSS (default `false`) | | `vssAllowEmptyRestore` | `boolean?` | Allow restore when no VSS backup exists yet (default `false`) | | `lspBaseUrl` | `string? \| null` | LSP base URL for `createLsp()` and APay. Optional on `utexo` (defaults to `https://lsp-signet.utexo.com`) | | `lspBearerToken` | `string? \| null` | LSP bearer token — required for APay | | `reuseAddresses` | `boolean?` | Reuse on-chain addresses instead of deriving a new one per call (default `false`) | ## Signers Pass a signer to the `UTEXOWallet` constructor. On the first `init()` the wallet calls `initNode`; on every later `unlock()` or `reinit()` it calls `unlockNode`. ### `NativeExternalRLNSigner` (recommended) Native hardware-style external signer. Keys stay in the device key store. Accepts a mnemonic **or** raw BIP39 seed bytes. ```typescript theme={null} import { NativeExternalRLNSigner } from '@utexo/rgb-sdk-rn'; const signer = new NativeExternalRLNSigner(keys.mnemonic, 'regtest'); const signer = new NativeExternalRLNSigner(seedBytes, 'regtest'); const signer = new NativeExternalRLNSigner(keys.mnemonic, 'regtest', true); // relaxed policy ``` ### `PasswordRLNSigner` Password-based auth. The mnemonic is only needed for the first `init()` (written to disk), then cleared from memory. ```typescript theme={null} import { PasswordRLNSigner } from '@utexo/rgb-sdk-rn'; const signer = new PasswordRLNSigner('my-secure-password', keys.mnemonic); const signer = new PasswordRLNSigner('my-secure-password'); // later unlocks ``` ## Lifecycle | Phase | Method | When to call | | ---------------- | ---------------- | ------------------------------------------------------------- | | First-time setup | `init()` | Once per new wallet — writes key material to `storageDirPath` | | Connect & unlock | `unlock(params)` | Every start — connects indexer/bitcoind and proxy | | Graceful stop | `shutdown()` | Pause the node — state stays on disk | | Full teardown | `destroy()` | Logout or `finally` — shutdown + destroyNode + release signer | `initialize()` is an alias for `init()`. `reinit(params)` is `shutdown()` + `init()` + `unlock()` on the same instance. `dispose()` aliases `destroy()`. ```typescript theme={null} const unlockParams = { indexerUrl: '127.0.0.1:50001', proxyEndpoint: 'rpc://127.0.0.1:3000/json-rpc', }; await wallet.init(); await wallet.unlock(unlockParams); await wallet.shutdown(); await wallet.reinit(unlockParams); await wallet.destroy(); ``` All unlock fields are optional. Omit any field to use the network default. Electrum mode does not need the bitcoind RPC fields. #### `IRLNUnlockParams` | Field | Type | Description | | --------------------- | ----------------- | ------------------------------------------------------ | | `bitcoindRpcUsername` | `string?` | Bitcoin RPC username | | `bitcoindRpcPassword` | `string?` | Bitcoin RPC password | | `bitcoindRpcHost` | `string?` | Bitcoin RPC host | | `bitcoindRpcPort` | `number?` | Bitcoin RPC port | | `indexerUrl` | `string?` | Electrum indexer URL (e.g. `'127.0.0.1:50001'`) | | `proxyEndpoint` | `string?` | RGB proxy endpoint (e.g. `'rpc://host:3000/json-rpc'`) | | `announceAddresses` | `string[]?` | Public addresses to announce | | `announceAlias` | `string \| null?` | Node alias | | `gossipRgsServerUrl` | `string \| null?` | RGS server URL for rapid gossip sync | **Utexo Network Faucet** — Test BTC and RGB assets on the Utexo network: Telegram bot [@Utexo\_RLN\_bot](https://t.me/Utexo_RLN_bot). | Command | Description | | -------------- | -------------------------------------------------- | | `/getbtc` | Send your Bitcoin address to receive test satoshis | | `/getasset` | Send an RGB invoice to receive test RGB assets | | `/getinvoice` | Get an RGB Lightning invoice to test paying | | `/getnodeinfo` | Get the faucet node URI, asset ID, and ticker | Limited to 2 requests per 24 hours per user. ## Method Reference ### Balance & Address | Method | Description | | ------------------------ | ---------------------------------------------------------------------------------------------- | | `getBtcBalance()` | BTC balance split by `vanilla` and `colored` paths, each with `settled`, `future`, `spendable` | | `getAddress()` | Current on-chain deposit address | | `rotateVanillaAddress()` | Derive a fresh vanilla (BTC) address | | `getNetwork()` | Configured network string | `getXpub()` is not on this SDK. Use `getNodeInfo()` for node identity. ### UTXO Management | Method | Description | | ----------------------------------------------- | --------------------------------------- | | `createUtxos({ upTo?, num?, size?, feeRate? })` | Create colored UTXOs for RGB operations | | `listUnspents()` | Unspent UTXOs with RGB allocations | Call `syncWallet()` after funding and again after `createUtxos()` before RGB operations. ### RGB Assets RGB receive supports two invoice styles: * **Blinded invoice** — most common. The receiver creates a blinded endpoint; the sender pays directly. * **Witness invoice** — the receiver binds the transfer to witness data. The sender must provide `witnessData` (at minimum `amountSat`) in `onchainSend()`. `onchainReceive()` is the IUTEXOProtocol entry point (witness by default; `witness: false` for blinded). `blindReceive()` and `witnessReceive()` remain as the underlying primitives. There is no `send()` — use `onchainSend()`. ```typescript theme={null} const blinded = await wallet.onchainReceive({ witness: false, minConfirmations: 1, assetId, amount: 100, }); await senderWallet.onchainSend({ invoice: blinded.invoice, assetId, amount: 100, feeRate: 2, minConfirmations: 1, }); const witness = await wallet.onchainReceive({ witness: true, minConfirmations: 1, assetId, amount: 100, }); await senderWallet.onchainSend({ invoice: witness.invoice, assetId, amount: 100, feeRate: 2, minConfirmations: 1, witnessData: { amountSat: 1000 }, }); ``` | Method | Description | | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------- | | `listAssets()` | All RGB assets (NIA, CFA, IFA, UDA) | | `getAssetBalance(assetId)` | Balance for one asset | | `issueAssetNia({ ticker, name, precision, amounts })` | Issue a Non-Inflationary Asset | | `issueAssetIfa({ ticker, name, precision, amounts, inflationAmounts, rejectListUrl })` | Issue an Inflatable Asset | | `onchainReceive({ assetId?, amount?, durationSeconds?, minConfirmations?, witness? })` | RGB invoice — witness by default. Pass `witness: false` for blinded | | `onchainSend({ invoice, assetId, amount, donation?, feeRate?, minConfirmations?, skipSync?, witnessData? })` | RGB send. `assetId` and `amount` are required | | `blindReceive({ assetId?, amount?, durationSeconds?, minConfirmations? })` | Blinded RGB invoice | | `witnessReceive({ assetId?, amount?, durationSeconds?, minConfirmations? })` | Witness RGB invoice | | `decodeRGBInvoice({ invoice })` | Decode an RGB invoice | | `listOnchainTransfers(assetId?)` | Alias of `listTransfers()` | ### BTC Sends | Method | Description | | -------------------------------------------------- | ----------------- | | `sendBtc({ address, amount, feeRate, skipSync? })` | On-chain BTC send | ### Transactions & Transfers | Method | Description | | ------------------------- | -------------------------------------------------------------------------------------------------- | | `listTransactions()` | On-chain transaction history | | `listTransfers(assetId?)` | RGB transfer history. Statuses: `WaitingCounterparty`, `WaitingConfirmations`, `Settled`, `Failed` | | `failTransfers(params)` | Mark pending transfers as failed | | `refreshWallet()` | Refresh RGB transfer state | | `syncWallet()` | Sync blockchain and UTXO state | ### Fees & Backup | Method | Description | | ---------------------------------------- | --------------------------------------------------------------------- | | `estimateFeeRate(blocks)` | Fee rate estimate for a confirmation target | | `createBackup({ backupPath, password })` | Encrypted local file backup | | `backupNow()` | Upload a VSS snapshot now; returns the new version. Requires `vssUrl` | ### Lightning | Method | Description | | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | `createLightningInvoice({ amountSats?, expirySeconds?, asset? })` | Create a Lightning invoice. BTC via `amountSats`; RGB via `asset: { assetId, amount }` | | `payLightningInvoice({ lnInvoice, amount?, assetId? })` | Pay a Lightning invoice | | `getLightningSendStatus(paymentHash)` | Outbound status: `'Pending'`, `'Claimable'`, `'Claiming'`, `'Succeeded'`, `'Cancelled'`, `'Failed'`. `null` if unknown | | `getLightningReceiveStatus(invoice)` | Inbound invoice status | | `listLightningPayments()` | Lightning payments | Do not poll Lightning with RGB transfer statuses (`WaitingCounterparty` / `Settled`). ### LSP & Async payments (APay) `createLsp()` **must run before** `init()` / `reinit()`. The no-arg form discovers the peer from `lspBaseUrl` (or the network default) via `GET /get_info` and wires virtual channels (`enableVirtualChannelsV0: true` + LSP pubkey in `virtualPeerPubkeys`). | Method | Description | | -------------------------------------------------- | ------------------------------------------------------------------ | | `createLsp(peer?)` | Create an `UtexoLsp` session. Pass `LspPeer` to override discovery | | `getLspConfig()` | `{ baseUrl, bearerToken }` this node was created with | | `apayNewWithAddress(hostNodeId, username, domain)` | Register an attested hash pool | | `apayNew(hostNodeId)` | Register a hash pool without address attestation | | `createHodlInvoice(params)` | HODL invoice tied to a payment hash | | `claimHodlInvoice(paymentHash, preimage)` | Claim an inbound HODL payment | | `cancelHodlInvoice(paymentHash)` | Cancel a HODL invoice | See [docs/lsp.md](https://github.com/UTEXO-Protocol/rgb-sdk-rn/blob/dev/docs/lsp.md) and [docs/async-payments.md](https://github.com/UTEXO-Protocol/rgb-sdk-rn/blob/dev/docs/async-payments.md). ### Node Info, Peers & Channels | Method | Description | | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------- | | `getNodeInfo()` | Node pubkey, channel counts, sync status | | `getNetworkInfo()` | Network-level info | | `connectPeer(peerPubkeyAndAddr)` | Connect. Format: `'pubkey@host:port'` | | `disconnectPeer(peerPubkey)` | Disconnect a peer | | `listPeers()` | Connected peers | | `openChannel({ peerPubkeyAndOptAddr, capacitySat, pushMsat, public, withAnchors, assetId?, assetAmount? })` | Open a BTC or RGB channel | | `closeChannel(channelId, peerPubkey, force)` | Close a channel | | `listChannels()` | Open channels | | `getChannelId(temporaryChannelId)` | Resolve temporary → permanent channel ID | | `keysend(destPubkey, amtMsat, assetId?, assetAmount?)` | Spontaneous keysend | | `decodeLnInvoice(invoice)` / `invoiceStatus(invoice)` | Decode / poll a Lightning invoice | | `checkIndexerUrl(url)` | Validate an Electrum indexer URL | | `checkProxyEndpoint(endpoint)` | Validate an RGB proxy endpoint | ## Core Workflows ### First-Time Wallet Init ```typescript theme={null} import { UTEXOWallet, NativeExternalRLNSigner, generateKeys, } from '@utexo/rgb-sdk-rn'; import * as FileSystem from 'expo-file-system/legacy'; const network = 'utexo'; const keys = await generateKeys(network); const storageDir = `${FileSystem.documentDirectory}my-node`.replace('file://', ''); await FileSystem.makeDirectoryAsync(storageDir, { intermediates: true }); const wallet = new UTEXOWallet( { storageDirPath: storageDir, daemonListeningPort: 9735, ldkPeerListeningPort: 9736, network, }, new NativeExternalRLNSigner(keys.mnemonic, network), ); const unlockParams = { // indexerUrl / proxyEndpoint / bitcoind* are optional — network defaults apply }; await wallet.init(); await wallet.unlock(unlockParams); ``` ### App Restart (Existing Node) ```typescript theme={null} await wallet.reinit(unlockParams); ``` ### Issue an RGB Asset ```typescript theme={null} await wallet.syncWallet(); await wallet.createUtxos({ upTo: false, num: 10, feeRate: 1.5 }); const asset = await wallet.issueAssetNia({ ticker: 'DEMO', name: 'Demo Token', precision: 2, amounts: [1000], }); console.log('Asset ID:', asset.assetId); ``` ### Open a Lightning Channel ```typescript theme={null} await wallet.connectPeer(`${peerPubkey}@127.0.0.1:9736`); const { temporaryChannelId } = await wallet.openChannel({ peerPubkeyAndOptAddr: `${peerPubkey}@127.0.0.1:9736`, capacitySat: 500_000, pushMsat: 0, public: false, withAnchors: true, assetId: null, assetAmount: null, }); let usable = false; while (!usable) { await wallet.syncWallet(); const info = await wallet.getNodeInfo(); usable = (info.numUsableChannels ?? 0) >= 1; if (!usable) await new Promise((r) => setTimeout(r, 2000)); } ``` ### Lightning Payment ```typescript theme={null} const { lnInvoice } = await receiverWallet.createLightningInvoice({ amountSats: 3000, expirySeconds: 900, asset: { assetId: '', amount: 0 }, }); const { txid: paymentHash } = await senderWallet.payLightningInvoice({ lnInvoice }); let status = null; while (status !== 'Succeeded') { await senderWallet.syncWallet(); status = await senderWallet.getLightningSendStatus(paymentHash); if (status === 'Failed') throw new Error('Payment failed'); if (status !== 'Succeeded') await new Promise((r) => setTimeout(r, 2000)); } ``` BTC-only invoices can omit `asset` or pass an empty `assetId`. For RGB, pass `asset: { assetId, amount }`. ### Full Cleanup ```typescript theme={null} try { // ... wallet operations ... } finally { await wallet.destroy(); } ``` ## VSS — Encrypted Remote Backup Set `vssUrl` on the constructor. VSS syncs LDK state while the node runs. Restore on a new device: same VSS URL and credentials, empty `storageDirPath`, then `vssClearFence()` **after `init()` and before `unlock()`**. ```typescript theme={null} await walletRestored.init(); await walletRestored.vssClearFence('my-password'); await walletRestored.unlock(unlockParams); ``` `backupNow()` forces an upload and returns the new version. The web-only `configureVssBackup` / `vssBackup` / `vssBackupInfo` methods are not on this SDK. ## LSP Integration ```typescript theme={null} const wallet = new UTEXOWallet( { ...nodeParams, network: 'utexo', lspBearerToken: 'bearer-token', }, signer, ); const lsp = await wallet.createLsp(); // before init() await wallet.init(); await wallet.unlock(unlockParams); await lsp.connect(); const { lnInvoice, rgbInvoice } = await lsp.receiveAsset({ assetId: ASSET_ID, amountSats: 3_000, amountRgb: 1, }); await lsp.awaitReceiveSettlement(lnInvoice); ``` ## Standalone Helpers | Function | Description | | ------------------------------------------- | -------------------------------------------- | | `generateKeys(network?)` | Generate mnemonic, xpubs, master fingerprint | | `createWallet(network?)` | Alias for `generateKeys` | | `deriveKeysFromMnemonic(network, mnemonic)` | Derive keys from an existing BIP39 mnemonic | | `deriveKeysFromSeed(network, seed)` | Derive keys from BIP39 seed bytes | | `signMessage` / `verifyMessage` | Schnorr message signing (no wallet required) | ## RLN Manager (Advanced) `RLNManager` and `createRLNManager` expose the raw RLN node API without the `UTEXOWallet` wrapper. ```typescript theme={null} import { createRLNManager } from '@utexo/rgb-sdk-rn'; const rln = createRLNManager(); await rln.rlnCreateNode({ storageDirPath, daemonListeningPort, ldkPeerListeningPort, network }); await rln.rlnInitNode(password, mnemonic); await rln.rlnUnlockNode({ password, ...connectionParams }); await rln.rlnShutdown(); await rln.rlnDestroyNode(); ``` ## Demo App Full demo: [rgb-sdk-rn-demo](https://github.com/UTEXO-Protocol/rgb-sdk-rn-demo). Covers `UTEXOWallet` lifecycle, both signers, `reinit()`, VSS, and APay. ```bash theme={null} git clone https://github.com/UTEXO-Protocol/rgb-sdk-rn-demo cd rgb-sdk-rn-demo npm install && npm run prebuild cd ios && LANG=en_US.UTF-8 pod install && cd .. npm run ios:release # or npm run android:release ``` ## Further Reading * [SDK Overview](/product-suite/sdk) * [Web SDK](/sdk/web-sdk) * [wdk-rgb-lightning](/sdk/wdk-rgb-lightning) * [Architecture](/getting-started/architecture) * [rgb-sdk-rn README](https://github.com/UTEXO-Protocol/rgb-sdk-rn/blob/dev/Readme.md) # WDK Overview Source: https://docs.utexo.com/sdk/wdk-overview Overview of the Utexo Wallet Development Kit — WDK abstractions over RGB asset management and RGB Lightning for wallet builders. The Wallet Development Kit (WDK) is a set of packages that expose RGB capabilities through standardised wallet abstraction interfaces. `@utexo/wdk-rgb-lightning` is the current Node.js / Bare module for RGB-over-Lightning. `@utexo/rgb-sdk-web` and `@utexo/rgb-sdk-rn` target application developers building end-to-end Web and mobile flows. The archived `@utexo/rgb-sdk` Node.js package is not used for new integrations. ## WDK Packages | Package | Platform | Description | Status | | -------------------------- | -------------- | ------------------------------------------------------------- | ------------ | | `@utexo/wdk-wallet-rgb` | Node.js & Bare | RGB asset management — issuance, transfers, inventory, backup | Stable | | `@utexo/wdk-rgb-lightning` | Node.js & Bare | RGB Lightning node — channels, invoices, payments, LSP, VSS | Pre-1.0 beta | Both packages are built on `rgb-lib`, so the on-chain experience — UTXO management, asset state, and RGB operations — is consistent between them. They do **not** share asset records: give each module a **separate** `dataDir`. `wdk-rgb-lightning` runs in external-signer mode: the mnemonic stays in the WDK secret manager, and channel-state cryptography happens in-process through a VLS signer. Use `wdk-wallet-rgb` for issuance; use `wdk-rgb-lightning` for channels, invoices, and Lightning transfers. ## When to Use the WDK Use the WDK packages when: * You are building a **new Node.js** integration (use `@utexo/wdk-rgb-lightning`, not the archived `@utexo/rgb-sdk`) * Your application already builds on WDK-style account and manager abstractions * You want to plug RGB or RGB Lightning into an existing wallet architecture without adopting the `UTEXOWallet` lifecycle * You need lower-level control over account management, signing policy, and key derivation If you are building a **browser** or **React Native** app from scratch, `@utexo/rgb-sdk-web` and `@utexo/rgb-sdk-rn` provide a higher-level `UTEXOWallet` API. ## Further Reading * [wdk-wallet-rgb Reference](/sdk/wdk-wallet-rgb) — Full API for RGB asset management * [wdk-rgb-lightning Reference](/sdk/wdk-rgb-lightning) — Full API for RGB Lightning * [SDK Overview](/product-suite/sdk) — How the WDK fits into the broader Utexo SDK family # wdk-rgb-lightning Reference Source: https://docs.utexo.com/sdk/wdk-rgb-lightning Reference for @utexo/wdk-rgb-lightning — WDK module for RGB Lightning channels, invoices, and payments. Pre-1.0 beta. `@utexo/wdk-rgb-lightning` is a WDK module for RGB-over-Lightning, built on `rgb-lightning-node` (RLN). It runs an LDK + `rgb-lib` node behind WDK's manager/account contract: channels, BOLT11 and RGB invoices, payments, HODL invoices, optional VSS backup, and an LSP client. The node runs in **external-signer** mode. The BIP-39 mnemonic stays in the WDK secret manager. Channel-state crypto runs in-process through a VLS signer. Pre-1.0 beta (`0.1.0-beta` line). APIs may change between releases. ## Why a Separate Package This module complements [`@utexo/wdk-wallet-rgb`](/sdk/wdk-wallet-rgb). Each owns its own `rgb-lib` SQLite state and they do **not** share asset records. Give each module a **separate** `dataDir` — `rgb-lib` takes an exclusive lock on a wallet directory. This module holds and transfers RGB assets for channels and invoices. For issuance, use `@utexo/wdk-wallet-rgb`. Node-level issuance calls are forwarded on the account, but `wdk-wallet-rgb` is the supported path. ## Installation ```bash theme={null} npm install @utexo/wdk-rgb-lightning # Native binding for your runtime (optional peer deps): npm install @utexo/rgb-lightning-node-nodejs # Node # or npm install @utexo/rgb-lightning-node-bare # Bare / React Native ``` Install only the binding for your runtime. Each `postinstall` downloads a prebuilt native artifact; no Rust toolchain is required. On Node, `import '@utexo/wdk-rgb-lightning'` wires `@utexo/rgb-lightning-node-nodejs`. In a Bare worklet, `require('@utexo/wdk-rgb-lightning')` wires `@utexo/rgb-lightning-node-bare`. Both re-export the same manager, account, errors, and LSP surface. ## Configuration `WalletManagerRgbLightning` takes the seed at construction. `network` and `dataDir` are required. | Option | Type | Description | | ------------------------- | ---------- | --------------------------------------------------------------------- | | `network` | `string` | `'mainnet'`, `'testnet'`, `'signet'`, or `'regtest'` | | `dataDir` | `string` | Persistent directory for RLN SQLite + LDK state | | `daemonListeningPort` | `number` | RLN daemon port. Default `0` (ephemeral) | | `ldkPeerListeningPort` | `number` | LDK peer port. Default `0` (ephemeral) | | `enableVirtualChannelsV0` | `boolean` | Required for APay against a production LSP. Default `false` | | `virtualPeerPubkeys` | `string[]` | Peer node IDs allowed to open `trusted_no_broadcast` virtual channels | | `vssUrl` | `string` | VSS cloud backup URL. Omit to disable | | `vssAllowHttp` | `boolean` | Allow plain `http://` for non-loopback VSS hosts. Default `false` | | `lspBaseUrl` | `string` | LSP base URL for APay and `createLsp()` | | `lspBearerToken` | `string` | Bearer token for LSP `/internal/*` routes | ```typescript theme={null} import WalletManagerRgbLightning from '@utexo/wdk-rgb-lightning'; const manager = new WalletManagerRgbLightning(mnemonic, { network: 'regtest', dataDir: '/path/to/wallet-data', }); ``` ## Classes ### `WalletManagerRgbLightning` Default export. Construct with a BIP-39 mnemonic (or `Uint8Array` seed) and config. #### Methods | Method | Description | | ------------------------ | ---------------------------------------------------------------- | | `getAccount(0)` | Return the single `WalletAccountRgbLightning`. Index must be `0` | | `getAccountByPath(path)` | Same account, looked up by derivation path | | `getFeeRates()` | `{ normal, fast }` fee rates as `bigint` sat/vB | | `dispose()` | Shut down the node. Synchronous | ```typescript theme={null} const account = await manager.getAccount(0); await account.unlock({ indexer_url: 'tcp://localhost:50001', proxy_endpoint: 'rpc://localhost:3000/json-rpc', announce_addresses: [], announce_alias: 'my-node', }); ``` Unlock takes **exactly one** chain backend: `indexer_url`, or all four `bitcoind_rpc_*` fields (`bitcoind_rpc_username`, `bitcoind_rpc_password`, `bitcoind_rpc_host`, `bitcoind_rpc_port`). Mixing both is rejected. `proxy_endpoint`, `announce_addresses`, and `announce_alias` are always required. *** ### `WalletAccountRgbLightning` Returned by `getAccount(0)`. RGB Lightning is single-account; RLN owns one LDK node per `dataDir`. #### Lifecycle | Method | Description | | ----------------- | ------------------------------------------------------------------ | | `unlock(request)` | Bring the node online. Returns `{ ok: true }` | | `getBootstrap()` | Signer/node identity material | | `shutdown()` | Shut down the native node. Returns `{ ok: true }` | | `dispose()` | No-op on the account. Call `manager.dispose()` to release the node | #### Node Info | Method | Description | | --------------------------------- | --------------------------------------------------------------------------- | | `getNodeInfo()` | Node pubkey, channel counts, sync status | | `getNetworkInfo()` | Bitcoin network and chain info | | `refreshWalletSnapshot(options?)` | Production refresh. `options.mode` is `'routine'` (default) or `'recovery'` | | `sync()` | Deprecated. Colored FastSync only — do not use for portfolio state | | `getAddress()` | Current receive address. Throws `AccountLockedError` before unlock | | `getAddressState()` | `{ status: 'ready', address }` or `{ status: 'locked', address: null }` | | `rotateAddress()` | Advance the receive address. Returns the new address | #### Peers | Method | Description | | --------------------------------- | ------------------------------------------------------------------ | | `connectPeer(peerPubkeyAndAddr)` | Connect. String form: `'pubkey@host:port'`. Returns `{ ok: true }` | | `disconnectPeer({ peer_pubkey })` | Disconnect a peer. Returns `{ ok: true }` | | `listPeers()` | Connected peers | #### Channels | Method | Description | | ------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | | `openChannel({ peer_pubkey_and_opt_addr, capacity_sat, push_msat?, public?, with_anchors?, asset_id?, asset_amount?, virtual_open_mode? })` | Open a BTC or RGB channel | | `closeChannel({ channel_id })` | Close a channel. Returns `{ ok: true }` | | `listChannels()` | Open channels | | `getChannelId(temporaryChannelIdHex)` | Resolve a temporary channel ID | Set `virtual_open_mode: 'trusted_no_broadcast'` for APay virtual channels. Requires `enableVirtualChannelsV0: true` and the peer in `virtualPeerPubkeys`. #### Invoices & Payments | Method | Description | | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | | `createInvoice({ amt_msat?, expiry_sec, asset_id?, asset_amount? })` | Create a BOLT11 invoice (native snake\_case) | | `createLightningInvoice({ amountMsat?, expirySec, assetId?, assetAmount? })` | Same call, camelCase alias | | `decodeInvoice(invoice)` | Decode a BOLT11 invoice | | `getInvoiceStatus(invoice)` | Invoice status | | `sendPayment({ invoice, amt_msat?, asset_id?, asset_amount?, max_total_routing_fee_msat? })` | Pay a BOLT11 invoice | | `keysend({ dest_pubkey, amt_msat, asset_id?, asset_amount? })` | Spontaneous keysend | | `listPayments()` | Payment history | | `getPayment(paymentHash, type)` | One payment. `type` is `'Outbound'`, `'InboundAutoClaim'`, or `'InboundHodl'` | #### HODL Invoices | Method | Description | | --------------------------------------------------------------------------------- | --------------------------------- | | `createHodlInvoice({ paymentHash, expirySec, amtMsat?, assetId?, assetAmount? })` | Returns `{ bolt11, paymentHash }` | | `cancelHodlInvoice({ payment_hash })` | Cancel. Returns `{ ok: true }` | | `claimHodlInvoice({ payment_hash, preimage })` | Claim an inbound HODL payment | #### RGB Assets RGB receive supports two invoice styles: * **Blinded invoice** — most common. The receiver creates a blinded endpoint; the sender pays the invoice directly. * **Witness invoice** — the receiver binds the transfer to witness data. The sender must provide `witnessData` (at minimum `amountSats`) in `transfer()`. ```typescript theme={null} // Blinded invoice await receiver.createRgbInvoice({ min_confirmations: 1, witness: false, asset_id: assetId, assignment_amount: 100, }); await sender.transfer({ recipient: blindedInvoice, amount: 100, token: assetId, }); // Witness invoice await receiver.createRgbInvoice({ min_confirmations: 1, witness: true, asset_id: assetId, assignment_amount: 100, }); await sender.transfer({ recipient: witnessInvoice, amount: 100, token: assetId, witnessData: { amountSats: 1000 }, }); ``` `transfer()` rejects `witnessData` on a blinded recipient. `decodeRgbInvoice()` reports `recipient_type` as `'Blind'` or `'Witness'`. | Method | Description | | ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | | `listAssets(filterAssetSchemas?)` | List assets. Optional filter, e.g. `['Nia']` | | `getAssetBalance(assetId)` | Balance for one asset | | `getAssetMetadata(assetId)` | Asset metadata | | `getTokenBalance(assetId)` | Spendable amount as `bigint` | | `listTransfers(assetId)` | Transfer history for one asset | | `listTransfersByTxid(txid)` | Transfers for an on-chain txid | | `refreshTransfers(request)` / `failTransfers({ batch_transfer_idx })` | Advance or fail pending transfers | | `createRgbInvoice({ min_confirmations, witness, asset_id?, assignment_amount?, duration_seconds? })` | On-chain RGB invoice. `witness: true` = witness receive, `false` = blinded | | `decodeRgbInvoice(invoice)` | Decode an RGB invoice | | `sendRgbAsset({ donation, fee_rate, min_confirmations, recipient_groups })` | Send RGB. Recipients come from `decodeRgbInvoice` | | `importRgbContract({ contract_base64, expected_asset_id })` | Register trusted contract metadata only — no allocation | | `importRgbTransferConsignment({ consignment_base64, offchain_txid })` | Persist metadata for a transfer the native receive path already accepted | Issuance (`issueAssetNia`, `issueAssetUda`, `issueAssetCfa`, `issueAssetIfa`, `inflate`) is forwarded to the binding. Prefer [`@utexo/wdk-wallet-rgb`](/sdk/wdk-wallet-rgb) for issuance. Atomic swaps are on the native binding but are **not** on the WDK account. #### BTC | Method | Description | | ----------------------------------------------------------------------- | -------------------------------------------- | | `getBalance(skipSync?)` | Spendable vanilla BTC as `bigint` satoshis | | `getBalanceDetails(skipSync?)` | Full vanilla/colored breakdown | | `sendTransaction({ to, value, feeRate?, confirmationTarget? })` | WDK-shaped send. Returns `{ hash, fee }` | | `sendBtc({ address, amount, fee_rate, skip_sync })` | Native RLN send. Returns `{ txid }` | | `getTransactions(skipSync?)` / `getTransactionsByTxid(txid, skipSync?)` | On-chain history | | `listUnspents(skipSync?)` | Unspent outputs with RGB allocations | | `createUtxos({ up_to, num?, size?, fee_rate, skip_sync })` | Create colored UTXOs. Returns `{ ok: true }` | | `estimateFee(blocks)` | Fee estimate for a confirmation target | Prepare/commit/cancel variants exist for BTC sends, RGB sends, and UTXO creation (`prepareBtcSend`, `commitPreparedBtcSend`, `prepareRgbSend`, `prepareCreateUtxos`, …). #### VSS Requires `vssUrl` at construction. Otherwise these throw `VssNotConfiguredError`. | Method | Description | | ------------------------- | ---------------------------------------------------------------------- | | `vssStatus()` | Local view: `{ configured, url, allowHttp, lastBackupVersion }` | | `vssBackup()` | Flush now. Returns `{ version }` | | `clearVssFence(password)` | Take over a stale VSS fence. Two live nodes on one store corrupt state | | `vssDeleteAll(password)` | Delete all VSS keys. Returns `{ deleted_keys }` | VSS replicates RLN's LDK and wallet KV state. It does not replicate the VLS signer database under `dataDir`, so same-device restarts work; cross-device recovery with open channels does not. #### APay / LSP Production APay needs `enableVirtualChannelsV0: true` and the LSP node ID in `virtualPeerPubkeys`. | Method | Description | | --------------------------------------------------- | ------------------------------------------------------------------------- | | `createLsp(peer?)` | Composed `UtexoLsp`. No-arg form discovers the peer from `lspBaseUrl` | | `getLspConfig()` | `{ baseUrl, bearerToken }` from construction | | `getLspInfo()` | Validated LSP `GET /get_info` document | | `bootstrapLsp({ peerPubkeyAndAddr, hostNodeId? })` | Connect, wait until the peer is in `listPeers`, optionally call `apayNew` | | `apayNewWithAddress(hostNodeId, username, domain)` | Register an attested hash batch | | `apayNew(hostNodeId)` | Legacy unattested registration | | `payLightningAddress(addr, amountMsat)` | Pay a Lightning Address | | `requestLspRgbDeposit(args)` / `payRgbViaLsp(args)` | RGB deposit / pay via the LSP | ```typescript theme={null} const lsp = await account.createLsp(); await lsp.connect(); const { lnInvoice, rgbInvoice } = await lsp.receiveAsset({ assetId, amountSats: 3_000, amountRgb: 100, }); await lsp.awaitReceiveSettlement(lnInvoice); ``` `UtexoLsp` also exposes `sendAsset()`, `quoteAddress()`, `payAddress()`, `enableLightningAddress()`, and `claimPendingPayments()`. Do not call `apayNew` immediately before `enableLightningAddress` — the native batch can fill the LSP hash-pool cap. #### WDK-standard | Method | Description | | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `transfer({ recipient, amount, token?, feeRate?, witnessData? })` | Routes BOLT11, LN pubkey, BTC address, or RGB invoice. `token` is an RGB asset id. Amounts are msats (LN) or sats (on-chain). Witness RGB invoices require `witnessData.amountSats` | | `quoteTransfer(options)` / `quoteSendTransaction(tx)` | Fee quote | | `getTransactionReceipt(hash)` | Receipt, or `null` if pending/unknown | | `sign(message)` / `verify(message, signature)` | Lightning message sign/verify | | `toReadOnlyAccount()` | Cached query-only account (`Promise`). No signing, channels, VSS recovery, or LSP credentials | ## Error Handling Typed errors are exported from the package root. Branch on `err.name` / `err.code`. The original RLN message is on `cause`. ``` RgbLightningError code: RGB_LIGHTNING_ERROR ├── UnlockError code: UNLOCK_FAILED ├── AccountLockedError code: ACCOUNT_LOCKED ├── VssError code: VSS_ERROR │ └── VssNotConfiguredError code: VSS_NOT_CONFIGURED ├── ApayError code: APAY_ERROR ├── WalletSyncError code: WALLET_SYNC_FAILED ├── WalletSnapshotError code: WALLET_SNAPSHOT_FAILED └── NotImplementedError code: NOT_IMPLEMENTED ``` ```typescript theme={null} import { UnlockError } from '@utexo/wdk-rgb-lightning'; try { await account.unlock(request); } catch (err) { if (err instanceof UnlockError) { console.error(err.code, err.message, err.cause); } } ``` LSP HTTP failures throw `LspError` / `LspProtocolError`. Channel and liquidity waits throw `LspChannelTimeoutError` and `LspLiquidityTimeoutError`. ## Usage Example ```typescript theme={null} import WalletManagerRgbLightning from '@utexo/wdk-rgb-lightning'; const manager = new WalletManagerRgbLightning(mnemonic, { network: 'regtest', dataDir: '/path/to/wallet-data', }); const account = await manager.getAccount(0); await account.unlock({ indexer_url: 'tcp://localhost:50001', proxy_endpoint: 'rpc://localhost:3000/json-rpc', announce_addresses: [], announce_alias: 'my-node', }); const info = await account.getNodeInfo(); console.log('Node pubkey:', info.pubkey); await account.connectPeer(`${peerPubkey}@127.0.0.1:9736`); await account.openChannel({ peer_pubkey_and_opt_addr: `${peerPubkey}@127.0.0.1:9736`, capacity_sat: 500_000, push_msat: 0, public: false, with_anchors: true, }); const invoice = await account.createInvoice({ amt_msat: 5_000, expiry_sec: 3600, }); await account.sendPayment({ invoice: bolt11 }); manager.dispose(); ``` End-to-end LSP + RGB-over-Lightning examples live in [utexo-rgb-wdk-demo](https://github.com/UTEXO-Protocol/utexo-rgb-wdk-demo). ## Using with `wdk-wallet-rgb` Both packages use `rgb-lib`, but they do **not** share asset records. Use `@utexo/wdk-wallet-rgb` for issuance and on-chain inventory; use this module for channels, invoices, and Lightning transfers. Give each module its own `dataDir`. ## Further Reading * [WDK Overview](/sdk/wdk-overview) * [wdk-wallet-rgb Reference](/sdk/wdk-wallet-rgb) * [SDK Overview](/product-suite/sdk) * [Package README](https://github.com/UTEXO-Protocol/wdk-rgb-lightning/blob/dev/README.md) # wdk-wallet-rgb Reference Source: https://docs.utexo.com/sdk/wdk-wallet-rgb Complete reference for @utexo/wdk-wallet-rgb — WDK-compatible RGB asset management for wallet builders. `@utexo/wdk-wallet-rgb` bridges the Wallet Development Kit (WDK) interfaces with the RGB ecosystem. It wraps the `@utexo/rgb-lib-bare` native addon and the `@utexo/rgb-sdk` Taproot signer inside standard WDK account abstractions, giving wallet builders first-class RGB support without reimplementing the protocol layer. ## Installation ```bash theme={null} npm install @utexo/wdk-wallet-rgb ``` ## Configuration | Option | Type | Description | | --------- | -------- | ------------------------------------------------------------------------------------------- | | `network` | `string` | Bitcoin network: `'mainnet'`, `'testnet'`, `'testnet4'`, `'signet'`, `'utexo'`, `'regtest'` | | `dataDir` | `string` | Path to a persistent directory for SQLite state storage | ## Classes ### `WalletManagerRgb` The top-level manager. Constructs account instances and manages the underlying `rgb-lib` state. ```typescript theme={null} import { WalletManagerRgb } from '@utexo/wdk-wallet-rgb'; const manager = new WalletManagerRgb({ network: 'utexo', dataDir: '/path/to/wallet-data', }); ``` #### Methods | Method | Description | | ------------------------------------- | ---------------------------------------------------------------------- | | `getAccount(mnemonic)` | Derive a `WalletAccountRgb` from a BIP39 mnemonic | | `restoreFromBackup(backup, mnemonic)` | Restore wallet state from an encrypted backup, then return the account | | `getFeeRate()` | Get current fee rate estimate | | `dispose()` | Release native resources | ```typescript theme={null} const account = await manager.getAccount(mnemonic); // Or restore from backup first const account = await manager.restoreFromBackup(backupData, mnemonic); ``` *** ### `WalletAccountRgb` The primary account class. Implements the standard WDK account interface plus RGB-specific operations. #### Address & Signing (Standard WDK) | Method | Description | | --------------------------------------- | ------------------------------------------- | | `getAddress()` | Get current receive address | | `sign(psbt)` | Sign a PSBT with the account's key material | | `sendBtc({ address, amount, feeRate })` | On-chain BTC send | #### RGB Assets ```typescript theme={null} // Issue a Non-Inflationary Asset const asset = await account.issueAssetNia({ ticker: 'MYTOKEN', name: 'My Token', precision: 6, amounts: [1_000_000], }); // Issue a Collectible Fungible Asset const cfa = await account.issueAssetCfa({ name: 'Collectible', precision: 0, amounts: [100], description: 'A collectible token', fileDigest: null, }); // Issue a Unique Digital Asset (NFT) const uda = await account.issueAssetUda({ name: 'My NFT', precision: 0, details: 'metadata...', fileDigest: null, }); // Issue an Inflatable Asset const ifa = await account.issueAssetIfa({ ticker: 'IFA', name: 'Inflatable', precision: 0, amounts: [500], inflationAmounts: [{ assetId: '', amount: 100 }], rejectListUrl: '', }); ``` | Method | Description | | -------------------------------------------------------------------------------------- | ---------------------------------- | | `issueAssetNia({ ticker, name, precision, amounts })` | Issue a Non-Inflationary Asset | | `issueAssetCfa({ name, precision, amounts, description?, fileDigest? })` | Issue a Collectible Fungible Asset | | `issueAssetUda({ name, precision, details?, fileDigest? })` | Issue a Unique Digital Asset (NFT) | | `issueAssetIfa({ ticker, name, precision, amounts, inflationAmounts, rejectListUrl })` | Issue an Inflatable Asset | | `inflateAsset({ assetId, amounts })` | Inflate an existing IFA | #### Inventory & Balances | Method | Description | | -------------------------- | ------------------------------------------------------------------------------------------------------- | | `listAssets()` | List all RGB assets in the wallet | | `getAssetBalance(assetId)` | Get balance for a specific asset | | `listTransfers(assetId?)` | List RGB transfer history. Statuses: `WaitingCounterparty`, `WaitingConfirmations`, `Settled`, `Failed` | | `listUnspents()` | List unspent UTXOs with RGB allocations | #### Transfers ```typescript theme={null} // Receive — blinded invoice const receiveData = await account.blindReceive({ assetId, amount: 5000, minConfirmations: 1, durationSeconds: 3600, }); // Send await account.transferAsset({ invoice: receiveData.invoice, assetId, amount: 5000, }); ``` | Method | Description | | ---------------------------------------------------------------------------- | ------------------------------ | | `blindReceive({ assetId?, amount?, minConfirmations?, durationSeconds? })` | Generate a blinded RGB invoice | | `witnessReceive({ assetId?, amount?, minConfirmations?, durationSeconds? })` | Generate a witness RGB invoice | | `transferAsset({ invoice, assetId, amount, donation?, feeRate? })` | Execute an RGB asset transfer | | `decodeRgbInvoice(invoice)` | Decode an RGB invoice | #### UTXO Management | Method | Description | | ------------------------------------- | --------------------------------------- | | `createUtxos({ num?, size?, upTo? })` | Create colored UTXOs for RGB operations | | `syncWallet()` | Sync blockchain and UTXO state | | `refreshWallet()` | Refresh RGB transfer state | #### Backup | Method | Description | | ---------------------------------------- | ----------------------------- | | `createBackup({ backupPath, password })` | Create encrypted local backup | *** ### `WalletAccountReadOnlyRgb` A view-only account that does not hold private key material. Use for watch-only wallet UIs or balance dashboards. ```typescript theme={null} const readOnly = await manager.getReadOnlyAccount(xpub); ``` | Method | Description | | -------------------------------------------------- | ----------------------------------- | | `getBalance()` | BTC balance (vanilla + colored) | | `listAssets()` | List RGB assets | | `verifySignature({ message, signature, address })` | Verify a Schnorr or ECDSA signature | ## Full Example ```typescript theme={null} import { WalletManagerRgb } from '@utexo/wdk-wallet-rgb'; const manager = new WalletManagerRgb({ network: 'utexo', dataDir: '/path/to/wallet-data', }); const account = await manager.getAccount(mnemonic); // Fund address with BTC, then create UTXOs const address = await account.getAddress(); // ... send BTC to address, wait for confirmation ... await account.syncWallet(); await account.createUtxos({ num: 5 }); // Issue an asset const asset = await account.issueAssetNia({ ticker: 'USDT', name: 'Test USDT', precision: 6, amounts: [1_000_000], }); // Create a receive invoice on another account const receiveData = await receiverAccount.blindReceive({ assetId: asset.assetId, amount: 100, minConfirmations: 1, durationSeconds: 3600, }); // Transfer await account.transferAsset({ invoice: receiveData.invoice, assetId: asset.assetId, amount: 100, }); await account.refreshWallet(); await receiverAccount.refreshWallet(); // Cleanup manager.dispose(); ``` ## Further Reading * [WDK Overview](/sdk/wdk-overview) * [wdk-rgb-lightning](/sdk/wdk-rgb-lightning) — RGB Lightning for channels and payments * [SDK Overview](/product-suite/sdk) # Web SDK Reference Source: https://docs.utexo.com/sdk/web-sdk Complete reference for @utexo/rgb-sdk-web — browser-native RGB assets and Lightning payments via WebAssembly, no server required. The `@utexo/rgb-sdk-web` package is the browser SDK for the Utexo stack. All operations run locally via an **RGB Lightning Node (RLN)** compiled to **WebAssembly** — no RGB server, no Node.js, no native binaries. `UTEXOWallet` mirrors the React Native SDK surface, so app code ports across web ↔ mobile with minimal change. This SDK is designed for **browser environments only**. It is not compatible with Node.js (use [`@utexo/wdk-rgb-lightning`](/sdk/wdk-rgb-lightning)) or React Native (use [`@utexo/rgb-sdk-rn`](/sdk/react-native-sdk)). This is a **beta** release — APIs may change between releases. ## What You Can Do * Run a full Lightning node in the browser via the RLN WASM SDK * Open Lightning channels and send/receive BTC or RGB asset payments * LSP integration: receive RGB via Lightning, send RGB to on-chain recipients, Lightning Address * Async payments (APay): hash pool + Lightning Address via utexo-lsp * Issue, transfer, and manage RGB assets (NIA, IFA, CFA) * Manage UTXOs and BTC on-chain sends — atomic (`sendBtc`) or 3-step begin → sign → end for external signers * Encrypted file backup (raw bytes, browser-download friendly) and VSS cloud backup * HODL invoices: create, claim, cancel ## Requirements * Modern browser with WebAssembly and top-level `await` support: Chrome, Firefox, Safari, Edge * ESM-only bundler: Vite, Webpack 5, Rollup, or esbuild — CommonJS is not supported * At create time: an Esplora indexer, an RGB proxy (transport) endpoint, and — for Lightning — a WebSocket LN gateway. Known networks get defaults — see [Default endpoints](#default-endpoints) ## Installation ```bash theme={null} npm install @utexo/rgb-sdk-web ``` ### Bundler setup (Vite) The WASM module initialises asynchronously; exclude the package from Vite's dependency pre-bundling and enable WASM + top-level-await support: ```typescript theme={null} // vite.config.ts import wasm from 'vite-plugin-wasm'; import topLevelAwait from 'vite-plugin-top-level-await'; export default defineConfig({ plugins: [wasm(), topLevelAwait(), react()], optimizeDeps: { exclude: ['@utexo/rgb-sdk-web'] }, }); ``` ## Initialisation The primary class is `UTEXOWallet`. The constructor is sync and cheap (params are only stored); `init()` does all local WASM work and returns the wallet **LOCKED**; `unlock()` brings it online. ```typescript theme={null} import { UTEXOWallet, generateKeys } from '@utexo/rgb-sdk-web'; const network = 'utexo'; const keys = await generateKeys(network); const wallet = new UTEXOWallet({ mnemonic: keys.mnemonic, password: 'my-secure-password', network, }); await wallet.init(); // Restoring on a new device? await wallet.restoreFromVss() goes HERE. await wallet.unlock(); if (!wallet.isOnline()) { await wallet.goOnline(); } const address = await wallet.getAddress(); ``` `init()` and `unlock()` are idempotent and retryable after a thrown failure; `unlock()` throws unless `init()` ran first. Wallet/network methods throw until `unlock()` resolves. `UTEXOWallet.create(params)` is a one-call convenience for constructor + `init()` + `unlock()`. `initialize()` is an alias for that sequence. The current constructor accepts **one parameter object**. The older `new UTEXOWallet(mnemonic, options)` form and a standalone `create(mnemonic, options)` factory do not match the current implementation. #### `UTEXOWalletCreateParams` | Field | Type | Description | | ----------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `mnemonic` | `string` | BIP39 mnemonic — required | | `password` | `string` | RLN SDK password — required (encrypts local wallet state) | | `network` | `string?` | Bitcoin network (`'utexo'`, `'regtest'`, `'testnet'`, `'mainnet'`, …). Default `'utexo'` | | `indexerUrl` | `string?` | Esplora URL for `goOnline`. Defaults per network. `unlock()` always attempts to connect; failure is non-fatal (wallet returned offline) | | `transportEndpoint` | `string?` | RGB proxy for consignment delivery. Defaults per network | | `proxyUrl` | `string?` | WebSocket LN gateway URL — enables the embedded Lightning node. Defaults per network (`utexo`); on networks without a default, omitting it means no Lightning | | `nodeRuntimeId` | `string?` | Stable runtime ID so node state persists across page reloads | | `skipConsistencyCheck` | `boolean?` | Skip the indexer consistency check on connect | | `vssUrl` | `string? \| null` | VSS server URL. Defaults to `DEFAULT_VSS_SERVER_URL`; pass `null` to disable VSS | | `dataDir` | `string?` | Local wallet DB directory (default: auto-generated) | | `supportedSchemas` | `string[]?` | Asset schemas (default `['Nia', 'Ifa']`) | | `enableVirtualChannels` | `boolean?` | Enable virtual channels v0 on the Lightning node (default `true`) | | `lspBaseUrl` | `string?` | utexo-lsp HTTP base URL — source for no-arg `createLsp()` peer discovery | | `lspBearerToken` | `string?` | LSP bearer token — required for APay routes | ### Lifecycle The `init` → `unlock` gap is the explicit VSS-restore window: 1. **`new UTEXOWallet(params)` + `await wallet.init()`** — loads WASM, derives keys, creates the wallet from local storage, creates the Lightning node handle (when `proxyUrl` resolves), and configures VSS. The wallet is **LOCKED**: wallet/network ops throw; key reads (`getXpub`, `getNodePubkey`) and VSS restore APIs work. 2. **Optional: `await wallet.restoreFromVss({ takeoverFence? })`** — explicit cloud restore on a new device. Restore is never automatic. 3. **`await wallet.unlock()`** — validates the password, configures LDK/channel VSS replication, and auto-connects to the indexer non-fatally. 4. **`isOnline()` / `goOnline(indexerUrl)`** — check the connection; retry when offline. `goOnline` is idempotent. 5. **`dispose()`** — release the WASM wallet/node handles. Check with `isDisposed()`. ## Networks | Environment | Identifier | Use case | | -------------- | ---------- | ----------------------------------- | | Mainnet | `mainnet` | Production | | Testnet | `testnet` | Pre-production testing | | Utexo (Signet) | `utexo` | Development and integration testing | **Utexo Network Faucet** — To get test BTC and RGB assets on the Utexo network, use the Telegram bot [@Utexo\_RLN\_bot](https://t.me/Utexo_RLN_bot). | Command | Description | | -------------- | -------------------------------------------------- | | `/getbtc` | Send your Bitcoin address to receive test satoshis | | `/getasset` | Send an RGB invoice to receive test RGB assets | | `/getinvoice` | Get an RGB Lightning invoice to test paying | | `/getnodeinfo` | Get the faucet node URI, asset ID, and ticker | Limited to 2 requests per 24 hours per user. ## Default Endpoints Used automatically when the corresponding create param is omitted (`DEFAULT_RLN_URLS`): | Network | LN gateway (`proxyUrl`) | RGB transport (`transportEndpoint`) | Indexer (`indexerUrl`) | | ------- | ----------------------------------- | -------------------------------------- | ------------------------------- | | `utexo` | `wss://ln-gateway-signet.utexo.com` | `https://rgb-proxy.utexo.com/json-rpc` | `https://esplora-api.utexo.com` | On networks without a `proxyUrl` default, pass one explicitly to enable the Lightning node; without it the wallet is on-chain RGB only. ## Vanilla vs Colored Addresses The SDK operates two separate derivation paths, consistent with the React Native SDK: * **Vanilla** — standard Bitcoin derivation path for BTC receives, fee payments, and on-chain withdrawals. `getAddress()` returns a vanilla bech32 receive address. * **Colored** — RGB-specific derivation path. Used internally when creating UTXOs for RGB asset allocations. `getBtcBalance()` returns separate balances for each path, each with `settled`, `future`, and `spendable` fields. `getXpub()` returns `{ xpubVan, xpubCol }`. ## Wallet Methods ### Key Generation * `generateKeys(network?)` — Generate new wallet keys. Returns `mnemonic`, xpubs, and master fingerprint. * `restoreKeys(network, mnemonic)` / `deriveKeysFromMnemonic` / `deriveKeysFromSeed` — Derive keys from existing material. * `initRlnWasm()` — Explicit WASM init (singleton — `create()` calls it automatically). ### Wallet State | Method | Description | | -------------------------- | ------------------------------------------------------------ | | `getAddress()` | Current on-chain deposit address | | `getBtcBalance()` | BTC balance split by `vanilla` and `colored` paths | | `getXpub()` | `{ xpubVan, xpubCol }` | | `getNetwork()` | Configured network | | `listUnspents()` | List unspent UTXOs with RGB allocations | | `listAssets()` | List RGB assets held in the wallet | | `getAssetBalance(assetId)` | Get balance for a specific RGB asset | | `listTransactions()` | List BTC-level transactions | | `listTransfers(assetId?)` | List RGB transfer history | | `refreshWallet()` | Update RGB transfer state (consignments, status progression) | | `syncWallet()` | Update chain and UTXO state | | `dispose()` | Release wallet resources | Call `syncWallet()` after funding or UTXO creation to update chain state. Call `refreshWallet()` after `onchainSend()` to update RGB transfer status on both sender and receiver sides. ## UTXO Management Before issuing or receiving RGB assets, colored UTXOs must be created. Call `createUtxos()` after funding the vanilla address: ```typescript theme={null} await wallet.syncWallet(); await wallet.createUtxos({ upTo: true, num: 4, feeRate: 2 }); ``` | Method | Description | | ------------------------------------------------------------- | ----------------------------------------------------------------------------- | | `createUtxos({ upTo?, num?, size?, feeRate? })` | Create colored UTXOs — atomic (begin → sign → end); returns the count created | | `createUtxosBegin(params)` / `createUtxosEnd({ signedPsbt })` | 3-step variant for external signing | | `listUnspents()` | List unspent UTXOs with RGB allocations | ## RGB Asset Methods ### Issuing Assets ```typescript theme={null} const asset = await wallet.issueAssetNia({ ticker: 'MYTOKEN', name: 'My Token', amounts: [1_000_000], precision: 6, }); ``` | Method | Description | | -------------------------------------------------------------------------------------- | ----------------------------------------------- | | `issueAssetNia({ ticker, name, amounts, precision })` | Issue a Non-Inflatable Asset | | `issueAssetIfa({ ticker, name, precision, amounts, inflationAmounts, rejectListUrl })` | Issue an Inflatable Fungible Asset | | `issueAssetCfa(params)` | Issue a CFA asset (requires the Lightning node) | | `inflate(params)` / `inflateBegin` / `inflateEnd` | Inflate an IFA asset (atomic or 3-step) | | `decodeRGBInvoice({ invoice })` | Decode an RGB invoice | ### Receiving Assets RGB receive flows support two invoice styles: * **Blinded invoice** — most common. The receiver creates a blinded endpoint; the sender pays directly. * **Witness invoice** — the receiver binds the transfer to witness data. The sender must provide `witnessData` (at minimum `amountSat`) in `onchainSend()`. `onchainReceive()` is the single entry point. Witness invoices are the default; pass `witness: false` for a blinded invoice. `blindReceive()` and `witnessReceive()` remain available as the underlying primitives. ```typescript theme={null} // Witness invoice (default) const receive = await wallet.onchainReceive({ assetId: asset.assetId, amount: 100, }); // Blinded invoice const blind = await wallet.onchainReceive({ assetId: asset.assetId, amount: 100, witness: false, }); ``` | Method | Description | | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `onchainReceive({ assetId?, amount?, durationSeconds?, minConfirmations?, witness? })` | RGB invoice — witness by default. Pass `witness: false` for blinded. Resolves `{ invoice, recipientId, expirationTimestamp }` | | `listOnchainTransfers(assetId?)` | Alias of `listTransfers()` | ### Sending Assets ```typescript theme={null} // Blinded invoice — no witnessData await wallet.onchainSend({ invoice: blind.invoice, assetId: asset.assetId, amount: 100, feeRate: 2, }); // Witness invoice — witnessData required await wallet.onchainSend({ invoice: receive.invoice, assetId: asset.assetId, amount: 100, feeRate: 2, witnessData: { amountSat: 1000 }, }); await wallet.refreshWallet(); ``` | Method | Description | | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | | `onchainSend({ invoice, assetId?, amount?, donation?, feeRate?, minConfirmations?, witnessData? })` | Atomic RGB send (begin → sign with the stored mnemonic → end) | | `onchainSendBegin(params)` / `onchainSendEnd({ signedPsbt })` | 3-step variant for external signing | | `sendBtc({ address, amount, feeRate })` | Atomic on-chain BTC send — returns the txid | | `sendBtcBegin(params)` / `sendBtcEnd({ signedPsbt })` | 3-step BTC send for external signing | | `signPsbt(psbt)` | Sign a PSBT with the wallet mnemonic | ## Lightning Methods Lightning requires a resolved `proxyUrl` (set or defaulted, e.g. `utexo`) and usable peer/channel state. ```typescript theme={null} await wallet.connectPeer(`${peerPubkey}@peer.example.com:9735`); const { temporaryChannelId, fundingTxid } = await wallet.openChannel({ peerPubkey, capacitySat: 100_000n, isPublic: false, assetId: asset.assetId, assetLocalAmount: 600n, }); ``` `openChannel` both opens **and funds** the channel, then returns once the funding tx is submitted — poll `listChannels()` until `isUsable`. ```typescript theme={null} const { lnInvoice } = await receiverWallet.createLightningInvoice({ expirySeconds: 900, asset: { assetId, amount: 10 }, }); const { txid: paymentHash } = await senderWallet.payLightningInvoice({ lnInvoice }); const status = await senderWallet.getLightningSendStatus(paymentHash); ``` For a BTC-only invoice, omit the `asset` field and pass `amountSats`. | Method | Description | | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | `createLightningInvoice({ amountSats?, expirySeconds?, asset? })` | Create a Lightning invoice — BTC via `amountSats`, RGB via `asset: { assetId, amount }` | | `payLightningInvoice({ lnInvoice, amount?, assetId?, assetAmount? })` | Atomic pay via the local RLN node — resolves `{ txid: paymentHash, status }` | | `getLightningSendStatus(paymentHash)` | Poll send status (`Pending`, `Claimable`, `Claiming`, `Succeeded`, `Cancelled`, `Failed`) | | `getLightningReceiveStatus(invoice)` | Poll receive status | | `listLightningPayments()` | List Lightning payments | | `connectPeer(peerUri)` / `disconnectPeer(peerPubkey)` / `listPeers()` | Peer management — `peerUri` is `'pubkey@host:port'` | | `openChannel({ peerPubkey, capacitySat, isPublic, assetId?, assetLocalAmount? })` | Open and fund a channel (`capacitySat` / `assetLocalAmount` are `bigint`) | | `closeChannel(channelId, peerPubkey?, force?)` | Close a channel | | `listChannels()` | List channels | | `getNodeInfo()` / `getNetworkInfo()` / `getNodePubkey()` | Node pubkey, channel counts, sync status | | `keysend(destPubkey, amtMsat, assetId?, assetAmount?)` | Spontaneous keysend payment | | `decodeLnInvoice(invoice)` / `invoiceStatus(invoice)` | Decode / poll a Lightning invoice | | `createHodlInvoice(params)` / `claimHodlInvoice(paymentHash, preimage)` / `cancelHodlInvoice(paymentHash)` | HODL invoices | ### LSP & Async Payments (APay) | Method | Description | | -------------------------------------------------- | ---------------------------------------------------------------------------------------------- | | `createLsp(peer?, peerPort?)` | Create an `UtexoLsp` session. No-arg: discovers the peer from `lspBaseUrl` via `GET /get_info` | | `getLspConfig()` | `{ baseUrl, bearerToken }` this wallet was created with | | `apayNewWithAddress(hostNodeId, username, domain)` | Register an attested hash pool | | `apayNew(hostNodeId)` | Register a hash pool without an address attestation | See the [LSP guide](https://github.com/UTEXO-Protocol/rgb-sdk-web/blob/dev/docs/lsp.md) and [async payments guide](https://github.com/UTEXO-Protocol/rgb-sdk-web/blob/dev/docs/async-payments.md) in the package repo for composed `UtexoLsp` flows. ## Backup and Restore Backups are recommended after every significant state change: UTXO creation, asset issuance, and transfers. ### File Backup Creates an encrypted backup as raw bytes. Store or download the bytes — there is no file path in the browser. ```typescript theme={null} await wallet.createBackup({ backupPath: '', password: 'strong-password' }); const backupBytes = wallet.getLastBackupBytes(); wallet.restoreFromBackupBytes(backupBytes, 'strong-password'); ``` ### VSS Backup VSS keeps an encrypted remote copy of the wallet (RGB assets, stock, BDK state) and the node's LDK/channel state. Identity is derived from the mnemonic at `init()`; the server defaults to `DEFAULT_VSS_SERVER_URL`. Backup is automatic during normal operation. ```typescript theme={null} new UTEXOWallet({ mnemonic, password, network, vssUrl: 'https://vss.example.com' }); new UTEXOWallet({ mnemonic, password, network, vssUrl: null }); // disable VSS await wallet.backupNow(); const info = await wallet.vssBackupInfo(); ``` Restore is **explicit** — one call in the init → unlock gap, never automatic: ```typescript theme={null} const wallet = new UTEXOWallet({ mnemonic, password, network }); await wallet.init(); await wallet.restoreFromVss(); // takeoverFence: true by default await wallet.unlock(); ``` Only restore when the old device is actually gone. Two live writers on one channel store risk fund loss. If the old device might still be running, pass `{ takeoverFence: false }`. | Method | Description | | ----------------------------------------------- | ---------------------------------------------------------- | | `createBackup({ backupPath: '', password })` | Encrypted backup — bytes via `getLastBackupBytes()` | | `getLastBackupBytes()` | Raw bytes of the last backup | | `restoreFromBackupBytes(bytes, password)` | Restore wallet state from backup bytes | | `backupNow()` | Force a VSS upload; returns the new backup version | | `restoreFromVss(opts?)` | Explicit one-call VSS restore — init → unlock gap only | | `vssBackup(config?)` / `vssBackupInfo(config?)` | Back up to / query a chosen store | | `vssClearFence()` / `ldkVssBackupInfo()` | Bare fence clear (locked gap) / channel-replication health | ## Security The browser SDK is fully non-custodial. Private keys and mnemonics are never transmitted to remote servers. WASM runs in the browser's sandboxed environment. VSS values are encrypted client-side. For hardware wallet or external signer support, use the manual begin/end send flow: ```typescript theme={null} const unsignedPsbt = await wallet.onchainSendBegin({ invoice, assetId, amount }); const signedPsbt = await wallet.signPsbt(unsignedPsbt); await wallet.onchainSendEnd({ signedPsbt }); ``` The same begin/end pattern applies to UTXO creation (`createUtxosBegin` / `createUtxosEnd`) and BTC sends (`sendBtcBegin` / `sendBtcEnd`). Store mnemonics securely and never log or transmit them. In browser environments, use the Web Crypto API or a secure vault rather than `localStorage`. ## Demo App A full working demo is available at [rgb-sdk-web-sandbox](https://github.com/UTEXO-Protocol/rgb-sdk-web-sandbox). It covers the `UTEXOWallet` lifecycle, Lightning, LSP/APay, and file + VSS backup. ```bash theme={null} git clone https://github.com/UTEXO-Protocol/rgb-sdk-web-sandbox cd rgb-sdk-web-sandbox npm install npm run dev ``` ## Further Reading * [SDK Overview](/product-suite/sdk) — SDK family, key concepts, and execution model. * [wdk-rgb-lightning](/sdk/wdk-rgb-lightning) — Node.js / Bare WDK module for RGB Lightning. * [React Native SDK](/sdk/react-native-sdk) — On-device RLN for iOS and Android. * [Architecture](/getting-started/architecture) — The Bitcoin + RGB stack the SDK operates on. * [rgb-sdk-web README](https://github.com/UTEXO-Protocol/rgb-sdk-web/blob/dev/Readme.md) # RLN Remote Signer Source: https://docs.utexo.com/security/rln-remote-signer How Validating Lightning Signer (VLS) keeps private keys off your RGB Lightning Node. ## Overview Validating Lightning Signer (VLS) is an open-source Rust library for secure, self-custodial Lightning signers. Unlike hot wallets or blind signers, VLS keeps your private keys off the node and validates each signing request, ensuring only legitimate channel operations are approved. RGB Lightning Node includes generic remote external-signer support introduced in [UTEXO-Protocol/rgb-lightning-node#95](https://github.com/UTEXO-Protocol/rgb-lightning-node/commit/e8aa52e838ad523962e81196c137d6a7b4d45980). The VLS-specific integration described on this page remains tracked in [RGB-Tools/rgb-lightning-node#43](https://github.com/RGB-Tools/rgb-lightning-node/issues/43) and should still be considered experimental until its compatibility and production-readiness are confirmed. ## System Architecture VLS splits Lightning key management into two primary components: ### Lightning Node Runs the standard LN logic — channel opening, routing, HTLC management. **No private keys are stored here.** ### Remote Validating Signer Stores private keys in a secure environment and validates each request before generating a signature. If the request fails policy checks, it denies signing. ### Additional Components | Component | Description | | -------------------------- | ------------------------------------------------------------- | | **Policy Engine** | Customizable rules ensuring no suspicious requests are signed | | **UTXO Oracle** (optional) | Provides chain data to detect remote breaches | | **State Storage** | Secure cloud storage with anti-rollback protection | ## Validation Flow ```text theme={null} [Lightning Node] --> proposes transaction/state update | v [VLS Signer] --> checks protocol correctness + local policy | +-- valid --> returns signature | +-- invalid --> rejects request ``` 1. The Lightning Node proposes a transaction or state update. 2. VLS checks protocol correctness and local policy. 3. If valid, the signer returns a signature. Otherwise, it rejects the request. ## Why This Matters Traditional Lightning nodes require private keys to be on the same machine that handles routing and channel logic. VLS decouples these concerns: * **Reduced attack surface** — a compromised node cannot access signing keys * **Policy enforcement** — custom rules prevent unauthorized channel operations * **Self-custody** — keys never leave the secure signing environment # Utexo Overview Source: https://docs.utexo.com/what-utexo-is Utexo is a Bitcoin-native execution and settlement layer that allows payment operators to process stablecoin payments with predictable costs, private execution, and Bitcoin-anchored settlement through a single low-friction API integration. It leverages Bitcoin's finality, censorship resistance, and global liquidity as the security and settlement anchor of the system. ## The Problem with Existing Stablecoin Rails Existing stablecoin payment infrastructure was built for public blockchains, not business operations: * **Unpredictable fees** - gas markets fluctuate with network demand, making unit economics unreliable for payment operators. * **Public execution** - every transaction is visible on-chain, exposing business-sensitive payment flows. * **Fragmented settlement** - routing, liquidity management, and asset validation are handled by separate systems, increasing integration complexity. * **No Bitcoin finality** - most stablecoin rails depend on smart contract platforms without Bitcoin's proof-of-work security guarantees. These constraints make stablecoin settlement operationally brittle for payment systems, exchanges, wallets and financial operators that need deterministic margins and compliance-friendly infrastructure. ## The Utexo Framework Utexo redefines stablecoin settlement by combining four core design principles: * **Deterministic cost model** - fees are predefined and fixed at the protocol level. Transactions do not compete for global blockspace and are not subject to congestion-driven pricing. * **Off-chain execution with on-chain anchoring** - execution occurs off-chain for performance and scalability, while cryptographic commitments are anchored to Bitcoin for correctness and dispute resolution. * **Bitcoin + RGB + Lightning convergence** - stablecoins are issued and transferred using the RGB protocol, while payments are executed over the Lightning Network for instant settlement and low latency. Bitcoin provides the trust anchor for the entire stack. * **Single execution layer** - Utexo abstracts routing, liquidity management, asset validation and settlement coordination into a unified layer exposed via SDK and API, eliminating the need to integrate multiple systems. ## Getting Started Understand why existing stablecoin rails fail for business settlement and what Utexo solves. Learn how Bitcoin, the Lightning Network, RGB, and Utexo fit together as a unified stack. Integrate Utexo and process your first stablecoin payment in minutes. Explore the SDK, Cloud Modules, Mint and Cross-chain Swap. ## Key Design Properties Unlike public blockchain fee markets, Utexo's settlement layer uses a fixed, protocol-level fee schedule. Payment providers can model exact unit economics without exposure to gas price volatility. Transactions are executed off-chain within Utexo's settlement layer. Only cryptographic commitments are published to Bitcoin, preserving the confidentiality of business payment flows. Utexo does not rely on a new consensus mechanism. It inherits Bitcoin's finality and censorship resistance by anchoring settlement state to the Bitcoin blockchain. Applications integrate through a single SDK and API. Utexo handles routing, liquidity, asset validation and settlement coordination internally — no protocol-specific logic required in application code. ## Further Reading * [The Problem](/getting-started/the-problem) - Why existing stablecoin rails fail for business settlement. * [Architecture](/getting-started/architecture) - How Bitcoin, the Lightning Network, RGB, and Utexo fit together. * [Product Suite](/product-suite) - SDK/API, Cloud Modules, Mint, and Cross-chain Swap.