electronic microchip

DeFi on Bitcoin Part 3: Uniswap

This post was first published on Medium. Read DeFi on Bitcoin Part 1: Fungible tokens and token swap and DeFi on Bitcoin Part 2: NFT and Marketplace.

We illustrate how to build a Uniswap-like exchange directly on Bitcoin.

Uniswap

Uniswap liquidity pools
Uniswap

Uniswap is a so-called “decentralized exchange” (DEX). It allows individuals, called liquidity providers, to pool tokens/bitcoins together into smart contracts and provide liquidity to the exchange.

Overview

We implement Uniswap V1 that only swaps between bitcoins and a token directly. We use a stateful contract to represent the pool, as indicated by the @state decorator. It contains two tokens: one for the token we are swapping (Line 7) and the other is a governance token (Line 11), call liquidity pool (LP) token. The pool stores bitcoins directly in the amount part of the UTXO (in unit of satoshis) and tokens under its public key (Line 3).

Complete code can be found here.

Add Liquidity

Anyone can add liquidity to the pool by calling function addLiquidity. There are two cases (checked at Line 9):

  1. add liquidity for the first time: arbitrary amount of bitcoins and tokens can be deposited.
  2. add more liquidity later on: the ratio of bitcoins and tokens deposited must match the existing ratio in the pool (Line 22).

After bitcoins are deposited, new LP tokens are minted to the provider proportionally at Line 26. Tokens are transferred to the pool’s account at Line 30.

For example, if the pool has 10 bitcoins and 100 LP tokens and Alice deposits another 5 bitcoins into it, 50 new LP tokens will be minted to her.

Remove Liquidity

Liquidity providers call function removeLiquidity to withdraw their portion of the reserves, for both bitcoins and tokens.

Liquidity is withdrawn according to the potion of LP tokens a provider has (Line 9 & 10). After the withdrawal, the LP tokens are burned at Line 13. Line 16 transfers tokens from the pool to the provider. Line 18 & 20 does the same for bitcoins.

Note another output in the same transaction is needed to return the bitcoins to the provider, besides the contract output.

Bitcoin -> Token

A user calls functions swapBitcoinToToken to exchange bitcoins to tokens. After bitcoins are received by the pool (calculated at Line 7), Line 10 calculates the amount of tokens to be returned and Line 13 returns them to the user.

Token -> Bitcoin

A user calls functions swapTokenToBitcoin to exchange tokens to bitcoins. Line 9 calculates the amount of bitcoins to be returned. Line 13 transfers tokens to the pool.

Similar to removeLiquidity, another output is needed to return the bitcoins to the user.

Discussion

We have demonstrated how to implement a basic Uniswap-like exchange on Bitcoin. There are many ways to extend it to be more practical.

  • price formula: we use the following code to determine price, based only on bitcoin and token reserves. It is called a constant sum formula and the pool can be drained. To avoid draining, a more sophisticated formula like constant product formula (x * y = k) can be used, as in Uniswap.

Caption: getAmount() uses a constant sum price formula

  • liquidity mining: we can charge a fee for each swap and use the fees to reward liquidity providers.
  • allows users to directly swap one token to another.

TokenSwap has actually implemented all of the above and many more.

Acknowledgements:

This work is inspired by this article of Chen Cheng.

Watch: CoinGeek New York panel, Tokenized Assets, Stablecoins and Custody with BSV

New to Bitcoin? Check out CoinGeek’s Bitcoin for Beginners section, the ultimate resource guide to learn more about Bitcoin—as originally envisioned by Satoshi Nakamoto—and blockchain.

[id^="_form"]
[id^="_form"]
[id$="_submit"]
[id$="_submit"]
[^;]
[^;]
[?&]
[?&]
[^&#]
[^&#]
[(d+)]
[(d+)]
[elem.name]
[elem.name]
[+_a-z0-9-'&=]
[+_a-z0-9-'&=]
[+_a-z0-9-']
[+_a-z0-9-']
[a-z0-9-]
[a-z0-9-]
[a-z]
[a-z]
[el.name]
[el.name]
[id^="_form"]
[id^="_form"]
[id$="_submit"]
[id$="_submit"]
[^;]
[^;]
[?&]
[?&]
[^&#]
[^&#]
[(d+)]
[(d+)]
[elem.name]
[elem.name]
[+_a-z0-9-'&=]
[+_a-z0-9-'&=]
[+_a-z0-9-']
[+_a-z0-9-']
[a-z0-9-]
[a-z0-9-]
[a-z]
[a-z]
[el.name]
[el.name]