Atomic swaps: a simple, fair exchange protocol
Alice has x bitcoins and Bob has y litecoins. Assuming that these amounts are roughly of equal value, they would like to conduct an atomic exchange, so that after a given time, either Alice has y litecoins and Bob has x bitcoins, or the transaction was aborted and their positions are unchanged.
The protocol below enabling the atomic swap is an example of a “fair exchange” protocol, meaning neither Alice nor Bob need to trust each other or any intermediary.
In practice, Alice and Bob still need a venue to share their bid/ask offers with the world and to have them matched in a swap. The venue can be a decentralized network such as the Lightning network or a centralized platform: buy and sell orders are matched by the platform but buyers and sellers retain control of the coins while the swap is executed.
Our protocol is based on a simple HTLC (Hash Time Locked Contract) contract.
Because the Bitcoin and Litecoin blockchains support the same scripting language, known as Bitcoin Script, the same HTLC address can be used by Alice and Bob on both blockchains.
Phase 0: Alice and Bob are matched
Alice draws a random secret S and creates a Bitcoin HTLC address with the hash of S and a public key, initiating a swap if a bitcoin utxo bearing amount x matches her public key.
Symmetrically, Bob creates an ask with the public key corresponding to his Litecoin utxo (amount y).
Now either Alice or Bob can launch a search in the order book so that their bid/ask are matched:
Alice swap is updated and now points to Bob’s ask and Alice’s bid.
Phase 1: Alice bails in
Alice constructs TX1 sending x bitcoins to the HTLC address she created in Phase 0. TX1 has a single txout with the following scriptPubkey:
// Ordinary claim for B
HASH160 <H(S)> EQUALVERIFY
2 <pubkeyA> <pubkeyB>
// Refund for A
2 <pubkeyA> <pubkeyB>
The scriptPubkey is a smart contract in Bitcoin scripting language, i.e computer code setting the conditions required to transfer funds from the HTLC address to another address. The HTLC address is nothing more than a digest of the smart contract.
Alice signs TX1 but does not yet publish it since her funds would be the lost without the cooperation of Bob.
She creates Bitcoin transaction TX2, spending the above script to her refund address A with a locktime of +48 hours. The locktime is a parameter set in the transaction, that prevents its validation by the network before a certain date/time.
TX2 contains TX1 as a txin, and the txout is a standard spend to A. The scriptSig for this txin looks like:
<sigB2> <sigA2> FALSE
which proceeds through the ELSE branch of the IF/ELSE/ENDIF guard clause in the smart contract. The scriptSig is a proof that the conditions set in the smart contract are met by the spender, allowing a transfer of the funds previously deposited on the HTLC contract address.
Alice computes sigA2, her signature over transaction TX2.
Alice transmits TX2 to Bob, and requests that Bob returns his signature sigB2. Once Alice receives sigB2, she is safe to publish TX1 as long as she does not reveal S: she could claim her refund after 48 hours by publishing TX2, in case something goes wrong .
As soon as TX1 is confirmed in the Bitcoin blockchain, Alice is bailed in.
Phase 2: Bob bails in
Bob received TX2 in the first phase, and therefore knows H(S). Bob also signed Alice’s refund transaction, but that will not be active until after 48 hours. Unless he decides to abort the swap, Bob knows he can get x bitcoins within 24 hours max. Bob knows also that Alice has bailed in since TX1 has been published.
Bob creates Litecoin transaction TX3, sending y litecoins to the HTLC address. TX3 is symmetric with TX1, and has a single txout containing the same scriptPubkey as in Phase 1.
Bob also creates his own Litecoin refund transaction TX4. TX4 is timelocked for only 24 hours, uses TX3 as a txin, and the scriptSig looks like this:
<sigB4> <sigA4> FALSE
which proceeds through the ELSE branch of the script.
TX4 is symmetric with TX2.
Bob computes sigB4, his signature over TX4.
Bob transmits TX4 to Alice, and requests that she returns her signature sigA4. When Bob receives sigA4, he can safely publish TX3, knowing that he could abort and reclaim his litecoins after 24 hours.
As soon as TX3 is confirmed in the Litecoin blockchain, Bob is bailed in.
Phase 3: Alice reveals S and triggers both transactions
Phase 3 starts with Alice sending to Bob her signature sigA6 over a transaction TX6 paying him x bitcoins, spending the TX1 utxo. She knows Bob cannot broadcast TX6 yet because only she knows S at this point.
After having checked sigA6, Bob sends to Alice his signature sigB5 over TX5 paying her y litecoins , spending TX3.
Alice has now 24 hours to claim the litecoins with TX5, using the following scriptSig:
<sigA5><sigB5> <S> TRUE
which triggers the IF branch of the conditional.
In doing so, she reveals S in the Litecoin blockchain. If Alice publishes TX5 within 24 hours, then Bob can also claim his bitcoins before 48 hours with the following scriptSig, validating TX6:
<sigA6><sigB6> <S> TRUE
The swap is successfully executed as soon as TX5 and TX6 are confirmed in the Litecoin and Bitcoin blockchains, respectively.
If Alice is uncooperative and does not publish TX5 within 24 hours, Bob can get his refund by publishing TX4 on the Litecoin blockchain.
Bob has only 48 hours (TX2 locktime) to do so because, past this deadline, Alice could publish both TX2 and TX5. Our protocol is safe for Bob only if TX2 locktime is longer than TX4 locktime by several hours.
If TX5 were confirmed before TX4, then Bob’s refund transaction TX4 would be forever invalid because both transactions attempt to spend the same output of TX3.
If Bob does not send sigB6 before 48 hours, Alice can obtain her refund by publishing TX2 on the Bitcoin blockchain. Since she has not published TX5 yet, Bob has no way of knowing S, hence cannot fully sign TX6.
If TX6 were confirmed before TX2, then Alice refund transaction TX2 would be forever invalid because both transactions attempt to spend the same output of TX1.
What does locktime mean exactly?
We can use locktime to make sure that a transaction is locked until a specific block height, or a point in time.
Locktime < 500000000 Unlocked at block height.
Locktime >= 500000000 Unlocked at specific time (in Unix time)
In the latter case (Locktime set above the 500000000 value), there is a major caveat: the transaction can only be relayed on the network after the median time of the last 11 blocks (according to the time field in their block headers) is greater than the set locktime.
As a result, if the locktime is set to, say, one hour from now, the transaction won’t be mined until about two hours from now. In this case, the effective, network enforced locktime is off by one hour from the set locktime.
Also, for the locktime to be effective, one needs to set one of the sequence values (for one of the inputs in the transaction) to anything below the default maximum (0xffffffff).
Any attempt to broadcast a transaction before its effective locktime will only trigger the “64: non-final” network error message.
If you do NOT want your transaction to be affected by a locktime, simply set the locktime field to 0x00000000 (or anything below the current block height or unix time).
Because the locktime parameter (more precisely nLockTime in the Bitcoin Core code) applies to the entire transaction, a new op_code, CHECKLOCKTIMEVERIFY or CLTV for short, has been added to the Bitcoin Script language in 2015: a script containing CLTV t on a transaction output applies a timelock t only on this output and does not affect the other outputs, if any.
For instance, if a transaction T1 sends funds to an address with a scriptPubkey containing CLTV t, a transaction T2 spending this output of T1 can only be confirmed by the network if T2 locktime expires after t. The other ouputs of T1 could be spent without this time constraint.