I have a method in my contract like so:
mapping(address => uint256) allowance;
...
function setAllowance(address user, uint256 amount) external onlyOwner nonReentrant returns (uint256) {
allowance[user] = amount;
emit AllowanceLimitChange(user, amount, ChangeType.None, allowance[user]);
return allowance[user];
}
In my truffle test, I am expecting it to return me a uint256
, but it actually returns me a transaction object! Below is my test code:
it("should set allowance limits to non-zero", async () => {
try {
const value = web3.utils.toWei("0.2");
const newAllowance = await contract.setAllowance(accounts[1], value);
assert.equal(value, newAllowance); // assertionError
} catch (err) {
assert(false); // always come here because of assertionError due to type mismatch
}
});
Best Answer
TLDR;
Similar to this issue here , use
.call
after the function name. Then it works out!Edit: (adding more details in the line of @GoodVibration's comments)
setAllowance
is a non-constant call, which means it modifies contract state in some way.constant
was used in older solidity code, which in modern versions are indicated viaview
(only reads state) orpure
(no read from, or write to contract state).When we invoke such a non-constant method, we will only get the transaction response as the return value, irrespective of what return value we might have coded in (in this case,
uint256
). Thus, we have two options:.call
: this sort of "evaluates" the code inside the method, but not cause a transaction to happen, and thus no state change will be persisted. A test case to help explain things better:await contract.method(... args)
, thatmethod
is actually invoked, transaction goes through mining, and events are fired. While this is great, it will always return a Tx object as response, and not the return type you coded. As such you need to assert on the events that gets fired. something like this: