@tuwaio/orbit-evm 0.2.22 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,15 +3,17 @@
3
3
  [![NPM Version](https://img.shields.io/npm/v/@tuwaio/orbit-evm.svg)](https://www.npmjs.com/package/@tuwaio/orbit-evm)
4
4
  [![License](https://img.shields.io/npm/l/@tuwaio/orbit-evm.svg)](./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` 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, cached ENS metadata resolution, and full ERC-4337 Account Abstraction orchestration via Pimlico and Solady smart accounts. It enforces a complete exclusion of legacy libraries like `ethers.js` or `web3.js`.
7
7
 
8
8
  ---
9
9
 
10
10
  ## 🏛️ Core Capabilities
11
11
 
12
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.
13
+ - **ERC-4337 Account Abstraction (Pimlico & Solady):** High-level client factory (`createPimlicoSmartAccountClient`) and Solady smart account instantiation (`createSoladySmartAccount`) with automatic gas sponsorship (`createPimlicoPaymasterClient`).
14
+ - **Deterministic Solady Salt Generation:** Generates right-padded 32-byte salts (`pad(ownerAddress, { dir: 'right', size: 32 })`) compliant with the Solady ERC-4337 factory prefix requirements, preventing `SaltDoesNotStartWith()` exceptions and multi-user address collisions.
15
+ - **ENS Metadata Engine:** Direct lookup utilities (`getName`, `getAvatar`, `getAddress`) on Ethereum Mainnet with local in-memory caching.
16
+ - **Deterministic Chain Switching:** Low-level utility (`checkAndSwitchChain`) to enforce network alignment with the target blockchain.
15
17
  - **Strict Compile-Time Types:** Fully integrated with TypeScript standards v5.9+ and native Viem/Wagmi typings.
16
18
 
17
19
  ---
@@ -22,8 +24,14 @@
22
24
  pnpm add @tuwaio/orbit-evm @wagmi/core viem
23
25
  ```
24
26
 
27
+ If using `@tuwaio/orbit-core` adapters and type definitions alongside EVM primitives:
28
+
29
+ ```bash
30
+ pnpm add @tuwaio/orbit-evm @tuwaio/orbit-core @wagmi/core viem
31
+ ```
32
+
25
33
  > [!IMPORTANT]
26
- > `@wagmi/core` and `viem` are peer dependencies and must be installed alongside `@tuwaio/orbit-evm`.
34
+ > `@wagmi/core` (v3.x) and `viem` (v2.x) are peer dependencies and must be installed alongside `@tuwaio/orbit-evm`.
27
35
 
28
36
  ---
29
37
 
@@ -61,14 +69,70 @@ async function switchNetwork(targetChainId: number) {
61
69
  }
62
70
  ```
63
71
 
72
+ ### ERC-4337 Smart Account Client (Pimlico & Solady)
73
+
74
+ Instantiate a fully configured Solady smart account client with automated Pimlico bundler and paymaster sponsorship:
75
+
76
+ ```typescript
77
+ import { createPimlicoSmartAccountClient } from '@tuwaio/orbit-evm';
78
+ import { sepolia } from 'viem/chains';
79
+ import { type Config } from '@wagmi/core';
80
+
81
+ declare const wagmiConfig: Config;
82
+
83
+ async function initializeSmartAccount() {
84
+ const { account, bundlerClient, publicClient, paymasterClient } = await createPimlicoSmartAccountClient({
85
+ chain: sepolia,
86
+ wagmiConfig,
87
+ apiKey: process.env.NEXT_PUBLIC_PIMLICO_API_KEY, // or custom bundlerUrl
88
+ sponsor: true, // Enables Pimlico paymaster gas sponsorship
89
+ });
90
+
91
+ console.log('Solady Smart Account counterfactual address:', account.address);
92
+ return { account, bundlerClient, publicClient };
93
+ }
94
+ ```
95
+
96
+ #### Solady Salt Padding Rule
97
+
98
+ When deploying Solady smart accounts, the factory requires the salt to be prefixed with the EOA owner's 20-byte address. To guarantee a deterministic 32-byte representation without failing Solady's `SaltDoesNotStartWith()` check, `createSoladySmartAccount` defaults to right-padding:
99
+
100
+ ```typescript
101
+ import { pad } from 'viem';
102
+
103
+ // Deterministic salt ensuring owner prefix alignment
104
+ const accountSalt = pad(ownerAccount.address, { dir: 'right', size: 32 });
105
+ ```
106
+
107
+ ### Low-Level Pimlico Bundler Client & RPC URL
108
+
109
+ Instantiate and cache Viem Bundler clients with automated Pimlico URL resolution:
110
+
111
+ ```typescript
112
+ import { createBundlerRpcClient, createPimlicoRpcUrl } from '@tuwaio/orbit-evm';
113
+
114
+ // Generate or retrieve cached Pimlico RPC endpoint
115
+ const rpcUrl = createPimlicoRpcUrl({
116
+ chainId: 11155111,
117
+ apiKey: 'pim_test_key_123',
118
+ });
119
+
120
+ // Retrieve cached or new Viem Bundler Client (with in-memory cache)
121
+ const bundlerClient = createBundlerRpcClient({
122
+ chainId: 11155111,
123
+ apiKey: 'pim_test_key_123',
124
+ });
125
+ ```
126
+
64
127
  ---
65
128
 
66
129
  ## 🔧 API & Module Architecture
67
130
 
68
131
  `@tuwaio/orbit-evm` exposes the following modules:
69
132
 
70
- - **Chain Alignment:** `checkAndSwitchChain`.
71
- - **Client Factory:** `createViemClient`.
133
+ - **ERC-4337 Account Abstraction:** `createPimlicoSmartAccountClient`, `createSoladySmartAccount`, `createPimlicoPaymasterClient`, `createPimlicoRpcUrl`, `createBundlerRpcClient`, `clearBundlerCache`.
134
+ - **Chain Alignment:** `checkAndSwitchChain`, `normalizeChainId`.
135
+ - **Client Factory:** `createViemClient`, `clearViemClientCache`.
72
136
  - **ENS Resolvers:** `getAddress`, `getAvatar`, `getName`, `isEnsName`.
73
137
 
74
138
  ---
package/dist/index.d.mts CHANGED
@@ -1,11 +1,139 @@
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';
5
+
6
+ /**
7
+ * @file Utilities for Pimlico and ERC-4337 Bundler client instantiation with local in-memory caching.
8
+ */
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 a Viem Paymaster Client configured with the resolved Pimlico RPC endpoint.
106
+ *
107
+ * @param config - Pimlico URL configuration.
108
+ * @returns PaymasterClient instance configured for Pimlico gas sponsorship.
109
+ */
110
+ declare function createPimlicoPaymasterClient(config: PimlicoUrlConfig): PaymasterClient;
111
+ /**
112
+ * Instantiates a Solady ERC-4337 smart account with automatic wallet signing delegation
113
+ * and Solady factory-compliant deterministic salt.
114
+ *
115
+ * @param params - Configuration parameters including client and walletClient.
116
+ * @returns Promise resolving to the initialized SoladySmartAccount.
117
+ */
118
+ declare function createSoladySmartAccount({ client, walletClient, salt, }: CreateSoladySmartAccountParams): Promise<SoladySmartAccount>;
119
+ /**
120
+ * High-level orchestration utility that instantiates a Solady smart account,
121
+ * configures a Pimlico paymaster (sponsorship), and binds them to a Pimlico Bundler client.
122
+ *
123
+ * @param config - Configuration options including chain, wallet/wagmi, and Pimlico credentials.
124
+ * @returns Promise resolving to { account, bundlerClient, publicClient, paymasterClient }.
125
+ */
126
+ declare function createPimlicoSmartAccountClient(config: PimlicoSmartAccountClientConfig): Promise<PimlicoSmartAccountClientResult>;
127
+ /**
128
+ * Clears the in-memory cache of Pimlico URLs and Bundler clients.
129
+ * Useful for testing and resetting runtime state.
130
+ */
131
+ declare function clearBundlerCache(): void;
4
132
 
5
133
  /**
6
134
  * Get EVM chain IDs from app chains configuration
7
135
  */
8
- declare function getEvmChains(appChains?: readonly [Chain, ...Chain[]]): number[];
136
+ declare function getEvmChains(appChains?: readonly [Chain$1, ...Chain$1[]]): number[];
9
137
  /**
10
138
  * Type guard to check if a chain list contains EVM chain IDs
11
139
  */
@@ -46,7 +174,7 @@ declare function checkAndSwitchChain(chainId: number, config: Config): Promise<v
46
174
  * @returns {import('viem').PublicClient | undefined} A viem PublicClient instance if a matching chain is found, otherwise undefined.
47
175
  * It will also log a warning to the console if the chain is not configured.
48
176
  */
49
- declare function createViemClient(chainId: number, chains: readonly [Chain, ...Chain[]]): PublicClient | undefined;
177
+ declare function createViemClient(chainId: number, chains: readonly [Chain$1, ...Chain$1[]]): PublicClient | undefined;
50
178
 
51
179
  /**
52
180
  * @file This file contains utility functions for interacting with the Ethereum Name Service (ENS).
@@ -62,7 +190,7 @@ declare function createViemClient(chainId: number, chains: readonly [Chain, ...C
62
190
  * @param {readonly [Chain, ...Chain[]]} chains - The list of chains to use for client creation.
63
191
  * @returns {Promise<string | null>} The ENS name if found, otherwise null.
64
192
  */
65
- declare const getName: (address: Hex, chains: readonly [Chain, ...Chain[]]) => Promise<string | null>;
193
+ declare const getName: (address: Hex, chains: readonly [Chain$1, ...Chain$1[]]) => Promise<string | null>;
66
194
  /**
67
195
  * Fetches the avatar URL for a given ENS name from the Ethereum Mainnet.
68
196
  * Includes caching for performance.
@@ -71,7 +199,7 @@ declare const getName: (address: Hex, chains: readonly [Chain, ...Chain[]]) => P
71
199
  * @param {readonly [Chain, ...Chain[]]} chains - The list of chains to use for client creation.
72
200
  * @returns {Promise<string | null>} The URL of the avatar image if found, otherwise null.
73
201
  */
74
- declare const getAvatar: (name: string, chains: readonly [Chain, ...Chain[]]) => Promise<string | null>;
202
+ declare const getAvatar: (name: string, chains: readonly [Chain$1, ...Chain$1[]]) => Promise<string | null>;
75
203
  /**
76
204
  * Fetches the Ethereum address associated with a given ENS name from the Ethereum Mainnet.
77
205
  * Includes caching for performance.
@@ -80,7 +208,7 @@ declare const getAvatar: (name: string, chains: readonly [Chain, ...Chain[]]) =>
80
208
  * @param {readonly [Chain, ...Chain[]]} chains - The list of chains to use for client creation.
81
209
  * @returns {Promise<Address | null>} The associated Ethereum address (lowercase) or null if not found.
82
210
  */
83
- declare const getAddress: (name: string, chains: readonly [Chain, ...Chain[]]) => Promise<Address | null>;
211
+ declare const getAddress: (name: string, chains: readonly [Chain$1, ...Chain$1[]]) => Promise<Address | null>;
84
212
  /**
85
213
  * A heuristic to check if a string is likely an ENS name.
86
214
  *
@@ -97,4 +225,4 @@ declare const getAddress: (name: string, chains: readonly [Chain, ...Chain[]]) =
97
225
  */
98
226
  declare const isEnsName: (nameOrAddress: string) => boolean;
99
227
 
100
- export { checkAndSwitchChain, createViemClient, getAddress, getAvatar, getEvmChains, getName, isEnsName, isEvmChainList };
228
+ 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,11 +1,139 @@
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';
5
+
6
+ /**
7
+ * @file Utilities for Pimlico and ERC-4337 Bundler client instantiation with local in-memory caching.
8
+ */
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 a Viem Paymaster Client configured with the resolved Pimlico RPC endpoint.
106
+ *
107
+ * @param config - Pimlico URL configuration.
108
+ * @returns PaymasterClient instance configured for Pimlico gas sponsorship.
109
+ */
110
+ declare function createPimlicoPaymasterClient(config: PimlicoUrlConfig): PaymasterClient;
111
+ /**
112
+ * Instantiates a Solady ERC-4337 smart account with automatic wallet signing delegation
113
+ * and Solady factory-compliant deterministic salt.
114
+ *
115
+ * @param params - Configuration parameters including client and walletClient.
116
+ * @returns Promise resolving to the initialized SoladySmartAccount.
117
+ */
118
+ declare function createSoladySmartAccount({ client, walletClient, salt, }: CreateSoladySmartAccountParams): Promise<SoladySmartAccount>;
119
+ /**
120
+ * High-level orchestration utility that instantiates a Solady smart account,
121
+ * configures a Pimlico paymaster (sponsorship), and binds them to a Pimlico Bundler client.
122
+ *
123
+ * @param config - Configuration options including chain, wallet/wagmi, and Pimlico credentials.
124
+ * @returns Promise resolving to { account, bundlerClient, publicClient, paymasterClient }.
125
+ */
126
+ declare function createPimlicoSmartAccountClient(config: PimlicoSmartAccountClientConfig): Promise<PimlicoSmartAccountClientResult>;
127
+ /**
128
+ * Clears the in-memory cache of Pimlico URLs and Bundler clients.
129
+ * Useful for testing and resetting runtime state.
130
+ */
131
+ declare function clearBundlerCache(): void;
4
132
 
5
133
  /**
6
134
  * Get EVM chain IDs from app chains configuration
7
135
  */
8
- declare function getEvmChains(appChains?: readonly [Chain, ...Chain[]]): number[];
136
+ declare function getEvmChains(appChains?: readonly [Chain$1, ...Chain$1[]]): number[];
9
137
  /**
10
138
  * Type guard to check if a chain list contains EVM chain IDs
11
139
  */
@@ -46,7 +174,7 @@ declare function checkAndSwitchChain(chainId: number, config: Config): Promise<v
46
174
  * @returns {import('viem').PublicClient | undefined} A viem PublicClient instance if a matching chain is found, otherwise undefined.
47
175
  * It will also log a warning to the console if the chain is not configured.
48
176
  */
49
- declare function createViemClient(chainId: number, chains: readonly [Chain, ...Chain[]]): PublicClient | undefined;
177
+ declare function createViemClient(chainId: number, chains: readonly [Chain$1, ...Chain$1[]]): PublicClient | undefined;
50
178
 
51
179
  /**
52
180
  * @file This file contains utility functions for interacting with the Ethereum Name Service (ENS).
@@ -62,7 +190,7 @@ declare function createViemClient(chainId: number, chains: readonly [Chain, ...C
62
190
  * @param {readonly [Chain, ...Chain[]]} chains - The list of chains to use for client creation.
63
191
  * @returns {Promise<string | null>} The ENS name if found, otherwise null.
64
192
  */
65
- declare const getName: (address: Hex, chains: readonly [Chain, ...Chain[]]) => Promise<string | null>;
193
+ declare const getName: (address: Hex, chains: readonly [Chain$1, ...Chain$1[]]) => Promise<string | null>;
66
194
  /**
67
195
  * Fetches the avatar URL for a given ENS name from the Ethereum Mainnet.
68
196
  * Includes caching for performance.
@@ -71,7 +199,7 @@ declare const getName: (address: Hex, chains: readonly [Chain, ...Chain[]]) => P
71
199
  * @param {readonly [Chain, ...Chain[]]} chains - The list of chains to use for client creation.
72
200
  * @returns {Promise<string | null>} The URL of the avatar image if found, otherwise null.
73
201
  */
74
- declare const getAvatar: (name: string, chains: readonly [Chain, ...Chain[]]) => Promise<string | null>;
202
+ declare const getAvatar: (name: string, chains: readonly [Chain$1, ...Chain$1[]]) => Promise<string | null>;
75
203
  /**
76
204
  * Fetches the Ethereum address associated with a given ENS name from the Ethereum Mainnet.
77
205
  * Includes caching for performance.
@@ -80,7 +208,7 @@ declare const getAvatar: (name: string, chains: readonly [Chain, ...Chain[]]) =>
80
208
  * @param {readonly [Chain, ...Chain[]]} chains - The list of chains to use for client creation.
81
209
  * @returns {Promise<Address | null>} The associated Ethereum address (lowercase) or null if not found.
82
210
  */
83
- declare const getAddress: (name: string, chains: readonly [Chain, ...Chain[]]) => Promise<Address | null>;
211
+ declare const getAddress: (name: string, chains: readonly [Chain$1, ...Chain$1[]]) => Promise<Address | null>;
84
212
  /**
85
213
  * A heuristic to check if a string is likely an ENS name.
86
214
  *
@@ -97,4 +225,4 @@ declare const getAddress: (name: string, chains: readonly [Chain, ...Chain[]]) =
97
225
  */
98
226
  declare const isEnsName: (nameOrAddress: string) => boolean;
99
227
 
100
- export { checkAndSwitchChain, createViemClient, getAddress, getAvatar, getEvmChains, getName, isEnsName, isEvmChainList };
228
+ 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;function H(e){return e.bundlerUrl?`custom:${e.bundlerUrl.trim()}`:`${e.chainId}:${e.apiKey?.trim()??"public"}`}function K(e){let t=C(e),r=!!e.paymaster,n=!!e.client;return `${t}:pm=${r}:client=${n}`}function C(e){let t=H(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 N(e){let t=K(e),r=p.get(t);if(r)return r;let n=C(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 R(e){let t=C(e);return accountAbstraction.createPaymasterClient({transport:viem.http(t)})}async function k({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 Q(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()}),A=await k({client:u,walletClient:l,salt:a}),d=o&&(r||n)?R({chainId:t.id,apiKey:r,bundlerUrl:n}):void 0,x=N({chainId:t.id,apiKey:r,bundlerUrl:n,client:u,...d?{paymaster:d}:{}});return {account:A,bundlerClient:x,publicClient:u,paymasterClient:d}}function X(){m.clear(),p.clear();}function M(e){return e!=null&&typeof e=="number"&&e>0}function Z(e){return !e||e.length===0?[]:e.map(t=>t.id).filter(M)}function _(e){return e.length>0&&e.every(t=>typeof t=="number")}async function re(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 y=new Map;function f(e,t){let r=t.find(i=>i.id===e),n=y.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 y.set(e,i),i}console.warn(`createViemClient: No chain configuration found for chainId ${e}. A client could not be created.`);}var g=new Map,w=new Map,P=new Map,h=e=>{let t=e.find(r=>r.id===chains.mainnet.id);return t?f(chains.mainnet.id,[t]):f(chains.mainnet.id,[chains.mainnet])},fe=async(e,t)=>{let r=h(t);if(!r)return null;let n=g.get(e);if(n!==void 0)return n;try{let i=await ens.getEnsName(r,{address:e});return g.set(e,i),i}catch(i){return console.error(`ENS name lookup failed for address ${e}:`,i),null}},he=async(e,t)=>{let r=h(t);if(!r)return null;let n=ens.normalize(e),i=w.get(n);if(i!==void 0)return i;try{let a=await ens.getEnsAvatar(r,{name:n});return w.set(n,a),a}catch(a){return console.error(`ENS avatar lookup failed for name ${e}:`,a),null}},ye=async(e,t)=>{let r=h(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.getEnsAddress(r,{name:n}),o=a?a.toLowerCase():null;return P.set(n,o),o}catch(a){return console.error(`ENS address lookup failed for name ${e}:`,a),null}},ge=e=>e.includes(".")&&!viem.isAddress(e);
2
+ exports.checkAndSwitchChain=re;exports.clearBundlerCache=X;exports.createBundlerRpcClient=N;exports.createPimlicoPaymasterClient=R;exports.createPimlicoRpcUrl=C;exports.createPimlicoSmartAccountClient=Q;exports.createSoladySmartAccount=k;exports.createViemClient=f;exports.getAddress=ye;exports.getAvatar=he;exports.getEvmChains=Z;exports.getName=fe;exports.isEnsName=ge;exports.isEvmChainList=_;
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;function H(e){return e.bundlerUrl?`custom:${e.bundlerUrl.trim()}`:`${e.chainId}:${e.apiKey?.trim()??"public"}`}function K(e){let t=C(e),r=!!e.paymaster,n=!!e.client;return `${t}:pm=${r}:client=${n}`}function C(e){let t=H(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 N(e){let t=K(e),r=p.get(t);if(r)return r;let n=C(e),i={...e};delete i.bundlerUrl,delete i.apiKey;let a=createBundlerClient({...i,transport:http(n)});return p.set(t,a),a}function R(e){let t=C(e);return createPaymasterClient({transport:http(t)})}async function k({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 Q(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()}),A=await k({client:u,walletClient:l,salt:a}),d=o&&(r||n)?R({chainId:t.id,apiKey:r,bundlerUrl:n}):void 0,x=N({chainId:t.id,apiKey:r,bundlerUrl:n,client:u,...d?{paymaster:d}:{}});return {account:A,bundlerClient:x,publicClient:u,paymasterClient:d}}function X(){m.clear(),p.clear();}function M(e){return e!=null&&typeof e=="number"&&e>0}function Z(e){return !e||e.length===0?[]:e.map(t=>t.id).filter(M)}function _(e){return e.length>0&&e.every(t=>typeof t=="number")}async function re(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 y=new Map;function f(e,t){let r=t.find(i=>i.id===e),n=y.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 y.set(e,i),i}console.warn(`createViemClient: No chain configuration found for chainId ${e}. A client could not be created.`);}var g=new Map,w=new Map,P=new Map,h=e=>{let t=e.find(r=>r.id===mainnet.id);return t?f(mainnet.id,[t]):f(mainnet.id,[mainnet])},fe=async(e,t)=>{let r=h(t);if(!r)return null;let n=g.get(e);if(n!==void 0)return n;try{let i=await getEnsName(r,{address:e});return g.set(e,i),i}catch(i){return console.error(`ENS name lookup failed for address ${e}:`,i),null}},he=async(e,t)=>{let r=h(t);if(!r)return null;let n=normalize(e),i=w.get(n);if(i!==void 0)return i;try{let a=await getEnsAvatar(r,{name:n});return w.set(n,a),a}catch(a){return console.error(`ENS avatar lookup failed for name ${e}:`,a),null}},ye=async(e,t)=>{let r=h(t);if(!r)return null;let n=normalize(e),i=P.get(n);if(i!==void 0)return i;try{let a=await getEnsAddress(r,{name:n}),o=a?a.toLowerCase():null;return P.set(n,o),o}catch(a){return console.error(`ENS address lookup failed for name ${e}:`,a),null}},ge=e=>e.includes(".")&&!isAddress(e);
2
+ export{re as checkAndSwitchChain,X as clearBundlerCache,N as createBundlerRpcClient,R as createPimlicoPaymasterClient,C as createPimlicoRpcUrl,Q as createPimlicoSmartAccountClient,k as createSoladySmartAccount,f as createViemClient,ye as getAddress,he as getAvatar,Z as getEvmChains,fe as getName,ge as isEnsName,_ as isEvmChainList};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tuwaio/orbit-evm",
3
- "version": "0.2.22",
3
+ "version": "0.3.0",
4
4
  "private": false,
5
5
  "author": "Oleksandr Tkach",
6
6
  "license": "Apache-2.0",
@@ -41,13 +41,14 @@
41
41
  "viem": "2.x.x"
42
42
  },
43
43
  "devDependencies": {
44
- "@wagmi/core": "^3.6.4",
44
+ "@wagmi/core": "^3.6.5",
45
45
  "tsup": "^8.5.1",
46
46
  "typescript": "^6.0.3",
47
- "viem": "^2.55.11"
47
+ "viem": "^2.56.3"
48
48
  },
49
49
  "scripts": {
50
50
  "start": "tsup src/index.ts --watch",
51
- "build": "tsup"
51
+ "build": "tsup",
52
+ "test": "vitest run"
52
53
  }
53
54
  }