3

详解 SushiSwap

 3 years ago
source link: https://learnblockchain.cn/article/2740
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

你现在可能已经听说过SushiSwap了。其分叉自Uniswap,同时带来了新的功能,比如质押和治理。但它背后的合约究竟是如何运作的呢?

其实这并不难。详细了解这个工作原理将是学习Solidity和Defi的一个好方法。

我们现在将深入SushiSwap的实现细节。为了更容易理解,一些代码被修改了。你可以随时查看Github里面的完整代码。

1. Uniswap v2

SushiSwap核心部分只是一个Uniswap v2的分叉。除了一些小的差别,合同代码是完全复制的。如果你对Uniswap v2的工作原理感到好奇,请看我以前的文章这里。在不久的将来对Uniswap v3的深入研究。

特别是SushiSwap正在利用流动性池代币(LP代币)。请查看https://uniswap.org/docs/v2/core-concepts/pools/ 在 LP 代币下的所有细节。从本质上讲,LP是用来接收在流动池中累积的按比例费用。你在一个流动池里提供流动性,并得到LP代币的回报。当资金池现在随着交易的进行收取费用时,它们会在交易时平均分配给所有LP持有人。当你销毁LP代币时,则将收到对应流动池中的资金份额和收集的费用。

SushiSwap对Uniswap代码做了两处修改:

  1. 在部署中调用了setFeeTo函数,费用接受者被设置为SushiMaker合约(见下文)。一旦费用接受者被设置,由于当前交易导致的LP 发行量增长的1/6将以LP代币的形式被铸成协议费用。由于Uniswap的交易费是0.3%,因此每笔交易的0.05%的费用将流向SushiMaker。
  2. 增加了一个迁移者功能(见下文SushiRoll)。

你可以看到Uniswap的核心合约和SushiSwap如何改变它们之间的全部差异这里

2. SushiMaker

Sushi Maker

SushiMaker将从SushiSwap上交易的人那里接收LP代币。它主要由一个 convert 函数组成,它的作用如下:

  1. 销毁(Burn)掉提供的LP代币。其结果将是收到按比例的token0token1的数量。
  2. convertStep内将收到的两个代币兑换为SUSHI(代币)。如果没有直接的流动池来兑换为SUSHI,这可能需要额外的步骤。
function convert(address token0, address token1) external {
  UniV2Pair pair = UniV2Pair(factory.getPair(token0, token1));
  require(address(pair) != address(0), "Invalid pair");

  IERC20(address(pair)).safeTransfer(
      address(pair),
      pair.balanceOf(address(this))
  );

  (uint256 amount0, uint256 amount1) = pair.burn(address(this));

  if (token0 != pair.token0()) {
      (amount0, amount1) = (amount1, amount0);
  }

  _convertStep(token0, token1, amount0, amount1)
}

兑换本身也是通过SushiSwap 流动池来进行的。可以通过_swap函数来看看这是如何做到的。

function _swap(
    address fromToken,
    address toToken,
    uint256 amountIn,
    address to
) internal returns (uint256 amountOut) {
    UniV2Pair pair =
        UniV2Pair(factory.getPair(fromToken, toToken));
    require(address(pair) != address(0), "Cannot convert");

    (uint256 reserve0, uint256 reserve1, ) = pair.getReserves();
    uint256 amountInWithFee = amountIn.mul(997);

    if (fromToken == pair.token0()) {
        amountOut =
            amountInWithFee.mul(reserve1) /
            reserve0.mul(1000).add(amountInWithFee);
        IERC20(fromToken).safeTransfer(address(pair), amountIn);
        pair.swap(0, amountOut, to, new bytes(0));
    } else {
        amountOut =
            amountInWithFee.mul(reserve0) /
            reserve1.mul(1000).add(amountInWithFee);
        IERC20(fromToken).safeTransfer(address(pair), amountIn);
        pair.swap(amountOut, 0, to, new bytes(0));
    }
}

开始看到它使用了Uniswap低级别的 swap 函数。

  1. 获取池中两个代币的当前储备。
  2. 从储备金和被兑换的代币金额中计算出接收金额,减去费用。计算是基于x*y=k曲线

一旦计算出金额,我们就可以进行兑换了。转换为SUSHI的最后一步将总是通过传递SUSHI代币地址来调用_swap函数,并将其发送到bar:

_swap(token, sushi, amountIn, bar)

就这样,把所有的LP代币转换成了SUSHI,所有转换后的SUSHI都被送到了SushiBar,见下一个合约:

3. SushiBar

Sushi Bar

SushiBar内,人们可以带着SUSHI进入,得到xSUSHI,然后带着更多的SUSHI离开。请记住,所有来自SushiMaker的SUSHI都被送到这里。所以随着时间的推移,SushiBar会积累越来越多的SUSHI。

谁会收到这个SUSHI?

任何进入SushiBar的人。用户进入后会收到xSUSHI,这有点像Uniswap的LP代币。它们代表了SushiBar中SUSHI代币的所有权。

你收到的xSUSHI数量是你转移的SUSHI * xSUSHI发行总量 / SUSHI的当前余额...


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK