@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.
- package/README.md +466 -162
- package/index.cjs.js +8395 -6251
- package/index.d.ts +1049 -320
- package/index.mjs +8397 -6254
- 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
|
|
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
|
-
- [
|
|
18
|
-
- [
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
- [
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
- [
|
|
31
|
-
- [
|
|
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
|
|
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
|
|
59
|
+
### When to Use This Adapter
|
|
47
60
|
|
|
48
|
-
####
|
|
61
|
+
#### For Kit Users
|
|
49
62
|
|
|
50
|
-
If you're using
|
|
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
|
-
|
|
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
|
-
####
|
|
82
|
+
#### For Kit Provider Developers
|
|
62
83
|
|
|
63
|
-
If you
|
|
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
|
-
###
|
|
117
|
+
### Zero-Config Setup (Recommended)
|
|
76
118
|
|
|
77
|
-
The simplest way to get started
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
//
|
|
89
|
-
const
|
|
90
|
-
|
|
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
|
-
###
|
|
148
|
+
### Production Setup
|
|
94
149
|
|
|
95
|
-
|
|
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
|
|
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
|
-
|
|
105
|
-
getProvider: ({ chain }) =>
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
193
|
+
// Minimal browser wallet configuration
|
|
120
194
|
const adapter = await createAdapterFromProvider({
|
|
121
195
|
provider: window.ethereum,
|
|
122
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
136
|
-
|
|
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
|
-
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
-
##
|
|
289
|
+
## Address Context Guide
|
|
150
290
|
|
|
151
|
-
|
|
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
|
-
|
|
293
|
+
### User-Controlled (Recommended)
|
|
158
294
|
|
|
159
|
-
|
|
295
|
+
**Best for:** Private key wallets, browser wallets (MetaMask), hardware wallets
|
|
160
296
|
|
|
161
|
-
|
|
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
|
-
|
|
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
|
-
|
|
310
|
+
// addressContext: 'user-controlled' is the default
|
|
169
311
|
})
|
|
170
312
|
|
|
171
|
-
//
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
###
|
|
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 {
|
|
185
|
-
|
|
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
|
-
|
|
188
|
-
const wallet = new Wallet(process.env.PRIVATE_KEY!, provider)
|
|
369
|
+
## Usage Examples
|
|
189
370
|
|
|
190
|
-
|
|
371
|
+
### Contract Interactions
|
|
191
372
|
|
|
192
|
-
|
|
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
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
-
###
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
225
|
-
to: { adapter, chain: 'Base' },
|
|
226
|
-
amount: '
|
|
469
|
+
from: { adapter, chain: 'Ethereum' },
|
|
470
|
+
to: { adapter, chain: 'Base' },
|
|
471
|
+
amount: '100.50',
|
|
227
472
|
token: 'USDC',
|
|
228
473
|
})
|
|
229
474
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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
|
-
|
|
502
|
+
#### `createAdapterFromProvider(params)`
|
|
240
503
|
|
|
241
|
-
|
|
504
|
+
Creates an adapter from a browser wallet provider (MetaMask, WalletConnect, etc.).
|
|
242
505
|
|
|
243
|
-
|
|
506
|
+
**Parameters:**
|
|
244
507
|
|
|
245
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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
|
-
|
|
545
|
+
#### `signTypedData(typedData, ctx)`
|
|
259
546
|
|
|
260
|
-
-
|
|
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
|
-
|
|
549
|
+
**Parameters:**
|
|
270
550
|
|
|
271
|
-
|
|
551
|
+
- `typedData` - EIP-712 structured data
|
|
552
|
+
- `ctx` - **Required** OperationContext with chain specification
|
|
272
553
|
|
|
273
|
-
|
|
554
|
+
**Returns:** `Promise<string>` - Signature as hex string
|
|
274
555
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
556
|
+
```typescript
|
|
557
|
+
const signature = await adapter.signTypedData(permitData, {
|
|
558
|
+
chain: 'Ethereum',
|
|
559
|
+
})
|
|
560
|
+
```
|
|
279
561
|
|
|
280
|
-
|
|
562
|
+
#### `waitForTransaction(txHash, config?)`
|
|
281
563
|
|
|
282
|
-
|
|
564
|
+
Waits for transaction confirmation.
|
|
283
565
|
|
|
284
|
-
|
|
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
|
-
|
|
288
|
-
|
|
574
|
+
const receipt = await adapter.waitForTransaction('0x...')
|
|
575
|
+
```
|
|
289
576
|
|
|
290
|
-
|
|
577
|
+
#### `getAddress(chain?)`
|
|
291
578
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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
|
-
//
|
|
299
|
-
await
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
[
|
|
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
|
|