{"_id":"@aspect-wallet/sdk","_rev":"4-3f188d9565b0869818d30a94724327e7","name":"@aspect-wallet/sdk","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.1":{"name":"@aspect-wallet/sdk","version":"0.1.1","keywords":["erc-4337","account-abstraction","smart-wallet","gasless","paymaster","bundler","useroperation","passkeys","webauthn","session-keys","social-login","turnkey","ethereum","arbitrum","web3"],"author":{"name":"Future CX Lanka"},"license":"MIT","_id":"@aspect-wallet/sdk@0.1.1","maintainers":[{"name":"madhuranga333","email":"pasanmadhuranga333@gmail.com"}],"homepage":"https://docs.aspectwallet.com","dist":{"shasum":"e3175c056d516658e508dd6805232eeaf014f974","tarball":"https://registry.npmjs.org/@aspect-wallet/sdk/-/sdk-0.1.1.tgz","fileCount":164,"integrity":"sha512-e9GhsdF+iLQfykxRgZ0uCaB6sto/8BEX/ag4blNMCqhcwPZh4kn+Z9mXRDNgJhYai0xYMkN2dcvyuv+VSyFBPQ==","signatures":[{"sig":"MEUCIQDznH8u+6xh1pUdlWhIxwCtgh26sYllLC1rnJhWfF1tYwIgFTTi4tSZPBbYrncfYiAg5Kg5F/3txxT4pS9+PxL4lJ4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":279478},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./types":{"types":"./dist/types.d.ts","import":"./dist/types.js"}},"scripts":{"lint":"eslint src/ --ext .ts","test":"vitest run","build":"tsc","prepack":"npm run build","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"madhuranga333","email":"pasanmadhuranga333@gmail.com"},"_npmVersion":"11.10.0","description":"TypeScript SDK for ERC-4337 Account Abstraction smart wallets. Gasless transactions, social logins, passkeys, session keys, multi-factor auth, and account recovery.","directories":{},"_nodeVersion":"24.6.0","dependencies":{"viem":"^2.21.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.0.0","vitest":"^2.1.0","typescript":"^5.6.0","@types/node":"^22.0.0"},"peerDependencies":{"viem":"^2.0.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.1.1_1774802958261_0.38710602512812065","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@aspect-wallet/sdk","version":"0.1.2","description":"TypeScript SDK for ERC-4337 Account Abstraction smart wallets. Gasless transactions, social logins, passkeys, session keys, multi-factor auth, and account recovery.","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"},"./types":{"import":"./dist/types.js","types":"./dist/types.d.ts"}},"scripts":{"build":"tsc","lint":"eslint src/ --ext .ts","test":"vitest run","test:watch":"vitest","prepublishOnly":"npm run build","prepack":"npm run build"},"keywords":["erc-4337","account-abstraction","smart-wallet","gasless","paymaster","bundler","useroperation","passkeys","webauthn","session-keys","social-login","turnkey","ethereum","arbitrum","web3"],"author":{"name":"Future CX Lanka"},"homepage":"https://docs.aspectwallet.com","dependencies":{"viem":"2.21.0"},"devDependencies":{"@types/node":"^22.0.0","eslint":"^9.0.0","typescript":"~5.7.0","vitest":"^2.1.0"},"engines":{"node":">=18.0.0"},"license":"MIT","publishConfig":{"access":"public"},"gitHead":"6e460c4608ce5befcd886ffca29d49e65f8e24ed","_id":"@aspect-wallet/sdk@0.1.2","_nodeVersion":"24.6.0","_npmVersion":"11.10.0","dist":{"integrity":"sha512-H7QoMtGg9taXYafiVlsyLyDfyjR4EFxHtJSQDLRqP3hScXzBJHenY59DrHQd80fHuUy4ahzljONWQpbwNlSYyA==","shasum":"eef9724fbb6fac6ea70a144d8796e4562b5a4804","tarball":"https://registry.npmjs.org/@aspect-wallet/sdk/-/sdk-0.1.2.tgz","fileCount":163,"unpackedSize":284980,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCICLij/JTFwd2jWvztBfp9GFze+pRefcL2sq89cB/S09HAiEA5TcDwuMA8gA5e/vx8vdwNlUmZm8lTzBxxobDEom9lcE="}]},"_npmUser":{"name":"madhuranga333","email":"pasanmadhuranga333@gmail.com"},"directories":{},"maintainers":[{"name":"madhuranga333","email":"pasanmadhuranga333@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_0.1.2_1776741628148_0.8116697817238185"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-29T16:40:02.542Z","modified":"2026-04-21T03:20:28.423Z","0.1.0":"2026-03-29T16:40:02.821Z","0.1.1":"2026-03-29T16:49:18.412Z","0.1.2":"2026-04-21T03:20:28.294Z"},"author":{"name":"Future CX Lanka"},"license":"MIT","homepage":"https://docs.aspectwallet.com","keywords":["erc-4337","account-abstraction","smart-wallet","gasless","paymaster","bundler","useroperation","passkeys","webauthn","session-keys","social-login","turnkey","ethereum","arbitrum","web3"],"description":"TypeScript SDK for ERC-4337 Account Abstraction smart wallets. Gasless transactions, social logins, passkeys, session keys, multi-factor auth, and account recovery.","maintainers":[{"name":"madhuranga333","email":"pasanmadhuranga333@gmail.com"}],"readme":"# @aspect-wallet/sdk\n\nTypeScript 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.\n\n## Features\n\n| Feature | Description |\n|---------|-------------|\n| **Smart Wallets** | Deterministic CREATE2 addresses, lazy deployment on first transaction |\n| **Gasless Transactions** | VerifyingPaymaster sponsors gas -- users pay nothing |\n| **Social Login** | Google, Apple, Facebook, Email OTP -- bridged to on-chain signers via Turnkey |\n| **Passkeys** | WebAuthn/P256 biometric signing with RIP-7212 precompile support |\n| **Session Keys** | Scoped ephemeral keys with allowlist, spend limits, time bounds. Signs entirely in-browser (no auth round-trip) |\n| **Multi-Factor Auth** | On-chain enforced: device+guardian, K-of-N multi-sig, timelock |\n| **Account Recovery** | Social recovery via guardians with timelock, two-step key rotation |\n| **Emergency Freeze** | Instantly revoke all session keys and freeze account on compromise |\n| **Audit Trail** | Full operation history, real-time events, webhook notifications |\n| **Multi-Chain** | Arbitrum, Base, Polygon, Ethereum -- same address across chains |\n\n## Installation\n\n```bash\nnpm install @aspect-wallet/sdk viem\n```\n\n## Quick Start\n\n```typescript\nimport { FcxWalletClient } from '@aspect-wallet/sdk';\n\nconst client = new FcxWalletClient({\n  apiKey: 'fcx_live_abc123...',\n  chain: 'arbitrum-sepolia',\n  bundlerUrl: 'https://bundler.yourapp.com/rpc', // optional\n  paymasterUrl: 'https://paymaster.yourapp.com', // optional\n});\n\n// Resolve the deterministic wallet address for an owner (no on-chain call needed)\nconst wallet = await client.wallet.getAddress({ owner: signerAddress });\n// wallet.address -- the smart account address\n// wallet.deployed -- false until the first UserOp\n\n// Check the on-chain state (balance, modules, frozen flag, …)\nconst state = await client.wallet.getState(wallet.address);\n```\n\n`FcxWalletClient` exposes the following sub-modules:\n\n| Property | Class | Purpose |\n|----------|-------|---------|\n| `client.wallet` | `WalletFactory` | Address + state queries |\n| `client.sponsor` | `PaymasterClient` | Gas sponsorship requests |\n| `client.bundler` | `BundlerClient` | JSON-RPC submission / receipts |\n| `client.audit` | `AuditClient` | History, events, webhooks |\n| `client.chains` | `ChainRegistry` | Chain configs (per project) |\n\nExecution is performed by composing `UserOpBuilder` + a signer + `client.sponsor` + `client.bundler`. The end-to-end flow is shown below.\n\n---\n\n## Wallet Lifecycle\n\n### Counterfactual Address\n\nUsers get a wallet address **instantly** -- no on-chain transaction needed. Assets can be sent to this address before the contract exists.\n\n```typescript\nimport { computeWalletAddress } from '@aspect-wallet/sdk';\n\n// Pure computation -- no RPC, no API call\nconst address = computeWalletAddress(\n  factoryAddress,         // from ChainRegistry / your project config\n  implementationAddress,  // UUPS implementation behind the ERC-1167 clone\n  ownerAddress,\n  0n,                     // salt\n);\n```\n\n```typescript\n// Or query through the platform (also returns deployment status)\nconst wallet = await client.wallet.getAddress({\n  owner: signerAddress,\n  salt: 0n,\n});\n// wallet.address, wallet.deployed, wallet.factory, wallet.salt, wallet.chain\n```\n\n### Lazy Deployment\n\nThe wallet deploys automatically on the first UserOp, via `initCode`. `UserOpBuilder.setInitCode({ factory, owner, salt })` encodes the factory call for you.\n\n---\n\n## Sending a UserOperation\n\n`FcxWalletClient` does not expose a monolithic `execute()` helper -- you assemble a UserOp from the three building blocks (`UserOpBuilder`, a signer, `PaymasterClient`, `BundlerClient`). This keeps every step visible and overridable.\n\n```typescript\nimport {\n  UserOpBuilder,\n  EoaSigner,\n  getUserOpHash,\n} from '@aspect-wallet/sdk';\n\nconst signer = new EoaSigner(privateKey); // 0x…hex\nconst chainId = BigInt(client.chainId);\n\n// 1. Build\nconst userOp = await new UserOpBuilder(client.bundler, client.entryPoint, chainId)\n  .setSender(walletAddress)\n  .setCallData({ target, value, data })\n  // First deploy only — binds the initCode\n  // .setInitCode({ factory, owner, salt: 0n })\n  .setNonce({ key: 0n })\n  .build();\n\n// 2. Sponsorship (optional — skip for self-paid gas)\nconst approval = await client.sponsor.approve(userOp);\nuserOp.paymasterAndData = approval.paymasterAndData;\n\n// 3. Hash + sign\nconst hash = getUserOpHash(userOp, client.entryPoint, chainId);\nuserOp.signature = await signer.sign(hash);\n// EoaSigner returns moduleId(4) + ecdsaSig(65) = 69 bytes\n\n// 4. Submit\nconst userOpHash = await client.bundler.sendUserOperation(userOp);\n\n// 5. Wait for on-chain receipt\nconst receipt = await client.bundler.waitForReceipt(userOpHash, {\n  timeout: 60_000,\n  pollingInterval: 2_000,\n});\n```\n\n### Hash Computation\n\n`getUserOpHash(userOp, entryPoint, chainId)` matches `EntryPoint.getUserOpHash()` exactly -- variable-length fields (`initCode`, `callData`, `paymasterAndData`) are individually hashed, then `keccak256(abi.encode(innerHash, entryPoint, chainId))` anti-replays across chains.\n\n### Batch Calls\n\n```typescript\nconst userOp = await new UserOpBuilder(client.bundler, client.entryPoint, chainId)\n  .setSender(walletAddress)\n  .setCallDataBatch([\n    { target: tokenA, value: 0n, data: approveData },\n    { target: dex,    value: 0n, data: swapData    },\n  ])\n  .build();\n// All calls are atomic: all succeed, or the whole batch reverts.\n```\n\n---\n\n## Gas Sponsorship (Paymaster)\n\nUsers transact with **zero ETH**. The VerifyingPaymaster contract pays gas, authorised by your backend signing service. `paymasterAndData` is 97 bytes: `address(20) + validUntil(6) + validAfter(6) + signature(65)`.\n\n```typescript\nconst approval = await client.sponsor.approve(userOp);\n// approval.paymasterAndData, approval.validUntil, approval.validAfter, approval.estimatedCost\n\n// Budget + policy queries\nconst budget = await client.sponsor.getBudget();\nconst policy = await client.sponsor.getPolicy();\n```\n\n`PaymasterClient` can also be constructed standalone if you need sponsorship without the full `FcxWalletClient`:\n\n```typescript\nimport { PaymasterClient, ApiClient } from '@aspect-wallet/sdk';\n\nconst api = new ApiClient('https://paymaster.yourapp.com', apiKey);\nconst paymaster = new PaymasterClient(api, {\n  chainId: 421614,\n  entryPointAddress: '0x5FF1…',\n});\n```\n\n---\n\n## Authentication & Social Login\n\nAll auth clients take an `ApiClient` for the auth server. Wire them up once, share a `SessionManager` so a login via any method updates the same session.\n\n```typescript\nimport {\n  ApiClient,\n  AuthClient,\n  OAuthClient,\n  PasskeyAuthClient,\n  SessionManager,\n} from '@aspect-wallet/sdk';\n\nconst api        = new ApiClient('https://auth.yourapp.com', apiKey);\nconst session    = new SessionManager(api);\nconst email      = new AuthClient(api);            // AuthClient owns its own SessionManager\nconst oauth      = new OAuthClient(api, session);\nconst passkey    = new PasskeyAuthClient(api, session);\n```\n\n### Email OTP\n\n```typescript\nawait email.sendEmailOtp('user@example.com');\n\n// Rate limited: 3 attempts per OTP, 5 OTPs per hour per email\nconst info = await email.verifyEmailOtp({\n  email: 'user@example.com',\n  code:  '847291',\n});\n// info.jwt, info.refreshToken, info.user { id, email, signerAddress, … }, info.expiresAt\n```\n\n### OAuth (Google / Apple / Facebook)\n\n```typescript\nconst info = await oauth.loginWithGoogle();\nconst info = await oauth.loginWithApple();\nconst info = await oauth.loginWithFacebook();\n// First login: creates a Turnkey sub-org + signing key\n// Returning login: loads the existing key\n```\n\n### Passkey Authentication\n\nPasskeys use WebAuthn. The P256 public key is stored **on-chain** inside `WebAuthnValidationModule` — never in the backend database. Credentials live in the device secure enclave.\n\n```typescript\n// Registration (call this after email/OAuth login)\nconst reg = await passkey.registerPasskey({ displayName: 'My MacBook' });\n// reg.credentialId -- base64url; persist for future loginWithPasskey calls\n// reg.pubKeyX / reg.pubKeyY -- hex uint256 for on-chain installModule\n\n// Login from any device that has the credential\nconst info = await passkey.loginWithPasskey(walletAddress);\n```\n\n**Installing the WebAuthn module on-chain** (moduleId = 4) binds the public key to the account so on-chain verification works:\n\n```typescript\nimport { encodeAbiParameters } from 'viem';\n\nconst installData = encodeAbiParameters(\n  [{ type: 'uint256' }, { type: 'uint256' }],\n  [BigInt(reg.pubKeyX), BigInt(reg.pubKeyY)],\n);\n\n// Submit a UserOp that calls ModuleRouter.installModule(4, installData)\n// using UserOpBuilder + a signer as shown above.\n```\n\n---\n\n## Signing\n\n### Signer Interface\n\nAll signers implement `ISigner`:\n\n```typescript\ninterface ISigner {\n  type: 'eoa' | 'passkey' | 'turnkey' | 'session-key' | 'multi-sig';\n  address: Address;\n  moduleId: number;\n  sign(userOpHash: Hex): Promise<Hex>;\n}\n```\n\nEvery signature is prefixed with a 4-byte `moduleId` so `ModuleRouter` on-chain routes it to the correct validator.\n\n### EOA Signer\n\n```typescript\nimport { EoaSigner } from '@aspect-wallet/sdk';\n\nconst signer = new EoaSigner(privateKey); // Hex\nconst sig    = await signer.sign(userOpHash);\n// moduleId(4) + ecdsaSig(65) = 69 bytes, moduleId = 0 (SingleSigner)\n```\n\n### Session Key Signer\n\n```typescript\nimport { SessionKeySigner } from '@aspect-wallet/sdk';\n\nconst signer = new SessionKeySigner(sessionPrivateKey);\nconst sig    = await signer.sign(userOpHash);\n// Same 65-byte ECDSA wire format, moduleId = 1 (SessionKey)\n```\n\n### Passkey Signer\n\n`PasskeySigner` calls `navigator.credentials.get()` to trigger the biometric prompt, parses the DER-encoded P256 signature from the authenticator, normalises `s` to low-s, and ABI-encodes the result.\n\n```typescript\nimport { PasskeySigner } from '@aspect-wallet/sdk';\n\nconst signer = new PasskeySigner(walletAddress, credentialId);\nconst sig    = await signer.sign(userOpHash);\n// moduleId(4) + abi.encode(authenticatorData, clientDataJSON, r, s)\n// moduleId = 4 (WebAuthn); ~300–500 bytes total\n// Verified on-chain via RIP-7212 precompile or daimo-eth/p256-verifier fallback.\n```\n\nFor tests, pass the optional third `signFn` to skip the browser ceremony:\n\n```typescript\nnew PasskeySigner(walletAddress, credentialId, async (challenge) => ({\n  authenticatorData: '0x…',\n  clientDataJSON: '{\"type\":\"webauthn.get\",...}',\n  r: 0x…n,\n  s: 0x…n,\n}));\n```\n\n### Multi-Sig Collector\n\n```typescript\nimport { MultiSigCollector } from '@aspect-wallet/sdk';\n\nconst collector = new MultiSigCollector(threshold, signerAddresses);\ncollector.addSignature(sigFromOwner1);\ncollector.addSignature(sigFromOwner2);\nif (collector.isComplete) {\n  userOp.signature = await collector.sign(userOpHash); // concatenated packed sigs\n}\n```\n\n### Modular Signature Prefix (advanced)\n\n```typescript\nimport { encodeModuleSignature } from '@aspect-wallet/sdk';\n\nconst modularSig = encodeModuleSignature(0, ecdsaSignature);\n// Module IDs: 0=SingleSigner, 1=SessionKey, 2=DeviceGuardian, 3=MultiSig, 4=WebAuthn\n```\n\n---\n\n## Session Keys\n\nSession keys are ephemeral scoped keys. Once installed, they let a dApp execute transactions **without user interaction** per action — the key lives in the browser and signs locally. Permission hooks enforce limits on-chain.\n\n### Low-Level: `SessionKeyManager` (API-driven)\n\n```typescript\nimport { SessionKeyManager, SessionKeyTemplates } from '@aspect-wallet/sdk';\n\nconst keys = new SessionKeyManager(client.api);\n\n// Custom permissions\nconst info = await keys.create({\n  permissions: {\n    allowlist: [\n      { target: gameContract, selector: '0x12345678' },\n      { target: gameContract, selector: '0xabcdef01' },\n    ],\n    spendLimit: { perTx: 0n, cumulative: 0n },\n    timeRange: {\n      validAfter: Math.floor(Date.now() / 1000),\n      validUntil: Math.floor(Date.now() / 1000) + 4 * 3600,\n    },\n    requiredPaymaster: paymasterAddress,\n  },\n});\n\n// Or use a pre-built template\nconst perms = SessionKeyTemplates.gaming({\n  gameContract: '0x…',\n  duration:     4 * 3600,\n  paymaster:    '0x…',\n});\n\n// Execute via the managed API (server co-signs)\nawait keys.execute(info.moduleId, { target, value: 0n, data });\n\n// Revoke\nawait keys.revoke(info.moduleId);\n```\n\nAvailable templates on `SessionKeyTemplates`: `gaming`, `defi`, `subscription`, `nftMint`.\n\n### High-Level: `SessionKeyLifecycle` (browser-native)\n\nFor apps that want the key to live entirely in the browser (no auth round-trip on execute), use `SessionKeyLifecycle`. It generates the keypair locally, persists it in pluggable storage, listens for server-sent expiry events over an authenticated SSE stream, and auto-renews before the key expires.\n\n```typescript\nimport {\n  SessionKeyLifecycle,\n  WebSessionKeyStorage,\n} from '@aspect-wallet/sdk';\n\nconst lifecycle = new SessionKeyLifecycle({\n  walletAddress: '0x…',\n  platformUrl:   'https://platform.yourapp.com',\n  paymasterUrl:  'https://paymaster.yourapp.com',\n  bundlerUrl:    'https://bundler.yourapp.com/rpc',\n  rpcUrl:        'https://arb-sepolia-rpc.example.com',\n  chainId:       421614,\n  jwt:           ownerSessionJwt,\n  template:      'gaming',\n  storage:       new WebSessionKeyStorage(),\n  onExpiring: ({ remainingSeconds }) => toast(`Key expires in ${remainingSeconds}s`),\n  onRenewed:  ({ newExpiresAt })      => toast(`Renewed until ${new Date(newExpiresAt * 1000)}`),\n  onError:    (err)                   => console.error(err),\n});\n\nawait lifecycle.install();  // generate + register with the platform\nlifecycle.start();          // begin the SSE listener (auto-renew)\n\nconst result = await lifecycle.execute({\n  target: noteStoreAddress,\n  value:  0n,\n  data:   addNoteCallData,\n});\n// result.userOpHash, result.txHash?\n\nawait lifecycle.revoke();   // on logout / unmount\nlifecycle.stop();           // close the SSE stream\n```\n\n### Standalone: `executeViaSessionKey`\n\nWant the bare pipeline without the lifecycle manager? Call it directly:\n\n```typescript\nimport { executeViaSessionKey } from '@aspect-wallet/sdk';\n\nconst { userOpHash } = await executeViaSessionKey({\n  sessionPrivateKey,\n  moduleId:      1,\n  walletAddress: '0x…',\n  target,\n  value: 0n,\n  data,\n  paymasterUrl:  'https://paymaster.yourapp.com',\n  bundlerUrl:    'https://bundler.yourapp.com/rpc',\n  rpcUrl:        'https://arb-sepolia-rpc.example.com',\n  chainId:       421614,\n});\n```\n\n### Storage Adapters\n\n| Platform | Implementation | Backend | Lifecycle |\n|----------|---------------|---------|-----------|\n| Web | `WebSessionKeyStorage` | `window.sessionStorage` | Cleared on tab close |\n| Node / test | `MemorySessionKeyStorage` | `Map<string, string>` | Process lifetime |\n| Native (BYO) | Implement `SessionKeyStorage` | iOS Keychain / Android KeyStore | Persists across launches |\n\n---\n\n## Multi-Factor Authentication\n\nOn-chain enforced MFA -- the blockchain rejects transactions that don't meet the multi-factor requirements.\n\n### 4-Tier Step-Up Selection\n\n```typescript\nimport { TierSelector } from '@aspect-wallet/sdk';\n\nconst tier = TierSelector.select({\n  value:   parseEther('5'),\n  target:  tokenContract,\n  selector: '0xa9059cbb', // transfer(address,uint256)\n});\n// tier = 3  → requires device + guardian\n```\n\n| Tier | When | Signers | Latency |\n|------|------|---------|---------|\n| 1 | Low-value, scoped actions | Session key (auto-sign) | Instant |\n| 2 | Normal transactions | Owner key | 1 biometric prompt |\n| 3 | High-value transfers | Owner + Guardian | 2 approvals |\n| 4 | Account management | K-of-N multi-sig + timelock | Hours/days |\n\n### Guardian Management\n\n```typescript\nimport { GuardianManager } from '@aspect-wallet/sdk';\n\nconst guardians = new GuardianManager(client.api);\n\nawait guardians.addGuardian({ guardian: '0x…', label: 'Mom' });\nawait guardians.addGuardian({ guardian: '0x…', label: 'Backend Co-Signer' });\nawait guardians.setThreshold(2); // 2-of-3 required\n\nconst list       = await guardians.listGuardians(walletAddress);\nconst threshold  = await guardians.getThreshold(walletAddress);\nawait guardians.removeGuardian('0x…');\n```\n\n### Multi-Sig Proposals\n\n```typescript\nimport { MultiSigManager } from '@aspect-wallet/sdk';\n\nconst multisig = new MultiSigManager(client.api);\n\n// Owner 1 proposes\nconst proposal = await multisig.proposeMultiSig({ target, value: 0n, data });\n\n// Owner 2 approves -- if threshold met, the UserOp is submitted automatically\nawait multisig.approveMultiSig(proposal.id);\n\nconst current  = await multisig.getProposal(proposal.id);\nconst pending  = await multisig.listPending(walletAddress);\n```\n\n---\n\n## Account Recovery\n\n### Social Recovery (Guardian-Based)\n\n```typescript\nimport { SocialRecovery } from '@aspect-wallet/sdk';\n\nconst recovery = new SocialRecovery(client.api);\n\nawait recovery.initiateRecovery({ account: userWallet, newOwner: newKeyAddress });\nawait recovery.approveRecovery({ account: userWallet });\n\n// After timelock → execute\nawait recovery.executeRecovery({ account: userWallet });\n\n// Owner cancellation (during timelock)\nawait recovery.cancelRecovery();\n\nconst status = await recovery.getStatus(walletAddress);\n// { pending, approvals, threshold, executeAfter, canExecute, canCancel, newOwner? }\n```\n\n### Two-Step Key Rotation\n\n```typescript\nimport { KeyRotation } from '@aspect-wallet/sdk';\n\nconst rotation = new KeyRotation(client.api);\n\nawait rotation.initiateKeyRotation({ newOwner: newSignerAddress }); // current owner signs\nawait rotation.acceptKeyRotation();                                 // new owner signs\n// Old key loses access immediately; wallet address is unchanged.\n\nconst pending = await rotation.getPendingOwner(walletAddress);\n```\n\n### Multi-Device\n\n```typescript\nimport { DeviceManager } from '@aspect-wallet/sdk';\n\nconst devices = new DeviceManager(client.api);\n\nawait devices.addDevice({ name: 'iPhone 15', type: 'passkey', moduleId: 2 });\nawait devices.removeDevice(moduleId); // revoke a lost device\n\nconst list = await devices.listDevices(walletAddress);\n```\n\n---\n\n## Security & Emergency\n\n### Emergency Freeze\n\n```typescript\nimport { FreezeManager } from '@aspect-wallet/sdk';\n\nconst freeze = new FreezeManager(client.api);\n\nawait freeze.freeze({ reason: 'suspicious_activity' }); // revokes all session keys\nawait freeze.unfreeze();                                // requires MFA Tier 3/4\nconst isFrozen = await freeze.isFrozen(walletAddress);\n```\n\n### Bulk Session Key Revocation\n\n```typescript\nimport { RevokeManager } from '@aspect-wallet/sdk';\n\nconst revoke = new RevokeManager(client.api);\n\nawait revoke.revokeAllSessionKeys();\nconst { revokedCount } = await revoke.revokeSessionKeys({ expiredOnly: true });\n```\n\n### Watchtower Alerts\n\n```typescript\nimport { WatchtowerClient } from '@aspect-wallet/sdk';\n\nconst watchtower = new WatchtowerClient(client.api);\n\nawait watchtower.subscribe({\n  account: walletAddress,\n  alerts: ['recovery_initiated', 'owner_changed', 'large_transfer'],\n  channels: {\n    email:   'user@example.com',\n    webhook: 'https://myapp.com/webhooks/security',\n  },\n});\n\nconst alerts = await watchtower.getAlerts(walletAddress);\n```\n\n---\n\n## Audit & Events\n\n```typescript\nconst history = await client.audit.getHistory(walletAddress, {\n  limit: 50,\n  types: ['execute', 'deploy', 'module_install'],\n});\n// history.total, history.operations[] { userOpHash, transactionHash, target, value,\n//   signer, signerType, sponsored, paymaster?, gasCost, success, blockNumber, timestamp }\n\n// Real-time events\nconst unsubscribe = client.audit.subscribe(walletAddress, {\n  events: ['userop.mined', 'security.alert'],\n  onEvent: (e) => console.log(e.type, e.userOpHash),\n  onError: console.error,\n});\n\n// Webhook management\nawait client.audit.webhooks.create({\n  url:     'https://myapp.com/webhooks',\n  secret:  'whsec_…',\n  events:  ['userop.mined', 'session_key.installed'],\n});\n```\n\n---\n\n## Chain Configuration\n\nContract addresses come from the platform (`ChainRegistry`) at runtime -- keyed to your project via the API key.\n\n```typescript\nconst chains = await client.chains.list();             // all supported chains\nconst config = await client.chains.getConfig('arbitrum-sepolia');\n// config.chainId, config.entryPoint, config.contracts { factory, paymaster, …modules }\n\n// Switch chains on the same client\nclient.switchChain('base');\n\n// Or spin up a second client for cross-chain work\nconst baseClient = client.forChain('base');\n```\n\n---\n\n## Bundler Client\n\n```typescript\nimport { BundlerClient } from '@aspect-wallet/sdk';\n\nconst bundler = new BundlerClient('https://bundler.yourapp.com/rpc', entryPointAddress);\n\nconst hash    = await bundler.sendUserOperation(signedUserOp);\nconst est     = await bundler.estimateUserOperationGas(userOp);\n// est.preVerificationGas, est.verificationGasLimit, est.callGasLimit (hex)\n\nconst receipt = await bundler.waitForReceipt(hash, { timeout: 60_000, pollingInterval: 2_000 });\nconst points  = await bundler.getSupportedEntryPoints();\n```\n\n---\n\n## Error Handling\n\nAll SDK errors are instances of `FcxError` and carry a stable `code`:\n\n```typescript\nimport { FcxError } from '@aspect-wallet/sdk';\n\ntry {\n  await client.sponsor.approve(userOp);\n} catch (e) {\n  if (e instanceof FcxError) {\n    switch (e.code) {\n      case 'USEROP_SIGNATURE_INVALID':     // -32507\n      case 'USEROP_SIMULATION_FAILED':     // -32500\n      case 'SPONSOR_BUDGET_EXHAUSTED':\n      case 'SPONSOR_POLICY_REJECTED':\n      case 'SESSION_KEY_EXPIRED':\n      case 'SESSION_KEY_NOT_FOUND':\n      case 'SESSION_KEY_NOT_ALLOWED':\n      case 'SESSION_STORAGE_UNAVAILABLE':\n      case 'MFA_THRESHOLD_NOT_MET':\n      case 'AUTH_SESSION_EXPIRED':\n      case 'API_KEY_INVALID':\n      case 'WALLET_FROZEN':\n        // handle the specific failure mode\n        break;\n    }\n    console.error(e.code, e.message, e.details, e.retryable);\n  }\n}\n```\n\n`FcxError` also exposes `httpStatus`, `rpcCode`, `userOpHash?`, and static helpers `FcxError.fromRpcError()` and `FcxError.fromHttpError()`.\n\n---\n\n## TypeScript Types\n\nAll domain types are exported from the package root and from the `/types` sub-export:\n\n```typescript\nimport type {\n  UserOperation,\n  ExecutionResult,\n  SessionInfo,\n  WalletInfo,\n  WalletState,\n  SessionKeyPermissions,\n  SessionKeyInfo,\n  PaymasterApproval,\n  SponsorshipBudget,\n  RecoveryStatus,\n  AuditOperation,\n  ChainId,\n  ChainInfo,\n  ChainConfig,\n} from '@aspect-wallet/sdk';\n\n// Or the narrow types-only import\nimport type { UserOperation } from '@aspect-wallet/sdk/types';\n```\n\n---\n\n## Architecture\n\n```\nYour Frontend App\n       │\n       ▼\n@aspect-wallet/sdk (this package)\n       │\n       ├── BundlerClient ───── eth_sendUserOperation ──► EntryPoint (on-chain)\n       │                                                       │\n       ├── PaymasterClient ─── POST /api/paymaster/sign        ├── Smart Account (proxy)\n       │                                                       ├── Factory (CREATE2 / ERC-1167)\n       ├── AuthClient ──────── POST /auth/email/verify         ├── VerifyingPaymaster\n       │   OAuthClient         POST /auth/oauth/{provider}     └── Validation Modules\n       │   PasskeyAuthClient   POST /auth/passkey/*                ├── SingleSigner\n       │                                                           ├── WebAuthn (P256)\n       ├── SessionKeyLifecycle POST /session-keys/install          ├── MultiSig (K-of-N)\n       │                        GET /session-keys/events (SSE)     ├── SessionKey + hooks\n       │                                                           │   (Allowlist,\n       └── ChainRegistry / AuditClient / WatchtowerClient          │    SpendLimit,\n                                                                   │    TimeRange,\n                                                                   │    PaymasterGuard)\n                                                                   └── SocialRecovery\n```\n\n---\n\n## Supported Chains\n\n- Arbitrum One, Arbitrum Sepolia\n- Base, Base Sepolia\n- Polygon, Polygon Amoy\n- Ethereum, Sepolia\n\nSame CREATE2 address across every chain where the factory is deployed at the same address.\n\n---\n\n## Requirements\n\n- Node.js >= 18\n- `viem` 2.x\n- EVM chain with ERC-4337 EntryPoint v0.6 deployed at `0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789`\n\n## License\n\nMIT\n","readmeFilename":"README.md"}