download Resources
contact Stay tuned

Atomic swaps: a simple, fair exchange protocol

Pierre Noizat
Pierre Noizat

Full time Bitcoin entrepreneur since 2011, coder, Internet of Value evangelist.

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 both 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.

Our protocol is based on HTLCs (Hash Time Lock Contracts) that are used also by the Lightning network protocol but does not require interactions with the Lightning network.

In an upcoming article, I will introduce a proof of concept, non-custodial platform to match swap offers from users and to let 2 matched users (Alice and Bob) execute the subsequent swap.

We assume that both the Bitcoin and Litecoin chains are loosely synchronized to each other, such that neither chain gets significantly ahead of the other.

Because the Bitcoin and Litecoin blockchains support the same scripting language, known as Bitcoin Script, the same script can be used by Alice and Bob, each script mirroring the other, only with different keys.

Phase 0: Alice and Bob are matched

Alice draws a random secret S and creates a bid offer with the hash of S and a public key, initiating a swap if a bitcoin utxo (amount x) corresponds to 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 for a match 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 to bail in x BTC.Bitcoin transaction TX1 has a single txout containing the following scriptPubkey:

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. It contains TX1[0] as a txin, and the txout is a standard spend to A. The scriptSig for this txin looks like:

which proceeds through the ELSE branch of the IF/ELSE/ENDIF guard clause. Alice signs TX2, obtaining sigA2.

Alice transmits TX2 to Bob, and requests that Bob signs and returns it. Once Alice receives Bob’s signature sigB2, then Alice publishes TX1, knowing that she will be able to claim her refund after 48 hours, as long as she does not reveal S. Alice is now 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 gets what he wants within 24 hours max. Bob has also seen that TX1 has been published.

Bob creates Litecoin transaction TX3, which bails in y litecoins. TX3 is symmetric with TX1, and has a single txout containing the same scriptPubkey as in Phase 1.

Bob also creates TX4, which is his own Litecoin refund. TX4 is timelocked for only 24 hours, uses TX3[0] as a txin, and the scriptSig looks like this:

which proceeds through the ELSE branch of the script. Bob signs TX4, obtaining sigB4, and transmits TX4 to Alice, asking her to sign it. When Bob receives sigA4, he can safely publish TX3, knowing that he could abort and reclaim his litecoins after 24 hours. Bob is now bailed in.

Phase 3: Alice reveals S and triggers both transactions

Alice has 24 hours to claim the Litecoins, using the following scriptSig:

which triggers the IF branch of the conditional. However in doing so, she must necessarily reveal S.

If Alice reveals S within 24 hours, then Bob can also claim his bitcoins before 48 hours:

Phase 3 starts with Alice sending her signature to Bob over a transaction TX5 paying him bitcoins, spending the TX1 utxo. She knows Bob cannot broadcast TX5 yet because only she knows S at this point.

After checking Alice signature, Bob sends to Alice his signature over a transaction TX6 paying her litecoins, spending the TX3 utxo. Upon receiving Bob’s signature, she broadcasts TX6 paying herself litecoins, revealing S to Bob in the Litecoin blockchain. Bob can now collect his payment in bitcoins with TX5, completing the atomic swap successfully.

To sum up:

Phase 0
Alice bid and Bob ask are matched.

Phase 1
TX1: Alice locks bitcoins in the HTLC smart contract
TX2: timelocked bitcoin refund to Alice

Phase 2
TX3: Bob locks litecoins in the HTLC smart contract (symetric to TX1 smart contract)
TX4: timelocked litecoin refund to Bob

Phase 3
TX5: bitcoin payment to Bob
TX6: litecoin payment to Alice

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 defaut 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).

Further reading
Bitcoin Wiki
Bitcointalk Forum

Pierre Noizat
Pierre Noizat

Full time Bitcoin entrepreneur since 2011, coder, Internet of Value evangelist.

React to the article

Leave a Reply

Your email address will not be published. Required fields are marked *


Our site saves small pieces of text information (cookies) on your device in order to deliver better content and for statistical purposes. You can disable the usage of cookies by changing the settings of your browser. By browsing our website without changing the browser settings you grant us permission to store that information on your device.