Channel Addresses

Burak
5 min readAug 6, 2022

--

Imagine you can create a bitcoin address, and give it to a third party such as a friend, a bitcoin exchange, or a payroll service where they make you an on-chain payment where the payment is a lightning channel in and of itself. Here’s where the channel addresses come in.

Channel addresses make it possible to craft a bech32m address such that whenever it’s funded by someone, it becomes a payment channel between you and your channel partner (LSP) where the channel funds are initially kept on your side. This makes the onboarding UX frictionless, significantly reduces on-chain footprint, and allows for batched transactions for opening channels. The Bitcoin network can theoretically open up to ~38 channels per second.

Channel addresses should not be confused with “Lightning Addresses,” which is an abstraction over sending lightning payments post-channel-formation. “Channel address” is a way to open lightning channels non-interactively.

Today two if not more approaches exist to potentially enabling non-interactive channels;
1. SIGHASH_NOINPUT can solely enable non-interactive channels by crafting a refund transaction in advance of a funding transaction.
2. Jeremy Rubin has an approach to enable non-interactive channels using OP_CTV.

However, both approaches require determinism in that refund closure must have outputs with pre-determined values, and so is the channel capacity. For example, a non-interactive channel with an expected total channel capacity of 1 BTC must be coordinated in advance to refund the user 1 BTC. This channel must be explicitly funded 1 BTC since the exceeding values are not bound to refund outputs and therefore might be burnt as transaction fees. The requirement for paying a bitcoin address an explicit amount cannot be safely fulfilled since BIP70-payment protocol URIs are not widely recognized and standardized by most wallets and exchanges. Accidentally reusing the same address twice might also result in a loss of funds in both approaches.

Enabling channel addresses requires three new additions to the Bitcoin scripting language under a new TapLeaf version. Namely; OP_TXHASH, OP_CHECKSIGFROMSTACK and OP_SUB64.

Logic flow for eltoo-compatible channel addresses

A channel address is a p2tr output with a single-leaf script path and a MuSig2 key path. The key path is a 2-of-2 common pubkey of user and LSP which is used for everything except a refund; channel updates, uniliteral settlements, and collaborative settlements. The script path initiates refund:trigger — a window period for the user to claim a refund. This is triggered if the channel partner (LSP) becomes unresponsive or non-collaborative once the channel is funded so that the user can exit from the channel without requiring a signature from the channel partner.

If the channel partner is responsive, and therefore exchanges signatures for eltoo:initiator > eltoo:trigger > Settle:0, the refund path must be revoked by the user as a next step. To revoke this, the user signs transaction IDs of ten different versions of refund:trigger, and gives those signatures to the channel partner as revocation signatures.

refund:trigger comes with one input and one output; spending F and funding R. Additional inputs such as fee supplier-inputs are not permitted in this transaction to make the transaction ID deterministic (preventing unknown outpoints from committing to txid). This is so that nValue gap between F and R must pay the transaction fees. Ten different versions of refund:trigger is required to create ten different variations on how much this nValue gap is. These ten fee tiers are subsequent powers of two of refund:trigger virtual size (189 vBytes).

All transaction fields within refund:trigger except nValues and the F outpoint are constrained to pre-determined values:

Constrained Fields:Version: 0x02000000
Locktime: 0x00000000
Sequence numbers: 0xfdffffff
Number of inputs: 0x01
Output scriptpubkeys: <R scriptPubkey>
Number of outputs: 0x01
--------------------------------------------------------------------Txhash Flag:(1) the version is covered; (2) the locktime is covered; (4) sequence numbers are covered; (7) number of inputs is covered; (9) output scriptpubkeys are covered; (10) number of outputs is covered; (14) all inputs are covered; (15) all outputs are covered;11010010110000101000-0000 > 0xd2c280

To calculate the nValue gap, F and R values must be introspected and subtracted from each other. Here’s how F value can be introspected:

Inspecting F value: <0x000208> OP_TX or OP_DUP OP_SHA256(or TAGGEDHASH) <0x000208> OP_TXHASH OP_EQUALVERIFY--------------------------------------------------------------------Txhash Flag:(5) input amounts are covered; (14) all inputs are covered;00001000000000100000-0000 > 0x000208

And here’s how R value can be introspected:

Inspecting R value:<0x800001> OP_TX

or
OP_DUP OP_SHA256(or TAGGEDHASH) <0x800001> OP_TXHASH OP_EQUALVERIFY--------------------------------------------------------------------Txhash Flag:(8) output amounts are covered; (15) all outputs are covered;00000001000000001000-0000 > 0x800001

