Handshake logo

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.


HIP:
0001
Status:
Draft
Type:
Standards Track
Created:
Wed, 05 Aug 2020
Last commit:
Mon, 13 Mar 2023
Author:
Mark Tyneway <mark.tyneway@gmail.com>

Edit on GitHub