Skip to content

Commit 46dd252

Browse files
frolicjxom
andauthored
feat: improve writeContract error handling (#2624)
* parse writeContract errors * chore: tweaks * chore: format * chore: update snap --------- Co-authored-by: jxom <jakemoxey@gmail.com>
1 parent 5f350ec commit 46dd252

4 files changed

Lines changed: 287 additions & 22 deletions

File tree

.changeset/big-eagles-sing.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"viem": patch
3+
---
4+
5+
Improved `writeContract` error handling.

src/actions/wallet/writeContract.test.ts

Lines changed: 218 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import { describe, expect, test, vi } from 'vitest'
22

3-
import { BatchCallInvoker, Payable } from '~contracts/generated.js'
3+
import {
4+
BatchCallInvoker,
5+
ErrorsExample,
6+
Payable,
7+
} from '~contracts/generated.js'
48
import { wagmiContractConfig } from '~test/src/abis.js'
59
import { accounts } from '~test/src/constants.js'
6-
import { deploy, deployPayable } from '~test/src/utils.js'
10+
import { deploy, deployErrorExample, deployPayable } from '~test/src/utils.js'
711
import { anvilMainnet } from '../../../test/src/anvil.js'
812
import { privateKeyToAccount } from '../../accounts/privateKeyToAccount.js'
913
import { optimism } from '../../chains/index.js'
@@ -55,7 +59,7 @@ test('client chain mismatch', async () => {
5559
functionName: 'mint',
5660
}),
5761
).rejects.toThrowErrorMatchingInlineSnapshot(`
58-
[TransactionExecutionError: The current chain of the wallet (id: 1) does not match the target chain for the transaction (id: 10 – OP Mainnet).
62+
[ContractFunctionExecutionError: The current chain of the wallet (id: 1) does not match the target chain for the transaction (id: 10 – OP Mainnet).
5963
6064
Current Chain ID: 1
6165
Expected Chain ID: 10 – OP Mainnet
@@ -64,7 +68,13 @@ test('client chain mismatch', async () => {
6468
from: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
6569
to: 0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2
6670
data: 0x1249c58b
71+
72+
Contract Call:
73+
address: 0x0000000000000000000000000000000000000000
74+
function: mint()
75+
sender: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
6776
77+
Docs: https://viem.sh/docs/contract/writeContract
6878
Version: viem@x.y.z]
6979
`)
7080
})
@@ -81,14 +91,20 @@ test('no chain', async () => {
8191
functionName: 'mint',
8292
}),
8393
).rejects.toThrowErrorMatchingInlineSnapshot(`
84-
[TransactionExecutionError: No chain was provided to the request.
94+
[ContractFunctionExecutionError: No chain was provided to the request.
8595
Please provide a chain with the \`chain\` argument on the Action, or by supplying a \`chain\` to WalletClient.
8696
8797
Request Arguments:
8898
from: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
8999
to: 0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2
90100
data: 0x1249c58b
101+
102+
Contract Call:
103+
address: 0x0000000000000000000000000000000000000000
104+
function: mint()
105+
sender: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
91106
107+
Docs: https://viem.sh/docs/contract/writeContract
92108
Version: viem@x.y.z]
93109
`)
94110
})
@@ -118,7 +134,7 @@ describe('args: chain', () => {
118134
chain: optimism,
119135
}),
120136
).rejects.toThrowErrorMatchingInlineSnapshot(`
121-
[TransactionExecutionError: The current chain of the wallet (id: 1) does not match the target chain for the transaction (id: 10 – OP Mainnet).
137+
[ContractFunctionExecutionError: The current chain of the wallet (id: 1) does not match the target chain for the transaction (id: 10 – OP Mainnet).
122138
123139
Current Chain ID: 1
124140
Expected Chain ID: 10 – OP Mainnet
@@ -128,7 +144,13 @@ describe('args: chain', () => {
128144
from: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
129145
to: 0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2
130146
data: 0x1249c58b
147+
148+
Contract Call:
149+
address: 0x0000000000000000000000000000000000000000
150+
function: mint()
151+
sender: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
131152
153+
Docs: https://viem.sh/docs/contract/writeContract
132154
Version: viem@x.y.z]
133155
`)
134156
})
@@ -281,7 +303,10 @@ test('args: dataSuffix', async () => {
281303
dataSuffix: '0x12345678',
282304
})
283305
expect(spy).toHaveBeenCalledWith({
284-
account: accounts[0].address,
306+
account: {
307+
address: accounts[0].address,
308+
type: 'json-rpc',
309+
},
285310
data: '0x1249c58b12345678',
286311
to: wagmiContractConfig.address,
287312
})
@@ -381,7 +406,7 @@ test('w/ simulateContract (args chain mismatch)', async () => {
381406
await expect(() =>
382407
writeContract(client, request),
383408
).rejects.toThrowErrorMatchingInlineSnapshot(`
384-
[TransactionExecutionError: The current chain of the wallet (id: 1) does not match the target chain for the transaction (id: 10 – OP Mainnet).
409+
[ContractFunctionExecutionError: The current chain of the wallet (id: 1) does not match the target chain for the transaction (id: 10 – OP Mainnet).
385410
386411
Current Chain ID: 1
387412
Expected Chain ID: 10 – OP Mainnet
@@ -391,7 +416,13 @@ test('w/ simulateContract (args chain mismatch)', async () => {
391416
from: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
392417
to: 0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2
393418
data: 0x1249c58b
419+
420+
Contract Call:
421+
address: 0x0000000000000000000000000000000000000000
422+
function: mint()
423+
sender: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
394424
425+
Docs: https://viem.sh/docs/contract/writeContract
395426
Version: viem@x.y.z]
396427
`)
397428
})
@@ -410,7 +441,7 @@ test('w/ simulateContract (client chain mismatch)', async () => {
410441
await expect(() =>
411442
writeContract(client, request),
412443
).rejects.toThrowErrorMatchingInlineSnapshot(`
413-
[TransactionExecutionError: The current chain of the wallet (id: 1) does not match the target chain for the transaction (id: 10 – OP Mainnet).
444+
[ContractFunctionExecutionError: The current chain of the wallet (id: 1) does not match the target chain for the transaction (id: 10 – OP Mainnet).
414445
415446
Current Chain ID: 1
416447
Expected Chain ID: 10 – OP Mainnet
@@ -419,7 +450,186 @@ test('w/ simulateContract (client chain mismatch)', async () => {
419450
from: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
420451
to: 0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2
421452
data: 0x1249c58b
453+
454+
Contract Call:
455+
address: 0x0000000000000000000000000000000000000000
456+
function: mint()
457+
sender: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
422458
459+
Docs: https://viem.sh/docs/contract/writeContract
423460
Version: viem@x.y.z]
424461
`)
425462
})
463+
464+
describe('behavior: contract revert', () => {
465+
test('revert', async () => {
466+
const { contractAddress } = await deployErrorExample()
467+
468+
await expect(() =>
469+
writeContract(client, {
470+
abi: ErrorsExample.abi,
471+
address: contractAddress!,
472+
functionName: 'revertWrite',
473+
account: privateKeyToAccount(accounts[0].privateKey),
474+
}),
475+
).rejects.toMatchInlineSnapshot(`
476+
[ContractFunctionExecutionError: The contract function "revertWrite" reverted with the following reason:
477+
This is a revert message
478+
479+
Contract Call:
480+
address: 0x0000000000000000000000000000000000000000
481+
function: revertWrite()
482+
sender: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
483+
484+
Docs: https://viem.sh/docs/contract/writeContract
485+
Version: viem@x.y.z]
486+
`)
487+
})
488+
489+
test('assert', async () => {
490+
const { contractAddress } = await deployErrorExample()
491+
492+
await expect(() =>
493+
writeContract(client, {
494+
abi: ErrorsExample.abi,
495+
address: contractAddress!,
496+
functionName: 'assertWrite',
497+
account: privateKeyToAccount(accounts[0].privateKey),
498+
}),
499+
).rejects.toMatchInlineSnapshot(`
500+
[ContractFunctionExecutionError: The contract function "assertWrite" reverted with the following reason:
501+
An \`assert\` condition failed.
502+
503+
Contract Call:
504+
address: 0x0000000000000000000000000000000000000000
505+
function: assertWrite()
506+
sender: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
507+
508+
Docs: https://viem.sh/docs/contract/writeContract
509+
Version: viem@x.y.z]
510+
`)
511+
})
512+
513+
test('overflow', async () => {
514+
const { contractAddress } = await deployErrorExample()
515+
516+
await expect(() =>
517+
writeContract(client, {
518+
abi: ErrorsExample.abi,
519+
address: contractAddress!,
520+
functionName: 'overflowWrite',
521+
account: privateKeyToAccount(accounts[0].privateKey),
522+
}),
523+
).rejects.toMatchInlineSnapshot(`
524+
[ContractFunctionExecutionError: The contract function "overflowWrite" reverted with the following reason:
525+
Arithmetic operation resulted in underflow or overflow.
526+
527+
Contract Call:
528+
address: 0x0000000000000000000000000000000000000000
529+
function: overflowWrite()
530+
sender: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
531+
532+
Docs: https://viem.sh/docs/contract/writeContract
533+
Version: viem@x.y.z]
534+
`)
535+
})
536+
537+
test('divide by zero', async () => {
538+
const { contractAddress } = await deployErrorExample()
539+
540+
await expect(() =>
541+
writeContract(client, {
542+
abi: ErrorsExample.abi,
543+
address: contractAddress!,
544+
functionName: 'divideByZeroWrite',
545+
account: privateKeyToAccount(accounts[0].privateKey),
546+
}),
547+
).rejects.toMatchInlineSnapshot(`
548+
[ContractFunctionExecutionError: The contract function "divideByZeroWrite" reverted with the following reason:
549+
Division or modulo by zero (e.g. \`5 / 0\` or \`23 % 0\`).
550+
551+
Contract Call:
552+
address: 0x0000000000000000000000000000000000000000
553+
function: divideByZeroWrite()
554+
sender: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
555+
556+
Docs: https://viem.sh/docs/contract/writeContract
557+
Version: viem@x.y.z]
558+
`)
559+
})
560+
561+
test('require', async () => {
562+
const { contractAddress } = await deployErrorExample()
563+
564+
await expect(() =>
565+
writeContract(client, {
566+
abi: ErrorsExample.abi,
567+
address: contractAddress!,
568+
functionName: 'requireWrite',
569+
account: privateKeyToAccount(accounts[0].privateKey),
570+
}),
571+
).rejects.toMatchInlineSnapshot(`
572+
[ContractFunctionExecutionError: The contract function "requireWrite" reverted.
573+
574+
Contract Call:
575+
address: 0x0000000000000000000000000000000000000000
576+
function: requireWrite()
577+
sender: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
578+
579+
Docs: https://viem.sh/docs/contract/writeContract
580+
Version: viem@x.y.z]
581+
`)
582+
})
583+
584+
test('custom error: simple', async () => {
585+
const { contractAddress } = await deployErrorExample()
586+
587+
await expect(() =>
588+
writeContract(client, {
589+
abi: ErrorsExample.abi,
590+
address: contractAddress!,
591+
functionName: 'simpleCustomWrite',
592+
account: privateKeyToAccount(accounts[0].privateKey),
593+
}),
594+
).rejects.toMatchInlineSnapshot(`
595+
[ContractFunctionExecutionError: The contract function "simpleCustomWrite" reverted.
596+
597+
Error: SimpleError(string message)
598+
(bugger)
599+
600+
Contract Call:
601+
address: 0x0000000000000000000000000000000000000000
602+
function: simpleCustomWrite()
603+
sender: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
604+
605+
Docs: https://viem.sh/docs/contract/writeContract
606+
Version: viem@x.y.z]
607+
`)
608+
})
609+
610+
test('custom error: complex', async () => {
611+
const { contractAddress } = await deployErrorExample()
612+
613+
await expect(() =>
614+
writeContract(client, {
615+
abi: ErrorsExample.abi,
616+
address: contractAddress!,
617+
functionName: 'complexCustomWrite',
618+
account: privateKeyToAccount(accounts[0].privateKey),
619+
}),
620+
).rejects.toMatchInlineSnapshot(`
621+
[ContractFunctionExecutionError: The contract function "complexCustomWrite" reverted.
622+
623+
Error: ComplexError((address sender, uint256 bar), string message, uint256 number)
624+
({"sender":"0x0000000000000000000000000000000000000000","bar":"69"}, bugger, 69)
625+
626+
Contract Call:
627+
address: 0x0000000000000000000000000000000000000000
628+
function: complexCustomWrite()
629+
sender: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
630+
631+
Docs: https://viem.sh/docs/contract/writeContract
632+
Version: viem@x.y.z]
633+
`)
634+
})
635+
})

0 commit comments

Comments
 (0)