Atomic swaps walkthrough¶
Two concrete walkthroughs:
- Cross-chain BTC ↔ NAV via HTLC.
- Intra-chain NAV ↔ TokenA via BLS signature aggregation.
Concept doc: Concepts → Atomic swaps.
Cross-chain HTLC: BTC ↔ NAV¶
Alice has NAV, wants BTC. Bob has BTC, wants NAV.
Setup¶
Agreed:
amount_nav = 1000 NAV
amount_btc = 0.012 BTC
Alice timelock = t + 24h
Bob timelock = t + 48h # must be > Alice's
Alice:
secret_A = random_32_bytes()
hash_A = HASH160(secret_A)
share hash_A with Bob
Step 1 — Bob locks BTC¶
Bob creates a Bitcoin HTLC:
OP_IF
OP_HASH160 <hash_A> OP_EQUALVERIFY
<alice_btc_pubkey> OP_CHECKSIG
OP_ELSE
<bob_timelock> OP_CHECKLOCKTIMEVERIFY OP_DROP
<bob_btc_pubkey> OP_CHECKSIG
OP_ENDIF
Funds 0.012 BTC to this script's P2SH/P2WSH. Broadcasts.
Step 2 — Alice locks NAV¶
After seeing Bob's BTC funding confirmed, Alice creates the BLSCT HTLC via:
navio-cli createblsctrawtransaction \
'[{...inputs...}]' \
'[{"address":"<htlc-output>", "amount":1000}]'
Where the HTLC script is:
OP_IF
OP_HASH160 <hash_A> OP_EQUALVERIFY
<bob_nav_bls_pubkey> OP_BLSCHECKSIG
OP_ELSE
<alice_timelock> OP_CHECKLOCKTIMEVERIFY OP_DROP
<alice_nav_bls_pubkey> OP_BLSCHECKSIG
OP_ENDIF
Crucial: set the output's BLSCT spending key to zero so script logic alone governs spending. Use deriveblsctspendingkey helpers.
Step 3 — Alice claims Bob's BTC¶
Alice builds and broadcasts a Bitcoin tx spending Bob's HTLC on the IF branch:
secret_A is now public on Bitcoin.
Step 4 — Bob claims Alice's NAV¶
Bob extracts secret_A from the Bitcoin tx, builds a Navio tx spending Alice's HTLC:
Broadcasts on Navio. Swap complete.
Refund (failure)¶
If step 3 doesn't happen before Alice's timelock:
- Alice refunds her NAV via the ELSE branch with her signature.
- Bob refunds his BTC via the ELSE branch after his (longer) timelock.
Timelock ordering (alice < bob) ensures Alice has time to claim before her refund path opens, or to fall back to refund if Bob doesn't publish.
What can go wrong¶
- Alice claims + Bob doesn't learn secret in time. Can't happen on-chain — the secret is in a publicly-visible Bitcoin tx.
- Chain reorg unwinds Alice's claim. The secret is still public in whatever Bitcoin tx replaced it; as long as Bob's claim on Navio confirms before Alice's Navio timelock, funds are safe. For high-value swaps, use deeper confirmations.
- Fee estimation issues. The refund path must be funded with enough fee to confirm; RBF or fee-bumping may be required.
Intra-chain aggregated swap: NAV ↔ TokenA¶
Alice wants to sell 100 TokenA for 10 NAV.
Step 1 — Alice builds an unbalanced partial tx¶
Using createblsctrawtransaction:
inputs:
- 100 TokenA output from Alice's wallet
outputs:
- 10 NAV output addressed to Alice's wallet
This is unbalanced (Alice spends 100 TokenA, creates 10 NAV — no source for the NAV). Alice signs her input with signblsctrawtransaction. The signature covers only what Alice committed to; the transaction is not yet broadcast-able.
Alice publishes the partial raw tx hex to an order book, DM, peer-to-peer channel.
Step 2 — Bob fills¶
Bob receives the partial hex. He:
- Decodes it with
decodeblsctrawtransactionto verify the advertised trade. - Builds a completion tx adding:
- 10 NAV input from his wallet.
- 100 TokenA output addressed to himself.
- Signs his input.
Step 3 — Aggregate + broadcast¶
Either party aggregates the two transactions:
import { NavioClient } from 'navio-sdk';
const client = new NavioClient({ /* … */ });
await client.initialize();
const combined = client.aggregateTransactions([
aliceOrderHex,
bobFillHex,
]);
await client.broadcastRawTransaction(combined.rawTx);
console.log('swap tx:', combined.txId);
Under the hood, BLS signatures aggregate by summing group elements; the combined signature verifies against the union of signed inputs. Consensus sees a single balanced confidential transaction and accepts it.
Privacy properties of the aggregated swap¶
- Amounts hidden from observers.
- Token id is cleartext (BLSCT protocol limitation — required for per-asset balance enforcement).
- No linkage between Alice's "selling" role and Bob's "buying" role visible on-chain.
- Fee payer is whichever side includes fee-paying NAV inputs (typically encoded in the original partial transaction).
Multi-party or multi-asset¶
Same mechanic scales to N parties or N assets — each party contributes inputs and outputs, all signatures aggregate into one. Coordinated CoinJoin-style transactions with no central coordinator are possible.
References¶
CTx.aggregateTransactions— library primitive.NavioClient.aggregateTransactions— SDK wrapper.- BLSCT signatures — why aggregation works.
OP_BLSCHECKSIG— opcode0xbb.