@1llet.xyz/erc4337-gasless-sdk 0.1.0 → 0.1.2

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.
package/README.md ADDED
@@ -0,0 +1,161 @@
1
+ # ERC-4337 Gasless SDK ⛽️
2
+
3
+ A lightweight, typed SDK to integrate Account Abstraction (ERC-4337) into your dApp. It handles Smart Account creation, gasless transactions, and token approvals seamlessly.
4
+
5
+ ## 📦 Installation
6
+
7
+ ```bash
8
+ npm install @1llet.xyz/erc4337-gasless-sdk viem
9
+ # or
10
+ yarn add @1llet.xyz/erc4337-gasless-sdk viem
11
+ ```
12
+
13
+ ## 🚀 Quick Start
14
+
15
+ ### 1. Configuration
16
+
17
+ Define the chain configuration (including your Bundler URL and Paymaster).
18
+
19
+ ```typescript
20
+ import { type ChainConfig } from "@1llet.xyz/erc4337-gasless-sdk";
21
+ import { baseSepolia } from "viem/chains";
22
+
23
+ const config: ChainConfig = {
24
+ chain: baseSepolia,
25
+ // Your Bundler URL (must support ERC-4337 methods)
26
+ bundlerUrl: "https://api.yourbundler.com/rpc",
27
+ // Optional: Override RPC URL (defaults to chain.rpcUrls.default)
28
+ // rpcUrl: "https://sepolia.base.org",
29
+
30
+ // Addresses are automatically resolved for supported chains (Base, Base Sepolia)
31
+ // You can override them if needed:
32
+ // factoryAddress: "0x...",
33
+ };
34
+ ```
35
+
36
+ ### 2. Initialize & Connect
37
+
38
+ ```typescript
39
+ import { AccountAbstraction } from "@1llet.xyz/erc4337-gasless-sdk";
40
+
41
+ const aa = new AccountAbstraction(config);
42
+
43
+ // Connect to MetaMask (or any injected provider)
44
+ // This calculates the Smart Account address deterministically (Counterfactual)
45
+ const { owner, smartAccount } = await aa.connect();
46
+
47
+ console.log("EOA Owner:", owner);
48
+ console.log("Smart Account:", smartAccount);
49
+ ```
50
+
51
+ ### 3. Send a Gasless Transaction
52
+
53
+ Send a transaction where the Gas is paid by the Paymaster (sponsored).
54
+
55
+ ```typescript
56
+ import { encodeFunctionData, parseAbi } from "viem";
57
+
58
+ // Example: Calling a precise function on a contract
59
+ const myContractAbi = parseAbi(["function safeMint(address to)"]);
60
+ const callData = encodeFunctionData({
61
+ abi: myContractAbi,
62
+ functionName: "safeMint",
63
+ args: [smartAccount]
64
+ });
65
+
66
+ // Build the UserOperation
67
+ // This automatically handles: InitCode (if not deployed), Gas Estimation, and Paymaster data
68
+ const userOp = await aa.buildUserOperationBatch([
69
+ {
70
+ target: "0xMyNftContract...",
71
+ value: 0n,
72
+ data: callData
73
+ }
74
+ ]);
75
+
76
+ // Sign with the EOA (MetaMask)
77
+ const signedOp = await aa.signUserOperation(userOp);
78
+
79
+ // Send to Bundler
80
+ const userOpHash = await aa.sendUserOperation(signedOp);
81
+ console.log("Transaction sent! Hash:", userOpHash);
82
+
83
+ // Wait for confirmation
84
+ const receipt = await aa.waitForUserOperation(userOpHash);
85
+ console.log("Transaction confirmed in block:", receipt.receipt.blockNumber);
86
+ ```
87
+
88
+ ### 4. Special Feature: Approval Support
89
+
90
+ Fund the user's EOA with native ETH (via the Paymaster/Bundler) if they need to execute a legacy `approve` transaction and have no gas.
91
+
92
+ ```typescript
93
+ try {
94
+ const result = await aa.requestApprovalSupport(
95
+ usdcAddress,
96
+ spenderAddress,
97
+ amount
98
+ );
99
+
100
+ if (result.fundingNeeded) {
101
+ console.log(`User was funded with ${result.fundedAmount} ETH to pay for gas!`);
102
+ }
103
+ } catch (e) {
104
+ console.error("Failed to fund user:", e);
105
+ }
106
+ ```
107
+
108
+ ## 🛠️ Build Locally
109
+
110
+ ```bash
111
+ git clone https://github.com/your-repo/erc4337-gasless-sdk.git
112
+ cd erc4337-gasless-sdk
113
+ npm install
114
+ npm run build
115
+ ```
116
+
117
+ ## � API Reference
118
+
119
+ ### Balances & Allowances
120
+
121
+ ```typescript
122
+ // Get Smart Account USDC Balance
123
+ const balance = await aa.getUsdcBalance();
124
+
125
+ // Get EOA (Wallet) USDC Balance
126
+ const eoaBalance = await aa.getEoaUsdcBalance();
127
+
128
+ // Check how much USDC the Smart Account is allowed to spend from EOA
129
+ const allowance = await aa.getAllowance();
130
+ ```
131
+
132
+ ### Account Management
133
+
134
+ ```typescript
135
+ // Check if the Smart Account is already deployed on-chain
136
+ const isDeployed = await aa.isAccountDeployed();
137
+
138
+ // Get the Counterfactual Address (deterministic address based on owner)
139
+ const address = await aa.getSmartAccountAddress(ownerAddress);
140
+
141
+ // Manually deploy the account (if you don't want to bundle it with a tx)
142
+ if (!isDeployed) {
143
+ const deployOp = await aa.buildDeployUserOperation();
144
+ const signed = await aa.signUserOperation(deployOp);
145
+ await aa.sendUserOperation(signed);
146
+ }
147
+ ```
148
+
149
+ ### Utilities
150
+
151
+ ```typescript
152
+ // Get current Nonce
153
+ const nonce = await aa.getNonce();
154
+
155
+ // Get UserOp Hash (for manual signing or verification)
156
+ const hash = aa.getUserOpHash(userOp);
157
+ ```
158
+
159
+ ## �📄 License
160
+
161
+ MIT
package/dist/index.d.mts CHANGED
@@ -2,12 +2,12 @@ import { Chain, Address, Hex, Hash } from 'viem';
2
2
 
3
3
  interface ChainConfig {
4
4
  chain: Chain;
5
- rpcUrl: string;
5
+ rpcUrl?: string;
6
6
  bundlerUrl: string;
7
- entryPointAddress: Address;
8
- factoryAddress: Address;
9
- paymasterAddress: Address;
10
- usdcAddress: Address;
7
+ entryPointAddress?: Address;
8
+ factoryAddress?: Address;
9
+ paymasterAddress?: Address;
10
+ usdcAddress?: Address;
11
11
  }
