viem 0.0.1-alpha.21 → 0.0.1-alpha.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/dist/{chain-32f56cfa.d.ts → chain-4b39613a.d.ts} +2 -2
  2. package/dist/{chain-f12cdc7f.d.ts → chain-aa4898d0.d.ts} +1 -1
  3. package/dist/chains.d.ts +3 -3
  4. package/dist/chains.js +46 -46
  5. package/dist/chains.mjs +1 -1
  6. package/dist/{chunk-EC3NUIJE.js → chunk-7Y5QVLX7.js} +13 -13
  7. package/dist/{chunk-EC3NUIJE.js.map → chunk-7Y5QVLX7.js.map} +1 -1
  8. package/dist/{chunk-KEHGSYDO.js → chunk-BV5NTHUX.js} +14 -13
  9. package/dist/chunk-BV5NTHUX.js.map +1 -0
  10. package/dist/{chunk-46BO7YAQ.mjs → chunk-EGVXCZNJ.mjs} +4 -3
  11. package/dist/chunk-EGVXCZNJ.mjs.map +1 -0
  12. package/dist/{chunk-57ZOFERP.mjs → chunk-GX2KDAM3.mjs} +2 -2
  13. package/dist/{chunk-57ZOFERP.mjs.map → chunk-GX2KDAM3.mjs.map} +0 -0
  14. package/dist/{chunk-W7BWWAC4.js → chunk-NW6724MI.js} +14 -14
  15. package/dist/{chunk-W7BWWAC4.js.map → chunk-NW6724MI.js.map} +0 -0
  16. package/dist/{chunk-DGO77E2H.mjs → chunk-RJLUZTJS.mjs} +86 -3
  17. package/dist/chunk-RJLUZTJS.mjs.map +1 -0
  18. package/dist/{chunk-O2GYLJVD.js → chunk-SSPRUPGN.js} +405 -165
  19. package/dist/chunk-SSPRUPGN.js.map +1 -0
  20. package/dist/{chunk-DSPMAIDO.mjs → chunk-TXHOG6KU.mjs} +2 -2
  21. package/dist/{chunk-DSPMAIDO.mjs.map → chunk-TXHOG6KU.mjs.map} +1 -1
  22. package/dist/{chunk-62VTYU2V.mjs → chunk-XBUH66KN.mjs} +406 -166
  23. package/dist/chunk-XBUH66KN.mjs.map +1 -0
  24. package/dist/{chunk-KZMJR27B.js → chunk-ZKYGWITF.js} +147 -64
  25. package/dist/chunk-ZKYGWITF.js.map +1 -0
  26. package/dist/clients/index.d.ts +7 -7
  27. package/dist/clients/index.js +3 -3
  28. package/dist/clients/index.mjs +2 -2
  29. package/dist/{contract-9af4608b.d.ts → contract-4c3a37b3.d.ts} +14 -3
  30. package/dist/{createClient-5d316c7e.d.ts → createClient-55a04188.d.ts} +2 -2
  31. package/dist/{createPublicClient-9d2b42e1.d.ts → createPublicClient-3b27b282.d.ts} +3 -3
  32. package/dist/{createTestClient-79498dab.d.ts → createTestClient-93f9eac6.d.ts} +3 -3
  33. package/dist/{createWalletClient-f69a5230.d.ts → createWalletClient-c10df94d.d.ts} +3 -3
  34. package/dist/{eip1193-6c485d63.d.ts → eip1193-4c24765a.d.ts} +1 -1
  35. package/dist/ens.d.ts +1 -0
  36. package/dist/ens.js +11 -0
  37. package/dist/ens.js.map +1 -0
  38. package/dist/ens.mjs +11 -0
  39. package/dist/ens.mjs.map +1 -0
  40. package/dist/index.d.ts +174 -113
  41. package/dist/index.js +16 -6
  42. package/dist/index.mjs +15 -5
  43. package/dist/normalize-ef9240c0.d.ts +33 -0
  44. package/dist/{parseGwei-4308ad80.d.ts → parseGwei-3411cf2d.d.ts} +101 -37
  45. package/dist/public.d.ts +9 -9
  46. package/dist/public.js +4 -4
  47. package/dist/public.mjs +3 -3
  48. package/dist/{sendTransaction-1c8290a9.d.ts → sendTransaction-f17a2389.d.ts} +3 -3
  49. package/dist/{stopImpersonatingAccount-7781842a.d.ts → stopImpersonatingAccount-afb26486.d.ts} +2 -2
  50. package/dist/test.d.ts +5 -5
  51. package/dist/test.js +3 -3
  52. package/dist/test.mjs +2 -2
  53. package/dist/{transactionRequest-341b6ed2.d.ts → transactionRequest-93e9f001.d.ts} +2 -2
  54. package/dist/utils/index.d.ts +14 -16
  55. package/dist/utils/index.js +8 -2
  56. package/dist/utils/index.mjs +7 -1
  57. package/dist/wallet.d.ts +7 -7
  58. package/dist/wallet.js +3 -3
  59. package/dist/wallet.mjs +2 -2
  60. package/dist/{watchAsset-afaad3c7.d.ts → watchAsset-efd3dd05.d.ts} +3 -3
  61. package/dist/{watchPendingTransactions-3b722547.d.ts → watchPendingTransactions-57df1a13.d.ts} +17 -27
  62. package/dist/{webSocket-b180e679.d.ts → webSocket-d2e7bd0e.d.ts} +2 -2
  63. package/dist/window.d.ts +2 -2
  64. package/package.json +8 -2
  65. package/src/_test/abis.ts +7 -0
  66. package/src/_test/bench.ts +4 -4
  67. package/src/_test/constants.ts +4 -3
  68. package/src/_test/index.ts +4 -2
  69. package/src/_test/utils.ts +39 -1
  70. package/src/actions/index.test.ts +1 -0
  71. package/src/actions/index.ts +2 -0
  72. package/src/actions/public/call.bench.ts +5 -5
  73. package/src/actions/public/deployContract.ts +4 -4
  74. package/src/actions/public/estimateGas.bench.ts +6 -6
  75. package/src/actions/public/getBlock.bench.ts +5 -5
  76. package/src/actions/public/getBlockNumber.bench.ts +5 -5
  77. package/src/actions/public/getFilterChanges.test.ts +9 -9
  78. package/src/actions/public/getFilterLogs.test.ts +7 -7
  79. package/src/actions/public/getGasPrice.bench.ts +1 -10
  80. package/src/actions/public/getLogs.test.ts +7 -7
  81. package/src/actions/public/getTransaction.bench.ts +5 -5
  82. package/src/actions/public/getTransactionReceipt.bench.ts +5 -5
  83. package/src/actions/public/index.test.ts +1 -0
  84. package/src/actions/public/index.ts +3 -0
  85. package/src/actions/public/multicall.test.ts +452 -0
  86. package/src/actions/public/multicall.ts +103 -0
  87. package/src/actions/public/readContract.test.ts +226 -26
  88. package/src/actions/public/readContract.ts +13 -27
  89. package/src/actions/public/simulateContract.bench.ts +10 -0
  90. package/src/actions/public/simulateContract.test.ts +209 -37
  91. package/src/actions/public/simulateContract.ts +17 -21
  92. package/src/actions/public/watchContractEvent.test.ts +61 -57
  93. package/src/actions/public/watchEvent.test.ts +42 -37
  94. package/src/actions/test/impersonateAccount.test.ts +4 -6
  95. package/src/actions/test/sendUnsignedTransaction.test.ts +2 -2
  96. package/src/actions/test/stopImpersonatingAccount.test.ts +5 -7
  97. package/src/actions/wallet/signMessage.test.ts +0 -1
  98. package/src/actions/wallet/switchChain.test.ts +1 -2
  99. package/src/actions/wallet/watchAsset.test.ts +1 -2
  100. package/src/actions/wallet/writeContract.test.ts +37 -7
  101. package/src/actions/wallet/writeContract.ts +5 -14
  102. package/src/clients/transports/fallback.test.ts +34 -0
  103. package/src/clients/transports/fallback.ts +3 -1
  104. package/src/clients/transports/http.test.ts +0 -1
  105. package/src/clients/transports/webSocket.test.ts +0 -1
  106. package/src/constants/abis.test.ts +53 -0
  107. package/src/constants/abis.ts +44 -0
  108. package/src/constants/index.test.ts +14 -0
  109. package/src/constants/index.ts +3 -0
  110. package/src/constants/solidity.test.ts +41 -0
  111. package/src/constants/solidity.ts +35 -0
  112. package/src/ens.ts +5 -0
  113. package/src/errors/abi.test.ts +0 -2
  114. package/src/errors/base.test.ts +44 -2
  115. package/src/errors/base.ts +12 -12
  116. package/src/errors/block.test.ts +6 -6
  117. package/src/errors/contract.test.ts +233 -0
  118. package/src/errors/contract.ts +133 -80
  119. package/src/errors/index.ts +4 -2
  120. package/src/errors/request.test.ts +3 -4
  121. package/src/errors/request.ts +17 -17
  122. package/src/errors/rpc.test.ts +1 -2
  123. package/src/errors/transaction.test.ts +12 -12
  124. package/src/errors/transport.test.ts +0 -1
  125. package/src/index.test.ts +47 -0
  126. package/src/index.ts +10 -0
  127. package/src/types/contract.ts +55 -4
  128. package/src/types/index.ts +5 -0
  129. package/src/types/multicall.ts +82 -0
  130. package/src/utils/abi/decodeAbi.test.ts +1 -2
  131. package/src/utils/abi/decodeAbi.ts +11 -7
  132. package/src/utils/abi/decodeDeployData.test.ts +7 -15
  133. package/src/utils/abi/decodeDeployData.ts +10 -7
  134. package/src/utils/abi/decodeErrorResult.test.ts +103 -3
  135. package/src/utils/abi/decodeErrorResult.ts +30 -13
  136. package/src/utils/abi/decodeFunctionData.test.ts +0 -1
  137. package/src/utils/abi/decodeFunctionResult.test.ts +80 -9
  138. package/src/utils/abi/decodeFunctionResult.ts +15 -11
  139. package/src/utils/abi/encodeAbi.test.ts +3 -4
  140. package/src/utils/abi/encodeAbi.ts +19 -10
  141. package/src/utils/abi/encodeDeployData.test.ts +6 -13
  142. package/src/utils/abi/encodeDeployData.ts +10 -7
  143. package/src/utils/abi/encodeErrorResult.test.ts +2 -7
  144. package/src/utils/abi/encodeErrorResult.ts +18 -11
  145. package/src/utils/abi/encodeEventTopics.test.ts +11 -14
  146. package/src/utils/abi/encodeEventTopics.ts +15 -9
  147. package/src/utils/abi/encodeFunctionData.test.ts +5 -7
  148. package/src/utils/abi/encodeFunctionData.ts +16 -9
  149. package/src/utils/abi/encodeFunctionResult.test.ts +10 -15
  150. package/src/utils/abi/encodeFunctionResult.ts +9 -7
  151. package/src/utils/abi/getAbiItem.test.ts +547 -0
  152. package/src/utils/abi/getAbiItem.ts +93 -3
  153. package/src/utils/abi/index.ts +5 -1
  154. package/src/utils/address/getAddress.test.ts +6 -6
  155. package/src/utils/contract/getContractError.test.ts +247 -62
  156. package/src/utils/contract/getContractError.ts +30 -38
  157. package/src/utils/data/pad.bench.ts +0 -9
  158. package/src/utils/data/trim.bench.ts +0 -16
  159. package/src/utils/encoding/encodeBytes.bench.ts +0 -12
  160. package/src/utils/encoding/encodeHex.bench.ts +0 -11
  161. package/src/utils/ens/index.test.ts +13 -0
  162. package/src/utils/ens/index.ts +5 -0
  163. package/src/utils/ens/labelhash.test.ts +55 -0
  164. package/src/utils/ens/labelhash.ts +16 -0
  165. package/src/utils/ens/namehash.test.ts +65 -0
  166. package/src/utils/ens/namehash.ts +28 -0
  167. package/src/utils/ens/normalize.bench.ts +14 -0
  168. package/src/utils/ens/normalize.test.ts +35 -0
  169. package/src/utils/ens/normalize.ts +14 -0
  170. package/src/utils/hash/keccak256.ts +3 -5
  171. package/src/utils/index.test.ts +3 -0
  172. package/src/utils/index.ts +4 -0
  173. package/src/utils/rpc.test.ts +3 -6
  174. package/src/utils/unit/formatUnit.bench.ts +0 -5
  175. package/src/utils/unit/parseUnit.bench.ts +0 -5
  176. package/dist/chunk-46BO7YAQ.mjs.map +0 -1
  177. package/dist/chunk-62VTYU2V.mjs.map +0 -1
  178. package/dist/chunk-DGO77E2H.mjs.map +0 -1
  179. package/dist/chunk-KEHGSYDO.js.map +0 -1
  180. package/dist/chunk-KZMJR27B.js.map +0 -1
  181. package/dist/chunk-O2GYLJVD.js.map +0 -1
