@tuwaio/orbit-evm 0.2.22 → 0.3.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 CHANGED
@@ -1,18 +1,19 @@
1
1
  # @tuwaio/orbit-evm
2
2
 
3
3
  [![NPM Version](https://img.shields.io/npm/v/@tuwaio/orbit-evm.svg)](https://www.npmjs.com/package/@tuwaio/orbit-evm)
4
- [![License](https://img.shields.io/npm/l/@tuwaio/orbit-evm.svg)](./LICENSE)
4
+ [![License](https://img.shields.io/npm/l/@tuwaio/orbit-evm.svg)](https://github.com/TuwaIO/orbit/blob/main/packages/orbit-evm/LICENSE)
5
5
 
6
- `@tuwaio/orbit-evm` provides concrete implementations of low-level EVM-specific communication primitives for Layer 2 (L2) of the TUWA Orbit stack. Engineered strictly on top of **`@wagmi/core`** and **`viem`**, this package provides deterministic chain switching, custom Viem client generation, and cached ENS metadata resolution, while enforcing a complete exclusion of legacy libraries like `ethers.js` or `web3.js`.
6
+ `@tuwaio/orbit-evm` is the EVM Layer 2 (L2) package of **Orbit Utils**, the Stage 1 primitives layer of the TUWA ecosystem. It wraps **`viem`** and **`@wagmi/core`** into small, framework-agnostic helpers: cached public clients, chain switching, ENS resolution, and ERC-4337 smart accounts built on Solady with a Pimlico bundler and paymaster. It does not use `ethers.js` or `web3.js`.
7
7
 
8
8
  ---
9
9
 
10
10
  ## 🏛️ Core Capabilities
11
11
 
12
- - **Viem Client Optimization:** Creates and caches high-performance `viem` public clients (`createViemClient`) to minimize request latency and avoid duplicate RPC instantiation.
13
- - **ENS Metadata Engine:** Direct lookup utilities (`getName`, `getAvatar`, `getAddress`) on the Ethereum Mainnet context with local caching.
14
- - **Deterministic Chain Switching:** Low-level utility (`checkAndSwitchChain`) to enforce network alignment with the target blockchain, requesting wallet configurations dynamically.
15
- - **Strict Compile-Time Types:** Fully integrated with TypeScript standards v5.9+ and native Viem/Wagmi typings.
12
+ - **Public clients:** `createViemClient` returns a cached `viem` public client per chain, so repeated reads do not create new clients.
13
+ - **Chain alignment:** `checkAndSwitchChain` asks the connected wallet to switch networks only when it is on a different chain, and throws a readable error when the user rejects.
14
+ - **ENS resolution:** `getName`, `getAvatar` and `getAddress` always resolve against Ethereum Mainnet and cache results in memory; `isEnsName` tells names and addresses apart.
15
+ - **ERC-4337 smart accounts:** `createPimlicoSmartAccountClient` sets up a Solady smart account (EntryPoint v0.7), a bundler client and an optional gas-sponsoring paymaster in one call. Bundler and paymaster clients are cached in memory per endpoint. The building blocks (`createSoladySmartAccount`, `createBundlerRpcClient`, `createPimlicoPaymasterClient`, `createPimlicoRpcUrl`, `clearBundlerCache`) are exported for custom setups.
16
+ - **Chain lists:** `getEvmChains` and `isEvmChainList` extract and detect EVM chain IDs in mixed multi-chain configurations.
16
17
 
17
18
  ---
18
19
 
@@ -23,56 +24,123 @@ pnpm add @tuwaio/orbit-evm @wagmi/core viem
23
24
  ```
24
25
 
25
26
  > [!IMPORTANT]
26
- > `@wagmi/core` and `viem` are peer dependencies and must be installed alongside `@tuwaio/orbit-evm`.
27
+ > `viem` (2.x) and `@wagmi/core` (3.x) are peer dependencies and must be installed alongside `@tuwaio/orbit-evm`.
27
28
 
28
29
  ---
29
30
 
30
- ## 🚀 Technical Integration
31
+ ## 🚀 Usage
31
32
 
32
- ### Cached Client Generation & Routing
33
-
34
- Create a public client wrapper to route queries to EVM nodes:
33
+ ### Cached public client
35
34
 
36
35
  ```typescript
37
36
  import { createViemClient } from '@tuwaio/orbit-evm';
38
- import { mainnet } from 'viem/chains';
37
+ import { mainnet, sepolia } from 'viem/chains';
38
+
39
+ const chains = [mainnet, sepolia] as const;
39
40
 
40
- // Retrieve cached or new Viem Public Client
41
- const client = createViemClient(mainnet);
41
+ // Returns undefined (and logs a warning) if the chain ID is not in `chains`.
42
+ const client = createViemClient(sepolia.id, chains);
43
+ const blockNumber = await client?.getBlockNumber();
42
44
  ```
43
45
 
44
- ### Deterministic Chain Switcher
46
+ The client uses the chain's default RPC URL. The cache is keyed by chain ID and is rebuilt when that URL changes.
45
47
 
46
- Enforce that the wallet's connection context matches the requested chain:
48
+ ### Chain switching
47
49
 
48
50
  ```typescript
49
- import { checkAndSwitchChain } from '@tuwaio/orbit-evm';
50
51
  import { type Config } from '@wagmi/core';
52
+ import { checkAndSwitchChain } from '@tuwaio/orbit-evm';
51
53
 
52
- declare const config: Config;
54
+ declare const wagmiConfig: Config;
53
55
 
54
- async function switchNetwork(targetChainId: number) {
55
- try {
56
- await checkAndSwitchChain(targetChainId, config);
57
- console.log(`Execution context successfully switched to: ${targetChainId}`);
58
- } catch (error) {
59
- console.error('Chain switch rejected:', error);
60
- }
56
+ try {
57
+ await checkAndSwitchChain(11155111, wagmiConfig);
58
+ } catch (error) {
59
+ // "User rejected the request to switch network." or a generic switch error (original error in `cause`).
60
+ console.error(error);
61
61
  }
62
62
  ```
63
63
 
64
- ---
64
+ ### ENS resolution
65
+
66
+ ```typescript
67
+ import { getAddress, getAvatar, getName, isEnsName } from '@tuwaio/orbit-evm';
68
+ import { mainnet } from 'viem/chains';
69
+
70
+ const chains = [mainnet] as const;
71
+
72
+ const name = await getName('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', chains); // "vitalik.eth" or null
73
+ const avatar = name ? await getAvatar(name, chains) : null;
74
+
75
+ const input = 'vitalik.eth';
76
+ const address = isEnsName(input) ? await getAddress(input, chains) : null; // lowercased address or null
77
+ ```
78
+
79
+ Lookups use the mainnet entry of `chains` when present (so your own RPC URL is used), otherwise viem's default mainnet RPC.
80
+
81
+ ### ERC-4337 smart account with Pimlico
82
+
83
+ ```typescript
84
+ import { type Config } from '@wagmi/core';
85
+ import { createPimlicoSmartAccountClient } from '@tuwaio/orbit-evm';
86
+ import { sepolia } from 'viem/chains';
87
+
88
+ declare const wagmiConfig: Config;
89
+
90
+ const { account, bundlerClient } = await createPimlicoSmartAccountClient({
91
+ chain: sepolia,
92
+ wagmiConfig, // or pass `walletClient` directly
93
+ apiKey: process.env.NEXT_PUBLIC_PIMLICO_API_KEY, // or `bundlerUrl` for your own bundler endpoint
94
+ });
95
+
96
+ const userOpHash = await bundlerClient.sendUserOperation({
97
+ account,
98
+ calls: [{ to: '0x0000000000000000000000000000000000000000', value: 0n }],
99
+ });
100
+ const receipt = await bundlerClient.waitForUserOperationReceipt({ hash: userOpHash });
101
+ ```
102
+
103
+ - A connected wallet is required: the EOA signs for the smart account.
104
+ - Gas sponsorship (`sponsor`) is on by default when `apiKey` or `bundlerUrl` is set. Without either, the public Pimlico endpoint is used and no paymaster is attached.
105
+ - The smart account uses viem's Solady implementation with its default EntryPoint v0.7 (`entryPoint07Address`).
106
+ - The account salt defaults to the owner address right-padded to 32 bytes (`pad(owner, { dir: 'right', size: 32 })`). This satisfies the Solady factory's owner-prefix check (`SaltDoesNotStartWith()`) and gives every owner a deterministic, unique account address. Pass `salt` to override it.
65
107
 
66
- ## 🔧 API & Module Architecture
108
+ > [!WARNING]
109
+ > The Pimlico API key becomes part of the bundler URL used by the browser. Use a key restricted to your domains and sponsorship policies, or proxy the bundler through your backend and pass its address as `bundlerUrl`.
67
110
 
68
- `@tuwaio/orbit-evm` exposes the following modules:
111
+ ### Low-level bundler building blocks
69
112
 
70
- - **Chain Alignment:** `checkAndSwitchChain`.
71
- - **Client Factory:** `createViemClient`.
72
- - **ENS Resolvers:** `getAddress`, `getAvatar`, `getName`, `isEnsName`.
113
+ ```typescript
114
+ import {
115
+ clearBundlerCache,
116
+ createBundlerRpcClient,
117
+ createPimlicoPaymasterClient,
118
+ createPimlicoRpcUrl,
119
+ } from '@tuwaio/orbit-evm';
120
+
121
+ // Resolution order: bundlerUrl → https://api.pimlico.io/v2/{chainId}/rpc?apikey=… → https://public.pimlico.io/v2/{chainId}/rpc
122
+ const rpcUrl = createPimlicoRpcUrl({ chainId: 11155111, apiKey: process.env.PIMLICO_API_KEY });
123
+
124
+ // Cached by resolved URL.
125
+ const paymasterClient = createPimlicoPaymasterClient({ chainId: 11155111, apiKey: process.env.PIMLICO_API_KEY });
126
+
127
+ // Cached by resolved URL, paymaster presence and client presence.
128
+ const bundlerClient = createBundlerRpcClient({
129
+ chainId: 11155111,
130
+ apiKey: process.env.PIMLICO_API_KEY,
131
+ paymaster: paymasterClient,
132
+ });
133
+
134
+ // Drops cached URLs, bundler and paymaster clients (e.g. after rotating the API key).
135
+ clearBundlerCache();
136
+ ```
73
137
 
74
138
  ---
75
139
 
140
+ ## 📚 API Reference
141
+
142
+ Every export, with signatures and types generated from the source, is documented at **[orbit.docs.tuwa.io/packages/orbit-evm](https://orbit.docs.tuwa.io/packages/orbit-evm)**. For a full walkthrough of sovereign account abstraction with Orbit, Pulsar and Quasar, see the [ERC-4337 guide](https://docs.tuwa.io/guides/erc-4337-sovereign-account-abstraction).
143
+
76
144
  ## 📄 License
77
145
 
78
- Licensed under the **Apache-2.0 License**. See the [LICENSE](./LICENSE) file for details.
146
+ Licensed under the **Apache-2.0 License**. See the [LICENSE](https://github.com/TuwaIO/orbit/blob/main/packages/orbit-evm/LICENSE) file for details.
package/dist/index.d.mts CHANGED
@@ -1,13 +1,148 @@
1
- import { Chain } from 'viem/chains';
2
1
  import { Config } from '@wagmi/core';
3
- import { PublicClient, Address, Hex } from 'viem';
2
+ import { HttpTransport, Client, PublicClient, WalletClient, Hex, Chain, Address } from 'viem';
3
+ import { BundlerClientConfig, toSoladySmartAccount, ToSoladySmartAccountReturnType, BundlerClient, PaymasterClient } from 'viem/account-abstraction';
4
+ import { Chain as Chain$1 } from 'viem/chains';
4
5
 
5
6
  /**
6
- * Get EVM chain IDs from app chains configuration
7
+ * @file Utilities for Pimlico and ERC-4337 Bundler client instantiation with local in-memory caching.
7
8
  */
8
- declare function getEvmChains(appChains?: readonly [Chain, ...Chain[]]): number[];
9
+
10
+ /**
11
+ * Exported alias for Solady Smart Account type.
12
+ */
13
+ type SoladySmartAccount = ToSoladySmartAccountReturnType;
14
+ /**
15
+ * Configuration options for generating Pimlico Bundler RPC URLs.
16
+ */
17
+ interface PimlicoUrlConfig {
18
+ /** Target EVM chain ID (e.g. 1 for Ethereum Mainnet, 11155111 for Sepolia). */
19
+ chainId: number;
20
+ /** Optional Pimlico API key. If omitted, falls back to public RPC or bundlerUrl. */
21
+ apiKey?: string;
22
+ /** Optional explicit custom bundler RPC URL that takes precedence. */
23
+ bundlerUrl?: string;
24
+ }
25
+ /**
26
+ * Optional additional configuration forwarded to Viem's createBundlerClient.
27
+ */
28
+ type BundlerRpcClientConfig = PimlicoUrlConfig & Partial<Omit<BundlerClientConfig<HttpTransport>, 'transport' | 'client'>> & {
29
+ /** Optional execution client or public client used for fee estimation. */
30
+ client?: Client | PublicClient;
31
+ };
32
+ /**
33
+ * Parameters for creating a Solady ERC-4337 Smart Account.
34
+ */
35
+ interface CreateSoladySmartAccountParams {
36
+ /** The client used to interact with the blockchain. */
37
+ client: Parameters<typeof toSoladySmartAccount>[0]['client'];
38
+ /** The connected WalletClient (e.g. from Wagmi or browser provider) representing the EOA owner. */
39
+ walletClient: WalletClient;
40
+ /**
41
+ * Optional 32-byte salt for deterministic counterfactual deployment.
42
+ * Defaults to right-padded EOA address to satisfy Solady factory owner-prefix verification.
43
+ */
44
+ salt?: Hex;
45
+ }
46
+ /**
47
+ * Configuration options for instantiating a Pimlico-powered ERC-4337 Smart Account client.
48
+ */
49
+ interface PimlicoSmartAccountClientConfig {
50
+ /** Target EVM chain. */
51
+ chain: Chain;
52
+ /** The connected WalletClient representing the EOA signer. */
53
+ walletClient?: WalletClient;
54
+ /** Wagmi Config used to resolve the walletClient if not explicitly provided. */
55
+ wagmiConfig?: Config;
56
+ /** Optional public client for reading chain state. If omitted, one is created automatically. */
57
+ client?: PublicClient | Client;
58
+ /** Optional Pimlico API key. */
59
+ apiKey?: string;
60
+ /** Optional explicit custom bundler RPC URL. */
61
+ bundlerUrl?: string;
62
+ /** Optional RPC URL for public client execution transport (e.g., Alchemy / Infura). */
63
+ rpcUrl?: string;
64
+ /**
65
+ * Whether to configure and attach Pimlico paymaster for gas sponsorship.
66
+ * Defaults to true if apiKey or bundlerUrl is provided.
67
+ */
68
+ sponsor?: boolean;
69
+ /** Optional 32-byte salt for Solady smart account. */
70
+ salt?: Hex;
71
+ }
72
+ /**
73
+ * Result object returned by `createPimlicoSmartAccountClient`.
74
+ */
75
+ interface PimlicoSmartAccountClientResult {
76
+ /** The instantiated Solady smart account instance. */
77
+ account: SoladySmartAccount;
78
+ /** The configured Viem Bundler client. */
79
+ bundlerClient: BundlerClient<HttpTransport>;
80
+ /** The public client used for chain state reads and fee estimation. */
81
+ publicClient: PublicClient;
82
+ /** The Pimlico paymaster client if gas sponsorship is enabled. */
83
+ paymasterClient?: PaymasterClient;
84
+ }
85
+ /**
86
+ * Creates and caches a Pimlico RPC URL based on provided configuration.
87
+ *
88
+ * Priority order:
89
+ * 1. Explicit `bundlerUrl` (if provided, returned directly).
90
+ * 2. Dedicated Pimlico endpoint `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${apiKey}` (if apiKey provided).
91
+ * 3. Public community endpoint `https://public.pimlico.io/v2/${chainId}/rpc` (fallback).
92
+ *
93
+ * @param config - The Pimlico URL configuration.
94
+ * @returns The resolved Bundler RPC URL string.
95
+ */
96
+ declare function createPimlicoRpcUrl(config: PimlicoUrlConfig): string;
97
+ /**
98
+ * Creates or retrieves a cached Viem Bundler Client configured for the resolved Pimlico endpoint.
99
+ *
100
+ * @param config - Bundler URL and optional client configuration parameters.
101
+ * @returns Cached or newly instantiated BundlerClient.
102
+ */
103
+ declare function createBundlerRpcClient(config: BundlerRpcClientConfig): BundlerClient<HttpTransport>;
104
+ /**
105
+ * Creates or retrieves a cached Viem Paymaster Client configured with the resolved Pimlico RPC endpoint.
106
+ * Side effect: stores the client in an in-memory cache keyed by the resolved RPC URL (see `clearBundlerCache`).
107
+ *
108
+ * @param config - Pimlico URL configuration.
109
+ * @returns Cached or newly instantiated PaymasterClient configured for Pimlico gas sponsorship.
110
+ */
111
+ declare function createPimlicoPaymasterClient(config: PimlicoUrlConfig): PaymasterClient;
112
+ /**
113
+ * Instantiates a Solady ERC-4337 smart account with automatic wallet signing delegation
114
+ * and Solady factory-compliant deterministic salt.
115
+ *
116
+ * @param params - Configuration parameters including client and walletClient.
117
+ * @returns Promise resolving to the initialized SoladySmartAccount.
118
+ */
119
+ declare function createSoladySmartAccount({ client, walletClient, salt, }: CreateSoladySmartAccountParams): Promise<SoladySmartAccount>;
120
+ /**
121
+ * High-level orchestration utility that instantiates a Solady smart account,
122
+ * configures a Pimlico paymaster (sponsorship), and binds them to a Pimlico Bundler client.
123
+ *
124
+ * @param config - Configuration options including chain, wallet/wagmi, and Pimlico credentials.
125
+ * @returns Promise resolving to { account, bundlerClient, publicClient, paymasterClient }.
126
+ */
127
+ declare function createPimlicoSmartAccountClient(config: PimlicoSmartAccountClientConfig): Promise<PimlicoSmartAccountClientResult>;
128
+ /**
129
+ * Clears the in-memory caches of Pimlico URLs, Bundler clients and Paymaster clients.
130
+ * Useful for testing and resetting runtime state (e.g. after rotating an API key).
131
+ */
132
+ declare function clearBundlerCache(): void;
133
+
9
134
  /**
10
- * Type guard to check if a chain list contains EVM chain IDs
135
+ * Gets the EVM chain IDs from an app's viem chain configuration.
136
+ *
137
+ * @param appChains - The viem chains configured in the app.
138
+ * @returns The positive numeric chain IDs, or an empty array if no chains are provided.
139
+ */
140
+ declare function getEvmChains(appChains?: readonly [Chain$1, ...Chain$1[]]): number[];
141
+ /**
142
+ * Type guard to check if a chain list contains EVM chain IDs.
143
+ *
144
+ * @param chains - Mixed list of chain identifiers.
145
+ * @returns `true` if the list is non-empty and contains only numbers.
11
146
  */
12
147
  declare function isEvmChainList(chains: (string | number)[]): chains is number[];
13
148
 
@@ -46,7 +181,7 @@ declare function checkAndSwitchChain(chainId: number, config: Config): Promise<v
46
181
  * @returns {import('viem').PublicClient | undefined} A viem PublicClient instance if a matching chain is found, otherwise undefined.
47
182
  * It will also log a warning to the console if the chain is not configured.
48
183
  */
49
- declare function createViemClient(chainId: number, chains: readonly [Chain, ...Chain[]]): PublicClient | undefined;
184
+ declare function createViemClient(chainId: number, chains: readonly [Chain$1, ...Chain$1[]]): PublicClient | undefined;
50
185
 
51
186
  /**
52
187
  * @file This file contains utility functions for interacting with the Ethereum Name Service (ENS).
@@ -62,7 +197,7 @@ declare function createViemClient(chainId: number, chains: readonly [Chain, ...C
62
197
  * @param {readonly [Chain, ...Chain[]]} chains - The list of chains to use for client creation.
63
198
  * @returns {Promise<string | null>} The ENS name if found, otherwise null.
64
199
  */
65
- declare const getName: (address: Hex, chains: readonly [Chain, ...Chain[]]) => Promise<string | null>;
200
+ declare const getName: (address: Hex, chains: readonly [Chain$1, ...Chain$1[]]) => Promise<string | null>;
66
201
  /**
67
202
  * Fetches the avatar URL for a given ENS name from the Ethereum Mainnet.
68
203
  * Includes caching for performance.
@@ -71,7 +206,7 @@ declare const getName: (address: Hex, chains: readonly [Chain, ...Chain[]]) => P
71
206
  * @param {readonly [Chain, ...Chain[]]} chains - The list of chains to use for client creation.
72
207
  * @returns {Promise<string | null>} The URL of the avatar image if found, otherwise null.
73
208
  */
74
- declare const getAvatar: (name: string, chains: readonly [Chain, ...Chain[]]) => Promise<string | null>;
209
+ declare const getAvatar: (name: string, chains: readonly [Chain$1, ...Chain$1[]]) => Promise<string | null>;
75
210
  /**
76
211
  * Fetches the Ethereum address associated with a given ENS name from the Ethereum Mainnet.
77
212
  * Includes caching for performance.
@@ -80,7 +215,7 @@ declare const getAvatar: (name: string, chains: readonly [Chain, ...Chain[]]) =>
80
215
  * @param {readonly [Chain, ...Chain[]]} chains - The list of chains to use for client creation.
81
216
  * @returns {Promise<Address | null>} The associated Ethereum address (lowercase) or null if not found.
82
217
  */
83
- declare const getAddress: (name: string, chains: readonly [Chain, ...Chain[]]) => Promise<Address | null>;
218
+ declare const getAddress: (name: string, chains: readonly [Chain$1, ...Chain$1[]]) => Promise<Address | null>;
84
219
  /**
85
220
  * A heuristic to check if a string is likely an ENS name.
86
221
  *
@@ -97,4 +232,4 @@ declare const getAddress: (name: string, chains: readonly [Chain, ...Chain[]]) =
97
232
  */
98
233
  declare const isEnsName: (nameOrAddress: string) => boolean;
99
234
 
100
- export { checkAndSwitchChain, createViemClient, getAddress, getAvatar, getEvmChains, getName, isEnsName, isEvmChainList };
235
+ export { type BundlerRpcClientConfig, type CreateSoladySmartAccountParams, type PimlicoSmartAccountClientConfig, type PimlicoSmartAccountClientResult, type PimlicoUrlConfig, type SoladySmartAccount, checkAndSwitchChain, clearBundlerCache, createBundlerRpcClient, createPimlicoPaymasterClient, createPimlicoRpcUrl, createPimlicoSmartAccountClient, createSoladySmartAccount, createViemClient, getAddress, getAvatar, getEvmChains, getName, isEnsName, isEvmChainList };
package/dist/index.d.ts CHANGED
@@ -1,13 +1,148 @@
1
- import { Chain } from 'viem/chains';
2
1
  import { Config } from '@wagmi/core';
3
- import { PublicClient, Address, Hex } from 'viem';
2
+ import { HttpTransport, Client, PublicClient, WalletClient, Hex, Chain, Address } from 'viem';
3
+ import { BundlerClientConfig, toSoladySmartAccount, ToSoladySmartAccountReturnType, BundlerClient, PaymasterClient } from 'viem/account-abstraction';
4
+ import { Chain as Chain$1 } from 'viem/chains';
4
5
 
5
6
  /**
6
- * Get EVM chain IDs from app chains configuration
7
+ * @file Utilities for Pimlico and ERC-4337 Bundler client instantiation with local in-memory caching.
7
8
  */
8
- declare function getEvmChains(appChains?: readonly [Chain, ...Chain[]]): number[];
9
+
10
+ /**
11
+ * Exported alias for Solady Smart Account type.
12
+ */
13
+ type SoladySmartAccount = ToSoladySmartAccountReturnType;
14
+ /**
15
+ * Configuration options for generating Pimlico Bundler RPC URLs.
16
+ */
17
+ interface PimlicoUrlConfig {
18
+ /** Target EVM chain ID (e.g. 1 for Ethereum Mainnet, 11155111 for Sepolia). */
19
+ chainId: number;
20
+ /** Optional Pimlico API key. If omitted, falls back to public RPC or bundlerUrl. */
21
+ apiKey?: string;
22
+ /** Optional explicit custom bundler RPC URL that takes precedence. */
23
+ bundlerUrl?: string;
24
+ }
25
+ /**
26
+ * Optional additional configuration forwarded to Viem's createBundlerClient.
27
+ */
28
+ type BundlerRpcClientConfig = PimlicoUrlConfig & Partial<Omit<BundlerClientConfig<HttpTransport>, 'transport' | 'client'>> & {
29
+ /** Optional execution client or public client used for fee estimation. */
30
+ client?: Client | PublicClient;
31
+ };
32
+ /**
33
+ * Parameters for creating a Solady ERC-4337 Smart Account.
34
+ */
35
+ interface CreateSoladySmartAccountParams {
36
+ /** The client used to interact with the blockchain. */
37
+ client: Parameters<typeof toSoladySmartAccount>[0]['client'];
38
+ /** The connected WalletClient (e.g. from Wagmi or browser provider) representing the EOA owner. */
39
+ walletClient: WalletClient;
40
+ /**
41
+ * Optional 32-byte salt for deterministic counterfactual deployment.
42
+ * Defaults to right-padded EOA address to satisfy Solady factory owner-prefix verification.
43
+ */
44
+ salt?: Hex;
45
+ }
46
+ /**
47
+ * Configuration options for instantiating a Pimlico-powered ERC-4337 Smart Account client.
48
+ */
49
+ interface PimlicoSmartAccountClientConfig {
50
+ /** Target EVM chain. */
51
+ chain: Chain;
52
+ /** The connected WalletClient representing the EOA signer. */
53
+ walletClient?: WalletClient;
54
+ /** Wagmi Config used to resolve the walletClient if not explicitly provided. */
55
+ wagmiConfig?: Config;
56
+ /** Optional public client for reading chain state. If omitted, one is created automatically. */
57
+ client?: PublicClient | Client;
58
+ /** Optional Pimlico API key. */
59
+ apiKey?: string;
60
+ /** Optional explicit custom bundler RPC URL. */
61
+ bundlerUrl?: string;
62
+ /** Optional RPC URL for public client execution transport (e.g., Alchemy / Infura). */
63
+ rpcUrl?: string;
64
+ /**
65
+ * Whether to configure and attach Pimlico paymaster for gas sponsorship.
66
+ * Defaults to true if apiKey or bundlerUrl is provided.
67
+ */
68
+ sponsor?: boolean;
69
+ /** Optional 32-byte salt for Solady smart account. */
70
+ salt?: Hex;
71
+ }
72
+ /**
73
+ * Result object returned by `createPimlicoSmartAccountClient`.
74
+ */
75
+ interface PimlicoSmartAccountClientResult {
76
+ /** The instantiated Solady smart account instance. */
77
+ account: SoladySmartAccount;
78
+ /** The configured Viem Bundler client. */
79
+ bundlerClient: BundlerClient<HttpTransport>;
80
+ /** The public client used for chain state reads and fee estimation. */
81
+ publicClient: PublicClient;
82
+ /** The Pimlico paymaster client if gas sponsorship is enabled. */
83
+ paymasterClient?: PaymasterClient;
84
+ }
85
+ /**
86
+ * Creates and caches a Pimlico RPC URL based on provided configuration.
87
+ *
88
+ * Priority order:
89
+ * 1. Explicit `bundlerUrl` (if provided, returned directly).
90
+ * 2. Dedicated Pimlico endpoint `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${apiKey}` (if apiKey provided).
91
+ * 3. Public community endpoint `https://public.pimlico.io/v2/${chainId}/rpc` (fallback).
92
+ *
93
+ * @param config - The Pimlico URL configuration.
94
+ * @returns The resolved Bundler RPC URL string.
95
+ */
96
+ declare function createPimlicoRpcUrl(config: PimlicoUrlConfig): string;
97
+ /**
98
+ * Creates or retrieves a cached Viem Bundler Client configured for the resolved Pimlico endpoint.
99
+ *
100
+ * @param config - Bundler URL and optional client configuration parameters.
101
+ * @returns Cached or newly instantiated BundlerClient.
102
+ */
103
+ declare function createBundlerRpcClient(config: BundlerRpcClientConfig): BundlerClient<HttpTransport>;
104
+ /**
105
+ * Creates or retrieves a cached Viem Paymaster Client configured with the resolved Pimlico RPC endpoint.
106
+ * Side effect: stores the client in an in-memory cache keyed by the resolved RPC URL (see `clearBundlerCache`).
107
+ *
108
+ * @param config - Pimlico URL configuration.
109
+ * @returns Cached or newly instantiated PaymasterClient configured for Pimlico gas sponsorship.
110
+ */
111
+ declare function createPimlicoPaymasterClient(config: PimlicoUrlConfig): PaymasterClient;
112
+ /**
113
+ * Instantiates a Solady ERC-4337 smart account with automatic wallet signing delegation
114
+ * and Solady factory-compliant deterministic salt.
115
+ *
116
+ * @param params - Configuration parameters including client and walletClient.
117
+ * @returns Promise resolving to the initialized SoladySmartAccount.
118
+ */
119
+ declare function createSoladySmartAccount({ client, walletClient, salt, }: CreateSoladySmartAccountParams): Promise<SoladySmartAccount>;
120
+ /**
121
+ * High-level orchestration utility that instantiates a Solady smart account,
122
+ * configures a Pimlico paymaster (sponsorship), and binds them to a Pimlico Bundler client.
123
+ *
124
+ * @param config - Configuration options including chain, wallet/wagmi, and Pimlico credentials.
125
+ * @returns Promise resolving to { account, bundlerClient, publicClient, paymasterClient }.
126
+ */
127
+ declare function createPimlicoSmartAccountClient(config: PimlicoSmartAccountClientConfig): Promise<PimlicoSmartAccountClientResult>;
128
+ /**
129
+ * Clears the in-memory caches of Pimlico URLs, Bundler clients and Paymaster clients.
130
+ * Useful for testing and resetting runtime state (e.g. after rotating an API key).
131
+ */
132
+ declare function clearBundlerCache(): void;
133
+
9
134
  /**
10
- * Type guard to check if a chain list contains EVM chain IDs
135
+ * Gets the EVM chain IDs from an app's viem chain configuration.
136
+ *
137
+ * @param appChains - The viem chains configured in the app.
138
+ * @returns The positive numeric chain IDs, or an empty array if no chains are provided.
139
+ */
140
+ declare function getEvmChains(appChains?: readonly [Chain$1, ...Chain$1[]]): number[];
141
+ /**
142
+ * Type guard to check if a chain list contains EVM chain IDs.
143
+ *
144
+ * @param chains - Mixed list of chain identifiers.
145
+ * @returns `true` if the list is non-empty and contains only numbers.
11
146
  */
12
147
  declare function isEvmChainList(chains: (string | number)[]): chains is number[];
13
148
 
@@ -46,7 +181,7 @@ declare function checkAndSwitchChain(chainId: number, config: Config): Promise<v
46
181
  * @returns {import('viem').PublicClient | undefined} A viem PublicClient instance if a matching chain is found, otherwise undefined.
47
182
  * It will also log a warning to the console if the chain is not configured.
48
183
  */
49
- declare function createViemClient(chainId: number, chains: readonly [Chain, ...Chain[]]): PublicClient | undefined;
184
+ declare function createViemClient(chainId: number, chains: readonly [Chain$1, ...Chain$1[]]): PublicClient | undefined;
50
185
 
51
186
  /**
52
187
  * @file This file contains utility functions for interacting with the Ethereum Name Service (ENS).
@@ -62,7 +197,7 @@ declare function createViemClient(chainId: number, chains: readonly [Chain, ...C
62
197
  * @param {readonly [Chain, ...Chain[]]} chains - The list of chains to use for client creation.
63
198
  * @returns {Promise<string | null>} The ENS name if found, otherwise null.
64
199
  */
65
- declare const getName: (address: Hex, chains: readonly [Chain, ...Chain[]]) => Promise<string | null>;
200
+ declare const getName: (address: Hex, chains: readonly [Chain$1, ...Chain$1[]]) => Promise<string | null>;
66
201
  /**
67
202
  * Fetches the avatar URL for a given ENS name from the Ethereum Mainnet.
68
203
  * Includes caching for performance.
@@ -71,7 +206,7 @@ declare const getName: (address: Hex, chains: readonly [Chain, ...Chain[]]) => P
71
206
  * @param {readonly [Chain, ...Chain[]]} chains - The list of chains to use for client creation.
72
207
  * @returns {Promise<string | null>} The URL of the avatar image if found, otherwise null.
73
208
  */
74
- declare const getAvatar: (name: string, chains: readonly [Chain, ...Chain[]]) => Promise<string | null>;
209
+ declare const getAvatar: (name: string, chains: readonly [Chain$1, ...Chain$1[]]) => Promise<string | null>;
75
210
  /**
76
211
  * Fetches the Ethereum address associated with a given ENS name from the Ethereum Mainnet.
77
212
  * Includes caching for performance.
@@ -80,7 +215,7 @@ declare const getAvatar: (name: string, chains: readonly [Chain, ...Chain[]]) =>
80
215
  * @param {readonly [Chain, ...Chain[]]} chains - The list of chains to use for client creation.
81
216
  * @returns {Promise<Address | null>} The associated Ethereum address (lowercase) or null if not found.
82
217
  */
83
- declare const getAddress: (name: string, chains: readonly [Chain, ...Chain[]]) => Promise<Address | null>;
218
+ declare const getAddress: (name: string, chains: readonly [Chain$1, ...Chain$1[]]) => Promise<Address | null>;
84
219
  /**
85
220
  * A heuristic to check if a string is likely an ENS name.
86
221
  *
@@ -97,4 +232,4 @@ declare const getAddress: (name: string, chains: readonly [Chain, ...Chain[]]) =
97
232
  */
98
233
  declare const isEnsName: (nameOrAddress: string) => boolean;
99
234
 
100
- export { checkAndSwitchChain, createViemClient, getAddress, getAvatar, getEvmChains, getName, isEnsName, isEvmChainList };
235
+ export { type BundlerRpcClientConfig, type CreateSoladySmartAccountParams, type PimlicoSmartAccountClientConfig, type PimlicoSmartAccountClientResult, type PimlicoUrlConfig, type SoladySmartAccount, checkAndSwitchChain, clearBundlerCache, createBundlerRpcClient, createPimlicoPaymasterClient, createPimlicoRpcUrl, createPimlicoSmartAccountClient, createSoladySmartAccount, createViemClient, getAddress, getAvatar, getEvmChains, getName, isEnsName, isEvmChainList };
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
- 'use strict';var core=require('@wagmi/core'),viem=require('viem'),chains=require('viem/chains'),ens=require('viem/ens');function C(e){return e!=null&&typeof e=="number"&&e>0}function E(e){return !e||e.length===0?[]:e.map(r=>r.id).filter(C)}function N(e){return e.length>0&&e.every(r=>typeof r=="number")}async function U(e,r){let{connector:t,chainId:o}=core.getConnection(r);if(t&&o!==e)try{await core.switchChain(r,{chainId:e});}catch(n){throw n.cause?.name==="UserRejectedRequestError"?new Error("User rejected the request to switch network.",{cause:n}):(console.error("Failed to switch network:",n),new Error("An error occurred while switching the network.",{cause:n}))}}var u=new Map;function s(e,r){let t=r.find(n=>n.id===e),o=u.get(e);if(o&&o.chain?.rpcUrls.default.http[0]===t?.rpcUrls.default.http[0])return o;if(t){let n=viem.createPublicClient({chain:t,transport:viem.http()});return u.set(e,n),n}console.warn(`createViemClient: No chain configuration found for chainId ${e}. A client could not be created.`);}var d=new Map,m=new Map,f=new Map,c=e=>{let r=e.find(t=>t.id===chains.mainnet.id);return r?s(chains.mainnet.id,[r]):s(chains.mainnet.id,[chains.mainnet])},D=async(e,r)=>{let t=c(r);if(!t)return null;let o=d.get(e);if(o!==void 0)return o;try{let n=await ens.getEnsName(t,{address:e});return d.set(e,n),n}catch(n){return console.error(`ENS name lookup failed for address ${e}:`,n),null}},G=async(e,r)=>{let t=c(r);if(!t)return null;let o=ens.normalize(e),n=m.get(o);if(n!==void 0)return n;try{let i=await ens.getEnsAvatar(t,{name:o});return m.set(o,i),i}catch(i){return console.error(`ENS avatar lookup failed for name ${e}:`,i),null}},I=async(e,r)=>{let t=c(r);if(!t)return null;let o=ens.normalize(e),n=f.get(o);if(n!==void 0)return n;try{let i=await ens.getEnsAddress(t,{name:o}),l=i?i.toLowerCase():null;return f.set(o,l),l}catch(i){return console.error(`ENS address lookup failed for name ${e}:`,i),null}},J=e=>e.includes(".")&&!viem.isAddress(e);exports.checkAndSwitchChain=U;exports.createViemClient=s;exports.getAddress=I;exports.getAvatar=G;exports.getEvmChains=E;exports.getName=D;exports.isEnsName=J;exports.isEvmChainList=N;
1
+ 'use strict';var core=require('@wagmi/core'),viem=require('viem'),accountAbstraction=require('viem/account-abstraction'),accounts=require('viem/accounts'),chains=require('viem/chains'),ens=require('viem/ens');var m=new Map,p=new Map,C=new Map;function K(e){return e.bundlerUrl?`custom:${e.bundlerUrl.trim()}`:`${e.chainId}:${e.apiKey?.trim()??"public"}`}function N(e){let t=f(e),r=!!e.paymaster,n=!!e.client;return `${t}:pm=${r}:client=${n}`}function f(e){let t=K(e),r=m.get(t);if(r)return r;let n;return e.bundlerUrl?n=e.bundlerUrl.trim():e.apiKey?n=`https://api.pimlico.io/v2/${e.chainId}/rpc?apikey=${e.apiKey.trim()}`:n=`https://public.pimlico.io/v2/${e.chainId}/rpc`,m.set(t,n),n}function R(e){let t=N(e),r=p.get(t);if(r)return r;let n=f(e),i={...e};delete i.bundlerUrl,delete i.apiKey;let a=accountAbstraction.createBundlerClient({...i,transport:viem.http(n)});return p.set(t,a),a}function k(e){let t=f(e),r=C.get(t);if(r)return r;let n=accountAbstraction.createPaymasterClient({transport:viem.http(t)});return C.set(t,n),n}async function M({client:e,walletClient:t,salt:r}){if(!t.account)throw new Error("WalletClient must have an active account.");let n=t.account,i=accounts.toAccount({address:n.address,async signMessage({message:o}){return t.signMessage({account:n,message:o})},async signTransaction(o){return t.signTransaction({account:n,...o})},async signTypedData(o){return t.signTypedData({account:n,...o})}}),a=r??viem.pad(n.address,{dir:"right",size:32});return accountAbstraction.toSoladySmartAccount({client:e,owner:i,salt:a})}async function X(e){let{chain:t,apiKey:r,bundlerUrl:n,rpcUrl:i,salt:a,sponsor:o=!!(r||n)}=e,l=e.walletClient;if(!l&&e.wagmiConfig&&(l=await core.getWalletClient(e.wagmiConfig,{chainId:t.id})),!l||!l.account)throw new Error("Active wallet connection with account is required (provide walletClient or wagmiConfig).");let u=e.client??viem.createPublicClient({chain:t,transport:i?viem.http(i):viem.http()}),x=await M({client:u,walletClient:l,salt:a}),d=o&&(r||n)?k({chainId:t.id,apiKey:r,bundlerUrl:n}):void 0,S=R({chainId:t.id,apiKey:r,bundlerUrl:n,client:u,...d?{paymaster:d}:{}});return {account:x,bundlerClient:S,publicClient:u,paymasterClient:d}}function Y(){m.clear(),p.clear(),C.clear();}function I(e){return e!=null&&typeof e=="number"&&e>0}function _(e){return !e||e.length===0?[]:e.map(t=>t.id).filter(I)}function ee(e){return e.length>0&&e.every(t=>typeof t=="number")}async function ie(e,t){let{connector:r,chainId:n}=core.getConnection(t);if(r&&n!==e)try{await core.switchChain(t,{chainId:e});}catch(i){throw i?.cause?.name==="UserRejectedRequestError"?new Error("User rejected the request to switch network.",{cause:i}):(console.error("Failed to switch network:",i),new Error("An error occurred while switching the network.",{cause:i}))}}var g=new Map;function h(e,t){let r=t.find(i=>i.id===e),n=g.get(e);if(n&&n.chain?.rpcUrls.default.http[0]===r?.rpcUrls.default.http[0])return n;if(r){let i=viem.createPublicClient({chain:r,transport:viem.http()});return g.set(e,i),i}console.warn(`createViemClient: No chain configuration found for chainId ${e}. A client could not be created.`);}var w=new Map,P=new Map,b=new Map,y=e=>{let t=e.find(r=>r.id===chains.mainnet.id);return t?h(chains.mainnet.id,[t]):h(chains.mainnet.id,[chains.mainnet])},he=async(e,t)=>{let r=y(t);if(!r)return null;let n=w.get(e);if(n!==void 0)return n;try{let i=await ens.getEnsName(r,{address:e});return w.set(e,i),i}catch(i){return console.error(`ENS name lookup failed for address ${e}:`,i),null}},ye=async(e,t)=>{let r=y(t);if(!r)return null;let n=ens.normalize(e),i=P.get(n);if(i!==void 0)return i;try{let a=await ens.getEnsAvatar(r,{name:n});return P.set(n,a),a}catch(a){return console.error(`ENS avatar lookup failed for name ${e}:`,a),null}},ge=async(e,t)=>{let r=y(t);if(!r)return null;let n=ens.normalize(e),i=b.get(n);if(i!==void 0)return i;try{let a=await ens.getEnsAddress(r,{name:n}),o=a?a.toLowerCase():null;return b.set(n,o),o}catch(a){return console.error(`ENS address lookup failed for name ${e}:`,a),null}},we=e=>e.includes(".")&&!viem.isAddress(e);
2
+ exports.checkAndSwitchChain=ie;exports.clearBundlerCache=Y;exports.createBundlerRpcClient=R;exports.createPimlicoPaymasterClient=k;exports.createPimlicoRpcUrl=f;exports.createPimlicoSmartAccountClient=X;exports.createSoladySmartAccount=M;exports.createViemClient=h;exports.getAddress=ge;exports.getAvatar=ye;exports.getEvmChains=_;exports.getName=he;exports.isEnsName=we;exports.isEvmChainList=ee;
package/dist/index.mjs CHANGED
@@ -1 +1,2 @@
1
- import {getConnection,switchChain}from'@wagmi/core';import {createPublicClient,http,isAddress}from'viem';import {mainnet}from'viem/chains';import {getEnsName,normalize,getEnsAvatar,getEnsAddress}from'viem/ens';function C(e){return e!=null&&typeof e=="number"&&e>0}function E(e){return !e||e.length===0?[]:e.map(r=>r.id).filter(C)}function N(e){return e.length>0&&e.every(r=>typeof r=="number")}async function U(e,r){let{connector:t,chainId:o}=getConnection(r);if(t&&o!==e)try{await switchChain(r,{chainId:e});}catch(n){throw n.cause?.name==="UserRejectedRequestError"?new Error("User rejected the request to switch network.",{cause:n}):(console.error("Failed to switch network:",n),new Error("An error occurred while switching the network.",{cause:n}))}}var u=new Map;function s(e,r){let t=r.find(n=>n.id===e),o=u.get(e);if(o&&o.chain?.rpcUrls.default.http[0]===t?.rpcUrls.default.http[0])return o;if(t){let n=createPublicClient({chain:t,transport:http()});return u.set(e,n),n}console.warn(`createViemClient: No chain configuration found for chainId ${e}. A client could not be created.`);}var d=new Map,m=new Map,f=new Map,c=e=>{let r=e.find(t=>t.id===mainnet.id);return r?s(mainnet.id,[r]):s(mainnet.id,[mainnet])},D=async(e,r)=>{let t=c(r);if(!t)return null;let o=d.get(e);if(o!==void 0)return o;try{let n=await getEnsName(t,{address:e});return d.set(e,n),n}catch(n){return console.error(`ENS name lookup failed for address ${e}:`,n),null}},G=async(e,r)=>{let t=c(r);if(!t)return null;let o=normalize(e),n=m.get(o);if(n!==void 0)return n;try{let i=await getEnsAvatar(t,{name:o});return m.set(o,i),i}catch(i){return console.error(`ENS avatar lookup failed for name ${e}:`,i),null}},I=async(e,r)=>{let t=c(r);if(!t)return null;let o=normalize(e),n=f.get(o);if(n!==void 0)return n;try{let i=await getEnsAddress(t,{name:o}),l=i?i.toLowerCase():null;return f.set(o,l),l}catch(i){return console.error(`ENS address lookup failed for name ${e}:`,i),null}},J=e=>e.includes(".")&&!isAddress(e);export{U as checkAndSwitchChain,s as createViemClient,I as getAddress,G as getAvatar,E as getEvmChains,D as getName,J as isEnsName,N as isEvmChainList};
1
+ import {getWalletClient,getConnection,switchChain}from'@wagmi/core';import {http,pad,createPublicClient,isAddress}from'viem';import {createBundlerClient,createPaymasterClient,toSoladySmartAccount}from'viem/account-abstraction';import {toAccount}from'viem/accounts';import {mainnet}from'viem/chains';import {getEnsName,normalize,getEnsAvatar,getEnsAddress}from'viem/ens';var m=new Map,p=new Map,C=new Map;function K(e){return e.bundlerUrl?`custom:${e.bundlerUrl.trim()}`:`${e.chainId}:${e.apiKey?.trim()??"public"}`}function N(e){let t=f(e),r=!!e.paymaster,n=!!e.client;return `${t}:pm=${r}:client=${n}`}function f(e){let t=K(e),r=m.get(t);if(r)return r;let n;return e.bundlerUrl?n=e.bundlerUrl.trim():e.apiKey?n=`https://api.pimlico.io/v2/${e.chainId}/rpc?apikey=${e.apiKey.trim()}`:n=`https://public.pimlico.io/v2/${e.chainId}/rpc`,m.set(t,n),n}function R(e){let t=N(e),r=p.get(t);if(r)return r;let n=f(e),i={...e};delete i.bundlerUrl,delete i.apiKey;let a=createBundlerClient({...i,transport:http(n)});return p.set(t,a),a}function k(e){let t=f(e),r=C.get(t);if(r)return r;let n=createPaymasterClient({transport:http(t)});return C.set(t,n),n}async function M({client:e,walletClient:t,salt:r}){if(!t.account)throw new Error("WalletClient must have an active account.");let n=t.account,i=toAccount({address:n.address,async signMessage({message:o}){return t.signMessage({account:n,message:o})},async signTransaction(o){return t.signTransaction({account:n,...o})},async signTypedData(o){return t.signTypedData({account:n,...o})}}),a=r??pad(n.address,{dir:"right",size:32});return toSoladySmartAccount({client:e,owner:i,salt:a})}async function X(e){let{chain:t,apiKey:r,bundlerUrl:n,rpcUrl:i,salt:a,sponsor:o=!!(r||n)}=e,l=e.walletClient;if(!l&&e.wagmiConfig&&(l=await getWalletClient(e.wagmiConfig,{chainId:t.id})),!l||!l.account)throw new Error("Active wallet connection with account is required (provide walletClient or wagmiConfig).");let u=e.client??createPublicClient({chain:t,transport:i?http(i):http()}),x=await M({client:u,walletClient:l,salt:a}),d=o&&(r||n)?k({chainId:t.id,apiKey:r,bundlerUrl:n}):void 0,S=R({chainId:t.id,apiKey:r,bundlerUrl:n,client:u,...d?{paymaster:d}:{}});return {account:x,bundlerClient:S,publicClient:u,paymasterClient:d}}function Y(){m.clear(),p.clear(),C.clear();}function I(e){return e!=null&&typeof e=="number"&&e>0}function _(e){return !e||e.length===0?[]:e.map(t=>t.id).filter(I)}function ee(e){return e.length>0&&e.every(t=>typeof t=="number")}async function ie(e,t){let{connector:r,chainId:n}=getConnection(t);if(r&&n!==e)try{await switchChain(t,{chainId:e});}catch(i){throw i?.cause?.name==="UserRejectedRequestError"?new Error("User rejected the request to switch network.",{cause:i}):(console.error("Failed to switch network:",i),new Error("An error occurred while switching the network.",{cause:i}))}}var g=new Map;function h(e,t){let r=t.find(i=>i.id===e),n=g.get(e);if(n&&n.chain?.rpcUrls.default.http[0]===r?.rpcUrls.default.http[0])return n;if(r){let i=createPublicClient({chain:r,transport:http()});return g.set(e,i),i}console.warn(`createViemClient: No chain configuration found for chainId ${e}. A client could not be created.`);}var w=new Map,P=new Map,b=new Map,y=e=>{let t=e.find(r=>r.id===mainnet.id);return t?h(mainnet.id,[t]):h(mainnet.id,[mainnet])},he=async(e,t)=>{let r=y(t);if(!r)return null;let n=w.get(e);if(n!==void 0)return n;try{let i=await getEnsName(r,{address:e});return w.set(e,i),i}catch(i){return console.error(`ENS name lookup failed for address ${e}:`,i),null}},ye=async(e,t)=>{let r=y(t);if(!r)return null;let n=normalize(e),i=P.get(n);if(i!==void 0)return i;try{let a=await getEnsAvatar(r,{name:n});return P.set(n,a),a}catch(a){return console.error(`ENS avatar lookup failed for name ${e}:`,a),null}},ge=async(e,t)=>{let r=y(t);if(!r)return null;let n=normalize(e),i=b.get(n);if(i!==void 0)return i;try{let a=await getEnsAddress(r,{name:n}),o=a?a.toLowerCase():null;return b.set(n,o),o}catch(a){return console.error(`ENS address lookup failed for name ${e}:`,a),null}},we=e=>e.includes(".")&&!isAddress(e);
2
+ export{ie as checkAndSwitchChain,Y as clearBundlerCache,R as createBundlerRpcClient,k as createPimlicoPaymasterClient,f as createPimlicoRpcUrl,X as createPimlicoSmartAccountClient,M as createSoladySmartAccount,h as createViemClient,ge as getAddress,ye as getAvatar,_ as getEvmChains,he as getName,we as isEnsName,ee as isEvmChainList};
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@tuwaio/orbit-evm",
3
- "version": "0.2.22",
3
+ "version": "0.3.1",
4
4
  "private": false,
5
5
  "author": "Oleksandr Tkach",
6
6
  "license": "Apache-2.0",
7
- "description": "Layer 2 (L2) of the TUWA Ecosystem. Low-level EVM-specific communication primitives powered strictly by viem and wagmi.",
7
+ "description": "L2 EVM package of Orbit Utils (TUWA): cached viem clients, chain switching, ENS resolution and ERC-4337 smart accounts (Solady + Pimlico bundler/paymaster), built on viem and @wagmi/core.",
8
8
  "main": "./dist/index.js",
9
9
  "module": "./dist/index.mjs",
10
10
  "types": "./dist/index.d.ts",
@@ -16,9 +16,18 @@
16
16
  "socket.json"
17
17
  ],
18
18
  "keywords": [
19
+ "tuwa",
20
+ "orbit",
19
21
  "web3",
20
- "typescript",
21
22
  "evm",
23
+ "viem",
24
+ "wagmi",
25
+ "ens",
26
+ "erc-4337",
27
+ "account-abstraction",
28
+ "pimlico",
29
+ "solady",
30
+ "typescript",
22
31
  "headless"
23
32
  ],
24
33
  "repository": {
@@ -41,13 +50,14 @@
41
50
  "viem": "2.x.x"
42
51
  },
43
52
  "devDependencies": {
44
- "@wagmi/core": "^3.6.4",
53
+ "@wagmi/core": "^3.6.5",
45
54
  "tsup": "^8.5.1",
46
- "typescript": "^6.0.3",
47
- "viem": "^2.55.11"
55
+ "typescript": "6.0.3",
56
+ "viem": "^2.56.9"
48
57
  },
49
58
  "scripts": {
50
59
  "start": "tsup src/index.ts --watch",
51
- "build": "tsup"
60
+ "build": "tsup",
61
+ "test": "vitest run"
52
62
  }
53
63
  }