@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/index.mjs
CHANGED
|
@@ -48,6 +48,7 @@ var Blockchain;
|
|
|
48
48
|
Blockchain["Algorand_Testnet"] = "Algorand_Testnet";
|
|
49
49
|
Blockchain["Aptos"] = "Aptos";
|
|
50
50
|
Blockchain["Aptos_Testnet"] = "Aptos_Testnet";
|
|
51
|
+
Blockchain["Arc_Testnet"] = "Arc_Testnet";
|
|
51
52
|
Blockchain["Arbitrum"] = "Arbitrum";
|
|
52
53
|
Blockchain["Arbitrum_Sepolia"] = "Arbitrum_Sepolia";
|
|
53
54
|
Blockchain["Avalanche"] = "Avalanche";
|
|
@@ -268,6 +269,48 @@ const BRIDGE_CONTRACT_EVM_TESTNET = '0xC5567a5E3370d4DBfB0540025078e283e36A363d'
|
|
|
268
269
|
*/
|
|
269
270
|
const BRIDGE_CONTRACT_EVM_MAINNET = '0xB3FA262d0fB521cc93bE83d87b322b8A23DAf3F0';
|
|
270
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Arc Testnet chain definition
|
|
274
|
+
* @remarks
|
|
275
|
+
* This represents the test network for the Arc blockchain,
|
|
276
|
+
* Circle's EVM-compatible Layer-1 designed for stablecoin finance
|
|
277
|
+
* and asset tokenization. Arc uses USDC as the native gas token and
|
|
278
|
+
* features the Malachite Byzantine Fault Tolerant (BFT) consensus
|
|
279
|
+
* engine for sub-second finality.
|
|
280
|
+
*/
|
|
281
|
+
const ArcTestnet = defineChain({
|
|
282
|
+
type: 'evm',
|
|
283
|
+
chain: Blockchain.Arc_Testnet,
|
|
284
|
+
name: 'Arc Testnet',
|
|
285
|
+
title: 'ArcTestnet',
|
|
286
|
+
nativeCurrency: {
|
|
287
|
+
name: 'Arc',
|
|
288
|
+
symbol: 'Arc',
|
|
289
|
+
decimals: 18,
|
|
290
|
+
},
|
|
291
|
+
chainId: 5042002,
|
|
292
|
+
isTestnet: true,
|
|
293
|
+
explorerUrl: 'https://testnet.arcscan.app/tx/{hash}',
|
|
294
|
+
rpcEndpoints: ['https://rpc.testnet.arc.network/'],
|
|
295
|
+
eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
296
|
+
usdcAddress: '0x3600000000000000000000000000000000000000',
|
|
297
|
+
cctp: {
|
|
298
|
+
domain: 26,
|
|
299
|
+
contracts: {
|
|
300
|
+
v2: {
|
|
301
|
+
type: 'split',
|
|
302
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
303
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
304
|
+
confirmations: 1,
|
|
305
|
+
fastConfirmations: 1,
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
kitContracts: {
|
|
310
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET,
|
|
311
|
+
},
|
|
312
|
+
});
|
|
313
|
+
|
|
271
314
|
/**
|
|
272
315
|
* Arbitrum Mainnet chain definition
|
|
273
316
|
* @remarks
|
|
@@ -1559,26 +1602,26 @@ const Sonic = defineChain({
|
|
|
1559
1602
|
});
|
|
1560
1603
|
|
|
1561
1604
|
/**
|
|
1562
|
-
* Sonic
|
|
1605
|
+
* Sonic Testnet chain definition
|
|
1563
1606
|
* @remarks
|
|
1564
1607
|
* This represents the official test network for the Sonic blockchain.
|
|
1565
1608
|
*/
|
|
1566
1609
|
const SonicTestnet = defineChain({
|
|
1567
1610
|
type: 'evm',
|
|
1568
1611
|
chain: Blockchain.Sonic_Testnet,
|
|
1569
|
-
name: 'Sonic
|
|
1570
|
-
title: 'Sonic
|
|
1612
|
+
name: 'Sonic Testnet',
|
|
1613
|
+
title: 'Sonic Testnet',
|
|
1571
1614
|
nativeCurrency: {
|
|
1572
1615
|
name: 'Sonic',
|
|
1573
1616
|
symbol: 'S',
|
|
1574
1617
|
decimals: 18,
|
|
1575
1618
|
},
|
|
1576
|
-
chainId:
|
|
1619
|
+
chainId: 14601,
|
|
1577
1620
|
isTestnet: true,
|
|
1578
1621
|
explorerUrl: 'https://testnet.sonicscan.org/tx/{hash}',
|
|
1579
|
-
rpcEndpoints: ['https://rpc.
|
|
1622
|
+
rpcEndpoints: ['https://rpc.testnet.soniclabs.com'],
|
|
1580
1623
|
eurcAddress: null,
|
|
1581
|
-
usdcAddress: '
|
|
1624
|
+
usdcAddress: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
1582
1625
|
cctp: {
|
|
1583
1626
|
domain: 13,
|
|
1584
1627
|
contracts: {
|
|
@@ -2095,6 +2138,7 @@ var Chains = /*#__PURE__*/Object.freeze({
|
|
|
2095
2138
|
AptosTestnet: AptosTestnet,
|
|
2096
2139
|
Arbitrum: Arbitrum,
|
|
2097
2140
|
ArbitrumSepolia: ArbitrumSepolia,
|
|
2141
|
+
ArcTestnet: ArcTestnet,
|
|
2098
2142
|
Avalanche: Avalanche,
|
|
2099
2143
|
AvalancheFuji: AvalancheFuji,
|
|
2100
2144
|
Base: Base,
|
|
@@ -2569,69 +2613,133 @@ class BridgingProvider {
|
|
|
2569
2613
|
}
|
|
2570
2614
|
|
|
2571
2615
|
/**
|
|
2572
|
-
*
|
|
2573
|
-
*
|
|
2574
|
-
* The user agent string is formatted as:
|
|
2575
|
-
* name/version (platform)
|
|
2576
|
-
*
|
|
2577
|
-
* - name: The SDK or kit name, set at runtime.
|
|
2578
|
-
* - version: The SDK version, set at runtime.
|
|
2579
|
-
* - platform: The runtime environment, e.g., "node/nodeVersion" or "browser/browserName".
|
|
2616
|
+
* Detect the runtime environment and return a shortened identifier.
|
|
2580
2617
|
*
|
|
2581
|
-
* @
|
|
2582
|
-
* The kit should call setKitIdentifier(name, version) once at startup.
|
|
2583
|
-
* A custom user agent will be automatically added to all HTTP requests made by the SDK.
|
|
2584
|
-
* This user agent includes the kit name, version, and platform information to help with
|
|
2585
|
-
* debugging and analytics.
|
|
2586
|
-
*
|
|
2587
|
-
* @example
|
|
2588
|
-
* ```typescript
|
|
2589
|
-
* setKitIdentifier('bridge-kit', '1.2.3')
|
|
2590
|
-
* getUserAgent() // "bridge-kit/1.2.3 (node/18.16.0)"
|
|
2591
|
-
* ```
|
|
2592
|
-
*
|
|
2593
|
-
* @returns The Stablecoin Kits SDK user agent string.
|
|
2618
|
+
* @returns Runtime string, e.g., "node/18", "browser/Chrome", or "unknown"
|
|
2594
2619
|
*/
|
|
2595
|
-
|
|
2596
|
-
|
|
2620
|
+
const getRuntime = () => {
|
|
2621
|
+
// Node.js environment
|
|
2597
2622
|
if (typeof process !== 'undefined' &&
|
|
2598
2623
|
typeof process.versions === 'object' &&
|
|
2599
2624
|
typeof process.versions.node === 'string') {
|
|
2600
|
-
|
|
2625
|
+
// Shorten to major version only
|
|
2626
|
+
const majorVersion = process.versions.node.split('.')[0] ?? 'unknown';
|
|
2627
|
+
return `node/${majorVersion}`;
|
|
2601
2628
|
}
|
|
2602
|
-
//
|
|
2629
|
+
// Browser environment
|
|
2603
2630
|
if (typeof window !== 'undefined' && typeof navigator !== 'undefined') {
|
|
2604
2631
|
const userAgent = navigator.userAgent;
|
|
2605
2632
|
const browserMatchers = {
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
'browser/Opera': (ua) => ua.includes('Opera') || ua.includes('OPR'),
|
|
2612
|
-
'browser/Brave': (ua) => ua.includes('Brave'),
|
|
2633
|
+
Edge: (ua) => ua.includes('Edg'),
|
|
2634
|
+
Chrome: (ua) => ua.includes('Chrome') && !ua.includes('Edg'),
|
|
2635
|
+
Firefox: (ua) => ua.includes('Firefox'),
|
|
2636
|
+
Safari: (ua) => ua.includes('Safari') && !ua.includes('Chrome'),
|
|
2637
|
+
Opera: (ua) => ua.includes('Opera') || ua.includes('OPR'),
|
|
2613
2638
|
};
|
|
2614
2639
|
for (const [browserName, matcher] of Object.entries(browserMatchers)) {
|
|
2615
2640
|
if (matcher(userAgent))
|
|
2616
|
-
return browserName
|
|
2641
|
+
return `browser/${browserName}`;
|
|
2617
2642
|
}
|
|
2618
2643
|
return 'browser/unknown';
|
|
2619
2644
|
}
|
|
2620
2645
|
return 'unknown';
|
|
2621
|
-
}
|
|
2646
|
+
};
|
|
2622
2647
|
/**
|
|
2623
|
-
*
|
|
2648
|
+
* Shorten package names by removing common prefixes.
|
|
2624
2649
|
*
|
|
2625
|
-
* @
|
|
2650
|
+
* @param fullName - Full package name, e.g., "\@circle-fin/bridge-kit"
|
|
2651
|
+
* @returns Shortened name, e.g., "bridge-kit"
|
|
2626
2652
|
*/
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2653
|
+
const shortenPackageName = (fullName) => {
|
|
2654
|
+
return fullName.replace('@circle-fin/', '');
|
|
2655
|
+
};
|
|
2656
|
+
/**
|
|
2657
|
+
* Format a component (name/version) with length optimizations.
|
|
2658
|
+
*
|
|
2659
|
+
* @param nameWithVersion - Component identifier, e.g., "\@circle-fin/bridge-kit/1.2.3"
|
|
2660
|
+
* @returns Formatted component, e.g., "bridge-kit/1.2"
|
|
2661
|
+
*/
|
|
2662
|
+
const formatComponent = (nameWithVersion) => {
|
|
2663
|
+
// Find the last / to split name and version
|
|
2664
|
+
// This handles scoped packages like @circle-fin/bridge-kit/1.0.0 correctly
|
|
2665
|
+
const lastSlashIndex = nameWithVersion.lastIndexOf('/');
|
|
2666
|
+
if (lastSlashIndex === -1) {
|
|
2667
|
+
// No version, just a name
|
|
2668
|
+
return shortenPackageName(nameWithVersion);
|
|
2669
|
+
}
|
|
2670
|
+
const name = nameWithVersion.substring(0, lastSlashIndex);
|
|
2671
|
+
const version = nameWithVersion.substring(lastSlashIndex + 1);
|
|
2672
|
+
if (name === '')
|
|
2673
|
+
return '';
|
|
2674
|
+
if (version === '')
|
|
2675
|
+
return shortenPackageName(name);
|
|
2676
|
+
return `${shortenPackageName(name)}/${version}`;
|
|
2677
|
+
};
|
|
2678
|
+
/**
|
|
2679
|
+
* Create a new request context from global state.
|
|
2680
|
+
*
|
|
2681
|
+
* Reads the current external prefix and kit identifier from globalThis.
|
|
2682
|
+
* This is used internally by HTTP utilities.
|
|
2683
|
+
*
|
|
2684
|
+
* @returns A new request context
|
|
2685
|
+
* @internal
|
|
2686
|
+
*/
|
|
2687
|
+
const createRequestContext = () => {
|
|
2688
|
+
const context = {};
|
|
2689
|
+
if (typeof globalThis !== 'undefined') {
|
|
2690
|
+
if (globalThis.__STABLECOIN_KITS_EXTERNAL_PREFIX__ !== undefined) {
|
|
2691
|
+
context.externalPrefix = globalThis.__STABLECOIN_KITS_EXTERNAL_PREFIX__;
|
|
2692
|
+
}
|
|
2693
|
+
if (globalThis.__STABLECOIN_KITS_CURRENT_KIT__ !== undefined) {
|
|
2694
|
+
context.kit = globalThis.__STABLECOIN_KITS_CURRENT_KIT__;
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
return context;
|
|
2698
|
+
};
|
|
2699
|
+
/**
|
|
2700
|
+
* Build a user agent string from a request context.
|
|
2701
|
+
*
|
|
2702
|
+
* Formats the context into a user agent string with automatic optimizations
|
|
2703
|
+
* (shortened package names and truncated versions). The current implementation
|
|
2704
|
+
* tracks a single kit globally.
|
|
2705
|
+
*
|
|
2706
|
+
* Format: `[external-prefix] kit (runtime)`
|
|
2707
|
+
*
|
|
2708
|
+
* @param context - Request context or undefined to use the global context
|
|
2709
|
+
* @returns Formatted user agent string
|
|
2710
|
+
*
|
|
2711
|
+
* @example
|
|
2712
|
+
* ```typescript
|
|
2713
|
+
* // With application prefix and kit
|
|
2714
|
+
* const ua = getUserAgent(context)
|
|
2715
|
+
* // → "my-app/1.0 bridge-kit/1.2 (node/18)"
|
|
2716
|
+
*
|
|
2717
|
+
* // Kit only (no application prefix set)
|
|
2718
|
+
* const ua = getUserAgent()
|
|
2719
|
+
* // → "bridge-kit/1.2 (node/18)"
|
|
2720
|
+
* ```
|
|
2721
|
+
*/
|
|
2722
|
+
const getUserAgent = (context) => {
|
|
2723
|
+
const ctx = createRequestContext();
|
|
2724
|
+
const runtime = getRuntime();
|
|
2725
|
+
// Build user agent string
|
|
2726
|
+
const parts = [];
|
|
2727
|
+
// Add external prefix if set
|
|
2728
|
+
if (ctx.externalPrefix !== undefined) {
|
|
2729
|
+
const formatted = formatComponent(ctx.externalPrefix);
|
|
2730
|
+
if (formatted)
|
|
2731
|
+
parts.push(formatted);
|
|
2732
|
+
}
|
|
2733
|
+
// Add kit if set
|
|
2734
|
+
if (ctx.kit !== undefined) {
|
|
2735
|
+
const formatted = formatComponent(ctx.kit);
|
|
2736
|
+
if (formatted)
|
|
2737
|
+
parts.push(formatted);
|
|
2738
|
+
}
|
|
2739
|
+
// Add runtime
|
|
2740
|
+
parts.push(`(${runtime})`);
|
|
2741
|
+
return parts.join(' ');
|
|
2742
|
+
};
|
|
2635
2743
|
|
|
2636
2744
|
/**
|
|
2637
2745
|
* Default configuration values for the API polling utility.
|
|
@@ -3580,9 +3688,9 @@ const customFeeSchema = z
|
|
|
3580
3688
|
* token: 'USDC',
|
|
3581
3689
|
* config: {
|
|
3582
3690
|
* transferSpeed: 'FAST',
|
|
3583
|
-
* maxFee: '
|
|
3691
|
+
* maxFee: '1.5', // Decimal format
|
|
3584
3692
|
* customFee: {
|
|
3585
|
-
* value: '
|
|
3693
|
+
* value: '0.5', // Decimal format
|
|
3586
3694
|
* recipientAddress: '0x1234567890123456789012345678901234567890'
|
|
3587
3695
|
* }
|
|
3588
3696
|
* }
|
|
@@ -3609,7 +3717,12 @@ const bridgeParamsSchema = z.object({
|
|
|
3609
3717
|
transferSpeed: z.nativeEnum(TransferSpeed).optional(),
|
|
3610
3718
|
maxFee: z
|
|
3611
3719
|
.string()
|
|
3612
|
-
.
|
|
3720
|
+
.pipe(createDecimalStringValidator({
|
|
3721
|
+
allowZero: true,
|
|
3722
|
+
regexMessage: 'maxFee must be a numeric string with optional decimal places (e.g., "1", "0.5", "1.5")',
|
|
3723
|
+
attributeName: 'maxFee',
|
|
3724
|
+
maxDecimals: 6,
|
|
3725
|
+
})(z.string()))
|
|
3613
3726
|
.optional(),
|
|
3614
3727
|
customFee: customFeeSchema.optional(),
|
|
3615
3728
|
}),
|
|
@@ -3766,8 +3879,8 @@ const CCTPv2MinFinalityThreshold = {
|
|
|
3766
3879
|
*/
|
|
3767
3880
|
const DEFAULT_CONFIG = {
|
|
3768
3881
|
timeout: 2_000, // 2 seconds
|
|
3769
|
-
maxRetries: 30 * 20, // 2 seconds
|
|
3770
|
-
retryDelay:
|
|
3882
|
+
maxRetries: 30 * 20, // 30 * 20 * 2 seconds (from the retry delay) = 20 minutes (to account for slow transfers maximum time based on confirmations)
|
|
3883
|
+
retryDelay: 2_000, // 2 seconds
|
|
3771
3884
|
headers: {
|
|
3772
3885
|
'Content-Type': 'application/json',
|
|
3773
3886
|
},
|
|
@@ -4199,6 +4312,10 @@ class KitError extends Error {
|
|
|
4199
4312
|
}
|
|
4200
4313
|
}
|
|
4201
4314
|
|
|
4315
|
+
/**
|
|
4316
|
+
* Minimum error code for INPUT type errors.
|
|
4317
|
+
* INPUT errors represent validation failures and invalid parameters.
|
|
4318
|
+
*/
|
|
4202
4319
|
/**
|
|
4203
4320
|
* Standardized error definitions for INPUT type errors.
|
|
4204
4321
|
*
|
|
@@ -4684,8 +4801,6 @@ async function bridgeApproval({ params, provider, }) {
|
|
|
4684
4801
|
adapter: params.source.adapter,
|
|
4685
4802
|
chain: params.source.chain,
|
|
4686
4803
|
request: await provider.approve(params.source, approvalAmount),
|
|
4687
|
-
// We need to wait for the approval to be confirmed on chain before the transfer can be executed
|
|
4688
|
-
confirmations: 2,
|
|
4689
4804
|
});
|
|
4690
4805
|
}
|
|
4691
4806
|
|
|
@@ -4699,8 +4814,8 @@ async function bridgeApproval({ params, provider, }) {
|
|
|
4699
4814
|
* @param params - The bridge parameters containing source, destination, amount and optional config
|
|
4700
4815
|
* @param sourceChain - The source chain definition where the burn will occur
|
|
4701
4816
|
* @returns Promise resolving to the bridge step with transaction details
|
|
4702
|
-
* @throws {ValidationError} If the parameters are invalid
|
|
4703
|
-
* @throws {BridgeError} If the burn transaction fails
|
|
4817
|
+
* @throws \{ValidationError\} If the parameters are invalid
|
|
4818
|
+
* @throws \{BridgeError\} If the burn transaction fails
|
|
4704
4819
|
*
|
|
4705
4820
|
* @example
|
|
4706
4821
|
* ```typescript
|
|
@@ -4709,16 +4824,11 @@ async function bridgeApproval({ params, provider, }) {
|
|
|
4709
4824
|
* ```
|
|
4710
4825
|
*/
|
|
4711
4826
|
async function bridgeBurn({ params, provider, }) {
|
|
4712
|
-
const transferSpeed = params.config?.transferSpeed ?? TransferSpeed.FAST;
|
|
4713
4827
|
return await executePreparedChainRequest({
|
|
4714
4828
|
name: 'burn',
|
|
4715
4829
|
adapter: params.source.adapter,
|
|
4716
4830
|
chain: params.source.chain,
|
|
4717
4831
|
request: await provider.burn(params),
|
|
4718
|
-
confirmations: transferSpeed === TransferSpeed.FAST
|
|
4719
|
-
? params.source.chain.cctp.contracts.v2.fastConfirmations
|
|
4720
|
-
: params.source.chain.cctp.contracts.v2.confirmations,
|
|
4721
|
-
timeout: transferSpeed === TransferSpeed.FAST ? undefined : 1_200_000, // 20 minutes (max timeout for cctpv2 slow transfers)
|
|
4722
4832
|
});
|
|
4723
4833
|
}
|
|
4724
4834
|
|
|
@@ -4730,16 +4840,18 @@ async function bridgeBurn({ params, provider, }) {
|
|
|
4730
4840
|
* and authorizes the minting of equivalent tokens.
|
|
4731
4841
|
*
|
|
4732
4842
|
* @param params - The bridge parameters containing source, destination, amount and optional config
|
|
4733
|
-
* @param
|
|
4734
|
-
* @
|
|
4735
|
-
* @
|
|
4736
|
-
* @throws {
|
|
4737
|
-
* @throws {BridgeError} If the attestation fetch fails
|
|
4843
|
+
* @param txHash - The hash of the burn transaction
|
|
4844
|
+
* @returns Promise resolving to the bridge step with attestation data
|
|
4845
|
+
* @throws \{ValidationError\} If the parameters are invalid
|
|
4846
|
+
* @throws \{BridgeError\} If the attestation fetch fails
|
|
4738
4847
|
*
|
|
4739
4848
|
* @example
|
|
4740
4849
|
* ```typescript
|
|
4741
|
-
* const attestationStep = await
|
|
4742
|
-
*
|
|
4850
|
+
* const attestationStep = await bridgeFetchAttestation(
|
|
4851
|
+
* { params, provider },
|
|
4852
|
+
* burnTxHash
|
|
4853
|
+
* )
|
|
4854
|
+
* console.log('Attestation data:', attestationStep.data)
|
|
4743
4855
|
* ```
|
|
4744
4856
|
*/
|
|
4745
4857
|
async function bridgeFetchAttestation({ params, provider, }, txHash) {
|
|
@@ -4748,7 +4860,17 @@ async function bridgeFetchAttestation({ params, provider, }, txHash) {
|
|
|
4748
4860
|
state: 'pending',
|
|
4749
4861
|
};
|
|
4750
4862
|
try {
|
|
4751
|
-
|
|
4863
|
+
/**
|
|
4864
|
+
* Give slow transfers a longer retry delay of 30 seconds to account for the longer time it takes to get the
|
|
4865
|
+
* attestation so that we do not hit the rate limit of the IRIS API or the retry limit of the API polling utility.
|
|
4866
|
+
* We only do this for slow transfers on source chains that have greater than 20 confirmations (5 minutes of blocktime
|
|
4867
|
+
* on the slowest blocktime chains) so that we do not slow down the attestation polling for lower confirmation chains.
|
|
4868
|
+
*/
|
|
4869
|
+
const apiPollingConfig = params.config?.transferSpeed === TransferSpeed.SLOW &&
|
|
4870
|
+
params.source.chain.cctp.contracts.v2.confirmations > 20
|
|
4871
|
+
? { retryDelay: 30_000 }
|
|
4872
|
+
: undefined;
|
|
4873
|
+
const attestation = await provider.fetchAttestation(params.source, txHash, apiPollingConfig);
|
|
4752
4874
|
step = {
|
|
4753
4875
|
...step,
|
|
4754
4876
|
state: 'success',
|
|
@@ -4756,10 +4878,18 @@ async function bridgeFetchAttestation({ params, provider, }, txHash) {
|
|
|
4756
4878
|
};
|
|
4757
4879
|
}
|
|
4758
4880
|
catch (err) {
|
|
4881
|
+
let errorMessage = 'Unknown attestation error';
|
|
4882
|
+
if (err instanceof Error) {
|
|
4883
|
+
errorMessage = err.message;
|
|
4884
|
+
}
|
|
4885
|
+
else if (typeof err === 'string') {
|
|
4886
|
+
errorMessage = err;
|
|
4887
|
+
}
|
|
4759
4888
|
step = {
|
|
4760
4889
|
...step,
|
|
4761
4890
|
state: 'error',
|
|
4762
4891
|
error: err,
|
|
4892
|
+
errorMessage,
|
|
4763
4893
|
data: undefined,
|
|
4764
4894
|
};
|
|
4765
4895
|
}
|
|
@@ -4795,8 +4925,6 @@ async function bridgeMint({ params, provider, }, attestation) {
|
|
|
4795
4925
|
adapter: params.destination.adapter,
|
|
4796
4926
|
chain: params.destination.chain,
|
|
4797
4927
|
request: await provider.mint(params.source, params.destination, attestation),
|
|
4798
|
-
// We will wait for the mint to be confirmed on chain before we will return is as success
|
|
4799
|
-
confirmations: 2,
|
|
4800
4928
|
});
|
|
4801
4929
|
}
|
|
4802
4930
|
|
|
@@ -4882,6 +5010,56 @@ function handleStepError(stepName, error, result) {
|
|
|
4882
5010
|
});
|
|
4883
5011
|
}
|
|
4884
5012
|
|
|
5013
|
+
/**
|
|
5014
|
+
* Dispatch a bridge step event through the provider's action dispatcher.
|
|
5015
|
+
*
|
|
5016
|
+
* Constructs the appropriate action payload and dispatches it to any registered
|
|
5017
|
+
* event listeners. Handles type-safe dispatching for different step types.
|
|
5018
|
+
*
|
|
5019
|
+
* @param name - The step name (approve, burn, fetchAttestation, or mint).
|
|
5020
|
+
* @param step - The completed bridge step containing transaction details and explorerUrl.
|
|
5021
|
+
* @param provider - The CCTP v2 provider with action dispatcher.
|
|
5022
|
+
*
|
|
5023
|
+
* @example
|
|
5024
|
+
* ```typescript
|
|
5025
|
+
* const step: BridgeStep = {
|
|
5026
|
+
* name: 'burn',
|
|
5027
|
+
* state: 'success',
|
|
5028
|
+
* txHash: '0xabc...',
|
|
5029
|
+
* explorerUrl: 'https://sepolia.etherscan.io/tx/0xabc...',
|
|
5030
|
+
* data: { ... }
|
|
5031
|
+
* }
|
|
5032
|
+
* dispatchStepEvent('burn', step, provider)
|
|
5033
|
+
* ```
|
|
5034
|
+
*/
|
|
5035
|
+
function dispatchStepEvent(name, step, provider) {
|
|
5036
|
+
if (!provider.actionDispatcher) {
|
|
5037
|
+
return;
|
|
5038
|
+
}
|
|
5039
|
+
const actionValues = {
|
|
5040
|
+
protocol: 'cctp',
|
|
5041
|
+
version: 'v2',
|
|
5042
|
+
values: step,
|
|
5043
|
+
};
|
|
5044
|
+
switch (name) {
|
|
5045
|
+
case 'approve':
|
|
5046
|
+
case 'burn':
|
|
5047
|
+
case 'mint':
|
|
5048
|
+
provider.actionDispatcher.dispatch(name, {
|
|
5049
|
+
...actionValues,
|
|
5050
|
+
method: name,
|
|
5051
|
+
});
|
|
5052
|
+
break;
|
|
5053
|
+
case 'fetchAttestation':
|
|
5054
|
+
provider.actionDispatcher.dispatch(name, {
|
|
5055
|
+
...actionValues,
|
|
5056
|
+
method: name,
|
|
5057
|
+
values: step,
|
|
5058
|
+
});
|
|
5059
|
+
break;
|
|
5060
|
+
}
|
|
5061
|
+
}
|
|
5062
|
+
|
|
4885
5063
|
/**
|
|
4886
5064
|
* Execute a cross-chain USDC bridge using the CCTP v2 protocol.
|
|
4887
5065
|
*
|
|
@@ -4938,34 +5116,19 @@ async function bridge(params, provider) {
|
|
|
4938
5116
|
try {
|
|
4939
5117
|
const step = await executor(params, provider, context);
|
|
4940
5118
|
if (step.state === 'error') {
|
|
4941
|
-
// Include error details from the step in the thrown error
|
|
4942
|
-
|
|
5119
|
+
// Include error details from the step in the thrown error. Fall back to step.error.
|
|
5120
|
+
let fallbackErrorMessage = 'Unknown error';
|
|
5121
|
+
if (step.error instanceof Error) {
|
|
5122
|
+
fallbackErrorMessage = step.error.message;
|
|
5123
|
+
}
|
|
5124
|
+
else if (typeof step.error === 'string') {
|
|
5125
|
+
fallbackErrorMessage = step.error;
|
|
5126
|
+
}
|
|
5127
|
+
const errorDetails = step.errorMessage ?? fallbackErrorMessage;
|
|
4943
5128
|
throw new Error(`${name} step failed: ${errorDetails}`);
|
|
4944
5129
|
}
|
|
4945
5130
|
context = updateContext?.(step);
|
|
4946
|
-
|
|
4947
|
-
protocol: 'cctp',
|
|
4948
|
-
version: 'v2',
|
|
4949
|
-
values: step,
|
|
4950
|
-
};
|
|
4951
|
-
// use a switch statement for type safety to separate the different step types
|
|
4952
|
-
switch (name) {
|
|
4953
|
-
case 'approve':
|
|
4954
|
-
case 'burn':
|
|
4955
|
-
case 'mint':
|
|
4956
|
-
provider.actionDispatcher?.dispatch(name, {
|
|
4957
|
-
...actionValues,
|
|
4958
|
-
method: name,
|
|
4959
|
-
});
|
|
4960
|
-
break;
|
|
4961
|
-
case 'fetchAttestation':
|
|
4962
|
-
provider.actionDispatcher?.dispatch(name, {
|
|
4963
|
-
...actionValues,
|
|
4964
|
-
method: name,
|
|
4965
|
-
values: step,
|
|
4966
|
-
});
|
|
4967
|
-
break;
|
|
4968
|
-
}
|
|
5131
|
+
dispatchStepEvent(name, step, provider);
|
|
4969
5132
|
result.steps.push(step);
|
|
4970
5133
|
}
|
|
4971
5134
|
catch (error) {
|
|
@@ -5632,12 +5795,7 @@ async function retry(result, context, provider) {
|
|
|
5632
5795
|
throw new Error(errorMessage);
|
|
5633
5796
|
}
|
|
5634
5797
|
stepContext = updateContext?.(step);
|
|
5635
|
-
|
|
5636
|
-
protocol: 'cctp',
|
|
5637
|
-
version: 'v2',
|
|
5638
|
-
method: name,
|
|
5639
|
-
values: step.data,
|
|
5640
|
-
});
|
|
5798
|
+
dispatchStepEvent(name, step, provider);
|
|
5641
5799
|
result.steps.push(step);
|
|
5642
5800
|
}
|
|
5643
5801
|
catch (error) {
|
|
@@ -6206,7 +6364,9 @@ class CCTPV2BridgingProvider extends BridgingProvider {
|
|
|
6206
6364
|
* - `source`: The source wallet context with chain definition and adapter
|
|
6207
6365
|
* - `destination`: The destination wallet context with chain definition and adapter
|
|
6208
6366
|
* - `amount`: The bridge amount in minor units (e.g., "1000000" for 1 USDC)
|
|
6209
|
-
* - `config`: Optional bridge configuration including transferSpeed and maxFee settings
|
|
6367
|
+
* - `config`: Optional bridge configuration including transferSpeed and maxFee settings.
|
|
6368
|
+
* When used via BridgeKit, fee values are automatically converted from human-readable
|
|
6369
|
+
* format (e.g., "1") to smallest units (e.g., "1000000").
|
|
6210
6370
|
* @returns The maximum fee to be used for the bridge operation in minor units
|
|
6211
6371
|
*
|
|
6212
6372
|
* @example
|
|
@@ -6214,9 +6374,12 @@ class CCTPV2BridgingProvider extends BridgingProvider {
|
|
|
6214
6374
|
* const maxFee = await provider.getMaxFee({
|
|
6215
6375
|
* source: { adapter: sourceAdapter, chain: Chains.Ethereum, address: '0x...' },
|
|
6216
6376
|
* destination: { adapter: destAdapter, chain: Chains.Base, address: '0x...' },
|
|
6217
|
-
* amount: '1000000', // 1 USDC
|
|
6377
|
+
* amount: '1000000', // 1 USDC in minor units
|
|
6218
6378
|
* token: 'USDC',
|
|
6219
|
-
* config: {
|
|
6379
|
+
* config: {
|
|
6380
|
+
* transferSpeed: TransferSpeed.FAST,
|
|
6381
|
+
* maxFee: '1000000' // Provider receives values in smallest units
|
|
6382
|
+
* }
|
|
6220
6383
|
* })
|
|
6221
6384
|
* console.log('Max fee:', maxFee)
|
|
6222
6385
|
* ```
|
|
@@ -6247,7 +6410,7 @@ class CCTPV2BridgingProvider extends BridgingProvider {
|
|
|
6247
6410
|
maxFee = baseFee + baseFee / 10n;
|
|
6248
6411
|
}
|
|
6249
6412
|
else {
|
|
6250
|
-
// Use the max fee from the config
|
|
6413
|
+
// Use the max fee from the config (converted to minor units by BridgeKit)
|
|
6251
6414
|
maxFee = BigInt(config.maxFee);
|
|
6252
6415
|
}
|
|
6253
6416
|
return maxFee;
|
|
@@ -6352,5 +6515,5 @@ class CCTPV2BridgingProvider extends BridgingProvider {
|
|
|
6352
6515
|
}
|
|
6353
6516
|
}
|
|
6354
6517
|
|
|
6355
|
-
export { CCTPV2BridgingProvider };
|
|
6518
|
+
export { CCTPV2BridgingProvider, getMintRecipientAccount };
|
|
6356
6519
|
//# sourceMappingURL=index.mjs.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@circle-fin/provider-cctp-v2",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Circle's official Cross-Chain Transfer Protocol v2 provider for native USDC bridging",
|
|
4
5
|
"main": "./index.cjs.js",
|
|
5
6
|
"module": "./index.mjs",
|
|
6
7
|
"types": "./index.d.ts",
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
"package.json"
|
|
44
45
|
],
|
|
45
46
|
"publishConfig": {
|
|
47
|
+
"access": "public",
|
|
46
48
|
"directory": "../../dist/providers/cctp.v2"
|
|
47
49
|
}
|
|
48
50
|
}
|