@@ -17,6 +17,13 @@ test('BaseError', () => {
17
17
  Details: details
18
18
  Version: viem@1.0.2]
19
19
  `)
20
+
21
+ expect(new BaseError('', { details: 'details' })).toMatchInlineSnapshot(`
22
+ [ViemError: An error occurred.
23
+
24
+ Details: details
25
+ Version: viem@1.0.2]
26
+ `)
20
27
  })
21
28
 
22
29
  test('BaseError (w/ docsPath)', () => {
@@ -29,6 +36,43 @@ test('BaseError (w/ docsPath)', () => {
29
36
  [ViemError: An error occurred.
30
37
 
31
38
  Docs: https://viem.sh/lol
39
+ Details: details
40
+ Version: viem@1.0.2]
41
+ `)
42
+ expect(
43
+ new BaseError('An error occurred.', {
44
+ cause: new BaseError('error', { docsPath: '/docs' }),
45
+ }),
46
+ ).toMatchInlineSnapshot(`
47
+ [ViemError: An error occurred.
48
+
49
+ Docs: https://viem.sh/docs
50
+ Version: viem@1.0.2]
51
+ `)
52
+ expect(
53
+ new BaseError('An error occurred.', {
54
+ cause: new BaseError('error'),
55
+ docsPath: '/lol',
56
+ }),
57
+ ).toMatchInlineSnapshot(`
58
+ [ViemError: An error occurred.
59
+
60
+ Docs: https://viem.sh/lol
61
+ Version: viem@1.0.2]
62
+ `)
63
+ })
64
+
65
+ test('BaseError (w/ metaMessages)', () => {
66
+ expect(
67
+ new BaseError('An error occurred.', {
68
+ details: 'details',
69
+ metaMessages: ['Reason: idk', 'Cause: lol'],
70
+ }),
71
+ ).toMatchInlineSnapshot(`
72
+ [ViemError: An error occurred.
73
+
74
+ Reason: idk
75
+ Cause: lol
32
76
 
33
77
  Details: details
34
78
  Version: viem@1.0.2]
@@ -48,7 +92,6 @@ test('inherited BaseError', () => {
48
92
  [ViemError: An internal error occurred.
49
93
 
50
94
  Docs: https://viem.sh/lol
51
-
52
95
  Details: details
53
96
  Version: viem@1.0.2]
54
97
  `)
@@ -65,7 +108,6 @@ test('inherited Error', () => {
65
108
  [ViemError: An internal error occurred.
66
109
 
67
110
  Docs: https://viem.sh/lol
68
-
69
111
  Details: details
70
112
  Version: viem@1.0.2]
71
113
  `)
@@ -1,11 +1,13 @@
1
1
  // @ts-ignore
2
2
  import pkg from '../../package.json'
3
- import { stringify } from '../utils/stringify'
4
3
 
5
4
  /* c8 ignore next */
6
5
  const version = process.env.TEST ? '1.0.2' : pkg.version
7
6
 
8
- type BaseErrorArgs = { docsPath?: string } & (
7
+ type BaseErrorArgs = {
8
+ docsPath?: string
9
+ metaMessages?: string[]
10
+ } & (
9
11
  | {
10
12
  cause?: never
11
13
  details?: string
@@ -17,13 +19,14 @@ type BaseErrorArgs = { docsPath?: string } & (
17
19
  )
18
20
 
19
21
  export class BaseError extends Error {
20
- humanMessage: string
21
22
  details: string
22
23
  docsPath?: string
24
+ metaMessages?: string[]
25
+ shortMessage: string
23
26
 
24
27
  name = 'ViemError'
25
28
 
26
- constructor(humanMessage: string, args: BaseErrorArgs = {}) {
29
+ constructor(shortMessage: string, args: BaseErrorArgs = {}) {
27
30
  const details =
28
31
  args.cause instanceof BaseError
29
32
  ? args.cause.details
@@ -35,16 +38,12 @@ export class BaseError extends Error {
35
38
  ? args.cause.docsPath || args.docsPath
36
39
  : args.docsPath
37
40
  const message = [
38
- humanMessage,
39
- ...(docsPath ? ['', `Docs: https://viem.sh${docsPath}`] : []),
41
+ shortMessage || 'An error occurred.',
40
42
  '',
43
+ ...(args.metaMessages ? [...args.metaMessages, ''] : []),
44
+ ...(docsPath ? [`Docs: https://viem.sh${docsPath}`] : []),
41
45
  ...(details ? [`Details: ${details}`] : []),
42
46
  `Version: viem@${version}`,
43
- ...(args.cause &&
44
- !(args.cause instanceof BaseError) &&
45
- Object.keys(args.cause).length > 0
46
- ? [`Internal Error: ${stringify(args.cause)}`]
47
- : []),
48
47
  ].join('\n')
49
48
 
50
49
  super(message)
@@ -52,6 +51,7 @@ export class BaseError extends Error {
52
51
  if (args.cause) this.cause = args.cause
53
52
  this.details = details
54
53
  this.docsPath = docsPath
55
- this.humanMessage = humanMessage
54
+ this.metaMessages = args.metaMessages
55
+ this.shortMessage = shortMessage
56
56
  }
57
57
  }
@@ -5,17 +5,17 @@ test('BlockNotFoundError', () => {
5
5
  expect(
6
6
  new BlockNotFoundError({ blockNumber: 69420n }),
7
7
  ).toMatchInlineSnapshot(`
8
- [BlockNotFoundError: Block at number "69420" could not be found.
8
+ [BlockNotFoundError: Block at number "69420" could not be found.
9
9
 
10
- Version: viem@1.0.2]
11
- `)
10
+ Version: viem@1.0.2]
11
+ `)
12
12
  expect(
13
13
  new BlockNotFoundError({ blockHash: '0x69420' }),
14
14
  ).toMatchInlineSnapshot(`
15
- [BlockNotFoundError: Block at hash "0x69420" could not be found.
15
+ [BlockNotFoundError: Block at hash "0x69420" could not be found.
16
16
 
17
- Version: viem@1.0.2]
18
- `)
17
+ Version: viem@1.0.2]
18
+ `)
19
19
  expect(new BlockNotFoundError({})).toMatchInlineSnapshot(`
20
20
  [BlockNotFoundError: Block could not be found.
21
21
 
@@ -0,0 +1,233 @@
1
+ import { describe, expect, test } from 'vitest'
2
+ import { baycContractConfig } from '../_test/abis'
3
+ import { errorsExampleABI } from '../_test/generated'
4
+ import { BaseError } from './base'
5
+ import {
6
+ ContractFunctionExecutionError,
7
+ ContractFunctionRevertedError,
8
+ RawContractError,
9
+ } from './contract'
10
+
11
+ describe('ContractFunctionExecutionError', () => {
12
+ test('default', () => {
13
+ expect(
14
+ new ContractFunctionExecutionError(new BaseError('Internal error.'), {
15
+ abi: baycContractConfig.abi,
16
+ functionName: 'totalSupply',
17
+ }),
18
+ ).toMatchInlineSnapshot(`
19
+ [ContractFunctionExecutionError: Internal error.
20
+
21
+ Function: totalSupply()
22
+
23
+ Version: viem@1.0.2]
24
+ `)
25
+ })
26
+
27
+ test('args: contractAddress', () => {
28
+ expect(
29
+ new ContractFunctionExecutionError(new BaseError('Internal error.'), {
30
+ abi: baycContractConfig.abi,
31
+ functionName: 'totalSupply',
32
+ contractAddress: '0x0000000000000000000000000000000000000000',
33
+ }),
34
+ ).toMatchInlineSnapshot(`
35
+ [ContractFunctionExecutionError: Internal error.
36
+
37
+ Contract: 0x0000000000000000000000000000000000000000
38
+ Function: totalSupply()
39
+
40
+ Version: viem@1.0.2]
41
+ `)
42
+ })
43
+
44
+ test('args: args', () => {
45
+ expect(
46
+ new ContractFunctionExecutionError(new BaseError('Internal error.'), {
47
+ abi: baycContractConfig.abi,
48
+ functionName: 'mintApe',
49
+ args: [1n],
50
+ contractAddress: '0x0000000000000000000000000000000000000000',
51
+ }),
52
+ ).toMatchInlineSnapshot(`
53
+ [ContractFunctionExecutionError: Internal error.
54
+
55
+ Contract: 0x0000000000000000000000000000000000000000
56
+ Function: mintApe(uint256 numberOfTokens)
57
+ Arguments: (1)
58
+
59
+ Version: viem@1.0.2]
60
+ `)
61
+ })
62
+
63
+ test('args: docsPath', () => {
64
+ expect(
65
+ new ContractFunctionExecutionError(new BaseError('Internal error.'), {
66
+ abi: baycContractConfig.abi,
67
+ functionName: 'mintApe',
68
+ args: [1n],
69
+ contractAddress: '0x0000000000000000000000000000000000000000',
70
+ docsPath: '/docs',
71
+ }),
72
+ ).toMatchInlineSnapshot(`
73
+ [ContractFunctionExecutionError: Internal error.
74
+
75
+ Contract: 0x0000000000000000000000000000000000000000
76
+ Function: mintApe(uint256 numberOfTokens)
77
+ Arguments: (1)
78
+
79
+ Docs: https://viem.sh/docs
80
+ Version: viem@1.0.2]
81
+ `)
82
+ })
83
+
84
+ test('args: sender', () => {
85
+ expect(
86
+ new ContractFunctionExecutionError(new BaseError('Internal error.'), {
87
+ abi: baycContractConfig.abi,
88
+ functionName: 'mintApe',
89
+ args: [1n],
90
+ contractAddress: '0x0000000000000000000000000000000000000000',
91
+ sender: '0x0000000000000000000000000000000000000000',
92
+ }),
93
+ ).toMatchInlineSnapshot(`
94
+ [ContractFunctionExecutionError: Internal error.
95
+
96
+ Contract: 0x0000000000000000000000000000000000000000
97
+ Function: mintApe(uint256 numberOfTokens)
98
+ Arguments: (1)
99
+ Sender: 0x0000000000000000000000000000000000000000
100
+
101
+ Version: viem@1.0.2]
102
+ `)
103
+ })
104
+
105
+ test('cause: metaMessages', () => {
106
+ expect(
107
+ new ContractFunctionExecutionError(
108
+ new BaseError('Internal error.', { metaMessages: ['foo', 'bar'] }),
109
+ {
110
+ abi: baycContractConfig.abi,
111
+ functionName: 'totalSupply',
112
+ contractAddress: '0x0000000000000000000000000000000000000000',
113
+ },
114
+ ),
115
+ ).toMatchInlineSnapshot(`
116
+ [ContractFunctionExecutionError: Internal error.
117
+
118
+ foo
119
+ bar
120
+
121
+ Contract: 0x0000000000000000000000000000000000000000
122
+ Function: totalSupply()
123
+
124
+ Version: viem@1.0.2]
125
+ `)
126
+ })
127
+
128
+ test('no message', () => {
129
+ expect(
130
+ new ContractFunctionExecutionError(new BaseError(''), {
131
+ abi: baycContractConfig.abi,
132
+ functionName: 'foo',
133
+ }),
134
+ ).toMatchInlineSnapshot(`
135
+ [ContractFunctionExecutionError: An unknown error occurred while executing the contract function "foo".
136
+
137
+
138
+ Version: viem@1.0.2]
139
+ `)
140
+ })
141
+
142
+ test('function does not exist', () => {
143
+ expect(
144
+ new ContractFunctionExecutionError(new BaseError('Internal error.'), {
145
+ abi: baycContractConfig.abi,
146
+ functionName: 'foo',
147
+ }),
148
+ ).toMatchInlineSnapshot(`
149
+ [ContractFunctionExecutionError: Internal error.
150
+
151
+
152
+ Version: viem@1.0.2]
153
+ `)
154
+ })
155
+ })
156
+
157
+ describe('ContractFunctionRevertedError', () => {
158
+ test('default', () => {
159
+ expect(
160
+ new ContractFunctionRevertedError({
161
+ abi: errorsExampleABI,
162
+ message: 'oh no',
163
+ functionName: 'totalSupply',
164
+ }),
165
+ ).toMatchInlineSnapshot(`
166
+ [ContractFunctionRevertedError: The contract function "totalSupply" reverted with the following reason:
167
+ oh no
168
+
169
+ Version: viem@1.0.2]
170
+ `)
171
+ })
172
+
173
+ test('data: Error(string)', () => {
174
+ expect(
175
+ new ContractFunctionRevertedError({
176
+ abi: errorsExampleABI,
177
+ data: '0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000022456e756d657261626c655365743a20696e646578206f7574206f6620626f756e6473000000000000000000000000000000000000000000000000000000000000',
178
+ functionName: 'totalSupply',
179
+ }),
180
+ ).toMatchInlineSnapshot(`
181
+ [ContractFunctionRevertedError: The contract function "totalSupply" reverted with the following reason:
182
+ EnumerableSet: index out of bounds
183
+
184
+ Version: viem@1.0.2]
185
+ `)
186
+ })
187
+
188
+ test('data: Panic(uint256)', () => {
189
+ expect(
190
+ new ContractFunctionRevertedError({
191
+ abi: errorsExampleABI,
192
+ data: '0x4e487b710000000000000000000000000000000000000000000000000000000000000001',
193
+ functionName: 'totalSupply',
194
+ }),
195
+ ).toMatchInlineSnapshot(`
196
+ [ContractFunctionRevertedError: The contract function "totalSupply" reverted with the following reason:
197
+ An \`assert\` condition failed.
198
+
199
+ Version: viem@1.0.2]
200
+ `)
201
+ })
202
+
203
+ test('data: custom error', () => {
204
+ expect(
205
+ new ContractFunctionRevertedError({
206
+ abi: errorsExampleABI,
207
+ data: '0xdb731cf4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000000000066275676765720000000000000000000000000000000000000000000000000000',
208
+ functionName: 'customComplexError',
209
+ }),
210
+ ).toMatchInlineSnapshot(`
211
+ [ContractFunctionRevertedError: The contract function "customComplexError" reverted.
212
+
213
+ Error: ComplexError((address sender, uint256 bar), string message, uint256 number)
214
+ Arguments: ({"sender":"0x0000000000000000000000000000000000000000","bar":"69"}, bugger, 69)
215
+
216
+ Version: viem@1.0.2]
217
+ `)
218
+ })
219
+
220
+ test('data: zero data', () => {
221
+ expect(
222
+ new ContractFunctionRevertedError({
223
+ abi: errorsExampleABI,
224
+ data: '0x',
225
+ functionName: 'customComplexError',
226
+ }),
227
+ ).toMatchInlineSnapshot(`
228
+ [ContractFunctionRevertedError: The contract function "customComplexError" reverted.
229
+
230
+ Version: viem@1.0.2]
231
+ `)
232
+ })
233
+ })
@@ -1,125 +1,178 @@
1
1
  import { Abi } from 'abitype'
