4.9 KiB
Protocol
Current version
Alice has ETH and wants XMR, Bob has XMR and wants ETH. They come to an agreement to do the swap and the amounts they will swap.
Initial (offchain) phase
- Alice and Bob each generate Monero secret keys (which consist of secret spend and view keys): (
s_a,v_a) and (s_b,v_b), which are used to construct valid points on the ed25519 curve (ie. public keys):P_aandP_baccordingly. Alice sends Bob her public key and Bob sends Alice his public spend key and private view key. Note: The XMR will be locked in the account with address corresponding to the public keyP_a + P_b. Bob needs to send his private view key so Alice can check that Bob actually locked the amount of XMR he claims he will.
Step 1.
Alice deploys a smart contract on Ethereum and locks her ETH in it. The contract has the following properties:
-
it is non-destructible
-
it contains two timestamps,
t_0andt_1, before and after which different actions are authorized. -
it is constructed containing
P_aandP_b, so that if Alice or Bob reveals their secret by calling the contract, the contract will verify that the secret corresponds to the expected public key that it was initialized with. -
it has a
Ready()function which can only be called by Alice. OnceReady()is invoked, Bob can proceed with redeeming his ether. Alice has until thet_0timestamp to callReady()- oncet_0passes, then the contract automatically allows Bob to claim his ether, up until some second timestampt_1. -
it has a
Claim()function which can only be called by Bob afterReady()is called ort_0passes, up until the timestampt_1. Aftert_1, Bob can no longer claim the ETH. -
Claim()takes one parameter from Bob:s_b. OnceClaim()is called, the ETH is transferred to Bob, and simultaneously Bob reveals his secret and thus Alice can claim her XMR by combining her and Bob's secrets. -
it has a
Refund()function that can only be called by Alice and only beforeReady()is called ort_0is reached. OnceReady()is invoked, Alice can no longer callRefund()until the next timestampt_1. If Bob doesn't claim his ether byt_1, thenRefund()can be called by Alice once again. -
Refund()takes one parameter from Alice:s_a. This allows Alice to get her ETH back in case Bob goes offline, but it simultaneously reveals her secret, allowing Bob to regain access to the XMR he locked.
Step 2.
Bob sees the smart contract has been deployed with the correct parameters. He sends his XMR to an account address constructed from P_a + P_b. Thus, the funds can only be accessed by an entity having both s_a and s_b, as the secret spend key to that account is s_a + s_b. The funds are viewable by someone having v_a + v_b.
Note: Refund() and Claim() cannot be called at the same time. This is to prevent the case of front-running where, for example, Bob tries to claim, so his secret s_b is in the mempool, and then Alice tries to call Refund() with a higher priority while also transferring the XMR in the account controlled by s_a + s_b. If her call goes through before Bob's and Bob doesn't notice this happening in time, then Alice will now have both the ETH and the XMR. Due to this case, Alice and Bob should not call Refund() or Claim() when they are approaching t_0 or t_1 respectively, as their transaction may not go through in time.
Step 3.
Alice sees that the XMR has been locked, and the amount is correct (as she knows v_a and Bob send her v_b in the first key exchange step). She calls Ready() on the smart contract if the XMR has been locked. If the amount of XMR locked is incorrect, Alice calls Refund() to abort the swap and reclaim her ETH.
From this point on, Bob can redeem his ether by calling Claim(s_b), which transfers the ETH to him.
By redeeming, Bob reveals his secret. Now Alice is the only one that has both s_a and s_b and she can access the monero in the account created from P_a + P_b.
What could go wrong
-
Alice locked her ETH, but Bob doesn't lock his XMR. Alice has until time
t_0to callRefund()to reclaim her ETH, which she should do ift_0is soon. -
Alice called
Ready(), but Bob never redeems. Deadlocks are prevented thanks to a second timelockt_1, which re-enables Alice to call refund after it, while disabling Bob's ability to claim. -
Alice never calls
readywithint_0. Bob can still claim his ETH by waiting until aftert_0has passed, as the contract automatically allows him to callClaim().
Acknowledgements
This protocol was inspired by the previous atomic swap research and work done by COMIT Network and the Farcaster Project.
Thanks for @mmagician, @alxs, and @Lederstrumpf for helping to review the protocol and kick-start the development of this project.