This is a study note of Uniswap v1. It was launched in November 2018. It provides exchange of ERC20 tokens on Ethereum without middlemen, central token and platform fee. All smart contract functions are public and all upgrades are opt-in.

1 Features

The V1 has the following features:

  • Liquidity-sensitive automated pricing using constant product formula.
  • Trade any ECR20 for any ECR20 or ETH in a single transaction.
  • Trade and transfer to a different address in a single trasaction.
  • Buy ERC20 using ENS.
  • Open source frontend implementation.

The following analysis is based on an old pre-V1 solidity code.

2 Token Contracts

StandardToken is an ERC20Token. It implements the following states and functions:

  • totalSupply: the total supply of the token.
  • balances: a mapping(address => uint256) that holds balances of all dresses.
  • allowed: a mapping maps a _from address to another mapping that stores allowed transfer amount for msg.sender.
  • transfer: transfer _value from the msg.sender to _to and emit Transfer event.
  • transferFrom: transfer _value from the _from to _to and emit Transfer event. The _value is allowed by allowed[_from][_msg.sender].
  • approve: msg.sender allows _spender to transfer _value, defined in allowed[msg.sender][_spender]. It emits an Approval event.
  • allowance, increaseApproval, decreaseApproval: read or modified allowed and emit Approval if the allowance is changed.

The contract MintableToken is StandardToken, Ownable defines two events Mint and MintFinished, two functions mint and finishMinting, and a modifier canMint. The mint function checks the mintingFinshed state and if it is false, allows the owner to add _amount to totalSupply and balances[_to]. Then it emits a Mint event and a Transfer event.

3 Exchange and Factory

A UniswapExchange is created by a UniswapFactory for a specific token address. In contructor, it sets the tokenAddress, token, factoryAddress, and factory. The FEE_RATE is a constant 500, equals to a fee of 0.2%.

In initializeExchange payable function, the msg.sender deposits msg.value ethers (in valid range) in ethPool. Then it sets tokenPool to _tokenAmount, invariant as the product of tokenPool and ethPool. The shares[msg.sender] = 1000, totalShares = 1000. Finally, the _tokenAmount of the token is transferred from msg.sender to this exchange.

In ethToTokenSwap, the caller pays ethIn and receives tokensOut. tokenToEthSwap swaps tokensIn for ethOut. Both emit the corresponding events of EthToTokenPurchase and TokenToEthPurchase. ethToTokenPayment and tokenToEthPayment pays the tokens or ethers to a specified recipient address.

Uniswap uses totkenToTokenSwap to swap two different tokens. It involves two exchanges and pays doubled fees.

The investLiquidity function lets one to invest ethers to the exchange. The shares[msg.sender] will set to the purchased shares. totalShares, ethPool, tokenPool and invariant are increased. The divestLiquidity function lets one to withdraw ethers for the specified shares. Investment and Divestment events are emitted correspondingly.

The UniswapFactory contract has three states: tokenList, tokenToExchange and exchangeToToken. The launchExchange takes an address _token parameter to create and return a new exchange.

4 How It Works

Anybody can create a Uniswap exchange for an ERC20 token. The factory serves as a public registry for all exchange contracts. Only one exchange is allowed for each token.

To initialize an exchange, one must deposit both ethers and the tokens into the exchange. Anyone can add liquidity by providing ethers and correponding tokens to the pool. Pool shares are minted when liquidity is deposited into the system and can be burned to withdraw a proportion shares of the reserves.

Traders can swap between ether and token or between two tokens. Users can specify a recipient address to make a payment for the purchased tokens.

It uses a constant product market making formula. A small liquidity provider fee of 0.3% is added to the reserve for each transaction. Slippage occurs for each transaction. Traders can bound price fluctuation by specifying the minimum amount of the purchase.