2
- import { Address } from '../types'
2
+ import { panicReasons } from '../constants'
3
+ import { Address, Hex } from '../types'
4
+ import {
5
+ DecodeErrorResultResponse,
6
+ decodeErrorResult,
7
+ getAbiItem,
8
+ formatAbiItemWithArgs,
9
+ formatAbiItem,
10
+ } from '../utils'
3
11
  import { BaseError } from './base'
4
12
 
5
- export class ContractMethodExecutionError extends BaseError {
6
- abi?: Abi
13
+ export class ContractFunctionExecutionError extends BaseError {
14
+ abi: Abi
7
15
  args?: unknown[]
16
+ cause: BaseError
8
17
  contractAddress?: Address
9
18
  formattedArgs?: string
10
- functionName?: string
11
- reason?: string
19
+ functionName: string
12
20
  sender?: Address
13
21
 
14
- name = 'ContractMethodExecutionError'
22
+ name = 'ContractFunctionExecutionError'
15
23
 
16
24
  constructor(
17
- message?: string,
25
+ cause: BaseError,
18
26
  {
19
27
  abi,
20
28
  args,
21
- cause,
22
29
  contractAddress,
23
- formattedArgs,
30
+ docsPath,
24
31
  functionName,
25
- functionWithParams,
26
32
  sender,
27
33
  }: {
28
- abi?: Abi
34
+ abi: Abi
29
35
  args?: any
30
- cause?: Error
31
36
  contractAddress?: Address
32
- formattedArgs?: string
33
- functionName?: string
34
- functionWithParams?: string
37
+ docsPath?: string
38
+ functionName: string
35
39
  sender?: Address
36
- } = {},
40
+ },
37
41
  ) {
42
+ const abiItem = getAbiItem({ abi, args, name: functionName })
43
+ const formattedArgs = abiItem
44
+ ? formatAbiItemWithArgs({
45
+ abiItem,
46
+ args,
47
+ includeFunctionName: false,
48
+ includeName: false,
49
+ })
50
+ : undefined
51
+ const functionWithParams = abiItem
52
+ ? formatAbiItem(abiItem, { includeName: true })
53
+ : undefined
54
+
38
55
  super(
39
- [
40
- message,
41
- ' ',
42
- sender && `Sender: ${sender}`,
43
- contractAddress &&
44
- `Contract: ${
45
- /* c8 ignore start */
46
- process.env.TEST
47
- ? '0x0000000000000000000000000000000000000000'
48
- : contractAddress
49
- /* c8 ignore end */
50
- }`,
51
- functionWithParams && `Function: ${functionWithParams}`,
52
- formattedArgs &&
53
- `Arguments: ${[...Array(functionName?.length ?? 0).keys()]
54
- .map(() => ' ')
55
- .join('')}${formattedArgs}`,
56
- ]
57
- .filter(Boolean)
58
- .join('\n'),
56
+ cause.shortMessage ||
57
+ `An unknown error occurred while executing the contract function "${functionName}".`,
59
58
  {
60
59
  cause,
60
+ docsPath,
61
+ metaMessages: [
62
+ ...(cause.metaMessages ? [...cause.metaMessages, ' '] : []),
63
+ contractAddress &&
64
+ `Contract: ${
65
+ /* c8 ignore start */
66
+ process.env.TEST
67
+ ? '0x0000000000000000000000000000000000000000'
68
+ : contractAddress
69
+ /* c8 ignore end */
70
+ }`,
71
+ functionWithParams && `Function: ${functionWithParams}`,
72
+ formattedArgs &&
73
+ formattedArgs !== '()' &&
74
+ `Arguments: ${[...Array(functionName?.length ?? 0).keys()]
75
+ .map(() => ' ')
76
+ .join('')}${formattedArgs}`,
77
+ sender && `Sender: ${sender}`,
78
+ ].filter(Boolean) as string[],
61
79
  },
62
80
  )
63
- if (message) this.reason = message
64
81
  this.abi = abi
65
82
  this.args = args
83
+ this.cause = cause
66
84
  this.contractAddress = contractAddress
67
85
  this.functionName = functionName
68
86
  this.sender = sender
69
87
  }
70
88
  }
