I'm currently using viem in a NextJs dApp and I'm facing an issue. Basically, I'm using the waitForTransactionReceipt action to await for a tx to be confirmed. The docs says that if the call reverts then an error would be thrown. However, at the current stage, even if the tx fails no error is risen and therefore I cannot catch it. Thanks to the receipt I have been able to somehow handle this case but I'd like to fire a toast where is written the error from the smart contract (which is a revert string and not a custom error).
Probably I'm missing something and I'm here asking for your help, thanks in advantage.
Here the code:
try{
let tx = await walletClient.writeContract({
address: '0x04fcda1a2478388FF0Ea011fC1Aa4FD027E7f136',
abi: abi,
functionName: 'withdraw',
account: walletClient.getAddresses()[0],
})
let transaction = await publicClient.waitForTransactionReceipt({
hash: tx
})
if(transaction.status !== 'reverted'){
toast.success('Withdrawn!', {
position: 'top-right',
autoClose: 3000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});
} else {
toast.error('Could not withdraw', {
position: 'top-right',
autoClose: 3000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});
}
} catch(e) {
console.log(e)
/* toast.error(`${e.details}`, {
position: 'top-right',
autoClose: 3000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
}); */
}
}
While if I don't use the 'if' statement, Metamask says that the tx has failed, poly scan display the revert reason but on the dApp no error is caught and the success toast is fired.
try{
let tx = await walletClient.writeContract({
address: '0x04fcda1a2478388FF0Ea011fC1Aa4FD027E7f136',
abi: abi,
functionName: 'withdraw',
account: walletClient.getAddresses()[0],
})
await publicClient.waitForTransactionReceipt({
hash: tx
})
toast.success('Withdrawn!', {
position: 'top-right',
autoClose: 3000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});
} catch(e) {
console.log(e)
/* toast.error(`${e.details}`, {
position: 'top-right',
autoClose: 3000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
}); */
}
}
Am I missing the elephant in the room?
Thanks again for your help.
Jul 19, 2023, 6:27 PM
I'm using writeContract and it throws an error if the tx reverts
I think you have the wrong input for writeContract's account option
Jul 19, 2023, 7:32 PM
I had to add the wait for the receipt because the writeContract didn’t throw anything :/ I’ll try again
Jul 19, 2023, 7:32 PM
writeContract({
...
accont: walletClient.account
})
...
accont: walletClient.account
})
maybe it's the same as what you have idk. But this is how I get the account
Jul 19, 2023, 7:33 PM
It honestly works, because in MetaMask I have several account for testing and getting the [0] is the currently in use by the connected user
Jul 19, 2023, 7:33 PM
why you don't use wagmi ?
writeContract of viem won't tell you if it fails. You need to call simulateContract first
Jul 19, 2023, 7:34 PM
I’ll try this way, thank you
Jul 19, 2023, 7:34 PM
oh ok. typescript doesn't like it anyway, it throws a type error
Jul 19, 2023, 7:34 PM
btw I highly suggest to use wagmi.sh
Jul 19, 2023, 7:35 PM
hm i dont think so. I also used simulateContract, and tried without it. I'm still getting a thrown error without simulateContract
Jul 19, 2023, 7:35 PM
Honestly idk 😂
Jul 19, 2023, 7:35 PM
simulateContract is more of a convenience thing afaik
Jul 19, 2023, 7:35 PM
Oh ok, thanks m8 I’ll update you as soon as I’ll try this solution
Jul 19, 2023, 7:35 PM
it is needed in order to check if the tx fails or no
without it the tx will get submitted in any case, error or no
Jul 19, 2023, 7:38 PM
yes but when the tx reverts it still throws.
simulateContract allows you to avoid paying the gas when it already knows it'll fail
simulateContract allows you to avoid paying the gas when it already knows it'll fail
remix & metamask also do similar. If it knows the tx will fail, it'll warn you to not waste gas.
But if you submit, the tx fails when it hits the blockchain, and viem throws an error here.
But if you submit, the tx fails when it hits the blockchain, and viem throws an error here.
Jul 19, 2023, 7:42 PM
sure?
Last time I used viem the tx was sent anyway
Jul 19, 2023, 7:52 PM
on backend?
Jul 19, 2023, 7:54 PM
it was a script yes
Jul 19, 2023, 7:55 PM
metamask shows this when it knows the tx will fail.
I click "proceed anyway", sign the tx, and then it throws an error when it reverts
I click "proceed anyway", sign the tx, and then it throws an error when it reverts
Jul 19, 2023, 7:55 PM
yes this is metamask
I am refering to local wallet usage
Jul 19, 2023, 7:56 PM
then it would send the tx automatically like you said, but I'm pretty sure it will also throw after it reverts
frontend/backend viem should be identical except the metamask. but that is separate
Maybe you didn't await the promise, so the script ends before it resolved.?. but i'm just guessing here
Jul 19, 2023, 8:00 PM
are you talking with me?
Jul 19, 2023, 8:03 PM
yaya
Jul 19, 2023, 8:03 PM
mm nope
that wasn't the case
it just failed and returned the tx hash
Jul 19, 2023, 8:04 PM
hmm i see now it's metamask that's throwing the error. So it's probably different depending on your RPC provider
and with simulateContract it throws without Metamask. ok got it
Jul 19, 2023, 8:09 PM
metamask and remix is too buggy nowadays
Jul 19, 2023, 10:48 PM