HIP-0001: Non-Interactive Name Atomic Swaps
Abstract
This document proposes a standard way for Handshake names to be traded on a secondary market without the need of a trusted third party to act as an escrow.
Motivation
A healthy secondary market for Handshake names will bring more activity to the Handshake economy. Without a solution for a decentralized secondary market, it is likely that most names will end up being managed on a custodial platform where there is liquidity for names.
After purchasing a name directly from the protocol, the name-owner must rely on an escrow
to sell the name to a name-buyer. This adds friction to a secondary market developing,
as escrows must be trusted and have the incentive to extract rent from the system. Transferring
a name requires two transactions, a TRANSFER
where the name owner commits to the witness
version and witness program that the name will be transferred to, and a FINALIZE
(sent after
a minimum 288 blocks) where the name is finally under control of the new owner. A non-interactive
scheme is desired such that the name holder can simply publish a partially signed transaction
that the name-buyer can fill in without needing any communication between counter-parties.
This scheme can be used to emulate a decentralized secondary market, as long as the necessary
data is made available.
Specification
Swap Script
Handshake builds on Bitcoin Script and introduces a new OP code called OP_TYPE
.
When this OP code is encountered while evaluating an input script, the covenant type
of the corresponding output is pushed on to the stack. Covenant types are represented
as integers (for example BID
is 0x03
and TRANSFER
is 0x09
). This can be used to construct
a script that has different execution paths depending on which covenant is being created by the coin-spender.
For the name-buyer to be able to trust that the name-owner will not back out of the swap
between the TRANSFER and FINALIZE actions, the ability to cancel the swap needs to be prevented.
At the protocol level, this means that only TRANSFER
and FINALIZE
should be allowed.
In addition, only the name-owner should be able to TRANSFER
and to make the scheme non-interactive,
“anyone can FINALIZE
” – although we will also add a payment requirement in a different
transaction output.
OP_TYPE
0x09 // TRANSFER
OP_EQUAL
OP_IF
<name-owner's public key>
OP_CHECKSIG
OP_ELSE
OP_TYPE
0x0a // FINALIZE
OP_EQUAL
OP_ENDIF
Signature Hash Flags
The consensus rules dictate that the TRANSFER
covenant data must commit to the
address that the FINALIZE
is eventually spent to. Since the address of the name-buyer
is unknown by the name-owner, the TRANSFER
covenant cannot be committed to by the
name-owner’s signature. The name-owner however can commit to a second transaction
output that pays themselves for the value that they are willing to sell the name for.
This is possible with SIGHASH_SINGLEREVERSE
as it will commit to the output at the opposite
index as the input being signed. For example, if the first input is signed with
SIGHASH_SINGLEREVERSE
, then only the last output will be committed to.
The name-owner would like the name-buyer to be able to add in an input that has enough value
to create a valid transaction, so SIGHASH_ANYONECANPAY
must be used as a modifier.
Ultimately, This scheme must use the signature hash flag SINGLEREVERSE | ANYONECANPAY
.
Transaction Structure
The name-owner will publish a partially-signed transaction like this:
vin:
0: current name owner, encumbered by Swap Script
vout:
0: (null)
1: payment to name-owner
This transaction is not currently valid. The signature in vin[0]
is flagged with SINGLEREVERSE | ANYONECANPAY
,
meaning the content of vout[1]
can not be changed, but additional inputs and outputs
can still be added to this transaction.
The name-buyer will take this transaction and complete it:
vin:
0: current name owner, encumbered by Swap Script
1: name-buyer's input coin (funds transaction)
vout:
0: TRANSFER to name-buyer's address
1: name-buyer's change
2: payment to name-owner
Note that even though payment to name-owner
has been bumped from index 1
to
index 2
, it is still the “reverse” of the input with the name-owner’s signature.
Swap Proof
The Swap Proof includes all of the data that must be made available for a name-buyer to trust that the name is up for sale. Note that verification of this data structure depends on verifying that the UTXO that holds the name exists.
A Swap Proof includes:
- Name
- Swap Script
- Signature
- Value
The name could be substituted for the outpoint for the name, as long as the verifier can easily verify that the UTXO representing the name does exist. Ease of integration into user interfaces should be taken into account here. The Swap Script must be hashed with SHA3-256 and compared against the locking script for the name locking the UTXO.
Protocol Design
Setup Phase
The name-owner must TRANSFER
and FINALIZE
their name to the Swap Script and make the Swap Proof available.
This enables the protocol to be non-interactive. There are many options for making the proof
available and is out of scope for this document.
Trade
The name-buyer has the Swap Proof and must verify it. To do so, they must check that the name exists on chain, reconstruct the partially-signed transaction and verify the signature. The Swap Script must be verified that it matches the template and prevents the buyer from opting out of the atomic swap.
The name-buyer adds an input that fulfills the value desired by the name seller, adds a
change output such that it is not the last output and produces a signature using SIGHASH_ALL
.
This transaction can now be broadcast to the network. After the transfer timeout elapses (288 blocks),
the UTXO is in an anyone-can-spend state because no signature checks are required in the Swap Script.
The name-buyer can follow up with the FINALIZE
transaction
to themselves and take control of the name. Note that since the name-buyer’s address is
committed to in the TRANSFER
, there is no risk created by “anyone” spending the output.
Anyone willing to pay a miner fee can finish the protocol on behalf of the name-buyer,
but the name-buyer will likely do so themselves.
Offer Discovery
Offer discovery is out of scope for this HIP but needs to be considered in its design. Ideally there is a standard way to make offers available. This is possible with an additional p2p protocol like Bitmessage or Swarm. This design hasn’t been the most successful in the past. Potentially Sia could be leveraged or a simple open source website that aggregates offers, similar to a PGP server.
Timelock Auctions
It is possible to simulate a Dutch Auction
with this protocol. The name-owner can create multiple partially-signed transactions
in a series. Each transaction in the series has a decreased payout-to-name-owner value
and an increased locktime
.
This means that as the blockchain advances over time,
transactions with lower payout values become valid. In other words, the name is opened
for sale at a high price, but this price decreases over time until a name-buyer accepts
the latest valid offer and completes the protocol. After enough time without such a completion,
all the partially-signed transactions will be valid. The name-owner can “cancel” the auction
by either “buying” their own name for the lowest price or simply by signing a TRANSFER
of the name back to their own wallet without any payment being required.
Implementation
https://github.com/kurumiimari/shakedex
Acknowledgments
@kurumiimari for implementing this proposal into a working auction system and introducing the idea of the “Dutch” auction.
@pinheadmz for optimizing the locking script and this document.
Edit on GitHub