71
89
 
72
- export class ContractMethodZeroDataError extends BaseError {
73
- abi?: Abi
74
- args?: unknown[]
75
- contractAddress?: Address
76
- functionName?: string
77
- functionWithParams?: string
90
+ export class ContractFunctionRevertedError extends BaseError {
91
+ name = 'ContractFunctionRevertedError'
78
92
 
79
- name = 'ContractMethodZeroDataError'
93
+ data?: DecodeErrorResultResponse
94
+ reason?: string
80
95
 
81
96
  constructor({
82
97
  abi,
83
- args,
84
- cause,
85
- contractAddress,
98
+ data,
86
99
  functionName,
87
- functionWithParams,
88
- }: {
89
- abi?: Abi
90
- args?: any
91
- cause?: Error
92
- contractAddress?: Address
93
- functionName?: string
94
- functionWithParams?: string
95
- } = {}) {
100
+ message,
101
+ }: { abi: Abi; data?: Hex; functionName: string; message?: string }) {
102
+ let decodedData: DecodeErrorResultResponse | undefined = undefined
103
+ let metaMessages
104
+ let reason
105
+ if (data && data !== '0x') {
106
+ decodedData = decodeErrorResult({ abi, data })
107
+ const { abiItem, errorName, args: errorArgs } = decodedData
108
+ if (errorName === 'Error') {
109
+ reason = (errorArgs as [string])[0]
110
+ } else if (errorName === 'Panic') {
111
+ const [firstArg] = errorArgs as [number]
112
+ reason = panicReasons[firstArg as keyof typeof panicReasons]
113
+ } else if (errorArgs) {
114
+ const errorWithParams = abiItem
115
+ ? formatAbiItem(abiItem, { includeName: true })
116
+ : undefined
117
+ const formattedArgs = abiItem
118
+ ? formatAbiItemWithArgs({
119
+ abiItem,
120
+ args: errorArgs,
121
+ includeFunctionName: false,
122
+ includeName: false,
123
+ })
124
+ : undefined
125
+
126
+ metaMessages = [
127
+ errorWithParams ? `Error: ${errorWithParams}` : '',
128
+ formattedArgs && formattedArgs !== '()'
129
+ ? `Arguments: ${[...Array(errorName?.length ?? 0).keys()]
130
+ .map(() => ' ')
131
+ .join('')}${formattedArgs}`
132
+ : '',
133
+ ]
134
+ }
135
+ } else if (message) reason = message
136
+
96
137
  super(
97
- [
98
- `The contract method "${functionName}" returned no data ("0x"). This could be due to any of the following:`,
99
- `- The contract does not have the function "${functionName}",`,
100
- '- The parameters passed to the contract function may be invalid, or',
101
- '- The address is not a contract.',
102
- ' ',
103
- contractAddress &&
104
- `Contract: ${
105
- /* c8 ignore start */
106
- process.env.TEST
107
- ? '0x0000000000000000000000000000000000000000'
108
- : contractAddress
109
- /* c8 ignore end */
110
- }`,
111
- functionWithParams && `Function: ${functionWithParams}`,
112
- functionWithParams && ` > "0x"`,
113
- ]
114
- .filter(Boolean)
115
- .join('\n'),
138
+ reason
139
+ ? [
140
+ `The contract function "${functionName}" reverted with the following reason:`,
141
+ reason,
142
+ ].join('\n')
143
+ : `The contract function "${functionName}" reverted.`,
116
144
  {
117
- cause,
145
+ metaMessages,
118
146
  },
119
147
  )
120
- this.abi = abi
121
- this.args = args
122
- this.contractAddress = contractAddress
123
- this.functionName = functionName
148
+
149
+ this.reason = reason
150
+ this.data = decodedData
151
+ }
152
+ }
153
+
154
+ export class ContractFunctionZeroDataError extends BaseError {
155
+ name = 'ContractFunctionZeroDataError'
156
+ constructor({ functionName }: { functionName: string }) {
157
+ super(`The contract function "${functionName}" returned no data ("0x").`, {
158
+ metaMessages: [
159
+ 'This could be due to any of the following:',
160
+ `- The contract does not have the function "${functionName}",`,
161
+ '- The parameters passed to the contract function may be invalid, or',
162
+ '- The address is not a contract.',
163
+ ],
164
+ })
165
+ }
166
+ }
167
+
168
+ export class RawContractError extends BaseError {
169
+ code = 3
170
+ name = 'RawContractError'
171
+
172
+ data?: Hex
173
+
174
+ constructor({ data, message }: { data?: Hex; message?: string }) {
175
+ super(message || '')
176
+ this.data = data
124
177
  }
125
178
  }
