Search code examples
javascriptsolidityweb3jsethers.jsusedapp

useDapp and hardhat returning different values from smart contract


I have a local testnet node using Hardhat. I can successfully deploy and test against my contract using plain javascript, async await and const { ethers, upgrades } = require("hardhat");.

I am correctly returning, and printing to the console, a BigNumber array with 2 elements from a contract function.

But the useDapp function call returns a different value.

I have tried everything: JSON.stringify(array) returns [[]], array[0] returns undefined, BigNumber.from(array).toNumber throws some crazy BigNumber error, etc. But I know the contract is giving it the correct values.

Why am I getting 2 different values in 2 different javascript files? I'm assuming it's an issue with the way the hardhat test file is retrieving the values vs. useDapp.

My useDapp front end hook looks like this which returns [Array(0)] with length: 1:

export function useGetArray(): BigNumber[] | undefined {
  const {value,error}: any = useCall({
    contract: new Contract(myContract, myInterface),
    method: "getArray",
    args: [],
  }) ?? [];

  if(error) {
    return error;
  } else {
    return value;
  };
}

My hardhat javascript test looks like this which returns [ BigNumber { value: "50" }, BigNumber { value: "129" } ]:

CONTRACT = await ethers.getContractFactory("CONTRACT");
const contract = await CONTRACT.attach("0x109d198fca64d33Bd9F33E60333A544412cfAC7D");
  array = await contract.getArray();
  console.log(array);

Please know that 2 other nearly identical function calls using useDapp, and one even passing data to contract, work completely fine. So the issue does not lay in the address being used or imported ABI.


Solution

  • For anyone super confused on this, which I'm sure will be common in the future with EVM smart contract developers, the hardhat default network testing vs testing against a mainnet fork will return different number types from the contract.

    For example, using regular .js test files with the default network, returning a uint256[] from the contract will be regular integer looking numbers.

    But for the mainnet fork, returning a uint256[] will return a BigNumber array, which javascript has trouble breaking down. You will need a BigNumber package to work with it. It seems the mainnet fork .js interactions require getting the first element of the array Array[0], and inside of that element will be each BigNumber object, which further needs decoded with something like BigNumber.from(yourNumber).toNumber().

    Note: as for sending numbers in to the contract, you need to make sure you pay attention to the decimals of a token when dealing with any token values. For example, if a token has 6 decimal places programmed in the contract, and you want to send a value into the contract representing 600 coins, you need to send either 600000000 (600 with 6 0's added) or BigNumber.from(600000000). I am not sure if converting it to a BigNumber type before sending it into the contract saves gas or something, because the conversion is off chain, but it seems you can send either number in to the contract. You just have to make sure you add the 0's to the end of the number according to the token you are working with.