1

我正在寻找一种使用 Truffle 创建自动化测试套件的方法,该套件可以测试我的智能合约与 Uniswap V2 的交互。Uniswap 文档简要提到了使用 Truffle 进行测试,但没有提供任何示例。我希望使用带有 ganache 的主网分叉对其进行测试。

我猜这与这个问题的公认答案类似,但我特别在寻找一种使用 Truffle 和 web3.js 的方法。

例如,如果我正在测试以下合约:

pragma solidity ^0.6.6;

interface IUniswap {
  function swapExactETHForTokens(
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline)
  external
  payable
  returns (uint[] memory amounts);
  function WETH() external pure returns (address);
}

contract MyContract {
  IUniswap uniswap;

  constructor(address _uniswap) public {
    uniswap = IUniswap(_uniswap);
  }

  function swapExactETHForTokens(uint amountOutMin, address token) external payable {
    address[] memory path = new address[](2);
    path[0] = uniswap.WETH();
    path[1] = token;
    uniswap.swapExactETHForTokens{value: msg.value}(
      amountOutMin, 
      path,
      msg.sender, 
      now
    );
  }
}

我将如何创建一个单元测试来验证是否将swapExactETHForTokens()ETH换成 DAI?对于_uniswap我一直在使用UniswapV2Router02的价值。

任何帮助将不胜感激。

4

2 回答 2

1

如果您使用 Uniswap 平台交换代币,您将有 2 个步骤。您将批准令牌,在此步骤中元掩码将弹出,您将确认它。然后 Uniswap 将进行实际的交换,它将代币从你的钱包中取出并为你进行交换。

这是swapExactETHForTokens功能

function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        virtual
        override
        payable
        ensure(deadline)
        returns (uint[] memory amounts)
    {
        require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
        amounts = UniswapV2Library.getAmountsOut(factory, msg.value, path);
        require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
        IWETH(WETH).deposit{value: amounts[0]}();
        assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
        _swap(amounts, path, to);
    }

最后一个函数_swap调用swap函数:

从文档

同样重要的是要确保你的合约控制足够的 ETH/代币来进行交换,并已批准路由器撤回这么多代币。

想象一下,你想从你的智能合约中用 50 DAI 换取尽可能多的 ETH。

从转移

在交换之前,我们的智能合约需要控制 50 DAI。完成此操作的最简单方法是在 DAI 上调用 transferFrom,并将所有者设置为 msg.sender:

uint amountIn = 50 * 10 ** DAI.decimals();
require(DAI.transferFrom(msg.sender, address(this), amountIn), 'transferFrom failed.');

Uniswap 最终会transferFrom,但在你的代币必须批准交易之前,它必须添加uniswap address到它的allowance映射中。

mapping(address=>mapping(address=>uint)) public allowance;
// token address is allowign uniswap address for this much token

除非您设置了交换令牌并且您的交换令牌必须调用approve.

如果你有前端应用程序,当你调用合约的交换函数时,metamask 会弹出,你会确认它。但是,在测试环境中,您需要实际的 ERC20 合约,部署它并调用approve. 在前端,您将有两个函数swapTokenapprove. 你会按这个顺序打电话给他们吗?

const startSwap = async () => {
    await approve()
    await swapToken()
}

在测试套件中:

const MyContract = artifacts.require("MyContract");
const Dai = artifacts.require("Dai");

// ganache provides an array of accounts
contract("Uniswap", (ganachProvidedAccounts) => { 
  let myContract,dai;
  // intialize the contracts before each test
  before(async () => {
    myContract = await myContract.new();
    dai = await Dai.new();
  })

  describe("Swapping", async () => {
    it("swap tokens", async () => {
      let result;
     
      // first ask for approval of 100 token transfer
      await dai.approve(myContract.address, tokens("100"), {
        from:ganachProvidedAccounts[0] ,
      });
      // // check staking for customer
      await myContract.swapExactETHForTokens("100"), { from: ganachProvidedAccounts[0] });
      // make your assetion
})})
于 2022-02-07T10:38:39.290 回答
0

无论如何,我最终还是使用了 Hardhat/Ethers.js,只是因为设置主网分支和运行自动化测试套件非常容易。我在这里提供了一个答案,解释了设置主网分叉所需的步骤,并在这个问题中重用了示例合约(完成了测试)。

不过,为了具体回答这个问题,Hardhat 有一个支持使用 Truffle/Web3js 进行测试的插件,因此您仍然可以使用 Truffle/Web3js 编写测试/合约,但使用 Hardhat 的主网分叉功能与已经部署的其他合约进行交互主网。

于 2022-02-20T02:20:56.203 回答