Prior to a contract being accepted, a temporary_contract_id
is used,
which is the SHA256 hash of the offer message.
Most messages use a contract_id
to identify the contract. It's
derived from the funding transaction and the offer by combining the funding_txid
,
the funding_output_index
and the temporary_contract_id
, using big-endian
exclusive-OR (i.e. funding_output_index
alters the last 2 bytes of
funding_txid XOR temporary_contract_id
).
Contract Negotiation consists of the initiator (aka offerer) sending an offer_dlc
message,
followed by the responding node (aka accepter) sending accept_dlc
. With the
contract parameters locked in, both parties are able to create the funding
transaction and subsequently all contract execution transactions (CETs) and the refund transaction, as described in the transaction specification. As such, the accepter includes its signatures of the CETs and refund transaction in the accept_dlc
message.
The initiator is now able to generate signatures for all CETs and the refund transaction, as well as the funding transaction, and send them over using the sign_dlc
message.
Once the accepter receives the sign_dlc
message, it
must broadcast the funding transaction to the Bitcoin network.
+-------+ +-------+
| | | |
| |---- (1) offer --->| |
| | | |
| |<--- (2) accept ----| |
| A | | B |
| |---- (3) sign --->| |
| | | |
| | | (4) broadcast fund-tx
| | | |
+-------+ +-------+
- where node A is 'offerer' and node B is 'accepter'
If this fails at any stage, or if one node decides the contract terms offered by the other node are not suitable, the contract negotiation fails.
Note that multiple contracts can be open in parallel, as all DLC
messages are identified by either a temporary_contract_id
(before the
funding transaction is created) or a contract_id
(derived from the
funding transaction).
This message contains information about a node and indicates its desire to enter into a new contract. This is the first step toward creating the funding transaction and CETs.
- type: 42778 (
offer_dlc_v0
) - data:
- [
byte
:contract_flags
] - [
chain_hash
:chain_hash
] - [
contract_info
:contract_info
] - [
point
:funding_pubkey
] - [
spk
:payout_spk
] - [
u64
:payout_serial_id
] - [
u64
:offer_collateral_satoshis
] - [
u16
:num_funding_inputs
] - [
num_funding_inputs*funding_input
:funding_inputs
] - [
spk
:change_spk
] - [
u64
:change_serial_id
] - [
u64
:fund_output_serial_id
] - [
u64
:feerate_per_vb
] - [
u32
:cet_locktime
] - [
u32
:refund_locktime
]
- [
No bits of contract_flags
are currently defined, this field should be ignored.
The chain_hash
value denotes the exact blockchain that the DLC will
reside within. This is usually the genesis hash of the respective blockchain.
The existence of the chain_hash
allows nodes to open contracts
across many distinct blockchains as well as have contracts within multiple
blockchains opened to the same peer (if it supports the target chains).
contract_info
specifies the contract to be constructed and the oracles to be used.
funding_pubkey
is the public key in the 2-of-2 multisig script of
the funding transaction output. payout_spk
specifies the script
pubkey that CETs and the refund transaction should use in the sender's output.
offer_collateral_satoshis
is the amount the sender is putting into the
contract. num_funding_inputs
is the number of funding inputs contributed by
the sender and funding_inputs
contains outputs, outpoints, and expected weights
of the sender's funding inputs. change_spk
specifies the script pubkey that funding
change should be sent to.
payout_serial_id
is a randomly chosen number which uniquely identifies the payout output of the offering party.
Outputs in the contract execution transaction will be sorted by payout_serial_id
.
change_serial_id
is a randomly chosen number which uniquely identifies the change output.
Outputs in the funding transaction will be sorted by change_serial_id
and fund_output_serial_id
.
fund_output_serial_id
is a randomly chosen number which uniquely identifies the funding output.
Outputs in the funding transaction will be sorted by change_serial_id
and fund_output_serial_id
.
feerate_per_vb
indicates the fee rate in satoshi per virtual byte that both
sides will use to compute fees in the funding transaction, as described in the
transaction specification.
cet_locktime
is the nLockTime to be put on CETs. refund_locktime
is the nLockTime to be put on the refund transaction.
The sending node MUST:
- set undefined bits in
contract_flags
to 0. - ensure the
chain_hash
value identifies the chain it wishes to open the contract within. - set
payout_spk
andchange_spk
to a standard script pubkey - set
funding_pubkey
to a valid secp256k1 pubkey in compressed format. - set
offer_collateral_satoshis
to a value greater than or equal to 1000. - set
cet_locktime
andrefund_locktime
to either both be UNIX timestamps, or both be block heights as distinguished here. - set
cet_locktime
to be less thanrefund_locktime
. - use a unique
input_serial_id
for each input - set
change_serial_id
andfund_output_serial_id
to different values
The sending node SHOULD:
- set
feerate_per_vb
to at least the rate it estimates would cause the transaction to be immediately included in a block. - set
cet_locktime
to no later than the earliest expected oracle signature time. - set
refund_locktime
sufficiently long after the latest possible release of oracle signatures added to all other delays to closing the contract. - set
payout_spk
to a previously unused script public key. - set
change_spk
to a previously unused script public key.
The receiving node MUST:
- ignore undefined bits in
contract_flags
.
The receiving node MAY reject the contract if:
- it does not agree to the terms in
contract_info
. - the
contract_info
is missing relevant events. - it does not want to use the oracle(s) specified in
contract_info
. offer_collateral_satoshis
is too small.feerate_per_vb
is too small.feerate_per_vb
is too large.
The receiving node MUST reject the contract if:
- the
chain_hash
value is set to a hash of a chain that is unknown to the receiver. - the
contract_info
refers to events unknown to the receiver. - the
contract_info
refers to an oracle unknown or inaccessible to the receiver. payout_spk
orchange_spk
are not a standard script pubkey.- it considers
feerate_per_vb
too small for timely processing or unreasonably large. funding_pubkey
is not a valid secp256k1 pubkey in compressed format.funding_inputs
do not contribute at leasttotal_collateral_satoshis
plus full fee payment.- Any
input_serial_id
is duplicated - The
fund_output_serial_id
andchange_serial_id
are not set to different value - Any input in
funding_inputs
is not a BIP141 (Segregated Witness) input.
This message contains information about a node and indicates its acceptance of the new DLC, as well as its CET and refund transaction signatures. This is the second step toward creating the funding transaction and closing transactions.
- type: 42780 (
accept_dlc_v0
) - data:
- [
32*byte
:temporary_contract_id
] - [
u64
:accept_collateral_satoshis
] - [
point
:funding_pubkey
] - [
spk
:payout_spk
] - [
u64
:payout_serial_id
] - [
u16
:num_funding_inputs
] - [
num_funding_inputs*funding_input
:funding_inputs
] - [
spk
:change_spk
] - [
u64
:change_serial_id
] - [
cet_adaptor_signatures
:cet_adaptor_signatures
] - [
signature
:refund_signature
] - [
negotiation_fields
:negotiation_fields
]
- [
The temporary_contract_id
MUST be the SHA256 hash of the offer_dlc
message.
The sender MUST:
- set
accept_collateral_satoshis
to equal theoffer_dlc
'scontract_info
total_collateral
minus theoffer_collateral_satoshis
. - set
payout_spk
andchange_spk
to a standard script pubkey - set
cet_adaptor_signatures
to valid adaptor signatures, using itsfunding_pubkey
for each CET, as defined in the transaction specification and using signature public keys computed using theoffer_dlc
'scontract_info
andoracle_info
as adaptor points. - include an adaptor signature in
cet_adaptor_signatures
for every event specified in theoffer_dlc
'scontract_info
. - set
refund_signature
to the valid signature, using itsfunding_pubkey
for the refund transaction, as defined in the transaction specification. - use a unique
input_serial_id
for each input - use a unique
change_serial_id
- set
change_serial_id
so that it is not equal to thefund_output_serial_id
- use a unique
payout_serial_id
The sender SHOULD:
- set
payout_spk
to a previously unused script public key. - set
change_spk
to a previously unused script public key.
The receiver:
- if
accept_collateral_satoshis
is nottotal_collateral - offer_collateral_satoshis
:- MAY reject the contract.
- if
payout_spk
orchange_spk
are not a standard script pubkey- MUST reject the contract.
- if any input in
funding_inputs
is not a BIP141 (Segregated Witness) input.- MUST reject the contract.
- if
cet_adaptor_signatures
orrefund_signature
fail validation:- MUST reject the contract.
- if
funding_inputs
do not contribute at leastaccept_collateral_satoshis
plus fee payment- MUST reject the contract.
- if any
input_serial_id
is duplicated- MUST reject the contract.
- if any
change_serial_id
is duplicated- MUST reject the contract.
- if any
change_serial_id
is equal to thefund_output_serial_id
- MUST reject the contract.
- if any
payout_serial_id
is duplicated- MUST reject the contract.
Other fields have the same requirements as their counterparts in offer_dlc
.
This message gives all of the initiator's signatures, which allows the receiver to broadcast the funding transaction with both parties being fully committed to all closing transactions.
This message introduces the contract_id
to identify the contract.
- type: 42782 (
sign_dlc_v0
) - data:
- [
contract_id
:contract_id
] - [
cet_adaptor_signatures
:cet_adaptor_signatures
] - [
signature
:refund_signature
] - [
funding_signatures
:funding_signatures
]
- [
The sender MUST:
- set
contract_id
by exclusive-OR of thefunding_txid
, thefunding_output_index
and thetemporary_contract_id
from theoffer_dlc
andaccept_dlc
messages. - set
cet_adaptor_signatures
to valid adaptor signatures, using itsfunding_pubkey
for each CET, as defined in the transaction specification and using signature public keys computed using theoffer_dlc
'scontract_info
andoracle_info
as adaptor points. - include an adaptor signature in
cet_adaptor_signatures
for every event specified in theoffer_dlc
'scontract_info
. - set
refund_signature
to the valid signature, using itsfunding_pubkey
for the refund transaction, as defined in the transaction specification. - set
funding_signatures
to contain valid witnesses for every funding input specified in theoffer_dlc
message and in the same order.
The recipient:
- if any
signature
orwitness
is incorrect:- MUST reject the contract.
- if any witness exceeds its corresponding
max_witness_len
from theoffer_dlc
message:- MAY reject the contract.
- MUST NOT broadcast the funding transaction before receipt of a valid
sign_dlc
. - on receipt of a valid
sign_dlc
:- SHOULD broadcast the funding transaction.
For a script pub key to be valid it must be in one of the following forms:
1. `OP_DUP` `OP_HASH160` `20` 20-bytes `OP_EQUALVERIFY` `OP_CHECKSIG` (pay to pubkey hash), OR
2. `OP_HASH160` `20` 20-bytes `OP_EQUAL` (pay to script hash), OR
3. `OP_0` `20` 20-bytes (version 0 pay to witness pubkey hash), OR
4. `OP_0` `32` 32-bytes (version 0 pay to witness script hash), OR
5. `OP_1` through `OP_16` inclusive, followed by a single push of 2 to 40 bytes
(witness program versions 1 through 16)
These script pub key forms include only standard forms accepted by the wider set of deployed Bitcoin clients in the network, which increase the chances of successful propagation to miners.
Nadav Kohen [email protected]
Ben Carman [email protected]
This work is licensed under a Creative Commons Attribution 4.0 International License.