Skip to content

Instantly share code, notes, and snippets.

Last active November 4, 2023 04:36
Show Gist options
  • Save Anunayj/750c85c9bea6a707e7e32a72f9ef6e83 to your computer and use it in GitHub Desktop.
Save Anunayj/750c85c9bea6a707e7e32a72f9ef6e83 to your computer and use it in GitHub Desktop.
Staking on HNS?

Turbo Blinds

The Problem

  • Alice wants to bid 10 HNS
  • Bob has 90 HNS to stake
  • Bob charges a fee of 5 HNS

Generalized protocol

Step 0

Bob sends ALice his public key pubKeyB, Alice generates two keys (pubkeyA1, pubkeyA2)

Step 1

Alice creates the following contracts:

Funding contract (fundingScript):

  <reveal phase end height> OP_CHECKLOCKTIMEVERIFY OP_DROP

Bid Contract (bidScript):

  <reveal phase end height> OP_CHECKLOCKTIMEVERIFY OP_DROP

They are identical except the use of different publickeys to end with a different P2WSH address, this ensures transactions to these addresses cannot be correlated onchain before the reveal phase.

Step 2

Now Bob and Alice presign the following transaction:

Reveal tx:

txid : tx-unknown // txid depends on prevouts
  amount: bid + blind (100 HNS)
  script : bidScript
  amount: bid + fee + txFee (15+1 HNS)
Output #0:
  Covenant: REVEAL
  Amount:  10 HNS
  To: Bid Contract
Output #1:
  Amount: 105 HNS (Alice's Fee + Blind + Bid)
  to: Bob's wallet

Both Alice and Bob verify the presigns, the transaction can be aborted here in case of foul play by either user. Use of NOINPUT will allow one to fill the prevouts with any prevouts of appropriate value coming from the given script.

Step 3

Now Alice creates the following transaction and broadcasts it.

Alice's Funding Transaction

txid : t001
Input #0: her wallet

Output #0: 
  Amount: Her bid + Bob's Fee + Tx fee costs (16 HNS)
  To: Funding contract 
Output #1: change

Bob waits a appropriate (and random!) amount of time for this Transaction to get confirmed on-chain.

It is very important that this transaction is not orphaned in a reorg else Bob will not be able to reveal. (Though bob can pay for the bid himself in worst case scenario and lose bid + free)

Randomness ensures that these transactions are not easily correlated on-chain.

Bob then creates and broadcasts the following transaction Bob's Bid Transaction

txid : t002
Input #0: His wallet

Output #0: 
  type: BID to name
  Amount: Blind + Bid + Tx fee (100 HNS)
  To: Bid Contract
Output #1: change

Step 4

Since both parties have a copy of presigns, either of them can broadcast the reveal transaction as the auction goes on. It is important that Bob stays online during this period and ensures that there presigns are broadcasted, since Alice has no incentive to broadcast these transactions herself. (All she loses is some transaction fees, time and on the auction)

After the end of reveal phase, Alice can unilaterally spend from the Bid contract which allows her to TRANSFER/REGISTER/UPDATE the domain however she desires.

Attack Vectors

Liquidity trolling

In Step 4, there is nothing stopping Bob from going offline after Alice broadcasts his funding transaction at no cost to him, locking Alice's bid amount for the entire duration of auction.

There are a few solutions to this:

  1. The obvious, trusting Bob. If Bob is a big known entity, liquidity trolling will be detrimental to their reputation and therefore it might be feasible to just trust them.
  2. Both trusting a trusted 3rd party. If Both Alice and Bob trust a 3rd party (Carol), this party can act as arbitrator. The scheme works by Carol and Bob creating a multisig (which can be spent alone by Bob after a (long) penalty time), and making Bob transferring her funds into this multisig. Now Carol can simply punish Bob anytime by simply refusing to sign any transactions for him. This ensures that Carol is never in unilateral control of funds, and any attack involves Carol acting dishonestly (which is detrimental to her reputation), which in it's worth case scenario leads to funds being locked up for a duration of time.
  3. Atomic Swap using Adaptor Signatures Adaptor signatures can be used to ensure both transactions happen atomically (as in one transfer will allow the other to transfer, not as in same block or tx) in a way that cannot be correlated by a third party. The lockup time in case of malacious play will be in order of hours (instead of days).
Copy link

Anunayj commented Mar 9, 2022


Copy link

Anunayj commented Mar 9, 2022

Both Alice and Bob trust Carol, the trusted third party.
Bob creates a 2 of 2 Multisig with Carol, when he can spend after 45 days. (He renews it 15 days before expiry everytime).
Bob sends all his stake to this address.
Bob can ask Carol anytime to send his money back to his wallet.


Alice -> Bob: Fee Quote (sends amount to bid+blind)
Bob -> Alice: Bob's Public Key + His Offer (His fee)
Alice -> Bob: Offer Accept
Bob-> Alice: Offer Accept + presign
Alice-> Bob: signatures

Both Parties verify the presignatures, nope out in case of foul play. No money lost.

At this point Bob "reserves the money for Alice", he can spend his coins however he likes as long as he saves like 100 HNS for Alice

Alice -> Carol: Hey Can I trust bob, does he even have 100 HNS?
Carol -> Yup! (verifies that Bob has at least 100 HNS in his 2 of 2 address)
Alice -> Carol: Ok go Ahead
Carol -> Bob: Do you Bob, Agree to send the bid transaction to this name (to this address, with this nonce) once Alice funds the funding script?
Bob -> Carol: Yes I do!
Carol -> both: Go ahead

(Alice creates and broadcasts funding transaction)
(After a few confirmations) (say 50 minutes)

(Bob creates and signs the funding tx, Carol verifies the tx, adds her signature + broadcasts)
(If Bob doesn't do this, Carol punishes him by refusing to sign any further txs for him, he has to wait 45 days to retrieve his funds)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment