@tuwaio/orbit-evm 0.2.21 → 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 +70 -6
- package/dist/index.d.mts +136 -8
- package/dist/index.d.ts +136 -8
- package/dist/index.js +2 -1
- package/dist/index.mjs +2 -1
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@tuwaio/orbit-evm)
|
|
4
4
|
[](./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,
|
|
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
|
-
- **
|
|
14
|
-
- **Deterministic
|
|
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
|
-
- **
|
|
71
|
-
- **
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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.
|
|
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.
|
|
44
|
+
"@wagmi/core": "^3.6.5",
|
|
45
45
|
"tsup": "^8.5.1",
|
|
46
46
|
"typescript": "^6.0.3",
|
|
47
|
-
"viem": "^2.
|
|
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
|
}
|