@1llet.xyz/erc4337-gasless-sdk 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +119 -0
- package/dist/index.d.mts +9 -5
- package/dist/index.d.ts +9 -5
- package/dist/index.js +44 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +44 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/AccountAbstraction.ts +42 -14
- package/src/deployments.ts +22 -0
- package/src/types.ts +5 -5
package/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
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
|
+
## 📄 License
|
|
118
|
+
|
|
119
|
+
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
|
|
5
|
+
rpcUrl?: string;
|
|
6
6
|
bundlerUrl: string;
|
|
7
|
-
entryPointAddress
|
|
8
|
-
factoryAddress
|
|
9
|
-
paymasterAddress
|
|
10
|
-
usdcAddress
|
|
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
|
|
5
|
+
rpcUrl?: string;
|
|
6
6
|
bundlerUrl: string;
|
|
7
|
-
entryPointAddress
|
|
8
|
-
factoryAddress
|
|
9
|
-
paymasterAddress
|
|
10
|
-
usdcAddress
|
|
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)(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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":"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","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(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
509
|
+
this.entryPointAddress
|
|
480
510
|
]
|
|
481
511
|
})
|
|
482
512
|
});
|
package/dist/index.mjs.map
CHANGED
|
@@ -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.
|
|
6
|
+
"version": "0.1.1",
|
|
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(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
5
|
+
rpcUrl?: string; // Optional, defaults to chain.rpcUrls.default
|
|
6
6
|
bundlerUrl: string;
|
|
7
|
-
entryPointAddress
|
|
8
|
-
factoryAddress
|
|
9
|
-
paymasterAddress
|
|
10
|
-
usdcAddress
|
|
7
|
+
entryPointAddress?: Address;
|
|
8
|
+
factoryAddress?: Address;
|
|
9
|
+
paymasterAddress?: Address;
|
|
10
|
+
usdcAddress?: Address;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export interface UserOperation {
|