banner
zach

zach

github
twitter
medium

Introduction to Uniswap v1

Uniswap v1#

Overview | Uniswap

Uniswap v1 is the first version, with relatively simple functionality and logic. It only supports trading pairs between ETH and ERC20 tokens, with a fixed fee of 3%.
The basic functionality implemented by Uniswap v1 is the constant product market maker system, where the product of the number of ETH and ERC20 tokens in a single trading pair remains constant. In the AMM mechanism, each trader's counterparty is the trading pool itself.

The code of Uniswap v1 is divided into two parts: factory and exchange. The following explains the implementation mechanism and principles of each part.

Factory#

Uniswap Factory Contract

The factory contract is used to maintain all exchange trading pairs. It does not have core trading logic, but includes the following core methods:

  • initializeFactory: Used to set the exchangeTemplate contract address during creation, which will be used for all exchange trading pair contracts in the future. It can only be set once.
  • createExchange: Used to create a trading pair for a token. create_with_code_of is used to copy the code of the specified contract and deploy a new contract.

In addition, the factory also records the following mapping relationships for easy querying of trading pairs and token information:

  • tokenCount: Records the total number of trading pairs created.
  • token_to_exchange: Records the mapping of tokens to exchange trading pair addresses.
  • exchange_to_token: Records the mapping of exchange trading pair addresses to tokens.
  • id_to_token: Records the mapping of trading pair IDs to tokens.
@public
def initializeFactory(template: address):
    assert self.exchangeTemplate == ZERO_ADDRESS
    assert template != ZERO_ADDRESS
    self.exchangeTemplate = template

@public
def createExchange(token: address) -> address:
    assert token != ZERO_ADDRESS
    assert self.exchangeTemplate != ZERO_ADDRESS
    assert self.token_to_exchange[token] == ZERO_ADDRESS
    exchange: address = create_with_code_of(self.exchangeTemplate)
    Exchange(exchange).setup(token)
    self.token_to_exchange[token] = exchange
    self.exchange_to_token[exchange] = token
    token_id: uint256 = self.tokenCount + 1
    self.tokenCount = token_id
    self.id_to_token[token_id] = token
    log.NewExchange(token, exchange)
    return exchange

Exchange#

Interface#

Uniswap Exchange Contract

The core content of each trading pair is in the exchange contract. The core methods are shown in the following interface, which can be mainly divided into the following parts:

  • Liquidity management: Adding or removing liquidity, mainly using the object "lp".
  • Price query:
    • Calculate how much ETH can be obtained by selling a certain amount of tokens.
    • Calculate how many tokens can be obtained by selling a certain amount of ETH.
    • Calculate how much ETH is needed to buy a certain amount of tokens.
    • Calculate how many tokens can be bought by a certain amount of ETH.
  • Providing ETH to exchange for tokens: Similar to the price query above, there are four trading methods.
  • Providing tokens to exchange for ETH: Similar to the price query above, there are four trading methods.
  • Token-to-token exchange: Similar to the price query above, there are four trading methods.
interface UniswapExchangeInterface {
    // Liquidity
    function addLiquidity(uint256 min_liquidity, uint256 max_tokens, uint256 deadline) external payable returns (uint256);
    function removeLiquidity(uint256 amount, uint256 min_eth, uint256 min_tokens, uint256 deadline) external returns (uint256, uint256);
    // Price query
    function getEthToTokenInputPrice(uint256 eth_sold) external view returns (uint256 tokens_bought);
    function getEthToTokenOutputPrice(uint256 tokens_bought) external view returns (uint256 eth_sold);
    function getTokenToEthInputPrice(uint256 tokens_sold) external view returns (uint256 eth_bought);
    function getTokenToEthOutputPrice(uint256 eth_bought) external view returns (uint256 tokens_sold);
    // Providing ETH to exchange for tokens
    function ethToTokenSwapInput(uint256 min_tokens, uint256 deadline) external payable returns (uint256  tokens_bought);
    function ethToTokenTransferInput(uint256 min_tokens, uint256 deadline, address recipient) external payable returns (uint256  tokens_bought);
    function ethToTokenSwapOutput(uint256 tokens_bought, uint256 deadline) external payable returns (uint256  eth_sold);
    function ethToTokenTransferOutput(uint256 tokens_bought, uint256 deadline, address recipient) external payable returns (uint256  eth_sold);
    // Providing tokens to exchange for ETH
    function tokenToEthSwapInput(uint256 tokens_sold, uint256 min_eth, uint256 deadline) external returns (uint256  eth_bought);
    function tokenToEthTransferInput(uint256 tokens_sold, uint256 min_eth, uint256 deadline, address recipient) external returns (uint256  eth_bought);
    function tokenToEthSwapOutput(uint256 eth_bought, uint256 max_tokens, uint256 deadline) external returns (uint256  tokens_sold);
    function tokenToEthTransferOutput(uint256 eth_bought, uint256 max_tokens, uint256 deadline, address recipient) external returns (uint256  tokens_sold);
    // Token-to-token exchange
    function tokenToTokenSwapInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address token_addr) external returns (uint256  tokens_bought);
    function tokenToTokenTransferInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address recipient, address token_addr) external returns (uint256  tokens_bought);
    function tokenToTokenSwapOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address token_addr) external returns (uint256  tokens_sold);
    function tokenToTokenTransferOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address recipient, address token_addr) external returns (uint256  tokens_sold);
}

Core Process#

Although there are multiple types of trades involved in Uniswap, it may seem complex, but the core process of Uniswap v1 can be represented by these two diagrams.

As two roles using Uniswap, LP is responsible for adding and moving liquidity, while players are responsible for swapping in the trading pair.

  • As an LP, whether adding or removing liquidity, it needs to be done proportionally.
  • As a player, swapping in the trading pair needs to follow the constant product agreement.

image

Uniswap provides many sets of methods, and their names follow a certain rule: A-To-B-swap/transfer-input/output.

  • A and B represent the token and ETH combination.
  • swap/transfer: Choose one of the two types of transactions.
  • input/output: Choose one of the two transaction directions.

For token-ETH input-output, there are four combinations of price query methods:

// Price query
function getEthToTokenInputPrice(uint256 eth_sold) external view returns (uint256 tokens_bought);
function getEthToTokenOutputPrice(uint256 tokens_bought) external view returns (uint256 eth_sold);
function getTokenToEthInputPrice(uint256 tokens_sold) external view returns (uint256 eth_bought);
function getTokenToEthOutputPrice(uint256 eth_bought) external view returns (uint256 tokens_sold);
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.