@circle-fin/bridge-kit 1.3.0 → 1.4.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/CHANGELOG.md +6 -0
- package/QUICKSTART.md +1 -1
- package/README.md +54 -17
- package/chains.cjs +5 -2
- package/chains.d.ts +2 -2
- package/chains.mjs +5 -2
- package/index.cjs +55 -8
- package/index.d.ts +2246 -8
- package/index.mjs +55 -8
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
package/QUICKSTART.md
CHANGED
|
@@ -1421,7 +1421,7 @@ const attestation = await retryWithBackoff(
|
|
|
1421
1421
|
|
|
1422
1422
|
## Next Steps
|
|
1423
1423
|
|
|
1424
|
-
- **Explore Examples**: Check out the [examples directory](https://github.com/
|
|
1424
|
+
- **Explore Examples**: Check out the [examples directory](https://github.com/crcl-main/stablecoin-kits-private/tree/main/examples) for more detailed implementations
|
|
1425
1425
|
- **Join the community**: Connect with other developers on [discord](https://discord.com/invite/buildoncircle) building on Circle's stablecoin infrastructure
|
|
1426
1426
|
|
|
1427
1427
|
Ready to start bridging? Let's make cross-chain bridging as easy as a single function call! 🌉
|
package/README.md
CHANGED
|
@@ -194,26 +194,50 @@ const resultWithDifferentAdapter = await kit.bridge({
|
|
|
194
194
|
|
|
195
195
|
**Best for**: Production applications, better reliability, custom configuration
|
|
196
196
|
|
|
197
|
+
Bridging involves **two chains** (source and destination), and both require properly configured RPC endpoints. Use dynamic RPC mapping by chain ID to support multiple chains in a single adapter:
|
|
198
|
+
|
|
197
199
|
```typescript
|
|
198
|
-
import
|
|
200
|
+
import 'dotenv/config'
|
|
201
|
+
import { BridgeKit } from '@circle-fin/bridge-kit'
|
|
202
|
+
import { Ethereum, Base } from '@circle-fin/bridge-kit/chains'
|
|
203
|
+
import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
|
|
204
|
+
import { createPublicClient, http, fallback } from 'viem'
|
|
205
|
+
|
|
206
|
+
// Define RPCs mapped by chain ID
|
|
207
|
+
const RPC_BY_CHAIN_ID: Record<number, string[]> = {
|
|
208
|
+
// The array allows providing multiple RPC URLs for fallback, e.g.,
|
|
209
|
+
// `[ "https://primary-rpc-url.com/...", "https://secondary-rpc-url.com/..." ]`
|
|
210
|
+
[Ethereum.chainId]: [
|
|
211
|
+
`https://eth-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`,
|
|
212
|
+
],
|
|
213
|
+
[Base.chainId]: [
|
|
214
|
+
`https://base-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`,
|
|
215
|
+
],
|
|
216
|
+
}
|
|
199
217
|
|
|
200
|
-
// Production-ready setup with custom RPC endpoints
|
|
201
218
|
const adapter = createViemAdapterFromPrivateKey({
|
|
202
|
-
privateKey: process.env.PRIVATE_KEY as string
|
|
203
|
-
getPublicClient: ({ chain }) =>
|
|
204
|
-
|
|
219
|
+
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
|
|
220
|
+
getPublicClient: ({ chain }) => {
|
|
221
|
+
const rpcUrls = RPC_BY_CHAIN_ID[chain.id]
|
|
222
|
+
if (!rpcUrls) {
|
|
223
|
+
throw new Error(`No RPC configured for chainId=${chain.id}`)
|
|
224
|
+
}
|
|
225
|
+
return createPublicClient({
|
|
205
226
|
chain,
|
|
206
|
-
transport:
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
227
|
+
transport: fallback(
|
|
228
|
+
rpcUrls.map((url) =>
|
|
229
|
+
http(url, {
|
|
230
|
+
timeout: 10_000,
|
|
231
|
+
retryCount: 3,
|
|
232
|
+
}),
|
|
233
|
+
),
|
|
212
234
|
),
|
|
213
|
-
})
|
|
235
|
+
})
|
|
236
|
+
},
|
|
214
237
|
})
|
|
215
238
|
|
|
216
|
-
|
|
239
|
+
const kit = new BridgeKit()
|
|
240
|
+
|
|
217
241
|
const result = await kit.bridge({
|
|
218
242
|
from: { adapter, chain: 'Ethereum' },
|
|
219
243
|
to: { adapter, chain: 'Base' },
|
|
@@ -221,13 +245,22 @@ const result = await kit.bridge({
|
|
|
221
245
|
})
|
|
222
246
|
```
|
|
223
247
|
|
|
248
|
+
**Best practices:**
|
|
249
|
+
|
|
250
|
+
- **Use paid RPC providers** (Alchemy, Infura, QuickNode) for improved reliability
|
|
251
|
+
- **Implement `fallback()` transport** for automatic failover between endpoints
|
|
252
|
+
- **Configure timeout and retry options** to handle network variability
|
|
253
|
+
|
|
224
254
|
### 🌐 Browser/Wallet Provider Support
|
|
225
255
|
|
|
226
256
|
**Best for**: Browser applications, wallet integrations, user-controlled transactions
|
|
227
257
|
|
|
228
258
|
```typescript
|
|
259
|
+
import { BridgeKit } from '@circle-fin/bridge-kit'
|
|
229
260
|
import { createViemAdapterFromProvider } from '@circle-fin/adapter-viem-v2'
|
|
230
261
|
|
|
262
|
+
const kit = new BridgeKit()
|
|
263
|
+
|
|
231
264
|
// Create adapters from browser wallet providers
|
|
232
265
|
const adapter = await createViemAdapterFromProvider({
|
|
233
266
|
provider: window.ethereum,
|
|
@@ -254,10 +287,10 @@ import { privateKeyToAccount } from 'viem/accounts'
|
|
|
254
287
|
|
|
255
288
|
const account = privateKeyToAccount(process.env.PRIVATE_KEY as string)
|
|
256
289
|
|
|
257
|
-
// Chain-specific RPC URLs
|
|
258
|
-
const rpcUrls = {
|
|
259
|
-
[Ethereum.
|
|
260
|
-
[Base.
|
|
290
|
+
// Chain-specific RPC URLs mapped by chain ID
|
|
291
|
+
const rpcUrls: Record<number, string> = {
|
|
292
|
+
[Ethereum.chainId]: 'https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY',
|
|
293
|
+
[Base.chainId]: 'https://base-mainnet.g.alchemy.com/v2/YOUR_KEY',
|
|
261
294
|
}
|
|
262
295
|
|
|
263
296
|
// Create one multi-chain adapter with chain-specific RPC configuration
|
|
@@ -445,8 +478,12 @@ For dynamic fee calculation across all transfers, use kit-level policies:
|
|
|
445
478
|
|
|
446
479
|
```typescript
|
|
447
480
|
import { BridgeKit } from '@circle-fin/bridge-kit'
|
|
481
|
+
import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
|
|
448
482
|
|
|
449
483
|
const kit = new BridgeKit()
|
|
484
|
+
const adapter = createViemAdapterFromPrivateKey({
|
|
485
|
+
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
|
|
486
|
+
})
|
|
450
487
|
|
|
451
488
|
kit.setCustomFeePolicy({
|
|
452
489
|
computeFee: (params) => {
|
package/chains.cjs
CHANGED
|
@@ -366,8 +366,11 @@ const ArcTestnet = defineChain({
|
|
|
366
366
|
name: 'Arc Testnet',
|
|
367
367
|
title: 'ArcTestnet',
|
|
368
368
|
nativeCurrency: {
|
|
369
|
-
name: '
|
|
370
|
-
symbol: '
|
|
369
|
+
name: 'USDC',
|
|
370
|
+
symbol: 'USDC',
|
|
371
|
+
// Arc uses native USDC with 18 decimals for gas payments (EVM standard).
|
|
372
|
+
// Note: The ERC-20 USDC contract at usdcAddress uses 6 decimals.
|
|
373
|
+
// See: https://docs.arc.network/arc/references/contract-addresses
|
|
371
374
|
decimals: 18,
|
|
372
375
|
},
|
|
373
376
|
chainId: 5042002,
|
package/chains.d.ts
CHANGED
|
@@ -184,8 +184,8 @@ declare const ArcTestnet: {
|
|
|
184
184
|
readonly name: "Arc Testnet";
|
|
185
185
|
readonly title: "ArcTestnet";
|
|
186
186
|
readonly nativeCurrency: {
|
|
187
|
-
readonly name: "
|
|
188
|
-
readonly symbol: "
|
|
187
|
+
readonly name: "USDC";
|
|
188
|
+
readonly symbol: "USDC";
|
|
189
189
|
readonly decimals: 18;
|
|
190
190
|
};
|
|
191
191
|
readonly chainId: 5042002;
|
package/chains.mjs
CHANGED
|
@@ -364,8 +364,11 @@ const ArcTestnet = defineChain({
|
|
|
364
364
|
name: 'Arc Testnet',
|
|
365
365
|
title: 'ArcTestnet',
|
|
366
366
|
nativeCurrency: {
|
|
367
|
-
name: '
|
|
368
|
-
symbol: '
|
|
367
|
+
name: 'USDC',
|
|
368
|
+
symbol: 'USDC',
|
|
369
|
+
// Arc uses native USDC with 18 decimals for gas payments (EVM standard).
|
|
370
|
+
// Note: The ERC-20 USDC contract at usdcAddress uses 6 decimals.
|
|
371
|
+
// See: https://docs.arc.network/arc/references/contract-addresses
|
|
369
372
|
decimals: 18,
|
|
370
373
|
},
|
|
371
374
|
chainId: 5042002,
|
package/index.cjs
CHANGED
|
@@ -482,6 +482,12 @@ const InputError = {
|
|
|
482
482
|
name: 'INPUT_INVALID_CHAIN',
|
|
483
483
|
type: 'INPUT',
|
|
484
484
|
},
|
|
485
|
+
/** Invalid or unknown token (symbol not found, missing decimals, etc.) */
|
|
486
|
+
INVALID_TOKEN: {
|
|
487
|
+
code: 1006,
|
|
488
|
+
name: 'INPUT_INVALID_TOKEN',
|
|
489
|
+
type: 'INPUT',
|
|
490
|
+
},
|
|
485
491
|
/** General validation failure for complex validation rules */
|
|
486
492
|
VALIDATION_FAILED: {
|
|
487
493
|
code: 1098,
|
|
@@ -1264,8 +1270,11 @@ const ArcTestnet = defineChain({
|
|
|
1264
1270
|
name: 'Arc Testnet',
|
|
1265
1271
|
title: 'ArcTestnet',
|
|
1266
1272
|
nativeCurrency: {
|
|
1267
|
-
name: '
|
|
1268
|
-
symbol: '
|
|
1273
|
+
name: 'USDC',
|
|
1274
|
+
symbol: 'USDC',
|
|
1275
|
+
// Arc uses native USDC with 18 decimals for gas payments (EVM standard).
|
|
1276
|
+
// Note: The ERC-20 USDC contract at usdcAddress uses 6 decimals.
|
|
1277
|
+
// See: https://docs.arc.network/arc/references/contract-addresses
|
|
1269
1278
|
decimals: 18,
|
|
1270
1279
|
},
|
|
1271
1280
|
chainId: 5042002,
|
|
@@ -4630,7 +4639,7 @@ const parseAmount = (params) => {
|
|
|
4630
4639
|
};
|
|
4631
4640
|
|
|
4632
4641
|
var name = "@circle-fin/bridge-kit";
|
|
4633
|
-
var version = "1.
|
|
4642
|
+
var version = "1.4.0";
|
|
4634
4643
|
var pkg = {
|
|
4635
4644
|
name: name,
|
|
4636
4645
|
version: version};
|
|
@@ -5907,7 +5916,7 @@ class BridgeKit {
|
|
|
5907
5916
|
return formatBridgeResult(await provider.estimate(finalResolvedParams), 'to-human-readable');
|
|
5908
5917
|
}
|
|
5909
5918
|
/**
|
|
5910
|
-
* Get all chains supported by any provider in the kit.
|
|
5919
|
+
* Get all chains supported by any provider in the kit, with optional filtering.
|
|
5911
5920
|
*
|
|
5912
5921
|
* Aggregate and deduplicate the supported chains from all registered providers.
|
|
5913
5922
|
* This provides a comprehensive list of chains that can be used as either source
|
|
@@ -5917,6 +5926,7 @@ class BridgeKit {
|
|
|
5917
5926
|
* ensuring each chain appears only once in the result regardless of how many
|
|
5918
5927
|
* providers support it.
|
|
5919
5928
|
*
|
|
5929
|
+
* @param options - Optional filtering options to narrow down the returned chains
|
|
5920
5930
|
* @returns Array of unique chain definitions supported by the registered providers
|
|
5921
5931
|
*
|
|
5922
5932
|
* @example
|
|
@@ -5924,19 +5934,56 @@ class BridgeKit {
|
|
|
5924
5934
|
* import { BridgeKit } from '@circle-fin/bridge-kit'
|
|
5925
5935
|
*
|
|
5926
5936
|
* const kit = new BridgeKit()
|
|
5927
|
-
*
|
|
5937
|
+
*
|
|
5938
|
+
* // Get all supported chains (no filtering)
|
|
5939
|
+
* const allChains = kit.getSupportedChains()
|
|
5940
|
+
*
|
|
5941
|
+
* // Get only EVM chains
|
|
5942
|
+
* const evmChains = kit.getSupportedChains({ chainType: 'evm' })
|
|
5943
|
+
*
|
|
5944
|
+
* // Get EVM and Solana chains
|
|
5945
|
+
* const evmAndSolana = kit.getSupportedChains({ chainType: ['evm', 'solana'] })
|
|
5946
|
+
*
|
|
5947
|
+
* // Get only mainnet chains
|
|
5948
|
+
* const mainnets = kit.getSupportedChains({ isTestnet: false })
|
|
5949
|
+
*
|
|
5950
|
+
* // Get only EVM mainnet chains
|
|
5951
|
+
* const evmMainnets = kit.getSupportedChains({ chainType: 'evm', isTestnet: false })
|
|
5928
5952
|
*
|
|
5929
5953
|
* console.log('Supported chains:')
|
|
5930
|
-
*
|
|
5954
|
+
* allChains.forEach(chain => {
|
|
5931
5955
|
* console.log(`- ${chain.name} (${chain.type})`)
|
|
5932
5956
|
* })
|
|
5933
5957
|
* ```
|
|
5934
5958
|
*/
|
|
5935
|
-
getSupportedChains() {
|
|
5959
|
+
getSupportedChains(options) {
|
|
5936
5960
|
const supportedChains = this.providers.flatMap((p) => p.supportedChains);
|
|
5937
5961
|
// Deduplicate chains by using chain identifiers as object keys
|
|
5938
5962
|
// Later duplicates will override earlier ones, keeping only the last occurrence
|
|
5939
|
-
|
|
5963
|
+
let chains = Object.values(Object.fromEntries(supportedChains.map((chain) => [chain.chain, chain])));
|
|
5964
|
+
// Apply chain type filter if provided
|
|
5965
|
+
if (options?.chainType !== undefined) {
|
|
5966
|
+
// Validate at runtime since JS consumers can bypass TypeScript's narrow type.
|
|
5967
|
+
const supportedChainTypes = ['evm', 'solana'];
|
|
5968
|
+
const chainTypeInput = options.chainType;
|
|
5969
|
+
const chainTypeValues = Array.isArray(chainTypeInput)
|
|
5970
|
+
? chainTypeInput
|
|
5971
|
+
: [chainTypeInput];
|
|
5972
|
+
if (!chainTypeValues.every((chainType) => supportedChainTypes.includes(chainType))) {
|
|
5973
|
+
const listFormatter = new Intl.ListFormat('en', {
|
|
5974
|
+
style: 'long',
|
|
5975
|
+
type: 'conjunction',
|
|
5976
|
+
});
|
|
5977
|
+
throw createValidationFailedError$1('options.chainType', options.chainType, `Supported chain types include: ${listFormatter.format(supportedChainTypes)}`);
|
|
5978
|
+
}
|
|
5979
|
+
const chainTypes = new Set(chainTypeValues);
|
|
5980
|
+
chains = chains.filter((chain) => chainTypes.has(chain.type));
|
|
5981
|
+
}
|
|
5982
|
+
// Apply testnet filter if provided
|
|
5983
|
+
if (options?.isTestnet !== undefined) {
|
|
5984
|
+
chains = chains.filter((chain) => chain.isTestnet === options.isTestnet);
|
|
5985
|
+
}
|
|
5986
|
+
return chains;
|
|
5940
5987
|
}
|
|
5941
5988
|
/**
|
|
5942
5989
|
* Validate that source and destination chains are on the same network type.
|