3

I'm trying to decode the data from a transaction on a smart contract test using the instructions from Ethers.js docs but I keep getting that the first argument (fragment) is invalid:

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));

I tried with:

  1. Name of the function: "addLiquidityETH".
  2. Function signature: "addLiquidityETH(address,uint,uint,uint,address,uint)" and "addLiquidityETH(address,uint,uint,uint,address,uint) external payable returns (uint,uint,uint)"
  3. The sighash of both signatures: "0x1a3042d8" and "0x251511cc"
  4. interface.decodeFunctionResult( fragment , data )

...but the error still appears.

Error:

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

Thanks for the help!

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);  

  });
});

1 Answer 1

2

Found the solution:

I was importing IUniswapV2Router02 on my original contract thinking that the interface that I needed on my test was my contract's interface:

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);
    }
}

...when in fact I needed to require IUniswapV2Router02 directly into my test instead of my contract's interface.

As soon as I did that, decodeFunctionData worked perfectly by just using 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);  

  });
});

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.