Taking the above txhash flags into consideration, the script path that initiates the refund:trigger has this final construction:

Witness://R value 8_bytes is provided in witness, validated by OP_TXHASH
<r_nValue>
//F value 8_bytes is provided in witness, validated by OP_TXHASH
<f_nValue>
//Fee tier index 1_byte is provided in witness, from 0 to 9
<fee_tier_index>
//User signature 64_bytes is provided in witness, SIGHASH_ALL
<user_signature>
--------------------------------------------------------------------Script://Let user trigger a refund closure anytime
<user_pubKey> OP_CHECKSIGVERIFY
//Determine transaction fees based on fee tier indexOP_DUP OP_0 OP_EQUAL OP_IF OP_DROP
<0xbd00000000000000>
//Fee tier 1 sat/vByte, 189 sats
OP_ELSE OP_DUP OP_1 OP_EQUAL OP_IF OP_DROP
<0x7a01000000000000>
//Fee tier 2 sat/vByte, 378 sats
OP_ELSE OP_DUP OP_2 OP_EQUAL OP_IF OP_DROP
<0xf402000000000000>
//Fee tier 4 sat/vByte, 756 sats
OP_ELSE OP_DUP OP_3 OP_EQUAL OP_IF OP_DROP
<0xe805000000000000>
//Fee tier 8 sat/vByte, 1512 sats
OP_ELSE OP_DUP OP_4 OP_EQUAL OP_IF OP_DROP
<0xd00b000000000000>
//Fee tier 16 sat/vByte, 3024 sats
OP_ELSE OP_DUP OP_5 OP_EQUAL OP_IF OP_DROP
<0xa017000000000000>
//Fee tier 32 sat/vByte, 6048 sats
OP_ELSE OP_DUP OP_6 OP_EQUAL OP_IF OP_DROP
<0x402f000000000000>
//Fee tier 64 sat/vByte, 12096 sats
OP_ELSE OP_DUP OP_7 OP_EQUAL OP_IF OP_DROP
<0x805e000000000000>
//Fee tier 128 sat/vByte, 24192 sats
OP_ELSE OP_DUP OP_8 OP_EQUAL OP_IF OP_DROP
<0x00bd000000000000>
//Fee tier 256 sat/vByte, 48384 sats
OP_ELSE OP_DUP OP_9 OP_EQUAL OP_IF OP_DROP
<0x007a010000000000>
//Fee tier 512 sat/vByte, 96768 sats
OP_ELSE OP_RETURN OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_TOALTSTACK
//Constrain refund:trigger fields to excepted bindings
<0xd2c280> OP_TXHASH <expected_template> OP_EQUALVERIFY
//Inspect F value
OP_DUP OP_SHA256(or TAGGEDHASH) <0x000208> OP_TXHASH OP_EQUALVERIFY
//Inspect R value
OP_DUP OP_SHA256(or TAGGEDHASH) <0x800001> OP_TXHASH OP_EQUALVERIFY
//Calculate F - R (paid txfees)
OP_SUB64 OP_VERIFY
//Constrain paid txfees to tier txfees
OP_FROMALTSTACK OP_EQUAL

If a revoked refund:trigger is initiated by the user, the channel partner can then take all the funds by triggering refund:breach immediately.

Since refund:breach is the child of refund:trigger, the message that commits to revocation signature is its outpoint, and it can be inspected as follows:

(3) txids are covered; (14) all inputs are covered;00100000000000100000-0000 > 0x200200

The script path that triggers refund:breach has the following script:

Witness:<user_revocation_signature><lsp_signature>--------------------------------------------------------------------Script://Let channel partner trigger a breach immediatly
<lsp_pubkey> OP_CHECKSIGVERIFY
//With the user revocation signature
<0x200200> OP_TXHASH <user_pubkey> OP_CHECKSIGFROMSTACK

The script path that triggers refund:claim has the following script:

Witness:<user_signature>--------------------------------------------------------------------Script://After delay
<delay> OP_CHECKSEQUENCEVERIFY OP_DROP
//User can finalize the refund
<user_pubkey> OP_CHECKSIG

Reusing a channel address twice could have resulted in losing funds given Eltoo path. To prevent this, an extra step called eltoo:initiator to the beginning of Eltoo path is added. This initial step must always be signed with SIGHASH_ALL while subsequent parts are signed with SIGHASH_NONE.

--

--