viem 0.0.1-alpha.16 → 0.0.1-alpha.18

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 (86) hide show
  1. package/dist/chains.d.ts +1 -1
  2. package/dist/chains.js +5 -5
  3. package/dist/chains.mjs +1 -1
  4. package/dist/{chunk-U7QDLGQL.mjs → chunk-3E5WSIQU.mjs} +2 -2
  5. package/dist/{chunk-U7QDLGQL.mjs.map → chunk-3E5WSIQU.mjs.map} +0 -0
  6. package/dist/{chunk-XJKOJIX3.js → chunk-3EXLRM3B.js} +12 -12
  7. package/dist/{chunk-XJKOJIX3.js.map → chunk-3EXLRM3B.js.map} +0 -0
  8. package/dist/{chunk-EWTLCB3N.js → chunk-6CXRXH25.js} +2 -2
  9. package/dist/{chunk-EWTLCB3N.js.map → chunk-6CXRXH25.js.map} +0 -0
  10. package/dist/{chunk-WTXKCAG7.js → chunk-A4HJ47I6.js} +144 -53
  11. package/dist/chunk-A4HJ47I6.js.map +1 -0
  12. package/dist/{chunk-4XREGFHD.js → chunk-BW2LPGYJ.js} +36 -13
  13. package/dist/chunk-BW2LPGYJ.js.map +1 -0
  14. package/dist/{chunk-KM6AFT2K.mjs → chunk-NSPSPOUF.mjs} +2 -2
  15. package/dist/{chunk-KM6AFT2K.mjs.map → chunk-NSPSPOUF.mjs.map} +0 -0
  16. package/dist/{chunk-B7A2CAHU.mjs → chunk-OGQGNULX.mjs} +98 -7
  17. package/dist/chunk-OGQGNULX.mjs.map +1 -0
  18. package/dist/{chunk-TSJ3OOJW.mjs → chunk-TO7QJO5X.mjs} +2 -2
  19. package/dist/{chunk-TSJ3OOJW.mjs.map → chunk-TO7QJO5X.mjs.map} +0 -0
  20. package/dist/{chunk-LQXQPPTU.js → chunk-XQZRYOPA.js} +14 -14
  21. package/dist/{chunk-LQXQPPTU.js.map → chunk-XQZRYOPA.js.map} +0 -0
  22. package/dist/{chunk-KCMYVU3Z.mjs → chunk-Y3PSHZGB.mjs} +26 -3
  23. package/dist/chunk-Y3PSHZGB.mjs.map +1 -0
  24. package/dist/clients/index.d.ts +7 -7
  25. package/dist/clients/index.js +3 -3
  26. package/dist/clients/index.mjs +2 -2
  27. package/dist/{createClient-cd948138.d.ts → createClient-aadeff37.d.ts} +1 -1
  28. package/dist/{createPublicClient-989a0556.d.ts → createPublicClient-88f35518.d.ts} +2 -2
  29. package/dist/{createTestClient-81507f58.d.ts → createTestClient-fbf66ec2.d.ts} +2 -2
  30. package/dist/{createWalletClient-43f801b9.d.ts → createWalletClient-b13dabd6.d.ts} +2 -2
  31. package/dist/{eip1193-4330b722.d.ts → eip1193-3a40c941.d.ts} +9 -6
  32. package/dist/index.d.ts +57 -17
  33. package/dist/index.js +12 -6
  34. package/dist/index.mjs +15 -9
  35. package/dist/{parseGwei-f2d23de6.d.ts → parseGwei-dbd12305.d.ts} +2 -2
  36. package/dist/public.d.ts +9 -9
  37. package/dist/public.js +4 -4
  38. package/dist/public.mjs +5 -5
  39. package/dist/{rpc-b77c5aee.d.ts → rpc-858670f1.d.ts} +12 -1
  40. package/dist/{sendTransaction-7a9d241a.d.ts → sendTransaction-bd109cd4.d.ts} +3 -3
  41. package/dist/{stopImpersonatingAccount-8113150e.d.ts → stopImpersonatingAccount-6603ebdd.d.ts} +2 -2
  42. package/dist/test.d.ts +5 -5
  43. package/dist/test.js +3 -3
  44. package/dist/test.mjs +2 -2
  45. package/dist/{transactionReceipt-5d332aab.d.ts → transactionReceipt-aed524b4.d.ts} +30 -4
  46. package/dist/{transactionRequest-327eb7c2.d.ts → transactionRequest-8e970b0e.d.ts} +1 -1
  47. package/dist/utils/index.d.ts +5 -5
  48. package/dist/utils/index.js +2 -2
  49. package/dist/utils/index.mjs +1 -1
  50. package/dist/wallet.d.ts +7 -7
  51. package/dist/wallet.js +3 -3
  52. package/dist/wallet.mjs +2 -2
  53. package/dist/{watchAsset-0088384c.d.ts → watchAsset-7ef25553.d.ts} +3 -3
  54. package/dist/{watchPendingTransactions-670a7ca3.d.ts → watchPendingTransactions-7cbbef80.d.ts} +26 -11
  55. package/dist/{webSocket-9a3b0b26.d.ts → webSocket-2a77cdb3.d.ts} +2 -2
  56. package/dist/window.d.ts +2 -2
  57. package/package.json +1 -1
  58. package/src/actions/index.test.ts +4 -1
  59. package/src/actions/index.ts +12 -3
  60. package/src/actions/public/createEventFilter.ts +2 -4
  61. package/src/actions/public/deployContract.test.ts +8 -8
  62. package/src/actions/public/getLogs.test.ts +105 -0
  63. package/src/actions/public/getLogs.ts +83 -0
  64. package/src/actions/public/index.test.ts +3 -1
  65. package/src/actions/public/index.ts +13 -5
  66. package/src/actions/public/readContract.test.ts +128 -0
  67. package/src/actions/public/{callContract.ts → readContract.ts} +23 -16
  68. package/src/actions/public/simulateContract.bench.ts +31 -0
  69. package/src/actions/public/simulateContract.test.ts +238 -0
  70. package/src/actions/public/simulateContract.ts +98 -0
  71. package/src/actions/wallet/index.test.ts +1 -0
  72. package/src/actions/wallet/index.ts +3 -0
  73. package/src/actions/wallet/writeContract.test.ts +54 -0
  74. package/src/actions/wallet/writeContract.ts +56 -0
  75. package/src/index.test.ts +4 -1
  76. package/src/index.ts +12 -3
  77. package/src/public.ts +3 -3
  78. package/src/types/eip1193.ts +9 -6
  79. package/src/types/index.ts +1 -1
  80. package/src/types/misc.ts +1 -0
  81. package/dist/chunk-4XREGFHD.js.map +0 -1
  82. package/dist/chunk-B7A2CAHU.mjs.map +0 -1
  83. package/dist/chunk-KCMYVU3Z.mjs.map +0 -1
  84. package/dist/chunk-WTXKCAG7.js.map +0 -1
  85. package/src/actions/public/callContract.bench.ts +0 -24
  86. package/src/actions/public/callContract.test.ts +0 -285
