SIP-3: Lightning-Atomic NFT Trades
Sparkle Improvement Proposal for Trustless Ordinal Swaps
SIP-3 Draft Specification
Version 0.2.0 | Status: Draft
Author: David A. Michael
Status: Draft Specification
- Reference Implementation: TypeScript SDK available on NPM
- Theoretical design: Untested in real environments
- Subject to change: Specification may be revised
Abstract
SIP-3 defines a protocol for atomic swaps between Lightning Network payments and Bitcoin Ordinal inscriptions. The protocol uses Hash Time-Locked Contracts (HTLCs) to ensure that either both parties receive their expected assets, or neither transaction completes.
1. Motivation
Current Ordinal trading methods require either:
- Custodial trust: Marketplaces hold assets during trade
- Slow settlement: PSBT-based trades require on-chain confirmation
SIP-3 proposes a mechanism where Lightning payment settlement is instant while maintaining trustless guarantees through cryptographic locks.
2. Specification
2.1 Sparkle Swap Script
The ordinal is locked in a Taproot address with two spending paths:
// Taproot Script Tree
//
// Path 1: Buyer Claim (Hashlock)
// Requires: preimage + buyer_signature
OP_SHA256 <payment_hash> OP_EQUALVERIFY
<buyer_pubkey> OP_CHECKSIG
// Path 2: Seller Refund (Timelock)
// Requires: timeout expired + seller_signature
<locktime> OP_CHECKLOCKTIMEVERIFY OP_DROP
<seller_pubkey> OP_CHECKSIG
2.2 Trade Flow
| Step | Actor | Action |
|---|---|---|
| 1 | Seller | Generates random preimage r, computes H = SHA256(r) |
| 2 | Seller | Creates Taproot address with hashlock H and buyer pubkey |
| 3 | Seller | Transfers ordinal to Taproot address (on-chain) |
| 4 | Seller | Creates Lightning invoice with payment_hash = H |
| 5 | Buyer | Pays Lightning invoice, learns preimage r |
| 6 | Buyer | Claims ordinal using r + signature (on-chain) |
2.3 Timeout Parameters
To ensure safety, the protocol enforces delta-safe timelocks:
- Lightning HTLC timeout:
T_lnblocks - On-chain claim window:
T_claim = T_ln - delta - Seller refund time:
T_refund = T_ln + delta - Recommended delta: 144 blocks (24 hours)
2.4 Buyer Deposit
To prevent "free option" attacks, the buyer MUST pay a non-refundable deposit:
- Deposit amount: 1% of trade value (minimum 1000 sats)
- Purpose: Compensates seller for locked liquidity if buyer abandons
- Collection: Deposit is paid via separate Lightning invoice before trade initiation
3. Message Format
3.1 Trade Request
{
"p": "sparkle",
"op": "trade_request",
"v": 1,
"inscription_id": "abc123...i0",
"buyer_pubkey": "02...",
"offer_sats": 100000,
"deposit_invoice": "lnbc10n1..."
}
3.2 Trade Accept
{
"p": "sparkle",
"op": "trade_accept",
"v": 1,
"inscription_id": "abc123...i0",
"funding_txid": "def456...",
"funding_vout": 0,
"payment_hash": "789abc...",
"invoice": "lnbc1m1...",
"refund_locktime": 900144,
"witness_script": "..."
}
3.3 Trade Complete
{
"p": "sparkle",
"op": "trade_complete",
"v": 1,
"inscription_id": "abc123...i0",
"claim_txid": "fed987...",
"preimage": "..."
}
4. Security Considerations
4.1 Atomicity Guarantee
The protocol ensures atomicity through cryptographic binding:
- Lightning payment reveals preimage
- Preimage is required to claim ordinal
- Without payment, buyer cannot claim
- After timeout, seller can refund
4.2 Attack Mitigations
| Attack | Mitigation |
|---|---|
| Free option (buyer delays) | Non-refundable 1% deposit |
| Double-spend by seller | Wait for funding tx confirmation before payment |
| Preimage withholding | Buyer learns preimage from Lightning payment |
| Timeout race condition | Delta-safe timelocks (2x margin) |
4.3 Trust Assumptions
The protocol is trust-minimized, not trustless:
- Coordinator can censor trades but cannot steal funds
- Lightning routing must succeed within timeout
- Bitcoin network must confirm claim before refund timeout
5. Reference Implementation
5.1 Witness Script Construction (JavaScript)
import * as btc from '@scure/btc-signer';
import { sha256 } from '@noble/hashes/sha256';
function createSparkleSwapScript(
paymentHash, // 32 bytes
buyerPubkey, // 33 bytes
sellerPubkey, // 33 bytes
refundLocktime // block height
) {
// Hashlock branch (buyer claim)
const hashlockScript = btc.Script.encode([
'OP_SHA256',
paymentHash,
'OP_EQUALVERIFY',
buyerPubkey,
'OP_CHECKSIG'
]);
// Timelock branch (seller refund)
const timelockScript = btc.Script.encode([
btc.Script.encodeNumber(refundLocktime),
'OP_CHECKLOCKTIMEVERIFY',
'OP_DROP',
sellerPubkey,
'OP_CHECKSIG'
]);
return { hashlockScript, timelockScript };
}
5.2 Claim Transaction
function createClaimTransaction(
fundingTxid,
fundingVout,
fundingAmount,
preimage,
buyerPrivkey,
destinationAddress,
feeRate
) {
const tx = new btc.Transaction();
tx.addInput({
txid: fundingTxid,
index: fundingVout,
witnessUtxo: {
script: taprootOutputScript,
amount: BigInt(fundingAmount)
},
tapLeafScript: hashlockLeaf
});
const fee = BigInt(feeRate * 150); // ~150 vbytes
tx.addOutput({
address: destinationAddress,
amount: BigInt(fundingAmount) - fee
});
// Sign and add preimage to witness
tx.sign(buyerPrivkey);
tx.finalize();
return tx.hex;
}
6. Compatibility
6.1 Lightning Implementations
- LND: Compatible via standard BOLT-11 invoices
- Core Lightning: Compatible
- Eclair: Compatible
- LDK: Compatible
6.2 Bitcoin Requirements
- Taproot: Required (activated block 709,632)
- Schnorr signatures: Required
- CLTV: Required (BIP-65)
7. Future Extensions
- SIP-4: Multi-coordinator escrow for censorship resistance
- SIP-5: Batch trades for collection purchases
- SIP-6: Cross-chain atomic swaps