stacks-network / sbtc

Repo containing sbtc
GNU General Public License v3.0
280 stars 7 forks source link

[Design]: sBTC Withdrawal #16

Closed AshtonStephens closed 7 months ago

AshtonStephens commented 7 months ago

Design - sBTC Withdrawal

This ticket holds the design of sBTC Withdrawal and how it fits into sBTC-v1.

Details here: https://github.com/Trust-Machines/sbtc-v1/discussions/9

Proposed Design

Ported from discussion #9

Overview

withdrawal

Breakdown

The main steps of this withdrawal flow are as follows.

  1. Withdrawal request: An sBTC holder calls the withdraw-request function in the .sbtc contract.
    • This transfers the requested amount of sBTC to the .sbtc contract.
  2. Withdrawal accept: If accepted, the following happens 2.1. The signers create a "Withdrawal accept" transaction on Bitcoin which returns the requested amount to the designated address. 2.2. Once the Bitcoin transaction is confirmed, the Stacks node burns the equivalent amount of sBTC in the .sbtc contract. 2.3. Finally, the signers demonstrate to the chain that they have fulfilled their duty by calling the withdraw-accept function in the .sbtc contract.
  3. Withdrawal reject: If instead the request is rejected, the sBTC signers will call the withdraw-reject function in the .sbtc smart contract. This function does the following: 3.1. Returns the sBTC to the holder. 3.2. Records the signer votes.

Finally, here is a summary of the necessary contract functions.

Function name Parameters Description
withdraw-request (recipient_address, amount, max_fee, signatures) Transfers amount of sBTC into the .sbtc contract and records the request to withdraw returning a unique request_id. Also records the maximum fee that the user may accept to pay for the withdrawal.
withdraw-accept (request_id, bitcoin_txid, output_index, signer_bitmap, signatures) Records that the signers have accepted a withdraw request. request_id identifies the request, bitcoin_txid and output_index together identify the Bitcoin UTXO returning the requested amount of BTC to the user. signer_bitmap records what each signer voted if this information is not already provided in the Bitcoin transaction
withdraw-reject (request_id, signer_bitmap, signatures) Records that the signers have rejected a withdraw request, transferring back the sBTC to the principal who made the request. Must contain a bitmap of how the signers have voted.

All functions takes a list of signer signatures as decided in https://github.com/Trust-Machines/sbtc-v1/issues/36

Design motivation

  1. Why do we initiate withdrawals using .sbtc contract calls?
    • Simplicity, withdrawing sBTC is as easy as making any contract call on Stacks.
    • Security, any design which is not initiated by a contract call by the sBTC holder entails a mechanism from which sBTC may be seized from its holder without an explicit approval by the holder on the Stacks chain.
    • In previous sBTC designs, we have supported withdrawals initiated by Bitcoin transactions. That is not supported in this design to keep the initial release lean.
  2. Why do the Signers have to explicitly call withdraw-accept?
    • This makes it visible on the Stacks blockchain that a particular withdraw request has been accepted, who voted to accept the transaction and where the Bitcoin UTXO that fulfills the transaction is.
  3. Why do the Signers have to explicitly call withdraw-reject?
    • Primarily, to return the sBTC which will not be withdrawn to the holder.
    • Secondly, for visibility on-chain and to record who voted on the transaction.

Closing Checklist

netrome commented 7 months ago

I've ported the design from the discussion. I added a "Design motivation" to accommodate the third item in the closing checklist, but would like to know if anyone would like to see anything else in particular to be discussed or clarified before I check that box.

netrome commented 7 months ago

The current design is not defining the mechanism which is used to ensure that the signers are collectively calling withdrawal-reject and withdrawal-accept. A proposal is to add a signature to these contract calls, to ensure these functions can only be called if they have a collective signature. This requires schnorr signature verification in Clarity contract calls. We need to research if that is possible.

I will open a research discussion for that.

netrome commented 7 months ago

The current design is not defining the mechanism which is used to ensure that the signers are collectively calling withdrawal-reject and withdrawal-accept. A proposal is to add a signature to these contract calls, to ensure these functions can only be called if they have a collective signature. This requires schnorr signature verification in Clarity contract calls. We need to research if that is possible.

I will open a research discussion for that.

Research issue opened: https://github.com/Trust-Machines/sbtc-v1/issues/33

AshtonStephens commented 7 months ago

Blocked on #36

netrome commented 7 months ago

I've updated the ticket with the conclusion in #36 I think we are getting close to being able to close this.

hstove commented 7 months ago

Do we need fee information to be provided in withdrawal-accept? I'm thinking "no", as all of their sBTC is burnt anyways, but want to double check.

Secondly, in withdrawal accept, is the bitmap necessary? If we have a list of signatures, which can be optional, which can be a de-facto bitmap.

AshtonStephens commented 7 months ago

The flow is constant and there may be low level details on the contract side to figure out, though we did decide the following on a call:

We also saying all arguments should be signed by the signers.

We should make a diagram of the communication between Signers once they find withdrawals / deposits to batch.

AshtonStephens commented 7 months ago

@netrome can you update the diagram to include the fact that the signers need to wait 6 valid sortitions before making the transaction on Bitcoin.

In fact, I think the Signers will need to:

  1. call withdrawal accept
  2. wait 6 valid sortitions
  3. make the Bitcoin withdrawal
  4. If successful then call some other contract indicating that the withdrawal is complete and burn the sBTC, otherwise give it back.

I think this warrants a brief re-open, and we can quickly close after. This above bit is the part we want agreement on.

hstove commented 7 months ago

In fact, I think the Signers will need to:

  1. call withdrawal accept
  2. wait 6 valid sortitions
  3. make the Bitcoin withdrawal

@AshtonStephens , my assumption was that the withdrawal-accept transaction would happen after the BTC withdrawal was made and confirmed. One reason is that the signers don't know what the BTC fee rate will be 6 blocks ahead of time, and so it could turn out that the signers will need to reject because of too low of a max fee.

netrome commented 7 months ago

Yeah, withdrawal accept should not be called until the bitcoin transaction is sufficiently confirmed. Previously I had the whole RBF flow as part of the above chart but I felt like it is all part of the "Signers broadcast a withdraw accept transaction on Bitcoin" step. Success here would entail that the transaction is confirmed on the bitcoin blockchain. But I can re-expand that part again.

netrome commented 7 months ago

I just added "six confirmations on Bitcoin" for now to keep it specific and lean. @AshtonStephens let me know if you'd like to have more details here with the whole "not confirmed" -> "can fee be increased" -> "increase fee" -> "confirmed" etc. flow. I'd personally like to leave that for the LLD tickets which are already expanding these details.

netrome commented 7 months ago

Oh wait, I made a conceptual mistake. There is no need to wait for calling withdraw-accept instead we must wait for the withdraw-request transaction to have sufficient confirmations before accepting it. I'll update this in the chart.

AshtonStephens commented 7 months ago

Added this very high level diagram to the sBTC-v1 HLD.

sBTC-v1 High Level Withdrawal Flow