This details the exact format of all on-chain transactions, which both sides need to agree on to ensure signatures are valid.
- Funding Transaction
- Contract Execution Transaction
- Refund Transaction
- Fees
- Test Vectors
- References
- Authors
- version: 2
- locktime: 0
The funding inputs and change output script public keys are negotiated in the offer and accept messages.
The inputs are sorted by each funding_input
's input_serial_id
in ascending order.
The outputs are sorted in ascending order based on their respective change_serial_id
or fund_output_serial_id
.
All funding inputs must be Segwit or nested P2SH(Segwit) in order to protect against malleability attacks.
- The funding output script is a P2WSH to:
2 <pubkey1> <pubkey2> 2 OP_CHECKMULTISIG
-
Where
pubkey1
is the lexicographically lesser ofoffer_funding_pubkey
andaccept_funding_pubkey
, and wherepubkey2
is the lexicographically greater of the two. -
Where both
pubkey
s are in compressed format.
We order the pubkeys lexicographically to comply with BIP 67, as well as have the same fingerprint as a lightning funding output. This will improve the privacy for users as DLCs will share the same fingerprint as lightning channels as well as all other 2-of-2 multisig contracts compliant with BIP 67.
The funding transaction's change outputs should pay to the address specified in the relevant offer/accept message. A change output's value should equal the total funding amount of that party subtracted by their total collateral, their fees for this transaction, and their fees for the largest possible closing transaction. If this value is below the dust limit of 1000 satoshis
, then that party must include additional funding in order to ensure they have a valid anchor output.
Also known as a CET.
- version: 2
- locktime:
cet_locktime
- txin count: 1
txin[0]
outpoint:txid
of funding transaction andoutput_index
0txin[0]
sequence: 0xFFFFFFFEtxin[0]
script bytes: 0txin[0]
witness:0 <signature_for_pubkey1> <signature_for_pubkey2>
The output script public keys and cet_locktime
are negotiated in the offer and accept messages.
In the witness pubkey1
is the lexicographically lesser of offer_funding_pubkey
and accept_funding_pubkey
, and where pubkey2
is the lexicographically greater of the two.
There will be one CET for every possible outcome, the output values correspond to such an outcome and are negotiated in the offer message.
The outputs are sorted by each user's payout_serial_id
in ascending order.
If either party receives less than the dust limit of 1000 satoshis
for this outcome, then their output is not produced.
This output sends funds won by the offerer corresponding to this CET's outcome to the offerer's final address specified in the offer message.
This output sends funds won by the accepter corresponding to this CET's outcome to the accepter's final address specified in the accept message.
The refund transaction is exactly the same as a Contract Execution Transaction except that its locktime is refund_locktime
(as negotiated in the offer message) instead of cet_locktime
and the output values for the offerer and the accepter are their respective total collateral values from their offer/accept messages.
All fee calculations for all transactions are based on the fee rate specified in the offer message and the expected weight of the transaction in question.
Hereafter, the sum(calc)
function means computing calc
for each of the input in the scope of the current computation and adding the results together.
As an example, if two inputs are in scope, sum(script_sig_len) = script_sig_len_input_1 + script_sig_len_2
.
The actual and expected weights vary for several reasons:
- Bitcoin uses DER-encoded signatures, which vary in size.
- Bitcoin also uses variable-length integers, so a large number of outputs will take 3 bytes to encode rather than 1.
- Witnesses may be less than
max_witness_len
- The offerer output may be below the dust limit.
- The accepter output may be below the dust limit.
Thus, a simplified formula for expected weight is used, which assumes:
- Signatures are 72 bytes long.
- There are a small number of outputs (thus 1 byte to count them).
- All witnesses are of size
max_witness_len
This yields the following expected weights (details of the computation below):
Funding Transaction weight: 214 + (72 + 4*total_change_length)
+ sum(164 + 4*script_sig_len + max_witness_len)
CET/Refund Transaction weight: 498 + 4 * total_output_length
The funding output's value is composed of the sum of both parties' total_collateral
(from offer/accept messages) plus the max_fee
of closing transactions. In this way all fees are paid for in the Funding Transaction so that the funding output's value is inflated and the outputs of CETs and the refund transaction are the exact amounts specified in the offer message's contract information (or total collateral specified in the offer and accept messages for the refund transaction) with no fees subtracted from closing transactions.
Shared fields' fees are paid evenly between the two parties, while fields that belong to a specific party (i.e. funding inputs, change outputs, CET outputs) are paid by the contributing party. Specifically, a party's funding transaction and closing transaction weights are computed as (details of computation below):
input_weight = sum(164 + 4*script_sig_len + max_witness_len) (over party's funding inputs)
output_weight = 36 + 4*change_spk_script length
total_funding_weight = 107 + output_weight + input_weight
cet_weight = 249 + 4*payout_spk length
These weights must be divided by 4
(rounding up) to get vbytes after which these numbers are multiplied by the fee rate. The resulting funding fee is subtracted in value from the change output while the CET fee is added to the funding output's value and also subtracted from this party's change output.
Note that if a CET occurs in which one party's output is below the dust limit of 1000 satoshis
, then the resulting fee rate will be larger than expected.
The max_witness_len
should be computed to be an upper bound on the byte size of all elements on the witness stack (and no other data). For example, a P2WPKH funding input should have a max_witness_len
of 107
or 108
depending on if you use low-R signing (which takes a byte off the sig), below is the computation for non-low-R where wallets implementing low-R can use sig: 71 bytes
below to save a byte:
p2wpkh witness: 108 bytes
- number_of_witness_elements: 1 byte
- sig_length: 1 byte
- sig: 72 bytes
- pub_key_length: 1 byte
- pub_key: 33 bytes
The expected weight of a funding transaction is calculated as follows:
funding_input: 41 + script_sig_len bytes
- previous_out_point: 36 bytes
- hash: 32 bytes
- index: 4 bytes
- var_int: 1 byte (script_sig length)
- script_sig: script_sig_len bytes
- witness <---- "witness" is stored
separately, and the cost for its size is smaller. So,
the calculation of ordinary data is separated
from the witness data.
- sequence: 4 bytes
witness_header: 2 bytes
- flag: 1 byte
- marker: 1 byte
change_output: 9 + change_spk_script length bytes
- value: 8 bytes
- var_int: 1 byte (pk_script length)
- pk_script: change_spk_script length
funding_output: 43 bytes
- value: 8 bytes
- var_int: 1 byte (pk_script length)
- pk_script (p2wsh): 34 bytes
funding_transaction: 53 + (9 + offer_change_spk_script length) + (9 + accept_change_spk_script length) + sum(41 + script_sig_len) bytes
- version: 4 bytes
- witness_header <---- part of the witness data
- count_tx_in: 1 byte
- tx_in: sum(41 + script_sig_len) bytes
funding_inputs
- count_tx_out: 1 byte
- tx_out: 43 + (9 + offer_change_spk_script length) + (9 + accept_change_spk_script length) bytes
funding_ouptut (43 bytes),
change_output (9 + offer_change_spk_script length bytes),
change_output (9 + accept_change_spk_script length bytes)
- lock_time: 4 bytes
Multiplying non-witness data by 4 results in a weight of:
// total_change_length = offer_change_spk_script length + accept_change_spk_script length
// 212 + (72 + 4*total_change_length) + sum(164 + 4*script_sig_len) weight
funding_transaction_weight = 4 * funding_transaction
// 2 + sum(offer_max_witness_len) + sum(accept_max_witness_len) weight
witness_weight = witness_header + witness * num_inputs
overall_funding_tx_weight = 214 + (72 + 4*total_change_length) + sum(164 + 4*script_sig_len + max_witness_len) weight
offer_funding_tx_weight = 107 + (36 + 4*offer_change_spk_script length) + sum(164 + 4*offer_script_sig_len + offer_max_witness_len) weight
offer_funding_tx_vbytes = Ceil(offer_funding_tx_weight / 4.0) vbytes
accept_funding_tx_weight = 107 + (36 + 4*accept_change_spk_script length) + sum(164 + 4*accept_script_sig_len + accept_max_witness_len) weight
accept_funding_tx_vbytes = Ceil(accept_funding_tx_weight / 4.0) vbytes
The expected weight of a contract execution or refund transaction is calculated as follows:
multi_sig: 71 bytes
- OP_2: 1 byte
- OP_DATA: 1 byte (offer_pubkey length)
- offer_pubkey: 33 bytes
- OP_DATA: 1 byte (accept_pubkey length)
- accept_pubkey: 33 bytes
- OP_2: 1 byte
- OP_CHECKMULTISIG: 1 byte
funding_tx_input: 41 bytes
- previous_out_point: 36 bytes
- hash: 32 bytes
- index: 4 bytes
- var_int: 1 byte (script_sig length)
- script_sig: 0 bytes
- witness <---- "witness" is used instead of "script_sig" for
transaction validation; however, "witness" is stored
separately, and the cost for its size is smaller. So,
the calculation of ordinary data is separated
from the witness data.
- sequence: 4 bytes
witness_header: 2 bytes
- flag: 1 byte
- marker: 1 byte
witness: 220 bytes
- number_of_witness_elements: 1 byte
- nil_length: 1 byte
- sig_offer_length: 1 byte
- sig_offer: 72 bytes
- sig_accept_length: 1 byte
- sig_accept: 72 bytes
- witness_script_length: 1 byte
- witness_script (multi_sig): 71 bytes
offer_output: 9 + offer_output_script length bytes
- value: 8 bytes
- var_int: 1 byte (pk_script length)
- pk_script: offer_output_script length
accept_output: 9 + accept_output_script length bytes
- value: 8 bytes
- var_int: 1 byte (pk_script length)
- pk_script: accept_output_script length
cet: 69 + offer_output_script length + accept_output_script length bytes
- version: 4 bytes
- witness_header <---- part of the witness data
- count_tx_in: 1 byte
- tx_in: 41 bytes
funding_tx_input
- count_tx_out: 1 byte
- tx_out: 18 + offer_output_script length + accept_output_script length bytes
offer_ouptut ((9 + offer_output_script length bytes)),
accept_output (9 + accept_output_script length bytes)
- lock_time: 4 bytes
Multiplying non-witness data by 4 results in a weight of:
// total_output_length = offer_output_script length + accept_output_script length
// 276 + 4 * total_output_length weight
cet_weight = 4 * cet
// 222 weight
witness_weight = witness_header + witness
overall_cet_weight = overall_refund_tx_weight = 498 + 4 * total_output_length weight
offer_cet_weight = 249 + 4 * offer_output_script_length weight
offer_cet_vbytes = Ceil(offer_cet_weight / 4.0) vbytes
accept_cet_weight = 249 + 4 * accept_output_script_length weight
accept_cet_vbytes = Ceil(accept_cet_weight / 4.0) vbytes
TODO
Nadav Kohen [email protected]
This work is licensed under a Creative Commons Attribution 4.0 International License.