@circle-fin/adapter-ethers-v6 0.0.2-alpha.6 → 0.0.2-alpha.7
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 +437 -159
- package/index.cjs.js +8462 -6226
- package/index.d.ts +1081 -285
- package/index.mjs +8461 -6226
- package/package.json +2 -2
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 [Bridging Kit](https://www.npmjs.com/package/@circle-fin/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.
|
|
36
49
|
|
|
37
50
|
### Why Ethers v6 Adapter?
|
|
38
51
|
|
|
@@ -43,24 +56,22 @@ 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 Bridging 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
|
|
55
67
|
const adapter = createAdapterFromPrivateKey({
|
|
56
68
|
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
|
|
57
|
-
defaultChain: 'Ethereum',
|
|
58
69
|
})
|
|
59
70
|
```
|
|
60
71
|
|
|
61
|
-
####
|
|
72
|
+
#### For Kit Provider Developers
|
|
62
73
|
|
|
63
|
-
If you
|
|
74
|
+
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
75
|
|
|
65
76
|
## Installation
|
|
66
77
|
|
|
@@ -72,238 +83,508 @@ yarn add @circle-fin/adapter-ethers-v6 ethers
|
|
|
72
83
|
|
|
73
84
|
## Quick Start
|
|
74
85
|
|
|
75
|
-
###
|
|
86
|
+
### Zero-Config Setup (Recommended)
|
|
76
87
|
|
|
77
|
-
The simplest way to get started
|
|
88
|
+
The simplest way to get started with lazy initialization. Default configuration handles adapter setup automatically.
|
|
78
89
|
|
|
79
90
|
```typescript
|
|
80
91
|
import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
|
|
81
92
|
|
|
82
|
-
//
|
|
93
|
+
// Minimal configuration with lazy initialization
|
|
83
94
|
const adapter = createAdapterFromPrivateKey({
|
|
84
95
|
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
|
|
85
|
-
|
|
96
|
+
// Defaults applied:
|
|
97
|
+
// - addressContext: 'user-controlled'
|
|
98
|
+
// - supportedChains: all EVM chains (~34 networks)
|
|
99
|
+
// - Lazy initialization: wallet connects to chain on first operation
|
|
86
100
|
})
|
|
87
101
|
|
|
88
|
-
//
|
|
89
|
-
const
|
|
90
|
-
|
|
102
|
+
// Chain specified per operation via OperationContext
|
|
103
|
+
const prepared = await adapter.prepare(
|
|
104
|
+
{
|
|
105
|
+
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on Ethereum
|
|
106
|
+
abi: usdcAbi,
|
|
107
|
+
functionName: 'transfer',
|
|
108
|
+
args: ['0xrecipient', '1000000'],
|
|
109
|
+
},
|
|
110
|
+
{ chain: 'Ethereum' }, // Chain specified in context
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
const txHash = await prepared.execute()
|
|
91
114
|
```
|
|
92
115
|
|
|
93
|
-
###
|
|
116
|
+
### Production Setup
|
|
94
117
|
|
|
95
|
-
|
|
118
|
+
For production use, provide custom RPC endpoints for better reliability and performance:
|
|
96
119
|
|
|
97
120
|
```typescript
|
|
98
121
|
import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
|
|
99
122
|
import { JsonRpcProvider } from 'ethers'
|
|
123
|
+
import { Ethereum, Base, Polygon } from '@core/chains'
|
|
100
124
|
|
|
101
|
-
// Production-ready
|
|
125
|
+
// Production-ready with custom RPC endpoints and lazy initialization
|
|
102
126
|
const adapter = createAdapterFromPrivateKey({
|
|
103
127
|
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
|
|
104
|
-
|
|
105
|
-
getProvider: ({ chain }) =>
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
128
|
+
// Custom RPC provider with explicit chain mapping
|
|
129
|
+
getProvider: ({ chain }) => {
|
|
130
|
+
// Map chain names to RPC endpoints
|
|
131
|
+
// Customize this mapping based on your RPC provider
|
|
132
|
+
const rpcEndpoints: Record<string, string> = {
|
|
133
|
+
Ethereum: `https://eth-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`,
|
|
134
|
+
Base: `https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`,
|
|
135
|
+
Polygon: `https://polygon-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`,
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const endpoint = rpcEndpoints[chain.name]
|
|
139
|
+
if (!endpoint) {
|
|
140
|
+
throw new Error(`RPC endpoint not configured for chain: ${chain.name}`)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return new JsonRpcProvider(endpoint, chain.chainId)
|
|
144
|
+
},
|
|
145
|
+
// Optionally restrict to specific chains
|
|
146
|
+
capabilities: {
|
|
147
|
+
supportedChains: [Ethereum, Base, Polygon],
|
|
148
|
+
},
|
|
109
149
|
})
|
|
110
150
|
```
|
|
111
151
|
|
|
112
|
-
|
|
152
|
+
> **⚠️ Production Note**: Default factory methods use public RPC endpoints which may have rate limits. For production, use dedicated providers like Alchemy, Infura, or QuickNode.
|
|
153
|
+
|
|
154
|
+
### Browser Wallet Setup
|
|
113
155
|
|
|
114
|
-
For browser environments with
|
|
156
|
+
For browser environments with MetaMask or WalletConnect:
|
|
115
157
|
|
|
116
158
|
```typescript
|
|
117
159
|
import { createAdapterFromProvider } from '@circle-fin/adapter-ethers-v6'
|
|
118
160
|
|
|
119
|
-
//
|
|
161
|
+
// Minimal browser wallet configuration
|
|
120
162
|
const adapter = await createAdapterFromProvider({
|
|
121
163
|
provider: window.ethereum,
|
|
122
|
-
|
|
123
|
-
getProvider: ({ chain }) =>
|
|
124
|
-
new JsonRpcProvider(
|
|
125
|
-
`https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_KEY}`,
|
|
126
|
-
),
|
|
164
|
+
// Default capabilities applied automatically
|
|
127
165
|
})
|
|
166
|
+
|
|
167
|
+
// User will be prompted to connect wallet
|
|
168
|
+
// Address is automatically resolved from connected wallet
|
|
169
|
+
const prepared = await adapter.prepare(
|
|
170
|
+
{
|
|
171
|
+
address: '0xcontract',
|
|
172
|
+
abi: contractAbi,
|
|
173
|
+
functionName: 'approve',
|
|
174
|
+
args: ['0xspender', '1000000'],
|
|
175
|
+
},
|
|
176
|
+
{ chain: 'Polygon' },
|
|
177
|
+
)
|
|
128
178
|
```
|
|
129
179
|
|
|
130
|
-
|
|
180
|
+
## OperationContext Pattern
|
|
181
|
+
|
|
182
|
+
### Why OperationContext?
|
|
183
|
+
|
|
184
|
+
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.
|
|
185
|
+
|
|
186
|
+
**Benefits:**
|
|
187
|
+
|
|
188
|
+
- ✅ **One adapter, many chains** - No need to create separate adapters for each network
|
|
189
|
+
- ✅ **Explicit is better** - Chain is always clear in your code
|
|
190
|
+
- ✅ **Type-safe** - Full TypeScript support with compile-time checks
|
|
191
|
+
- ✅ **Eliminates ambiguity** - No confusion about which chain is being used
|
|
192
|
+
|
|
193
|
+
### Basic Usage
|
|
131
194
|
|
|
132
|
-
|
|
195
|
+
Every operation accepts an `OperationContext` parameter that specifies the chain:
|
|
133
196
|
|
|
134
197
|
```typescript
|
|
135
|
-
import {
|
|
136
|
-
import { JsonRpcProvider, Wallet } from 'ethers'
|
|
198
|
+
import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
|
|
137
199
|
|
|
138
|
-
//
|
|
139
|
-
const
|
|
140
|
-
|
|
200
|
+
// Create adapter without specifying a chain - true lazy initialization
|
|
201
|
+
const adapter = createAdapterFromPrivateKey({
|
|
202
|
+
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
// Chain specified explicitly in every operation
|
|
206
|
+
const prepared = await adapter.prepare(
|
|
207
|
+
{
|
|
208
|
+
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
209
|
+
abi: usdcAbi,
|
|
210
|
+
functionName: 'transfer',
|
|
211
|
+
args: ['0xrecipient', '1000000'],
|
|
212
|
+
},
|
|
213
|
+
{ chain: 'Ethereum' },
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
const gas = await prepared.estimate()
|
|
217
|
+
const txHash = await prepared.execute()
|
|
218
|
+
```
|
|
141
219
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
220
|
+
### Multi-Chain Operations
|
|
221
|
+
|
|
222
|
+
Use a single adapter instance for operations across multiple chains:
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
// Create adapter once for use across multiple chains
|
|
226
|
+
const adapter = createAdapterFromPrivateKey({
|
|
227
|
+
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
|
|
146
228
|
})
|
|
229
|
+
|
|
230
|
+
// Transfer USDC on Ethereum
|
|
231
|
+
const ethPrepared = await adapter.prepare(
|
|
232
|
+
{
|
|
233
|
+
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on Ethereum
|
|
234
|
+
abi: usdcAbi,
|
|
235
|
+
functionName: 'transfer',
|
|
236
|
+
args: ['0xrecipient', '1000000'],
|
|
237
|
+
},
|
|
238
|
+
{ chain: 'Ethereum' },
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
// Transfer USDC on Base using the same adapter
|
|
242
|
+
const basePrepared = await adapter.prepare(
|
|
243
|
+
{
|
|
244
|
+
address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base
|
|
245
|
+
abi: usdcAbi,
|
|
246
|
+
functionName: 'transfer',
|
|
247
|
+
args: ['0xrecipient', '1000000'],
|
|
248
|
+
},
|
|
249
|
+
{ chain: 'Base' },
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
// Execute both transfers
|
|
253
|
+
await ethPrepared.execute()
|
|
254
|
+
await basePrepared.execute()
|
|
147
255
|
```
|
|
148
256
|
|
|
149
|
-
##
|
|
257
|
+
## Address Context Guide
|
|
150
258
|
|
|
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
|
|
259
|
+
The adapter supports two address control patterns. Choose the one that fits your use case.
|
|
156
260
|
|
|
157
|
-
|
|
261
|
+
### User-Controlled (Recommended)
|
|
158
262
|
|
|
159
|
-
|
|
263
|
+
**Best for:** Private key wallets, browser wallets (MetaMask), hardware wallets
|
|
160
264
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
265
|
+
**How it works:** Address is automatically resolved from the connected signer/wallet. You don't need to specify it in the OperationContext.
|
|
266
|
+
|
|
267
|
+
**When to use:**
|
|
164
268
|
|
|
165
|
-
|
|
269
|
+
- ✅ Building a dApp where users connect their wallets
|
|
270
|
+
- ✅ Using a private key for backend automation
|
|
271
|
+
- ✅ Single wallet signing all transactions
|
|
272
|
+
- ✅ Server-side scripts with one identity
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
// User-controlled adapter (default for factory functions)
|
|
166
276
|
const adapter = createAdapterFromPrivateKey({
|
|
167
277
|
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
|
|
168
|
-
|
|
278
|
+
// addressContext: 'user-controlled' is the default
|
|
169
279
|
})
|
|
170
280
|
|
|
171
|
-
//
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
281
|
+
// Address automatically resolved from private key/wallet
|
|
282
|
+
const prepared = await adapter.prepare(
|
|
283
|
+
{
|
|
284
|
+
address: '0xcontract',
|
|
285
|
+
abi: contractAbi,
|
|
286
|
+
functionName: 'approve',
|
|
287
|
+
args: ['0xspender', '1000000'],
|
|
288
|
+
},
|
|
289
|
+
{ chain: 'Polygon' }, // No address needed in context for user-controlled
|
|
290
|
+
)
|
|
178
291
|
```
|
|
179
292
|
|
|
180
|
-
###
|
|
293
|
+
### Developer-Controlled (Advanced)
|
|
294
|
+
|
|
295
|
+
**Best for:** Custody solutions, multi-entity systems, enterprise applications
|
|
296
|
+
|
|
297
|
+
**How it works:** Address must be explicitly provided in the OperationContext for each operation.
|
|
298
|
+
|
|
299
|
+
**When to use:**
|
|
300
|
+
|
|
301
|
+
- ✅ Building a custody solution managing multiple client wallets
|
|
302
|
+
- ✅ Enterprise system where different users have different signing keys
|
|
303
|
+
- ✅ Multi-sig or delegated signing infrastructure
|
|
304
|
+
- ✅ Systems where address varies per transaction
|
|
181
305
|
|
|
182
306
|
```typescript
|
|
183
307
|
import { EthersAdapter } from '@circle-fin/adapter-ethers-v6'
|
|
184
|
-
import {
|
|
185
|
-
|
|
308
|
+
import { Ethereum, Base } from '@core/chains'
|
|
309
|
+
|
|
310
|
+
// Developer-controlled adapter (manual constructor)
|
|
311
|
+
const adapter = new EthersAdapter(
|
|
312
|
+
{
|
|
313
|
+
getProvider: ({ chain }) => new JsonRpcProvider('https://...'),
|
|
314
|
+
signer: wallet,
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
addressContext: 'developer-controlled', // ← Explicit address required
|
|
318
|
+
supportedChains: [Ethereum, Base],
|
|
319
|
+
},
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
// Address must be provided in context for developer-controlled adapters
|
|
323
|
+
const prepared = await adapter.prepare(
|
|
324
|
+
{
|
|
325
|
+
address: '0xcontract',
|
|
326
|
+
abi: contractAbi,
|
|
327
|
+
functionName: 'approve',
|
|
328
|
+
args: ['0xspender', '1000000'],
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
chain: 'Ethereum',
|
|
332
|
+
address: '0x1234...', // Required for developer-controlled
|
|
333
|
+
},
|
|
334
|
+
)
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Usage Examples
|
|
186
338
|
|
|
187
|
-
|
|
188
|
-
const wallet = new Wallet(process.env.PRIVATE_KEY!, provider)
|
|
339
|
+
### Contract Interactions
|
|
189
340
|
|
|
190
|
-
|
|
341
|
+
**Transfer USDC** across different chains with the same adapter:
|
|
191
342
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
343
|
+
```typescript
|
|
344
|
+
import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
|
|
345
|
+
import { parseAbi } from 'ethers'
|
|
346
|
+
|
|
347
|
+
// Create adapter with lazy initialization
|
|
348
|
+
const adapter = createAdapterFromPrivateKey({
|
|
349
|
+
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
|
|
198
350
|
})
|
|
199
351
|
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
352
|
+
const usdcAbi = parseAbi([
|
|
353
|
+
'function transfer(address to, uint256 amount) returns (bool)',
|
|
354
|
+
])
|
|
355
|
+
|
|
356
|
+
// Transfer on Ethereum - chain specified in operation
|
|
357
|
+
const ethPrepared = await adapter.prepare(
|
|
358
|
+
{
|
|
359
|
+
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on Ethereum
|
|
360
|
+
abi: usdcAbi,
|
|
361
|
+
functionName: 'transfer',
|
|
362
|
+
args: ['0xrecipient', '1000000'], // 1 USDC (6 decimals)
|
|
363
|
+
},
|
|
364
|
+
{ chain: 'Ethereum' },
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
// Estimate and execute
|
|
368
|
+
const gas = await ethPrepared.estimate()
|
|
369
|
+
console.log('Estimated gas:', gas.gas)
|
|
370
|
+
|
|
371
|
+
const txHash = await ethPrepared.execute()
|
|
372
|
+
console.log('Transaction hash:', txHash)
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### EIP-712 Signatures
|
|
376
|
+
|
|
377
|
+
**Sign permit approvals** for gasless token approvals:
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
|
|
381
|
+
|
|
382
|
+
const adapter = createAdapterFromPrivateKey({
|
|
383
|
+
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
|
|
205
384
|
})
|
|
385
|
+
|
|
386
|
+
// Sign ERC-2612 permit (gasless USDC approval)
|
|
387
|
+
const signature = await adapter.signTypedData(
|
|
388
|
+
{
|
|
389
|
+
domain: {
|
|
390
|
+
name: 'USD Coin',
|
|
391
|
+
version: '2',
|
|
392
|
+
chainId: 1,
|
|
393
|
+
verifyingContract: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
394
|
+
},
|
|
395
|
+
types: {
|
|
396
|
+
Permit: [
|
|
397
|
+
{ name: 'owner', type: 'address' },
|
|
398
|
+
{ name: 'spender', type: 'address' },
|
|
399
|
+
{ name: 'value', type: 'uint256' },
|
|
400
|
+
{ name: 'nonce', type: 'uint256' },
|
|
401
|
+
{ name: 'deadline', type: 'uint256' },
|
|
402
|
+
],
|
|
403
|
+
},
|
|
404
|
+
primaryType: 'Permit',
|
|
405
|
+
message: {
|
|
406
|
+
owner: '0xowner',
|
|
407
|
+
spender: '0xspender',
|
|
408
|
+
value: '1000000',
|
|
409
|
+
nonce: '0',
|
|
410
|
+
deadline: '1735689600',
|
|
411
|
+
},
|
|
412
|
+
},
|
|
413
|
+
{ chain: 'Ethereum' }, // Chain must be specified
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
console.log('Permit signature:', signature)
|
|
417
|
+
// Use signature for gasless approval
|
|
206
418
|
```
|
|
207
419
|
|
|
208
|
-
###
|
|
420
|
+
### Cross-Chain Bridging
|
|
421
|
+
|
|
422
|
+
**Bridge USDC** using the Bridging Kit with OperationContext:
|
|
209
423
|
|
|
210
424
|
```typescript
|
|
211
425
|
import { createAdapterFromPrivateKey } from '@circle-fin/adapter-ethers-v6'
|
|
212
426
|
import { BridgingKit } from '@circle-fin/bridging-kit'
|
|
213
427
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
// Create ONE adapter that can work across ANY supported chain
|
|
428
|
+
// Create adapter for multi-chain operations
|
|
217
429
|
const adapter = createAdapterFromPrivateKey({
|
|
218
430
|
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
|
|
219
|
-
defaultChain: 'Ethereum', // This is just the default
|
|
220
431
|
})
|
|
221
432
|
|
|
222
|
-
|
|
433
|
+
const kit = new BridgingKit()
|
|
434
|
+
|
|
435
|
+
// Bridge from Ethereum to Base using the same adapter
|
|
223
436
|
const result = await kit.bridge({
|
|
224
|
-
from: { adapter
|
|
225
|
-
to: { adapter, chain: 'Base' },
|
|
226
|
-
amount: '
|
|
437
|
+
from: { adapter, chain: 'Ethereum' },
|
|
438
|
+
to: { adapter, chain: 'Base' },
|
|
439
|
+
amount: '100.50',
|
|
227
440
|
token: 'USDC',
|
|
228
441
|
})
|
|
229
442
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
443
|
+
console.log('Bridge transaction:', result.transactionHash)
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
## API Reference
|
|
447
|
+
|
|
448
|
+
### Factory Functions
|
|
449
|
+
|
|
450
|
+
#### `createAdapterFromPrivateKey(params)`
|
|
451
|
+
|
|
452
|
+
Creates an adapter from a private key for server-side use.
|
|
453
|
+
|
|
454
|
+
**Parameters:**
|
|
455
|
+
|
|
456
|
+
- `privateKey` - 32-byte hex string with `0x` prefix
|
|
457
|
+
- `getProvider?` - Optional custom provider function
|
|
458
|
+
- `capabilities?` - Optional partial capabilities (defaults: user-controlled + all EVM chains)
|
|
459
|
+
|
|
460
|
+
**Returns:** `EthersAdapter` instance with lazy initialization
|
|
461
|
+
|
|
462
|
+
**Note:** No chain required at creation time. The adapter connects to chains lazily on first operation.
|
|
463
|
+
|
|
464
|
+
```typescript
|
|
465
|
+
const adapter = createAdapterFromPrivateKey({
|
|
466
|
+
privateKey: '0x...',
|
|
236
467
|
})
|
|
237
468
|
```
|
|
238
469
|
|
|
239
|
-
|
|
470
|
+
#### `createAdapterFromProvider(params)`
|
|
240
471
|
|
|
241
|
-
|
|
472
|
+
Creates an adapter from a browser wallet provider (MetaMask, WalletConnect, etc.).
|
|
242
473
|
|
|
243
|
-
|
|
474
|
+
**Parameters:**
|
|
244
475
|
|
|
245
|
-
|
|
476
|
+
- `provider` - EIP-1193 compatible provider
|
|
477
|
+
- `getProvider?` - Optional custom provider function
|
|
478
|
+
- `capabilities?` - Optional partial capabilities (defaults: user-controlled + all EVM chains)
|
|
246
479
|
|
|
247
|
-
|
|
480
|
+
**Returns:** `Promise<EthersAdapter>` instance
|
|
481
|
+
|
|
482
|
+
```typescript
|
|
483
|
+
const adapter = await createAdapterFromProvider({
|
|
484
|
+
provider: window.ethereum,
|
|
485
|
+
})
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### Core Methods
|
|
489
|
+
|
|
490
|
+
#### `prepare(params, ctx)`
|
|
491
|
+
|
|
492
|
+
Prepares a contract function call for estimation and execution.
|
|
248
493
|
|
|
249
|
-
|
|
494
|
+
**Parameters:**
|
|
495
|
+
|
|
496
|
+
- `params` - Contract call parameters (address, abi, functionName, args)
|
|
497
|
+
- `ctx` - **Required** OperationContext with chain specification
|
|
498
|
+
|
|
499
|
+
**Returns:** `Promise<PreparedChainRequest>` with `estimate()` and `execute()` methods
|
|
250
500
|
|
|
251
501
|
```typescript
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
502
|
+
const prepared = await adapter.prepare(
|
|
503
|
+
{
|
|
504
|
+
address: '0xcontract',
|
|
505
|
+
abi: contractAbi,
|
|
506
|
+
functionName: 'transfer',
|
|
507
|
+
args: ['0xto', '1000000'],
|
|
508
|
+
},
|
|
509
|
+
{ chain: 'Ethereum' }, // Required
|
|
510
|
+
)
|
|
256
511
|
```
|
|
257
512
|
|
|
258
|
-
|
|
513
|
+
#### `signTypedData(typedData, ctx)`
|
|
514
|
+
|
|
515
|
+
Signs EIP-712 typed data for permits, meta-transactions, etc.
|
|
516
|
+
|
|
517
|
+
**Parameters:**
|
|
259
518
|
|
|
260
|
-
- `
|
|
261
|
-
- `
|
|
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
|
|
519
|
+
- `typedData` - EIP-712 structured data
|
|
520
|
+
- `ctx` - **Required** OperationContext with chain specification
|
|
268
521
|
|
|
269
|
-
|
|
522
|
+
**Returns:** `Promise<string>` - Signature as hex string
|
|
270
523
|
|
|
271
|
-
|
|
524
|
+
```typescript
|
|
525
|
+
const signature = await adapter.signTypedData(permitData, {
|
|
526
|
+
chain: 'Ethereum',
|
|
527
|
+
})
|
|
528
|
+
```
|
|
272
529
|
|
|
273
|
-
|
|
530
|
+
#### `waitForTransaction(txHash, config?)`
|
|
274
531
|
|
|
275
|
-
|
|
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)
|
|
532
|
+
Waits for transaction confirmation.
|
|
279
533
|
|
|
280
|
-
|
|
534
|
+
**Parameters:**
|
|
281
535
|
|
|
282
|
-
|
|
536
|
+
- `txHash` - Transaction hash to wait for
|
|
537
|
+
- `config?` - Optional wait configuration (confirmations, timeout)
|
|
283
538
|
|
|
284
|
-
|
|
539
|
+
**Returns:** `Promise<TransactionReceipt>`
|
|
285
540
|
|
|
286
541
|
```typescript
|
|
287
|
-
|
|
288
|
-
|
|
542
|
+
const receipt = await adapter.waitForTransaction('0x...')
|
|
543
|
+
```
|
|
289
544
|
|
|
290
|
-
|
|
545
|
+
#### `getAddress(chain?)`
|
|
291
546
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
547
|
+
Gets the connected wallet address. Chain parameter is provided automatically by OperationContext resolution.
|
|
548
|
+
|
|
549
|
+
**Returns:** `Promise<string>` - Wallet address
|
|
550
|
+
|
|
551
|
+
#### `getChain()`
|
|
552
|
+
|
|
553
|
+
**Deprecated** - Use OperationContext pattern instead. Gets the current chain definition.
|
|
554
|
+
|
|
555
|
+
**Returns:** `Promise<ChainDefinition>`
|
|
556
|
+
|
|
557
|
+
### Token Operations
|
|
558
|
+
|
|
559
|
+
Built-in token operations using the action system:
|
|
560
|
+
|
|
561
|
+
```typescript
|
|
562
|
+
// Get USDC balance
|
|
563
|
+
const balance = await adapter.actions.usdc.balanceOf({
|
|
564
|
+
address: '0xwallet',
|
|
565
|
+
chain: 'Ethereum',
|
|
296
566
|
})
|
|
297
567
|
|
|
298
|
-
//
|
|
299
|
-
await
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
568
|
+
// Get token allowance
|
|
569
|
+
const allowance = await adapter.actions.token.allowance({
|
|
570
|
+
tokenAddress: '0xtoken',
|
|
571
|
+
owner: '0xowner',
|
|
572
|
+
spender: '0xspender',
|
|
573
|
+
chain: 'Base',
|
|
303
574
|
})
|
|
304
575
|
```
|
|
305
576
|
|
|
306
|
-
|
|
577
|
+
## Supported Chains & Routes
|
|
578
|
+
|
|
579
|
+
The Ethers v6 adapter supports **34 EVM-compatible chains** across mainnet and testnet environments through Circle's CCTP v2 protocol:
|
|
580
|
+
|
|
581
|
+
### Mainnet Chains (17 chains)
|
|
582
|
+
|
|
583
|
+
**Arbitrum**, **Avalanche**, **Base**, **Celo**, **Codex**, **Ethereum**, **HyperEVM**, **Ink**, **Linea**, **OP Mainnet**, **Plume**, **Polygon PoS**, **Sonic**, **Unichain**, **World Chain**, **XDC**, **ZKSync Era**
|
|
584
|
+
|
|
585
|
+
### Testnet Chains (17 chains)
|
|
586
|
+
|
|
587
|
+
**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
588
|
|
|
308
589
|
## Development
|
|
309
590
|
|
|
@@ -317,13 +598,9 @@ nx build @circle-fin/adapter-ethers-v6
|
|
|
317
598
|
nx test @circle-fin/adapter-ethers-v6
|
|
318
599
|
```
|
|
319
600
|
|
|
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
601
|
## License
|
|
325
602
|
|
|
326
|
-
This project is licensed under the Apache 2.0 License
|
|
603
|
+
This project is licensed under the Apache 2.0 License. Contact [support](https://help.circle.com/s/submit-ticket) for details.
|
|
327
604
|
|
|
328
605
|
---
|
|
329
606
|
|
|
@@ -331,7 +608,8 @@ This project is licensed under the Apache 2.0 License - see the [LICENSE](https:
|
|
|
331
608
|
|
|
332
609
|
**Ready to integrate?**
|
|
333
610
|
|
|
334
|
-
[
|
|
611
|
+
[Join Discord](https://discord.com/invite/buildoncircle) •
|
|
612
|
+
[Visit our Help-Desk](https://help.circle.com/s/submit-ticket)
|
|
335
613
|
|
|
336
614
|
_Built with ❤️ by Circle_
|
|
337
615
|
|