Fiber LogoFiber Docs

Transfer Stablecoins

Learn how to transfer stablecoins between nodes

Requirements
Updated 4/9/2026
latest

TL;DR

Set up three nodes, open UDT (stablecoin) channels, and send a stablecoin payment through a multi-hop path. Builds on the Basic Transfer example.

Overview

This guide demonstrates UDT transfers using stablecoins (RUSD) across 3 nodes via multi-hop routing.

Prerequisites

Setting Up Your Environment

1. Prepare Fiber Binary

Download from GitHub Releases or build from source:

git clone https://github.com/nervosnetwork/fiber.git
cd fiber
cargo build --release

macOS Security

xattr -d com.apple.quarantine fnn fnn-cli

2. Configure Three Nodes

for node in node1 node2 node3; do
  mkdir $node
  cp target/release/fnn $node/
  cp target/release/fnn-cli $node/
  cp config/testnet/config.yml $node/
done

Create a CKB account for each node and export the keys:

ckb-cli account new  # repeat 3 times, save each lock_arg

# For each node directory:
mkdir ckb
ckb-cli account export --lock-arg <node_lock_arg> --extended-privkey-path ./ckb/exported-key
head -n 1 ./ckb/exported-key > ./ckb/key

Key File Format

ckb/key must contain only the 64-character hex private key, no 0x prefix.

Get Testnet funds:

3. Configure Ports

  • Node 1: RPC 8227, P2P 8228
  • Node 2: RPC 8237, P2P 8238
  • Node 3: RPC 8247, P2P 8248
View complete config.yml example
fiber:
  listening_addr: "/ip4/127.0.0.1/tcp/8228"
  bootnode_addrs:
    - "/ip4/54.179.226.154/tcp/8228/p2p/Qmes1EBD4yNo9Ywkfe6eRw9tG1nVNGLDmMud1xJMsoYFKy"
  announce_listening_addr: true
  chain: testnet
  scripts:
    - name: FundingLock
      script:
        code_hash: 0x6c67887fe201ee0c7853f1682c0b77c0e6214044c156c7558269390a8afa6d7c
        hash_type: type
        args: 0x
      cell_deps:
        - type_id:
            code_hash: 0x00000000000000000000000000000000000000000000000000545950455f4944
            hash_type: type
            args: 0x3cb7c0304fe53f75bb5727e2484d0beae4bd99d979813c6fc97c3cca569f10f6
        - cell_dep:
            out_point:
              tx_hash: 0x12c569a258dd9c5bd99f632bb8314b1263b90921ba31496467580d6b79dd14a7
              index: 0x0
            dep_type: code
    - name: CommitmentLock
      script:
        code_hash: 0x740dee83f87c6f309824d8fd3fbdd3c8380ee6fc9acc90b1a748438afcdf81d8
        hash_type: type
        args: 0x
      cell_deps:
        - type_id:
            code_hash: 0x00000000000000000000000000000000000000000000000000545950455f4944
            hash_type: type
            args: 0xf7e458887495cf70dd30d1543cad47dc1dfe9d874177bf19291e4db478d5751b
        - cell_dep:
            out_point:
              tx_hash: 0x12c569a258dd9c5bd99f632bb8314b1263b90921ba31496467580d6b79dd14a7
              index: 0x0
            dep_type: code
rpc:
  listening_addr: "127.0.0.1:8227"
ckb:
  rpc_url: "https://testnet.ckbapp.dev/"
  udt_whitelist:
    - name: RUSD
      script:
        code_hash: 0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a
        hash_type: type
        args: 0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b
      cell_deps:
        - type_id:
            code_hash: 0x00000000000000000000000000000000000000000000000000545950455f4944
            hash_type: type
            args: 0x97d30b723c0b2c66e9cb8d4d0df4ab5d7222cbb00d4a9a2055ce2e5d7f0d8b0f
      auto_accept_amount: 10
services:
  - fiber
  - rpc
  - ckb

4. Start All Nodes

# Terminal 1
FIBER_SECRET_KEY_PASSWORD='password1' RUST_LOG=info ./fnn -c node1/config.yml -d node1

# Terminal 2
FIBER_SECRET_KEY_PASSWORD='password2' RUST_LOG=info ./fnn -c node2/config.yml -d node2

# Terminal 3
FIBER_SECRET_KEY_PASSWORD='password3' RUST_LOG=info ./fnn -c node3/config.yml -d node3

Creating Stablecoin Payment Channels

1. Connect Node 1 and Node 2

cd node1 && ./fnn-cli peer connect_peer --address "/ip4/127.0.0.1/tcp/8238"
curl --location 'http://127.0.0.1:8227' \
  --header 'Content-Type: application/json' \
  --data '{
    "id": 42, "jsonrpc": "2.0", "method": "connect_peer",
    "params": [{"pubkey": "<node2_pubkey>", "address": "/ip4/127.0.0.1/tcp/8238"}]
  }'
