Невозможность декодирования данных транзакции

Я пытаюсь декодировать данные из транзакции в тесте смарт-контракта, используя инструкции из документации Ethers.js, но я продолжаю получать, что первый аргумент (фрагмент) недействителен:

Ethers.js

      interface.decodeFunctionData( fragment , data ) ⇒ Result

Returns the decoded values from transaction data for fragment (see Specifying Fragments) for the given data.

ABI:

      const abi = require('../artifacts/contracts/CoinX.sol/CoinX.json').abi;

Interface:

       let ICoinX = new ethers.utils.Interface(abi);

AddLiquidityETH function on UniswapV2Router02.sol:

      function addLiquidityETH(
  address token,
  uint amountTokenDesired,
  uint amountTokenMin,
  uint amountETHMin,
  address to,
  uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);

Main snippet on my test:

      const tx = await router.addLiquidityETH(coinX.address, supply, supply, supply, addr1, MaxUint256, {
      value: supply
    });   
    const { data } = tx;

    console.log("Decoded data: ", await ICoinX.decodeFunctionData("addLiquidityETH", data));

Я пробовал:

  1. Название функции: "addLiquidityETH".
  2. Сигнатура функции: "addLiquidityETH(address,uint,uint,uint,address,uint)" а также "addLiquidityETH(address,uint,uint,uint,address,uint) external payable returns (uint,uint,uint)"
  3. Сигхеш обеих подписей: "0x1a3042d8" а также "0x251511cc"
  4. interface.decodeFunctionResult( fragment , data )

... но ошибка все равно появляется.

Error:

      Error: no matching function (argument="name", value="addLiquidityETH", code=INVALID_ARGUMENT, version=abi/5.3.1)

Спасибо за помощь!

Full test:

      const { parseEther, formatEther } = ethers.utils;
const { MaxUint256 } = ethers.constants;

const abi = require('../artifacts/contracts/CoinX.sol/CoinX.json').abi;

const routerAddress = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D";
const factoryAddress = "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f";

describe("Uniswap", function() {
  let router, coinX, ICoinX, factory;
  const supply = parseEther('100');

  before(async () => {
    router = await ethers.getContractAt("IUniswapV2Router02", routerAddress);
    factory = await ethers.getContractAt("IUniswapV2Factory", factoryAddress);

    const CoinX = await ethers.getContractFactory('CoinX');
    coinX = await CoinX.deploy(supply);
    await coinX.deployed();

    ICoinX = new ethers.utils.Interface(abi);
  });

  it("should allow trades", async function() {
    const wethAddr = await router.WETH();
    const [addr1] = await ethers.provider.listAccounts();

    console.log("coins before: ", formatEther(await coinX.balanceOf(addr1)));

    await coinX.approve(routerAddress, MaxUint256);

    const tx = await router.addLiquidityETH(coinX.address, supply, supply, supply, addr1, MaxUint256, {
      value: supply
    });

    const { data } = tx;

    console.log("Decoded data: ", await ICoinX.decodeFunctionData("addLiquidityETH", data)); // --------> Problem

    console.log("coins after: ", formatEther(await coinX.balanceOf(addr1)));

    const pairAddress = await factory.getPair(coinX.address, wethAddr);  
    console.log(pairAddress);  

  });
});

2 ответа

uintэто псевдоним для. Сигнатура функции всегда генерируется из выражения, содержащего длину байта (в вашем случае uint256).

Итак, вам нужно пройти

      addLiquidityETH(address,uint256,uint256,uint256,address,uint256)

вместо addLiquidityETH к decodeFunctionData() функция.

Нашел решение:

Я импортировал свой исходный контракт, думая, что интерфейс, который мне нужен в моем тесте, был интерфейсом моего контракта:

      pragma solidity ^0.8.0;

//routers interface
import '@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol';     
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';


contract CoinX is ERC20 {
    constructor(uint256 initialSupply) ERC20("CoinX", "CNX") {
        _mint(msg.sender, initialSupply);
    }
}

... когда на самом деле мне нужно было потребовать IUniswapV2Router02 прямо в мой тест, а не в интерфейс моего контракта.

Как только я это сделал, decodeFunctionData отлично работал, просто используя addLiquidityETH.

Full test (fixed):

      const { parseEther, formatEther } = ethers.utils;
const { MaxUint256 } = ethers.constants;

//router's ABI
const abiRouter = require('../artifacts/@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol/IUniswapV2Router02.json').abi;

const routerAddress = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D";
const factoryAddress = "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f";

describe("Uniswap", function() {
  let router, coinX, myIUniswapV2Router02, factory;
  const supply = parseEther('100');

  before(async () => {
    router = await ethers.getContractAt("IUniswapV2Router02", routerAddress);
    factory = await ethers.getContractAt("IUniswapV2Factory", factoryAddress);

    const CoinX = await ethers.getContractFactory('CoinX');
    coinX = await CoinX.deploy(supply);
    await coinX.deployed();

    //router's interface on my test
    myIUniswapV2Router02 = new ethers.utils.Interface(abiRouter);
  });

  it("should allow trades", async function() {
    const wethAddr = await router.WETH();
    const [addr1] = await ethers.provider.listAccounts();

    console.log("coins before: ", formatEther(await coinX.balanceOf(addr1)));

    await coinX.approve(routerAddress, MaxUint256);

    const tx = await router.addLiquidityETH(coinX.address, supply, supply, supply, addr1, MaxUint256, {
      value: supply
    });

    const { data } = tx;

    //works as expected
    console.log("Decoded data: ", await myIUniswapV2Router02.decodeFunctionData("addLiquidityETH", data)); 
    
    console.log("coins after: ", formatEther(await coinX.balanceOf(addr1)));

    const pairAddress = await factory.getPair(coinX.address, wethAddr);  
    console.log(pairAddress);  

  });
});
Другие вопросы по тегам