2

I have a function, fn(), in a contract that returns a variable. I am then testing said function's returned variable value in a Hardhat unit test written in TypeScript. However, when I console.log the output of calling fn(), it logs the entire transaction receipt.

If I then alter the function to be either a view or pure function, it logs the actual value of the returned variable. The problem is that I need to test that the function actually alters a state variable. How do I remedy this?

function that logs tx receipt:

fn() public returns(uint8) {
    uint8 numberLogged = 1;
    return numberLogged;
}

function that logs variable's value:

fn() public pure /*or view*/ returns(uint8) {
    uint8 numberLogged = 1;
    return numberLogged;
}

unit test:

import { FnContract } from "../typechain/FnContract";

describe("FnContract contract test", function () {
    let fnContract: FnContract;

    it("logs the output of fn()", async function() {
        const fnContractFactory = await ethers.getContractFactory("FnContract");

        const accounts = await ethers.getSigners();

        const accountOne = accounts[0];
        const accountTwo = accounts[1];

        fnContract = (await fnContractFactory.deploy()) as FnContract;

        const numberLogged = await fnContract.fn();
        await numberLogged.wait();

        console.log(numberLogged);
    })

Lastly, I am currently learning TypeScript, so could it possibly be in how I set up the TypeScript test file?

2 Answers 2

3

Unfortunately, it's not possible to get the return value of a state-changing function outside the off-chain. It's only possible to get it on-chain, in other contracts which call your contract.

What is usually done is that you emit events with the required data, and listen to those events. Or then you save the required data in the contract and have another view function which you call to return the data.

3
  • 2
    I've been searching for answers, and what you say echoes others things I've come across. I find it peculiar I'm just now coming across this issue, since I've written a good amount of tests previously. But thank you!
    – Roberto
    Sep 13, 2021 at 17:43
  • Yeah it's surprisingly difficult to find this information around. There are a few StackExchange answers about it around, and that's almost it. Sep 13, 2021 at 17:46
  • 2
    You can do this in brownie with return_value. I feel like hardhat should support it too. ethereum.stackexchange.com/questions/92603/… Nov 10, 2021 at 17:10
2
contract.callStatic.METHOD_NAME( ...args [ , overrides ] ) ⇒ Promise< any >

Rather than executing the state-change of a transaction, it is possible to ask a node to pretend that a call is not state-changing and return the result.

This does not actually change any state, and can be used to get the return value from a non-const contract method, by executing it, but without really executing it.

For ref -> https://docs.ethers.io/v5/api/contract/contract/#contract-callStatic

In truffle/web3 also, we can do this by calling a non-const contract method with .call() instead of .send().

Hope it helps!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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