banner
zach

zach

github
twitter
medium

初识 Uniswap v1

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);
加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。