@@ -25,8 +25,10 @@ export { BaseError } from './base'
25
25
  export { BlockNotFoundError } from './block'
26
26
 
27
27
  export {
28
- ContractMethodExecutionError,
29
- ContractMethodZeroDataError,
28
+ ContractFunctionExecutionError,
29
+ ContractFunctionRevertedError,
30
+ ContractFunctionZeroDataError,
31
+ RawContractError,
30
32
  } from './contract'
31
33
 
32
34
  export { SizeExceedsPaddingSizeError } from './data'
@@ -27,7 +27,7 @@ test('RequestError', () => {
27
27
  error: { code: 1337, message: 'error details' },
28
28
  }),
29
29
  {
30
- humanMessage: 'An internal error was received.',
30
+ shortMessage: 'An internal error was received.',
31
31
  },
32
32
  ),
33
33
  ).toMatchInlineSnapshot(`
@@ -46,7 +46,7 @@ test('RpcRequestError', () => {
46
46
  url: 'https://viem.sh',
47
47
  error: { code: 1337, message: 'error details' },
48
48
  }),
49
- { humanMessage: 'An internal error was received.' },
49
+ { shortMessage: 'An internal error was received.' },
50
50
  ),
51
51
  ).toMatchInlineSnapshot(`
52
52
  [RpcError: An internal error was received.
@@ -65,7 +65,7 @@ test('RpcRequestError', () => {
65
65
  error: { code: 1337, message: 'error details' },
66
66
  }),
67
67
  {
68
- humanMessage: 'An internal error was received.',
68
+ shortMessage: 'An internal error was received.',
69
69
  docsPath: '/lol',
70
70
  },
71
71
  ),
@@ -73,7 +73,6 @@ test('RpcRequestError', () => {
73
73
  [RpcError: An internal error was received.
74
74
 
75
75
  Docs: https://viem.sh/lol
76
-
77
76
  Details: error details
78
77
  Version: viem@1.0.2]
79
78
  `)