@circle-fin/provider-cctp-v2 1.0.0 → 1.0.1
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 +4 -2
- package/index.cjs.js +273 -109
- package/index.d.ts +100 -20
- package/index.mjs +273 -110
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -232,8 +232,10 @@ const destAdapter = new ViemAdapter({
|
|
|
232
232
|
// Monitor transfer events
|
|
233
233
|
kit.on('*', (event) => console.log('Event:', event)) // subscribe to all events
|
|
234
234
|
kit.on('approve', (event) => console.log('Approval:', event.values.txHash))
|
|
235
|
-
kit.on('
|
|
236
|
-
kit.on('
|
|
235
|
+
kit.on('burn', (event) => console.log('Burn:', event.values.txHash))
|
|
236
|
+
kit.on('fetchAttestation', (event) =>
|
|
237
|
+
console.log('Attestation:', event.values.data),
|
|
238
|
+
)
|
|
237
239
|
kit.on('mint', (event) => console.log('Mint:', event.values.txHash))
|
|
238
240
|
|
|
239
241
|
// Execute transfer
|
package/index.cjs.js
CHANGED
|
@@ -54,6 +54,7 @@ var Blockchain;
|
|
|
54
54
|
Blockchain["Algorand_Testnet"] = "Algorand_Testnet";
|
|
55
55
|
Blockchain["Aptos"] = "Aptos";
|
|
56
56
|
Blockchain["Aptos_Testnet"] = "Aptos_Testnet";
|
|
57
|
+
Blockchain["Arc_Testnet"] = "Arc_Testnet";
|
|
57
58
|
Blockchain["Arbitrum"] = "Arbitrum";
|
|
58
59
|
Blockchain["Arbitrum_Sepolia"] = "Arbitrum_Sepolia";
|
|
59
60
|
Blockchain["Avalanche"] = "Avalanche";
|
|
@@ -274,6 +275,48 @@ const BRIDGE_CONTRACT_EVM_TESTNET = '0xC5567a5E3370d4DBfB0540025078e283e36A363d'
|
|
|
274
275
|
*/
|
|
275
276
|
const BRIDGE_CONTRACT_EVM_MAINNET = '0xB3FA262d0fB521cc93bE83d87b322b8A23DAf3F0';
|
|
276
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Arc Testnet chain definition
|
|
280
|
+
* @remarks
|
|
281
|
+
* This represents the test network for the Arc blockchain,
|
|
282
|
+
* Circle's EVM-compatible Layer-1 designed for stablecoin finance
|
|
283
|
+
* and asset tokenization. Arc uses USDC as the native gas token and
|
|
284
|
+
* features the Malachite Byzantine Fault Tolerant (BFT) consensus
|
|
285
|
+
* engine for sub-second finality.
|
|
286
|
+
*/
|
|
287
|
+
const ArcTestnet = defineChain({
|
|
288
|
+
type: 'evm',
|
|
289
|
+
chain: Blockchain.Arc_Testnet,
|
|
290
|
+
name: 'Arc Testnet',
|
|
291
|
+
title: 'ArcTestnet',
|
|
292
|
+
nativeCurrency: {
|
|
293
|
+
name: 'Arc',
|
|
294
|
+
symbol: 'Arc',
|
|
295
|
+
decimals: 18,
|
|
296
|
+
},
|
|
297
|
+
chainId: 5042002,
|
|
298
|
+
isTestnet: true,
|
|
299
|
+
explorerUrl: 'https://testnet.arcscan.app/tx/{hash}',
|
|
300
|
+
rpcEndpoints: ['https://rpc.testnet.arc.network/'],
|
|
301
|
+
eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
302
|
+
usdcAddress: '0x3600000000000000000000000000000000000000',
|
|
303
|
+
cctp: {
|
|
304
|
+
domain: 26,
|
|
305
|
+
contracts: {
|
|
306
|
+
v2: {
|
|
307
|
+
type: 'split',
|
|
308
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
309
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
310
|
+
confirmations: 1,
|
|
311
|
+
fastConfirmations: 1,
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
kitContracts: {
|
|
316
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET,
|
|
317
|
+
},
|
|
318
|
+
});
|
|
319
|
+
|
|
277
320
|
/**
|
|
278
321
|
* Arbitrum Mainnet chain definition
|
|
279
322
|
* @remarks
|
|
@@ -1565,26 +1608,26 @@ const Sonic = defineChain({
|
|
|
1565
1608
|
});
|
|
1566
1609
|
|
|
1567
1610
|
/**
|
|
1568
|
-
* Sonic
|
|
1611
|
+
* Sonic Testnet chain definition
|
|
1569
1612
|
* @remarks
|
|
1570
1613
|
* This represents the official test network for the Sonic blockchain.
|
|
1571
1614
|
*/
|
|
1572
1615
|
const SonicTestnet = defineChain({
|
|
1573
1616
|
type: 'evm',
|
|
1574
1617
|
chain: Blockchain.Sonic_Testnet,
|
|
1575
|
-
name: 'Sonic
|
|
1576
|
-
title: 'Sonic
|
|
1618
|
+
name: 'Sonic Testnet',
|
|
1619
|
+
title: 'Sonic Testnet',
|
|
1577
1620
|
nativeCurrency: {
|
|
1578
1621
|
name: 'Sonic',
|
|
1579
1622
|
symbol: 'S',
|
|
1580
1623
|
decimals: 18,
|
|
1581
1624
|
},
|
|
1582
|
-
chainId:
|
|
1625
|
+
chainId: 14601,
|
|
1583
1626
|
isTestnet: true,
|
|
1584
1627
|
explorerUrl: 'https://testnet.sonicscan.org/tx/{hash}',
|
|
1585
|
-
rpcEndpoints: ['https://rpc.
|
|
1628
|
+
rpcEndpoints: ['https://rpc.testnet.soniclabs.com'],
|
|
1586
1629
|
eurcAddress: null,
|
|
1587
|
-
usdcAddress: '
|
|
1630
|
+
usdcAddress: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
1588
1631
|
cctp: {
|
|
1589
1632
|
domain: 13,
|
|
1590
1633
|
contracts: {
|
|
@@ -2101,6 +2144,7 @@ var Chains = {
|
|
|
2101
2144
|
AptosTestnet: AptosTestnet,
|
|
2102
2145
|
Arbitrum: Arbitrum,
|
|
2103
2146
|
ArbitrumSepolia: ArbitrumSepolia,
|
|
2147
|
+
ArcTestnet: ArcTestnet,
|
|
2104
2148
|
Avalanche: Avalanche,
|
|
2105
2149
|
AvalancheFuji: AvalancheFuji,
|
|
2106
2150
|
Base: Base,
|
|
@@ -2575,69 +2619,133 @@ class BridgingProvider {
|
|
|
2575
2619
|
}
|
|
2576
2620
|
|
|
2577
2621
|
/**
|
|
2578
|
-
*
|
|
2579
|
-
*
|
|
2580
|
-
* The user agent string is formatted as:
|
|
2581
|
-
* name/version (platform)
|
|
2582
|
-
*
|
|
2583
|
-
* - name: The SDK or kit name, set at runtime.
|
|
2584
|
-
* - version: The SDK version, set at runtime.
|
|
2585
|
-
* - platform: The runtime environment, e.g., "node/nodeVersion" or "browser/browserName".
|
|
2622
|
+
* Detect the runtime environment and return a shortened identifier.
|
|
2586
2623
|
*
|
|
2587
|
-
* @
|
|
2588
|
-
* The kit should call setKitIdentifier(name, version) once at startup.
|
|
2589
|
-
* A custom user agent will be automatically added to all HTTP requests made by the SDK.
|
|
2590
|
-
* This user agent includes the kit name, version, and platform information to help with
|
|
2591
|
-
* debugging and analytics.
|
|
2592
|
-
*
|
|
2593
|
-
* @example
|
|
2594
|
-
* ```typescript
|
|
2595
|
-
* setKitIdentifier('bridge-kit', '1.2.3')
|
|
2596
|
-
* getUserAgent() // "bridge-kit/1.2.3 (node/18.16.0)"
|
|
2597
|
-
* ```
|
|
2598
|
-
*
|
|
2599
|
-
* @returns The Stablecoin Kits SDK user agent string.
|
|
2624
|
+
* @returns Runtime string, e.g., "node/18", "browser/Chrome", or "unknown"
|
|
2600
2625
|
*/
|
|
2601
|
-
|
|
2602
|
-
|
|
2626
|
+
const getRuntime = () => {
|
|
2627
|
+
// Node.js environment
|
|
2603
2628
|
if (typeof process !== 'undefined' &&
|
|
2604
2629
|
typeof process.versions === 'object' &&
|
|
2605
2630
|
typeof process.versions.node === 'string') {
|
|
2606
|
-
|
|
2631
|
+
// Shorten to major version only
|
|
2632
|
+
const majorVersion = process.versions.node.split('.')[0] ?? 'unknown';
|
|
2633
|
+
return `node/${majorVersion}`;
|
|
2607
2634
|
}
|
|
2608
|
-
//
|
|
2635
|
+
// Browser environment
|
|
2609
2636
|
if (typeof window !== 'undefined' && typeof navigator !== 'undefined') {
|
|
2610
2637
|
const userAgent = navigator.userAgent;
|
|
2611
2638
|
const browserMatchers = {
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
'browser/Opera': (ua) => ua.includes('Opera') || ua.includes('OPR'),
|
|
2618
|
-
'browser/Brave': (ua) => ua.includes('Brave'),
|
|
2639
|
+
Edge: (ua) => ua.includes('Edg'),
|
|
2640
|
+
Chrome: (ua) => ua.includes('Chrome') && !ua.includes('Edg'),
|
|
2641
|
+
Firefox: (ua) => ua.includes('Firefox'),
|
|
2642
|
+
Safari: (ua) => ua.includes('Safari') && !ua.includes('Chrome'),
|
|
2643
|
+
Opera: (ua) => ua.includes('Opera') || ua.includes('OPR'),
|
|
2619
2644
|
};
|
|
2620
2645
|
for (const [browserName, matcher] of Object.entries(browserMatchers)) {
|
|
2621
2646
|
if (matcher(userAgent))
|
|
2622
|
-
return browserName
|
|
2647
|
+
return `browser/${browserName}`;
|
|
2623
2648
|
}
|
|
2624
2649
|
return 'browser/unknown';
|
|
2625
2650
|
}
|
|
2626
2651
|
return 'unknown';
|
|
2627
|
-
}
|
|
2652
|
+
};
|
|
2628
2653
|
/**
|
|
2629
|
-
*
|
|
2654
|
+
* Shorten package names by removing common prefixes.
|
|
2630
2655
|
*
|
|
2631
|
-
* @
|
|
2656
|
+
* @param fullName - Full package name, e.g., "\@circle-fin/bridge-kit"
|
|
2657
|
+
* @returns Shortened name, e.g., "bridge-kit"
|
|
2632
2658
|
*/
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2659
|
+
const shortenPackageName = (fullName) => {
|
|
2660
|
+
return fullName.replace('@circle-fin/', '');
|
|
2661
|
+
};
|
|
2662
|
+
/**
|
|
2663
|
+
* Format a component (name/version) with length optimizations.
|
|
2664
|
+
*
|
|
2665
|
+
* @param nameWithVersion - Component identifier, e.g., "\@circle-fin/bridge-kit/1.2.3"
|
|
2666
|
+
* @returns Formatted component, e.g., "bridge-kit/1.2"
|
|
2667
|
+
*/
|
|
2668
|
+
const formatComponent = (nameWithVersion) => {
|
|
2669
|
+
// Find the last / to split name and version
|
|
2670
|
+
// This handles scoped packages like @circle-fin/bridge-kit/1.0.0 correctly
|
|
2671
|
+
const lastSlashIndex = nameWithVersion.lastIndexOf('/');
|
|
2672
|
+
if (lastSlashIndex === -1) {
|
|
2673
|
+
// No version, just a name
|
|
2674
|
+
return shortenPackageName(nameWithVersion);
|
|
2675
|
+
}
|
|
2676
|
+
const name = nameWithVersion.substring(0, lastSlashIndex);
|
|
2677
|
+
const version = nameWithVersion.substring(lastSlashIndex + 1);
|
|
2678
|
+
if (name === '')
|
|
2679
|
+
return '';
|
|
2680
|
+
if (version === '')
|
|
2681
|
+
return shortenPackageName(name);
|
|
2682
|
+
return `${shortenPackageName(name)}/${version}`;
|
|
2683
|
+
};
|
|
2684
|
+
/**
|
|
2685
|
+
* Create a new request context from global state.
|
|
2686
|
+
*
|
|
2687
|
+
* Reads the current external prefix and kit identifier from globalThis.
|
|
2688
|
+
* This is used internally by HTTP utilities.
|
|
2689
|
+
*
|
|
2690
|
+
* @returns A new request context
|
|
2691
|
+
* @internal
|
|
2692
|
+
*/
|
|
2693
|
+
const createRequestContext = () => {
|
|
2694
|
+
const context = {};
|
|
2695
|
+
if (typeof globalThis !== 'undefined') {
|
|
2696
|
+
if (globalThis.__STABLECOIN_KITS_EXTERNAL_PREFIX__ !== undefined) {
|
|
2697
|
+
context.externalPrefix = globalThis.__STABLECOIN_KITS_EXTERNAL_PREFIX__;
|
|
2698
|
+
}
|
|
2699
|
+
if (globalThis.__STABLECOIN_KITS_CURRENT_KIT__ !== undefined) {
|
|
2700
|
+
context.kit = globalThis.__STABLECOIN_KITS_CURRENT_KIT__;
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
return context;
|
|
2704
|
+
};
|
|
2705
|
+
/**
|
|
2706
|
+
* Build a user agent string from a request context.
|
|
2707
|
+
*
|
|
2708
|
+
* Formats the context into a user agent string with automatic optimizations
|
|
2709
|
+
* (shortened package names and truncated versions). The current implementation
|
|
2710
|
+
* tracks a single kit globally.
|
|
2711
|
+
*
|
|
2712
|
+
* Format: `[external-prefix] kit (runtime)`
|
|
2713
|
+
*
|
|
2714
|
+
* @param context - Request context or undefined to use the global context
|
|
2715
|
+
* @returns Formatted user agent string
|
|
2716
|
+
*
|
|
2717
|
+
* @example
|
|
2718
|
+
* ```typescript
|
|
2719
|
+
* // With application prefix and kit
|
|
2720
|
+
* const ua = getUserAgent(context)
|
|
2721
|
+
* // → "my-app/1.0 bridge-kit/1.2 (node/18)"
|
|
2722
|
+
*
|
|
2723
|
+
* // Kit only (no application prefix set)
|
|
2724
|
+
* const ua = getUserAgent()
|
|
2725
|
+
* // → "bridge-kit/1.2 (node/18)"
|
|
2726
|
+
* ```
|
|
2727
|
+
*/
|
|
2728
|
+
const getUserAgent = (context) => {
|
|
2729
|
+
const ctx = createRequestContext();
|
|
2730
|
+
const runtime = getRuntime();
|
|
2731
|
+
// Build user agent string
|
|
2732
|
+
const parts = [];
|
|
2733
|
+
// Add external prefix if set
|
|
2734
|
+
if (ctx.externalPrefix !== undefined) {
|
|
2735
|
+
const formatted = formatComponent(ctx.externalPrefix);
|
|
2736
|
+
if (formatted)
|
|
2737
|
+
parts.push(formatted);
|
|
2738
|
+
}
|
|
2739
|
+
// Add kit if set
|
|
2740
|
+
if (ctx.kit !== undefined) {
|
|
2741
|
+
const formatted = formatComponent(ctx.kit);
|
|
2742
|
+
if (formatted)
|
|
2743
|
+
parts.push(formatted);
|
|
2744
|
+
}
|
|
2745
|
+
// Add runtime
|
|
2746
|
+
parts.push(`(${runtime})`);
|
|
2747
|
+
return parts.join(' ');
|
|
2748
|
+
};
|
|
2641
2749
|
|
|
2642
2750
|
/**
|
|
2643
2751
|
* Default configuration values for the API polling utility.
|
|
@@ -3586,9 +3694,9 @@ const customFeeSchema = zod.z
|
|
|
3586
3694
|
* token: 'USDC',
|
|
3587
3695
|
* config: {
|
|
3588
3696
|
* transferSpeed: 'FAST',
|
|
3589
|
-
* maxFee: '
|
|
3697
|
+
* maxFee: '1.5', // Decimal format
|
|
3590
3698
|
* customFee: {
|
|
3591
|
-
* value: '
|
|
3699
|
+
* value: '0.5', // Decimal format
|
|
3592
3700
|
* recipientAddress: '0x1234567890123456789012345678901234567890'
|
|
3593
3701
|
* }
|
|
3594
3702
|
* }
|
|
@@ -3615,7 +3723,12 @@ const bridgeParamsSchema = zod.z.object({
|
|
|
3615
3723
|
transferSpeed: zod.z.nativeEnum(TransferSpeed).optional(),
|
|
3616
3724
|
maxFee: zod.z
|
|
3617
3725
|
.string()
|
|
3618
|
-
.
|
|
3726
|
+
.pipe(createDecimalStringValidator({
|
|
3727
|
+
allowZero: true,
|
|
3728
|
+
regexMessage: 'maxFee must be a numeric string with optional decimal places (e.g., "1", "0.5", "1.5")',
|
|
3729
|
+
attributeName: 'maxFee',
|
|
3730
|
+
maxDecimals: 6,
|
|
3731
|
+
})(zod.z.string()))
|
|
3619
3732
|
.optional(),
|
|
3620
3733
|
customFee: customFeeSchema.optional(),
|
|
3621
3734
|
}),
|
|
@@ -3772,8 +3885,8 @@ const CCTPv2MinFinalityThreshold = {
|
|
|
3772
3885
|
*/
|
|
3773
3886
|
const DEFAULT_CONFIG = {
|
|
3774
3887
|
timeout: 2_000, // 2 seconds
|
|
3775
|
-
maxRetries: 30 * 20, // 2 seconds
|
|
3776
|
-
retryDelay:
|
|
3888
|
+
maxRetries: 30 * 20, // 30 * 20 * 2 seconds (from the retry delay) = 20 minutes (to account for slow transfers maximum time based on confirmations)
|
|
3889
|
+
retryDelay: 2_000, // 2 seconds
|
|
3777
3890
|
headers: {
|
|
3778
3891
|
'Content-Type': 'application/json',
|
|
3779
3892
|
},
|
|
@@ -4205,6 +4318,10 @@ class KitError extends Error {
|
|
|
4205
4318
|
}
|
|
4206
4319
|
}
|
|
4207
4320
|
|
|
4321
|
+
/**
|
|
4322
|
+
* Minimum error code for INPUT type errors.
|
|
4323
|
+
* INPUT errors represent validation failures and invalid parameters.
|
|
4324
|
+
*/
|
|
4208
4325
|
/**
|
|
4209
4326
|
* Standardized error definitions for INPUT type errors.
|
|
4210
4327
|
*
|
|
@@ -4690,8 +4807,6 @@ async function bridgeApproval({ params, provider, }) {
|
|
|
4690
4807
|
adapter: params.source.adapter,
|
|
4691
4808
|
chain: params.source.chain,
|
|
4692
4809
|
request: await provider.approve(params.source, approvalAmount),
|
|
4693
|
-
// We need to wait for the approval to be confirmed on chain before the transfer can be executed
|
|
4694
|
-
confirmations: 2,
|
|
4695
4810
|
});
|
|
4696
4811
|
}
|
|
4697
4812
|
|
|
@@ -4705,8 +4820,8 @@ async function bridgeApproval({ params, provider, }) {
|
|
|
4705
4820
|
* @param params - The bridge parameters containing source, destination, amount and optional config
|
|
4706
4821
|
* @param sourceChain - The source chain definition where the burn will occur
|
|
4707
4822
|
* @returns Promise resolving to the bridge step with transaction details
|
|
4708
|
-
* @throws {ValidationError} If the parameters are invalid
|
|
4709
|
-
* @throws {BridgeError} If the burn transaction fails
|
|
4823
|
+
* @throws \{ValidationError\} If the parameters are invalid
|
|
4824
|
+
* @throws \{BridgeError\} If the burn transaction fails
|
|
4710
4825
|
*
|
|
4711
4826
|
* @example
|
|
4712
4827
|
* ```typescript
|
|
@@ -4715,16 +4830,11 @@ async function bridgeApproval({ params, provider, }) {
|
|
|
4715
4830
|
* ```
|
|
4716
4831
|
*/
|
|
4717
4832
|
async function bridgeBurn({ params, provider, }) {
|
|
4718
|
-
const transferSpeed = params.config?.transferSpeed ?? TransferSpeed.FAST;
|
|
4719
4833
|
return await executePreparedChainRequest({
|
|
4720
4834
|
name: 'burn',
|
|
4721
4835
|
adapter: params.source.adapter,
|
|
4722
4836
|
chain: params.source.chain,
|
|
4723
4837
|
request: await provider.burn(params),
|
|
4724
|
-
confirmations: transferSpeed === TransferSpeed.FAST
|
|
4725
|
-
? params.source.chain.cctp.contracts.v2.fastConfirmations
|
|
4726
|
-
: params.source.chain.cctp.contracts.v2.confirmations,
|
|
4727
|
-
timeout: transferSpeed === TransferSpeed.FAST ? undefined : 1_200_000, // 20 minutes (max timeout for cctpv2 slow transfers)
|
|
4728
4838
|
});
|
|
4729
4839
|
}
|
|
4730
4840
|
|
|
@@ -4736,16 +4846,18 @@ async function bridgeBurn({ params, provider, }) {
|
|
|
4736
4846
|
* and authorizes the minting of equivalent tokens.
|
|
4737
4847
|
*
|
|
4738
4848
|
* @param params - The bridge parameters containing source, destination, amount and optional config
|
|
4739
|
-
* @param
|
|
4740
|
-
* @
|
|
4741
|
-
* @
|
|
4742
|
-
* @throws {
|
|
4743
|
-
* @throws {BridgeError} If the attestation fetch fails
|
|
4849
|
+
* @param txHash - The hash of the burn transaction
|
|
4850
|
+
* @returns Promise resolving to the bridge step with attestation data
|
|
4851
|
+
* @throws \{ValidationError\} If the parameters are invalid
|
|
4852
|
+
* @throws \{BridgeError\} If the attestation fetch fails
|
|
4744
4853
|
*
|
|
4745
4854
|
* @example
|
|
4746
4855
|
* ```typescript
|
|
4747
|
-
* const attestationStep = await
|
|
4748
|
-
*
|
|
4856
|
+
* const attestationStep = await bridgeFetchAttestation(
|
|
4857
|
+
* { params, provider },
|
|
4858
|
+
* burnTxHash
|
|
4859
|
+
* )
|
|
4860
|
+
* console.log('Attestation data:', attestationStep.data)
|
|
4749
4861
|
* ```
|
|
4750
4862
|
*/
|
|
4751
4863
|
async function bridgeFetchAttestation({ params, provider, }, txHash) {
|
|
@@ -4754,7 +4866,17 @@ async function bridgeFetchAttestation({ params, provider, }, txHash) {
|
|
|
4754
4866
|
state: 'pending',
|
|
4755
4867
|
};
|
|
4756
4868
|
try {
|
|
4757
|
-
|
|
4869
|
+
/**
|
|
4870
|
+
* Give slow transfers a longer retry delay of 30 seconds to account for the longer time it takes to get the
|
|
4871
|
+
* attestation so that we do not hit the rate limit of the IRIS API or the retry limit of the API polling utility.
|
|
4872
|
+
* We only do this for slow transfers on source chains that have greater than 20 confirmations (5 minutes of blocktime
|
|
4873
|
+
* on the slowest blocktime chains) so that we do not slow down the attestation polling for lower confirmation chains.
|
|
4874
|
+
*/
|
|
4875
|
+
const apiPollingConfig = params.config?.transferSpeed === TransferSpeed.SLOW &&
|
|
4876
|
+
params.source.chain.cctp.contracts.v2.confirmations > 20
|
|
4877
|
+
? { retryDelay: 30_000 }
|
|
4878
|
+
: undefined;
|
|
4879
|
+
const attestation = await provider.fetchAttestation(params.source, txHash, apiPollingConfig);
|
|
4758
4880
|
step = {
|
|
4759
4881
|
...step,
|
|
4760
4882
|
state: 'success',
|
|
@@ -4762,10 +4884,18 @@ async function bridgeFetchAttestation({ params, provider, }, txHash) {
|
|
|
4762
4884
|
};
|
|
4763
4885
|
}
|
|
4764
4886
|
catch (err) {
|
|
4887
|
+
let errorMessage = 'Unknown attestation error';
|
|
4888
|
+
if (err instanceof Error) {
|
|
4889
|
+
errorMessage = err.message;
|
|
4890
|
+
}
|
|
4891
|
+
else if (typeof err === 'string') {
|
|
4892
|
+
errorMessage = err;
|
|
4893
|
+
}
|
|
4765
4894
|
step = {
|
|
4766
4895
|
...step,
|
|
4767
4896
|
state: 'error',
|
|
4768
4897
|
error: err,
|
|
4898
|
+
errorMessage,
|
|
4769
4899
|
data: undefined,
|
|
4770
4900
|
};
|
|
4771
4901
|
}
|
|
@@ -4801,8 +4931,6 @@ async function bridgeMint({ params, provider, }, attestation) {
|
|
|
4801
4931
|
adapter: params.destination.adapter,
|
|
4802
4932
|
chain: params.destination.chain,
|
|
4803
4933
|
request: await provider.mint(params.source, params.destination, attestation),
|
|
4804
|
-
// We will wait for the mint to be confirmed on chain before we will return is as success
|
|
4805
|
-
confirmations: 2,
|
|
4806
4934
|
});
|
|
4807
4935
|
}
|
|
4808
4936
|
|
|
@@ -4888,6 +5016,56 @@ function handleStepError(stepName, error, result) {
|
|
|
4888
5016
|
});
|
|
4889
5017
|
}
|
|
4890
5018
|
|
|
5019
|
+
/**
|
|
5020
|
+
* Dispatch a bridge step event through the provider's action dispatcher.
|
|
5021
|
+
*
|
|
5022
|
+
* Constructs the appropriate action payload and dispatches it to any registered
|
|
5023
|
+
* event listeners. Handles type-safe dispatching for different step types.
|
|
5024
|
+
*
|
|
5025
|
+
* @param name - The step name (approve, burn, fetchAttestation, or mint).
|
|
5026
|
+
* @param step - The completed bridge step containing transaction details and explorerUrl.
|
|
5027
|
+
* @param provider - The CCTP v2 provider with action dispatcher.
|
|
5028
|
+
*
|
|
5029
|
+
* @example
|
|
5030
|
+
* ```typescript
|
|
5031
|
+
* const step: BridgeStep = {
|
|
5032
|
+
* name: 'burn',
|
|
5033
|
+
* state: 'success',
|
|
5034
|
+
* txHash: '0xabc...',
|
|
5035
|
+
* explorerUrl: 'https://sepolia.etherscan.io/tx/0xabc...',
|
|
5036
|
+
* data: { ... }
|
|
5037
|
+
* }
|
|
5038
|
+
* dispatchStepEvent('burn', step, provider)
|
|
5039
|
+
* ```
|
|
5040
|
+
*/
|
|
5041
|
+
function dispatchStepEvent(name, step, provider) {
|
|
5042
|
+
if (!provider.actionDispatcher) {
|
|
5043
|
+
return;
|
|
5044
|
+
}
|
|
5045
|
+
const actionValues = {
|
|
5046
|
+
protocol: 'cctp',
|
|
5047
|
+
version: 'v2',
|
|
5048
|
+
values: step,
|
|
5049
|
+
};
|
|
5050
|
+
switch (name) {
|
|
5051
|
+
case 'approve':
|
|
5052
|
+
case 'burn':
|
|
5053
|
+
case 'mint':
|
|
5054
|
+
provider.actionDispatcher.dispatch(name, {
|
|
5055
|
+
...actionValues,
|
|
5056
|
+
method: name,
|
|
5057
|
+
});
|
|
5058
|
+
break;
|
|
5059
|
+
case 'fetchAttestation':
|
|
5060
|
+
provider.actionDispatcher.dispatch(name, {
|
|
5061
|
+
...actionValues,
|
|
5062
|
+
method: name,
|
|
5063
|
+
values: step,
|
|
5064
|
+
});
|
|
5065
|
+
break;
|
|
5066
|
+
}
|
|
5067
|
+
}
|
|
5068
|
+
|
|
4891
5069
|
/**
|
|
4892
5070
|
* Execute a cross-chain USDC bridge using the CCTP v2 protocol.
|
|
4893
5071
|
*
|
|
@@ -4944,34 +5122,19 @@ async function bridge(params, provider) {
|
|
|
4944
5122
|
try {
|
|
4945
5123
|
const step = await executor(params, provider, context);
|
|
4946
5124
|
if (step.state === 'error') {
|
|
4947
|
-
// Include error details from the step in the thrown error
|
|
4948
|
-
|
|
5125
|
+
// Include error details from the step in the thrown error. Fall back to step.error.
|
|
5126
|
+
let fallbackErrorMessage = 'Unknown error';
|
|
5127
|
+
if (step.error instanceof Error) {
|
|
5128
|
+
fallbackErrorMessage = step.error.message;
|
|
5129
|
+
}
|
|
5130
|
+
else if (typeof step.error === 'string') {
|
|
5131
|
+
fallbackErrorMessage = step.error;
|
|
5132
|
+
}
|
|
5133
|
+
const errorDetails = step.errorMessage ?? fallbackErrorMessage;
|
|
4949
5134
|
throw new Error(`${name} step failed: ${errorDetails}`);
|
|
4950
5135
|
}
|
|
4951
5136
|
context = updateContext?.(step);
|
|
4952
|
-
|
|
4953
|
-
protocol: 'cctp',
|
|
4954
|
-
version: 'v2',
|
|
4955
|
-
values: step,
|
|
4956
|
-
};
|
|
4957
|
-
// use a switch statement for type safety to separate the different step types
|
|
4958
|
-
switch (name) {
|
|
4959
|
-
case 'approve':
|
|
4960
|
-
case 'burn':
|
|
4961
|
-
case 'mint':
|
|
4962
|
-
provider.actionDispatcher?.dispatch(name, {
|
|
4963
|
-
...actionValues,
|
|
4964
|
-
method: name,
|
|
4965
|
-
});
|
|
4966
|
-
break;
|
|
4967
|
-
case 'fetchAttestation':
|
|
4968
|
-
provider.actionDispatcher?.dispatch(name, {
|
|
4969
|
-
...actionValues,
|
|
4970
|
-
method: name,
|
|
4971
|
-
values: step,
|
|
4972
|
-
});
|
|
4973
|
-
break;
|
|
4974
|
-
}
|
|
5137
|
+
dispatchStepEvent(name, step, provider);
|
|
4975
5138
|
result.steps.push(step);
|
|
4976
5139
|
}
|
|
4977
5140
|
catch (error) {
|
|
@@ -5638,12 +5801,7 @@ async function retry(result, context, provider) {
|
|
|
5638
5801
|
throw new Error(errorMessage);
|
|
5639
5802
|
}
|
|
5640
5803
|
stepContext = updateContext?.(step);
|
|
5641
|
-
|
|
5642
|
-
protocol: 'cctp',
|
|
5643
|
-
version: 'v2',
|
|
5644
|
-
method: name,
|
|
5645
|
-
values: step.data,
|
|
5646
|
-
});
|
|
5804
|
+
dispatchStepEvent(name, step, provider);
|
|
5647
5805
|
result.steps.push(step);
|
|
5648
5806
|
}
|
|
5649
5807
|
catch (error) {
|
|
@@ -6212,7 +6370,9 @@ class CCTPV2BridgingProvider extends BridgingProvider {
|
|
|
6212
6370
|
* - `source`: The source wallet context with chain definition and adapter
|
|
6213
6371
|
* - `destination`: The destination wallet context with chain definition and adapter
|
|
6214
6372
|
* - `amount`: The bridge amount in minor units (e.g., "1000000" for 1 USDC)
|
|
6215
|
-
* - `config`: Optional bridge configuration including transferSpeed and maxFee settings
|
|
6373
|
+
* - `config`: Optional bridge configuration including transferSpeed and maxFee settings.
|
|
6374
|
+
* When used via BridgeKit, fee values are automatically converted from human-readable
|
|
6375
|
+
* format (e.g., "1") to smallest units (e.g., "1000000").
|
|
6216
6376
|
* @returns The maximum fee to be used for the bridge operation in minor units
|
|
6217
6377
|
*
|
|
6218
6378
|
* @example
|
|
@@ -6220,9 +6380,12 @@ class CCTPV2BridgingProvider extends BridgingProvider {
|
|
|
6220
6380
|
* const maxFee = await provider.getMaxFee({
|
|
6221
6381
|
* source: { adapter: sourceAdapter, chain: Chains.Ethereum, address: '0x...' },
|
|
6222
6382
|
* destination: { adapter: destAdapter, chain: Chains.Base, address: '0x...' },
|
|
6223
|
-
* amount: '1000000', // 1 USDC
|
|
6383
|
+
* amount: '1000000', // 1 USDC in minor units
|
|
6224
6384
|
* token: 'USDC',
|
|
6225
|
-
* config: {
|
|
6385
|
+
* config: {
|
|
6386
|
+
* transferSpeed: TransferSpeed.FAST,
|
|
6387
|
+
* maxFee: '1000000' // Provider receives values in smallest units
|
|
6388
|
+
* }
|
|
6226
6389
|
* })
|
|
6227
6390
|
* console.log('Max fee:', maxFee)
|
|
6228
6391
|
* ```
|
|
@@ -6253,7 +6416,7 @@ class CCTPV2BridgingProvider extends BridgingProvider {
|
|
|
6253
6416
|
maxFee = baseFee + baseFee / 10n;
|
|
6254
6417
|
}
|
|
6255
6418
|
else {
|
|
6256
|
-
// Use the max fee from the config
|
|
6419
|
+
// Use the max fee from the config (converted to minor units by BridgeKit)
|
|
6257
6420
|
maxFee = BigInt(config.maxFee);
|
|
6258
6421
|
}
|
|
6259
6422
|
return maxFee;
|
|
@@ -6359,4 +6522,5 @@ class CCTPV2BridgingProvider extends BridgingProvider {
|
|
|
6359
6522
|
}
|
|
6360
6523
|
|
|
6361
6524
|
exports.CCTPV2BridgingProvider = CCTPV2BridgingProvider;
|
|
6525
|
+
exports.getMintRecipientAccount = getMintRecipientAccount;
|
|
6362
6526
|
//# sourceMappingURL=index.cjs.js.map
|