12
12
  interface UserOperation {
13
13
  sender: Address;
@@ -54,6 +54,10 @@ declare class AccountAbstraction {
54
54
  private smartAccountAddress;
55
55
  private chainConfig;
56
56
  private publicClient;
57
+ private entryPointAddress;
58
+ private factoryAddress;
59
+ private paymasterAddress?;
60
+ private usdcAddress;
57
61
  constructor(chainConfig: ChainConfig);
58
62
  /**
59
63
  * Connect to MetaMask and get the owner address
package/dist/index.d.ts CHANGED
@@ -2,12 +2,12 @@ import { Chain, Address, Hex, Hash } from 'viem';
2
2
 
3
3
  interface ChainConfig {
4
4
  chain: Chain;
5
- rpcUrl: string;
5
+ rpcUrl?: string;
6
6
  bundlerUrl: string;
7
- entryPointAddress: Address;
8
- factoryAddress: Address;
9
- paymasterAddress: Address;
10
- usdcAddress: Address;
7
+ entryPointAddress?: Address;
8
+ factoryAddress?: Address;
9
+ paymasterAddress?: Address;
10
+ usdcAddress?: Address;
11
11
  }
12
12
  interface UserOperation {
13
13
  sender: Address;
@@ -54,6 +54,10 @@ declare class AccountAbstraction {
54
54
  private smartAccountAddress;
55
55
  private chainConfig;
56
56
  private publicClient;
57
+ private entryPointAddress;
58
+ private factoryAddress;
59
+ private paymasterAddress?;
60
+ private usdcAddress;
57
61
  constructor(chainConfig: ChainConfig);
58
62
  /**
59
63
  * Connect to MetaMask and get the owner address
package/dist/index.js CHANGED
@@ -162,15 +162,45 @@ var erc20Abi = [
162
162
  }
163
163
  ];
164
164
 
165
+ // src/deployments.ts
166
+ var DEPLOYMENTS = {
167
+ // Base Mainnet
168
+ 8453: {
169
+ entryPoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
170
+ factory: "0xe2584152891E4769025807DEa0cD611F135aDC68",
171
+ paymaster: "0x1e13Eb16C565E3f3FDe49A011755e50410bb1F95",
172
+ usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
173
+ },
174
+ // Base Sepolia
175
+ 84532: {
176
+ entryPoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
177
+ factory: "0x9406Cc6185a346906296840746125a0E44976454",
178
+ usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
179
+ }
180
+ };
181
+
165
182
  // src/AccountAbstraction.ts
166
183
  var AccountAbstraction = class {
167
184
  constructor(chainConfig) {
168
185
  this.owner = null;
169
186
  this.smartAccountAddress = null;
170
187
  this.chainConfig = chainConfig;
188
+ const chainId = chainConfig.chain.id;
189
+ const defaults = DEPLOYMENTS[chainId];
190
+ const entryPoint = chainConfig.entryPointAddress || defaults?.entryPoint;
191
+ if (!entryPoint) throw new Error(`EntryPoint address not found for chain ${chainId}`);
192
+ this.entryPointAddress = entryPoint;
193
+ const factory = chainConfig.factoryAddress || defaults?.factory;
194
+ if (!factory) throw new Error(`Factory address not found for chain ${chainId}`);
195
+ this.factoryAddress = factory;
196
+ const usdc = chainConfig.usdcAddress || defaults?.usdc;
197
+ if (!usdc) throw new Error(`USDC address not found for chain ${chainId}`);
198
+ this.usdcAddress = usdc;
199
+ this.paymasterAddress = chainConfig.paymasterAddress || defaults?.paymaster;
200
+ const rpcUrl = chainConfig.rpcUrl || chainConfig.chain.rpcUrls.default.http[0];
171
201
  this.publicClient = (0, import_viem.createPublicClient)({
172
202
  chain: chainConfig.chain,
173
- transport: (0, import_viem.http)(chainConfig.rpcUrl)
203
+ transport: (0, import_viem.http)(rpcUrl)
174
204
  });
175
205
  }
176
206
  /**
@@ -228,7 +258,7 @@ var AccountAbstraction = class {
228
258
  */
229
259
  async getSmartAccountAddress(owner) {
230
260
  const address = await this.publicClient.readContract({
231
- address: this.chainConfig.factoryAddress,
261
+ address: this.factoryAddress,
232
262
  abi: factoryAbi,
233
263
  functionName: "getAccountAddress",
234
264
  args: [owner, 0n]
@@ -256,7 +286,7 @@ var AccountAbstraction = class {
256
286
  throw new Error("Not connected");
257
287
  }
258
288
  return await this.publicClient.readContract({
259
- address: this.chainConfig.usdcAddress,
289
+ address: this.usdcAddress,
260
290
  abi: erc20Abi,
261
291
  functionName: "balanceOf",
262
292
  args: [this.smartAccountAddress]
@@ -270,7 +300,7 @@ var AccountAbstraction = class {
270
300
  throw new Error("Not connected");
271
301
  }
272
302
  return await this.publicClient.readContract({
273
- address: this.chainConfig.usdcAddress,
303
+ address: this.usdcAddress,
274
304
  abi: erc20Abi,
275
305
  functionName: "balanceOf",
276
306
  args: [this.owner]
@@ -284,7 +314,7 @@ var AccountAbstraction = class {
284
314
  throw new Error("Not connected");
285
315
  }
286
316
  return await this.publicClient.readContract({
287
- address: this.chainConfig.usdcAddress,
317
+ address: this.usdcAddress,
288
318
  abi: erc20Abi,
289
319
  functionName: "allowance",
290
320
  args: [this.owner, this.smartAccountAddress]
@@ -298,7 +328,7 @@ var AccountAbstraction = class {
298
328
  throw new Error("Not connected");
299
329
  }
300
330
  return await this.publicClient.readContract({
301
- address: this.chainConfig.entryPointAddress,
331
+ address: this.entryPointAddress,
302
332
  abi: entryPointAbi,
303
333
  functionName: "getNonce",
304
334
  args: [this.smartAccountAddress, 0n]
@@ -316,7 +346,7 @@ var AccountAbstraction = class {
316
346
  functionName: "createAccount",
317
347
  args: [this.owner, 0n]
318
348
  });
319
- return `${this.chainConfig.factoryAddress}${createAccountData.slice(2)}`;
349
+ return `${this.factoryAddress}${createAccountData.slice(2)}`;
320
350
  }
321
351
  /**
322
352
  * Estimate gas for a UserOperation
@@ -338,7 +368,7 @@ var AccountAbstraction = class {
338
368
  paymasterAndData: userOp.paymasterAndData || "0x",
339
369
  signature: "0x"
340
370
  },
341
- this.chainConfig.entryPointAddress
371
+ this.entryPointAddress
342
372
  ]
343
373
  })
344
374
  });
@@ -371,7 +401,7 @@ var AccountAbstraction = class {
371
401
  nonce,
372
402
  initCode,
373
403
  callData,
374
- paymasterAndData: this.chainConfig.paymasterAddress
404
+ paymasterAndData: this.paymasterAddress
375
405
  });
376
406
  return {
377
407
  sender: this.smartAccountAddress,
@@ -383,7 +413,7 @@ var AccountAbstraction = class {
383
413
  preVerificationGas: BigInt(gasEstimate.preVerificationGas),
384
414
  maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),
385
415
  maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),
386
- paymasterAndData: this.chainConfig.paymasterAddress,
416
+ paymasterAndData: this.paymasterAddress,
387
417
  signature: "0x"
388
418
  };
389
419
  }
@@ -406,7 +436,7 @@ var AccountAbstraction = class {
406
436
  nonce,
407
437
  initCode,
408
438
  callData,
409
- paymasterAndData: this.chainConfig.paymasterAddress
439
+ paymasterAndData: this.paymasterAddress
410
440
  });
411
441
  return {
412
442
  sender: this.smartAccountAddress,
@@ -418,7 +448,7 @@ var AccountAbstraction = class {
418
448
  preVerificationGas: BigInt(gasEstimate.preVerificationGas),
419
449
  maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),
420
450
  maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),
421
- paymasterAndData: this.chainConfig.paymasterAddress,
451
+ paymasterAndData: this.paymasterAddress,
422
452
  signature: "0x"
423
453
  };
424
454
  }
@@ -456,7 +486,7 @@ var AccountAbstraction = class {
456
486
  return (0, import_viem.keccak256)(
457
487
  (0, import_viem.encodeAbiParameters)(
458
488
  [{ type: "bytes32" }, { type: "address" }, { type: "uint256" }],
459
- [packedHash, this.chainConfig.entryPointAddress, BigInt(this.chainConfig.chain.id)]
489
+ [packedHash, this.entryPointAddress, BigInt(this.chainConfig.chain.id)]
460
490
  )
461
491
  );
462
492
  }
@@ -502,7 +532,7 @@ var AccountAbstraction = class {
502
532
  paymasterAndData: userOp.paymasterAndData,
503
533
  signature: userOp.signature
504
534
  },
505
- this.chainConfig.entryPointAddress
535
+ this.entryPointAddress
506
536
  ]
507
537
  })
508
538
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/AccountAbstraction.ts","../src/constants.ts"],"sourcesContent":["export * from \"./AccountAbstraction\";\nexport * from \"./types\";\nexport * from \"./constants\";\n","import {\n createPublicClient,\n http,\n encodeFunctionData,\n encodeAbiParameters,\n keccak256,\n type Address,\n type Hash,\n type Hex,\n type PublicClient\n} from \"viem\";\nimport {\n factoryAbi,\n entryPointAbi,\n smartAccountAbi,\n erc20Abi,\n} from \"./constants\";\nimport {\n type ChainConfig,\n type UserOperation,\n type GasEstimate,\n type UserOpReceipt,\n type ApprovalSupportResult\n} from \"./types\";\n\n/**\n * ERC-4337 Account Abstraction Client\n */\nexport class AccountAbstraction {\n private owner: Address | null = null;\n private smartAccountAddress: Address | null = null;\n private chainConfig: ChainConfig;\n private publicClient: PublicClient;\n\n constructor(chainConfig: ChainConfig) {\n this.chainConfig = chainConfig;\n this.publicClient = createPublicClient({\n chain: chainConfig.chain,\n transport: http(chainConfig.rpcUrl),\n });\n }\n\n /**\n * Connect to MetaMask and get the owner address\n */\n async connect(): Promise<{ owner: Address; smartAccount: Address }> {\n if (typeof window === \"undefined\" || !window.ethereum) {\n throw new Error(\"MetaMask is not installed\");\n }\n\n // Request account access\n const accounts = (await window.ethereum.request({\n method: \"eth_requestAccounts\",\n })) as string[];\n\n if (!accounts || accounts.length === 0) {\n throw new Error(\"No accounts found\");\n }\n\n // Check network\n const chainId = (await window.ethereum.request({\n method: \"eth_chainId\",\n })) as string;\n\n const targetChainId = this.chainConfig.chain.id;\n\n if (parseInt(chainId, 16) !== targetChainId) {\n // Switch to configured chain\n try {\n await window.ethereum.request({\n method: \"wallet_switchEthereumChain\",\n params: [{ chainId: \"0x\" + targetChainId.toString(16) }],\n });\n } catch (switchError: unknown) {\n const error = switchError as { code?: number };\n // Chain not added, add it\n if (error.code === 4902) {\n await window.ethereum.request({\n method: \"wallet_addEthereumChain\",\n params: [\n {\n chainId: \"0x\" + targetChainId.toString(16),\n chainName: this.chainConfig.chain.name,\n nativeCurrency: this.chainConfig.chain.nativeCurrency,\n rpcUrls: [this.chainConfig.rpcUrl],\n blockExplorerUrls: this.chainConfig.chain.blockExplorers?.default?.url\n ? [this.chainConfig.chain.blockExplorers.default.url]\n : [],\n },\n ],\n });\n } else {\n throw switchError;\n }\n }\n }\n\n this.owner = accounts[0] as Address;\n this.smartAccountAddress = await this.getSmartAccountAddress(this.owner);\n\n return {\n owner: this.owner,\n smartAccount: this.smartAccountAddress,\n };\n }\n\n /**\n * Get the Smart Account address for an owner (counterfactual)\n */\n async getSmartAccountAddress(owner: Address): Promise<Address> {\n const address = await this.publicClient.readContract({\n address: this.chainConfig.factoryAddress,\n abi: factoryAbi,\n functionName: \"getAccountAddress\",\n args: [owner, 0n], // salt = 0\n }) as Address;\n return address;\n }\n\n /**\n * Check if the Smart Account is deployed\n */\n async isAccountDeployed(): Promise<boolean> {\n if (!this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n const code = await this.publicClient.getCode({\n address: this.smartAccountAddress,\n });\n return code !== undefined && code !== \"0x\";\n }\n\n\n /**\n * Get the USDC balance of the Smart Account\n */\n async getUsdcBalance(): Promise<bigint> {\n if (!this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n return await this.publicClient.readContract({\n address: this.chainConfig.usdcAddress,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.smartAccountAddress],\n }) as bigint;\n }\n\n\n /**\n * Get the EOA's USDC balance\n */\n async getEoaUsdcBalance(): Promise<bigint> {\n if (!this.owner) {\n throw new Error(\"Not connected\");\n }\n\n return await this.publicClient.readContract({\n address: this.chainConfig.usdcAddress,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.owner],\n }) as bigint;\n }\n\n /**\n * Get the allowance of the Smart Account to spend the EOA's USDC\n */\n async getAllowance(): Promise<bigint> {\n if (!this.owner || !this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n return await this.publicClient.readContract({\n address: this.chainConfig.usdcAddress,\n abi: erc20Abi,\n functionName: \"allowance\",\n args: [this.owner, this.smartAccountAddress],\n }) as bigint;\n }\n\n /**\n * Get the nonce for the Smart Account\n */\n async getNonce(): Promise<bigint> {\n if (!this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n return await this.publicClient.readContract({\n address: this.chainConfig.entryPointAddress,\n abi: entryPointAbi,\n functionName: \"getNonce\",\n args: [this.smartAccountAddress, 0n],\n }) as bigint;\n }\n\n /**\n * Build initCode for account deployment\n */\n buildInitCode(): Hex {\n if (!this.owner) {\n throw new Error(\"Not connected\");\n }\n\n const createAccountData = encodeFunctionData({\n abi: factoryAbi,\n functionName: \"createAccount\",\n args: [this.owner, 0n],\n });\n\n return `${this.chainConfig.factoryAddress}${createAccountData.slice(2)}` as Hex;\n }\n\n\n /**\n * Estimate gas for a UserOperation\n */\n async estimateGas(userOp: Partial<UserOperation>): Promise<GasEstimate> {\n const response = await fetch(this.chainConfig.bundlerUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"eth_estimateUserOperationGas\",\n params: [\n {\n sender: userOp.sender,\n nonce: userOp.nonce ? \"0x\" + userOp.nonce.toString(16) : \"0x0\",\n initCode: userOp.initCode || \"0x\",\n callData: userOp.callData || \"0x\",\n paymasterAndData: userOp.paymasterAndData || \"0x\",\n signature: \"0x\",\n },\n this.chainConfig.entryPointAddress,\n ],\n }),\n });\n\n const result = await response.json();\n if (result.error) {\n throw new Error(result.error.message);\n }\n\n return result.result;\n }\n\n\n /**\n * Build a UserOperation for Batched Execution (e.g. USDC Transfer + Fee)\n */\n async buildUserOperationBatch(\n transactions: { target: Address; value: bigint; data: Hex }[]\n ): Promise<UserOperation> {\n if (!this.owner || !this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n const isDeployed = await this.isAccountDeployed();\n const initCode = isDeployed ? \"0x\" : this.buildInitCode();\n\n // Prepare arrays for executeBatch\n const targets = transactions.map((tx) => tx.target);\n const values = transactions.map((tx) => tx.value);\n const datas = transactions.map((tx) => tx.data);\n\n // Encode callData for executeBatch\n const callData = encodeFunctionData({\n abi: smartAccountAbi,\n functionName: \"executeBatch\",\n args: [targets, values, datas],\n });\n\n const nonce = await this.getNonce();\n\n // Estimate gas\n const gasEstimate = await this.estimateGas({\n sender: this.smartAccountAddress,\n nonce,\n initCode: initCode as Hex,\n callData,\n paymasterAndData: this.chainConfig.paymasterAddress as Hex,\n });\n\n return {\n sender: this.smartAccountAddress,\n nonce,\n initCode: initCode as Hex,\n callData,\n callGasLimit: BigInt(gasEstimate.callGasLimit),\n verificationGasLimit: BigInt(gasEstimate.verificationGasLimit),\n preVerificationGas: BigInt(gasEstimate.preVerificationGas),\n maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),\n maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),\n paymasterAndData: this.chainConfig.paymasterAddress as Hex,\n signature: \"0x\",\n };\n }\n\n /**\n * Build a UserOperation to ONLY deploy the account (empty callData)\n */\n async buildDeployUserOperation(): Promise<UserOperation> {\n if (!this.owner || !this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n const isDeployed = await this.isAccountDeployed();\n if (isDeployed) {\n throw new Error(\"Account is already deployed\");\n }\n\n const initCode = this.buildInitCode();\n const callData = \"0x\"; // Empty callData for deployment only\n const nonce = await this.getNonce();\n\n // Estimate gas\n const gasEstimate = await this.estimateGas({\n sender: this.smartAccountAddress,\n nonce,\n initCode: initCode as Hex,\n callData,\n paymasterAndData: this.chainConfig.paymasterAddress as Hex,\n });\n\n return {\n sender: this.smartAccountAddress,\n nonce,\n initCode: initCode as Hex,\n callData,\n callGasLimit: BigInt(gasEstimate.callGasLimit),\n verificationGasLimit: BigInt(gasEstimate.verificationGasLimit),\n preVerificationGas: BigInt(gasEstimate.preVerificationGas),\n maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),\n maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),\n paymasterAndData: this.chainConfig.paymasterAddress as Hex,\n signature: \"0x\",\n };\n }\n\n /**\n * Calculate the UserOperation hash\n */\n getUserOpHash(userOp: UserOperation): Hex {\n const packed = encodeAbiParameters(\n [\n { type: \"address\" },\n { type: \"uint256\" },\n { type: \"bytes32\" },\n { type: \"bytes32\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"bytes32\" },\n ],\n [\n userOp.sender,\n userOp.nonce,\n keccak256(userOp.initCode),\n keccak256(userOp.callData),\n userOp.callGasLimit,\n userOp.verificationGasLimit,\n userOp.preVerificationGas,\n userOp.maxFeePerGas,\n userOp.maxPriorityFeePerGas,\n keccak256(userOp.paymasterAndData),\n ]\n );\n\n const packedHash = keccak256(packed);\n\n return keccak256(\n encodeAbiParameters(\n [{ type: \"bytes32\" }, { type: \"address\" }, { type: \"uint256\" }],\n [packedHash, this.chainConfig.entryPointAddress, BigInt(this.chainConfig.chain.id)]\n )\n );\n }\n\n /**\n * Sign a UserOperation with MetaMask\n */\n async signUserOperation(userOp: UserOperation): Promise<UserOperation> {\n if (!this.owner) {\n throw new Error(\"Not connected\");\n }\n\n const userOpHash = this.getUserOpHash(userOp);\n\n // Sign with MetaMask using personal_sign (EIP-191)\n const signature = (await window.ethereum!.request({\n method: \"personal_sign\",\n params: [userOpHash, this.owner],\n })) as Hex;\n\n return {\n ...userOp,\n signature,\n };\n }\n\n /**\n * Send a signed UserOperation to the bundler\n */\n async sendUserOperation(userOp: UserOperation): Promise<Hash> {\n const response = await fetch(this.chainConfig.bundlerUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"eth_sendUserOperation\",\n params: [\n {\n sender: userOp.sender,\n nonce: \"0x\" + userOp.nonce.toString(16),\n initCode: userOp.initCode,\n callData: userOp.callData,\n callGasLimit: \"0x\" + userOp.callGasLimit.toString(16),\n verificationGasLimit: \"0x\" + userOp.verificationGasLimit.toString(16),\n preVerificationGas: \"0x\" + userOp.preVerificationGas.toString(16),\n maxFeePerGas: \"0x\" + userOp.maxFeePerGas.toString(16),\n maxPriorityFeePerGas: \"0x\" + userOp.maxPriorityFeePerGas.toString(16),\n paymasterAndData: userOp.paymasterAndData,\n signature: userOp.signature,\n },\n this.chainConfig.entryPointAddress,\n ],\n }),\n });\n\n const result = await response.json();\n if (result.error) {\n throw new Error(result.error.message);\n }\n\n return result.result as Hash;\n }\n\n /**\n * Wait for a UserOperation to be confirmed\n */\n async waitForUserOperation(\n userOpHash: Hash,\n timeout = 60000\n ): Promise<UserOpReceipt> {\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeout) {\n const response = await fetch(this.chainConfig.bundlerUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"eth_getUserOperationReceipt\",\n params: [userOpHash],\n }),\n });\n\n const result = await response.json();\n if (result.result) {\n return result.result as UserOpReceipt;\n }\n\n // Wait 2 seconds before polling again\n await new Promise((resolve) => setTimeout(resolve, 2000));\n }\n\n throw new Error(\"Timeout waiting for UserOperation\");\n }\n\n\n /**\n * Request support for token approval (fund if needed)\n */\n async requestApprovalSupport(\n token: Address,\n spender: Address,\n amount: bigint\n ): Promise<ApprovalSupportResult> {\n if (!this.owner) {\n throw new Error(\"Not connected\");\n }\n\n const response = await fetch(this.chainConfig.bundlerUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"pm_requestApprovalSupport\",\n params: [token, this.owner, spender, amount.toString()],\n }),\n });\n\n const result = await response.json();\n if (result.error) {\n throw new Error(result.error.message);\n }\n\n return result.result;\n }\n\n // Getters\n getOwner(): Address | null {\n return this.owner;\n }\n\n getSmartAccount(): Address | null {\n return this.smartAccountAddress;\n }\n}\n\n// Global window types for MetaMask\ndeclare global {\n interface Window {\n ethereum?: {\n request: (args: { method: string; params?: unknown[] }) => Promise<unknown>;\n on: (event: string, callback: (args: unknown) => void) => void;\n removeListener: (event: string, callback: (args: unknown) => void) => void;\n };\n }\n}\n","export const DEFAULT_ENTRYPOINT = \"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789\";\nexport const DEFAULT_FACTORY = \"0x9406Cc6185a346906296840746125a0E44976454\"; // SimpleAccountFactory v0.6\n\nexport const factoryAbi = [\n {\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"salt\", type: \"uint256\" },\n ],\n name: \"getAccountAddress\",\n outputs: [{ name: \"\", type: \"address\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"salt\", type: \"uint256\" },\n ],\n name: \"isAccountDeployed\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"salt\", type: \"uint256\" },\n ],\n name: \"createAccount\",\n outputs: [{ name: \"account\", type: \"address\" }],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n] as const;\n\nexport const entryPointAbi = [\n {\n inputs: [\n { name: \"sender\", type: \"address\" },\n { name: \"key\", type: \"uint192\" },\n ],\n name: \"getNonce\",\n outputs: [{ name: \"nonce\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\nexport const smartAccountAbi = [\n {\n inputs: [\n { name: \"target\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"data\", type: \"bytes\" },\n ],\n name: \"execute\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"targets\", type: \"address[]\" },\n { name: \"values\", type: \"uint256[]\" },\n { name: \"datas\", type: \"bytes[]\" },\n ],\n name: \"executeBatch\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n] as const;\n\nexport const erc20Abi = [\n {\n inputs: [{ name: \"account\", type: \"address\" }],\n name: \"balanceOf\",\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"to\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n name: \"transfer\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"spender\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n name: \"approve\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n ],\n name: \"allowance\",\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n name: \"transferFrom\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [],\n name: \"decimals\",\n outputs: [{ name: \"\", type: \"uint8\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,kBAUO;;;ACVA,IAAM,qBAAqB;AAC3B,IAAM,kBAAkB;AAExB,IAAM,aAAa;AAAA,EACtB;AAAA,IACI,QAAQ;AAAA,MACJ,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,MACjC,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,IACpC;AAAA,IACA,MAAM;AAAA,IACN,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,IACvC,iBAAiB;AAAA,IACjB,MAAM;AAAA,EACV;AAAA,EACA;AAAA,IACI,QAAQ;AAAA,MACJ,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,MACjC,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,IACpC;AAAA,IACA,MAAM;AAAA,IACN,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,OAAO,CAAC;AAAA,IACpC,iBAAiB;AAAA,IACjB,MAAM;AAAA,EACV;AAAA,EACA;AAAA,IACI,QAAQ;AAAA,MACJ,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,MACjC,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,IACpC;AAAA,IACA,MAAM;AAAA,IACN,SAAS,CAAC,EAAE,MAAM,WAAW,MAAM,UAAU,CAAC;AAAA,IAC9C,iBAAiB;AAAA,IACjB,MAAM;AAAA,EACV;AACJ;AAEO,IAAM,gBAAgB;AAAA,EACzB;AAAA,IACI,QAAQ;AAAA,MACJ,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,MAClC,EAAE,MAAM,OAAO,MAAM,UAAU;AAAA,IACnC;AAAA,IACA,MAAM;AAAA,IACN,SAAS,CAAC,EAAE,MAAM,SAAS,MAAM,UAAU,CAAC;AAAA,IAC5C,iBAAiB;AAAA,IACjB,MAAM;AAAA,EACV;AACJ;AAEO,IAAM,kBAAkB;AAAA,EAC3B;AAAA,IACI,QAAQ;AAAA,MACJ,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,MAClC,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,MACjC,EAAE,MAAM,QAAQ,MAAM,QAAQ;AAAA,IAClC;AAAA,IACA,MAAM;AAAA,IACN,SAAS,CAAC;AAAA,IACV,iBAAiB;AAAA,IACjB,MAAM;AAAA,EACV;AAAA,EACA;AAAA,IACI,QAAQ;AAAA,MACJ,EAAE,MAAM,WAAW,MAAM,YAAY;AAAA,MACrC,EAAE,MAAM,UAAU,MAAM,YAAY;AAAA,MACpC,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,IACrC;AAAA,IACA,MAAM;AAAA,IACN,SAAS,CAAC;AAAA,IACV,iBAAiB;AAAA,IACjB,MAAM;AAAA,EACV;AACJ;AAEO,IAAM,WAAW;AAAA,EACpB;AAAA,IACI,QAAQ,CAAC,EAAE,MAAM,WAAW,MAAM,UAAU,CAAC;AAAA,IAC7C,MAAM;AAAA,IACN,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,IACvC,iBAAiB;AAAA,IACjB,MAAM;AAAA,EACV;AAAA,EACA;AAAA,IACI,QAAQ;AAAA,MACJ,EAAE,MAAM,MAAM,MAAM,UAAU;AAAA,MAC9B,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,IACtC;AAAA,IACA,MAAM;AAAA,IACN,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,OAAO,CAAC;AAAA,IACpC,iBAAiB;AAAA,IACjB,MAAM;AAAA,EACV;AAAA,EACA;AAAA,IACI,QAAQ;AAAA,MACJ,EAAE,MAAM,WAAW,MAAM,UAAU;AAAA,MACnC,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,IACtC;AAAA,IACA,MAAM;AAAA,IACN,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,OAAO,CAAC;AAAA,IACpC,iBAAiB;AAAA,IACjB,MAAM;AAAA,EACV;AAAA,EACA;AAAA,IACI,QAAQ;AAAA,MACJ,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,MACjC,EAAE,MAAM,WAAW,MAAM,UAAU;AAAA,IACvC;AAAA,IACA,MAAM;AAAA,IACN,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,IACvC,iBAAiB;AAAA,IACjB,MAAM;AAAA,EACV;AAAA,EACA;AAAA,IACI,QAAQ;AAAA,MACJ,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,MAChC,EAAE,MAAM,MAAM,MAAM,UAAU;AAAA,MAC9B,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,IACtC;AAAA,IACA,MAAM;AAAA,IACN,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,OAAO,CAAC;AAAA,IACpC,iBAAiB;AAAA,IACjB,MAAM;AAAA,EACV;AAAA,EACA;AAAA,IACI,QAAQ,CAAC;AAAA,IACT,MAAM;AAAA,IACN,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,QAAQ,CAAC;AAAA,IACrC,iBAAiB;AAAA,IACjB,MAAM;AAAA,EACV;AACJ;;;ADtGO,IAAM,qBAAN,MAAyB;AAAA,EAM5B,YAAY,aAA0B;AALtC,SAAQ,QAAwB;AAChC,SAAQ,sBAAsC;AAK1C,SAAK,cAAc;AACnB,SAAK,mBAAe,gCAAmB;AAAA,MACnC,OAAO,YAAY;AAAA,MACnB,eAAW,kBAAK,YAAY,MAAM;AAAA,IACtC,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAA8D;AAChE,QAAI,OAAO,WAAW,eAAe,CAAC,OAAO,UAAU;AACnD,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC/C;AAGA,UAAM,WAAY,MAAM,OAAO,SAAS,QAAQ;AAAA,MAC5C,QAAQ;AAAA,IACZ,CAAC;AAED,QAAI,CAAC,YAAY,SAAS,WAAW,GAAG;AACpC,YAAM,IAAI,MAAM,mBAAmB;AAAA,IACvC;AAGA,UAAM,UAAW,MAAM,OAAO,SAAS,QAAQ;AAAA,MAC3C,QAAQ;AAAA,IACZ,CAAC;AAED,UAAM,gBAAgB,KAAK,YAAY,MAAM;AAE7C,QAAI,SAAS,SAAS,EAAE,MAAM,eAAe;AAEzC,UAAI;AACA,cAAM,OAAO,SAAS,QAAQ;AAAA,UAC1B,QAAQ;AAAA,UACR,QAAQ,CAAC,EAAE,SAAS,OAAO,cAAc,SAAS,EAAE,EAAE,CAAC;AAAA,QAC3D,CAAC;AAAA,MACL,SAAS,aAAsB;AAC3B,cAAM,QAAQ;AAEd,YAAI,MAAM,SAAS,MAAM;AACrB,gBAAM,OAAO,SAAS,QAAQ;AAAA,YAC1B,QAAQ;AAAA,YACR,QAAQ;AAAA,cACJ;AAAA,gBACI,SAAS,OAAO,cAAc,SAAS,EAAE;AAAA,gBACzC,WAAW,KAAK,YAAY,MAAM;AAAA,gBAClC,gBAAgB,KAAK,YAAY,MAAM;AAAA,gBACvC,SAAS,CAAC,KAAK,YAAY,MAAM;AAAA,gBACjC,mBAAmB,KAAK,YAAY,MAAM,gBAAgB,SAAS,MAC7D,CAAC,KAAK,YAAY,MAAM,eAAe,QAAQ,GAAG,IAClD,CAAC;AAAA,cACX;AAAA,YACJ;AAAA,UACJ,CAAC;AAAA,QACL,OAAO;AACH,gBAAM;AAAA,QACV;AAAA,MACJ;AAAA,IACJ;AAEA,SAAK,QAAQ,SAAS,CAAC;AACvB,SAAK,sBAAsB,MAAM,KAAK,uBAAuB,KAAK,KAAK;AAEvE,WAAO;AAAA,MACH,OAAO,KAAK;AAAA,MACZ,cAAc,KAAK;AAAA,IACvB;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,uBAAuB,OAAkC;AAC3D,UAAM,UAAU,MAAM,KAAK,aAAa,aAAa;AAAA,MACjD,SAAS,KAAK,YAAY;AAAA,MAC1B,KAAK;AAAA,MACL,cAAc;AAAA,MACd,MAAM,CAAC,OAAO,EAAE;AAAA;AAAA,IACpB,CAAC;AACD,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBAAsC;AACxC,QAAI,CAAC,KAAK,qBAAqB;AAC3B,YAAM,IAAI,MAAM,eAAe;AAAA,IACnC;AAEA,UAAM,OAAO,MAAM,KAAK,aAAa,QAAQ;AAAA,MACzC,SAAS,KAAK;AAAA,IAClB,CAAC;AACD,WAAO,SAAS,UAAa,SAAS;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,iBAAkC;AACpC,QAAI,CAAC,KAAK,qBAAqB;AAC3B,YAAM,IAAI,MAAM,eAAe;AAAA,IACnC;AAEA,WAAO,MAAM,KAAK,aAAa,aAAa;AAAA,MACxC,SAAS,KAAK,YAAY;AAAA,MAC1B,KAAK;AAAA,MACL,cAAc;AAAA,MACd,MAAM,CAAC,KAAK,mBAAmB;AAAA,IACnC,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,oBAAqC;AACvC,QAAI,CAAC,KAAK,OAAO;AACb,YAAM,IAAI,MAAM,eAAe;AAAA,IACnC;AAEA,WAAO,MAAM,KAAK,aAAa,aAAa;AAAA,MACxC,SAAS,KAAK,YAAY;AAAA,MAC1B,KAAK;AAAA,MACL,cAAc;AAAA,MACd,MAAM,CAAC,KAAK,KAAK;AAAA,IACrB,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAgC;AAClC,QAAI,CAAC,KAAK,SAAS,CAAC,KAAK,qBAAqB;AAC1C,YAAM,IAAI,MAAM,eAAe;AAAA,IACnC;AAEA,WAAO,MAAM,KAAK,aAAa,aAAa;AAAA,MACxC,SAAS,KAAK,YAAY;AAAA,MAC1B,KAAK;AAAA,MACL,cAAc;AAAA,MACd,MAAM,CAAC,KAAK,OAAO,KAAK,mBAAmB;AAAA,IAC/C,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAA4B;AAC9B,QAAI,CAAC,KAAK,qBAAqB;AAC3B,YAAM,IAAI,MAAM,eAAe;AAAA,IACnC;AAEA,WAAO,MAAM,KAAK,aAAa,aAAa;AAAA,MACxC,SAAS,KAAK,YAAY;AAAA,MAC1B,KAAK;AAAA,MACL,cAAc;AAAA,MACd,MAAM,CAAC,KAAK,qBAAqB,EAAE;AAAA,IACvC,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAqB;AACjB,QAAI,CAAC,KAAK,OAAO;AACb,YAAM,IAAI,MAAM,eAAe;AAAA,IACnC;AAEA,UAAM,wBAAoB,gCAAmB;AAAA,MACzC,KAAK;AAAA,MACL,cAAc;AAAA,MACd,MAAM,CAAC,KAAK,OAAO,EAAE;AAAA,IACzB,CAAC;AAED,WAAO,GAAG,KAAK,YAAY,cAAc,GAAG,kBAAkB,MAAM,CAAC,CAAC;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAY,QAAsD;AACpE,UAAM,WAAW,MAAM,MAAM,KAAK,YAAY,YAAY;AAAA,MACtD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU;AAAA,QACjB,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,QAAQ;AAAA,UACJ;AAAA,YACI,QAAQ,OAAO;AAAA,YACf,OAAO,OAAO,QAAQ,OAAO,OAAO,MAAM,SAAS,EAAE,IAAI;AAAA,YACzD,UAAU,OAAO,YAAY;AAAA,YAC7B,UAAU,OAAO,YAAY;AAAA,YAC7B,kBAAkB,OAAO,oBAAoB;AAAA,YAC7C,WAAW;AAAA,UACf;AAAA,UACA,KAAK,YAAY;AAAA,QACrB;AAAA,MACJ,CAAC;AAAA,IACL,CAAC;AAED,UAAM,SAAS,MAAM,SAAS,KAAK;AACnC,QAAI,OAAO,OAAO;AACd,YAAM,IAAI,MAAM,OAAO,MAAM,OAAO;AAAA,IACxC;AAEA,WAAO,OAAO;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,wBACF,cACsB;AACtB,QAAI,CAAC,KAAK,SAAS,CAAC,KAAK,qBAAqB;AAC1C,YAAM,IAAI,MAAM,eAAe;AAAA,IACnC;AAEA,UAAM,aAAa,MAAM,KAAK,kBAAkB;AAChD,UAAM,WAAW,aAAa,OAAO,KAAK,cAAc;AAGxD,UAAM,UAAU,aAAa,IAAI,CAAC,OAAO,GAAG,MAAM;AAClD,UAAM,SAAS,aAAa,IAAI,CAAC,OAAO,GAAG,KAAK;AAChD,UAAM,QAAQ,aAAa,IAAI,CAAC,OAAO,GAAG,IAAI;AAG9C,UAAM,eAAW,gCAAmB;AAAA,MAChC,KAAK;AAAA,MACL,cAAc;AAAA,MACd,MAAM,CAAC,SAAS,QAAQ,KAAK;AAAA,IACjC,CAAC;AAED,UAAM,QAAQ,MAAM,KAAK,SAAS;AAGlC,UAAM,cAAc,MAAM,KAAK,YAAY;AAAA,MACvC,QAAQ,KAAK;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA,kBAAkB,KAAK,YAAY;AAAA,IACvC,CAAC;AAED,WAAO;AAAA,MACH,QAAQ,KAAK;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA,cAAc,OAAO,YAAY,YAAY;AAAA,MAC7C,sBAAsB,OAAO,YAAY,oBAAoB;AAAA,MAC7D,oBAAoB,OAAO,YAAY,kBAAkB;AAAA,MACzD,cAAc,OAAO,YAAY,YAAY;AAAA,MAC7C,sBAAsB,OAAO,YAAY,oBAAoB;AAAA,MAC7D,kBAAkB,KAAK,YAAY;AAAA,MACnC,WAAW;AAAA,IACf;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,2BAAmD;AACrD,QAAI,CAAC,KAAK,SAAS,CAAC,KAAK,qBAAqB;AAC1C,YAAM,IAAI,MAAM,eAAe;AAAA,IACnC;AAEA,UAAM,aAAa,MAAM,KAAK,kBAAkB;AAChD,QAAI,YAAY;AACZ,YAAM,IAAI,MAAM,6BAA6B;AAAA,IACjD;AAEA,UAAM,WAAW,KAAK,cAAc;AACpC,UAAM,WAAW;AACjB,UAAM,QAAQ,MAAM,KAAK,SAAS;AAGlC,UAAM,cAAc,MAAM,KAAK,YAAY;AAAA,MACvC,QAAQ,KAAK;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA,kBAAkB,KAAK,YAAY;AAAA,IACvC,CAAC;AAED,WAAO;AAAA,MACH,QAAQ,KAAK;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA,cAAc,OAAO,YAAY,YAAY;AAAA,MAC7C,sBAAsB,OAAO,YAAY,oBAAoB;AAAA,MAC7D,oBAAoB,OAAO,YAAY,kBAAkB;AAAA,MACzD,cAAc,OAAO,YAAY,YAAY;AAAA,MAC7C,sBAAsB,OAAO,YAAY,oBAAoB;AAAA,MAC7D,kBAAkB,KAAK,YAAY;AAAA,MACnC,WAAW;AAAA,IACf;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,QAA4B;AACtC,UAAM,aAAS;AAAA,MACX;AAAA,QACI,EAAE,MAAM,UAAU;AAAA,QAClB,EAAE,MAAM,UAAU;AAAA,QAClB,EAAE,MAAM,UAAU;AAAA,QAClB,EAAE,MAAM,UAAU;AAAA,QAClB,EAAE,MAAM,UAAU;AAAA,QAClB,EAAE,MAAM,UAAU;AAAA,QAClB,EAAE,MAAM,UAAU;AAAA,QAClB,EAAE,MAAM,UAAU;AAAA,QAClB,EAAE,MAAM,UAAU;AAAA,QAClB,EAAE,MAAM,UAAU;AAAA,MACtB;AAAA,MACA;AAAA,QACI,OAAO;AAAA,QACP,OAAO;AAAA,YACP,uBAAU,OAAO,QAAQ;AAAA,YACzB,uBAAU,OAAO,QAAQ;AAAA,QACzB,OAAO;AAAA,QACP,OAAO;AAAA,QACP,OAAO;AAAA,QACP,OAAO;AAAA,QACP,OAAO;AAAA,YACP,uBAAU,OAAO,gBAAgB;AAAA,MACrC;AAAA,IACJ;AAEA,UAAM,iBAAa,uBAAU,MAAM;AAEnC,eAAO;AAAA,UACH;AAAA,QACI,CAAC,EAAE,MAAM,UAAU,GAAG,EAAE,MAAM,UAAU,GAAG,EAAE,MAAM,UAAU,CAAC;AAAA,QAC9D,CAAC,YAAY,KAAK,YAAY,mBAAmB,OAAO,KAAK,YAAY,MAAM,EAAE,CAAC;AAAA,MACtF;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,QAA+C;AACnE,QAAI,CAAC,KAAK,OAAO;AACb,YAAM,IAAI,MAAM,eAAe;AAAA,IACnC;AAEA,UAAM,aAAa,KAAK,cAAc,MAAM;AAG5C,UAAM,YAAa,MAAM,OAAO,SAAU,QAAQ;AAAA,MAC9C,QAAQ;AAAA,MACR,QAAQ,CAAC,YAAY,KAAK,KAAK;AAAA,IACnC,CAAC;AAED,WAAO;AAAA,MACH,GAAG;AAAA,MACH;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,QAAsC;AAC1D,UAAM,WAAW,MAAM,MAAM,KAAK,YAAY,YAAY;AAAA,MACtD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU;AAAA,QACjB,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,QAAQ;AAAA,UACJ;AAAA,YACI,QAAQ,OAAO;AAAA,YACf,OAAO,OAAO,OAAO,MAAM,SAAS,EAAE;AAAA,YACtC,UAAU,OAAO;AAAA,YACjB,UAAU,OAAO;AAAA,YACjB,cAAc,OAAO,OAAO,aAAa,SAAS,EAAE;AAAA,YACpD,sBAAsB,OAAO,OAAO,qBAAqB,SAAS,EAAE;AAAA,YACpE,oBAAoB,OAAO,OAAO,mBAAmB,SAAS,EAAE;AAAA,YAChE,cAAc,OAAO,OAAO,aAAa,SAAS,EAAE;AAAA,YACpD,sBAAsB,OAAO,OAAO,qBAAqB,SAAS,EAAE;AAAA,YACpE,kBAAkB,OAAO;AAAA,YACzB,WAAW,OAAO;AAAA,UACtB;AAAA,UACA,KAAK,YAAY;AAAA,QACrB;AAAA,MACJ,CAAC;AAAA,IACL,CAAC;AAED,UAAM,SAAS,MAAM,SAAS,KAAK;AACnC,QAAI,OAAO,OAAO;AACd,YAAM,IAAI,MAAM,OAAO,MAAM,OAAO;AAAA,IACxC;AAEA,WAAO,OAAO;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,qBACF,YACA,UAAU,KACY;AACtB,UAAM,YAAY,KAAK,IAAI;AAE3B,WAAO,KAAK,IAAI,IAAI,YAAY,SAAS;AACrC,YAAM,WAAW,MAAM,MAAM,KAAK,YAAY,YAAY;AAAA,QACtD,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU;AAAA,UACjB,SAAS;AAAA,UACT,IAAI;AAAA,UACJ,QAAQ;AAAA,UACR,QAAQ,CAAC,UAAU;AAAA,QACvB,CAAC;AAAA,MACL,CAAC;AAED,YAAM,SAAS,MAAM,SAAS,KAAK;AACnC,UAAI,OAAO,QAAQ;AACf,eAAO,OAAO;AAAA,MAClB;AAGA,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAI,CAAC;AAAA,IAC5D;AAEA,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,uBACF,OACA,SACA,QAC8B;AAC9B,QAAI,CAAC,KAAK,OAAO;AACb,YAAM,IAAI,MAAM,eAAe;AAAA,IACnC;AAEA,UAAM,WAAW,MAAM,MAAM,KAAK,YAAY,YAAY;AAAA,MACtD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU;AAAA,QACjB,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,QAAQ,CAAC,OAAO,KAAK,OAAO,SAAS,OAAO,SAAS,CAAC;AAAA,MAC1D,CAAC;AAAA,IACL,CAAC;AAED,UAAM,SAAS,MAAM,SAAS,KAAK;AACnC,QAAI,OAAO,OAAO;AACd,YAAM,IAAI,MAAM,OAAO,MAAM,OAAO;AAAA,IACxC;AAEA,WAAO,OAAO;AAAA,EAClB;AAAA;AAAA,EAGA,WAA2B;AACvB,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,kBAAkC;AAC9B,WAAO,KAAK;AAAA,EAChB;AACJ;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/AccountAbstraction.ts","../src/constants.ts","../src/deployments.ts"],"sourcesContent":["export * from \"./AccountAbstraction\";\nexport * from \"./types\";\nexport * from \"./constants\";\n","import {\n createPublicClient,\n http,\n encodeFunctionData,\n encodeAbiParameters,\n keccak256,\n type Address,\n type Hash,\n type Hex,\n type PublicClient\n} from \"viem\";\nimport {\n factoryAbi,\n entryPointAbi,\n smartAccountAbi,\n erc20Abi,\n} from \"./constants\";\nimport {\n type ChainConfig,\n type UserOperation,\n type GasEstimate,\n type UserOpReceipt,\n type ApprovalSupportResult\n} from \"./types\";\nimport { DEPLOYMENTS } from \"./deployments\";\n\n/**\n * ERC-4337 Account Abstraction Client\n */\nexport class AccountAbstraction {\n private owner: Address | null = null;\n private smartAccountAddress: Address | null = null;\n private chainConfig: ChainConfig;\n private publicClient: PublicClient;\n\n // Resolved addresses\n private entryPointAddress: Address;\n private factoryAddress: Address;\n private paymasterAddress?: Address;\n private usdcAddress: Address;\n\n constructor(chainConfig: ChainConfig) {\n this.chainConfig = chainConfig;\n const chainId = chainConfig.chain.id;\n const defaults = DEPLOYMENTS[chainId];\n\n // Resolve addresses (Config > Defaults > Error)\n const entryPoint = chainConfig.entryPointAddress || defaults?.entryPoint;\n if (!entryPoint) throw new Error(`EntryPoint address not found for chain ${chainId}`);\n this.entryPointAddress = entryPoint;\n\n const factory = chainConfig.factoryAddress || defaults?.factory;\n if (!factory) throw new Error(`Factory address not found for chain ${chainId}`);\n this.factoryAddress = factory;\n\n const usdc = chainConfig.usdcAddress || defaults?.usdc;\n if (!usdc) throw new Error(`USDC address not found for chain ${chainId}`);\n this.usdcAddress = usdc;\n\n this.paymasterAddress = chainConfig.paymasterAddress || defaults?.paymaster;\n\n // Use provided RPC or default from chain\n const rpcUrl = chainConfig.rpcUrl || chainConfig.chain.rpcUrls.default.http[0];\n\n this.publicClient = createPublicClient({\n chain: chainConfig.chain,\n transport: http(rpcUrl),\n });\n }\n\n /**\n * Connect to MetaMask and get the owner address\n */\n async connect(): Promise<{ owner: Address; smartAccount: Address }> {\n if (typeof window === \"undefined\" || !window.ethereum) {\n throw new Error(\"MetaMask is not installed\");\n }\n\n // Request account access\n const accounts = (await window.ethereum.request({\n method: \"eth_requestAccounts\",\n })) as string[];\n\n if (!accounts || accounts.length === 0) {\n throw new Error(\"No accounts found\");\n }\n\n // Check network\n const chainId = (await window.ethereum.request({\n method: \"eth_chainId\",\n })) as string;\n\n const targetChainId = this.chainConfig.chain.id;\n\n if (parseInt(chainId, 16) !== targetChainId) {\n // Switch to configured chain\n try {\n await window.ethereum.request({\n method: \"wallet_switchEthereumChain\",\n params: [{ chainId: \"0x\" + targetChainId.toString(16) }],\n });\n } catch (switchError: unknown) {\n const error = switchError as { code?: number };\n // Chain not added, add it\n if (error.code === 4902) {\n await window.ethereum.request({\n method: \"wallet_addEthereumChain\",\n params: [\n {\n chainId: \"0x\" + targetChainId.toString(16),\n chainName: this.chainConfig.chain.name,\n nativeCurrency: this.chainConfig.chain.nativeCurrency,\n rpcUrls: [this.chainConfig.rpcUrl],\n blockExplorerUrls: this.chainConfig.chain.blockExplorers?.default?.url\n ? [this.chainConfig.chain.blockExplorers.default.url]\n : [],\n },\n ],\n });\n } else {\n throw switchError;\n }\n }\n }\n\n this.owner = accounts[0] as Address;\n this.smartAccountAddress = await this.getSmartAccountAddress(this.owner);\n\n return {\n owner: this.owner,\n smartAccount: this.smartAccountAddress,\n };\n }\n\n /**\n * Get the Smart Account address for an owner (counterfactual)\n */\n async getSmartAccountAddress(owner: Address): Promise<Address> {\n const address = await this.publicClient.readContract({\n address: this.factoryAddress,\n abi: factoryAbi,\n functionName: \"getAccountAddress\",\n args: [owner, 0n], // salt = 0\n }) as Address;\n return address;\n }\n\n /**\n * Check if the Smart Account is deployed\n */\n async isAccountDeployed(): Promise<boolean> {\n if (!this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n const code = await this.publicClient.getCode({\n address: this.smartAccountAddress,\n });\n return code !== undefined && code !== \"0x\";\n }\n\n\n /**\n * Get the USDC balance of the Smart Account\n */\n async getUsdcBalance(): Promise<bigint> {\n if (!this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n return await this.publicClient.readContract({\n address: this.usdcAddress,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.smartAccountAddress],\n }) as bigint;\n }\n\n\n /**\n * Get the EOA's USDC balance\n */\n async getEoaUsdcBalance(): Promise<bigint> {\n if (!this.owner) {\n throw new Error(\"Not connected\");\n }\n\n return await this.publicClient.readContract({\n address: this.usdcAddress,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.owner],\n }) as bigint;\n }\n\n /**\n * Get the allowance of the Smart Account to spend the EOA's USDC\n */\n async getAllowance(): Promise<bigint> {\n if (!this.owner || !this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n return await this.publicClient.readContract({\n address: this.usdcAddress,\n abi: erc20Abi,\n functionName: \"allowance\",\n args: [this.owner, this.smartAccountAddress],\n }) as bigint;\n }\n\n /**\n * Get the nonce for the Smart Account\n */\n async getNonce(): Promise<bigint> {\n if (!this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n return await this.publicClient.readContract({\n address: this.entryPointAddress,\n abi: entryPointAbi,\n functionName: \"getNonce\",\n args: [this.smartAccountAddress, 0n],\n }) as bigint;\n }\n\n /**\n * Build initCode for account deployment\n */\n buildInitCode(): Hex {\n if (!this.owner) {\n throw new Error(\"Not connected\");\n }\n\n const createAccountData = encodeFunctionData({\n abi: factoryAbi,\n functionName: \"createAccount\",\n args: [this.owner, 0n],\n });\n\n return `${this.factoryAddress}${createAccountData.slice(2)}` as Hex;\n }\n\n\n /**\n * Estimate gas for a UserOperation\n */\n async estimateGas(userOp: Partial<UserOperation>): Promise<GasEstimate> {\n const response = await fetch(this.chainConfig.bundlerUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"eth_estimateUserOperationGas\",\n params: [\n {\n sender: userOp.sender,\n nonce: userOp.nonce ? \"0x\" + userOp.nonce.toString(16) : \"0x0\",\n initCode: userOp.initCode || \"0x\",\n callData: userOp.callData || \"0x\",\n paymasterAndData: userOp.paymasterAndData || \"0x\",\n signature: \"0x\",\n },\n this.entryPointAddress,\n ],\n }),\n });\n\n const result = await response.json();\n if (result.error) {\n throw new Error(result.error.message);\n }\n\n return result.result;\n }\n\n\n /**\n * Build a UserOperation for Batched Execution (e.g. USDC Transfer + Fee)\n */\n async buildUserOperationBatch(\n transactions: { target: Address; value: bigint; data: Hex }[]\n ): Promise<UserOperation> {\n if (!this.owner || !this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n const isDeployed = await this.isAccountDeployed();\n const initCode = isDeployed ? \"0x\" : this.buildInitCode();\n\n // Prepare arrays for executeBatch\n const targets = transactions.map((tx) => tx.target);\n const values = transactions.map((tx) => tx.value);\n const datas = transactions.map((tx) => tx.data);\n\n // Encode callData for executeBatch\n const callData = encodeFunctionData({\n abi: smartAccountAbi,\n functionName: \"executeBatch\",\n args: [targets, values, datas],\n });\n\n const nonce = await this.getNonce();\n\n // Estimate gas\n const gasEstimate = await this.estimateGas({\n sender: this.smartAccountAddress,\n nonce,\n initCode: initCode as Hex,\n callData,\n paymasterAndData: this.paymasterAddress as Hex,\n });\n\n return {\n sender: this.smartAccountAddress,\n nonce,\n initCode: initCode as Hex,\n callData,\n callGasLimit: BigInt(gasEstimate.callGasLimit),\n verificationGasLimit: BigInt(gasEstimate.verificationGasLimit),\n preVerificationGas: BigInt(gasEstimate.preVerificationGas),\n maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),\n maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),\n paymasterAndData: this.paymasterAddress as Hex,\n signature: \"0x\",\n };\n }\n\n /**\n * Build a UserOperation to ONLY deploy the account (empty callData)\n */\n async buildDeployUserOperation(): Promise<UserOperation> {\n if (!this.owner || !this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n const isDeployed = await this.isAccountDeployed();\n if (isDeployed) {\n throw new Error(\"Account is already deployed\");\n }\n\n const initCode = this.buildInitCode();\n const callData = \"0x\"; // Empty callData for deployment only\n const nonce = await this.getNonce();\n\n // Estimate gas\n const gasEstimate = await this.estimateGas({\n sender: this.smartAccountAddress,\n nonce,\n initCode: initCode as Hex,\n callData,\n paymasterAndData: this.paymasterAddress as Hex,\n });\n\n return {\n sender: this.smartAccountAddress,\n nonce,\n initCode: initCode as Hex,\n callData,\n callGasLimit: BigInt(gasEstimate.callGasLimit),\n verificationGasLimit: BigInt(gasEstimate.verificationGasLimit),\n preVerificationGas: BigInt(gasEstimate.preVerificationGas),\n maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),\n maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),\n paymasterAndData: this.paymasterAddress as Hex,\n signature: \"0x\",\n };\n }\n\n /**\n * Calculate the UserOperation hash\n */\n getUserOpHash(userOp: UserOperation): Hex {\n const packed = encodeAbiParameters(\n [\n { type: \"address\" },\n { type: \"uint256\" },\n { type: \"bytes32\" },\n { type: \"bytes32\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"bytes32\" },\n ],\n [\n userOp.sender,\n userOp.nonce,\n keccak256(userOp.initCode),\n keccak256(userOp.callData),\n userOp.callGasLimit,\n userOp.verificationGasLimit,\n userOp.preVerificationGas,\n userOp.maxFeePerGas,\n userOp.maxPriorityFeePerGas,\n keccak256(userOp.paymasterAndData),\n ]\n );\n\n const packedHash = keccak256(packed);\n\n return keccak256(\n encodeAbiParameters(\n [{ type: \"bytes32\" }, { type: \"address\" }, { type: \"uint256\" }],\n [packedHash, this.entryPointAddress, BigInt(this.chainConfig.chain.id)]\n )\n );\n }\n\n /**\n * Sign a UserOperation with MetaMask\n */\n async signUserOperation(userOp: UserOperation): Promise<UserOperation> {\n if (!this.owner) {\n throw new Error(\"Not connected\");\n }\n\n const userOpHash = this.getUserOpHash(userOp);\n\n // Sign with MetaMask using personal_sign (EIP-191)\n const signature = (await window.ethereum!.request({\n method: \"personal_sign\",\n params: [userOpHash, this.owner],\n })) as Hex;\n\n return {\n ...userOp,\n signature,\n };\n }\n\n /**\n * Send a signed UserOperation to the bundler\n */\n async sendUserOperation(userOp: UserOperation): Promise<Hash> {\n const response = await fetch(this.chainConfig.bundlerUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"eth_sendUserOperation\",\n params: [\n {\n sender: userOp.sender,\n nonce: \"0x\" + userOp.nonce.toString(16),\n initCode: userOp.initCode,\n callData: userOp.callData,\n callGasLimit: \"0x\" + userOp.callGasLimit.toString(16),\n verificationGasLimit: \"0x\" + userOp.verificationGasLimit.toString(16),\n preVerificationGas: \"0x\" + userOp.preVerificationGas.toString(16),\n maxFeePerGas: \"0x\" + userOp.maxFeePerGas.toString(16),\n maxPriorityFeePerGas: \"0x\" + userOp.maxPriorityFeePerGas.toString(16),\n paymasterAndData: userOp.paymasterAndData,\n signature: userOp.signature,\n },\n this.entryPointAddress,\n ],\n }),\n });\n\n const result = await response.json();\n if (result.error) {\n throw new Error(result.error.message);\n }\n\n return result.result as Hash;\n }\n\n /**\n * Wait for a UserOperation to be confirmed\n */\n async waitForUserOperation(\n userOpHash: Hash,\n timeout = 60000\n ): Promise<UserOpReceipt> {\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeout) {\n const response = await fetch(this.chainConfig.bundlerUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"eth_getUserOperationReceipt\",\n params: [userOpHash],\n }),\n });\n\n const result = await response.json();\n if (result.result) {\n return result.result as UserOpReceipt;\n }\n\n // Wait 2 seconds before polling again\n await new Promise((resolve) => setTimeout(resolve, 2000));\n }\n\n throw new Error(\"Timeout waiting for UserOperation\");\n }\n\n\n /**\n * Request support for token approval (fund if needed)\n */\n async requestApprovalSupport(\n token: Address,\n spender: Address,\n amount: bigint\n ): Promise<ApprovalSupportResult> {\n if (!this.owner) {\n throw new Error(\"Not connected\");\n }\n\n const response = await fetch(this.chainConfig.bundlerUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"pm_requestApprovalSupport\",\n params: [token, this.owner, spender, amount.toString()],\n }),\n });\n\n const result = await response.json();\n if (result.error) {\n throw new Error(result.error.message);\n }\n\n return result.result;\n }\n\n // Getters\n getOwner(): Address | null {\n return this.owner;\n }\n\n getSmartAccount(): Address | null {\n return this.smartAccountAddress;\n }\n}\n\n// Global window types for MetaMask\ndeclare global {\n interface Window {\n ethereum?: {\n request: (args: { method: string; params?: unknown[] }) => Promise<unknown>;\n on: (event: string, callback: (args: unknown) => void) => void;\n removeListener: (event: string, callback: (args: unknown) => void) => void;\n };\n }\n}\n","export const DEFAULT_ENTRYPOINT = \"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789\";\nexport const DEFAULT_FACTORY = \"0x9406Cc6185a346906296840746125a0E44976454\"; // SimpleAccountFactory v0.6\n\nexport const factoryAbi = [\n {\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"salt\", type: \"uint256\" },\n ],\n name: \"getAccountAddress\",\n outputs: [{ name: \"\", type: \"address\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"salt\", type: \"uint256\" },\n ],\n name: \"isAccountDeployed\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"salt\", type: \"uint256\" },\n ],\n name: \"createAccount\",\n outputs: [{ name: \"account\", type: \"address\" }],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n] as const;\n\nexport const entryPointAbi = [\n {\n inputs: [\n { name: \"sender\", type: \"address\" },\n { name: \"key\", type: \"uint192\" },\n ],\n name: \"getNonce\",\n outputs: [{ name: \"nonce\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\nexport const smartAccountAbi = [\n {\n inputs: [\n { name: \"target\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"data\", type: \"bytes\" },\n ],\n name: \"execute\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"targets\", type: \"address[]\" },\n { name: \"values\", type: \"uint256[]\" },\n { name: \"datas\", type: \"bytes[]\" },\n ],\n name: \"executeBatch\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n] as const;\n\nexport const erc20Abi = [\n {\n inputs: [{ name: \"account\", type: \"address\" }],\n name: \"balanceOf\",\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"to\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n name: \"transfer\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"spender\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n name: \"approve\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n ],\n name: \"allowance\",\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n name: \"transferFrom\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [],\n name: \"decimals\",\n outputs: [{ name: \"\", type: \"uint8\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n","import { type Address } from \"viem\";\n\nexport const DEPLOYMENTS: Record<number, {\n entryPoint: Address;\n factory: Address;\n paymaster?: Address;\n usdc: Address;\n}> = {\n // Base Mainnet\n 8453: {\n entryPoint: \"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789\",\n factory: \"0xe2584152891E4769025807DEa0cD611F135aDC68\",\n paymaster: \"0x1e13Eb16C565E3f3FDe49A011755e50410bb1F95\",\n usdc: \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\"\n },\n // Base Sepolia\n 84532: {\n entryPoint: \"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789\",\n factory: \"0x9406Cc6185a346906296840746125a0E44976454\",\n usdc: \"0x036CbD53842c5426634e7929541eC2318f3dCF7e\"\n }\n};\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -136,15 +136,45 @@ var erc20Abi = [
136
136
  }
137
137
  ];
138
138
 
139
+ // src/deployments.ts
140
+ var DEPLOYMENTS = {
141
+ // Base Mainnet
142
+ 8453: {
143
+ entryPoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
144
+ factory: "0xe2584152891E4769025807DEa0cD611F135aDC68",
145
+ paymaster: "0x1e13Eb16C565E3f3FDe49A011755e50410bb1F95",
146
+ usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
147
+ },
148
+ // Base Sepolia
149
+ 84532: {
150
+ entryPoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
151
+ factory: "0x9406Cc6185a346906296840746125a0E44976454",
152
+ usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
153
+ }
154
+ };
155
+
139
156
  // src/AccountAbstraction.ts
140
157
  var AccountAbstraction = class {
141
158
  constructor(chainConfig) {
142
159
  this.owner = null;
143
160
  this.smartAccountAddress = null;
144
161
  this.chainConfig = chainConfig;
162
+ const chainId = chainConfig.chain.id;
163
+ const defaults = DEPLOYMENTS[chainId];
164
+ const entryPoint = chainConfig.entryPointAddress || defaults?.entryPoint;
165
+ if (!entryPoint) throw new Error(`EntryPoint address not found for chain ${chainId}`);
166
+ this.entryPointAddress = entryPoint;
167
+ const factory = chainConfig.factoryAddress || defaults?.factory;
168
+ if (!factory) throw new Error(`Factory address not found for chain ${chainId}`);
169
+ this.factoryAddress = factory;
170
+ const usdc = chainConfig.usdcAddress || defaults?.usdc;
171
+ if (!usdc) throw new Error(`USDC address not found for chain ${chainId}`);
172
+ this.usdcAddress = usdc;
173
+ this.paymasterAddress = chainConfig.paymasterAddress || defaults?.paymaster;
174
+ const rpcUrl = chainConfig.rpcUrl || chainConfig.chain.rpcUrls.default.http[0];
145
175
  this.publicClient = createPublicClient({
146
176
  chain: chainConfig.chain,
147
- transport: http(chainConfig.rpcUrl)
177
+ transport: http(rpcUrl)
148
178
  });
149
179
  }
150
180
  /**
@@ -202,7 +232,7 @@ var AccountAbstraction = class {
202
232
  */
203
233
  async getSmartAccountAddress(owner) {
204
234
  const address = await this.publicClient.readContract({
205
- address: this.chainConfig.factoryAddress,
235
+ address: this.factoryAddress,
206
236
  abi: factoryAbi,
207
237
  functionName: "getAccountAddress",
208
238
  args: [owner, 0n]
@@ -230,7 +260,7 @@ var AccountAbstraction = class {
230
260
  throw new Error("Not connected");
231
261
  }
232
262
  return await this.publicClient.readContract({
233
- address: this.chainConfig.usdcAddress,
263
+ address: this.usdcAddress,
234
264
  abi: erc20Abi,
235
265
  functionName: "balanceOf",
236
266
  args: [this.smartAccountAddress]
@@ -244,7 +274,7 @@ var AccountAbstraction = class {
244
274
  throw new Error("Not connected");
245
275
  }
246
276
  return await this.publicClient.readContract({
247
- address: this.chainConfig.usdcAddress,
277
+ address: this.usdcAddress,
248
278
  abi: erc20Abi,
249
279
  functionName: "balanceOf",
250
280
  args: [this.owner]
@@ -258,7 +288,7 @@ var AccountAbstraction = class {
258
288
  throw new Error("Not connected");
259
289
  }
260
290
  return await this.publicClient.readContract({
261
- address: this.chainConfig.usdcAddress,
291
+ address: this.usdcAddress,
262
292
  abi: erc20Abi,
263
293
  functionName: "allowance",
264
294
  args: [this.owner, this.smartAccountAddress]
@@ -272,7 +302,7 @@ var AccountAbstraction = class {
272
302
  throw new Error("Not connected");
273
303
  }
274
304
  return await this.publicClient.readContract({
275
- address: this.chainConfig.entryPointAddress,
305
+ address: this.entryPointAddress,
276
306
  abi: entryPointAbi,
277
307
  functionName: "getNonce",
278
308
  args: [this.smartAccountAddress, 0n]
@@ -290,7 +320,7 @@ var AccountAbstraction = class {
290
320
  functionName: "createAccount",
291
321
  args: [this.owner, 0n]
292
322
  });
293
- return `${this.chainConfig.factoryAddress}${createAccountData.slice(2)}`;
323
+ return `${this.factoryAddress}${createAccountData.slice(2)}`;
294
324
  }
295
325
  /**
296
326
  * Estimate gas for a UserOperation
@@ -312,7 +342,7 @@ var AccountAbstraction = class {
312
342
  paymasterAndData: userOp.paymasterAndData || "0x",
313
343
  signature: "0x"
314
344
  },
315
- this.chainConfig.entryPointAddress
345
+ this.entryPointAddress
316
346
  ]
317
347
  })
318
348
  });
@@ -345,7 +375,7 @@ var AccountAbstraction = class {
345
375
  nonce,
346
376
  initCode,
347
377
  callData,
348
- paymasterAndData: this.chainConfig.paymasterAddress
378
+ paymasterAndData: this.paymasterAddress
349
379
  });
350
380
  return {
351
381
  sender: this.smartAccountAddress,
@@ -357,7 +387,7 @@ var AccountAbstraction = class {
357
387
  preVerificationGas: BigInt(gasEstimate.preVerificationGas),
358
388
  maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),
359
389
  maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),
360
- paymasterAndData: this.chainConfig.paymasterAddress,
390
+ paymasterAndData: this.paymasterAddress,
361
391
  signature: "0x"
362
392
  };
363
393
  }
@@ -380,7 +410,7 @@ var AccountAbstraction = class {
380
410
  nonce,
381
411
  initCode,
382
412
  callData,
383
- paymasterAndData: this.chainConfig.paymasterAddress
413
+ paymasterAndData: this.paymasterAddress
384
414
  });
385
415
  return {
386
416
  sender: this.smartAccountAddress,
@@ -392,7 +422,7 @@ var AccountAbstraction = class {
392
422
  preVerificationGas: BigInt(gasEstimate.preVerificationGas),
393
423
  maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),
394
424
  maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),
395
- paymasterAndData: this.chainConfig.paymasterAddress,
425
+ paymasterAndData: this.paymasterAddress,
396
426
  signature: "0x"
397
427
  };
398
428
  }
@@ -430,7 +460,7 @@ var AccountAbstraction = class {
430
460
  return keccak256(
431
461
  encodeAbiParameters(
432
462
  [{ type: "bytes32" }, { type: "address" }, { type: "uint256" }],
433
- [packedHash, this.chainConfig.entryPointAddress, BigInt(this.chainConfig.chain.id)]
463
+ [packedHash, this.entryPointAddress, BigInt(this.chainConfig.chain.id)]
434
464
  )
435
465
  );
436
466
  }
@@ -476,7 +506,7 @@ var AccountAbstraction = class {
476
506
  paymasterAndData: userOp.paymasterAndData,
477
507
  signature: userOp.signature
478
508
  },
479
- this.chainConfig.entryPointAddress
509
+ this.entryPointAddress
480
510
  ]
481
511
  })
482
512
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/AccountAbstraction.ts","../src/constants.ts"],"sourcesContent":["import {\n createPublicClient,\n http,\n encodeFunctionData,\n encodeAbiParameters,\n keccak256,\n type Address,\n type Hash,\n type Hex,\n type PublicClient\n} from \"viem\";\nimport {\n factoryAbi,\n entryPointAbi,\n smartAccountAbi,\n erc20Abi,\n} from \"./constants\";\nimport {\n type ChainConfig,\n type UserOperation,\n type GasEstimate,\n type UserOpReceipt,\n type ApprovalSupportResult\n} from \"./types\";\n\n/**\n * ERC-4337 Account Abstraction Client\n */\nexport class AccountAbstraction {\n private owner: Address | null = null;\n private smartAccountAddress: Address | null = null;\n private chainConfig: ChainConfig;\n private publicClient: PublicClient;\n\n constructor(chainConfig: ChainConfig) {\n this.chainConfig = chainConfig;\n this.publicClient = createPublicClient({\n chain: chainConfig.chain,\n transport: http(chainConfig.rpcUrl),\n });\n }\n\n /**\n * Connect to MetaMask and get the owner address\n */\n async connect(): Promise<{ owner: Address; smartAccount: Address }> {\n if (typeof window === \"undefined\" || !window.ethereum) {\n throw new Error(\"MetaMask is not installed\");\n }\n\n // Request account access\n const accounts = (await window.ethereum.request({\n method: \"eth_requestAccounts\",\n })) as string[];\n\n if (!accounts || accounts.length === 0) {\n throw new Error(\"No accounts found\");\n }\n\n // Check network\n const chainId = (await window.ethereum.request({\n method: \"eth_chainId\",\n })) as string;\n\n const targetChainId = this.chainConfig.chain.id;\n\n if (parseInt(chainId, 16) !== targetChainId) {\n // Switch to configured chain\n try {\n await window.ethereum.request({\n method: \"wallet_switchEthereumChain\",\n params: [{ chainId: \"0x\" + targetChainId.toString(16) }],\n });\n } catch (switchError: unknown) {\n const error = switchError as { code?: number };\n // Chain not added, add it\n if (error.code === 4902) {\n await window.ethereum.request({\n method: \"wallet_addEthereumChain\",\n params: [\n {\n chainId: \"0x\" + targetChainId.toString(16),\n chainName: this.chainConfig.chain.name,\n nativeCurrency: this.chainConfig.chain.nativeCurrency,\n rpcUrls: [this.chainConfig.rpcUrl],\n blockExplorerUrls: this.chainConfig.chain.blockExplorers?.default?.url\n ? [this.chainConfig.chain.blockExplorers.default.url]\n : [],\n },\n ],\n });\n } else {\n throw switchError;\n }\n }\n }\n\n this.owner = accounts[0] as Address;\n this.smartAccountAddress = await this.getSmartAccountAddress(this.owner);\n\n return {\n owner: this.owner,\n smartAccount: this.smartAccountAddress,\n };\n }\n\n /**\n * Get the Smart Account address for an owner (counterfactual)\n */\n async getSmartAccountAddress(owner: Address): Promise<Address> {\n const address = await this.publicClient.readContract({\n address: this.chainConfig.factoryAddress,\n abi: factoryAbi,\n functionName: \"getAccountAddress\",\n args: [owner, 0n], // salt = 0\n }) as Address;\n return address;\n }\n\n /**\n * Check if the Smart Account is deployed\n */\n async isAccountDeployed(): Promise<boolean> {\n if (!this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n const code = await this.publicClient.getCode({\n address: this.smartAccountAddress,\n });\n return code !== undefined && code !== \"0x\";\n }\n\n\n /**\n * Get the USDC balance of the Smart Account\n */\n async getUsdcBalance(): Promise<bigint> {\n if (!this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n return await this.publicClient.readContract({\n address: this.chainConfig.usdcAddress,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.smartAccountAddress],\n }) as bigint;\n }\n\n\n /**\n * Get the EOA's USDC balance\n */\n async getEoaUsdcBalance(): Promise<bigint> {\n if (!this.owner) {\n throw new Error(\"Not connected\");\n }\n\n return await this.publicClient.readContract({\n address: this.chainConfig.usdcAddress,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.owner],\n }) as bigint;\n }\n\n /**\n * Get the allowance of the Smart Account to spend the EOA's USDC\n */\n async getAllowance(): Promise<bigint> {\n if (!this.owner || !this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n return await this.publicClient.readContract({\n address: this.chainConfig.usdcAddress,\n abi: erc20Abi,\n functionName: \"allowance\",\n args: [this.owner, this.smartAccountAddress],\n }) as bigint;\n }\n\n /**\n * Get the nonce for the Smart Account\n */\n async getNonce(): Promise<bigint> {\n if (!this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n return await this.publicClient.readContract({\n address: this.chainConfig.entryPointAddress,\n abi: entryPointAbi,\n functionName: \"getNonce\",\n args: [this.smartAccountAddress, 0n],\n }) as bigint;\n }\n\n /**\n * Build initCode for account deployment\n */\n buildInitCode(): Hex {\n if (!this.owner) {\n throw new Error(\"Not connected\");\n }\n\n const createAccountData = encodeFunctionData({\n abi: factoryAbi,\n functionName: \"createAccount\",\n args: [this.owner, 0n],\n });\n\n return `${this.chainConfig.factoryAddress}${createAccountData.slice(2)}` as Hex;\n }\n\n\n /**\n * Estimate gas for a UserOperation\n */\n async estimateGas(userOp: Partial<UserOperation>): Promise<GasEstimate> {\n const response = await fetch(this.chainConfig.bundlerUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"eth_estimateUserOperationGas\",\n params: [\n {\n sender: userOp.sender,\n nonce: userOp.nonce ? \"0x\" + userOp.nonce.toString(16) : \"0x0\",\n initCode: userOp.initCode || \"0x\",\n callData: userOp.callData || \"0x\",\n paymasterAndData: userOp.paymasterAndData || \"0x\",\n signature: \"0x\",\n },\n this.chainConfig.entryPointAddress,\n ],\n }),\n });\n\n const result = await response.json();\n if (result.error) {\n throw new Error(result.error.message);\n }\n\n return result.result;\n }\n\n\n /**\n * Build a UserOperation for Batched Execution (e.g. USDC Transfer + Fee)\n */\n async buildUserOperationBatch(\n transactions: { target: Address; value: bigint; data: Hex }[]\n ): Promise<UserOperation> {\n if (!this.owner || !this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n const isDeployed = await this.isAccountDeployed();\n const initCode = isDeployed ? \"0x\" : this.buildInitCode();\n\n // Prepare arrays for executeBatch\n const targets = transactions.map((tx) => tx.target);\n const values = transactions.map((tx) => tx.value);\n const datas = transactions.map((tx) => tx.data);\n\n // Encode callData for executeBatch\n const callData = encodeFunctionData({\n abi: smartAccountAbi,\n functionName: \"executeBatch\",\n args: [targets, values, datas],\n });\n\n const nonce = await this.getNonce();\n\n // Estimate gas\n const gasEstimate = await this.estimateGas({\n sender: this.smartAccountAddress,\n nonce,\n initCode: initCode as Hex,\n callData,\n paymasterAndData: this.chainConfig.paymasterAddress as Hex,\n });\n\n return {\n sender: this.smartAccountAddress,\n nonce,\n initCode: initCode as Hex,\n callData,\n callGasLimit: BigInt(gasEstimate.callGasLimit),\n verificationGasLimit: BigInt(gasEstimate.verificationGasLimit),\n preVerificationGas: BigInt(gasEstimate.preVerificationGas),\n maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),\n maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),\n paymasterAndData: this.chainConfig.paymasterAddress as Hex,\n signature: \"0x\",\n };\n }\n\n /**\n * Build a UserOperation to ONLY deploy the account (empty callData)\n */\n async buildDeployUserOperation(): Promise<UserOperation> {\n if (!this.owner || !this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n const isDeployed = await this.isAccountDeployed();\n if (isDeployed) {\n throw new Error(\"Account is already deployed\");\n }\n\n const initCode = this.buildInitCode();\n const callData = \"0x\"; // Empty callData for deployment only\n const nonce = await this.getNonce();\n\n // Estimate gas\n const gasEstimate = await this.estimateGas({\n sender: this.smartAccountAddress,\n nonce,\n initCode: initCode as Hex,\n callData,\n paymasterAndData: this.chainConfig.paymasterAddress as Hex,\n });\n\n return {\n sender: this.smartAccountAddress,\n nonce,\n initCode: initCode as Hex,\n callData,\n callGasLimit: BigInt(gasEstimate.callGasLimit),\n verificationGasLimit: BigInt(gasEstimate.verificationGasLimit),\n preVerificationGas: BigInt(gasEstimate.preVerificationGas),\n maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),\n maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),\n paymasterAndData: this.chainConfig.paymasterAddress as Hex,\n signature: \"0x\",\n };\n }\n\n /**\n * Calculate the UserOperation hash\n */\n getUserOpHash(userOp: UserOperation): Hex {\n const packed = encodeAbiParameters(\n [\n { type: \"address\" },\n { type: \"uint256\" },\n { type: \"bytes32\" },\n { type: \"bytes32\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"bytes32\" },\n ],\n [\n userOp.sender,\n userOp.nonce,\n keccak256(userOp.initCode),\n keccak256(userOp.callData),\n userOp.callGasLimit,\n userOp.verificationGasLimit,\n userOp.preVerificationGas,\n userOp.maxFeePerGas,\n userOp.maxPriorityFeePerGas,\n keccak256(userOp.paymasterAndData),\n ]\n );\n\n const packedHash = keccak256(packed);\n\n return keccak256(\n encodeAbiParameters(\n [{ type: \"bytes32\" }, { type: \"address\" }, { type: \"uint256\" }],\n [packedHash, this.chainConfig.entryPointAddress, BigInt(this.chainConfig.chain.id)]\n )\n );\n }\n\n /**\n * Sign a UserOperation with MetaMask\n */\n async signUserOperation(userOp: UserOperation): Promise<UserOperation> {\n if (!this.owner) {\n throw new Error(\"Not connected\");\n }\n\n const userOpHash = this.getUserOpHash(userOp);\n\n // Sign with MetaMask using personal_sign (EIP-191)\n const signature = (await window.ethereum!.request({\n method: \"personal_sign\",\n params: [userOpHash, this.owner],\n })) as Hex;\n\n return {\n ...userOp,\n signature,\n };\n }\n\n /**\n * Send a signed UserOperation to the bundler\n */\n async sendUserOperation(userOp: UserOperation): Promise<Hash> {\n const response = await fetch(this.chainConfig.bundlerUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"eth_sendUserOperation\",\n params: [\n {\n sender: userOp.sender,\n nonce: \"0x\" + userOp.nonce.toString(16),\n initCode: userOp.initCode,\n callData: userOp.callData,\n callGasLimit: \"0x\" + userOp.callGasLimit.toString(16),\n verificationGasLimit: \"0x\" + userOp.verificationGasLimit.toString(16),\n preVerificationGas: \"0x\" + userOp.preVerificationGas.toString(16),\n maxFeePerGas: \"0x\" + userOp.maxFeePerGas.toString(16),\n maxPriorityFeePerGas: \"0x\" + userOp.maxPriorityFeePerGas.toString(16),\n paymasterAndData: userOp.paymasterAndData,\n signature: userOp.signature,\n },\n this.chainConfig.entryPointAddress,\n ],\n }),\n });\n\n const result = await response.json();\n if (result.error) {\n throw new Error(result.error.message);\n }\n\n return result.result as Hash;\n }\n\n /**\n * Wait for a UserOperation to be confirmed\n */\n async waitForUserOperation(\n userOpHash: Hash,\n timeout = 60000\n ): Promise<UserOpReceipt> {\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeout) {\n const response = await fetch(this.chainConfig.bundlerUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"eth_getUserOperationReceipt\",\n params: [userOpHash],\n }),\n });\n\n const result = await response.json();\n if (result.result) {\n return result.result as UserOpReceipt;\n }\n\n // Wait 2 seconds before polling again\n await new Promise((resolve) => setTimeout(resolve, 2000));\n }\n\n throw new Error(\"Timeout waiting for UserOperation\");\n }\n\n\n /**\n * Request support for token approval (fund if needed)\n */\n async requestApprovalSupport(\n token: Address,\n spender: Address,\n amount: bigint\n ): Promise<ApprovalSupportResult> {\n if (!this.owner) {\n throw new Error(\"Not connected\");\n }\n\n const response = await fetch(this.chainConfig.bundlerUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"pm_requestApprovalSupport\",\n params: [token, this.owner, spender, amount.toString()],\n }),\n });\n\n const result = await response.json();\n if (result.error) {\n throw new Error(result.error.message);\n }\n\n return result.result;\n }\n\n // Getters\n getOwner(): Address | null {\n return this.owner;\n }\n\n getSmartAccount(): Address | null {\n return this.smartAccountAddress;\n }\n}\n\n// Global window types for MetaMask\ndeclare global {\n interface Window {\n ethereum?: {\n request: (args: { method: string; params?: unknown[] }) => Promise<unknown>;\n on: (event: string, callback: (args: unknown) => void) => void;\n removeListener: (event: string, callback: (args: unknown) => void) => void;\n };\n }\n}\n","export const DEFAULT_ENTRYPOINT = \"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789\";\nexport const DEFAULT_FACTORY = \"0x9406Cc6185a346906296840746125a0E44976454\"; // SimpleAccountFactory v0.6\n\nexport const factoryAbi = [\n {\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"salt\", type: \"uint256\" },\n ],\n name: \"getAccountAddress\",\n outputs: [{ name: \"\", type: \"address\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"salt\", type: \"uint256\" },\n ],\n name: \"isAccountDeployed\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"salt\", type: \"uint256\" },\n ],\n name: \"createAccount\",\n outputs: [{ name: \"account\", type: \"address\" }],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n] as const;\n\nexport const entryPointAbi = [\n {\n inputs: [\n { name: \"sender\", type: \"address\" },\n { name: \"key\", type: \"uint192\" },\n ],\n name: \"getNonce\",\n outputs: [{ name: \"nonce\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\nexport const smartAccountAbi = [\n {\n inputs: [\n { name: \"target\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"data\", type: \"bytes\" },\n ],\n name: \"execute\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"targets\", type: \"address[]\" },\n { name: \"values\", type: \"uint256[]\" },\n { name: \"datas\", type: \"bytes[]\" },\n ],\n name: \"executeBatch\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n] as const;\n\nexport const erc20Abi = [\n {\n inputs: [{ name: \"account\", type: \"address\" }],\n name: \"balanceOf\",\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"to\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n name: \"transfer\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"spender\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n name: \"approve\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n ],\n name: \"allowance\",\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n name: \"transferFrom\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [],\n name: \"decimals\",\n outputs: [{ name: \"\", type: \"uint8\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/AccountAbstraction.ts","../src/constants.ts","../src/deployments.ts"],"sourcesContent":["import {\n createPublicClient,\n http,\n encodeFunctionData,\n encodeAbiParameters,\n keccak256,\n type Address,\n type Hash,\n type Hex,\n type PublicClient\n} from \"viem\";\nimport {\n factoryAbi,\n entryPointAbi,\n smartAccountAbi,\n erc20Abi,\n} from \"./constants\";\nimport {\n type ChainConfig,\n type UserOperation,\n type GasEstimate,\n type UserOpReceipt,\n type ApprovalSupportResult\n} from \"./types\";\nimport { DEPLOYMENTS } from \"./deployments\";\n\n/**\n * ERC-4337 Account Abstraction Client\n */\nexport class AccountAbstraction {\n private owner: Address | null = null;\n private smartAccountAddress: Address | null = null;\n private chainConfig: ChainConfig;\n private publicClient: PublicClient;\n\n // Resolved addresses\n private entryPointAddress: Address;\n private factoryAddress: Address;\n private paymasterAddress?: Address;\n private usdcAddress: Address;\n\n constructor(chainConfig: ChainConfig) {\n this.chainConfig = chainConfig;\n const chainId = chainConfig.chain.id;\n const defaults = DEPLOYMENTS[chainId];\n\n // Resolve addresses (Config > Defaults > Error)\n const entryPoint = chainConfig.entryPointAddress || defaults?.entryPoint;\n if (!entryPoint) throw new Error(`EntryPoint address not found for chain ${chainId}`);\n this.entryPointAddress = entryPoint;\n\n const factory = chainConfig.factoryAddress || defaults?.factory;\n if (!factory) throw new Error(`Factory address not found for chain ${chainId}`);\n this.factoryAddress = factory;\n\n const usdc = chainConfig.usdcAddress || defaults?.usdc;\n if (!usdc) throw new Error(`USDC address not found for chain ${chainId}`);\n this.usdcAddress = usdc;\n\n this.paymasterAddress = chainConfig.paymasterAddress || defaults?.paymaster;\n\n // Use provided RPC or default from chain\n const rpcUrl = chainConfig.rpcUrl || chainConfig.chain.rpcUrls.default.http[0];\n\n this.publicClient = createPublicClient({\n chain: chainConfig.chain,\n transport: http(rpcUrl),\n });\n }\n\n /**\n * Connect to MetaMask and get the owner address\n */\n async connect(): Promise<{ owner: Address; smartAccount: Address }> {\n if (typeof window === \"undefined\" || !window.ethereum) {\n throw new Error(\"MetaMask is not installed\");\n }\n\n // Request account access\n const accounts = (await window.ethereum.request({\n method: \"eth_requestAccounts\",\n })) as string[];\n\n if (!accounts || accounts.length === 0) {\n throw new Error(\"No accounts found\");\n }\n\n // Check network\n const chainId = (await window.ethereum.request({\n method: \"eth_chainId\",\n })) as string;\n\n const targetChainId = this.chainConfig.chain.id;\n\n if (parseInt(chainId, 16) !== targetChainId) {\n // Switch to configured chain\n try {\n await window.ethereum.request({\n method: \"wallet_switchEthereumChain\",\n params: [{ chainId: \"0x\" + targetChainId.toString(16) }],\n });\n } catch (switchError: unknown) {\n const error = switchError as { code?: number };\n // Chain not added, add it\n if (error.code === 4902) {\n await window.ethereum.request({\n method: \"wallet_addEthereumChain\",\n params: [\n {\n chainId: \"0x\" + targetChainId.toString(16),\n chainName: this.chainConfig.chain.name,\n nativeCurrency: this.chainConfig.chain.nativeCurrency,\n rpcUrls: [this.chainConfig.rpcUrl],\n blockExplorerUrls: this.chainConfig.chain.blockExplorers?.default?.url\n ? [this.chainConfig.chain.blockExplorers.default.url]\n : [],\n },\n ],\n });\n } else {\n throw switchError;\n }\n }\n }\n\n this.owner = accounts[0] as Address;\n this.smartAccountAddress = await this.getSmartAccountAddress(this.owner);\n\n return {\n owner: this.owner,\n smartAccount: this.smartAccountAddress,\n };\n }\n\n /**\n * Get the Smart Account address for an owner (counterfactual)\n */\n async getSmartAccountAddress(owner: Address): Promise<Address> {\n const address = await this.publicClient.readContract({\n address: this.factoryAddress,\n abi: factoryAbi,\n functionName: \"getAccountAddress\",\n args: [owner, 0n], // salt = 0\n }) as Address;\n return address;\n }\n\n /**\n * Check if the Smart Account is deployed\n */\n async isAccountDeployed(): Promise<boolean> {\n if (!this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n const code = await this.publicClient.getCode({\n address: this.smartAccountAddress,\n });\n return code !== undefined && code !== \"0x\";\n }\n\n\n /**\n * Get the USDC balance of the Smart Account\n */\n async getUsdcBalance(): Promise<bigint> {\n if (!this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n return await this.publicClient.readContract({\n address: this.usdcAddress,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.smartAccountAddress],\n }) as bigint;\n }\n\n\n /**\n * Get the EOA's USDC balance\n */\n async getEoaUsdcBalance(): Promise<bigint> {\n if (!this.owner) {\n throw new Error(\"Not connected\");\n }\n\n return await this.publicClient.readContract({\n address: this.usdcAddress,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.owner],\n }) as bigint;\n }\n\n /**\n * Get the allowance of the Smart Account to spend the EOA's USDC\n */\n async getAllowance(): Promise<bigint> {\n if (!this.owner || !this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n return await this.publicClient.readContract({\n address: this.usdcAddress,\n abi: erc20Abi,\n functionName: \"allowance\",\n args: [this.owner, this.smartAccountAddress],\n }) as bigint;\n }\n\n /**\n * Get the nonce for the Smart Account\n */\n async getNonce(): Promise<bigint> {\n if (!this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n return await this.publicClient.readContract({\n address: this.entryPointAddress,\n abi: entryPointAbi,\n functionName: \"getNonce\",\n args: [this.smartAccountAddress, 0n],\n }) as bigint;\n }\n\n /**\n * Build initCode for account deployment\n */\n buildInitCode(): Hex {\n if (!this.owner) {\n throw new Error(\"Not connected\");\n }\n\n const createAccountData = encodeFunctionData({\n abi: factoryAbi,\n functionName: \"createAccount\",\n args: [this.owner, 0n],\n });\n\n return `${this.factoryAddress}${createAccountData.slice(2)}` as Hex;\n }\n\n\n /**\n * Estimate gas for a UserOperation\n */\n async estimateGas(userOp: Partial<UserOperation>): Promise<GasEstimate> {\n const response = await fetch(this.chainConfig.bundlerUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"eth_estimateUserOperationGas\",\n params: [\n {\n sender: userOp.sender,\n nonce: userOp.nonce ? \"0x\" + userOp.nonce.toString(16) : \"0x0\",\n initCode: userOp.initCode || \"0x\",\n callData: userOp.callData || \"0x\",\n paymasterAndData: userOp.paymasterAndData || \"0x\",\n signature: \"0x\",\n },\n this.entryPointAddress,\n ],\n }),\n });\n\n const result = await response.json();\n if (result.error) {\n throw new Error(result.error.message);\n }\n\n return result.result;\n }\n\n\n /**\n * Build a UserOperation for Batched Execution (e.g. USDC Transfer + Fee)\n */\n async buildUserOperationBatch(\n transactions: { target: Address; value: bigint; data: Hex }[]\n ): Promise<UserOperation> {\n if (!this.owner || !this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n const isDeployed = await this.isAccountDeployed();\n const initCode = isDeployed ? \"0x\" : this.buildInitCode();\n\n // Prepare arrays for executeBatch\n const targets = transactions.map((tx) => tx.target);\n const values = transactions.map((tx) => tx.value);\n const datas = transactions.map((tx) => tx.data);\n\n // Encode callData for executeBatch\n const callData = encodeFunctionData({\n abi: smartAccountAbi,\n functionName: \"executeBatch\",\n args: [targets, values, datas],\n });\n\n const nonce = await this.getNonce();\n\n // Estimate gas\n const gasEstimate = await this.estimateGas({\n sender: this.smartAccountAddress,\n nonce,\n initCode: initCode as Hex,\n callData,\n paymasterAndData: this.paymasterAddress as Hex,\n });\n\n return {\n sender: this.smartAccountAddress,\n nonce,\n initCode: initCode as Hex,\n callData,\n callGasLimit: BigInt(gasEstimate.callGasLimit),\n verificationGasLimit: BigInt(gasEstimate.verificationGasLimit),\n preVerificationGas: BigInt(gasEstimate.preVerificationGas),\n maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),\n maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),\n paymasterAndData: this.paymasterAddress as Hex,\n signature: \"0x\",\n };\n }\n\n /**\n * Build a UserOperation to ONLY deploy the account (empty callData)\n */\n async buildDeployUserOperation(): Promise<UserOperation> {\n if (!this.owner || !this.smartAccountAddress) {\n throw new Error(\"Not connected\");\n }\n\n const isDeployed = await this.isAccountDeployed();\n if (isDeployed) {\n throw new Error(\"Account is already deployed\");\n }\n\n const initCode = this.buildInitCode();\n const callData = \"0x\"; // Empty callData for deployment only\n const nonce = await this.getNonce();\n\n // Estimate gas\n const gasEstimate = await this.estimateGas({\n sender: this.smartAccountAddress,\n nonce,\n initCode: initCode as Hex,\n callData,\n paymasterAndData: this.paymasterAddress as Hex,\n });\n\n return {\n sender: this.smartAccountAddress,\n nonce,\n initCode: initCode as Hex,\n callData,\n callGasLimit: BigInt(gasEstimate.callGasLimit),\n verificationGasLimit: BigInt(gasEstimate.verificationGasLimit),\n preVerificationGas: BigInt(gasEstimate.preVerificationGas),\n maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),\n maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),\n paymasterAndData: this.paymasterAddress as Hex,\n signature: \"0x\",\n };\n }\n\n /**\n * Calculate the UserOperation hash\n */\n getUserOpHash(userOp: UserOperation): Hex {\n const packed = encodeAbiParameters(\n [\n { type: \"address\" },\n { type: \"uint256\" },\n { type: \"bytes32\" },\n { type: \"bytes32\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"bytes32\" },\n ],\n [\n userOp.sender,\n userOp.nonce,\n keccak256(userOp.initCode),\n keccak256(userOp.callData),\n userOp.callGasLimit,\n userOp.verificationGasLimit,\n userOp.preVerificationGas,\n userOp.maxFeePerGas,\n userOp.maxPriorityFeePerGas,\n keccak256(userOp.paymasterAndData),\n ]\n );\n\n const packedHash = keccak256(packed);\n\n return keccak256(\n encodeAbiParameters(\n [{ type: \"bytes32\" }, { type: \"address\" }, { type: \"uint256\" }],\n [packedHash, this.entryPointAddress, BigInt(this.chainConfig.chain.id)]\n )\n );\n }\n\n /**\n * Sign a UserOperation with MetaMask\n */\n async signUserOperation(userOp: UserOperation): Promise<UserOperation> {\n if (!this.owner) {\n throw new Error(\"Not connected\");\n }\n\n const userOpHash = this.getUserOpHash(userOp);\n\n // Sign with MetaMask using personal_sign (EIP-191)\n const signature = (await window.ethereum!.request({\n method: \"personal_sign\",\n params: [userOpHash, this.owner],\n })) as Hex;\n\n return {\n ...userOp,\n signature,\n };\n }\n\n /**\n * Send a signed UserOperation to the bundler\n */\n async sendUserOperation(userOp: UserOperation): Promise<Hash> {\n const response = await fetch(this.chainConfig.bundlerUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"eth_sendUserOperation\",\n params: [\n {\n sender: userOp.sender,\n nonce: \"0x\" + userOp.nonce.toString(16),\n initCode: userOp.initCode,\n callData: userOp.callData,\n callGasLimit: \"0x\" + userOp.callGasLimit.toString(16),\n verificationGasLimit: \"0x\" + userOp.verificationGasLimit.toString(16),\n preVerificationGas: \"0x\" + userOp.preVerificationGas.toString(16),\n maxFeePerGas: \"0x\" + userOp.maxFeePerGas.toString(16),\n maxPriorityFeePerGas: \"0x\" + userOp.maxPriorityFeePerGas.toString(16),\n paymasterAndData: userOp.paymasterAndData,\n signature: userOp.signature,\n },\n this.entryPointAddress,\n ],\n }),\n });\n\n const result = await response.json();\n if (result.error) {\n throw new Error(result.error.message);\n }\n\n return result.result as Hash;\n }\n\n /**\n * Wait for a UserOperation to be confirmed\n */\n async waitForUserOperation(\n userOpHash: Hash,\n timeout = 60000\n ): Promise<UserOpReceipt> {\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeout) {\n const response = await fetch(this.chainConfig.bundlerUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"eth_getUserOperationReceipt\",\n params: [userOpHash],\n }),\n });\n\n const result = await response.json();\n if (result.result) {\n return result.result as UserOpReceipt;\n }\n\n // Wait 2 seconds before polling again\n await new Promise((resolve) => setTimeout(resolve, 2000));\n }\n\n throw new Error(\"Timeout waiting for UserOperation\");\n }\n\n\n /**\n * Request support for token approval (fund if needed)\n */\n async requestApprovalSupport(\n token: Address,\n spender: Address,\n amount: bigint\n ): Promise<ApprovalSupportResult> {\n if (!this.owner) {\n throw new Error(\"Not connected\");\n }\n\n const response = await fetch(this.chainConfig.bundlerUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"pm_requestApprovalSupport\",\n params: [token, this.owner, spender, amount.toString()],\n }),\n });\n\n const result = await response.json();\n if (result.error) {\n throw new Error(result.error.message);\n }\n\n return result.result;\n }\n\n // Getters\n getOwner(): Address | null {\n return this.owner;\n }\n\n getSmartAccount(): Address | null {\n return this.smartAccountAddress;\n }\n}\n\n// Global window types for MetaMask\ndeclare global {\n interface Window {\n ethereum?: {\n request: (args: { method: string; params?: unknown[] }) => Promise<unknown>;\n on: (event: string, callback: (args: unknown) => void) => void;\n removeListener: (event: string, callback: (args: unknown) => void) => void;\n };\n }\n}\n","export const DEFAULT_ENTRYPOINT = \"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789\";\nexport const DEFAULT_FACTORY = \"0x9406Cc6185a346906296840746125a0E44976454\"; // SimpleAccountFactory v0.6\n\nexport const factoryAbi = [\n {\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"salt\", type: \"uint256\" },\n ],\n name: \"getAccountAddress\",\n outputs: [{ name: \"\", type: \"address\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"salt\", type: \"uint256\" },\n ],\n name: \"isAccountDeployed\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"salt\", type: \"uint256\" },\n ],\n name: \"createAccount\",\n outputs: [{ name: \"account\", type: \"address\" }],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n] as const;\n\nexport const entryPointAbi = [\n {\n inputs: [\n { name: \"sender\", type: \"address\" },\n { name: \"key\", type: \"uint192\" },\n ],\n name: \"getNonce\",\n outputs: [{ name: \"nonce\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\nexport const smartAccountAbi = [\n {\n inputs: [\n { name: \"target\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"data\", type: \"bytes\" },\n ],\n name: \"execute\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"targets\", type: \"address[]\" },\n { name: \"values\", type: \"uint256[]\" },\n { name: \"datas\", type: \"bytes[]\" },\n ],\n name: \"executeBatch\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n] as const;\n\nexport const erc20Abi = [\n {\n inputs: [{ name: \"account\", type: \"address\" }],\n name: \"balanceOf\",\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"to\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n name: \"transfer\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"spender\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n name: \"approve\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n ],\n name: \"allowance\",\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n name: \"transferFrom\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [],\n name: \"decimals\",\n outputs: [{ name: \"\", type: \"uint8\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n","import { type Address } from \"viem\";\n\nexport const DEPLOYMENTS: Record<number, {\n entryPoint: Address;\n factory: Address;\n paymaster?: Address;\n usdc: Address;\n}> = {\n // Base Mainnet\n 8453: {\n entryPoint: \"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789\",\n factory: \"0xe2584152891E4769025807DEa0cD611F135aDC68\",\n paymaster: \"0x1e13Eb16C565E3f3FDe49A011755e50410bb1F95\",\n usdc: \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\"\n },\n // Base Sepolia\n 84532: {\n entryPoint: \"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789\",\n factory: \"0x9406Cc6185a346906296840746125a0E44976454\",\n usdc: \"0x036CbD53842c5426634e7929541eC2318f3dCF7e\"\n }\n};\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.1.0",
6
+ "version": "0.1.2",
7
7
  "description": "SDK for ERC-4337 Gasless Transfers",
8
8
  "main": "./dist/index.js",
9
9
  "module": "./dist/index.mjs",
@@ -35,4 +35,4 @@
35
35
  "tsup": "^8.0.0",
36
36
  "typescript": "^5.0.0"
37
37
  }
38
- }
38
+ }
@@ -22,6 +22,7 @@ import {
22
22
  type UserOpReceipt,
23
23
  type ApprovalSupportResult
24
24
  } from "./types";
25
+ import { DEPLOYMENTS } from "./deployments";
25
26
 
26
27
  /**
27
28
  * ERC-4337 Account Abstraction Client
@@ -32,11 +33,38 @@ export class AccountAbstraction {
32
33
  private chainConfig: ChainConfig;
33
34
  private publicClient: PublicClient;
34
35
 
36
+ // Resolved addresses
37
+ private entryPointAddress: Address;
38
+ private factoryAddress: Address;
39
+ private paymasterAddress?: Address;
40
+ private usdcAddress: Address;
41
+
35
42
  constructor(chainConfig: ChainConfig) {
36
43
  this.chainConfig = chainConfig;
44
+ const chainId = chainConfig.chain.id;
45
+ const defaults = DEPLOYMENTS[chainId];
46
+
47
+ // Resolve addresses (Config > Defaults > Error)
48
+ const entryPoint = chainConfig.entryPointAddress || defaults?.entryPoint;
49
+ if (!entryPoint) throw new Error(`EntryPoint address not found for chain ${chainId}`);
50
+ this.entryPointAddress = entryPoint;
51
+
52
+ const factory = chainConfig.factoryAddress || defaults?.factory;
53
+ if (!factory) throw new Error(`Factory address not found for chain ${chainId}`);
54
+ this.factoryAddress = factory;
55
+
56
+ const usdc = chainConfig.usdcAddress || defaults?.usdc;
57
+ if (!usdc) throw new Error(`USDC address not found for chain ${chainId}`);
58
+ this.usdcAddress = usdc;
59
+
60
+ this.paymasterAddress = chainConfig.paymasterAddress || defaults?.paymaster;
61
+
62
+ // Use provided RPC or default from chain
63
+ const rpcUrl = chainConfig.rpcUrl || chainConfig.chain.rpcUrls.default.http[0];
64
+
37
65
  this.publicClient = createPublicClient({
38
66
  chain: chainConfig.chain,
39
- transport: http(chainConfig.rpcUrl),
67
+ transport: http(rpcUrl),
40
68
  });
41
69
  }
42
70
 
@@ -109,7 +137,7 @@ export class AccountAbstraction {
109
137
  */
110
138
  async getSmartAccountAddress(owner: Address): Promise<Address> {
111
139
  const address = await this.publicClient.readContract({
112
- address: this.chainConfig.factoryAddress,
140
+ address: this.factoryAddress,
113
141
  abi: factoryAbi,
114
142
  functionName: "getAccountAddress",
115
143
  args: [owner, 0n], // salt = 0
@@ -141,7 +169,7 @@ export class AccountAbstraction {
141
169
  }
142
170
 
143
171
  return await this.publicClient.readContract({
144
- address: this.chainConfig.usdcAddress,
172
+ address: this.usdcAddress,
145
173
  abi: erc20Abi,
146
174
  functionName: "balanceOf",
147
175
  args: [this.smartAccountAddress],
@@ -158,7 +186,7 @@ export class AccountAbstraction {
158
186
  }
159
187
 
160
188
  return await this.publicClient.readContract({
161
- address: this.chainConfig.usdcAddress,
189
+ address: this.usdcAddress,
162
190
  abi: erc20Abi,
163
191
  functionName: "balanceOf",
164
192
  args: [this.owner],
@@ -174,7 +202,7 @@ export class AccountAbstraction {
174
202
  }
175
203
 
176
204
  return await this.publicClient.readContract({
177
- address: this.chainConfig.usdcAddress,
205
+ address: this.usdcAddress,
178
206
  abi: erc20Abi,
179
207
  functionName: "allowance",
180
208
  args: [this.owner, this.smartAccountAddress],
@@ -190,7 +218,7 @@ export class AccountAbstraction {
190
218
  }
191
219
 
192
220
  return await this.publicClient.readContract({
193
- address: this.chainConfig.entryPointAddress,
221
+ address: this.entryPointAddress,
194
222
  abi: entryPointAbi,
195
223
  functionName: "getNonce",
196
224
  args: [this.smartAccountAddress, 0n],
@@ -211,7 +239,7 @@ export class AccountAbstraction {
211
239
  args: [this.owner, 0n],
212
240
  });
213
241
 
214
- return `${this.chainConfig.factoryAddress}${createAccountData.slice(2)}` as Hex;
242
+ return `${this.factoryAddress}${createAccountData.slice(2)}` as Hex;
215
243
  }
216
244
 
217
245
 
@@ -235,7 +263,7 @@ export class AccountAbstraction {
235
263
  paymasterAndData: userOp.paymasterAndData || "0x",
236
264
  signature: "0x",
237
265
  },
238
- this.chainConfig.entryPointAddress,
266
+ this.entryPointAddress,
239
267
  ],
240
268
  }),
241
269
  });
@@ -282,7 +310,7 @@ export class AccountAbstraction {
282
310
  nonce,
283
311
  initCode: initCode as Hex,
284
312
  callData,
285
- paymasterAndData: this.chainConfig.paymasterAddress as Hex,
313
+ paymasterAndData: this.paymasterAddress as Hex,
286
314
  });
287
315
 
288
316
  return {
@@ -295,7 +323,7 @@ export class AccountAbstraction {
295
323
  preVerificationGas: BigInt(gasEstimate.preVerificationGas),
296
324
  maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),
297
325
  maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),
298
- paymasterAndData: this.chainConfig.paymasterAddress as Hex,
326
+ paymasterAndData: this.paymasterAddress as Hex,
299
327
  signature: "0x",
300
328
  };
301
329
  }
@@ -323,7 +351,7 @@ export class AccountAbstraction {
323
351
  nonce,
324
352
  initCode: initCode as Hex,
325
353
  callData,
326
- paymasterAndData: this.chainConfig.paymasterAddress as Hex,
354
+ paymasterAndData: this.paymasterAddress as Hex,
327
355
  });
328
356
 
329
357
  return {
@@ -336,7 +364,7 @@ export class AccountAbstraction {
336
364
  preVerificationGas: BigInt(gasEstimate.preVerificationGas),
337
365
  maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),
338
366
  maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),
339
- paymasterAndData: this.chainConfig.paymasterAddress as Hex,
367
+ paymasterAndData: this.paymasterAddress as Hex,
340
368
  signature: "0x",
341
369
  };
342
370
  }
@@ -377,7 +405,7 @@ export class AccountAbstraction {
377
405
  return keccak256(
378
406
  encodeAbiParameters(
379
407
  [{ type: "bytes32" }, { type: "address" }, { type: "uint256" }],
380
- [packedHash, this.chainConfig.entryPointAddress, BigInt(this.chainConfig.chain.id)]
408
+ [packedHash, this.entryPointAddress, BigInt(this.chainConfig.chain.id)]
381
409
  )
382
410
  );
383
411
  }
@@ -429,7 +457,7 @@ export class AccountAbstraction {
429
457
  paymasterAndData: userOp.paymasterAndData,
430
458
  signature: userOp.signature,
431
459
  },
432
- this.chainConfig.entryPointAddress,
460
+ this.entryPointAddress,
433
461
  ],
434
462
  }),
435
463
  });
@@ -0,0 +1,22 @@
1
+ import { type Address } from "viem";
2
+
3
+ export const DEPLOYMENTS: Record<number, {
4
+ entryPoint: Address;
5
+ factory: Address;
6
+ paymaster?: Address;
7
+ usdc: Address;
8
+ }> = {
9
+ // Base Mainnet
10
+ 8453: {
11
+ entryPoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
12
+ factory: "0xe2584152891E4769025807DEa0cD611F135aDC68",
13
+ paymaster: "0x1e13Eb16C565E3f3FDe49A011755e50410bb1F95",
14
+ usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
15
+ },
16
+ // Base Sepolia
17
+ 84532: {
18
+ entryPoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
19
+ factory: "0x9406Cc6185a346906296840746125a0E44976454",
20
+ usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
21
+ }
22
+ };
package/src/types.ts CHANGED
@@ -2,12 +2,12 @@ import { type Address, type Chain, type Hash, type Hex } from "viem";
2
2
 
3
3
  export interface ChainConfig {
4
4
  chain: Chain;
5
- rpcUrl: string;
5
+ rpcUrl?: string; // Optional, defaults to chain.rpcUrls.default
6
6
  bundlerUrl: string;
7
- entryPointAddress: Address;
8
- factoryAddress: Address;
9
- paymasterAddress: Address;
10
- usdcAddress: Address;
7
+ entryPointAddress?: Address;
8
+ factoryAddress?: Address;
9
+ paymasterAddress?: Address;
10
+ usdcAddress?: Address;
11
11
  }
12
12
 
13
13
  export interface UserOperation {