@aspect-wallet/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/LICENSE +21 -0
  3. package/README.md +708 -0
  4. package/dist/audit/history.d.ts +44 -0
  5. package/dist/audit/history.d.ts.map +1 -0
  6. package/dist/audit/history.js +80 -0
  7. package/dist/audit/history.js.map +1 -0
  8. package/dist/auth/email.d.ts +52 -0
  9. package/dist/auth/email.d.ts.map +1 -0
  10. package/dist/auth/email.js +66 -0
  11. package/dist/auth/email.js.map +1 -0
  12. package/dist/auth/oauth.d.ts +47 -0
  13. package/dist/auth/oauth.d.ts.map +1 -0
  14. package/dist/auth/oauth.js +103 -0
  15. package/dist/auth/oauth.js.map +1 -0
  16. package/dist/auth/passkey-auth.d.ts +39 -0
  17. package/dist/auth/passkey-auth.d.ts.map +1 -0
  18. package/dist/auth/passkey-auth.js +108 -0
  19. package/dist/auth/passkey-auth.js.map +1 -0
  20. package/dist/auth/session.d.ts +30 -0
  21. package/dist/auth/session.d.ts.map +1 -0
  22. package/dist/auth/session.js +61 -0
  23. package/dist/auth/session.js.map +1 -0
  24. package/dist/chain/registry.d.ts +25 -0
  25. package/dist/chain/registry.d.ts.map +1 -0
  26. package/dist/chain/registry.js +46 -0
  27. package/dist/chain/registry.js.map +1 -0
  28. package/dist/core/client.d.ts +78 -0
  29. package/dist/core/client.d.ts.map +1 -0
  30. package/dist/core/client.js +129 -0
  31. package/dist/core/client.js.map +1 -0
  32. package/dist/core/config.d.ts +22 -0
  33. package/dist/core/config.d.ts.map +1 -0
  34. package/dist/core/config.js +91 -0
  35. package/dist/core/config.js.map +1 -0
  36. package/dist/core/errors.d.ts +32 -0
  37. package/dist/core/errors.d.ts.map +1 -0
  38. package/dist/core/errors.js +95 -0
  39. package/dist/core/errors.js.map +1 -0
  40. package/dist/index.d.ts +55 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +64 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/mfa/guardian.d.ts +27 -0
  45. package/dist/mfa/guardian.d.ts.map +1 -0
  46. package/dist/mfa/guardian.js +37 -0
  47. package/dist/mfa/guardian.js.map +1 -0
  48. package/dist/mfa/multisig.d.ts +28 -0
  49. package/dist/mfa/multisig.d.ts.map +1 -0
  50. package/dist/mfa/multisig.js +40 -0
  51. package/dist/mfa/multisig.js.map +1 -0
  52. package/dist/mfa/tiers.d.ts +34 -0
  53. package/dist/mfa/tiers.d.ts.map +1 -0
  54. package/dist/mfa/tiers.js +66 -0
  55. package/dist/mfa/tiers.js.map +1 -0
  56. package/dist/mfa/timelock.d.ts +32 -0
  57. package/dist/mfa/timelock.d.ts.map +1 -0
  58. package/dist/mfa/timelock.js +47 -0
  59. package/dist/mfa/timelock.js.map +1 -0
  60. package/dist/recovery/devices.d.ts +31 -0
  61. package/dist/recovery/devices.d.ts.map +1 -0
  62. package/dist/recovery/devices.js +33 -0
  63. package/dist/recovery/devices.js.map +1 -0
  64. package/dist/recovery/export.d.ts +33 -0
  65. package/dist/recovery/export.d.ts.map +1 -0
  66. package/dist/recovery/export.js +44 -0
  67. package/dist/recovery/export.js.map +1 -0
  68. package/dist/recovery/rotation.d.ts +26 -0
  69. package/dist/recovery/rotation.d.ts.map +1 -0
  70. package/dist/recovery/rotation.js +31 -0
  71. package/dist/recovery/rotation.js.map +1 -0
  72. package/dist/recovery/social.d.ts +33 -0
  73. package/dist/recovery/social.d.ts.map +1 -0
  74. package/dist/recovery/social.js +36 -0
  75. package/dist/recovery/social.js.map +1 -0
  76. package/dist/security/freeze.d.ts +34 -0
  77. package/dist/security/freeze.d.ts.map +1 -0
  78. package/dist/security/freeze.js +42 -0
  79. package/dist/security/freeze.js.map +1 -0
  80. package/dist/security/revoke.d.ts +27 -0
  81. package/dist/security/revoke.d.ts.map +1 -0
  82. package/dist/security/revoke.js +27 -0
  83. package/dist/security/revoke.js.map +1 -0
  84. package/dist/security/watchtower.d.ts +34 -0
  85. package/dist/security/watchtower.d.ts.map +1 -0
  86. package/dist/security/watchtower.js +38 -0
  87. package/dist/security/watchtower.js.map +1 -0
  88. package/dist/session-keys/manager.d.ts +40 -0
  89. package/dist/session-keys/manager.d.ts.map +1 -0
  90. package/dist/session-keys/manager.js +65 -0
  91. package/dist/session-keys/manager.js.map +1 -0
  92. package/dist/session-keys/permissions.d.ts +44 -0
  93. package/dist/session-keys/permissions.d.ts.map +1 -0
  94. package/dist/session-keys/permissions.js +63 -0
  95. package/dist/session-keys/permissions.js.map +1 -0
  96. package/dist/session-keys/templates.d.ts +49 -0
  97. package/dist/session-keys/templates.d.ts.map +1 -0
  98. package/dist/session-keys/templates.js +65 -0
  99. package/dist/session-keys/templates.js.map +1 -0
  100. package/dist/signer/eoa.d.ts +24 -0
  101. package/dist/signer/eoa.d.ts.map +1 -0
  102. package/dist/signer/eoa.js +32 -0
  103. package/dist/signer/eoa.js.map +1 -0
  104. package/dist/signer/interface.d.ts +60 -0
  105. package/dist/signer/interface.d.ts.map +1 -0
  106. package/dist/signer/interface.js +47 -0
  107. package/dist/signer/interface.js.map +1 -0
  108. package/dist/signer/multisig.d.ts +38 -0
  109. package/dist/signer/multisig.d.ts.map +1 -0
  110. package/dist/signer/multisig.js +56 -0
  111. package/dist/signer/multisig.js.map +1 -0
  112. package/dist/signer/passkey.d.ts +35 -0
  113. package/dist/signer/passkey.d.ts.map +1 -0
  114. package/dist/signer/passkey.js +112 -0
  115. package/dist/signer/passkey.js.map +1 -0
  116. package/dist/signer/session.d.ts +24 -0
  117. package/dist/signer/session.d.ts.map +1 -0
  118. package/dist/signer/session.js +32 -0
  119. package/dist/signer/session.js.map +1 -0
  120. package/dist/sponsor/paymaster.d.ts +27 -0
  121. package/dist/sponsor/paymaster.d.ts.map +1 -0
  122. package/dist/sponsor/paymaster.js +43 -0
  123. package/dist/sponsor/paymaster.js.map +1 -0
  124. package/dist/transport/api.d.ts +25 -0
  125. package/dist/transport/api.d.ts.map +1 -0
  126. package/dist/transport/api.js +79 -0
  127. package/dist/transport/api.js.map +1 -0
  128. package/dist/transport/bundler.d.ts +52 -0
  129. package/dist/transport/bundler.d.ts.map +1 -0
  130. package/dist/transport/bundler.js +109 -0
  131. package/dist/transport/bundler.js.map +1 -0
  132. package/dist/transport/iframe.d.ts +33 -0
  133. package/dist/transport/iframe.d.ts.map +1 -0
  134. package/dist/transport/iframe.js +131 -0
  135. package/dist/transport/iframe.js.map +1 -0
  136. package/dist/types.d.ts +366 -0
  137. package/dist/types.d.ts.map +1 -0
  138. package/dist/types.js +6 -0
  139. package/dist/types.js.map +1 -0
  140. package/dist/userop/builder.d.ts +75 -0
  141. package/dist/userop/builder.d.ts.map +1 -0
  142. package/dist/userop/builder.js +150 -0
  143. package/dist/userop/builder.js.map +1 -0
  144. package/dist/userop/encoding.d.ts +44 -0
  145. package/dist/userop/encoding.d.ts.map +1 -0
  146. package/dist/userop/encoding.js +99 -0
  147. package/dist/userop/encoding.js.map +1 -0
  148. package/dist/userop/gas.d.ts +35 -0
  149. package/dist/userop/gas.d.ts.map +1 -0
  150. package/dist/userop/gas.js +53 -0
  151. package/dist/userop/gas.js.map +1 -0
  152. package/dist/userop/hash.d.ts +34 -0
  153. package/dist/userop/hash.d.ts.map +1 -0
  154. package/dist/userop/hash.js +55 -0
  155. package/dist/userop/hash.js.map +1 -0
  156. package/dist/userop/nonce.d.ts +53 -0
  157. package/dist/userop/nonce.d.ts.map +1 -0
  158. package/dist/userop/nonce.js +79 -0
  159. package/dist/userop/nonce.js.map +1 -0
  160. package/dist/wallet/factory.d.ts +63 -0
  161. package/dist/wallet/factory.d.ts.map +1 -0
  162. package/dist/wallet/factory.js +63 -0
  163. package/dist/wallet/factory.js.map +1 -0
  164. package/package.json +70 -0
