xChar
·a year ago

Uniswap v1

Overview | Uniswap

uniswap v1是第一个版本,实现的功能和逻辑都比较简单,它只支持eth-erc20的交易对,固定的手续费3%
uniswap v1实现的最基本功能就是恒定乘积做市商系统,在单个交易对内的eth和erc20代币数目乘积总体保持恒定,在AMM机制中,每个交易者的对手方都是交易池本身

uniswap v1的代码就分为factory和exchange两部分,下面分别对照代码讲解它的实现机制和原理
下载

factory

工厂合约,用来维护所有的exchange交易对,没有核心的交易逻辑,核心的方法包括以下两个:

  • initializeFactory 用来在创建时设置exchangeTemplate合约地址,用作后续所有的exchange交易对合约,只允许设置一次
  • createExchange 用来创建token的交易对,create_with_code_of是用来拷贝指定合约的代码并部署新的合约

此外在factory中还记录了以下映射关系,便于查询交易对和token信息

  • tokenCount:记录当前创建的交易对总数
  • token_to_exchange:记录token到exchange交易对地址的映射
  • exchange_to_token:记录exchange交易对地址到token的映射
  • id_to_token:记录交易对id到token的映射
@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

接口

每个交易对的交易核心内容在exchange合约中,核心方法如下接口所示,主要可以分为以下几部分:

  • 流动性管理:添加或移除流动性,主要使用对象是lp
  • 价格查询:
    • 计算卖出一定额度token可以换取多少eth
    • 计算卖出一定额度eth可以换取多少token
    • 计算买入一定额度token可以换取多少eth
    • 计算买入一定额度eth可以换取多少token
  • 提供ETH兑换代币:同上面的价格查询,也有四种交易方法
  • 提供代币兑换ETH:同上面的价格查询,也有四种交易方法
  • 代币间兑换:同上面的价格查询,也有四种交易方法
interface UniswapExchangeInterface {
    // 流动性
    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);
    // 价格查询
    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);
    // 提供ETH以兑换代币
    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);
    // 提供代币以兑换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);
    // 代币之间的互换
    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);
}

核心流程

由于uniswap中涉及的交易类型,交易方向比较多,看着会有些复杂,但uniswap v1的核心流程可以用这两张图体现

作为使用uniswap的两种角色,lp负责添加和移动流动性,player负责在交易对中进行swap

  • 作为lp,无论添加还是移除流动性都需要按比例进行
  • 作为player,在交易对中swap需要按照恒定乘积的约定来换入换出
    image

uniswap提供的方法有很多组,命名是有规则的:A-To-B-swap/transfer-input/output

  • A和B是token和eth组合
  • swap transfer:交易类型二选一
  • input output:交易方向二选一

代币兑换

虽然uniswapv1的交易对都是由token-eth组成的,但是也提供了tokenA-tokenB的兑换

实现方式是在两个池子之间通过eth作为中间桥梁完成两次swap

价格换算

根据swap时约定的恒定乘积,在价格查询上有两个最基本的方法:

  • getInputPrice 根据输入计算输出
  • getOutputPrice 根据输出计算输入

并在此基础之上衍生了这几种方法,格式为:A-To-B-Input/Output

  • A是主动交易的token,A-input:即计算买入A可以换出多少B,A-output:即计算卖出A可以换出多少B

因此对于token-eth input-output共组合出四种价格查询方法:

// 价格查询
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 comments...