CCC support coming soon.

Get Node 2's pubkey: cd node2 && ./fnn-cli --url http://127.0.0.1:8237 info | grep pubkey

2. Open a Stablecoin Channel (Node 1 → Node 2)

The funding_udt_type_script identifies the RUSD token:

cd node1 && ./fnn-cli channel open_channel \
  --pubkey <node2_pubkey> \
  --funding-amount 10 \
  --public true \
  --funding-udt-type-script '{"code_hash":"0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a","hash_type":"type","args":"0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b"}'
curl --location 'http://127.0.0.1:8227' \
  --header 'Content-Type: application/json' \
  --data '{
    "id": 42, "jsonrpc": "2.0", "method": "open_channel",
    "params": [{
      "pubkey": "<node2_pubkey>",
      "funding_amount": "0xa",
      "public": true,
      "funding_udt_type_script": {
        "code_hash": "0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a",
        "hash_type": "type",
        "args": "0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b"
      }
    }]
  }'
CCC support coming soon.

3. Monitor Channel Status

Wait until state_name becomes ChannelReady:

./fnn-cli channel list_channels
curl --location 'http://127.0.0.1:8227' \
  --header 'Content-Type: application/json' \
  --data '{"id": 42, "jsonrpc": "2.0", "method": "list_channels", "params": [{}]}'
CCC support coming soon.

Repeat steps 1–3 to connect Node 2 and Node 3 (using ports 8247/8248).

Generating Invoices and Making Payments

1. Generate a Stablecoin Invoice on Node 2

cd node2 && ./fnn-cli --url http://127.0.0.1:8237 invoice new_invoice \
  --amount 10 \
  --currency Fibt \
  --description "test stablecoin invoice" \
  --expiry 3600 \
  --udt-type-script '{"code_hash":"0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a","hash_type":"type","args":"0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b"}'
curl --location 'http://127.0.0.1:8237' \
  --header 'Content-Type: application/json' \
  --data '{
    "id": 42, "jsonrpc": "2.0", "method": "new_invoice",
    "params": [{
      "amount": "0xa",
      "currency": "Fibt",
      "description": "test stablecoin invoice",
      "expiry": "0xe10",
      "udt_type_script": {
        "code_hash": "0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a",
        "hash_type": "type",
        "args": "0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b"
      }
    }]
  }'
CCC support coming soon.

Generate a unique payment_preimage with: echo "0x$(openssl rand -hex 32)"

Note: CLI auto-generates preimage; for RPC add "payment_preimage": "<your_preimage>" to params.

2. Send the Stablecoin Payment from Node 1

cd node1 && ./fnn-cli payment send_payment --invoice "fibt10000000001p..."
curl --location 'http://127.0.0.1:8227' \
  --header 'Content-Type: application/json' \
  --data '{
    "id": 42, "jsonrpc": "2.0", "method": "send_payment",
    "params": [{"invoice": "fibt10000000001p..."}]
  }'
CCC support coming soon.

3. Check Channel Balance

# Node 1
./fnn-cli channel list_channels

# Node 2
./fnn-cli --url http://127.0.0.1:8237 channel list_channels
curl --location 'http://127.0.0.1:8227' \
  --header 'Content-Type: application/json' \
  --data '{"id": 42, "jsonrpc": "2.0", "method": "list_channels", "params": [{}]}'
CCC support coming soon.

Closing the Channel

cd node1 && ./fnn-cli channel shutdown_channel \
  --channel-id <channel_id> \
  --close-script '{"code_hash":"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8","hash_type":"type","args":"<your_lock_arg>"}'
curl --location 'http://127.0.0.1:8227' \
  --header 'Content-Type: application/json' \
  --data '{
    "id": 42, "jsonrpc": "2.0", "method": "shutdown_channel",
    "params": [{
      "channel_id": "<channel_id>",
      "close_script": {
        "code_hash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8",
        "hash_type": "type",
        "args": "<your_lock_arg>"
      }
    }]
  }'
CCC support coming soon.

close_script

Get args from fnn-cli info under default_funding_lock_script.args.

Important Notes

  • RUSD amounts: CLI uses base units (e.g. 10 = 10 RUSD); RPC uses hex strings (e.g. "0xa" = 10)
  • Invoice currency: Use "Fibt" for testnet, not "RUSD"
  • auto_accept_amount: Channels with funding below this value require manual acceptance

Fiber AI Assistant

Ask me anything

I can answer questions about Fiber Network using our documentation.

AI answers are based on Fiber documentation