Multi-hop Transfers
User manual on how to connect to the public Testnet nodes
TL;DR
Connect your local node to Fiber's public relay nodes, open a channel, and send multi-hop payments through the Testnet. Your local node does not need a public IP.
Public Testnet Node Addresses
node1: /ip4/18.162.235.225/tcp/8119/p2p/QmXen3eUHhywmutEzydCsW4hXBoeVmdET2FJvMX69XJ1Eo
node2: /ip4/18.163.221.211/tcp/8119/p2p/QmbKyzq9qUmymW2Gi8Zq7kKVpPiNA1XUJ6uMvsUC4F3p89Local Node Setup
-
Download fnn from the releases page:
mkdir tmp && cd tmp tar xzvf fnn-latest.tar.gzmacOS Security
xattr -d com.apple.quarantine fnn fnn-cli fnn-migrate -
Create account and export private key:
mkdir -p testnet-fnn/nodeA/ckb ./ckb-cli account new # save the lock_arg ./ckb-cli account export --lock-arg <YOUR_LOCK_ARG> --extended-privkey-path ./exported-key head -n 1 ./exported-key > testnet-fnn/nodeA/ckb/key chmod 600 testnet-fnn/nodeA/ckb/key -
Copy config and tools:
cp config/testnet/config.yml testnet-fnn/nodeA cp fnn-cli testnet-fnn/nodeAHTTP Proxy Issues
export NO_PROXY=127.0.0.1,localhost -
Fund nodeA's address with 10,000 CKB and 20 RUSD:
- CKB: https://faucet.nervos.org
- RUSD: https://testnet0815.stablepp.xyz/faucet (claim via JoyID, then transfer to nodeA's address)
-
Start nodeA:
FIBER_SECRET_KEY_PASSWORD='123' RUST_LOG=info ./fnn -c testnet-fnn/nodeA/config.yml -d testnet-fnn/nodeA > testnet-fnn/nodeA/a.log 2>&1 &
CKB Channel with Public Node 1
CLI amounts are in shannons (1 CKB = 100,000,000). RPC amounts are hex strings (e.g. "0x5f5e100" = 100,000,000).
1. Connect to node1
First get node1's pubkey:
curl -s 'http://18.162.235.225:8227' \
-H 'Content-Type: application/json' \
-d '{"id":1,"jsonrpc":"2.0","method":"node_info"}' | grep -o '"pubkey":"[^"]*"'Then connect:
cd testnet-fnn/nodeA && ./fnn-cli peer connect_peer \
--address "/ip4/18.162.235.225/tcp/8119/p2p/QmXen3eUHhywmutEzydCsW4hXBoeVmdET2FJvMX69XJ1Eo"curl -s 'http://127.0.0.1:8227' \
-H 'Content-Type: application/json' \
-d '{
"id": 1, "jsonrpc": "2.0", "method": "connect_peer",
"params": [{"pubkey": "<node1_pubkey>", "address": "/ip4/18.162.235.225/tcp/8119/p2p/QmXen3eUHhywmutEzydCsW4hXBoeVmdET2FJvMX69XJ1Eo"}]
}'2. Open a CKB Channel (500 CKB minimum)
node1 requires at least 438 CKB funding amount.
cd testnet-fnn/nodeA && ./fnn-cli channel open_channel \
--pubkey <node1_pubkey> \
--funding-amount 50000000000 \
--public truecurl -s 'http://127.0.0.1:8227' \
-H 'Content-Type: application/json' \
-d '{
"id": 2, "jsonrpc": "2.0", "method": "open_channel",
"params": [{"pubkey": "<node1_pubkey>", "funding_amount": "0xba43b7400", "public": true}]
}'3. Wait for ChannelReady
./fnn-cli channel list_channelscurl -s 'http://127.0.0.1:8227' \
-H 'Content-Type: application/json' \
-d '{"id": 3, "jsonrpc": "2.0", "method": "list_channels", "params": [{"peer_pubkey": "<node1_pubkey>"}]}'After ChannelReady, wait a few minutes before sending payments — the gossip protocol needs time to sync routing info.
4. Create an Invoice on node2
Generate a preimage: payment_preimage="0x$(openssl rand -hex 32)"
./fnn-cli --url http://18.163.221.211:8227 invoice new_invoice \
--amount 100000000 \
--currency Fibt \
--description "test invoice" \
--expiry 3600 \
--payment-preimage $payment_preimagecurl -s 'http://18.163.221.211:8227' \
-H 'Content-Type: application/json' \
-d "{
\"id\": 4, \"jsonrpc\": \"2.0\", \"method\": \"new_invoice\",
\"params\": [{
\"amount\": \"0x5f5e100\",
\"currency\": \"Fibt\",
\"description\": \"test invoice\",
\"expiry\": \"0xe10\",
\"payment_preimage\": \"$payment_preimage\",
\"hash_algorithm\": \"sha256\"
}]
}"5. Send Payment (nodeA → node1 → node2)
./fnn-cli payment send_payment --invoice "<invoice_address>"curl -s 'http://127.0.0.1:8227' \
-H 'Content-Type: application/json' \
-d '{"id": 6, "jsonrpc": "2.0", "method": "send_payment", "params": [{"invoice": "<invoice_address>"}]}'6. Close the Channel
./fnn-cli channel shutdown_channel \
--channel-id <channel_id> \
--close-script '{"code_hash":"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8","hash_type":"type","args":"<your_lock_arg>"}'curl -s 'http://127.0.0.1:8227' \
-H 'Content-Type: application/json' \
-d '{
"id": 9, "jsonrpc": "2.0", "method": "shutdown_channel",
"params": [{
"channel_id": "<channel_id>",
"close_script": {
"code_hash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8",
"hash_type": "type",
"args": "<your_lock_arg>"
},
"fee_rate": "0x3FC"
}]
}'RUSD Channel with Public Node 1
The steps are identical to the CKB channel above, with two differences:
- Open channel — add
funding_udt_type_script:
./fnn-cli channel open_channel \
--pubkey <node1_pubkey> \
--funding-amount 20 \
--public true \
--funding-udt-type-script '{"code_hash":"0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a","hash_type":"type","args":"0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b"}'curl -s 'http://127.0.0.1:8227' \
-H 'Content-Type: application/json' \
-d '{
"id": 2, "jsonrpc": "2.0", "method": "open_channel",
"params": [{
"pubkey": "<node1_pubkey>",
"funding_amount": "0x2540be400",
"public": true,
"funding_udt_type_script": {
"code_hash": "0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a",
"hash_type": "type",
"args": "0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b"
}
}]
}'- Create invoice — add
udt_type_script:
./fnn-cli --url http://18.163.221.211:8227 invoice new_invoice \
--amount 100000000 \
--currency Fibt \
--description "test RUSD invoice" \
--expiry 3600 \
--udt-type-script '{"code_hash":"0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a","hash_type":"type","args":"0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b"}'curl -s 'http://18.163.221.211:8227' \
-H 'Content-Type: application/json' \
-d "{
\"id\": 4, \"jsonrpc\": \"2.0\", \"method\": \"new_invoice\",
\"params\": [{
\"amount\": \"0x5f5e100\",
\"currency\": \"Fibt\",
\"description\": \"test RUSD invoice\",
\"expiry\": \"0xe10\",
\"payment_preimage\": \"$payment_preimage\",
\"hash_algorithm\": \"sha256\",
\"udt_type_script\": {
\"code_hash\": \"0x1142755a044bf2ee358cba9f2da187ce928c91cd4dc8692ded0337efa677d21a\",
\"hash_type\": \"type\",
\"args\": \"0x878fcc6f1f08d48e87bb1c3b3d5083f23f8a39c5d5c764f253b55b998526439b\"
}
}]
}"node1 requires at least 20 RUSD funding amount. The send_payment call is identical to the CKB flow above.