[ad_1]
UTXOs, Bitcoin Script, and tBTC v2 deposits defined
TL;DR
In tBTC v2, we use Bitcoin Script to make sure depositors can at all times get a refund in case of catastrophic pockets error. For every deposit, the tBTC dApp generates a Pay To Script Hash (P2SH) tackle — a sort of Bitcoin tackle that may solely be unlocked when sure circumstances are met.
Here is the Script that the dApp used to generate every deposit tackle:
<eth-address> DROP
<blinding-factor> DROP
DUP HASH160 <signingGroupPubkeyHash> EQUAL
IF
CHECKSIG
ELSE
DUP HASH160 <refundPubkeyHash> EQUALVERIFY
<locktime> CHECKLOCKTIMEVERIFY DROP
CHECKSIG
ENDIF
The place:
<eth-address>
is the Ethereum tackle you would like your tBTC minted to.<blinding-factor>
is 8 bytes of random noise to verify deposits from the identical tackle to the identical tackle are distinctive.<signingGroupPubkeyHash>
is the public key hash of the at the moment lively tBTC pockets. tBTC wallets are 51-of-100 threshold ECDSA “multisigs” that custody person funds.<refundPubkeyHash>
is the general public key hash that you just’d like to have the ability to refund the deposit to in case one thing is amiss.<locktime>
is the time limit while you’re capable of refund the deposit.
In english it reads as “Inform Bitcoin about my ethereum tackle and blinding issue, however ignore them for the needs of working the script. The signing group can at all times unlock the funds. The refund pockets can unlock the funds after <locktime>
.”
Possession in Bitcoin
In case the above seems to be like wizardry, let’s take a step again and begin from the start: Bitcoin’s mannequin of possession.
Bitcoin, in contrast to an account-based chain like Ethereum, has a mannequin of possession primarily based on Unspent Transaction Outputs (UTXO). I’ve at all times considered these like working with money. Relatively than having a digital stability related together with your checking account that goes up and down (like in conventional digital banking), you retain observe of every coin.
Relatively than offering philosophical or authorized definitions of possession just like the US Government does, Bitcoin takes a quite simple route. In Bitcoin, you may both unlock and relock a specific UTXO. The scripting language for Bitcoin is stack based [note 1] and makes use of lists of instructions that run left-to-right. A UTXO at all times has a locking script, after which somebody supplies an unlocking script and a brand new locking script. We prepend the unlocking script to the unique locking script, and consider it. If it comes out to be simply 1
, then we re-lock the UTXO with the supplied locking script.
Here is a quite simple instance:
unique lock: [5 9 ADD EQUAL]
then somebody would possibly present:
unlock: [14]
relock: [DUP <publicKey> EQUALVERIFY CHECKSIG]
We prepend the unlocking script to the unique lock and get [14 5 9 ADD EQUAL]
, after which execute this. Here is what the execution steps seem like:
(1)
stack: []
script: [14 5 9 ADD EQUAL]
// information is pushed to the top of the stack
(2)
stack: [14]
script [5 9 ADD EQUAL]
(3)
stack: [14 5]
script [9 ADD EQUAL]
(4)
stack: [14 5 9]
script [ADD EQUAL]
// ADD takes the highest two off the stack, provides them, and
places the outcome on the finish of the stack
(5)
stack: [14 14]
script [EQUAL]
// EQUAL takes the highest two off the stack, then pushes 1 if
they're equal, else 0 on the finish of the stack
(6)
stack: [1]
script []
Because the stack is simply [1]
on the finish, we re-lock with the supplied script: [DUP <publicKey> EQUALVERIFY CHECKSIG]
.
So who “owns”, that Bitcoin? Nobody and everybody, type of. Anybody can re-lock it by offering a trivially straightforward to calculate unlocking script.
What Is My Bitcoin Pockets Doing?
At this level you would possibly interject and say “grasp on a second, I’ve a Bitcoin pockets and it tells me my stability similar to a financial institution. Is that fallacious?” Sure, however it’s sensible. Pockets software program is programmed to examine the Bitcoin chain for explicit patterns of locking scripts. Here is an instance: [DUP <publicKey> EQUALVERIFY CHECKSIG]
. The related unlocking script is [<signature>, <publicKey>]
. Here is the way it works:
(1)
stack: []
script: [<signature> <publicKey> DUP <publicKey>
EQUALVERIFY CHECKSIG]
// information is pushed to the top of the stack
(2)
stack: [<signature>]
script: [<publicKey> DUP <publicKey> EQUALVERIFY CHECKSIG]
(3)
stack: [<signature> <publicKey>]
script: [DUP <publicKey> EQUALVERIFY CHECKSIG]
// DUP provides a duplicate of the top of the stack
(3)
stack: [<signature> <publicKey> <publicKey>]
script: [<publicKey> EQUALVERIFY CHECKSIG]
(4)
stack: [<signature> <publicKey> <publicKey> <publicKey>]
script: [EQUALVERIFY CHECKSIG]
// EQUALVERIFY removes the highest two objects of the stack and
throws an error if they are not equal
(5)
stack: [<signature> <publicKey>]
script: [CHECKSIG]
// CHECKSIG removes the highest two objects of the stack and
pushes 1 if the primary merchandise is a signature that matches
the second.
(6)
stack: [1]
script: []
The thought right here is that we’re solely capable of create <signature>
if we have now the personal key related to <publicKey>
. There are two checks right here: in case your signature and public key do not match, the CHECKSIG
fails. In case your public key does not match the one within the locking script, the EQUALVERIFY
fails. If each of these handed, you might have the personal key related to the general public key listed within the unlocking script.
Bitcoin wallets work out what your <publicKey>
is, after which go search for all of the UTXOs with unlocking scripts which are precisely [DUP <publicKey> EQUALVERIFY CHECKSIG]
(in addition to another frequent variations).
If somebody had been to lock up bitcoin utilizing this script: [10 DROP DUP <publicKey> EQUALVERIFY CHECKSIG]
, then you might unlock that with the identical unlocking script, however your pockets will not decide it up or add it to your stability. Demonstration:
(1)
stack: []
script: [<signature> <publicKey> 10 DROP DUP <publicKey>
EQUALVERIFY CHECKSIG]
(2)
stack: [<signature>]
script: [<publicKey> 10 DROP DUP <publicKey> EQUALVERIFY
CHECKSIG]
(3)
stack: [<signature> <publicKey>]
script: [10 DROP DUP <publicKey> EQUALVERIFY CHECKSIG]
(4)
stack: [<signature> <publicKey> 10]
script: [DROP DUP <publicKey> EQUALVERIFY CHECKSIG]
// DROP removes the very last thing on the stack
(5)
stack: [<signature> <publicKey>]
script: [DUP <publicKey> EQUALVERIFY CHECKSIG]
// DUP provides a duplicate of the top of the stack
(6)
stack: [<signature> <publicKey> <publicKey>]
script: [<publicKey> EQUALVERIFY CHECKSIG]
(7)
stack: [<signature> <publicKey> <publicKey> <publicKey>]
script: [EQUALVERIFY CHECKSIG]
// EQUALVERIFY removes the highest two objects of the stack and
throws an error if they are not equal
(8)
stack: [<signature> <publicKey>]
script: [CHECKSIG]
// CHECKSIG removes the highest two objects of the stack and
pushes 1 if the primary merchandise is a signature that matches
the second.
(9)
stack: [1]
script: []
After we say “I despatched somebody bitcoin”. We imply “I unlocked some bitcoin after which re-locked it utilizing a normal locking script sample that solely they will unlock”.
Pay to Script Hash
Remaining complication! In 2012, Bitcoin authorized BIP-0016. The best way this works is we create a standardized locking script that appears like [HASH160 <lockingScriptHash> EQUAL]
.
Then, we offer an unlocking script that appears like [<unlockingScript> <lockingScript>]
. Execution:
(1)
stack: []
script: [<unlockingScript> <lockingScript> HASH160
<lockingScriptHash> EQUAL]
(2)
stack: [<unlockingScript>]
script: [<lockingScript> HASH160 <lockingScriptHash>
EQUAL]
(3)
stack: [<unlockingScript> <lockingScript>]
script: [HASH160 <lockingScriptHash> EQUAL]
// HASH160 takes the final merchandise from the stack, hashes it,
and pushes the outcome
(4)
stack: [<unlockingScript> <lockingScriptHash>]
script: [<lockingScriptHash> EQUAL]
(5)
stack: [<unlockingScript> <lockingScriptHash>
<lockingScriptHash>]
script: [EQUAL]
// EQUAL takes the highest two off the stack, then pushes 1 if
they're equal, else 0 on the finish of the stack
(6)
stack: [<unlockingScript> 1]
script: []
For P2SH scripts particularly, this half succeeds if we’re left with [<unlockingscript> 1]
. Then, we rewind and ensure that the supplied enter [<lockingScript> <unlockingScript>]
additionally resolves to [1]
when executed as a script. If each components go, then we’re allowed to relock the UTXO.
Here is a simple instance that transforms our first script [5 9 ADD EQUAL]
into Pay To Script Hash. Say that [5 9 ADD EQUAL]
hashes into 3cf7fabccdc56b241f669e1661dd105d75bcefda
[note 2]. Then, our locking script could be [HASH160 <3cf7fabccdc56b241f669e1661dd105d75bcefda> EQUAL]
. To unlock this we offer: <[14]> <[5 9 ADD EQUAL]>
because the unlocking script. Execution:
(1)
stack: []
script: [<[14]> <[5 9 ADD EQUAL]> HASH160
<3cf7fabccdc56b241f669e1661dd105d75bcefda> EQUAL]
(2)
stack: [<[14]>]
script: [<[5 9 ADD EQUAL]> HASH160
<3cf7fabccdc56b241f669e1661dd105d75bcefda> EQUAL]
(3)
stack: [<[14]> <[5 9 ADD EQUAL]>]
script: [HASH160
<3cf7fabccdc56b241f669e1661dd105d75bcefda> EQUAL]
// HASH160 takes the final merchandise from the stack, hashes it,
and pushes the outcome
(4)
stack: [<[14]> <3cf7fabccdc56b241f669e1661dd105d75bcefda>]
script: [<3cf7fabccdc56b241f669e1661dd105d75bcefda> EQUAL]
(5)
stack: [<[14]> <3cf7fabccdc56b241f669e1661dd105d75bcefda>
<3cf7fabccdc56b241f669e1661dd105d75bcefda>]
script: [EQUAL]
// EQUAL takes the highest two off the stack, then pushes 1 if
they're equal, else 0 on the finish of the stack
(6)
stack: [<[14]> 1]
script: []
the primary half is profitable
(7)
stack: []
script: [14 5 9 ADD EQUAL]
// information is pushed to the top of the stack
(8)
stack: [14]
script [5 9 ADD EQUAL]
(9)
stack: [14 5]
script [9 ADD EQUAL]
(10)
stack: [14 5 9]
script [ADD EQUAL]
// ADD takes the highest two off the stack, provides them, and
places the outcome on the finish of the stack
(11)
stack: [14 14]
script [EQUAL]
// EQUAL takes the highest two off the stack, then pushes 1 if
they're equal, else 0 on the finish of the stack
(12)
stack: [1]
script []
the second half is profitable!
There are a pair necessary properties we acquire right here.
- All the P2SH transactions look the identical till they’re unlocked.
- Bitcoin customers pay mining charges by the byte, so this strikes the price from the sender to the receiver.
tBTC v2 Deposits
Now, we are able to unpack the unique script:
<eth-address> DROP
<blinding-factor> DROP
DUP HASH160 <signingGroupPubkeyHash> EQUAL
IF
CHECKSIG
ELSE
DUP HASH160 <refundPubkeyHash> EQUALVERIFY
<locktime> CHECKLOCKTIMEVERIFY DROP
CHECKSIG
ENDIF
Notice: the primary two instructions: <eth-address> DROP <blinding-factor> DROP
, don’t change the logic, so this finally ends up being a technique to insert arbitrary information into the script. Together with the <eth-address>
signifies that whoever locked up cash with this script meant for TBTC to be minted to that particular eth tackle, which we are able to lookup and confirm ethereum-side.
Let’s check the script with an invalid unlocking script: [<unrelatedSignature> <unrelatedPublicKey>]
(1)
stack: []
script: [<unrelatedSignature> <unrelatedPublicKey>
<eth-address> DROP <blinding-factor> DROP DUP HASH160
<signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE DUP
HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
(2)
stack: [<unrelatedSignature>]
script: [<unrelatedPublicKey> <eth-address> DROP
<blinding-factor> DROP DUP HASH160
<signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE DUP
HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
(3)
stack: [<unrelatedSignature> <unrelatedPublicKey>]
script: [<eth-address> DROP <blinding-factor> DROP DUP
HASH160 <signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE
DUP HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
(4)
stack: [<unrelatedSignature> <unrelatedPublicKey>
<eth-address>]
script: [DROP <blinding-factor> DROP DUP HASH160
<signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE DUP
HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
// DROP removes the very last thing on the stack
(5)
stack: [<unrelatedSignature> <unrelatedPublicKey>]
script: [<blinding-factor> DROP DUP HASH160
<signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE DUP
HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
(6)
stack: [<unrelatedSignature> <unrelatedPublicKey>
<blinding-factor>]
script: [DROP DUP HASH160 <signingGroupPubkeyHash> EQUAL
IF CHECKSIG ELSE DUP HASH160 <refundPubkeyHash>
EQUALVERIFY <locktime> CHECKLOCKTIMEVERIFY DROP CHECKSIG
ENDIF]
// DROP removes the very last thing on the stack
(7)
stack: [<unrelatedSignature> <unrelatedPublicKey>]
script: [DUP HASH160 <signingGroupPubkeyHash> EQUAL IF
CHECKSIG ELSE DUP HASH160 <refundPubkeyHash> EQUALVERIFY
<locktime> CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
// DUP provides a duplicate of the top of the stack
(8)
stack: [<unrelatedSignature> <unrelatedPublicKey>
<unrelatedPublicKey>]
script: [HASH160 <signingGroupPubkeyHash> EQUAL IF
CHECKSIG ELSE DUP HASH160 <refundPubkeyHash> EQUALVERIFY
<locktime> CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
// HASH160 takes the final merchandise from the stack, hashes it,
and pushes the outcome
(9)
stack: [<unrelatedSignature> <unrelatedPublicKey>
<unrelatedPublicKeyHash>]
script: [<signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE
DUP HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
(10)
stack: [<unrelatedSignature> <unrelatedPublicKey>
<unrelatedPublicKeyHash> <signingGroupPubkeyHash>]
script: [EQUAL IF CHECKSIG ELSE DUP HASH160
<refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
// EQUAL takes the highest two off the stack, then pushes 1 if
they're equal, else 0 on the finish of the stack
(11)
stack: [<unrelatedSignature> <unrelatedPublicKey> 0]
script: [IF CHECKSIG ELSE DUP HASH160 <refundPubkeyHash>
EQUALVERIFY <locktime> CHECKLOCKTIMEVERIFY DROP CHECKSIG
ENDIF]
// IF removes the highest merchandise from the stack. If it is a 1, we
use the IF a part of the script. In any other case, we use the
ELSE half.
(12)
stack: [<unrelatedSignature> <unrelatedPublicKey>]
script: [DUP HASH160 <refundPubkeyHash> EQUALVERIFY
<locktime> CHECKLOCKTIMEVERIFY DROP CHECKSIG]
// DUP provides a duplicate of the top of the stack
(13)
stack: [<unrelatedSignature> <unrelatedPublicKey>
<unrelatedPublicKey>]
script: [HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG]
// HASH160 takes the final merchandise from the stack, hashes it,
and pushes the outcome
(14)
stack: [<unrelatedSignature> <unrelatedPublicKey>
<unrelatedPublicKeyHash>]
script: [<refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG]
(15)
stack: [<unrelatedSignature> <unrelatedPublicKey>
<unrelatedPublicKeyHash> <refundPubkeyHash>]
script: [EQUALVERIFY <locktime> CHECKLOCKTIMEVERIFY DROP
CHECKSIG]
// EQUALVERIFY removes the highest two objects of the stack and
throws an error if they are not equal
(16)
error!
The supplied public key did not match both <signingGroupPubkeyHash>
or <refundPubkeyHash>
.
What about after we present <signingGroupPubkey>
?
(1)
stack: []
script: [<signingGroupSignature> <signingGroupPubkey>
<eth-address> DROP <blinding-factor> DROP DUP HASH160
<signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE DUP
HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
(2)
stack: [<signingGroupSignature>]
script: [<signingGroupPubkey> <eth-address> DROP
<blinding-factor> DROP DUP HASH160
<signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE DUP
HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
(3)
stack: [<signingGroupSignature> <signingGroupPubkey>]
script: [<eth-address> DROP <blinding-factor> DROP DUP
HASH160 <signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE
DUP HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
(4)
stack: [<signingGroupSignature> <signingGroupPubkey>
<eth-address>]
script: [DROP <blinding-factor> DROP DUP HASH160
<signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE DUP
HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
// DROP removes the very last thing on the stack
(5)
stack: [<signingGroupSignature> <signingGroupPubkey>]
script: [<blinding-factor> DROP DUP HASH160
<signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE DUP
HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
(6)
stack: [<signingGroupSignature> <signingGroupPubkey>
<blinding-factor>]
script: [DROP DUP HASH160 <signingGroupPubkeyHash> EQUAL
IF CHECKSIG ELSE DUP HASH160 <refundPubkeyHash>
EQUALVERIFY <locktime> CHECKLOCKTIMEVERIFY DROP CHECKSIG
ENDIF]
// DROP removes the very last thing on the stack
(7)
stack: [<signingGroupSignature> <signingGroupPubkey>]
script: [DUP HASH160 <signingGroupPubkeyHash> EQUAL IF
CHECKSIG ELSE DUP HASH160 <refundPubkeyHash> EQUALVERIFY
<locktime> CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
// DUP provides a duplicate of the top of the stack
(8)
stack: [<signingGroupSignature> <signingGroupPubkey>
<signingGroupPubkey>]
script: [HASH160 <signingGroupPubkeyHash> EQUAL IF
CHECKSIG ELSE DUP HASH160 <refundPubkeyHash> EQUALVERIFY
<locktime> CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
// HASH160 takes the final merchandise from the stack, hashes it,
and pushes the outcome
(9)
stack: [<signingGroupSignature> <signingGroupPubkey>
<signingGroupPubkeyHash>]
script: [<signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE
DUP HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
(10)
stack: [<signingGroupSignature> <signingGroupPubkey>
<signingGroupPubkeyHash> <signingGroupPubkeyHash>]
script: [EQUAL IF CHECKSIG ELSE DUP HASH160
<refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
// EQUAL takes the highest two off the stack, then pushes 1 if
they're equal, else 0 on the finish of the stack
(11)
stack: [<signingGroupSignature> <signingGroupPubkey> 1]
script: [IF CHECKSIG ELSE DUP HASH160 <refundPubkeyHash>
EQUALVERIFY <locktime> CHECKLOCKTIMEVERIFY DROP CHECKSIG
ENDIF]
// IF removes the highest merchandise from the stack. If it is a 1, we
use the IF a part of the script. In any other case, we use the ELSE
half.
(12)
stack: [<unrelatedSignature> <unrelatedPublicKey>]
script: [CHECKSIG]
// CHECKSIG removes the highest two objects of the stack and
pushes 1 if the primary merchandise is a signature that matches the
second.
(13)
stack: [1]
script: []
success!
Final two circumstances: we unlock utilizing [<refundSignature> <refundPublickey>]
earlier than and after <locktime>
. Beginning with earlier than.
(1)
stack: []
script: [<refundSignature> <refundPublicKey> <eth-address>
DROP <blinding-factor> DROP DUP HASH160
<signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE DUP
HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
(2)
stack: [<refundSignature>]
script: [<refundPublicKey> <eth-address> DROP
<blinding-factor> DROP DUP HASH160
<signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE DUP
HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
(3)
stack: [<refundSignature> <refundPublicKey>]
script: [<eth-address> DROP <blinding-factor> DROP DUP
HASH160 <signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE
DUP HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
(4)
stack: [<refundSignature> <refundPublicKey> <eth-address>]
script: [DROP <blinding-factor> DROP DUP HASH160
<signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE DUP
HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
// DROP removes the very last thing on the stack
(5)
stack: [<refundSignature> <refundPublicKey>]
script: [<blinding-factor> DROP DUP HASH160
<signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE DUP
HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
(6)
stack: [<refundSignature> <refundPublicKey>
<blinding-factor>]
script: [DROP DUP HASH160 <signingGroupPubkeyHash> EQUAL
IF CHECKSIG ELSE DUP HASH160 <refundPubkeyHash>
EQUALVERIFY <locktime> CHECKLOCKTIMEVERIFY DROP CHECKSIG
ENDIF]
// DROP removes the very last thing on the stack
(7)
stack: [<refundSignature> <refundPublicKey>]
script: [DUP HASH160 <signingGroupPubkeyHash> EQUAL IF
CHECKSIG ELSE DUP HASH160 <refundPubkeyHash> EQUALVERIFY
<locktime> CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
// DUP provides a duplicate of the top of the stack
(8)
stack: [<refundSignature> <refundPublicKey> <refundPublicKey>]
script: [HASH160 <signingGroupPubkeyHash> EQUAL IF
CHECKSIG ELSE DUP HASH160 <refundPubkeyHash> EQUALVERIFY
<locktime> CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
// HASH160 takes the final merchandise from the stack, hashes it,
and pushes the outcome
(9)
stack: [<refundSignature> <refundPublicKey>
<refundPubkeyHash>]
script: [<signingGroupPubkeyHash> EQUAL IF CHECKSIG ELSE
DUP HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
(10)
stack: [<refundSignature> <refundPublicKey>
<refundPubkeyHash> <signingGroupPubkeyHash>]
script: [EQUAL IF CHECKSIG ELSE DUP HASH160
<refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG ENDIF]
// EQUAL takes the highest two off the stack, then pushes 1 if
they're equal, else 0 on the finish of the stack
(11)
stack: [<refundSignature> <refundPublicKey> 0]
script: [IF CHECKSIG ELSE DUP HASH160 <refundPubkeyHash>
EQUALVERIFY <locktime> CHECKLOCKTIMEVERIFY DROP CHECKSIG
ENDIF]
// IF removes the highest merchandise from the stack. If it is a 1, we
use the IF a part of the script. In any other case, we use the ELSE
half.
(12)
stack: [<refundSignature> <refundPublicKey>]
script: [DUP HASH160 <refundPubkeyHash> EQUALVERIFY
<locktime> CHECKLOCKTIMEVERIFY DROP CHECKSIG]
// DUP provides a duplicate of the top of the stack
(13)
stack: [<refundSignature> <refundPublicKey>
<refundPublicKey>]
script: [HASH160 <refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG]
// HASH160 takes the final merchandise from the stack, hashes it,
and pushes the outcome
(14)
stack: [<refundSignature> <refundPublicKey>
<refundPubkeyHash>]
script: [<refundPubkeyHash> EQUALVERIFY <locktime>
CHECKLOCKTIMEVERIFY DROP CHECKSIG]
(15)
stack: [<refundSignature> <refundPublicKey>
<refundPubkeyHash> <refundPubkeyHash>]
script: [EQUALVERIFY <locktime> CHECKLOCKTIMEVERIFY DROP
CHECKSIG]
// EQUALVERIFY removes the highest two objects of the stack and
throws an error if they are not equal
(16)
stack: [<refundSignature> <refundPublicKey>]
script: [<locktime> CHECKLOCKTIMEVERIFY DROP CHECKSIG]
(17)
stack: [<refundSignature> <refundPublicKey> <locktime>]
script: [CHECKLOCKTIMEVERIFY DROP CHECKSIG]
// CHECKLOCKTIMEVERIFY checks to see if the present time
is after the final merchandise on the stack. If it is not, it
throws an error.
(18)
stack: [<refundSignature> <refundPublicKey> <locktime>]
script: [DROP CHECKSIG]
error! present time is earlier than <locktime>
Then, repeating this from Step 17 when the present time is after <locktime>
:
(17)
stack: [<refundSignature> <refundPublicKey> <locktime>]
script: [CHECKLOCKTIMEVERIFY DROP CHECKSIG]
// CHECKLOCKTIMEVERIFY checks to see if the present time
is after the final merchandise on the stack. If it is not, it
throws an error.
(18)
stack: [<refundSignature> <refundPublicKey> <locktime>]
script: [DROP CHECKSIG]
// DROP removes the very last thing on the stack
(19)
stack: [<refundSignature> <refundPublicKey>]
script: [CHECKSIG]
// CHECKSIG removes the highest two objects of the stack and
pushes 1 if the primary merchandise is a signature that matches
the second.
(20)
stack: [1]
script: []
This implies we find yourself with the next logic:
- The signing group tackle can at all times unlock the UTXO
- The refund tackle can solely unlock the UTXO after
<locktime>
- No different tackle can unlock the UTXO
So that is the underlying script. Then we hash this to get the P2SH tackle, and the ultimate locking script seems to be like [HASH160 <38d06abe62e70fb3a72dd4d08554e767683079c4> EQUAL]
The transformation into P2SH does two necessary issues:
- It seems to be like another P2SH transaction, offering broad pockets help.
- Altering any of the variables makes the hash utterly totally different. Particularly, which means altering
<eth-address>
,<blinding-factor>
or<refundPubkeyHash>
makes you find yourself with a completely totally different hash.
That signifies that every tBTC depositor will get their very own one-time-use deposit tackle, and nobody watching bitcoin is ready to inform that this can be a tBTC transaction. Later, the depositor reveals the above info to Ethereum, and the shopper is ready to recreate the underlying script, hash it, discover the transaction on bitcoin, affiliate the deposit with a minting request, and pull the vacation spot Ethereum tackle from the deposit.
Wrapping Up
As soon as the system verifies {that a} transaction occurred [note 3], we’re capable of “optimistically mint” your tBTC.
A set of nodes referred to as “Minters” look ahead to transactions that comply with this construction. If one of them thinks it is a legitimate transaction, they suggest to mint tBTC. One other set of nodes referred to as “Guardians” look ahead to Minters making these requests. The Guardians confirm that the deposit seems to be good, and if none of them thinks it is invalid inside 3 hours, the mint goes by.
Within the meantime, the signing group has till <locktime>
to unlock the deposit, and re-lock it with a P2PKH utilizing its personal public key hash. This implies the UTXO is not locked with a script that enables a refund, and we do not have to fret about people minting tBTC after which later double-spending the underlying BTC.
Wish to see all of this in motion? You may give tBTC v2 a try right now!
[note 1]: Stack-based information varieties solely have two operations: “push” which provides a component to the gathering, and “pop”, which removes the most-recently-added component (and makes it accessible for processing).
[note 2]: I am simplifying by working this calculator, however the precise hashing course of is a bit more sophisticated.
[note 3]: We carry out a SPV proof utilizing our Relay, and wait for six bitcoin block confirmations.
[ad_2]