{"_id":"@baliola/smart-account-sdk","_rev":"7-06359865a5325a26132e0be5618fa8d9","name":"@baliola/smart-account-sdk","dist-tags":{"latest":"0.4.0"},"versions":{"0.3.1":{"name":"@baliola/smart-account-sdk","version":"0.3.1","keywords":["erc-4337","account-abstraction","smart-account","viem","mac","baliola"],"author":{"name":"Baliola Development Team"},"license":"SEE LICENSE IN LICENSE","_id":"@baliola/smart-account-sdk@0.3.1","maintainers":[{"name":"gustutyoghantara","email":"npm@baliola.io"}],"homepage":"https://github.com/baliola/smart-account#readme","bugs":{"url":"https://github.com/baliola/smart-account/issues"},"dist":{"shasum":"f82971fb3656aeabf2d3a08d2f9807a84356492f","tarball":"https://registry.npmjs.org/@baliola/smart-account-sdk/-/smart-account-sdk-0.3.1.tgz","fileCount":32,"integrity":"sha512-tuolpSq4Ylw8CGQ0C54oxZG8UKC4cWLir4G8oLNYu0VnPsOVb5h5rGgClznZ8DPIsawQd0yKxAGdSWQsz2JKpA==","signatures":[{"sig":"MEQCIDfXcE931+2Gqb/Glr+7guNuX7jvuVQbgyZw2YdSmjyeAiAXzy7BeWNdtJDqtSwarOz/OZTVBlzQ5hp+aF3oErhd9w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":127303},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./types":{"types":"./dist/types/index.d.ts","import":"./dist/types/index.js"},"./chains":{"types":"./dist/chains/index.d.ts","import":"./dist/chains/index.js"},"./errors":{"types":"./dist/errors/index.d.ts","import":"./dist/errors/index.js"},"./actions":{"types":"./dist/actions/index.d.ts","import":"./dist/actions/index.js"},"./clients":{"types":"./dist/clients/index.d.ts","import":"./dist/clients/index.js"},"./accounts":{"types":"./dist/accounts/index.d.ts","import":"./dist/accounts/index.js"}},"gitHead":"e04bb9db1ed25ed817716096b5b420e9faf98e83","scripts":{"test":"bun test test/unit test/integration","build":"tsdown","test:e2e":"LIVE=1 bun test --env-file=../bundler/.env test/e2e","typecheck":"tsc --noEmit","prepublishOnly":"bun run build"},"_npmUser":{"name":"gustutyoghantara","email":"npm@baliola.io"},"repository":{"url":"git+https://github.com/baliola/smart-account.git","type":"git","directory":"sdk"},"_npmVersion":"10.9.3","description":"Client-side SDK for Baliola's Smart Account (ERC-4337) stack on MAC","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"viem":"^2.46.3","tsdown":"^0.21.10","@types/bun":"latest","typescript":"^5.7.3","@baliola/smart-account-shared":"workspace:*"},"peerDependencies":{"viem":"^2.46"},"_npmOperationalInternal":{"tmp":"tmp/smart-account-sdk_0.3.1_1779331941288_0.3677922041517234","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@baliola/smart-account-sdk","version":"0.3.2","keywords":["erc-4337","account-abstraction","smart-account","viem","mac","baliola"],"author":{"name":"Baliola Development Team"},"license":"SEE LICENSE IN LICENSE","_id":"@baliola/smart-account-sdk@0.3.2","maintainers":[{"name":"gustutyoghantara","email":"npm@baliola.io"}],"homepage":"https://github.com/baliola/smart-account#readme","bugs":{"url":"https://github.com/baliola/smart-account/issues"},"dist":{"shasum":"03c49f76395d5c3c57a2c338fb325f0ab3a41170","tarball":"https://registry.npmjs.org/@baliola/smart-account-sdk/-/smart-account-sdk-0.3.2.tgz","fileCount":32,"integrity":"sha512-bR2q4xpyZHj8NBor7Dizy3TUwH77z4a8MxcZAdIQ2kBXQmMP8+zjKlDUNX3UkNeBMnqRCxesPaWf8vNdkrCQ1A==","signatures":[{"sig":"MEQCIEJcc9DPtiiAB/7YJnsPyM1zOFRwJ4YFIrnA9RVt5crNAiB+4Pratkm9CkurYyqQRqkJ2ztaKBPx+AoNGvpKGHAiSQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":133268},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./auth":{"types":"./dist/auth/index.d.ts","import":"./dist/auth/index.js"},"./types":{"types":"./dist/types/index.d.ts","import":"./dist/types/index.js"},"./chains":{"types":"./dist/chains/index.d.ts","import":"./dist/chains/index.js"},"./errors":{"types":"./dist/errors/index.d.ts","import":"./dist/errors/index.js"},"./actions":{"types":"./dist/actions/index.d.ts","import":"./dist/actions/index.js"},"./clients":{"types":"./dist/clients/index.d.ts","import":"./dist/clients/index.js"},"./accounts":{"types":"./dist/accounts/index.d.ts","import":"./dist/accounts/index.js"}},"gitHead":"464dab740d2da8be484b52566eacfe65f367261c","scripts":{"test":"bun test test/unit test/integration","build":"tsdown","test:e2e":"LIVE=1 bun test --env-file=../bundler/.env test/e2e","typecheck":"tsc --noEmit","prepublishOnly":"bun run build"},"_npmUser":{"name":"gustutyoghantara","email":"npm@baliola.io"},"repository":{"url":"git+https://github.com/baliola/smart-account.git","type":"git","directory":"sdk"},"_npmVersion":"10.9.3","description":"Client-side SDK for Baliola's Smart Account (ERC-4337) stack on MAC","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"viem":"^2.46.3","tsdown":"^0.21.10","@types/bun":"latest","typescript":"^5.7.3","@baliola/smart-account-shared":"workspace:*"},"peerDependencies":{"viem":"^2.46"},"_npmOperationalInternal":{"tmp":"tmp/smart-account-sdk_0.3.2_1782876950842_0.33746310363953613","host":"s3://npm-registry-packages-npm-production"}},"0.3.3":{"name":"@baliola/smart-account-sdk","version":"0.3.3","keywords":["erc-4337","account-abstraction","smart-account","viem","mac","baliola"],"author":{"name":"Baliola Development Team"},"license":"SEE LICENSE IN LICENSE","_id":"@baliola/smart-account-sdk@0.3.3","maintainers":[{"name":"gustutyoghantara","email":"npm@baliola.io"}],"homepage":"https://github.com/baliola/smart-account#readme","bugs":{"url":"https://github.com/baliola/smart-account/issues"},"dist":{"shasum":"1fc7f34033c190f56e1451103229e0f47391db26","tarball":"https://registry.npmjs.org/@baliola/smart-account-sdk/-/smart-account-sdk-0.3.3.tgz","fileCount":33,"integrity":"sha512-t/PCxvEg41GOKld3lzN9CP/ro6t+yPqwov7rYk2JiP2Vs/2Zq+84XF+6BEZQ1sPU4+pT0eiuhu2IQQjLhPxwFw==","signatures":[{"sig":"MEUCIQDM0vKRGwh/JA5t+kD2tnnZLIi1n3CRFIFmLZjQNGhl2QIgbZj3GWUgHMqrEhcJYCRptxPwKU4MQI635ROnH2FeT7A=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":133917},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./types":{"types":"./dist/types/index.d.ts","import":"./dist/types/index.js"},"./chains":{"types":"./dist/chains/index.d.ts","import":"./dist/chains/index.js"},"./errors":{"types":"./dist/errors/index.d.ts","import":"./dist/errors/index.js"},"./actions":{"types":"./dist/actions/index.d.ts","import":"./dist/actions/index.js"},"./clients":{"types":"./dist/clients/index.d.ts","import":"./dist/clients/index.js"},"./accounts":{"types":"./dist/accounts/index.d.ts","import":"./dist/accounts/index.js"},"./api-keys":{"types":"./dist/api-keys/index.d.ts","import":"./dist/api-keys/index.js"}},"gitHead":"464dab740d2da8be484b52566eacfe65f367261c","scripts":{"test":"bun test test/unit test/integration","build":"tsdown","test:e2e":"LIVE=1 bun test --env-file=../bundler/.env test/e2e","typecheck":"tsc --noEmit","prepublishOnly":"bun run build"},"_npmUser":{"name":"gustutyoghantara","email":"npm@baliola.io"},"repository":{"url":"git+https://github.com/baliola/smart-account.git","type":"git","directory":"sdk"},"_npmVersion":"10.9.3","description":"Client-side SDK for Baliola's Smart Account (ERC-4337) stack on MAC","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"viem":"^2.46.3","tsdown":"^0.21.10","@types/bun":"latest","typescript":"^5.7.3","@baliola/smart-account-shared":"workspace:*"},"peerDependencies":{"viem":"^2.46"},"_npmOperationalInternal":{"tmp":"tmp/smart-account-sdk_0.3.3_1783582702579_0.3960790374969847","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@baliola/smart-account-sdk","version":"0.4.0","description":"Client-side SDK for Baliola's Smart Account (ERC-4337) stack on MAC","keywords":["erc-4337","account-abstraction","smart-account","viem","mac","baliola"],"license":"SEE LICENSE IN LICENSE","author":{"name":"Baliola Development Team"},"repository":{"type":"git","url":"git+https://github.com/baliola/smart-account.git","directory":"sdk"},"publishConfig":{"registry":"https://registry.npmjs.org","access":"public"},"type":"module","sideEffects":false,"main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./accounts":{"types":"./dist/accounts/index.d.ts","import":"./dist/accounts/index.js"},"./actions":{"types":"./dist/actions/index.d.ts","import":"./dist/actions/index.js"},"./api-keys":{"types":"./dist/api-keys/index.d.ts","import":"./dist/api-keys/index.js"},"./chains":{"types":"./dist/chains/index.d.ts","import":"./dist/chains/index.js"},"./clients":{"types":"./dist/clients/index.d.ts","import":"./dist/clients/index.js"},"./errors":{"types":"./dist/errors/index.d.ts","import":"./dist/errors/index.js"},"./types":{"types":"./dist/types/index.d.ts","import":"./dist/types/index.js"}},"scripts":{"build":"tsdown","typecheck":"tsc --noEmit","test":"bun test test/unit test/integration","test:e2e":"LIVE=1 bun test --env-file=../bundler/.env test/e2e","prepublishOnly":"bun run build"},"peerDependencies":{"viem":"^2.46"},"devDependencies":{"@baliola/smart-account-shared":"workspace:*","@types/bun":"latest","tsdown":"^0.21.10","typescript":"^5.7.3","viem":"^2.46.3"},"_id":"@baliola/smart-account-sdk@0.4.0","gitHead":"61276f889c915a4032f2d8d643f27deb65fb423d","bugs":{"url":"https://github.com/baliola/smart-account/issues"},"homepage":"https://github.com/baliola/smart-account#readme","_nodeVersion":"22.20.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-wra2xPTYMccpX5AjjYWtnKtIqaa6bFRMpOIgb5Owpw6J5kJHfJz+VSNsiXilvdlV+rYqlOkSUygjYVdpaoZgEA==","shasum":"fe2caef862d5caac2bc4137b2f250de803e07f8c","tarball":"https://registry.npmjs.org/@baliola/smart-account-sdk/-/smart-account-sdk-0.4.0.tgz","fileCount":34,"unpackedSize":139308,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDZDSYlEolCYu1blHPbtNBOTRR949WvW3BX879QcvyljQIgP6RtnmcmO6zT5YDOH+gvllufdGdKGIMj1KoCI5gyec4="}]},"_npmUser":{"name":"gustutyoghantara","email":"npm@baliola.io"},"directories":{},"maintainers":[{"name":"gustutyoghantara","email":"npm@baliola.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/smart-account-sdk_0.4.0_1785743701262_0.8005493318151811"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-21T02:52:21.162Z","modified":"2026-08-03T07:55:01.635Z","0.3.0":"2026-05-21T02:47:32.491Z","0.3.1":"2026-05-21T02:52:21.433Z","0.3.2":"2026-07-01T03:35:50.994Z","0.3.3":"2026-07-09T07:38:22.722Z","0.4.0":"2026-08-03T07:55:01.454Z"},"bugs":{"url":"https://github.com/baliola/smart-account/issues"},"author":{"name":"Baliola Development Team"},"license":"SEE LICENSE IN LICENSE","homepage":"https://github.com/baliola/smart-account#readme","keywords":["erc-4337","account-abstraction","smart-account","viem","mac","baliola"],"repository":{"type":"git","url":"git+https://github.com/baliola/smart-account.git","directory":"sdk"},"description":"Client-side SDK for Baliola's Smart Account (ERC-4337) stack on MAC","maintainers":[{"name":"gustutyoghantara","email":"npm@baliola.io"}],"readme":"# @baliola/smart-account-sdk\n\nClient-side TypeScript SDK for Baliola's ERC-4337 v0.7 stack on **MAC and Mandala chains**. A thin viem extension that handles UserOperation packing, signing, bundler RPC, and Gas Allowance Pool (paymaster) wiring. Pick a chain by name, plug in your API key, send transactions.\n\n```ts\nconst account = await toSmartAccount({ owner, chain: \"macTestnet\" });\nconst client = await createSmartAccountClient({\n  account,\n  chain: \"macTestnet\",\n  apiKey: BALIOLA_KEY,\n});\n\nconst userOpHash = await client.writeContract({\n  address: nft,\n  abi: nftAbi,\n  functionName: \"mint\",\n  args: [1n],\n});\n\nconst receipt = await client.waitForUserOperationReceipt({ userOpHash });\n```\n\n## Install\n\n```sh\nbun add @baliola/smart-account-sdk viem\n# or: npm install / pnpm add\n```\n\n`viem` (`^2.46`) is a peer dependency. Install it alongside.\n\n## Quick Start\n\n```ts\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport {\n  createSmartAccountClient,\n  toSmartAccount,\n} from \"@baliola/smart-account-sdk\";\n\nconst owner = privateKeyToAccount(process.env.OWNER_KEY as `0x${string}`);\n\nconst account = await toSmartAccount({\n  owner,\n  chain: \"macTestnet\",\n});\n\n// createSmartAccountClient is async. It validates the API key against\n// the Baliola console API before returning.\nconst client = await createSmartAccountClient({\n  account,\n  chain: \"macTestnet\",\n  apiKey: process.env.BALIOLA_KEY!,\n});\n\nconst userOpHash = await client.writeContract({\n  address: \"0xYourContract\",\n  abi: yourAbi,\n  functionName: \"doSomething\",\n});\n\nconst receipt = await client.waitForUserOperationReceipt({ userOpHash });\nconsole.log(\"included in tx:\", receipt.txHash);\n```\n\n## Chains\n\nPick a chain by name and everything else is preconfigured: chain RPC, bundler RPC, and the console API URL.\n\n| `chain` | Network | Bundler |\n| --- | --- | --- |\n| `\"macTestnet\"` | MAC Testnet (20017) | `bundler-testnet.baliola.dev/macTestnet/rpc` |\n| `\"mandalaTestnet\"` | Mandala Testnet (20011) | `bundler-testnet.baliola.dev/mandalaTestnet/rpc` |\n| `\"mandalaMainnet\"` | Mandala Mainnet (20010) | `bundler-mainnet.baliola.io/mandalaMainnet/rpc` |\n\nEvery chain listed here works end to end — the SDK does not offer a chain whose\nERC-4337 stack is not deployed. MAC Mainnet (20016) is absent for that reason and\nwill be added once its stack ships.\n\nThe bundler endpoint is derived from the chain, not configured: testnet chains\nresolve to the testnet host, mainnet chains to the mainnet host, and the path\nsegment is always the chain name itself. Switching networks is a one-word change.\n\n```ts\nimport { macTestnet, mandalaMainnet, resolveChain, CHAINS, bundlerUrlFor } from \"@baliola/smart-account-sdk\";\n\nresolveChain(\"macTestnet\");       // viem Chain object\nObject.keys(CHAINS);              // [\"macTestnet\", \"mandalaTestnet\", \"mandalaMainnet\"]\nbundlerUrlFor(\"mandalaMainnet\");  // \"https://bundler-mainnet.baliola.io/mandalaMainnet/rpc\"\n```\n\n## API Key Validation\n\n`createSmartAccountClient` validates the API key once at construction time against the Baliola **console API** (`POST /api-keys/validate`). On success, the resolved key info is exposed on `client.apiKey`. On rejection it throws `ApiKeyInvalidError`; on transport failure it throws `ApiKeyServiceUnreachableError`.\n\n```ts\ntry {\n  const client = await createSmartAccountClient({\n    account,\n    chain: \"macTestnet\",\n    apiKey: BALIOLA_KEY,\n  });\n\n  client.apiKey.accountId;                // Baliola account uuid that owns the key\n  client.apiKey.type;                     // \"client\" | \"secret\"\n} catch (err) {\n  if (err instanceof ApiKeyInvalidError) {\n    switch (err.reason) {\n      case \"invalid_key\":\n        // unknown, revoked, expired, or wrong-tier key — the user needs a new one\n        break;\n      case \"origin_not_allowed\":\n        // a client key whose origin allowlist rejects this request's Origin\n        break;\n    }\n  } else if (err instanceof ApiKeyServiceUnreachableError) {\n    // console API down or network issue; safe to retry\n  }\n}\n```\n\n> Use a **secret** key (`baliola_secret_…`) for server-side use. **client** keys (`baliola_client_…`) are checked against the request `Origin` header — meant for the browser, where the browser sets `Origin` for you. Cache the client; don't rebuild it on every request.\n\nTo point at a custom console host (for staging or dev), pass `apiKeyUrl`:\n\n```ts\nawait createSmartAccountClient({\n  account,\n  chain: \"macTestnet\",\n  apiKey: BALIOLA_KEY,\n  apiKeyUrl: \"https://your-console-host\",\n});\n```\n\n## `createSmartAccountClient` options\n\n```ts\nawait createSmartAccountClient({\n  account,                              // required, from toSmartAccount\n  chain,                                // required, \"macTestnet\" | \"mandalaTestnet\" | \"mandalaMainnet\"\n  apiKey,                               // required\n  apiKeyUrl?,                           // override the chain's default console API host\n  paymasterAddress?,                    // override the chain's default Gas Allowance Pool\n  transport?,                           // chain RPC transport (defaults to chain's built-in RPC)\n});\n```\n\nResolution precedence:\n\n- **Console API URL**: `apiKeyUrl` then the default for the chain.\n- **Chain RPC**: `transport` then `http()` of the chain default.\n- **Bundler RPC**: derived from the chain — see `bundlerUrlFor`. There is no override.\n- **Paymaster**: `paymasterAddress` then the chain's registered Gas Allowance Pool, otherwise throw `PaymasterConfigError`.\n\n## `toSmartAccount` options\n\n```ts\ntoSmartAccount({\n  owner,                                // required, viem Account or \"0x\"-prefixed 32-byte private key\n  chain,                                // required, \"macTestnet\" | \"mandalaTestnet\" | \"mandalaMainnet\"\n  salt?,                                // CREATE2 salt for counterfactual address (default 0n)\n  nonceKey?,                            // EntryPoint nonce key (default 0n)\n  transport?,                           // chain RPC transport (defaults to chain's built-in RPC)\n  publicClient?,                        // share a publicClient across calls (default: built internally)\n});\n```\n\nReturned `ISmartAccount` is counterfactual until the first UserOperation is sent. The factory call is injected automatically.\n\n## `writeContract`, the single write verb\n\nSame shape for everything: a typed call, a raw call, or a batch.\n\n### Typed contract call\n\n```ts\nconst userOpHash = await client.writeContract({\n  address: counter,\n  abi: counterAbi,\n  functionName: \"increment\",\n  args: [],\n  value: 0n,                            // optional\n});\n```\n\n### Raw call (ETH transfer or pre-encoded data)\n\n```ts\n// Pure native transfer\nawait client.writeContract({ to: recipient, value: 1n });\n\n// Pre-encoded calldata\nawait client.writeContract({ to: target, value: 0n, data: \"0xabcd...\" });\n```\n\n### Batch with an array\n\nMixed typed and raw entries are allowed in one batch. The whole batch is one UserOperation submitted via `SimpleAccount.executeBatch`.\n\n```ts\nconst userOpHash = await client.writeContract([\n  { address: usdc, abi: erc20Abi, functionName: \"approve\", args: [router, amount] },\n  { address: router, abi: routerAbi, functionName: \"swap\", args: [...] },\n  { to: refundAddr, value: 1n },        // raw entry alongside typed ones\n]);\n```\n\n### Overrides\n\nA second optional argument lets you override UserOperation-level fields (gas, fee, paymaster, nonce). Most callers never touch this.\n\n```ts\nawait client.writeContract(input, {\n  preVerificationGas: 200_000n,\n  maxFeePerGas: 5_000_000_000n,\n});\n```\n\n## Receipts\n\n```ts\n// One-shot; returns null if not yet included\nconst maybe = await client.getUserOperationReceipt({ userOpHash });\n\n// Poll until included or timeout\nconst receipt = await client.waitForUserOperationReceipt({\n  userOpHash,\n  timeout: 60_000,\n  pollingInterval: 1_000,\n  signal: abortSignal,                  // optional AbortSignal\n});\n\nreceipt.userOpHash;     // ERC-4337 hash\nreceipt.txHash;         // on-chain handleOps tx hash\nreceipt.blockNumber;\nreceipt.success;\nreceipt.actualGasUsed;\nreceipt.actualGasCost;\nreceipt.logs;           // pre-sliced to this UserOp\n```\n\n## Watching events\n\nSubscribe to `EntryPoint.UserOperationEvent` filtered by sender or a specific `userOpHash`. The SDK decodes each match into typed fields.\n\n```ts\nconst unwatch = client.watchUserOperations({\n  // Defaults to your account's address when omitted\n  sender: account.address,\n  onUserOp(event) {\n    console.log(event.userOpHash, event.success, event.actualGasCost);\n  },\n  onError(err) { console.error(err); },\n});\n\nunwatch();                              // stop the subscription\n```\n\n## Paymaster (Gas Allowance Pool)\n\nEvery UserOperation is sponsored by a paymaster. The default is the **Gas Allowance Pool (GAP)** registered for the chain, no configuration required.\n\n```ts\n// Default: uses the chain's GAP\nawait createSmartAccountClient({ account, chain: \"macTestnet\", apiKey });\n\n// Override: route through a different paymaster contract\nawait createSmartAccountClient({\n  account, chain: \"macTestnet\", apiKey,\n  paymasterAddress: \"0x...\",\n});\n```\n\n`paymasterAddress` is validated at construction. Invalid or zero addresses throw `PaymasterConfigError`. Self-funded mode is not supported.\n\n## Errors\n\nEvery SDK error extends `SmartAccountSDKError`. The library is **opinionated about messages**: `err.message` is always written for an end user (short, polite, and safe to surface directly in product UI). Technical detail lives on:\n\n- `err.code`: internal tag or AA code (e.g. `\"API_KEY_INVALID\"`, `\"AA24\"`)\n- `err.reason`: typed enum on errors that have one (`ApiKeyInvalidError`, `PaymasterConfigError`)\n- `err.detail`: optional technical sentence for developer logs\n- `err.cause`: the underlying transport or library error\n\nDiscriminate with `instanceof`, not message matching.\n\n```text\nSmartAccountSDKError                    // root\n├─ UserOperationReceiptTimeoutError\n├─ PaymasterConfigError                 // dev-config error, carries `reason`\n├─ ApiKeyInvalidError                   // console API rejected the key (carries `reason`)\n├─ ApiKeyServiceUnreachableError        // network or non-2xx talking to the console API\n├─ BundlerRpcError\n│   ├─ InvalidUserOperationError        // bundler rejected the params\n│   ├─ UserOperationRejectedError       // bundler dropped on submit\n│   └─ BundlerUnreachableError          // network or timeout\n└─ UserOperationRevertError             // AA-code reverts\n    ├─ AccountFactoryError              // AA1x\n    ├─ AccountValidationError           // AA2x: signature, nonce, prefund\n    ├─ PaymasterValidationError         // AA3x: paymaster rejection\n    └─ BundleFrameError                 // AA9x\n```\n\n### Surfacing errors\n\nYou can pipe `err.message` straight into a toast or banner. It's already user-safe:\n\n```ts\ntry {\n  await client.writeContract({ /* ... */ });\n} catch (err) {\n  toast(err instanceof Error ? err.message : \"Something went wrong.\");\n  console.error(err); // full technical detail still on err.detail / err.cause\n}\n```\n\n### Default user messages\n\n| Error | `err.message` |\n| --- | --- |\n| `ApiKeyInvalidError` (reason=`invalid_key`) | \"Invalid API key. Please check your credentials.\" |\n| `ApiKeyInvalidError` (reason=`origin_not_allowed`) | \"This domain isn't allowed to use this API key.\" |\n| `ApiKeyServiceUnreachableError` | \"API key service is temporarily unavailable. Please try again in a moment.\" |\n| `BundlerUnreachableError` | \"Couldn't reach the network. Please check your connection and try again.\" |\n| `UserOperationReceiptTimeoutError` | \"Your transaction is taking longer than expected. Please check the block explorer or try again.\" |\n| `PaymasterValidationError` (AA3x) | \"Gas sponsorship was declined for this transaction. Please try again later.\" |\n| `AccountValidationError` (AA2x) | \"Your transaction couldn't be authorized. Please try again.\" |\n| `AccountFactoryError` (AA1x) | \"We couldn't set up your smart account. Please try again.\" |\n| `BundleFrameError` (AA9x) | \"Something went wrong submitting your transaction. Please try again.\" |\n| `InvalidUserOperationError` | \"Your transaction was rejected before submission. Please try again.\" |\n| `UserOperationRejectedError` | \"Your transaction was rejected by the network. Please try again.\" |\n| `PaymasterConfigError` | \"Gas sponsorship isn't available for this network. Please contact support.\" |\n\n### Tailoring the copy\n\nIf you need different tone, branding, or i18n, switch on the typed fields and write your own copy. Every error carries enough metadata to do so:\n\n```ts\nfunction copy(err: unknown): string {\n  if (err instanceof ApiKeyInvalidError) {\n    switch (err.reason) {\n      case \"origin_not_allowed\": return \"This domain can't use this key.\";\n      case \"invalid_key\": return \"Your API key is invalid. Please check your credentials.\";\n    }\n  }\n  if (err instanceof Error) return err.message; // sensible default\n  return \"Something went wrong.\";\n}\n```\n\n## Subpath imports\n\n```ts\nimport { createSmartAccountClient } from \"@baliola/smart-account-sdk\";\nimport { toSmartAccount } from \"@baliola/smart-account-sdk/accounts\";\nimport { writeContract } from \"@baliola/smart-account-sdk/actions\";\nimport { validateApiKey, DEFAULT_API_KEY_URLS } from \"@baliola/smart-account-sdk/api-keys\";\nimport { macTestnet, CHAINS } from \"@baliola/smart-account-sdk/chains\";\nimport { DEFAULT_BUNDLER_URLS } from \"@baliola/smart-account-sdk/clients\";\nimport { SmartAccountSDKError } from \"@baliola/smart-account-sdk/errors\";\nimport type { UserOperationReceipt } from \"@baliola/smart-account-sdk/types\";\n```\n\n## License\n\nProprietary. Copyright 2026 Baliola. All rights reserved. See [LICENSE](./LICENSE).\n","readmeFilename":"README.md"}