erc4337-kit 0.1.0 → 0.1.1

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 (2) hide show
  1. package/README.md +368 -70
  2. package/package.json +17 -23
package/README.md CHANGED
@@ -1,167 +1,465 @@
1
1
  # erc4337-kit
2
2
 
3
- ERC-4337 Account Abstraction for React apps — gasless transactions, social login, smart accounts. Plug in, don't plumb.
3
+ > ERC-4337 Account Abstraction for React — gasless transactions, social login, and smart accounts without the complexity.
4
4
 
5
- Built on: Privy · Pimlico · Permissionless · Polygon Amoy
5
+ Built on **Privy** (auth) · **Pimlico** (bundler + paymaster) · **Permissionless** (smart accounts) · **Polygon Amoy** (default chain)
6
+
7
+ [![npm](https://img.shields.io/npm/v/erc4337-kit)](https://www.npmjs.com/package/erc4337-kit)
8
+ [![license](https://img.shields.io/npm/l/erc4337-kit)](LICENSE)
6
9
 
7
10
  ---
8
11
 
9
- ## Install
12
+ ## What this package does
10
13
 
11
- ```bash
12
- npm install erc4337-kit
14
+ Normally, setting up ERC-4337 means wiring together Privy, Permissionless, Pimlico, viem, wagmi, and writing ~200 lines of boilerplate hooks yourself — dealing with race conditions, polyfills, gas estimation, UserOperation formatting, and paymaster sponsorship.
15
+
16
+ This package collapses all of that into **three exports**: a provider, a hook, and a transaction hook.
17
+
18
+ ```
19
+ Without erc4337-kit: With erc4337-kit:
20
+ ───────────────────── ─────────────────────
21
+ 200 lines of setup → <ChainProvider> (5 lines)
22
+ Privy + wagmi + QueryClient useSmartAccount() (1 line)
23
+ Smart account init race fix useStoreOnChain() (1 line)
24
+ Pimlico gas estimation
25
+ UserOperation formatting
26
+ Error parsing
13
27
  ```
14
28
 
15
- Also install peer dependencies if you haven't already:
29
+ ---
30
+
31
+ ## Requirements
32
+
33
+ - React 18 or 19
34
+ - Vite (Next.js support coming)
35
+ - Node.js 18+
36
+ - A Privy App ID (free at [dashboard.privy.io](https://dashboard.privy.io))
37
+ - A Pimlico API Key (free at [dashboard.pimlico.io](https://dashboard.pimlico.io))
38
+ - An Alchemy RPC URL (free at [dashboard.alchemy.com](https://dashboard.alchemy.com))
39
+
40
+ ---
41
+
42
+ ## Installation
16
43
 
17
44
  ```bash
18
- npm install @privy-io/react-auth @privy-io/wagmi viem wagmi @tanstack/react-query permissionless
45
+ # Step 1: install the package
46
+ npm install erc4337-kit
47
+
48
+ # Step 2: install peer dependencies
49
+ npm install @privy-io/react-auth @privy-io/wagmi viem wagmi @tanstack/react-query
50
+
51
+ # Step 3: install browser polyfills (viem needs these)
52
+ npm install buffer process
19
53
  ```
20
54
 
21
55
  ---
22
56
 
23
- ## Vite setup (required)
57
+ ## Setup (two files to edit, then you're done)
24
58
 
25
- Add this to `vite.config.js` — viem needs these polyfills in the browser:
59
+ ### 1. `vite.config.js`
26
60
 
27
61
  ```js
62
+ import { defineConfig } from 'vite'
63
+ import react from '@vitejs/plugin-react'
64
+
28
65
  export default defineConfig({
29
- define: { global: 'globalThis' },
66
+ plugins: [react()],
67
+ define: {
68
+ global: 'globalThis', // required for viem
69
+ },
30
70
  resolve: {
31
- alias: { '@noble/curves/nist.js': '@noble/curves/nist' },
71
+ alias: {
72
+ '@noble/curves/nist.js': '@noble/curves/nist', // required for permissionless
73
+ },
32
74
  },
33
75
  })
34
76
  ```
35
77
 
36
- Add this to your `index.html` `<head>` before your app script:
78
+ > If you're using Tailwind v4, add `tailwindcss from '@tailwindcss/vite'` to plugins as normal — it's compatible.
79
+
80
+ ### 2. `index.html` — add this in `<head>`, **before** your app script
37
81
 
38
82
  ```html
39
- <script type="module">
40
- import { Buffer } from 'buffer'
41
- import process from 'process'
42
- window.Buffer = Buffer
43
- window.process = process
44
- </script>
83
+ <head>
84
+ <!-- ... your other meta tags ... -->
85
+
86
+ <!-- REQUIRED: add this before <script src="/src/main.jsx"> -->
87
+ <script type="module">
88
+ import { Buffer } from 'buffer'
89
+ import process from 'process'
90
+ window.Buffer = Buffer
91
+ window.process = process
92
+ </script>
93
+ </head>
45
94
  ```
46
95
 
96
+ > **Why?** `viem` and `permissionless` use Node.js globals (`Buffer`, `process`) that don't exist in the browser. This polyfill must load before your app or you'll get `ReferenceError: Buffer is not defined`.
97
+
47
98
  ---
48
99
 
49
- ## Quick start
100
+ ## `.env`
50
101
 
51
- ### 1. Wrap your app
102
+ ```env
103
+ VITE_PRIVY_APP_ID= # from dashboard.privy.io → your app → App ID
104
+ VITE_PIMLICO_API_KEY= # from dashboard.pimlico.io → API Keys
105
+ VITE_RPC_URL= # from dashboard.alchemy.com → Polygon Amoy → HTTPS URL
106
+ VITE_CONTRACT_ADDRESS= # your deployed contract address (after you deploy)
107
+ ```
108
+
109
+ > Never commit `.env` to git. Add it to `.gitignore`.
110
+
111
+ ---
112
+
113
+ ## Usage
114
+
115
+ ### Step 1 — Wrap your app with `ChainProvider`
116
+
117
+ Put this in `src/main.jsx`. It sets up Privy, QueryClient, and Wagmi in one shot.
52
118
 
53
119
  ```jsx
54
- import { ChainProvider } from 'erc4337-kit'
55
- import { polygonAmoy } from 'erc4337-kit'
120
+ import React from 'react'
121
+ import ReactDOM from 'react-dom/client'
122
+ import { ChainProvider, polygonAmoy } from 'erc4337-kit'
123
+ import App from './App.jsx'
56
124
 
57
- function main() {
58
- return (
125
+ ReactDOM.createRoot(document.getElementById('root')).render(
126
+ <React.StrictMode>
59
127
  <ChainProvider
60
128
  privyAppId={import.meta.env.VITE_PRIVY_APP_ID}
61
129
  chain={polygonAmoy}
62
130
  rpcUrl={import.meta.env.VITE_RPC_URL}
131
+ loginMethods={['google', 'email']} // optional, this is the default
132
+ appearance={{ theme: 'dark', accentColor: '#7c3aed' }} // optional
63
133
  >
64
134
  <App />
65
135
  </ChainProvider>
66
- )
67
- }
136
+ </React.StrictMode>,
137
+ )
68
138
  ```
69
139
 
70
- ### 2. Initialize the smart account
140
+ ### Step 2 Initialize the smart account
71
141
 
72
142
  ```jsx
73
- import { useSmartAccount } from 'erc4337-kit'
74
- import { polygonAmoy } from 'erc4337-kit'
143
+ import { useSmartAccount, polygonAmoy } from 'erc4337-kit'
75
144
 
76
145
  function App() {
77
146
  const {
78
- login, logout, authenticated,
79
- smartAccountClient, smartAccountAddress,
80
- isReady, isLoading, error
147
+ login, // Function — opens Privy login modal
148
+ logout, // Function — clears all state
149
+ authenticated, // boolean — user is logged in
150
+ user, // Privy user object (has .email.address, .google.email)
151
+ smartAccountAddress, // string — the user's smart account address (0x...)
152
+ smartAccountClient, // SmartAccountClient — use this to send transactions
153
+ isReady, // boolean — smart account is initialized, safe to transact
154
+ isLoading, // boolean — still setting up
155
+ error, // string | null — human-readable error message
81
156
  } = useSmartAccount({
82
157
  pimlicoApiKey: import.meta.env.VITE_PIMLICO_API_KEY,
83
158
  rpcUrl: import.meta.env.VITE_RPC_URL,
84
159
  chain: polygonAmoy,
85
160
  })
86
161
 
87
- if (!authenticated) return <button onClick={login}>Login with Google</button>
88
- if (isLoading) return <p>Setting up your wallet...</p>
89
- if (error) return <p>Error: {error}</p>
162
+ if (!authenticated) return <button onClick={login}>Sign in</button>
163
+ if (isLoading) return <p>Setting up your wallet…</p>
164
+ if (error) return <p style={{ color: 'red' }}>Error: {error}</p>
90
165
 
91
- return <Dashboard smartAccountClient={smartAccountClient} />
166
+ return (
167
+ <div>
168
+ <p>Smart account: {smartAccountAddress}</p>
169
+ <button onClick={logout}>Sign out</button>
170
+ </div>
171
+ )
92
172
  }
93
173
  ```
94
174
 
95
- ### 3. Store data on-chain (gasless)
175
+ > `smartAccountAddress` is **deterministic** — the same user always gets the same address across sessions. It is a smart contract address, not the user's EOA (embedded wallet). Store this in your database, not the Privy user ID, if you need to link on-chain records to users.
176
+
177
+ ### Step 3 — Send a gasless transaction
178
+
179
+ #### Option A: use `useStoreOnChain` (simplest — for hash-based data storage)
96
180
 
97
181
  ```jsx
98
182
  import { useStoreOnChain, sha256Hash } from 'erc4337-kit'
99
183
 
100
- const MY_CONTRACT_ABI = [
101
- {
102
- name: 'storeRecord',
103
- type: 'function',
104
- inputs: [{ name: 'dataHash', type: 'bytes32' }],
105
- },
106
- ]
184
+ const MY_ABI = [{
185
+ name: 'storeRecord',
186
+ type: 'function',
187
+ inputs: [{ name: 'dataHash', type: 'bytes32' }],
188
+ }]
107
189
 
108
- function ReportForm({ smartAccountClient }) {
109
- const { submit, txHash, isLoading, error } = useStoreOnChain({
190
+ function SubmitForm({ smartAccountClient }) {
191
+ const {
192
+ submit, // async (args: any[]) => string | null — returns txHash
193
+ txHash, // string | null
194
+ recordId, // string | null — decoded bytes32 from first event log
195
+ isLoading, // boolean
196
+ isSuccess, // boolean
197
+ error, // string | null
198
+ reset, // Function — resets all state back to null
199
+ } = useStoreOnChain({
110
200
  smartAccountClient,
111
201
  contractAddress: import.meta.env.VITE_CONTRACT_ADDRESS,
112
- abi: MY_CONTRACT_ABI,
202
+ abi: MY_ABI,
113
203
  functionName: 'storeRecord',
114
204
  })
115
205
 
116
- const handleSubmit = async (reportText) => {
117
- const hash = await sha256Hash(reportText) // hashed locally
118
- await submit([hash])
206
+ const handleSubmit = async (rawData) => {
207
+ const hash = await sha256Hash(JSON.stringify(rawData)) // hash locally
208
+ await submit([hash]) // send on-chain
119
209
  }
120
210
 
121
211
  return (
122
212
  <div>
123
- <button onClick={() => handleSubmit('incident details')} disabled={isLoading}>
124
- {isLoading ? 'Storing...' : 'Submit Report'}
213
+ <button onClick={() => handleSubmit({ text: 'my data' })} disabled={isLoading}>
214
+ {isLoading ? 'Storing' : 'Submit'}
125
215
  </button>
126
- {txHash && <p>Stored! Tx: {txHash}</p>}
127
- {error && <p>Error: {error}</p>}
216
+ {isSuccess && <p>Stored! Tx: <a href={`https://amoy.polygonscan.com/tx/${txHash}`}>{txHash?.slice(0,10)}…</a></p>}
217
+ {error && <p style={{ color: 'red' }}>{error}</p>}
128
218
  </div>
129
219
  )
130
220
  }
131
221
  ```
132
222
 
223
+ #### Option B: use `smartAccountClient.sendTransaction` directly (for any contract call)
224
+
225
+ ```jsx
226
+ import { encodeFunctionData } from 'viem'
227
+
228
+ const handleAddTodo = async (task) => {
229
+ const calldata = encodeFunctionData({
230
+ abi: contractABI,
231
+ functionName: 'addTodo',
232
+ args: [task],
233
+ })
234
+
235
+ // ✅ Correct — use sendTransaction with encoded calldata
236
+ const hash = await smartAccountClient.sendTransaction({
237
+ to: contractAddress,
238
+ data: calldata,
239
+ value: 0n, // no ETH/MATIC being sent
240
+ })
241
+
242
+ console.log('tx hash:', hash)
243
+ }
244
+ ```
245
+
246
+ > **Critical:** Do NOT use `smartAccountClient.writeContract()`. The smart account client uses `sendTransaction` with `encodeFunctionData`. Calling `writeContract` throws `account.encodeCalls is not a function`.
247
+
248
+ ### Step 4 — Read from the contract
249
+
250
+ For reading, create a standard `publicClient` from viem. Reading is free (no gas, no smart account needed).
251
+
252
+ ```jsx
253
+ import { createPublicClient, http } from 'viem'
254
+ import { polygonAmoy } from 'erc4337-kit'
255
+
256
+ const publicClient = createPublicClient({
257
+ chain: polygonAmoy,
258
+ transport: http(import.meta.env.VITE_RPC_URL),
259
+ })
260
+
261
+ // For user-specific data, pass account: smartAccountAddress
262
+ const todos = await publicClient.readContract({
263
+ address: contractAddress,
264
+ abi: contractABI,
265
+ functionName: 'getTodos',
266
+ args: [],
267
+ account: smartAccountAddress, // required for mapping(address => ...) returns
268
+ })
269
+ ```
270
+
271
+ > `account: smartAccountAddress` is required when your contract uses `msg.sender` to look up data. Without it, the read returns data for address `0x000...000` instead.
272
+
133
273
  ---
134
274
 
135
- ## Contract template
275
+ ## Supported chains
276
+
277
+ ```js
278
+ import { polygonAmoy, polygon, sepolia, baseSepolia } from 'erc4337-kit'
279
+ ```
136
280
 
137
- Copy `src/contracts/BaseStorage.sol` from this package as a starting point. It is pre-commented with all ERC-4337 compatibility rules. Add fields to the struct and parameters to `storeRecord()` as needed for your use case.
281
+ | Export | Network | Use for |
282
+ |--------|---------|---------|
283
+ | `polygonAmoy` | Polygon Amoy testnet (chain ID 80002) | Development and testing |
284
+ | `polygon` | Polygon mainnet | Production |
285
+ | `sepolia` | Ethereum Sepolia testnet | Ethereum testing |
286
+ | `baseSepolia` | Base Sepolia testnet | Base chain testing |
138
287
 
139
- Deploy it with Hardhat or Remix to your chain, then pass the address to `useStoreOnChain()`.
288
+ Any chain supported by both Pimlico and Privy works these are just the re-exported convenience constants.
140
289
 
141
290
  ---
142
291
 
143
- ## Environment variables
292
+ ## Solidity contract compatibility
144
293
 
145
- ```env
146
- VITE_PRIVY_APP_ID= # dashboard.privy.io
147
- VITE_PIMLICO_API_KEY= # dashboard.pimlico.io
148
- VITE_RPC_URL= # Alchemy or Infura RPC for your chain
149
- VITE_CONTRACT_ADDRESS= # deployed BaseStorage.sol address
294
+ Your contract works with this package without modification. There is one rule you must understand:
295
+
296
+ **`msg.sender` in your contract will be the user's Smart Account address, not their EOA.**
297
+
298
+ This is correct and expected. Your mappings, ownership checks, and identity logic should use `msg.sender` as normal — it will consistently resolve to the user's smart account address every session.
299
+
300
+ A minimal compatible contract:
301
+
302
+ ```solidity
303
+ // SPDX-License-Identifier: MIT
304
+ pragma solidity ^0.8.20;
305
+
306
+ contract YourApp {
307
+ // msg.sender = user's Smart Account (consistent, deterministic)
308
+ mapping(address => bytes32[]) private _records;
309
+
310
+ function storeRecord(bytes32 dataHash) external {
311
+ _records[msg.sender].push(dataHash);
312
+ }
313
+
314
+ function getRecords() external view returns (bytes32[] memory) {
315
+ return _records[msg.sender];
316
+ }
317
+ }
150
318
  ```
151
319
 
320
+ A template with more complete patterns is included at `node_modules/erc4337-kit/src/contracts/BaseStorage.sol`.
321
+
152
322
  ---
153
323
 
154
- ## Supported chains
324
+ ## API reference
325
+
326
+ ### `<ChainProvider>`
327
+
328
+ | Prop | Type | Required | Default | Description |
329
+ |------|------|----------|---------|-------------|
330
+ | `privyAppId` | `string` | Yes | — | Your Privy App ID |
331
+ | `chain` | `Chain` (viem) | Yes | — | Target blockchain |
332
+ | `rpcUrl` | `string` | Yes | — | Alchemy / Infura RPC URL |
333
+ | `loginMethods` | `string[]` | No | `['google', 'email']` | Privy login methods |
334
+ | `appearance` | `object` | No | `{ theme: 'light' }` | Privy modal appearance |
335
+
336
+ ### `useSmartAccount(config)`
337
+
338
+ **Config:**
339
+
340
+ | Field | Type | Required | Description |
341
+ |-------|------|----------|-------------|
342
+ | `pimlicoApiKey` | `string` | Yes | Pimlico API key |
343
+ | `rpcUrl` | `string` | Yes | RPC URL matching your chain |
344
+ | `chain` | `Chain` (viem) | Yes | Must match ChainProvider |
345
+
346
+ **Returns:**
347
+
348
+ | Field | Type | Description |
349
+ |-------|------|-------------|
350
+ | `login` | `Function` | Opens Privy login modal |
351
+ | `logout` | `Function` | Clears all state and logs out |
352
+ | `authenticated` | `boolean` | True when user is logged in |
353
+ | `user` | `PrivyUser \| null` | Privy user object |
354
+ | `smartAccountAddress` | `string \| null` | The user's smart account address |
355
+ | `smartAccountClient` | `SmartAccountClient \| null` | For sending transactions |
356
+ | `pimlicoClient` | `PimlicoClient \| null` | For gas price reads |
357
+ | `isReady` | `boolean` | True when safe to call `sendTransaction` |
358
+ | `isLoading` | `boolean` | True during initialization |
359
+ | `error` | `string \| null` | Human-readable error |
360
+
361
+ ### `useStoreOnChain(config)`
362
+
363
+ **Config:**
364
+
365
+ | Field | Type | Required | Description |
366
+ |-------|------|----------|-------------|
367
+ | `smartAccountClient` | `SmartAccountClient` | Yes | From `useSmartAccount()` |
368
+ | `contractAddress` | `string` | Yes | Deployed contract address |
369
+ | `abi` | `Abi` | Yes | Contract ABI (just the functions you need) |
370
+ | `functionName` | `string` | Yes | Function to call |
371
+
372
+ **Returns:**
373
+
374
+ | Field | Type | Description |
375
+ |-------|------|-------------|
376
+ | `submit` | `async (args: any[]) => string \| null` | Sends the transaction, returns txHash |
377
+ | `txHash` | `string \| null` | Transaction hash after success |
378
+ | `recordId` | `string \| null` | bytes32 decoded from first event log |
379
+ | `isLoading` | `boolean` | True while submitting |
380
+ | `isSuccess` | `boolean` | True after successful submission |
381
+ | `error` | `string \| null` | Human-readable error |
382
+ | `reset` | `Function` | Clears all state back to null |
383
+
384
+ ### `sha256Hash(data)` / `sha256HashFile(file)`
385
+
386
+ ```js
387
+ const hash = await sha256Hash('any string') // → '0x7f3a...' (66 chars)
388
+ const hash = await sha256HashFile(fileObject) // → '0xabcd...' (66 chars)
389
+ ```
390
+
391
+ Both return a `0x`-prefixed hex string that is `bytes32`-compatible. Hashing happens in the browser using the Web Crypto API — no data leaves the device.
392
+
393
+ ---
394
+
395
+ ## Troubleshooting
396
+
397
+ ### `ReferenceError: Buffer is not defined`
398
+ The polyfill script is missing from `index.html`, or it's placed after your app script. It must come first in `<head>`.
399
+
400
+ ### Smart account not initializing
401
+ Check all three env vars are set and correct. Add `console.log(error)` from `useSmartAccount` to see the exact message. Most commonly: wrong Pimlico API key, or Polygon Amoy not enabled in your Pimlico dashboard.
402
+
403
+ ### `account.encodeCalls is not a function`
404
+ You called `smartAccountClient.writeContract()`. Use `smartAccountClient.sendTransaction()` with `encodeFunctionData()` from viem instead. See Option B in usage above.
405
+
406
+ ### Contract reads returning empty or wrong data
407
+ You're missing `account: smartAccountAddress` in `publicClient.readContract()`. Without it, reads go out as address `0x0` which returns empty mappings.
408
+
409
+ ### `AA21` — paymaster rejected
410
+ Your Pimlico API key is wrong, or Polygon Amoy isn't enabled in your Pimlico project dashboard. The erc4337-kit error message will say this in plain English.
411
+
412
+ ### `AA31` — paymaster out of funds
413
+ Your Pimlico paymaster balance is empty. The free tier works for testnet — log in and check your dashboard balance.
414
+
415
+ ### `nonce` error
416
+ A previous UserOperation from this smart account is still pending in the bundler mempool. Wait 30–60 seconds and retry.
417
+
418
+ ---
419
+
420
+ ## Production checklist
421
+
422
+ - [ ] Move from Polygon Amoy to Polygon mainnet (change `chain` and `rpcUrl`)
423
+ - [ ] Upgrade Pimlico to a paid plan (free tier is testnet only)
424
+ - [ ] Set `PRIVATE_KEY` and deployment keys only in server env, never in `VITE_` prefixed vars
425
+ - [ ] Audit your Solidity contract before mainnet
426
+ - [ ] Add `waitForTransactionReceipt` calls where confirmation matters
427
+ - [ ] Handle the `error` state from `useSmartAccount` visibly in your UI
428
+ - [ ] Add `.env` to `.gitignore`
429
+
430
+ ---
431
+
432
+ ## Contributing
433
+
434
+ Found a bug? Have a feature request? Contributions are welcome!
435
+
436
+ 1. Fork the repo
437
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
438
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
439
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
440
+ 5. Open a Pull Request
441
+
442
+ ---
443
+
444
+ ## Links
445
+
446
+ - **npm**: https://www.npmjs.com/package/erc4337-kit
447
+ - **GitHub**: https://github.com/atharvabaodhankar/erc4337-kit
448
+ - **Privy dashboard**: https://dashboard.privy.io
449
+ - **Pimlico dashboard**: https://dashboard.pimlico.io
450
+ - **Alchemy**: https://dashboard.alchemy.com
451
+ - **Polygon Amoy explorer**: https://amoy.polygonscan.com
452
+ - **ERC-4337 spec**: https://eips.ethereum.org/EIPS/eip-4337
453
+
454
+ ---
155
455
 
156
- Any EVM chain supported by Pimlico and Privy. Chains exported from this package for convenience:
456
+ ## Support
157
457
 
158
- - `polygonAmoy` Polygon testnet (recommended for dev)
159
- - `polygon` Polygon mainnet
160
- - `sepolia` — Ethereum testnet
161
- - `baseSepolia` — Base testnet
458
+ - 🐛 Issues: https://github.com/atharvabaodhankar/erc4337-kit/issues
459
+ - 💬 Discussions: https://github.com/atharvabaodhankar/erc4337-kit/discussions
162
460
 
163
461
  ---
164
462
 
165
463
  ## License
166
464
 
167
- MIT
465
+ MIT © Atharva Baodhankar
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "erc4337-kit",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Plug-and-play ERC-4337 Account Abstraction for React apps. Gasless txs, social login, smart accounts — without the complexity.",
5
5
  "author": "Atharva Baodhankar",
6
6
  "license": "MIT",
@@ -20,15 +20,13 @@
20
20
  "smart-account",
21
21
  "userops"
22
22
  ],
23
-
24
23
  "type": "module",
25
-
26
- "main": "./dist/index.cjs",
27
- "module": "./dist/index.js",
24
+ "main": "./dist/index.cjs",
25
+ "module": "./dist/index.js",
28
26
  "exports": {
29
27
  ".": {
30
- "types": "./dist/index.d.ts",
31
- "import": "./dist/index.js",
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js",
32
30
  "require": "./dist/index.cjs"
33
31
  }
34
32
  },
@@ -37,31 +35,27 @@
37
35
  "src/contracts/BaseStorage.sol",
38
36
  "README.md"
39
37
  ],
40
-
41
38
  "scripts": {
42
- "build": "tsup",
43
- "dev": "tsup --watch",
39
+ "build": "tsup",
40
+ "dev": "tsup --watch",
44
41
  "prepublishOnly": "npm run build"
45
42
  },
46
-
47
43
  "peerDependencies": {
48
- "react": ">=18.0.0",
49
- "react-dom": ">=18.0.0",
50
- "@privy-io/react-auth":">=3.0.0",
51
- "@privy-io/wagmi": ">=4.0.0",
52
- "viem": ">=2.0.0",
53
- "wagmi": ">=3.0.0",
54
- "@tanstack/react-query":">=5.0.0"
44
+ "react": ">=18.0.0",
45
+ "react-dom": ">=18.0.0",
46
+ "@privy-io/react-auth": ">=3.0.0",
47
+ "@privy-io/wagmi": ">=4.0.0",
48
+ "viem": ">=2.0.0",
49
+ "wagmi": ">=3.0.0",
50
+ "@tanstack/react-query": ">=5.0.0"
55
51
  },
56
-
57
52
  "dependencies": {
58
53
  "permissionless": "^0.3.4"
59
54
  },
60
-
61
55
  "devDependencies": {
62
- "tsup": "^8.0.0",
63
- "react": "^18.2.0",
64
- "react-dom": "^18.2.0",
56
+ "tsup": "^8.0.0",
57
+ "react": "^18.2.0",
58
+ "react-dom": "^18.2.0",
65
59
  "typescript": "^5.0.0"
66
60
  }
67
61
  }