12

I just came from truffle to hardhat. Like the title says, I have a return value (address) of a contract and getting the transaction back. Any idea what I can do about that?

it("Check all tested", async function () {
testingFunction("createPair")

let justSo = await token.connect(actorA).approve(liqminter.address, startAmount)

const shareTokenAddress = await liqminter.connect(actorA).createPair(arg0, arg1, arg2, arg3, arg4, arg5)
console.log("Created Token: ", shareTokenAddress)

});

Output:

Created Token:  {
hash: '0xd1bd72405efb01c80b7dfe75507d93cb878ebba08bd61501dae586e938e74a88',
type: 2,
accessList: [],
blockHash: '0x044321bf6f437da19ef27f5e46e482bf58bafd823c4b8b010ff70d72dbc12498',
blockNumber: 8,
transactionIndex: 0,
confirmations: 1,
from: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
gasPrice: BigNumber { _hex: '0x525b8ada', _isBigNumber: true },
maxPriorityFeePerGas: BigNumber { _hex: '0x3b9aca00', _isBigNumber: true },
maxFeePerGas: BigNumber { _hex: '0x691c4bb4', _isBigNumber: true },
gasLimit: BigNumber { _hex: '0x01bae3d8', _isBigNumber: true },
to: '0x8ce361602B935680E8DeC218b820ff5056BeB7af',
value: BigNumber { _hex: '0x00', _isBigNumber: true },
nonce: 3,
data:   '0xb34471f2000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f05120000000000000000000000000    00000000000000000000000000000000000000000000000000000000000000090f79bf6eb2c4f870365e785982e1f101e93b    9060000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000    00000000000000000000000000027100000000000000000000000000000000000000000000000056bc75e2d63100000',
r: '0x2320064cb991b41feba18c5307d11a38e1d66344e75dc9d0d6844127910e3b49',
s: '0x4253b8a878827affc6f5d08d6122ac21c28ef1f3a9227ae6025ac6a0afd1cde0',
v: 0,
creates: null,
chainId: 31337,
wait: [Function (anonymous)]
}

4 Answers 4

7

I had the same issue. It's hard to tell without seeing your contract posted, but for me, I was trying to simply read a value from a public function.

You need to let the Ethereum know that you're returning a read only value, which does not require a transaction. To do this, mark your function as a view:

function ping() public view returns (string memory) {
    return "pong";
}
8

To get the return value you should add callStatic to it.

>   const shareTokenAddress = await liqminter.connect(actorA).callStatic.createPair([...])

callStatic is a read-only operation and will not consume any Ether. It simulates what would happen in a transaction, but discards all the state changes when it is done.

1
  • Thank you. But it behaves a bit different or I misunderstood something. That is the output [Function: shareTokenAddress] (There should be an address) Also I can't call it twice (in the contract is a check if the function already created an address) so I guess the state is changed even with callStatic
    – MaTok
    Commented Oct 21, 2021 at 8:50
5

You need to use Events. Here is an idea:

const tx = await contract.transfer(...args); // 100ms
const rc = await tx.wait(); // 0ms, as tx is already confirmed
const event = rc.events.find(event => event.event === 'Transfer');
const [from, to, value] = event.args;
console.log(from, to, value);

Check it out https://ethereum.stackexchange.com/a/119856/92472

3
  • 1
    This does not answer the question. Using your method, we can find information about the Transfer event (whence, whither, and how much was transferred), but the return value of the Transfer function should be a boolean. How do we read that boolean? Commented Aug 5, 2022 at 14:58
  • 1
    @imat This answers the question perfectly. Up to this date return values are used on-chain ie. between or within contracts. Events are exposed off-chain and it is what you can capture through events after writing to the blockchain. We all would love to get the return value but until now, this is the best we can do.
    – Carlitos
    Commented Dec 26, 2022 at 23:54
  • You could use callStatic but that does not change the state of the blockchain and behaves like a read operation. The docs recommended its use for testing if a transaction will be successful or not for UX purposes. For testing we need to use events if we are changing state and want to receive some data.
    – Carlitos
    Commented Dec 26, 2022 at 23:58
1

Can't find any documentation but there is currently a method called "staticCall" which achieves what you're looking for:

const shareTokenAddress = await liqminter.connect(actorA).createPair.staticCall(arg0, arg1, arg2, arg3, arg4, arg5)

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.