@@ -0,0 +1,128 @@
1
+ /**
2
+ * TODO: Heaps more test cases :D
3
+ * - Complex calldata types
4
+ * - Complex return types (tuple/structs)
5
+ * - Calls against blocks
6
+ */
7
+
8
+ import { describe, expect, test } from 'vitest'
9
+ import {
10
+ accounts,
11
+ publicClient,
12
+ testClient,
13
+ wagmiContractConfig,
14
+ walletClient,
15
+ } from '../../_test'
16
+ import { baycContractConfig } from '../../_test/abis'
17
+ import { encodeFunctionData } from '../../utils'
18
+ import { mine } from '../test'
19
+ import { sendTransaction } from '../wallet'
20
+
21
+ import { deployContract } from './deployContract'
22
+ import { getTransactionReceipt } from './getTransactionReceipt'
23
+ import { readContract } from './readContract'
24
+
25
+ describe('wagmi', () => {
26
+ test('default', async () => {
27
+ expect(
28
+ await readContract(publicClient, {
29
+ ...wagmiContractConfig,
30
+ functionName: 'balanceOf',
31
+ args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'],
32
+ }),
33
+ ).toEqual(3n)
34
+ expect(
35
+ await readContract(publicClient, {
36
+ ...wagmiContractConfig,
37
+ functionName: 'getApproved',
38
+ args: [420n],
39
+ }),
40
+ ).toEqual('0x0000000000000000000000000000000000000000')
41
+ expect(
42
+ await readContract(publicClient, {
43
+ ...wagmiContractConfig,
44
+ functionName: 'isApprovedForAll',
45
+ args: [
46
+ '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
47
+ '0x0000000000000000000000000000000000000000',
48
+ ],
49
+ }),
50
+ ).toEqual(false)
51
+ expect(
52
+ await readContract(publicClient, {
53
+ ...wagmiContractConfig,
54
+ functionName: 'name',
55
+ }),
56
+ ).toEqual('wagmi')
57
+ expect(
58
+ await readContract(publicClient, {
59
+ ...wagmiContractConfig,
60
+ functionName: 'ownerOf',
61
+ args: [420n],
62
+ }),
63
+ ).toEqual('0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC')
64
+ expect(
65
+ await readContract(publicClient, {
66
+ ...wagmiContractConfig,
67
+ functionName: 'supportsInterface',
68
+ args: ['0x1a452251'],
69
+ }),
70
+ ).toEqual(false)
71
+ expect(
72
+ await readContract(publicClient, {
73
+ ...wagmiContractConfig,
74
+ functionName: 'symbol',
75
+ }),
76
+ ).toEqual('WAGMI')
77
+ expect(
78
+ await readContract(publicClient, {
79
+ ...wagmiContractConfig,
80
+ functionName: 'tokenURI',
81
+ args: [420n],
82
+ }),
83
+ ).toMatchInlineSnapshot(
84
+ '"data:application/json;base64,eyJuYW1lIjogIndhZ21pICM0MjAiLCAiaW1hZ2UiOiAiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhkcFpIUm9QU0l4TURJMElpQm9aV2xuYUhROUlqRXdNalFpSUdacGJHdzlJbTV2Ym1VaVBqeHdZWFJvSUdacGJHdzlJbWh6YkNneE1UY3NJREV3TUNVc0lERXdKU2tpSUdROUlrMHdJREJvTVRBeU5IWXhNREkwU0RCNklpQXZQanhuSUdacGJHdzlJbWh6YkNneU9EZ3NJREV3TUNVc0lEa3dKU2tpUGp4d1lYUm9JR1E5SWswNU1ETWdORE0zTGpWak1DQTVMakV4TXkwM0xqTTRPQ0F4Tmk0MUxURTJMalVnTVRZdU5YTXRNVFl1TlMwM0xqTTROeTB4Tmk0MUxURTJMalVnTnk0ek9EZ3RNVFl1TlNBeE5pNDFMVEUyTGpVZ01UWXVOU0EzTGpNNE55QXhOaTQxSURFMkxqVjZUVFk1T0M0MU1qa2dOVFkyWXpZdU9USXhJREFnTVRJdU5UTXROUzQxT1RZZ01USXVOVE10TVRJdU5YWXROVEJqTUMwMkxqa3dOQ0ExTGpZd09TMHhNaTQxSURFeUxqVXlPUzB4TWk0MWFESTFMakExT1dNMkxqa3lJREFnTVRJdU5USTVJRFV1TlRrMklERXlMalV5T1NBeE1pNDFkalV3WXpBZ05pNDVNRFFnTlM0Mk1Ea2dNVEl1TlNBeE1pNDFNeUF4TWk0MWN6RXlMalV5T1MwMUxqVTVOaUF4TWk0MU1qa3RNVEl1TlhZdE5UQmpNQzAyTGprd05DQTFMall3T1MweE1pNDFJREV5TGpVekxURXlMalZvTWpVdU1EVTVZell1T1RJZ01DQXhNaTQxTWprZ05TNDFPVFlnTVRJdU5USTVJREV5TGpWMk5UQmpNQ0EyTGprd05DQTFMall3T1NBeE1pNDFJREV5TGpVeU9TQXhNaTQxYURNM0xqVTRPV00yTGpreUlEQWdNVEl1TlRJNUxUVXVOVGsySURFeUxqVXlPUzB4TWk0MWRpMDNOV013TFRZdU9UQTBMVFV1TmpBNUxURXlMalV0TVRJdU5USTVMVEV5TGpWekxURXlMalV6SURVdU5UazJMVEV5TGpVeklERXlMalYyTlRZdU1qVmhOaTR5TmpRZ05pNHlOalFnTUNBeElERXRNVEl1TlRJNUlEQldORGM0TGpWak1DMDJMamt3TkMwMUxqWXdPUzB4TWk0MUxURXlMalV6TFRFeUxqVklOams0TGpVeU9XTXROaTQ1TWlBd0xURXlMalV5T1NBMUxqVTVOaTB4TWk0MU1qa2dNVEl1TlhZM05XTXdJRFl1T1RBMElEVXVOakE1SURFeUxqVWdNVEl1TlRJNUlERXlMalY2SWlBdlBqeHdZWFJvSUdROUlrMHhOVGN1TmpVMUlEVTBNV010Tmk0NU16SWdNQzB4TWk0MU5USXROUzQxT1RZdE1USXVOVFV5TFRFeUxqVjJMVFV3WXpBdE5pNDVNRFF0TlM0Mk1Ua3RNVEl1TlMweE1pNDFOVEV0TVRJdU5WTXhNakFnTkRjeExqVTVOaUF4TWpBZ05EYzRMalYyTnpWak1DQTJMamt3TkNBMUxqWXlJREV5TGpVZ01USXVOVFV5SURFeUxqVm9NVFV3TGpZeVl6WXVPVE16SURBZ01USXVOVFV5TFRVdU5UazJJREV5TGpVMU1pMHhNaTQxZGkwMU1HTXdMVFl1T1RBMElEVXVOakU1TFRFeUxqVWdNVEl1TlRVeUxURXlMalZvTVRRMExqTTBOV016TGpRMk5TQXdJRFl1TWpjMklESXVOems0SURZdU1qYzJJRFl1TWpWekxUSXVPREV4SURZdU1qVXROaTR5TnpZZ05pNHlOVWd6TWpBdU9ESTRZeTAyTGprek15QXdMVEV5TGpVMU1pQTFMalU1TmkweE1pNDFOVElnTVRJdU5YWXpOeTQxWXpBZ05pNDVNRFFnTlM0Mk1Ua2dNVEl1TlNBeE1pNDFOVElnTVRJdU5XZ3hOVEF1TmpKak5pNDVNek1nTUNBeE1pNDFOVEl0TlM0MU9UWWdNVEl1TlRVeUxURXlMalYyTFRjMVl6QXROaTQ1TURRdE5TNDJNVGt0TVRJdU5TMHhNaTQxTlRJdE1USXVOVWd5T0RNdU1UY3lZeTAyTGprek1pQXdMVEV5TGpVMU1TQTFMalU1TmkweE1pNDFOVEVnTVRJdU5YWTFNR013SURZdU9UQTBMVFV1TmpFNUlERXlMalV0TVRJdU5UVXlJREV5TGpWb0xUSTFMakV3TTJNdE5pNDVNek1nTUMweE1pNDFOVEl0TlM0MU9UWXRNVEl1TlRVeUxURXlMalYyTFRVd1l6QXROaTQ1TURRdE5TNDJNaTB4TWk0MUxURXlMalUxTWkweE1pNDFjeTB4TWk0MU5USWdOUzQxT1RZdE1USXVOVFV5SURFeUxqVjJOVEJqTUNBMkxqa3dOQzAxTGpZeE9TQXhNaTQxTFRFeUxqVTFNU0F4TWk0MWFDMHlOUzR4TURSNmJUTXdNUzR5TkRJdE5pNHlOV013SURNdU5EVXlMVEl1T0RFeElEWXVNalV0Tmk0eU56WWdOaTR5TlVnek16a3VOalUxWXkwekxqUTJOU0F3TFRZdU1qYzJMVEl1TnprNExUWXVNamMyTFRZdU1qVnpNaTQ0TVRFdE5pNHlOU0EyTGpJM05pMDJMakkxYURFeE1pNDVOalpqTXk0ME5qVWdNQ0EyTGpJM05pQXlMamM1T0NBMkxqSTNOaUEyTGpJMWVrMDBPVGNnTlRVekxqZ3hPR013SURZdU9USTVJRFV1TmpJNElERXlMalUwTmlBeE1pNDFOekVnTVRJdU5UUTJhREV6TW1FMkxqSTRJRFl1TWpnZ01DQXdJREVnTmk0eU9EWWdOaTR5TnpJZ05pNHlPQ0EyTGpJNElEQWdNQ0F4TFRZdU1qZzJJRFl1TWpjemFDMHhNekpqTFRZdU9UUXpJREF0TVRJdU5UY3hJRFV1TmpFMkxURXlMalUzTVNBeE1pNDFORFpCTVRJdU5UWWdNVEl1TlRZZ01DQXdJREFnTlRBNUxqVTNNU0EyTURSb01UVXdMamcxT0dNMkxqazBNeUF3SURFeUxqVTNNUzAxTGpZeE5pQXhNaTQxTnpFdE1USXVOVFExZGkweE1USXVPVEZqTUMwMkxqa3lPQzAxTGpZeU9DMHhNaTQxTkRVdE1USXVOVGN4TFRFeUxqVTBOVWcxTURrdU5UY3hZeTAyTGprME15QXdMVEV5TGpVM01TQTFMall4TnkweE1pNDFOekVnTVRJdU5UUTFkamMxTGpJM00zcHRNemN1TnpFMExUWXlMamN5TjJNdE5pNDVORE1nTUMweE1pNDFOekVnTlM0Mk1UY3RNVEl1TlRjeElERXlMalUwTlhZeU5TNHdPVEZqTUNBMkxqa3lPU0ExTGpZeU9DQXhNaTQxTkRZZ01USXVOVGN4SURFeUxqVTBObWd4TURBdU5UY3lZell1T1RReklEQWdNVEl1TlRjeExUVXVOakUzSURFeUxqVTNNUzB4TWk0MU5EWjJMVEkxTGpBNU1XTXdMVFl1T1RJNExUVXVOakk0TFRFeUxqVTBOUzB4TWk0MU56RXRNVEl1TlRRMVNEVXpOQzQzTVRSNklpQm1hV3hzTFhKMWJHVTlJbVYyWlc1dlpHUWlJQzgrUEM5blBqd3ZjM1puUGc9PSJ9"',
85
+ )
86
+ expect(
87
+ await readContract(publicClient, {
88
+ ...wagmiContractConfig,
89
+ functionName: 'totalSupply',
90
+ }),
91
+ ).toEqual(558n)
92
+ })
93
+ })
94
+
95
+ test('fake contract address', async () => {
96
+ await expect(() =>
97
+ readContract(publicClient, {
98
+ abi: wagmiContractConfig.abi,
99
+ address: '0x0000000000000000000000000000000000000069',
100
+ functionName: 'totalSupply',
101
+ }),
102
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
103
+ "The contract method \\"totalSupply\\" returned no data (\\"0x\\"). This could be due to any of the following:
104
+ - The contract does not have the function \\"totalSupply\\",
105
+ - The parameters passed to the contract function may be invalid, or
106
+ - The address is not a contract.
107
+
108
+ Contract: 0x0000000000000000000000000000000000000000
109
+ Function: totalSupply()
110
+ > \\"0x\\"
111
+
112
+ Version: viem@1.0.2"
113
+ `)
114
+ })
115
+
116
+ // Deploy BAYC Contract
117
+ async function deployBAYC() {
118
+ const hash = await deployContract(walletClient, {
119
+ ...baycContractConfig,
120
+ args: ['Bored Ape Wagmi Club', 'BAYC', 69420n, 0n],
121
+ from: accounts[0].address,
122
+ })
123
+ await mine(testClient, { blocks: 1 })
124
+ const { contractAddress } = await getTransactionReceipt(publicClient, {
125
+ hash,
126
+ })
127
+ return { contractAddress }
128
+ }
@@ -7,7 +7,6 @@ import type {
7
7
  ExtractArgsFromAbi,
8
8
  ExtractResultFromAbi,
9
9
  ExtractFunctionNameFromAbi,
10
- GetValue,
11
10
  } from '../../types'
12
11
  import {
13
12
  EncodeFunctionDataArgs,
@@ -17,29 +16,38 @@ import {
17
16
  } from '../../utils'
18
17
  import { call, CallArgs, FormattedCall } from './call'
19
18
 
20
- export type FormattedCallContract<
19
+ export type FormattedReadContract<
21
20
  TFormatter extends Formatter | undefined = Formatter,
22
21
  > = FormattedCall<TFormatter>
23
22
 
24
- export type CallContractArgs<
25
- TChain extends Chain = Chain,
23
+ export type ReadContractArgs<
26
24
  TAbi extends Abi | readonly unknown[] = Abi,
27
25
  TFunctionName extends string = any,
28
- > = Omit<CallArgs<TChain>, 'from' | 'to' | 'data' | 'value'> & {
26
+ > = Omit<
27
+ CallArgs,
28
+ | 'accessList'
29
+ | 'chain'
30
+ | 'from'
31
+ | 'gas'
32
+ | 'gasPrice'
33
+ | 'maxFeePerGas'
34
+ | 'maxPriorityFeePerGas'
35
+ | 'nonce'
36
+ | 'to'
37
+ | 'data'
38
+ | 'value'
39
+ > & {
29
40
  address: Address
30
41
  abi: TAbi
31
- from?: Address
32
- functionName: ExtractFunctionNameFromAbi<TAbi, TFunctionName>
33
- value?: GetValue<TAbi, TFunctionName, CallArgs<TChain>['value']>
42
+ functionName: ExtractFunctionNameFromAbi<TAbi, TFunctionName, 'pure' | 'view'>
34
43
  } & ExtractArgsFromAbi<TAbi, TFunctionName>
35
44
 
36
- export type CallContractResponse<
45
+ export type ReadContractResponse<
37
46
  TAbi extends Abi | readonly unknown[] = Abi,
38
47
  TFunctionName extends string = string,
39
48
  > = ExtractResultFromAbi<TAbi, TFunctionName>
40
49
 
41
- export async function callContract<
42
- TChain extends Chain,
50
+ export async function readContract<
43
51
  TAbi extends Abi = Abi,
44
52
  TFunctionName extends string = any,
45
53
  >(
@@ -50,8 +58,8 @@ export async function callContract<
50
58
  args,
51
59
  functionName,
52
60
  ...callRequest
53
- }: CallContractArgs<TChain, TAbi, TFunctionName>,
54
- ): Promise<CallContractResponse<TAbi, TFunctionName>> {
61
+ }: ReadContractArgs<TAbi, TFunctionName>,
62
+ ): Promise<ReadContractResponse<TAbi, TFunctionName>> {
55
63
  const calldata = encodeFunctionData({
56
64
  abi,
57
65
  args,
@@ -62,19 +70,18 @@ export async function callContract<
62
70
  data: calldata,
63
71
  to: address,
64
72
  ...callRequest,
65
- } as unknown as CallArgs<TChain>)
73
+ } as unknown as CallArgs)
66
74
  return decodeFunctionResult({
67
75
  abi,
68
76
  functionName,
69
77
  data: data || '0x',
70
- }) as CallContractResponse<TAbi, TFunctionName>
78
+ })
71
79
  } catch (err) {
72
80
  throw getContractError(err, {
73
81
  abi,
74
82
  address,
75
83
  args,
76
84
  functionName,
77
- sender: callRequest.from,
78
85
  })
79
86
  }
80
87
  }
@@ -0,0 +1,31 @@
1
+ import { Contract } from 'ethers'
2
+ import { bench, describe } from 'vitest'
3
+
4
+ import {
5
+ accounts,
6
+ ethersProvider,
7
+ publicClient,
8
+ wagmiContractConfig,
9
+ } from '../../_test'
10
+
11
+ import { simulateContract } from './simulateContract'
12
+
13
+ describe('Simulate Contract', () => {
14
+ bench('viem: `simulateContract`', async () => {
15
+ await simulateContract(publicClient, {
16
+ ...wagmiContractConfig,
17
+ functionName: 'mint',
18
+ args: [1n],
19
+ from: accounts[0].address,
20
+ })
21
+ })
22
+
23
+ bench('ethers: `callStatic`', async () => {
24
+ const wagmi = new Contract(
25
+ wagmiContractConfig.address,
26
+ wagmiContractConfig.abi,
27
+ ethersProvider,
28
+ )
29
+ await wagmi.callStatic.mint(1)
30
+ })
31
+ })
@@ -0,0 +1,238 @@
1
+ /**
2
+ * TODO: Heaps more test cases :D
3
+ * - Complex calldata types
4
+ * - Complex return types (tuple/structs)
5
+ * - EIP-1559
6
+ * - Calls against blocks
7
+ * - Custom chain types
8
+ * - Custom nonce
9
+ */
10
+
11
+ import { describe, expect, test } from 'vitest'
12
+ import {
13
+ accounts,
14
+ publicClient,
15
+ testClient,
16
+ wagmiContractConfig,
17
+ walletClient,
18
+ } from '../../_test'
19
+ import { baycContractConfig } from '../../_test/abis'
20
+ import { encodeFunctionData } from '../../utils'
21
+ import { mine } from '../test'
22
+ import { sendTransaction } from '../wallet'
23
+
24
+ import { deployContract } from './deployContract'
25
+ import { getTransactionReceipt } from './getTransactionReceipt'
26
+ import { simulateContract } from './simulateContract'
27
+
28
+ describe('wagmi', () => {
29
+ test('default', async () => {
30
+ expect(
31
+ (
32
+ await simulateContract(publicClient, {
33
+ ...wagmiContractConfig,
34
+ from: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
35
+ functionName: 'mint',
36
+ args: [69420n],
37
+ })
38
+ ).result,
39
+ ).toEqual(undefined)
40
+ expect(
41
+ (
42
+ await simulateContract(publicClient, {
43
+ ...wagmiContractConfig,
44
+ functionName: 'safeTransferFrom',
45
+ from: '0x1a1E021A302C237453D3D45c7B82B19cEEB7E2e6',
46
+ args: [
47
+ '0x1a1E021A302C237453D3D45c7B82B19cEEB7E2e6',
48
+ '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
49
+ 1n,
50
+ ],
51
+ })
52
+ ).result,
53
+ ).toEqual(undefined)
54
+ })
55
+
56
+ test('revert', async () => {
57
+ await expect(() =>
58
+ simulateContract(publicClient, {
59
+ ...wagmiContractConfig,
60
+ functionName: 'approve',
61
+ args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', 420n],
62
+ from: accounts[0].address,
63
+ }),
64
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
65
+ "ERC721: approval to current owner
66
+
67
+ Sender: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
68
+ Contract: 0x0000000000000000000000000000000000000000
69
+ Function: approve(address to, uint256 tokenId)
70
+ Arguments: (0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC, 420)
71
+
72
+ Details: execution reverted: ERC721: approval to current owner
73
+ Version: viem@1.0.2"
74
+ `)
75
+ await expect(() =>
76
+ simulateContract(publicClient, {
77
+ ...wagmiContractConfig,
78
+ functionName: 'mint',
79
+ args: [1n],
80
+ from: accounts[0].address,
81
+ }),
82
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
83
+ "Token ID is taken
84
+
85
+ Sender: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
86
+ Contract: 0x0000000000000000000000000000000000000000
87
+ Function: mint(uint256 tokenId)
88
+ Arguments: (1)
89
+
90
+ Details: execution reverted: Token ID is taken
91
+ Version: viem@1.0.2"
92
+ `)
93
+ await expect(() =>
94
+ simulateContract(publicClient, {
95
+ ...wagmiContractConfig,
96
+ functionName: 'safeTransferFrom',
97
+ from: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
98
+ args: [
99
+ '0x1a1E021A302C237453D3D45c7B82B19cEEB7E2e6',
100
+ '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
101
+ 1n,
102
+ ],
103
+ }),
104
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
105
+ "ERC721: transfer caller is not owner nor approved
106
+
107
+ Sender: 0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC
108
+ Contract: 0x0000000000000000000000000000000000000000
109
+ Function: safeTransferFrom(address from, address to, uint256 tokenId)
110
+ Arguments: (0x1a1E021A302C237453D3D45c7B82B19cEEB7E2e6, 0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC, 1)
111
+
112
+ Details: execution reverted: ERC721: transfer caller is not owner nor approved
113
+ Version: viem@1.0.2"
114
+ `)
115
+ })
116
+ })
117
+
118
+ describe('BAYC', () => {
119
+ describe('default', () => {
120
+ test('mintApe', async () => {
121
+ const { contractAddress } = await deployBAYC()
122
+
123
+ // Set sale state to active
124
+ // TODO: replace w/ writeContract
125
+ await sendTransaction(walletClient, {
126
+ data: encodeFunctionData({
127
+ abi: baycContractConfig.abi,
128
+ functionName: 'flipSaleState',
129
+ }),
130
+ from: accounts[0].address,
131
+ to: contractAddress!,
132
+ })
133
+ await mine(testClient, { blocks: 1 })
134
+
135
+ // Mint an Ape!
136
+ expect(
137
+ (
138
+ await simulateContract(publicClient, {
139
+ abi: baycContractConfig.abi,
140
+ address: contractAddress!,
141
+ functionName: 'mintApe',
142
+ from: accounts[0].address,
143
+ args: [1n],
144
+ value: 1000000000000000000n,
145
+ })
146
+ ).result,
147
+ ).toBe(undefined)
148
+ })
149
+
150
+ test('get a free $100k', async () => {
151
+ const { contractAddress } = await deployBAYC()
152
+
153
+ // Reserve apes
154
+ expect(
155
+ (
156
+ await simulateContract(publicClient, {
157
+ abi: baycContractConfig.abi,
158
+ address: contractAddress!,
159
+ functionName: 'reserveApes',
160
+ from: accounts[0].address,
161
+ })
162
+ ).result,
163
+ ).toBe(undefined)
164
+ })
165
+ })
166
+
167
+ describe('revert', () => {
168
+ test('sale inactive', async () => {
169
+ const { contractAddress } = await deployBAYC()
170
+
171
+ // Expect mint to fail.
172
+ await expect(() =>
173
+ simulateContract(publicClient, {
174
+ abi: baycContractConfig.abi,
175
+ address: contractAddress!,
176
+ functionName: 'mintApe',
177
+ from: accounts[0].address,
178
+ args: [1n],
179
+ }),
180
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
181
+ "Sale must be active to mint Ape
182
+
183
+ Sender: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
184
+ Contract: 0x0000000000000000000000000000000000000000
185
+ Function: mintApe(uint256 numberOfTokens)
186
+ Arguments: (1)
187
+
188
+ Details: execution reverted: Sale must be active to mint Ape
189
+ Version: viem@1.0.2"
190
+ `)
191
+ })
192
+ })
193
+ })
194
+
195
+ test('fake contract address', async () => {
196
+ await expect(() =>
197
+ simulateContract(publicClient, {
198
+ abi: [
199
+ {
200
+ name: 'mint',
201
+ type: 'function',
202
+ stateMutability: 'nonpayable',
203
+ inputs: [],
204
+ outputs: [{ type: 'uint256' }],
205
+ },
206
+ ],
207
+ address: '0x0000000000000000000000000000000000000069',
208
+ functionName: 'mint',
209
+ from: accounts[0].address,
210
+ args: [],
211
+ }),
212
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
213
+ "The contract method \\"mint\\" returned no data (\\"0x\\"). This could be due to any of the following:
214
+ - The contract does not have the function \\"mint\\",
215
+ - The parameters passed to the contract function may be invalid, or
216
+ - The address is not a contract.
217
+
218
+ Contract: 0x0000000000000000000000000000000000000000
219
+ Function: mint()
220
+ > \\"0x\\"
221
+
222
+ Version: viem@1.0.2"
223
+ `)
224
+ })
225
+
226
+ // Deploy BAYC Contract
227
+ async function deployBAYC() {
228
+ const hash = await deployContract(walletClient, {
229
+ ...baycContractConfig,
230
+ args: ['Bored Ape Wagmi Club', 'BAYC', 69420n, 0n],
231
+ from: accounts[0].address,
232
+ })
233
+ await mine(testClient, { blocks: 1 })
234
+ const { contractAddress } = await getTransactionReceipt(publicClient, {
235
+ hash,
236
+ })
237
+ return { contractAddress }
238
+ }
@@ -0,0 +1,98 @@
1
+ import { Abi } from 'abitype'
2
+
3
+ import type { Chain, Formatter } from '../../chains'
4
+ import type { PublicClient } from '../../clients'
5
+ import type {
6
+ Address,
7
+ ExtractArgsFromAbi,
8
+ ExtractResultFromAbi,
9
+ ExtractFunctionNameFromAbi,
10
+ GetValue,
11
+ } from '../../types'
12
+ import {
13
+ EncodeFunctionDataArgs,
14
+ decodeFunctionResult,
15
+ encodeFunctionData,
16
+ getContractError,
17
+ } from '../../utils'
18
+ import { WriteContractArgs } from '../wallet'
19
+ import { call, CallArgs } from './call'
20
+
21
+ export type SimulateContractArgs<
22
+ TChain extends Chain = Chain,
23
+ TAbi extends Abi | readonly unknown[] = Abi,
24
+ TFunctionName extends string = any,
25
+ > = Omit<CallArgs<TChain>, 'to' | 'data' | 'value'> & {
26
+ address: Address
27
+ abi: TAbi
28
+ functionName: ExtractFunctionNameFromAbi<
29
+ TAbi,
30
+ TFunctionName,
31
+ 'payable' | 'nonpayable'
32
+ >
33
+ value?: GetValue<TAbi, TFunctionName, CallArgs<TChain>['value']>
34
+ } & ExtractArgsFromAbi<TAbi, TFunctionName>
35
+
36
+ export type SimulateContractResponse<
37
+ TChain extends Chain = Chain,
38
+ TAbi extends Abi | readonly unknown[] = Abi,
39
+ TFunctionName extends string = string,
40
+ > = {
41
+ result: ExtractResultFromAbi<TAbi, TFunctionName>
42
+ request: WriteContractArgs<TChain, TAbi, TFunctionName> & {
43
+ address: Address
44
+ abi: TAbi
45
+ functionName: ExtractFunctionNameFromAbi<TAbi, TFunctionName>
46
+ } & ExtractArgsFromAbi<TAbi, TFunctionName>
47
+ }
48
+
49
+ export async function simulateContract<
50
+ TChain extends Chain,
51
+ TAbi extends Abi = Abi,
52
+ TFunctionName extends string = any,
53
+ >(
54
+ client: PublicClient,
55
+ {
56
+ abi,
57
+ address,
58
+ args,
59
+ functionName,
60
+ ...callRequest
61
+ }: SimulateContractArgs<TChain, TAbi, TFunctionName>,
62
+ ): Promise<SimulateContractResponse<TChain, TAbi, TFunctionName>> {
63
+ const calldata = encodeFunctionData({
64
+ abi,
65
+ args,
66
+ functionName,
67
+ } as unknown as EncodeFunctionDataArgs<TAbi, TFunctionName>)
68
+ try {
69
+ const { data } = await call(client, {
70
+ data: calldata,
71
+ to: address,
72
+ ...callRequest,
73
+ } as unknown as CallArgs<TChain>)
74
+ const result = decodeFunctionResult({
75
+ abi,
76
+ functionName,
77
+ data: data || '0x',
78
+ })
79
+ return {
80
+ result,
81
+ request: {
82
+ abi,
83
+ address,
84
+ args,
85
+ functionName,
86
+ ...callRequest,
87
+ },
88
+ } as unknown as SimulateContractResponse<TChain, TAbi, TFunctionName>
89
+ } catch (err) {
90
+ throw getContractError(err, {
91
+ abi,
92
+ address,
93
+ args,
94
+ functionName,
95
+ sender: callRequest.from,
96
+ })
97
+ }
98
+ }
@@ -14,6 +14,7 @@ test('exports actions', () => {
14
14
  "signMessage": [Function],
15
15
  "switchChain": [Function],
16
16
  "watchAsset": [Function],
17
+ "writeContract": [Function],
17
18
  }
18
19
  `)
19
20
  })
@@ -25,3 +25,6 @@ export type { SwitchChainArgs } from './switchChain'
25
25
 
26
26
  export { watchAsset } from './watchAsset'
27
27
  export type { WatchAssetArgs, WatchAssetResponse } from './watchAsset'
28
+
29
+ export { writeContract } from './writeContract'
30
+ export type { WriteContractArgs, WriteContractResponse } from './writeContract'
@@ -0,0 +1,54 @@
1
+ import { expect, test } from 'vitest'
2
+ import {
3
+ accounts,
4
+ publicClient,
5
+ testClient,
6
+ wagmiContractConfig,
7
+ walletClient,
8
+ } from '../../_test'
9
+ import { simulateContract } from '../public'
10
+ import { mine } from '../test'
11
+
12
+ import { writeContract } from './writeContract'
13
+
14
+ test('default', async () => {
15
+ expect(
16
+ await writeContract(walletClient, {
17
+ ...wagmiContractConfig,
18
+ from: accounts[0].address,
19
+ functionName: 'mint',
20
+ args: [69420n],
21
+ }),
22
+ ).toBeDefined()
23
+ })
24
+
25
+ test('w/ simulateContract', async () => {
26
+ const { request } = await simulateContract(publicClient, {
27
+ ...wagmiContractConfig,
28
+ from: accounts[0].address,
29
+ functionName: 'mint',
30
+ args: [69420n],
31
+ })
32
+ expect(await writeContract(walletClient, request)).toBeDefined()
33
+
34
+ await mine(testClient, { blocks: 1 })
35
+
36
+ await expect(() =>
37
+ simulateContract(publicClient, {
38
+ ...wagmiContractConfig,
39
+ from: accounts[0].address,
40
+ functionName: 'mint',
41
+ args: [69420n],
42
+ }),
43
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
44
+ "Token ID is taken
45
+
46
+ Sender: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
47
+ Contract: 0x0000000000000000000000000000000000000000
48
+ Function: mint(uint256 tokenId)
49
+ Arguments: (69420)
50
+
51
+ Details: execution reverted: Token ID is taken
52
+ Version: viem@1.0.2"
53
+ `)
54
+ })