How to Build: Censorship Resistant Cross Chain Swap

Micah Zoltu
6 min readAug 9, 2022

Premise

Being able to swap ETH for ZEC is useful (if you don’t agree with this statement, now is a good time to stop reading).

Movie Transfers

In older movies when someone is doing a large money transfer you often will see a number on a screen count up as (presumably) some balance was moving between banks, as though someone had to move each penny one at a time from bank A to bank B and the number of the screen was a progress bar for the transfer. In the movies this was a ridiculous setup that didn’t align with reality, but it might actually be an accurate representation of how money transfers of the future look!

Trust Minimized Transfers

Imagine (Alice) finds someone (Bob) who says they’ll trade 220 of their ZEC for 10 of Alice’s ETH. Alice doesn’t trust Bob, but it is a good deal and Alice would like to make that trade with them. Alice is willing to take a small amount of risk, but they aren’t willing to risk 10 ETH on it. Alice could instead suggest a smaller trade of 2.2 ZEC for 0.1 ETH, and Alice will send 0.1 ETH first. If Bob is a scammer, they’ll get 0.1 of Alice’s ETH but Alice will still have 9.9, and if Bob is legitimate Alice will have 2.2 ZEC. Alice can repeat this process 100 times until they have 220 ZEC and Bob has 10 ETH.

What if 0.1 ETH is still too big of a risk? Alice and Bob could instead do 1000 swaps of 0.01 ETH size. Or Alice and Bob could do 10,000 swaps of 0.001 size.

The progress bar of this would actually be just like in the movies, where each swap is a small amount of money successfully being traded!

Fees and Tedium

The problem with this strategy is two fold:

  1. Neither Alice nor Bob want to manually do 1000 or 10,000 swaps.
  2. The transaction fees for 10,000 swaps may end up coming out to more than the amount being swapped!

Luckily, we can build autonomous systems that alleviate both of these problems. The first is to simply automate the swaps. If both parties involved in the trade have some software running locally (maybe in their browser), then they can simply make the agreement and then click “go” and the software will automatically carry out each transaction one at a time. If you assume 250ms round trip time between the two parties, then 10,000 swaps would take 42 minutes but would leave the initiating party at risk of loss of only 0.001 ETH, which is arguably an insignificant amount.

The second problem can be solved with payment channels. Rather than doing 10,000 transactions on Ethereum and ZCash, Alice could instead create a payment channel of ETH to Bob and Bob could create a payment channel of ZEC to Alice. These payment channels would be seeded with the full amount and have a timeout of something like 2 hours. This means that in the worst case scenario, Alice loses a tiny amount of money (0.001 ETH in the example above) and Alice’s ETH is locked in a contract for a couple hours. Each party would have to pay for a transaction to create a payment channel and close a payment channel, but otherwise there would be no additional fees per iteration of the game.

First Mover Disadvantage

One issue with this technique is that the person who moves first is the one taking on the risk. If Alice is the first one to open a payment channel and Bob doesn’t open a payment channel in response, then Alice’s funds are locked for a couple hours and Bob’s aren’t. If both parties open a payment channel but Alice updates theirs and Bob doesn’t then Alice is out 0.001 ETH and Bob is up 0.001 ETH, and both parties have to wait a couple hours before they can close the channels.

These problems are quite unfortunate, but I think they are small enough that reputation can resolve them. We can imagine people with both ZEC and ETH making themselves available as pseudoanonymous liquidity providers. They would advertise their services and Alice and Bob would both open a payment channel with a mutually agreed upon liquidity provider (Carol). The idea here is that Carol has a reputation in the space of honoring the swaps. This doesn’t mean Carol is on the hook for the full amount, but instead Carol is on the hook for the smallest increment. If Alice opens a payment channel with Carol and Bob doesn’t, then Carol will cleanly close the payment channel with Alice after a much shorter time (say 5 minutes). If Alice and Bob both open payment channels and Alice sends 0.01 ETH but Bob doesn’t, then Carol will send the 0.01 ETH back and cleanly close the payment channel with Alice.

Carol would likely change a small fee for utilizing their reputation. Something like 0.1% of the volume they handle perhaps. If Carol misbehaves, Alice can send a notice to a P2P gossip network claiming Carol misbehaved. Carol then either needs to provide proof that they didn’t (by respecting the agreement), or Carol would lose reputation among the peers in the network. This means in the worst case scenario, either Carol loses reputation or Alice gets her channel cleanly closed without loss.

Parameter Tuning

Another issue with this sort of protocol is that either party can stop the trade part way through. While the naive solution here would be to try to punish users who don’t complete the trade, actually implementing this in a censorship resistant, trustless, and permissionless way is incredibly hard.

Instead, it is probably best to just make it a core “feature” of the system. Users would open a trade knowing that they’ll get the agreed upon rate but also knowing that the counterparty can terminate the trade at any point.

This brings us to one of the “hard” parts of the system, which is parameter tuning. The smaller the increment, the longer the swap takes, and the more likely it is that one of the parties will want out of the deal. The larger the increment, the more at risk the first mover’s funds are. The fee received by liquidity providers over time is what incentivizes them to remain honest, and the higher you can likely drive the chunk size before liquidity providers start to defect.

You could let the user pick their parameters, but this is a bit of a UX nightmare compared to baked in parameters. I would initially launch with pretty defensive parameters (very small chunk size), and then increase in future iterations if the reputation system seems to be working well.

Censorship Resistance

The nice part about the above system design is that there are no central parties involved. Anyone can trade with anyone else and while there are some actors with reputation, they cannot exploit this reputation for more financial gain than they get by having that reputation (remember, Carol is earning 0.1% on volume and the only thing that people care about is Carol’s reputation).

You can make the whole system further resistant to censorship by making all of its individual pieces operate in a censorship resistant way. For example, the “app” that users run could all be run on IPFS. Users could be encouraged to run their own network clients (Ethereum/ZCash client) for interacting with each of the blockchains. Further, the system could use something like WebRTC for connecting browser peers together without the need for centralized coordination servers/relayers.

Someone implementing this protocol should also protect user privacy, so ensuring that the system can be used behind a VPN, Tor, etc. is critical.

The Future is Bright

While it is certainly easier to build a centralized exchange, eventually a powerful actor will try to shutdown, limit, or censor these exchanges. We have seen this happen time and time again. We need to start building tools that are resistant to governance capture and luckily there is a way. I think with the proper amount of love, a system as described above could provide a UX that isn’t absolutely terrible and with proper tuning isn’t so slow to use that people are significantly bothered by it.

--

--