Handshake logo

HIP-0006: Trustless Live Auctions for Handshake

Abstract

We propose an ascending-price auction system for HNS domain names without trust or third-party custody. A name owner initiates an auction by locking their TLD with a verifiable script. Bidders place bids by partially-signing TRANSFER transactions, and the name owner eventually picks the highest bid and atomically swaps the name ownership for the payment. The protocol requires more interactivity and centralization than the current Shakedex-style HIP-0001 auction format, but with some compelling trade-offs. In addition, the limits on collaborative transaction construction (like atomic swaps) mean that the buyer can not add a change output to the final transaction. Because there is no change output, the name owner must pay the miner fee out of their sale price in the final transaction.

Definitions

This proposal is based on HIP-0001, and in particular the Swap Script, Transaction Structure, and Swap Proof. Handshake primitives like OP_TYPE and SIGHASH_SINGLEREVERSE are also required.

Recall the HIP-0001 Swap Script only allows two covenant actions be applied to the name:

  • The name owner can sign a TRANSFER with their private key

  • Anyone can FINALIZE without a signature

Protocol Summary

Auction OPEN

The auction technically begins when a name owner FINALIZEs a transfer of their name to a HIP-0001 locking script. The name owner must then publicly reveal the redeem script for the address that owns the name, so it can be verified. The locking script prevents the name owner from canceling an in-progress name ownership transfer. Since there is a small amount of interactivity required in the protocol, the name owner must also publish “where” the auction will take place. The auction “location” is just some internet endpoint where bidders can submit bids. It can be a private email address (in which case the name owner may choose to keep all bids confidential or truly blind), or it can be a public server that announces every new bid as they arrive.

Auction BID

A user that wants to bid on the name constructs a partially-signed transaction in the following format:

vin:
  0: current name owner, encumbered by Swap Script
  1: A UTXO controlled by the bidder of some value V
vout:
  0: TRANSFER to the bidder's address

Input 1 is signed with SIGHASH_ANYONECANPAY | SIGHASH_SINGLEREVERSE. This commits the incoming payment to the name transfer. Note that Input 0 is not signed yet, but it must be the current name-owning UTXO or the linked output 0 would be invalid.

Note that this transaction has no change output. Because the bidder is signing with single-reverse, they can’t specify a change output in addition to the name transfer output. If they were to sign with SIGHASH_ALL then the next step of the protocol would not be possible. If they signed with SIGHASH_SINGLE they could commit to a change address, but not the name transfer.

Having no change output means the INPUT coin they are spending MUST BE THE VALUE OF THE BID THEY INTEND TO PLACE ON THE NAME. This is a big inconvenience that can be solved in at least these two ways:

  • The user prepares their wallet in advance and collects UTXOs with a range of values (1 HNS, 10 HNS, 100 HNS, 1000 HNS, etc).

  • When the user wants to bid, their wallet creates a “perfect” UTXO by spending to itself, creating a coin with the exact value desired. This output can be used (even before it is confirmed) in this protocol.

Auction FINALIZE

The name owner collects partially-signed bids and after some time, declares the highest value bid the winner. The name owner completes the auction by adding a payment output to the partially-signed transaction, signing and broadcasting:

vin:
  0: current name owner, encumbered by Swap Script
  1: A UTXO controlled by the bidder of some value V
vout:
  0: TRANSFER to the bidder's address
  1: payment to the name-owner

The name owner pays themselves from the fully funded transaction, and signs input 0 with SIGHASH_ALL. This transaction is a valid atomic swap and can be broadcast to the network. Because the locking script prevents all other name actions, the auction winner can FINALIZE this name transfer any time after the 288-block lockout without any other obligation.

Note that since the bidder creates the INPUT and the name owner creates the OUTPUT, the name owner MUST also pay the miner fee for this transaction. They do so by reducing the value of output 1, effectively paying the miner fee out of the money they earned by the sale.

Extra Notes

Bids must remain valid off-chain

The partially-signed bid transactions are collected by the name owner and commit to spending a UTXO of some value V from the blockchain. In the simplest construction, nothing prevents the bidder from invalidating this off-chain transaction by double-spending the coin they used to bid. For this reason, the name owner must routinely check that all submitted bids are still valid. They can try finalizing the highest bid and if that fails, try to finalize the second-highest bid, etc.

More advanced constructions may be possible to more effectively prevent this, see the next section for one possible extension.

“Locked bids” mode

To ensure that bids are funded by reliable outputs, the bidder and name owner can engage in a time-lock multisig contract that will ensure the bids are valid until the end of the auction. Bidders will effectively be “locking up” their bids for the duration of the auction. After the auction expiry time, bidders can “redeem” their losing bids with (almost) no potential grief. This pattern should be very familiar to Handshake users!

OPEN: Name owners must include extra metadata in their auction announcement:

  1. An indication that all bids must be submitted using this mode, or they will be ignored.

  2. An auction expiration time, set by blockchain height: expiration_height

  3. A public key from the name owner’s wallet that they can sign transactions with: owner_pk

