@circle-fin/adapter-ethers-v6 0.0.2-alpha.6 → 1.0.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.
Files changed (5) hide show
  1. package/README.md +466 -162
  2. package/index.cjs.js +8395 -6251
  3. package/index.d.ts +1049 -320
  4. package/index.mjs +8397 -6254
  5. package/package.json +5 -5
package/README.md CHANGED
@@ -8,31 +8,44 @@
8
8
 
9
9
  **Type-safe EVM blockchain adapter powered by Ethers v6**
10
10
 
11
- _Seamlessly interact with 12+ EVM networks using a single, strongly-typed interface_
11
+ _Seamlessly interact with 16+ EVM networks using a single, strongly-typed interface_
12
12
 
13
13
  </div>
14
14
 
15
15
  ## Table of Contents
16
16
 
17
- - [Ethers v6 Adapter](#ethers-v6-adapter)
18
- - [Overview](#overview)
19
- - [Why Ethers v6 Adapter?](#why-ethers-v6-adapter)
20
- - [Installation](#installation)
21
- - [Quick Start](#quick-start)
22
- - [🚀 Easy Setup with Factory Methods (Recommended)](#-easy-setup-with-factory-methods-recommended)
23
- - [🏭 Production Considerations](#-production-considerations)
24
- - [Usage Examples](#usage-examples)
25
- - [Basic Usage with Factory Methods](#basic-usage-with-factory-methods)
26
- - [Manual Setup with Ethers Clients](#manual-setup-with-ethers-clients)
27
- - [Multi-Chain Setup](#multi-chain-setup)
28
- - [Methods](#methods)
29
- - [Development](#development)
30
- - [Contributing](#contributing)
31
- - [License](#license)
17
+ - [Overview](#overview)
18
+ - [Why Ethers v6 Adapter?](#why-ethers-v6-adapter)
19
+ - [When to Use This Adapter](#when-to-use-this-adapter)
20
+ - [Installation](#installation)
21
+ - [Quick Start](#quick-start)
22
+ - [Zero-Config Setup (Recommended)](#zero-config-setup-recommended)
23
+ - [Production Setup](#production-setup)
24
+ - [Browser Wallet Setup](#browser-wallet-setup)
25
+ - [OperationContext Pattern](#operationcontext-pattern)
26
+ - [Why OperationContext?](#why-operationcontext)
27
+ - [Basic Usage](#basic-usage)
28
+ - [Multi-Chain Operations](#multi-chain-operations)
29
+ - [Address Context Guide](#address-context-guide)
30
+ - [User-Controlled (Recommended)](#user-controlled-recommended)
31
+ - [Developer-Controlled (Advanced)](#developer-controlled-advanced)
32
+ - [Decision Matrix](#decision-matrix)
33
+ - [Usage Examples](#usage-examples)
34
+ - [Contract Interactions](#contract-interactions)
35
+ - [EIP-712 Signatures](#eip-712-signatures)
36
+ - [Cross-Chain Bridging](#cross-chain-bridging)
37
+ - [API Reference](#api-reference)
38
+ - [Factory Functions](#factory-functions)
39
+ - [Core Methods](#core-methods)
40
+ - [Token Operations](#token-operations)
41
+ - [Migration Guide](#migration-guide)
42
+ - [Supported Chains](#supported-chains)
43
+ - [Development](#development)
44
+ - [License](#license)
32
45
 
33
46
  ## Overview
34
47
 
35
- The Ethers v6 Adapter is a strongly-typed implementation of the [`Adapter`](https://github.com/circlefin/stablecoin-kits-private/blob/main/core/adapter/README.md) interface for **EVM-compatible blockchains**. Built on top of the popular [Ethers v6](https://docs.ethers.org/v6/) library, it provides type-safe blockchain interactions through a unified interface that's designed to work seamlessly with the [Bridging Kit](https://github.com/circlefin/stablecoin-kits-private/tree/main/kits/bridging-kit) for cross-chain USDC transfers between Solana and EVM networks, as well as any future kits for additional stablecoin operations. It can be used by any Kit built using the Stablecoin Kits architecture and/or any providers plugged into those kits.
48
+ The Ethers v6 Adapter is a strongly-typed implementation of the `Adapter` interface for **EVM-compatible blockchains**. Built on top of the popular [Ethers v6](https://docs.ethers.org/v6/) library, it provides type-safe blockchain interactions through a unified interface that's designed to work seamlessly with the [Bridge Kit](https://www.npmjs.com/package/@circle-fin/bridge-kit) for cross-chain USDC transfers between Solana and EVM networks, as well as any future kits for additional stablecoin operations. It can be used by any Kit built using the Stablecoin Kits architecture and/or any providers plugged into those kits.
36
49
 
37
50
  ### Why Ethers v6 Adapter?
38
51
 
@@ -43,24 +56,32 @@ The Ethers v6 Adapter is a strongly-typed implementation of the [`Adapter`](http
43
56
  - **🔄 Transaction lifecycle** - Complete prepare/estimate/execute workflow
44
57
  - **🌉 Cross-chain ready** - Seamlessly bridge USDC between EVM chains and Solana
45
58
 
46
- ### When and How Should I Use The Ethers v6 Adapter?
59
+ ### When to Use This Adapter
47
60
 
48
- #### I'm a developer using a kit
61
+ #### For Kit Users
49
62
 
50
- If you're using one of the kits to perform actions such as bridging from chain 'A' to chain 'B', you only need to instantiate the adapter for your chain and pass it to the kit.
51
-
52
- ##### Example
63
+ If you're using the Bridge Kit or other Stablecoin Kits for cross-chain operations, you only need to instantiate one adapter and pass it to the kit. The same adapter works across all supported chains.
53
64
 
54
65
  ```typescript
66
+ // Single adapter instance for multi-chain operations
67
+ // Note: Private keys can be provided with or without '0x' prefix
55
68
  const adapter = createAdapterFromPrivateKey({
56
- privateKey: process.env.PRIVATE_KEY as `0x${string}`,
57
- defaultChain: 'Ethereum',
69
+ privateKey: process.env.PRIVATE_KEY as `0x${string}`, // Both '0x...' and '...' work
70
+ })
71
+
72
+ // Both formats are automatically normalized:
73
+ const adapter1 = createAdapterFromPrivateKey({
74
+ privateKey: '0x1234...', // With prefix ✅
75
+ })
76
+
77
+ const adapter2 = createAdapterFromPrivateKey({
78
+ privateKey: '1234...', // Without prefix ✅ (automatically normalized)
58
79
  })
59
80
  ```
60
81
 
61
- #### I'm a developer making a Kit Provider
82
+ #### For Kit Provider Developers
62
83
 
63
- If you are making a provider for other Kit users to plug in to the kit, e.g. a `BridgingProvider`, and you'll need to interact with diff chains, then you'll need to use the abstracted `Adapter` methods to execute on chain.
84
+ If you're building a provider (e.g., a custom `BridgingProvider` implementation), you'll use the adapter's abstracted methods to interact with different chains. The OperationContext pattern makes multi-chain operations seamless.
64
85
 
65
86
  ## Installation
66
87
 
@@ -70,240 +91,526 @@ npm install @circle-fin/adapter-ethers-v6 ethers
70
91
  yarn add @circle-fin/adapter-ethers-v6 ethers
71
92
  ```
72
93
 
94
+ ## Peer Dependencies
95
+
96
+ This adapter requires `ethers` (v6) as a peer dependency. Install it alongside the adapter:
97
+
98
+ ```bash
99
+ npm install @circle-fin/adapter-ethers-v6 ethers
100
+ # or
101
+ yarn add @circle-fin/adapter-ethers-v6 ethers
102
+ ```
103
+
104
+ **Supported Versions:** `^6.11.0` (6.11.x through 6.x.x, excluding 7.x.x)
105
+
106
+ ### Troubleshooting Version Conflicts
107
+
108
+ If you encounter peer dependency warnings:
109
+
110
+ - Check your `ethers` version: `npm ls ethers`
111
+ - Ensure ethers v6 is between 6.11.0 and 7.0.0 (exclusive)
112
+ - Use `npm install ethers@^6.11.0` to install a compatible version
113
+ - Note: This adapter is **not** compatible with ethers v5 or v7
114
+
73
115
  ## Quick Start
74
116
 
75
- ### 🚀 Easy Setup with Factory Methods (Recommended)
117
+ ### Zero-Config Setup (Recommended)
76
118
 
77
- The simplest way to get started is with our factory methods. You can create just **one adapter** and use it across different chains!
119
+ The simplest way to get started with lazy initialization. Default configuration handles adapter setup automatically.
78
120
 
79
121
  ```typescript
80
122
  import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
81
123
 
82
- // Create ONE adapter that can work across chains!
124
+ // Minimal configuration with lazy initialization
125
+ // Note: Private keys work with or without '0x' prefix
83
126
  const adapter = createAdapterFromPrivateKey({
84
- privateKey: process.env.PRIVATE_KEY as `0x${string}`,
85
- defaultChain: 'Ethereum',
127
+ privateKey: process.env.PRIVATE_KEY as `0x${string}`, // Both '0x...' and '...' work
128
+ // Defaults applied:
129
+ // - addressContext: 'user-controlled'
130
+ // - supportedChains: all EVM chains (~34 networks)
131
+ // - Lazy initialization: wallet connects to chain on first operation
86
132
  })
87
133
 
88
- // Ready to use with Bridging Kit!
89
- const address = await adapter.getAddress()
90
- console.log('Connected address:', address)
134
+ // Chain specified per operation via OperationContext
135
+ const prepared = await adapter.prepare(
136
+ {
137
+ address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on Ethereum
138
+ abi: usdcAbi,
139
+ functionName: 'transfer',
140
+ args: ['0xrecipient', '1000000'],
141
+ },
142
+ { chain: 'Ethereum' }, // Chain specified in context
143
+ )
144
+
145
+ const txHash = await prepared.execute()
91
146
  ```
92
147
 
93
- ### 🏭 Production Considerations
148
+ ### Production Setup
94
149
 
95
- > **⚠️ Important for Production**: The factory methods use Ethers's default public RPC endpoints, which may have rate limits and lower reliability. For production applications, we strongly recommend using dedicated RPC providers like Alchemy, Infura, or QuickNode.
150
+ For production use, provide custom RPC endpoints for better reliability and performance:
96
151
 
97
152
  ```typescript
98
153
  import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
99
154
  import { JsonRpcProvider } from 'ethers'
155
+ import { Ethereum, Base, Polygon } from '@core/chains'
100
156
 
101
- // Production-ready setup with custom RPC endpoints
157
+ // Production-ready with custom RPC endpoints and lazy initialization
102
158
  const adapter = createAdapterFromPrivateKey({
103
159
  privateKey: process.env.PRIVATE_KEY as `0x${string}`,
104
- defaultChain: 'Ethereum',
105
- getProvider: ({ chain }) =>
106
- new JsonRpcProvider(
107
- `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_KEY}`,
108
- ),
160
+ // Custom RPC provider with explicit chain mapping
161
+ getProvider: ({ chain }) => {
162
+ // Map chain names to RPC endpoints
163
+ // Customize this mapping based on your RPC provider
164
+ const rpcEndpoints: Record<string, string> = {
165
+ Ethereum: `https://eth-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`,
166
+ Base: `https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`,
167
+ Polygon: `https://polygon-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`,
168
+ }
169
+
170
+ const endpoint = rpcEndpoints[chain.name]
171
+ if (!endpoint) {
172
+ throw new Error(`RPC endpoint not configured for chain: ${chain.name}`)
173
+ }
174
+
175
+ return new JsonRpcProvider(endpoint, chain.chainId)
176
+ },
177
+ // Optionally restrict to specific chains
178
+ capabilities: {
179
+ supportedChains: [Ethereum, Base, Polygon],
180
+ },
109
181
  })
110
182
  ```
111
183
 
112
- ### 🌐 Browser Support with Wallet Providers
184
+ > **⚠️ Production Note**: Default factory methods use public RPC endpoints which may have rate limits. For production, use dedicated providers like Alchemy, Infura, or QuickNode.
113
185
 
114
- For browser environments with wallet providers like MetaMask:
186
+ ### Browser Wallet Setup
187
+
188
+ For browser environments with MetaMask or WalletConnect:
115
189
 
116
190
  ```typescript
117
191
  import { createAdapterFromProvider } from '@circle-fin/adapter-ethers-v6'
118
192
 
119
- // Create an adapter from a browser wallet
193
+ // Minimal browser wallet configuration
120
194
  const adapter = await createAdapterFromProvider({
121
195
  provider: window.ethereum,
122
- chain: 'Ethereum', // Required: specify the intended chain
123
- getProvider: ({ chain }) =>
124
- new JsonRpcProvider(
125
- `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_KEY}`,
126
- ),
196
+ // Default capabilities applied automatically
127
197
  })
198
+
199
+ // User will be prompted to connect wallet
200
+ // Address is automatically resolved from connected wallet
201
+ const prepared = await adapter.prepare(
202
+ {
203
+ address: '0xcontract',
204
+ abi: contractAbi,
205
+ functionName: 'approve',
206
+ args: ['0xspender', '1000000'],
207
+ },
208
+ { chain: 'Polygon' },
209
+ )
128
210
  ```
129
211
 
130
- ### 🔧 Advanced Manual Setup
212
+ ## OperationContext Pattern
213
+
214
+ ### Why OperationContext?
215
+
216
+ The OperationContext pattern is the modern approach for multi-chain operations. Instead of locking an adapter to a single chain, you specify the chain per operation. This enables powerful patterns like using a single adapter for cross-chain bridging.
131
217
 
132
- For advanced use cases requiring custom RPC endpoints:
218
+ **Benefits:**
219
+
220
+ - ✅ **One adapter, many chains** - No need to create separate adapters for each network
221
+ - ✅ **Explicit is better** - Chain is always clear in your code
222
+ - ✅ **Type-safe** - Full TypeScript support with compile-time checks
223
+ - ✅ **Eliminates ambiguity** - No confusion about which chain is being used
224
+
225
+ ### Basic Usage
226
+
227
+ Every operation accepts an `OperationContext` parameter that specifies the chain:
133
228
 
134
229
  ```typescript
135
- import { EthersAdapter } from '@circle-fin/adapter-ethers-v6'
136
- import { JsonRpcProvider, Wallet } from 'ethers'
230
+ import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
231
+
232
+ // Create adapter without specifying a chain - true lazy initialization
233
+ const adapter = createAdapterFromPrivateKey({
234
+ privateKey: process.env.PRIVATE_KEY as `0x${string}`,
235
+ })
236
+
237
+ // Chain specified explicitly in every operation
238
+ const prepared = await adapter.prepare(
239
+ {
240
+ address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
241
+ abi: usdcAbi,
242
+ functionName: 'transfer',
243
+ args: ['0xrecipient', '1000000'],
244
+ },
245
+ { chain: 'Ethereum' },
246
+ )
247
+
248
+ const gas = await prepared.estimate()
249
+ const txHash = await prepared.execute()
250
+ ```
137
251
 
138
- // Use your existing Ethers setup
139
- const provider = new JsonRpcProvider('https://your-custom-rpc.com')
140
- const wallet = new Wallet(process.env.PRIVATE_KEY, provider)
252
+ ### Multi-Chain Operations
141
253
 
142
- // Create the adapter
143
- const adapter = new EthersAdapter({
144
- provider,
145
- wallet,
254
+ Use a single adapter instance for operations across multiple chains:
255
+
256
+ ```typescript
257
+ // Create adapter once for use across multiple chains
258
+ const adapter = createAdapterFromPrivateKey({
259
+ privateKey: process.env.PRIVATE_KEY as `0x${string}`,
146
260
  })
261
+
262
+ // Transfer USDC on Ethereum
263
+ const ethPrepared = await adapter.prepare(
264
+ {
265
+ address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on Ethereum
266
+ abi: usdcAbi,
267
+ functionName: 'transfer',
268
+ args: ['0xrecipient', '1000000'],
269
+ },
270
+ { chain: 'Ethereum' },
271
+ )
272
+
273
+ // Transfer USDC on Base using the same adapter
274
+ const basePrepared = await adapter.prepare(
275
+ {
276
+ address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base
277
+ abi: usdcAbi,
278
+ functionName: 'transfer',
279
+ args: ['0xrecipient', '1000000'],
280
+ },
281
+ { chain: 'Base' },
282
+ )
283
+
284
+ // Execute both transfers
285
+ await ethPrepared.execute()
286
+ await basePrepared.execute()
147
287
  ```
148
288
 
149
- ## Features
289
+ ## Address Context Guide
150
290
 
151
- - **Full EVM compatibility** - Works with any Ethereum-compatible blockchain
152
- - ✅ **Ethers v6 integration** - Uses your existing `JsonRpcProvider` and `Wallet`
153
- - ✅ **Transaction lifecycle** - Complete prepare/estimate/execute workflow
154
- - ✅ **Type safety** - Full TypeScript support with strict mode
155
- - ✅ **Cross-chain ready** - Seamlessly bridge USDC between Solana and EVM chains
291
+ The adapter supports two address control patterns. Choose the one that fits your use case.
156
292
 
157
- ## Usage Examples
293
+ ### User-Controlled (Recommended)
158
294
 
159
- ### Basic Usage with Factory Methods
295
+ **Best for:** Private key wallets, browser wallets (MetaMask), hardware wallets
160
296
 
161
- ```typescript
162
- import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
163
- import { BridgingKit } from '@circle-fin/bridging-kit'
297
+ **How it works:** Address is automatically resolved from the connected signer/wallet. You don't need to specify it in the OperationContext.
164
298
 
165
- // Create ONE adapter that can work across chains - so simple!
299
+ **When to use:**
300
+
301
+ - ✅ Building a dApp where users connect their wallets
302
+ - ✅ Using a private key for backend automation
303
+ - ✅ Single wallet signing all transactions
304
+ - ✅ Server-side scripts with one identity
305
+
306
+ ```typescript
307
+ // User-controlled adapter (default for factory functions)
166
308
  const adapter = createAdapterFromPrivateKey({
167
309
  privateKey: process.env.PRIVATE_KEY as `0x${string}`,
168
- defaultChain: 'Ethereum',
310
+ // addressContext: 'user-controlled' is the default
169
311
  })
170
312
 
171
- // Use directly with Bridging Kit - same adapter, different chains!
172
- const kit = new BridgingKit()
173
- const result = await kit.bridge({
174
- from: { adapter }, // Uses default chain (Ethereum)
175
- to: { adapter, chain: 'Base' }, // Same adapter, different chain
176
- amount: '10.50',
177
- })
313
+ // Address automatically resolved from private key/wallet
314
+ const prepared = await adapter.prepare(
315
+ {
316
+ address: '0xcontract',
317
+ abi: contractAbi,
318
+ functionName: 'approve',
319
+ args: ['0xspender', '1000000'],
320
+ },
321
+ { chain: 'Polygon' }, // No address needed in context for user-controlled
322
+ )
178
323
  ```
179
324
 
180
- ### Manual Setup with Ethers
325
+ ### Developer-Controlled (Advanced)
326
+
327
+ **Best for:** Custody solutions, multi-entity systems, enterprise applications
328
+
329
+ **How it works:** Address must be explicitly provided in the OperationContext for each operation.
330
+
331
+ **When to use:**
332
+
333
+ - ✅ Building a custody solution managing multiple client wallets
334
+ - ✅ Enterprise system where different users have different signing keys
335
+ - ✅ Multi-sig or delegated signing infrastructure
336
+ - ✅ Systems where address varies per transaction
181
337
 
182
338
  ```typescript
183
339
  import { EthersAdapter } from '@circle-fin/adapter-ethers-v6'
184
- import { BridgingKit } from '@circle-fin/bridging-kit'
185
- import { JsonRpcProvider, Wallet } from 'ethers'
340
+ import { Ethereum, Base } from '@core/chains'
341
+
342
+ // Developer-controlled adapter (manual constructor)
343
+ const adapter = new EthersAdapter(
344
+ {
345
+ getProvider: ({ chain }) => new JsonRpcProvider('https://...'),
346
+ signer: wallet,
347
+ },
348
+ {
349
+ addressContext: 'developer-controlled', // ← Explicit address required
350
+ supportedChains: [Ethereum, Base],
351
+ },
352
+ )
353
+
354
+ // Address must be provided in context for developer-controlled adapters
355
+ const prepared = await adapter.prepare(
356
+ {
357
+ address: '0xcontract',
358
+ abi: contractAbi,
359
+ functionName: 'approve',
360
+ args: ['0xspender', '1000000'],
361
+ },
362
+ {
363
+ chain: 'Ethereum',
364
+ address: '0x1234...', // Required for developer-controlled
365
+ },
366
+ )
367
+ ```
186
368
 
187
- const provider = new JsonRpcProvider('https://your-custom-rpc.com')
188
- const wallet = new Wallet(process.env.PRIVATE_KEY!, provider)
369
+ ## Usage Examples
189
370
 
190
- const adapter = new EthersAdapter({ provider, wallet })
371
+ ### Contract Interactions
191
372
 
192
- const destinationAdapter = new EthersAdapter({
193
- provider: new JsonRpcProvider('https://another-rpc.com'),
194
- wallet: new Wallet(
195
- process.env.PRIVATE_KEY!,
196
- new JsonRpcProvider('https://another-rpc.com'),
197
- ),
198
- })
373
+ **Transfer USDC** across different chains with the same adapter:
199
374
 
200
- const kit = new BridgingKit()
201
- const result = await kit.bridge({
202
- from: { adapter },
203
- to: { adapter: destinationAdapter },
204
- amount: '10.50',
375
+ ```typescript
376
+ import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
377
+ import { parseAbi } from 'ethers'
378
+
379
+ // Create adapter with lazy initialization
380
+ const adapter = createAdapterFromPrivateKey({
381
+ privateKey: process.env.PRIVATE_KEY as `0x${string}`,
205
382
  })
383
+
384
+ const usdcAbi = parseAbi([
385
+ 'function transfer(address to, uint256 amount) returns (bool)',
386
+ ])
387
+
388
+ // Transfer on Ethereum - chain specified in operation
389
+ const ethPrepared = await adapter.prepare(
390
+ {
391
+ address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on Ethereum
392
+ abi: usdcAbi,
393
+ functionName: 'transfer',
394
+ args: ['0xrecipient', '1000000'], // 1 USDC (6 decimals)
395
+ },
396
+ { chain: 'Ethereum' },
397
+ )
398
+
399
+ // Estimate and execute
400
+ const gas = await ethPrepared.estimate()
401
+ console.log('Estimated gas:', gas.gas)
402
+
403
+ const txHash = await ethPrepared.execute()
404
+ console.log('Transaction hash:', txHash)
206
405
  ```
207
406
 
208
- ### Multi-Chain Setup
407
+ ### EIP-712 Signatures
408
+
409
+ **Sign permit approvals** for gasless token approvals:
209
410
 
210
411
  ```typescript
211
412
  import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
212
- import { BridgingKit } from '@circle-fin/bridging-kit'
213
413
 
214
- const kit = new BridgingKit()
414
+ const adapter = createAdapterFromPrivateKey({
415
+ privateKey: process.env.PRIVATE_KEY as `0x${string}`,
416
+ })
417
+
418
+ // Sign ERC-2612 permit (gasless USDC approval)
419
+ const signature = await adapter.signTypedData(
420
+ {
421
+ domain: {
422
+ name: 'USD Coin',
423
+ version: '2',
424
+ chainId: 1,
425
+ verifyingContract: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
426
+ },
427
+ types: {
428
+ Permit: [
429
+ { name: 'owner', type: 'address' },
430
+ { name: 'spender', type: 'address' },
431
+ { name: 'value', type: 'uint256' },
432
+ { name: 'nonce', type: 'uint256' },
433
+ { name: 'deadline', type: 'uint256' },
434
+ ],
435
+ },
436
+ primaryType: 'Permit',
437
+ message: {
438
+ owner: '0xowner',
439
+ spender: '0xspender',
440
+ value: '1000000',
441
+ nonce: '0',
442
+ deadline: '1735689600',
443
+ },
444
+ },
445
+ { chain: 'Ethereum' }, // Chain must be specified
446
+ )
447
+
448
+ console.log('Permit signature:', signature)
449
+ // Use signature for gasless approval
450
+ ```
451
+
452
+ ### Cross-Chain Bridging
215
453
 
216
- // Create ONE adapter that can work across ANY supported chain
454
+ **Bridge USDC** using the Bridge Kit with OperationContext:
455
+
456
+ ```typescript
457
+ import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
458
+ import { BridgeKit } from '@circle-fin/bridge-kit'
459
+
460
+ // Create adapter for multi-chain operations
217
461
  const adapter = createAdapterFromPrivateKey({
218
462
  privateKey: process.env.PRIVATE_KEY as `0x${string}`,
219
- defaultChain: 'Ethereum', // This is just the default
220
463
  })
221
464
 
222
- // Use for cross-chain bridging by specifying different chains
465
+ const kit = new BridgeKit()
466
+
467
+ // Bridge from Ethereum to Base using the same adapter
223
468
  const result = await kit.bridge({
224
- from: { adapter }, // Ethereum (from defaultChain)
225
- to: { adapter, chain: 'Base' }, // Base (explicitly specified)
226
- amount: '10.50',
469
+ from: { adapter, chain: 'Ethereum' },
470
+ to: { adapter, chain: 'Base' },
471
+ amount: '100.50',
227
472
  token: 'USDC',
228
473
  })
229
474
 
230
- // Or bridge between any other supported chains
231
- const anotherResult = await kit.bridge({
232
- from: { adapter, chain: 'Arbitrum' },
233
- to: { adapter, chain: 'Polygon' },
234
- amount: '25.00',
235
- token: 'USDC',
475
+ console.log('Bridge transaction:', result.transactionHash)
476
+ ```
477
+
478
+ ## API Reference
479
+
480
+ ### Factory Functions
481
+
482
+ #### `createAdapterFromPrivateKey(params)`
483
+
484
+ Creates an adapter from a private key for server-side use.
485
+
486
+ **Parameters:**
487
+
488
+ - `privateKey` - 32-byte hex string with `0x` prefix
489
+ - `getProvider?` - Optional custom provider function
490
+ - `capabilities?` - Optional partial capabilities (defaults: user-controlled + all EVM chains)
491
+
492
+ **Returns:** `EthersAdapter` instance with lazy initialization
493
+
494
+ **Note:** No chain required at creation time. The adapter connects to chains lazily on first operation.
495
+
496
+ ```typescript
497
+ const adapter = createAdapterFromPrivateKey({
498
+ privateKey: '0x...',
236
499
  })
237
500
  ```
238
501
 
239
- > **💡 Pro Tip**: With the single adapter pattern, you create one adapter and can use it for bridging between any supported EVM chains. Just specify the desired chain in the bridge parameters!
502
+ #### `createAdapterFromProvider(params)`
240
503
 
241
- ## Supported Chains
504
+ Creates an adapter from a browser wallet provider (MetaMask, WalletConnect, etc.).
242
505
 
243
- Works with all EVM-compatible chains supported by Ethers v6 and the Bridging Kit:
506
+ **Parameters:**
244
507
 
245
- **Ethereum**, **Base**, **Arbitrum**, **Avalanche**, **Polygon**, **Optimism**, **Linea**, **Sonic**, **Unichain**, **World Chain**, **Codex**, and their respective testnets.
508
+ - `provider` - EIP-1193 compatible provider
509
+ - `getProvider?` - Optional custom provider function
510
+ - `capabilities?` - Optional partial capabilities (defaults: user-controlled + all EVM chains)
246
511
 
247
- ## API Reference
512
+ **Returns:** `Promise<EthersAdapter>` instance
513
+
514
+ ```typescript
515
+ const adapter = await createAdapterFromProvider({
516
+ provider: window.ethereum,
517
+ })
518
+ ```
519
+
520
+ ### Core Methods
521
+
522
+ #### `prepare(params, ctx)`
523
+
524
+ Prepares a contract function call for estimation and execution.
525
+
526
+ **Parameters:**
248
527
 
249
- ### Constructor Options
528
+ - `params` - Contract call parameters (address, abi, functionName, args)
529
+ - `ctx` - **Required** OperationContext with chain specification
530
+
531
+ **Returns:** `Promise<PreparedChainRequest>` with `estimate()` and `execute()` methods
250
532
 
251
533
  ```typescript
252
- interface EthersAdapterOptions {
253
- getProvider: (params: { chain: ChainDefinition }) => Provider
254
- signer: Signer
255
- }
534
+ const prepared = await adapter.prepare(
535
+ {
536
+ address: '0xcontract',
537
+ abi: contractAbi,
538
+ functionName: 'transfer',
539
+ args: ['0xto', '1000000'],
540
+ },
541
+ { chain: 'Ethereum' }, // Required
542
+ )
256
543
  ```
257
544
 
258
- ### Methods
545
+ #### `signTypedData(typedData, ctx)`
259
546
 
260
- - `getAddress()` - Get the connected wallet address
261
- - `getChain()` - Get chain information
262
- - `prepare()` - Prepare transactions for execution
263
- - `estimate()` - Estimate transaction costs
264
- - `execute()` - Execute prepared transactions
265
- - `waitForTransaction()` - Wait for transaction confirmation
266
- - `calculateTransactionFee()` - Calculate transaction fees with optional buffer
267
- - `readContract()` - Read contract functions with comprehensive validation
547
+ Signs EIP-712 typed data for permits, meta-transactions, etc.
268
548
 
269
- You can see the implementation of each of these methods in the Ethers v6 Adapter's [main implementation file](./src/adapter/adapter.ts).
549
+ **Parameters:**
270
550
 
271
- ### Token Operations via Actions
551
+ - `typedData` - EIP-712 structured data
552
+ - `ctx` - **Required** OperationContext with chain specification
272
553
 
273
- For token balance and allowance operations, this adapter uses the standardized action-based system inherited from `EvmAdapter`:
554
+ **Returns:** `Promise<string>` - Signature as hex string
274
555
 
275
- - **`token.balanceOf`** - Get balance for any ERC-20 token
276
- - **`token.allowance`** - Get allowance for any ERC-20 token
277
- - **`usdc.balanceOf`** - Get USDC balance (uses `token.balanceOf` with USDC address)
278
- - **`usdc.allowance`** - Get USDC allowance (uses `token.allowance` with USDC address)
556
+ ```typescript
557
+ const signature = await adapter.signTypedData(permitData, {
558
+ chain: 'Ethereum',
559
+ })
560
+ ```
279
561
 
280
- These actions provide type-safe, validated interfaces and use the adapter's `readContract()` method internally.
562
+ #### `waitForTransaction(txHash, config?)`
281
563
 
282
- ## Integration with Stablecoin Kits
564
+ Waits for transaction confirmation.
283
565
 
284
- This adapter is designed to work seamlessly across the Stablecoin Kits ecosystem. Here's an example with the [Bridging Kit](https://github.com/circlefin/stablecoin-kits-private/tree/main/kits/bridging-kit):
566
+ **Parameters:**
567
+
568
+ - `txHash` - Transaction hash to wait for
569
+ - `config?` - Optional wait configuration (confirmations, timeout)
570
+
571
+ **Returns:** `Promise<TransactionReceipt>`
285
572
 
286
573
  ```typescript
287
- import { BridgingKit } from '@circle-fin/bridging-kit'
288
- import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
574
+ const receipt = await adapter.waitForTransaction('0x...')
575
+ ```
289
576
 
290
- const kit = new BridgingKit()
577
+ #### `getAddress(chain?)`
291
578
 
292
- // Create ONE adapter that works across all EVM chains - incredibly simple!
293
- const adapter = createAdapterFromPrivateKey({
294
- privateKey: process.env.PRIVATE_KEY as `0x${string}`,
295
- defaultChain: 'Ethereum',
579
+ Gets the connected wallet address. Chain parameter is provided automatically by OperationContext resolution.
580
+
581
+ **Returns:** `Promise<string>` - Wallet address
582
+
583
+ ### Token Operations
584
+
585
+ Built-in token operations using the action system:
586
+
587
+ ```typescript
588
+ // Get USDC balance
589
+ const balance = await adapter.actions.usdc.balanceOf({
590
+ address: '0xwallet',
591
+ chain: 'Ethereum',
296
592
  })
297
593
 
298
- // Ready for cross-chain bridging between any supported chains!
299
- await kit.bridge({
300
- from: { adapter }, // Uses default chain (Ethereum)
301
- to: { adapter, chain: 'Base' }, // Same adapter, different chain
302
- amount: '50.0',
594
+ // Get token allowance
595
+ const allowance = await adapter.actions.token.allowance({
596
+ tokenAddress: '0xtoken',
597
+ owner: '0xowner',
598
+ spender: '0xspender',
599
+ chain: 'Base',
303
600
  })
304
601
  ```
305
602
 
306
- **For Production Use**: Remember to provide custom RPC endpoints using the `getProvider` parameter for better reliability and performance!
603
+ ## Supported Chains & Routes
604
+
605
+ The Ethers v6 adapter supports **34 EVM-compatible chains** across mainnet and testnet environments through Circle's CCTP v2 protocol:
606
+
607
+ ### Mainnet Chains (17 chains)
608
+
609
+ **Arbitrum**, **Avalanche**, **Base**, **Celo**, **Codex**, **Ethereum**, **HyperEVM**, **Ink**, **Linea**, **OP Mainnet**, **Plume**, **Polygon PoS**, **Sonic**, **Unichain**, **World Chain**, **XDC**, **ZKSync Era**
610
+
611
+ ### Testnet Chains (17 chains)
612
+
613
+ **Arbitrum Sepolia**, **Avalanche Fuji**, **Base Sepolia**, **Celo Alfajores**, **Codex Testnet**, **Ethereum Sepolia**, **HyperEVM Testnet**, **Ink Testnet**, **Linea Sepolia**, **OP Sepolia**, **Plume Testnet**, **Polygon PoS Amoy**, **Sonic Testnet**, **Unichain Sepolia**, **World Chain Sepolia**, **XDC Apothem**, **ZKSync Era Sepolia**
307
614
 
308
615
  ## Development
309
616
 
@@ -317,13 +624,9 @@ nx build @circle-fin/adapter-ethers-v6
317
624
  nx test @circle-fin/adapter-ethers-v6
318
625
  ```
319
626
 
320
- ## Contributing
321
-
322
- We welcome contributions! Please see our [Contributing Guide](https://github.com/circlefin/stablecoin-kits-private/blob/main/CONTRIBUTING.md) for details.
323
-
324
627
  ## License
325
628
 
326
- This project is licensed under the Apache 2.0 License - see the [LICENSE](https://github.com/circlefin/stablecoin-kits-private/blob/main/LICENSE) file for details.
629
+ This project is licensed under the Apache 2.0 License. Contact [support](https://help.circle.com/s/submit-ticket) for details.
327
630
 
328
631
  ---
329
632
 
@@ -331,7 +634,8 @@ This project is licensed under the Apache 2.0 License - see the [LICENSE](https:
331
634
 
332
635
  **Ready to integrate?**
333
636
 
334
- [View Stablecoin Kits](https://github.com/circlefin/stablecoin-kits-private) • [Join Discord](https://discord.com/invite/buildoncircle) • [Report Issues](https://github.com/circlefin/stablecoin-kits-private/issues)
637
+ [Join Discord](https://discord.com/invite/buildoncircle) •
638
+ [Visit our Help-Desk](https://help.circle.com/s/submit-ticket)
335
639
 
336
640
  _Built with ❤️ by Circle_
337
641