如何在合约中集成 Uniswap v3

如何在合约中集成 Uniswap v3

Uniswap v3的新内容及集成

如果你还不熟悉Uniswap,它是一个去中心化的交易所(DEX),依靠外部流动性提供者将代币添加到流动池配对中,用户可以直接交易这些代币。

由于它在以太坊上运行,可以交易的是以太坊ERC-20代币。每种代币都有自己的智能合约和流动资金池。Uniswap--作为完全的去中心化--对哪些代币可以添加没有限制。如果一个代币对还没有流动池合约存在,任何人都可以Uniswap的工厂创建一个,任何人都可以向池子提供流动性。每笔交易有0.3%的费用给流动性提供者作为奖励。

代币的价格是由池中的流动性决定的。例如,如果一个用户用TOKEN2购买TOKEN1,池中TOKEN1的供应将减少,而TOKEN2的供应将增加,TOKEN1的价格将增加。同样地,如果一个用户正在出售TOKEN1TOKEN1的价格将下降。因此,代币价格总是反映了供需关系。

当然,用户不一定是人,也可以是一个智能合约。这使得可以将Uniswap添加到我们自己的合约中,为我们合约的用户增加额外的支付选项。Uniswap使这个过程非常方便,请看下面的整合方法。

Uniswap UI

UniSwap v3 中有什么新内容?

之前有一篇文章讨论了Uniswap v2的新内容,现在让我们看看Uniswap v3的新内容。

  • 为流动性提供者提供的一个新功能,允许设置有效的价格范围。每当资金池价格在该范围之外时,他们的流动性就会被忽略。这不仅减少了流动性提供者的无常损失的风险,提高了资本效率...
  • 提供了不同的收费等级,由资金池的风险水平决定收费等级。有三个不同的级别:

    • 稳定币交易对:费率0.05%,针对像USDT/DAI这样波动风险低的货币对。由于两者都是稳定币,这些潜在的无常损失是非常低的。这对交易者来说特别有趣,因为它将允许在稳定币之间进行非常便宜的兑换。
    • 中度风险对:费率0.30%, 中等风险被认为是任何具有高交易量/主流的非相关货币对,主流货币对往往在波动性方面具有稍低的风险。
    • 高风险货币对:费率1.00%,其他独特的货币对可以被视为流动性提供者的高风险,并产生最高的交易费用1%。
  • 改进了Uniswap v2 TWAP预言机机制,一个链上调用就可以检索到过去9天的TWAP价格。为了实现这一点,不是只存储一个累积价格总和,而是将所有相关的价格存储在一个固定大小的数组中。这可以说稍微增加了Gas成本,但总的来说,对于大型预言机的增强是值得的。

进一步的Uniswap v3资源

整合UniSwap v3

Uniswap如此受欢迎的原因之一可能是将它们整合到自己的智能合约中的非常简单。比方说,你有一个系统,用户用DAI支付。有了Uniswap,只需几行代码,你就可以增加他们也可以用ETH支付的选项。ETH可以在实际逻辑之前自动转换为DAI。它看起来像这样:

function pay(uint paymentAmountInDai) public payable {
if (msg.value > 0) {
convertEthToExactDai(paymentAmountInDai);
} else {
require(daiToken.transferFrom(msg.sender, address(this), paymentAmountInDai);
}
// do something with that DAI
...
}

在你的函数的开头做一个简单的检查就足够了。现在,对于convertEthToExactDai函数,它将看起来像这样的东西。

function convertEthToExactDai(uint256 daiAmount) external payable {
    require(daiAmount > 0, "Must pass non 0 DAI amount");
    require(msg.value > 0, "Must pass non 0 ETH amount");

    uint256 deadline = block.timestamp + 15; // using 'now' for convenience, for mainnet pass deadline from frontend!
    address tokenIn = WETH9;
    address tokenOut = multiDaiKovan;
    uint24 fee = 3000;
    address recipient = msg.sender;
    uint256 amountOut = daiAmount;
    uint256 amountInMaximum = msg.value;
    uint160 sqrtPriceLimitX96 = 0;

    ISwapRouter.ExactOutputSingleParams memory params = ISwapRouter.ExactOutputSingleParams(
        tokenIn,
        tokenOut,
        fee,
        recipient,
        deadline,
        amountOut,
        amountInMaximum,
        sqrtPriceLimitX96
    );

    uniswapRouter.exactOutputSingle{ value: msg.value }(params);
    uniswapRouter.refundETH();

    // refund leftover ETH to user
    (bool success,) = msg.sender.call{ value: address(this).balance }("");
    require(success, "refund failed");
}

这里有几件事情需要解读。

  • Swap Router:SwapRouter将是一个由Uniswap提供的包装合约,它有几个安全机制和便利功能。你可以使用 ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564)为任何主网或测试网实例化它。接口代码可以在这里找到。
  • WETH: 你可能注意到,我们在这里使用ETH。在Uniswap中,不再有直接的ETH对,所有的ETH必须首先转换为WETH(这是ETH包裹的ERC-20)。在我们的案例中,这是由SwapRouter完成的。
  • exactOutputSingle: 该函数可用于使用ETH并接收准确的代币数量。任何剩余的ETH将被退还,但不是自动! 我自己没有第一时间意识到这一点,ETH最后在路由器合约中。所以不要忘记在兑换后调用uniswapRouter.refundETH()! 并确保你的合约中有一个回退函数来接收ETH:receive() payable external {}deadline参数控制交易有效期。确保从你的前端传递这个UNIX时间戳,不要在合约内使用now
  • Refund(退款):一旦交易完成,我们可以将任...

剩余50%的内容订阅专栏后可查看

0 条评论

请先 登录 后评论
翻译小组
翻译小组

首席翻译官

90 篇文章, 13827 学分