package/README.md ADDED
@@ -0,0 +1,708 @@
1
+ # @aspect-wallet/sdk
2
+
3
+ TypeScript SDK for building on the **Aspect Wallet** ERC-4337 Account Abstraction system. Create smart wallets, send gasless transactions, authenticate with social logins, and manage session keys -- all from your frontend.
4
+
5
+ ## Features
6
+
7
+ | Feature | Description |
8
+ |---------|-------------|
9
+ | **Smart Wallets** | Deterministic CREATE2 addresses, lazy deployment on first transaction |
10
+ | **Gasless Transactions** | VerifyingPaymaster sponsors gas -- users pay nothing |
11
+ | **Social Login** | Google, Apple, Facebook, Email OTP -- bridged to on-chain signers via Turnkey |
12
+ | **Passkeys** | WebAuthn/P256 biometric signing with RIP-7212 precompile support |
13
+ | **Session Keys** | Scoped ephemeral keys with allowlist, spend limits, time bounds |
14
+ | **Multi-Factor Auth** | On-chain enforced: device+guardian, K-of-N multi-sig, timelock |
15
+ | **Account Recovery** | Social recovery via guardians with timelock, two-step key rotation |
16
+ | **Emergency Freeze** | Instantly revoke all session keys and freeze account on compromise |
17
+ | **Audit Trail** | Full operation history, real-time events, webhook notifications |
18
+ | **Multi-Chain** | Arbitrum, Base, Polygon, Ethereum -- same address across chains |
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install @aspect-wallet/sdk viem
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ```typescript
29
+ import { FcxWalletClient, EoaSigner } from '@aspect-wallet/sdk';
30
+ import { privateKeyToAccount } from 'viem/accounts';
31
+
32
+ const client = new FcxWalletClient({
33
+ chain: 'arbitrum-sepolia',
34
+ paymasterUrl: 'https://paymaster.yourapp.com',
35
+ bundlerUrl: 'https://bundler.yourapp.com/rpc',
36
+ });
37
+
38
+ // Get deterministic wallet address (no deployment needed yet)
39
+ const walletAddress = await client.getWalletAddress();
40
+
41
+ // Execute a transaction (deploys wallet on first tx if needed)
42
+ const result = await client.execute({
43
+ target: '0xContractAddress...',
44
+ value: 0n,
45
+ data: '0x...',
46
+ sponsored: true, // Paymaster pays gas
47
+ });
48
+
49
+ console.log('TX:', result.transactionHash);
50
+ console.log('Gas paid by user:', 0); // Gasless!
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Wallet Lifecycle
56
+
57
+ ### Counterfactual Address
58
+
59
+ Users get a wallet address **instantly** -- no on-chain transaction needed. Assets can be sent to this address before the contract exists.
60
+
61
+ ```typescript
62
+ import { computeWalletAddress, WalletFactory } from '@aspect-wallet/sdk';
63
+
64
+ // Option A: Pure computation (no RPC call)
65
+ const address = computeWalletAddress({
66
+ factory: '0x1DFCc3c2ae138Da4BdF00DBF62CFf6f922D353EA',
67
+ owner: signerAddress,
68
+ salt: 0n,
69
+ });
70
+
71
+ // Option B: Query factory contract
72
+ const factory = new WalletFactory(publicClient, factoryAddress);
73
+ const address = await factory.getAddress(signerAddress, 0n);
74
+ const isDeployed = await factory.isDeployed(address);
75
+ ```
76
+
77
+ ### Lazy Deployment
78
+
79
+ The wallet deploys automatically on the first UserOp. The SDK handles `initCode` transparently:
80
+
81
+ ```typescript
82
+ // First transaction: SDK includes initCode, factory deploys via CREATE2
83
+ const result = await client.execute({
84
+ target: recipientAddress,
85
+ value: parseEther('0.01'),
86
+ data: '0x',
87
+ });
88
+ // Wallet now exists on-chain at the same address
89
+ ```
90
+
91
+ ---
92
+
93
+ ## UserOperation Builder
94
+
95
+ ### High-Level (Recommended)
96
+
97
+ ```typescript
98
+ // Single call
99
+ const result = await client.execute({
100
+ target: tokenContract,
101
+ value: 0n,
102
+ data: encodeFunctionData({ abi: erc20Abi, functionName: 'transfer', args: [to, amount] }),
103
+ });
104
+
105
+ // Batch call (atomic: all succeed or all revert)
106
+ const result = await client.executeBatch([
107
+ { target: tokenA, value: 0n, data: approveData },
108
+ { target: dex, value: 0n, data: swapData },
109
+ ]);
110
+ ```
111
+
112
+ ### Low-Level (Advanced)
113
+
114
+ ```typescript
115
+ import { UserOpBuilder, getUserOpHash } from '@aspect-wallet/sdk';
116
+
117
+ const builder = new UserOpBuilder({ publicClient, entryPoint, factory });
118
+
119
+ // Step 1: Build
120
+ const userOp = await builder
121
+ .setSender(walletAddress)
122
+ .setCallData({ target, value, data })
123
+ .setNonce({ key: 0n })
124
+ .build();
125
+
126
+ // Step 2: Estimate gas (applies 130% safety margin)
127
+ const estimated = await builder.estimateGas(userOp);
128
+
129
+ // Step 3: Get sponsorship
130
+ const sponsored = await paymasterClient.approve(estimated);
131
+
132
+ // Step 4: Compute hash
133
+ const hash = getUserOpHash(sponsored, entryPointAddress, chainId);
134
+
135
+ // Step 5: Sign
136
+ const signature = await signer.sign(hash);
137
+ sponsored.signature = signature;
138
+
139
+ // Step 6: Submit
140
+ const opHash = await bundlerClient.sendUserOperation(sponsored);
141
+
142
+ // Step 7: Wait for receipt
143
+ const receipt = await bundlerClient.waitForReceipt(opHash, { timeout: 60_000 });
144
+ ```
145
+
146
+ ### Hash Computation
147
+
148
+ The SDK's `getUserOpHash()` matches `EntryPoint.getUserOpHash()` exactly (verified on-chain):
149
+
150
+ ```typescript
151
+ import { getUserOpHash } from '@aspect-wallet/sdk';
152
+
153
+ const hash = getUserOpHash(userOp, entryPointAddress, chainId);
154
+ // Includes chainId + entryPoint address for anti-replay
155
+ // Variable-length fields (initCode, callData, paymasterAndData) individually hashed
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Gas Sponsorship (Paymaster)
161
+
162
+ Users transact with **zero ETH**. The VerifyingPaymaster contract pays gas, authorized by your backend signing service.
163
+
164
+ ```typescript
165
+ import { PaymasterClient } from '@aspect-wallet/sdk';
166
+
167
+ const paymaster = new PaymasterClient({
168
+ url: 'https://paymaster.yourapp.com',
169
+ });
170
+
171
+ // Request sponsorship approval
172
+ const approval = await paymaster.approve(userOp);
173
+ // approval.paymasterAndData = 97 bytes: address(20) + validUntil(6) + validAfter(6) + signature(65)
174
+
175
+ // Insert into UserOp
176
+ userOp.paymasterAndData = approval.paymasterAndData;
177
+
178
+ // Check remaining budget
179
+ const budget = await paymaster.getBudget();
180
+ // budget.daily.remaining = 3800000000000000000n (3.8 ETH)
181
+ ```
182
+
183
+ ### Transparent Sponsorship
184
+
185
+ ```typescript
186
+ const result = await client.execute({
187
+ target: contractAddress,
188
+ value: 0n,
189
+ data: callData,
190
+ sponsored: true, // SDK handles paymaster flow automatically
191
+ });
192
+ ```
193
+
194
+ ---
195
+
196
+ ## Authentication & Social Login
197
+
198
+ ### Email OTP
199
+
200
+ ```typescript
201
+ import { AuthClient } from '@aspect-wallet/sdk';
202
+
203
+ const auth = new AuthClient({ url: 'https://auth.yourapp.com' });
204
+
205
+ // Send OTP
206
+ await auth.sendEmailOtp('user@example.com');
207
+
208
+ // Verify OTP → get session + wallet
209
+ const session = await auth.verifyEmailOtp({
210
+ email: 'user@example.com',
211
+ code: '847291',
212
+ });
213
+ // session.wallet.address = '0x...' (deterministic, instant)
214
+ // session.signer.address = '0x...' (Turnkey-generated secp256k1 key)
215
+ // session.jwt = 'eyJ...' (for subsequent API calls)
216
+ ```
217
+
218
+ ### OAuth (Google / Apple / Facebook)
219
+
220
+ ```typescript
221
+ import { OAuthClient } from '@aspect-wallet/sdk';
222
+
223
+ const oauth = new OAuthClient({ url: 'https://auth.yourapp.com' });
224
+
225
+ // Google
226
+ const session = await oauth.loginWithGoogle();
227
+
228
+ // Apple
229
+ const session = await oauth.loginWithApple();
230
+
231
+ // Facebook
232
+ const session = await oauth.loginWithFacebook();
233
+
234
+ // All return the same SessionInfo structure
235
+ // First login: creates Turnkey sub-org + generates signing key
236
+ // Returning login: loads existing key
237
+ ```
238
+
239
+ ### Passkey Authentication
240
+
241
+ ```typescript
242
+ import { PasskeyAuthClient } from '@aspect-wallet/sdk';
243
+
244
+ const passkey = new PasskeyAuthClient({ url: 'https://auth.yourapp.com' });
245
+
246
+ // Register passkey (after initial login)
247
+ await passkey.register({ displayName: 'My MacBook' });
248
+
249
+ // Login with passkey (biometric prompt)
250
+ const session = await passkey.authenticate();
251
+ ```
252
+
253
+ ---
254
+
255
+ ## Signing
256
+
257
+ ### Signer Interface
258
+
259
+ All signers implement `ISigner`:
260
+
261
+ ```typescript
262
+ interface ISigner {
263
+ type: 'eoa' | 'passkey' | 'turnkey' | 'session-key' | 'multi-sig';
264
+ address: string;
265
+ sign(userOpHash: Hex): Promise<Hex>;
266
+ }
267
+ ```
268
+
269
+ ### EOA Signer (Testing / Backend)
270
+
271
+ ```typescript
272
+ import { EoaSigner } from '@aspect-wallet/sdk';
273
+
274
+ const signer = new EoaSigner({ privateKey: '0x...' });
275
+ const signature = await signer.sign(userOpHash);
276
+ // 65-byte ECDSA signature with EIP-191 prefix
277
+ ```
278
+
279
+ ### Passkey Signer (Browser)
280
+
281
+ ```typescript
282
+ import { PasskeySigner } from '@aspect-wallet/sdk';
283
+
284
+ const signer = new PasskeySigner({ credentialId: '...' });
285
+ const signature = await signer.sign(userOpHash);
286
+ // WebAuthn assertion: authenticatorData + clientDataJSON + r + s
287
+ // P256 verified on-chain via RIP-7212 precompile (3,450 gas)
288
+ ```
289
+
290
+ ### Modular Signature Format
291
+
292
+ For modular accounts (ERC-6900), signatures include a module ID prefix:
293
+
294
+ ```typescript
295
+ import { encodeModuleSignature } from '@aspect-wallet/sdk';
296
+
297
+ const modularSig = encodeModuleSignature(0, ecdsaSignature);
298
+ // moduleId(4 bytes) + signature = routes to correct on-chain validator
299
+ // 0 = SingleSigner, 1 = SessionKey, 2 = DeviceGuardian, 3 = MultiSig, 4 = WebAuthn
300
+ ```
301
+
302
+ ---
303
+
304
+ ## Session Keys
305
+
306
+ Temporary scoped keys that let dApps execute transactions **without user interaction** per action, while strictly limiting what the key can do.
307
+
308
+ ### Create Session Key
309
+
310
+ ```typescript
311
+ import { SessionKeyManager, SessionKeyTemplates } from '@aspect-wallet/sdk';
312
+
313
+ const manager = new SessionKeyManager(client);
314
+
315
+ // Custom permissions
316
+ const session = await manager.create({
317
+ permissions: {
318
+ allowlist: [
319
+ { target: gameContract, selector: '0x12345678' }, // playMove()
320
+ { target: gameContract, selector: '0xabcdef01' }, // claimReward()
321
+ ],
322
+ spendLimit: { perTx: 0n, cumulative: 0n },
323
+ timeRange: {
324
+ validAfter: Math.floor(Date.now() / 1000),
325
+ validUntil: Math.floor(Date.now() / 1000) + 4 * 3600, // 4 hours
326
+ },
327
+ requiredPaymaster: paymasterAddress,
328
+ },
329
+ });
330
+
331
+ // Or use pre-built templates
332
+ const gaming = SessionKeyTemplates.gaming({
333
+ gameContract: '0x...',
334
+ duration: 4 * 3600,
335
+ paymaster: '0x...',
336
+ });
337
+
338
+ const defi = SessionKeyTemplates.defi({
339
+ dexRouter: '0x...',
340
+ lendingPool: '0x...',
341
+ spendLimit: parseEther('1'),
342
+ duration: 3600,
343
+ });
344
+ ```
345
+
346
+ ### Execute with Session Key
347
+
348
+ ```typescript
349
+ // No user interaction needed -- session key signs automatically
350
+ const result = await manager.execute(session.moduleId, {
351
+ target: gameContract,
352
+ value: 0n,
353
+ data: playMoveData,
354
+ });
355
+
356
+ // On-chain hooks enforce:
357
+ // - AllowlistModule: target + selector in whitelist
358
+ // - NativeTokenLimitModule: value within limits
359
+ // - TimeRangeModule: within valid time window
360
+ // - PaymasterGuardModule: using required paymaster
361
+ ```
362
+
363
+ ### Revoke
364
+
365
+ ```typescript
366
+ await manager.revoke(session.moduleId); // Immediate on-chain revocation
367
+ ```
368
+
369
+ ---
370
+
371
+ ## Multi-Factor Authentication
372
+
373
+ On-chain enforced MFA -- the blockchain rejects transactions that don't meet the multi-factor requirements.
374
+
375
+ ### 4-Tier Step-Up Auth
376
+
377
+ ```typescript
378
+ import { TierSelector } from '@aspect-wallet/sdk';
379
+
380
+ // SDK auto-selects tier based on value + target
381
+ const result = await client.execute({
382
+ target: tokenContract,
383
+ value: parseEther('5'), // High value → Tier 3 (device + guardian)
384
+ data: transferData,
385
+ });
386
+
387
+ // Force specific tier
388
+ const result = await client.execute({
389
+ target: tokenContract,
390
+ value: parseEther('0.01'),
391
+ data: transferData,
392
+ authTier: 3, // Force device + guardian
393
+ });
394
+ ```
395
+
396
+ | Tier | When | Signers | Latency |
397
+ |------|------|---------|---------|
398
+ | 1 | Low-value, scoped actions | Session key (auto-sign) | Instant |
399
+ | 2 | Normal transactions | Owner key | 1 biometric prompt |
400
+ | 3 | High-value transfers | Owner + Guardian | 2 approvals |
401
+ | 4 | Account management | 2-of-3 multi-sig + 24h timelock | Hours/days |
402
+
403
+ ### Guardian Management
404
+
405
+ ```typescript
406
+ import { GuardianManager } from '@aspect-wallet/sdk';
407
+
408
+ const guardians = new GuardianManager(client);
409
+
410
+ await guardians.add({ guardian: '0x...', label: 'Mom' });
411
+ await guardians.add({ guardian: '0x...', label: 'Backend Co-Signer' });
412
+ await guardians.setThreshold(2); // 2-of-3 required for recovery
413
+
414
+ const list = await guardians.list(walletAddress);
415
+ ```
416
+
417
+ ### Multi-Sig Operations
418
+
419
+ ```typescript
420
+ import { MultiSigManager } from '@aspect-wallet/sdk';
421
+
422
+ const multisig = new MultiSigManager(client);
423
+
424
+ // Propose (owner 1)
425
+ const proposal = await multisig.propose({
426
+ target: tokenContract,
427
+ value: 0n,
428
+ data: transferData,
429
+ });
430
+
431
+ // Approve (owner 2)
432
+ await multisig.approve(proposal.id);
433
+ // If threshold met → UserOp submitted automatically
434
+ ```
435
+
436
+ ---
437
+
438
+ ## Account Recovery
439
+
440
+ ### Social Recovery (Guardian-Based)
441
+
442
+ ```typescript
443
+ import { SocialRecovery } from '@aspect-wallet/sdk';
444
+
445
+ const recovery = new SocialRecovery(client);
446
+
447
+ // Guardian A initiates
448
+ await recovery.initiate({
449
+ account: userWallet,
450
+ newOwner: newKeyAddress,
451
+ });
452
+
453
+ // Guardian B approves
454
+ await recovery.approve({ account: userWallet });
455
+
456
+ // After timelock (e.g., 3 days) → execute
457
+ await recovery.execute({ account: userWallet });
458
+
459
+ // Owner can cancel during timelock
460
+ await recovery.cancel();
461
+
462
+ // Check status
463
+ const status = await recovery.getStatus(walletAddress);
464
+ // { pending: true, approvals: 2, threshold: 2, executeAfter: ..., canExecute: false }
465
+ ```
466
+
467
+ ### Key Rotation (Two-Step)
468
+
469
+ ```typescript
470
+ import { KeyRotation } from '@aspect-wallet/sdk';
471
+
472
+ const rotation = new KeyRotation(client);
473
+
474
+ // Step 1: Current owner initiates
475
+ await rotation.initiate({ newOwner: newSignerAddress });
476
+
477
+ // Step 2: New owner accepts
478
+ await rotation.accept();
479
+ // Old key immediately loses access. Account address unchanged.
480
+ ```
481
+
482
+ ### Multi-Device
483
+
484
+ ```typescript
485
+ import { DeviceManager } from '@aspect-wallet/sdk';
486
+
487
+ const devices = new DeviceManager(client);
488
+
489
+ await devices.add({ name: 'iPhone 15', type: 'passkey', moduleId: 2 });
490
+ await devices.remove(moduleId); // Remove lost device
491
+
492
+ const list = await devices.list(walletAddress);
493
+ // [{ moduleId: 0, name: 'MacBook', type: 'turnkey', active: true }, ...]
494
+ ```
495
+
496
+ ---
497
+
498
+ ## Security & Emergency
499
+
500
+ ### Emergency Freeze
501
+
502
+ ```typescript
503
+ import { FreezeManager } from '@aspect-wallet/sdk';
504
+
505
+ const freeze = new FreezeManager(client);
506
+
507
+ // Freeze account (revokes all session keys, suspends paymaster)
508
+ await freeze.freeze({ reason: 'suspicious_activity' });
509
+
510
+ // Unfreeze (requires MFA)
511
+ await freeze.unfreeze();
512
+ ```
513
+
514
+ ### Bulk Session Key Revocation
515
+
516
+ ```typescript
517
+ import { RevokeManager } from '@aspect-wallet/sdk';
518
+
519
+ const revoke = new RevokeManager(client);
520
+ await revoke.revokeAll(); // Revoke ALL session keys at once
521
+ ```
522
+
523
+ ### Watchtower Alerts
524
+
525
+ ```typescript
526
+ import { WatchtowerClient } from '@aspect-wallet/sdk';
527
+
528
+ const watchtower = new WatchtowerClient(client);
529
+
530
+ await watchtower.subscribe({
531
+ account: walletAddress,
532
+ alerts: ['recovery_initiated', 'owner_changed', 'large_transfer'],
533
+ channels: {
534
+ email: 'user@example.com',
535
+ webhook: 'https://myapp.com/webhooks/security',
536
+ },
537
+ });
538
+ ```
539
+
540
+ ---
541
+
542
+ ## Audit & Logging
543
+
544
+ ```typescript
545
+ import { AuditClient } from '@aspect-wallet/sdk';
546
+
547
+ const audit = new AuditClient(client);
548
+
549
+ // Operation history
550
+ const history = await audit.getHistory(walletAddress, {
551
+ limit: 50,
552
+ types: ['execute', 'deploy', 'module_install'],
553
+ });
554
+
555
+ // Each operation includes:
556
+ // - userOpHash, transactionHash
557
+ // - target, value, selector
558
+ // - signer address + type (turnkey/passkey/session-key/multi-sig)
559
+ // - sponsored (boolean), paymaster address
560
+ // - gasCost, success, blockNumber, timestamp
561
+ ```
562
+
563
+ ---
564
+
565
+ ## Chain Configuration
566
+
567
+ ```typescript
568
+ import { ChainRegistry } from '@aspect-wallet/sdk';
569
+
570
+ const chains = new ChainRegistry();
571
+
572
+ // Get chain config
573
+ const config = chains.get('arbitrum-sepolia');
574
+ // { chainId: 421614, entryPoint: '0x5FF1...', factory: '0x1DFC...', paymaster: '0x13e6...', ... }
575
+
576
+ // Switch chains
577
+ client.switchChain('base');
578
+
579
+ // Same address across chains (CREATE2 determinism)
580
+ const arbAddr = computeWalletAddress({ factory: arbFactory, owner, salt: 0n });
581
+ const baseAddr = computeWalletAddress({ factory: baseFactory, owner, salt: 0n });
582
+ // arbAddr === baseAddr (if factories deployed at same address)
583
+ ```
584
+
585
+ ---
586
+
587
+ ## Bundler Client
588
+
589
+ ```typescript
590
+ import { BundlerClient } from '@aspect-wallet/sdk';
591
+
592
+ const bundler = new BundlerClient({ url: 'https://bundler.yourapp.com/rpc' });
593
+
594
+ // Submit UserOp
595
+ const hash = await bundler.sendUserOperation(signedUserOp, entryPointAddress);
596
+
597
+ // Wait for receipt (exponential backoff)
598
+ const receipt = await bundler.waitForReceipt(hash, {
599
+ timeout: 60_000,
600
+ pollingInterval: 2_000,
601
+ });
602
+
603
+ // Gas estimation
604
+ const gas = await bundler.estimateUserOperationGas(userOp, entryPointAddress);
605
+ // { preVerificationGas, verificationGasLimit, callGasLimit }
606
+
607
+ // Check supported entry points
608
+ const entryPoints = await bundler.supportedEntryPoints();
609
+ ```
610
+
611
+ ---
612
+
613
+ ## Error Handling
614
+
615
+ All errors are typed via `FcxError`:
616
+
617
+ ```typescript
618
+ import { FcxError } from '@aspect-wallet/sdk';
619
+
620
+ try {
621
+ await client.execute({ ... });
622
+ } catch (e) {
623
+ if (e instanceof FcxError) {
624
+ switch (e.code) {
625
+ case 'USEROP_SIGNATURE_INVALID': // -32507
626
+ case 'USEROP_SIMULATION_FAILED': // -32500
627
+ case 'SPONSOR_BUDGET_EXHAUSTED': // Budget exceeded
628
+ case 'SESSION_KEY_EXPIRED': // Session key time range expired
629
+ case 'SESSION_KEY_NOT_ALLOWED': // Target/selector not in allowlist
630
+ case 'MFA_THRESHOLD_NOT_MET': // Not enough signatures
631
+ case 'AUTH_SESSION_EXPIRED': // JWT expired
632
+ // Handle specific error
633
+ break;
634
+ }
635
+ console.error(e.code, e.message, e.details);
636
+ }
637
+ }
638
+ ```
639
+
640
+ ---
641
+
642
+ ## Deployed Contracts
643
+
644
+ ### Arbitrum Sepolia (Testnet)
645
+
646
+ | Contract | Address |
647
+ |----------|---------|
648
+ | EntryPoint v0.6 | `0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789` |
649
+ | SimpleAccountFactory | `0x1DFCc3c2ae138Da4BdF00DBF62CFf6f922D353EA` |
650
+ | SimpleAccount (impl) | `0xe6FEe0AF343A9c59a03070Ef4239519bD6C243F2` |
651
+ | VerifyingPaymaster | `0x13e6e887168d5ca78a47fac4EF71Ec5d0C6a9d2B` |
652
+
653
+ ---
654
+
655
+ ## Architecture
656
+
657
+ ```
658
+ Your Frontend App
659
+
660
+
661
+ @aspect-wallet/sdk (this package)
662
+
663
+ ├── Bundler RPC ──────── eth_sendUserOperation ──► EntryPoint (on-chain)
664
+ │ │
665
+ ├── Paymaster Service ── POST /api/paymaster/sign ├── Smart Account (proxy)
666
+ │ ├── Factory (CREATE2)
667
+ ├── Auth Server ──────── POST /auth/email/verify ├── Paymaster (verifying)
668
+ │ POST /auth/oauth/google └── Validation Modules
669
+ │ ├── SingleSigner
670
+ └── Turnkey Enclave ─── Key generation + signing ├── WebAuthn (P256)
671
+ (AWS Nitro) via cross-origin iframe ├── MultiSig (K-of-N)
672
+ ├── SessionKey + hooks
673
+ └── SocialRecovery
674
+ ```
675
+
676
+ ---
677
+
678
+ ## TypeScript Types
679
+
680
+ All types are exported and available for your application:
681
+
682
+ ```typescript
683
+ import type {
684
+ UserOperation,
685
+ ExecutionResult,
686
+ SessionInfo,
687
+ WalletState,
688
+ SessionKeyPermissions,
689
+ PaymasterApproval,
690
+ RecoveryStatus,
691
+ AuditOperation,
692
+ } from '@aspect-wallet/sdk';
693
+
694
+ // Or import types separately
695
+ import type { UserOperation } from '@aspect-wallet/sdk/types';
696
+ ```
697
+
698
+ ---
699
+
700
+ ## Requirements
701
+
702
+ - Node.js >= 18
703
+ - `viem` >= 2.0.0 (peer dependency)
704
+ - EVM chain with ERC-4337 EntryPoint v0.6 deployed
705
+
706
+ ## License
707
+
708
+ MIT