All transactions are version 2 and use version 0 native Segwit scripts.
We use miniscript and output descriptors to generally describe outputs spending policies.
We denote N
the number of stakeholders, M
the number of fund managers (allowed
to unlock the unvault transaction output along with the cosigning servers after a timeout),
and X
the CSV value in the unvault transaction. Each transaction type here signals
replace-by-fee (RBF).
While a larger number of participants is technically possible, we explicitly limit the number of
stakeholders and managers to 20
.
The transaction which deposits into the vault.
N/A
At least one output paying to deposit_descriptor
, with:
deposit_descriptor = wsh(deposit_witness_script)
deposit_witness_script = thresh(N, pubkey1, pubkey2, ..., pubkeyN)
The transaction which spends the deposit_tx
deposit output, and creates an
unvault output spendable by the N
stakeholders or the managers (along with the cosigning
servers) after X
blocks.
The Unvault transaction is signed using a fixed 6 sat/WU
feerate. This is a
completely arbitrary value that was chosen to avoid blocking operations too early
in case of a huge load of transactions on the network and an increase of the
network mempools minimum feerate.
This transaction's fees can be bumped if not competitive (using the CPFP output) but
it will likely not be relayed if the network mempools minimum feerate goes above
24 sat/vb
until package relay is deployed on the Bitcoin network.
- version: 2
- locktime: 0
- count: 1
- inputs[0]:
- txid:
<deposit_tx txid>
- vout:
<deposit_tx vout>
- sequence:
0xfffffffd
- scriptSig:
<empty>
- witness:
satisfy(deposit_descriptor)
- txid:
-
count: 2
-
outputs[0]:
- value:
<deposit_tx output value - tx_fee - 330>
- scriptPubkey:
unvault_descriptor
- value:
-
outputs[1]:
- value:
30000
- scriptPubkey:
cpfp_descriptor
- value:
With:
unvault_descriptor = wsh(unvault_witness_script)
unvault_witness_script = or(1@thresh(len(stakeholders), stakeholders), 9@and(thresh(len(managers), managers), and(thresh(len(cosigners), cosigners), older(X))))
cpfp_descriptor = wsh(cpfp_witness_script)
cpfp_witness_script = thresh(1, pubkey1, pubkey2, ..., pubkeyM) # The pubkeys being the managers'
The transaction which spends one or many unvault_tx
output[0]
by the [M
+ cosigners]
path, only spendable after X
blocks.
The CPFP output value is adjusted depending on the actual transaction size.
- version: 2
- locktime: 0
- count: 1
- inputs[0]:
- txid:
<unvault_tx txid>
- sequence:
X
- scriptSig:
<empty>
- witness:
satisfy(unvault_descriptor)
- txid:
- count: 1
- outputs[0]:
- value:
2 * 32 * tx_size_vbytes
- scriptPubkey:
cpfp_descriptor
- value:
- outputs[1]:
- value: N/A (may be many of them)
- scriptPubkey: N/A
- outputs[n]:
- value: N/A (may be many of them)
- scriptPubkey: N/A
The transaction which spends the unvault_tx
output[0]
using the N-of-N path and
pays back to a deposit output (it is therefore another vault deposit transaction).
The Cancel transaction is signed using the ALL | ANYONECANPAY
signature hash flag, to
allow watchtowers (or anyone else) to attach fee-bumping inputs.
The Cancel transaction is signed at a fixed 22 sat/WU
feerate. This is in order to
reduce the funds burden on each of the watchtowers.
- version: 2
- locktime: 0
- count: 1
- inputs[0]:
- txid:
<unvault_tx txid>
- vout: 0
- sequence:
0xfffffffd
- scriptSig:
<empty>
- witness:
satisfy(unvault_descriptor)
- txid:
- count: 1
- outputs[0]:
- value:
<unvault_tx outputs[0] value - tx_fee>
- scriptPubkey:
deposit_descriptor
- value:
Emergency transactions are used as deterrents against threats targeting stakeholders' funds. They lock coins to what we call an EDV (Emergency Deep Vault): a script chosen by the participants and kept obfuscated by the properties of P2WSH, as the emergency transactions are never meant to be used.
Both Emergency transactions are signed at a fixed 75 sat/WU
feerate.
Both Emergency transaction are signed using the ALL | ANYONECANPAY
signature hash flag,
to allow watchtowers (or anyone else) to attach fee-bumping inputs.
The Emergency scriptPubKey
is not known to the managers.
The transaction which spends the deposit_tx
output to the EDV by the N
-of-N
path.
- version: 2
- locktime: 0
- count: 1
- inputs[0]:
- txid:
<deposit_tx txid>
- vout:
<deposit_tx vout>
- sequence:
0xfffffffd
- scriptSig:
<empty>
- witness:
satisfy(deposit_descriptor)
- txid:
- count: 1
- outputs[0]:
- value:
<deposit_tx output value - fees>
- scriptPubkey:
0x00 SHA256(<EDV_script>)
- value:
This transaction spends the unvault_tx
output[0]
to the EDV by the N
-of-N
path.
- version: 2
- locktime: 0
- count: 1
- inputs[0]:
- txid:
<unvault_tx txid>
- vout: 0
- sequence:
0xfffffffd
- scriptSig:
<empty>
- witness:
satisfy(unvault_descriptor)
- txid:
- count: 1
- outputs[0]:
- value:
<unvault_tx outputs[0] value - fees>
- scriptPubkey:
0x00 SHA256(<EDV_script>)
- value:
Bypass txs are used in the case where stakeholders need immediate access to funds. Bypass
txs avoid the controls on expenses set by stakeholders and enforced by watchtowers. A
Bypass tx spends the deposit_tx
and pays to arbitrary addresses.
- version: 2
- locktime: 0
- count: 1
- inputs[0]:
- txid:
<deposit_tx txid>
- vout:
<deposit_tx vout>
- sequence:
0xfffffffd
- scriptSig:
<empty>
- witness:
satisfy(deposit_descriptor)
- txid:
Unspecified