BID: When a user wants to submit a bid for this name, they follow these steps:

  1. Derive a public key from their wallet that they can sign with: bidder_pk

  2. Combine their key and the auction announcement data into the script below: bid_lock_script

  3. Derive the corresponding address for that script and send their bid amount to that address: bid_lock_tx

  4. Construct a partially-signed TX bid_submit_tx as defined in Auction BID but with the following modifications:

    1. Input 1 of this transaction will spend the UTXO created by bid_lock_tx

    2. The redeem script in the witness of input 1 will be a partially-signed multisig spend defined below as bid_submit_script, with a single 0x00 byte as a placeholder for the name owner’s signature.

  5. Bidder submits the following data to the name owner:

    1. bid_lock_script with all data inserted such that the name owner can verify it matches the address in the output of bid_lock_tx.

    2. The double-partially-signed bid_submit_tx (which will explicitly indicate the outpoint of the UTXO created by bid_lock_tx)

FINALIZE: The name owner must finalize the atomic swap BEFORE expiration_height:

  1. Name owner chooses the highest bid and verifies that its bid_lock_tx is confirmed on chain, and that the output address is spendable by bid_lock_script. They construct a final TX as defined in Auction FINALIZE:

    1. Name owner inserts their self-payment (minus miner fee) at output 1 like normal.

    2. Name owner signs the name-owning UTXO into a TRANSFER at input 0 like normal.

    3. Name owner must now also COMPLETE THE MULTISIG in input 1 to fund the transaction. This is accomplished by filling in owner_sig in the incomplete bid_submit_script that the bidder has included in the witness of bid_submit_tx.

REDEEM: If the bidder loses the auction or if for any reason the expiration_height is reached without their bid_lock_tx output being spent into an atomic swap, they can refund their bid value using bid_redeem_script below. That refund transaction MUST have a locktime set at expiration_height and of course can not be submitted until that time.

The only potential grief attack is a race condition after expiration_height has been reached in which both spending paths are valid: the name owner can still complete the atomic swap, and the bidder can now submit a refund. However, if the name owner has already completed the auction and finalized a “winner” then only the refund path is valid.

bid_lock_script:

OP_IF
  OP_2
    <owner_pk>
    <bidder_pk>
  OP_2
  OP_CHECKMULTISIG
OP_ELSE
  <expiration_height>
  OP_CHECKLOCKTIMEVERIFY
  OP_DROP
  <bidder_pk>
  OP_CHECKSIG
OP_ENDIF

bid_submit_script:

OP_1
0x00 # placeholder for <owner_sig>
<bidder_sig>

bid_redeem_script:

OP_0
<bidder_sig>

A semi-custodial platform could help ensure auction finality

One possible scenario with this protocol is that the name owner never finalizes any bids. They might have decided a “reserve price” was not met or just changed their mind about the sale. One technique that may be used to ensure bidders that a winner will be chosen by a certain time is to include a trusted moderator.

Auctions could be held on a platform like Shakedex or run by an agency with a good reputation like Namebase or Kyokan. This agent would publish a static public key for their platform, and name owners would have to incorporate that key along with a relative locktime into the HIP-0001 locking script like so:

OP_TYPE
0x09 // TRANSFER
OP_EQUAL
OP_IF
  OP_IF
    <name-owner's public key>
  OP_ELSE
    <timespan of auction>
    OP_CSV
    OP_DROP
    <platform's public key>
  OP_ENDIF
  OP_CHECKSIG
OP_ELSE
  OP_TYPE
  0x0a // FINALIZE
  OP_EQUAL
OP_ENDIF

What this does is add a rule to the locking script such that, after a certain amount of time (i.e. 5 days) the platform operator can finalize the auction with their own private key instead of waiting for the name owner to do so. Technically this means that if the name owner does not finalize the auction in time (or simply transfer the name back to themselves – publicly ending the auction on the blockchain) the platform can steal the name OR the value of the highest bid. In some cases, this may be the actual terms-of-service. In more common cases we can assume a platform with interest in maintaining a good reputation would award the highest bidder with the name and pay the name owner from output 1 of the final transaction.

A commercial platform could also improve auction quality by regularly performing the offline bid-validity checks mentioned in the previous section. The platform would have to be trusted (via reputation) to perform this job correctly or some bids may be censored.

Where & When

Because this auction protocol is interactive, bidders need a place to send their partially-signed transactions where they are accessible to the name owner to finalize. A name owner could therefore open an auction by adding TXT records to their zone announcing the endpoint to send bids, along with the redeem script to prove the name is locked by HIP-0001! Once this UPDATE has been sent, users just need to wait for the name owner to FINALIZE the transfer to the HIP-0001 address, and the auction is LIVE!


HIP:
0006
Status:
Final
Type:
Informational
Created:
Thu, 17 Jun 2021
Last commit:
Mon, 13 Mar 2023
Author:
Matthew Zipkin (@pinheadmz)

Edit on GitHub