Inspiration
Loosely inspired by https://github.com/farcaster-project/
What it does
SmoothieSwap: Swaps between MOnerO & eTHIrEum
Alice has some ETH and wants XMR. Bob has XMR which he wants to exchange for ETH.
They agree off-chain on the rate of exchange and launch the client with their respective roles. Alice locks her ETH in a smart contract, while Bob locks his XMR in an account obtained by adding the Monero public keys of the two of them. In the end, either both are able to claim the other currency or they are both able to claim the amount they locked back.
Capabilities:
- send and receive messages between the p2p network participants
- interact with the Ethereum blockchain, specifically:
- create a Swap contract (locking ether)
- submit Claim or Refund
- listen to events (Create, SetReady, Claim & Refund)
- interact with the Monero chain, specifically:
- spending to a combined PubKey (locking monero)
- viewing the balance of the locked account via combined ViewKey
See the repo for more info!
How we built it
Challenges we ran into
There's no Go Monero library, so it was first necessary to write a client that calls the Monero RPC server and implement the cryptography ourselves.
The main challenge we faced after that was around elliptic curve implementations across the different protocols.
The issues arose from public key derivation from the secret:
We chose to use an ed25519 library from https://github.com/javgh/ed25519-solidity, which however didn't handle public key encoding in the canonical fashion as defined in RFC8031.
The default in the Go implementation outputs Bytes() in canonical representation (as per above RFC), and it was not easy to get the encoding right considering the exceedingly convoluted definition in the RFC in addition to having to handle Endianness across platforms.
The Ed25519 lib is also very expensive on gas cost for EC multiplications (> 1M gas), which we use to check against ed25519 pubKeys. A more efficient library we tried didn't seem to work and even with half the gas which it claimed to achieve it still remains rather expensive for real usage. To get around this, we also implemented a version using DLEQ proofs between the ed25519 pubKeys and secp256k1 pubKeys. The onchain verification of a secp256k1 privKey against its pubKey is much cheaper (~10k) since one can exploit ECRECOVER to perform ECMUL, as described by Vitalik here and implemented by Anton Bukov here. The exchange and verification of the proof of discrete log equality between the secp256k1 and the ed25519 curve points are done off-chain.
Accomplishments that we're proud of
- implementing a canonical derivation of ed25519 pubKeys in Solidity, with correct Endian encoding
- an alternate implementation using DLEQ proofs to cut gas cost for claiming & refunding by 26x
- p2p layer that handles the entirety of the communication between the two parties
- extensive test coverage (both unit and per-chain integration tests)
- Not one, but two approaches to proving correct key derivation to the other party
What we learned
- Data serialisation and canonisation is critical
- Go, Solidity, Rust
- Endianness
- Inner workings of Monero
- Protocol design
- Challenges around atomic swaps
- Working with different curves: ed25519, secp256k1
What's next for eth-xmr-atomic-swap
- At the moment the negotiation regarding price is assumed to happen offline and the protocol "only" handles the p2p communication via a CLI flag.
- We have automated integration tests for the protocol on each side, but not across chains.
- Smart contract optimisation: some parameters are hardcoded (e.g. timeout periods to 1 day).
- Deployment optimisation: while our main contract is supposed to self-destruct (i.e. cannot be re-used across multiple swaps), we rely on libraries which could be re-used (at the moment they are re-deployed with each swap as well).
Log in or sign up for Devpost to join the conversation.