@circle-fin/provider-cctp-v2 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.
Files changed (6) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +93 -9
  3. package/index.cjs +4526 -2150
  4. package/index.d.ts +1590 -222
  5. package/index.mjs +4525 -2151
  6. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -313,7 +313,7 @@ type ChainDefinitionWithCCTPv2 = ChainDefinition & {
313
313
  * - A Blockchain enum value (e.g., Blockchain.Ethereum)
314
314
  * - A string literal of the blockchain value (e.g., "Ethereum")
315
315
  */
316
- type ChainIdentifier = ChainDefinition | Blockchain | `${Blockchain}`;
316
+ type ChainIdentifier$1 = ChainDefinition | Blockchain | `${Blockchain}`;
317
317
  interface CCTPSplitConfig {
318
318
  type: 'split';
319
319
  tokenMessenger: string;
@@ -357,6 +357,22 @@ interface CCTPConfig {
357
357
  * The contracts required for CCTP.
358
358
  */
359
359
  contracts: CCTPContracts;
360
+ /**
361
+ * Indicates whether the chain supports forwarder for source and destination.
362
+ * @example
363
+ * ```typescript
364
+ * const chainWithForwarderSupported: ChainDefinition = {
365
+ * forwarderSupported: {
366
+ * source: true,
367
+ * destination: true,
368
+ * },
369
+ * }
370
+ * ```
371
+ */
372
+ forwarderSupported: {
373
+ source: boolean;
374
+ destination: boolean;
375
+ };
360
376
  }
361
377
  /**
362
378
  * Available kit contract types for enhanced chain functionality.
@@ -913,7 +929,7 @@ type OperationContext<TAdapterCapabilities extends AdapterCapabilities = Adapter
913
929
  /**
914
930
  * The blockchain network to use for this operation.
915
931
  */
916
- chain: ChainIdentifier;
932
+ chain: ChainIdentifier$1;
917
933
  } & AddressField<ExtractAddressContext<TAdapterCapabilities>>;
918
934
  /**
919
935
  * Fully resolved context for an adapter operation, with concrete chain and address.
@@ -1322,6 +1338,99 @@ interface CCTPv2ActionMap {
1322
1338
  */
1323
1339
  permitParams?: PermitParams;
1324
1340
  };
1341
+ /**
1342
+ * Initiate a cross-chain USDC transfer using a custom bridge contract with hook data for CCTP forwarding.
1343
+ *
1344
+ * This action combines the custom bridge functionality with CCTP forwarding hookData.
1345
+ * It uses either `bridgeWithPreapprovalAndHook` or `bridgeWithPermitAndHook` contract
1346
+ * functions depending on whether permit parameters are provided.
1347
+ *
1348
+ * @remarks
1349
+ * When CCTP forwarding is enabled with custom burn, Circle's relay infrastructure will:
1350
+ * 1. Watch for the burn transaction with forwarding hookData
1351
+ * 2. Fetch the attestation automatically
1352
+ * 3. Submit the destination mint transaction on behalf of the user
1353
+ * 4. Deduct the relay fee from the minted USDC
1354
+ *
1355
+ * The hookData must be formatted with the CCTP forwarding magic bytes prefix
1356
+ * followed by version and length fields. Use the `buildForwardingHookData`
1357
+ * utility to construct properly formatted hookData.
1358
+ *
1359
+ * @example
1360
+ * ```typescript
1361
+ * import { buildForwardingHookData } from '@core/utils'
1362
+ * import { hasCustomContractSupport } from '@core/chains'
1363
+ *
1364
+ * if (hasCustomContractSupport(sourceChain, 'bridge')) {
1365
+ * await adapter.action('cctp.v2.customBurnWithHook', {
1366
+ * amount: BigInt('1000000'),
1367
+ * mintRecipient: '0x...',
1368
+ * maxFee: BigInt('50000'),
1369
+ * minFinalityThreshold: 1000,
1370
+ * fromChain: ethereum,
1371
+ * toChain: base,
1372
+ * hookData: buildForwardingHookData()
1373
+ * })
1374
+ * }
1375
+ * ```
1376
+ */
1377
+ customBurnWithHook: CCTPv2ActionMap['customBurn'] & {
1378
+ /**
1379
+ * Hex-encoded hook data for CCTP forwarding.
1380
+ *
1381
+ * The hookData signals to Circle's Orbit relayer that forwarding is requested.
1382
+ * Must be formatted with the CCTP forwarding magic bytes prefix ("cctp-forward"
1383
+ * right-padded to 24 bytes) followed by uint32 version and uint32 length fields.
1384
+ *
1385
+ * Use the `buildForwardingHookData` utility to construct properly formatted hookData.
1386
+ */
1387
+ hookData: string;
1388
+ };
1389
+ /**
1390
+ * Initiate a cross-chain USDC transfer with hook data for CCTP forwarding.
1391
+ *
1392
+ * This action extends the standard `depositForBurn` with an additional `hookData`
1393
+ * parameter that signals to Circle's Orbit relayer that the user wants automated
1394
+ * attestation fetching and destination mint execution.
1395
+ *
1396
+ * @remarks
1397
+ * When CCTP forwarding is enabled, Circle's relay infrastructure will:
1398
+ * 1. Watch for the burn transaction with forwarding hookData
1399
+ * 2. Fetch the attestation automatically
1400
+ * 3. Submit the destination mint transaction on behalf of the user
1401
+ * 4. Deduct the relay fee from the minted USDC
1402
+ *
1403
+ * The hookData must be formatted with the CCTP forwarding magic bytes prefix
1404
+ * followed by version and length fields. Use the `buildForwardingHookData`
1405
+ * utility to construct properly formatted hookData.
1406
+ *
1407
+ * @example
1408
+ * ```typescript
1409
+ * import { buildForwardingHookData } from '@core/utils'
1410
+ *
1411
+ * await adapter.action('cctp.v2.depositForBurnWithHook', {
1412
+ * amount: BigInt('1000000'),
1413
+ * mintRecipient: '0x...',
1414
+ * maxFee: BigInt('50000'), // Must cover burn fee + forwarding fee
1415
+ * minFinalityThreshold: 1000,
1416
+ * fromChain: ethereum,
1417
+ * toChain: base,
1418
+ * hookData: buildForwardingHookData()
1419
+ * })
1420
+ * ```
1421
+ */
1422
+ depositForBurnWithHook: CCTPv2ActionMap['depositForBurn'] & {
1423
+ /**
1424
+ * Hex-encoded hook data for CCTP forwarding.
1425
+ *
1426
+ * The hookData signals to Circle's Orbit relayer that forwarding is requested.
1427
+ * Must be formatted with the CCTP forwarding magic bytes prefix ("cctp-forward"
1428
+ * right-padded to 24 bytes) followed by uint32 version and uint32 length fields.
1429
+ *
1430
+ * Use the `buildForwardingHookData` utility to construct properly formatted hookData.
1431
+ */
1432
+ hookData: string;
1433
+ };
1325
1434
  }
1326
1435
 
1327
1436
  /**
@@ -2441,238 +2550,1328 @@ declare class Actionable<AllActions> {
2441
2550
  }
2442
2551
 
2443
2552
  /**
2444
- * Transfer speed options for cross-chain operations.
2553
+ * Module augmentation to register known token symbols.
2445
2554
  *
2446
- * Defines the available speed modes for CCTPv2 transfers, affecting
2447
- * both transfer time and potential fee implications.
2448
- */
2449
- declare enum TransferSpeed {
2450
- /** Fast burn mode - reduces transfer time but may have different fee implications */
2451
- FAST = "FAST",
2452
- /** Standard burn mode - normal transfer time with standard fees */
2453
- SLOW = "SLOW"
2454
- }
2455
- /**
2456
- * Context object representing a wallet and signing authority on a specific blockchain network.
2555
+ * @remarks
2556
+ * This file augments the `TokenSymbolRegistry` interface to provide
2557
+ * type-safe autocomplete for built-in tokens.
2457
2558
  *
2458
- * Combines a wallet or contract address, the blockchain it resides on, and the adapter (signer)
2459
- * responsible for authorizing transactions. Used to specify the source or destination in cross-chain
2460
- * transfer operations.
2559
+ * When imported, TypeScript will recognize 'USDC' as a valid
2560
+ * `TokenSymbol` value with autocomplete support.
2461
2561
  *
2462
- * @remarks
2463
- * The `adapter` (signer) and `address` do not always have to belong to the same entity. For example,
2464
- * in minting or withdrawal scenarios, the signing adapter may authorize a transaction that credits
2465
- * funds to a different recipient address. This context is essential for cross-chain operations,
2466
- * ensuring that both the address and the associated adapter are correctly paired with the intended
2467
- * blockchain, but not necessarily with each other.
2562
+ * Other packages or applications can create their own augmentations
2563
+ * to add additional tokens.
2468
2564
  *
2469
2565
  * @example
2470
2566
  * ```typescript
2471
- * import type { WalletContext } from '@core/provider'
2472
- * import { adapter, blockchain } from './setup'
2567
+ * import '@core/tokens' // Automatically includes this augmentation
2473
2568
  *
2474
- * const wallet: WalletContext = {
2475
- * adapter,
2476
- * address: '0x1234...abcd',
2477
- * chain: blockchain,
2478
- * }
2569
+ * const symbol: TokenSymbol = 'USDC' // ✓ Autocomplete shows USDC
2479
2570
  * ```
2480
2571
  */
2481
- interface WalletContext<TAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities,
2482
- /**
2483
- * The chain definition type to use for the wallet context.
2484
- *
2485
- * @defaultValue ChainDefinition
2486
- */
2487
- TChainDefinition extends ChainDefinition = ChainDefinition> {
2572
+ declare module './types' {
2488
2573
  /**
2489
- * The adapter (signer) for the wallet on the specified chain.
2490
- *
2491
- * Responsible for authorizing transactions and signing messages on behalf of the wallet or
2492
- * for a different recipient, depending on the use case.
2493
- */
2494
- adapter: Adapter<TAdapterCapabilities>;
2495
- /**
2496
- * The wallet or contract address.
2574
+ * Module augmentation: Adds known token symbols as valid keys
2575
+ * to the TokenSymbolRegistry interface.
2497
2576
  *
2498
- * Must be a valid address format for the specified blockchain. May differ from the adapter's
2499
- * own address in scenarios such as relayed transactions or third-party minting.
2500
- */
2501
- address: string;
2502
- /**
2503
- * The blockchain network where the wallet or contract address resides.
2504
- *
2505
- * Determines the context and format for the address and adapter.
2577
+ * Keys are explicitly listed to ensure IDE autocomplete works properly.
2506
2578
  */
2507
- chain: TChainDefinition;
2579
+ interface TokenSymbolRegistry {
2580
+ USDC: true;
2581
+ }
2508
2582
  }
2583
+
2509
2584
  /**
2510
- * Wallet context for bridge destinations with optional custom recipient.
2585
+ * Module augmentation to register Blockchain enum values as ChainIdentifiers.
2511
2586
  *
2512
- * Extends WalletContext to support scenarios where the recipient address
2513
- * differs from the signer address (e.g., bridging to a third-party wallet).
2514
- * The signer address is used for transaction authorization, while the
2515
- * recipient address specifies where the minted funds should be sent.
2587
+ * @remarks
2588
+ * This file augments the `ChainRegistry` interface to provide type-safe
2589
+ * autocomplete for all `Blockchain` enum values from `@core/chains`.
2516
2590
  *
2517
- * @typeParam TAdapterCapabilities - The adapter capabilities type to use for the wallet context.
2518
- * @typeParam TChainDefinition - The chain definition type to use for the wallet context.
2591
+ * When this augmentation is imported (via `@core/tokens`), TypeScript will
2592
+ * recognize all blockchain identifiers as valid `ChainIdentifier` values
2593
+ * with IDE autocomplete support.
2594
+ *
2595
+ * The `Blockchain` enum values are converted to their string representations,
2596
+ * enabling both enum values and string literals to be accepted as chain identifiers.
2519
2597
  *
2520
2598
  * @example
2521
2599
  * ```typescript
2522
- * import type { DestinationWalletContext } from '@core/provider'
2523
- * import { adapter, blockchain } from './setup'
2600
+ * import { Blockchain } from '@core/chains'
2601
+ * import type { ChainIdentifier } from '@core/tokens'
2524
2602
  *
2525
- * // Bridge to a custom recipient address
2526
- * const destination: DestinationWalletContext = {
2527
- * adapter,
2528
- * address: '0x1234...abcd', // Signer address
2529
- * chain: blockchain,
2530
- * recipientAddress: '0x9876...fedc' // Custom recipient
2531
- * }
2532
- * ```
2533
- */
2534
- interface DestinationWalletContext<TAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities,
2535
- /**
2536
- * The chain definition type to use for the wallet context.
2603
+ * // Using enum value
2604
+ * const chain1: ChainIdentifier = Blockchain.Ethereum
2537
2605
  *
2538
- * @defaultValue ChainDefinition
2606
+ * // Using string literal (with autocomplete!)
2607
+ * const chain2: ChainIdentifier = 'Base'
2608
+ *
2609
+ * // Arbitrary strings also work (escape hatch for custom chains)
2610
+ * const chain3: ChainIdentifier = 'my-custom-chain'
2611
+ * ```
2539
2612
  */
2540
- TChainDefinition extends ChainDefinition = ChainDefinition> extends WalletContext<TAdapterCapabilities, TChainDefinition> {
2613
+
2614
+ declare module './types' {
2541
2615
  /**
2542
- * Optional custom recipient address for minted funds.
2616
+ * Module augmentation: Adds all Blockchain enum values as valid keys
2617
+ * to the ChainRegistry interface for type-safe chain identifier support.
2543
2618
  *
2544
- * When provided, minted tokens will be sent to this address instead of
2545
- * the address specified in the wallet context. The wallet context address
2546
- * is still used for transaction signing and authorization.
2619
+ * This ensures both enum property access (e.g., Blockchain.Ethereum) and plain
2620
+ * string literals (e.g., 'Ethereum') are accepted by TypeScript as chain keys,
2621
+ * providing robust autocomplete and error checking.
2547
2622
  *
2548
- * Must be a valid address format for the specified blockchain.
2623
+ * NOTE:
2624
+ * - This interface intentionally has no body. It merges a mapped Record type
2625
+ * into ChainRegistry solely for type augmentation.
2626
+ * - This empty-body construct is a necessary TypeScript idiom for module
2627
+ * augmentation with Record types—directly listing mapped keys is not
2628
+ * feasible in interface extensions.
2629
+ *
2630
+ * eslint-disable-next-line directives below suppress linter complaints about
2631
+ * the empty interface/mapping, which are benign and required for this pattern.
2549
2632
  */
2550
- recipientAddress?: string;
2633
+ interface ChainRegistry extends Record<`${Blockchain}`, true> {
2634
+ }
2551
2635
  }
2636
+
2552
2637
  /**
2553
- * Parameters for executing a cross-chain bridge operation.
2638
+ * Creates a union type that preserves IDE autocomplete for known literals
2639
+ * while still accepting any string at runtime.
2640
+ *
2641
+ * @remarks
2642
+ * This pattern uses `Record<never, never>` (an empty record type) to prevent
2643
+ * TypeScript from widening string literals to just `string`. This gives us
2644
+ * the best of both worlds: autocomplete for known values and flexibility
2645
+ * for arbitrary strings.
2646
+ *
2647
+ * @typeParam T - The known string literal union to preserve.
2554
2648
  */
2555
- interface BridgeParams<TFromCapabilities extends AdapterCapabilities = AdapterCapabilities, TToCapabilities extends AdapterCapabilities = AdapterCapabilities,
2649
+ type LiteralUnion<T extends string> = T | (string & Record<never, never>);
2556
2650
  /**
2557
- * The chain definition type to use for the wallet context.
2651
+ * Registry for known chain identifiers (augmentation target).
2558
2652
  *
2559
- * @defaultValue ChainDefinition
2653
+ * @remarks
2654
+ * This empty interface exists solely for module augmentation. Extend it to
2655
+ * register chain identifiers for type-safe token definitions.
2656
+ *
2657
+ * **Why an interface?** TypeScript only allows module augmentation on
2658
+ * interfaces, not type aliases.
2659
+ *
2660
+ * **Note:** This is NOT the EVM "chain ID" (numeric like 1 for Ethereum).
2661
+ * It's a human-readable identifier like "Ethereum", "Solana", "Base".
2662
+ *
2663
+ * **Usage**
2664
+ *
2665
+ * Without augmentation, `ChainIdentifier` defaults to `string`.
2666
+ * With `@core/chains` imported, you get autocomplete for all `Blockchain` values.
2667
+ *
2668
+ * **Custom Chains**
2669
+ *
2670
+ * ```typescript
2671
+ * declare module '@core/tokens' {
2672
+ * interface ChainRegistry {
2673
+ * MyChain: true
2674
+ * MyTestnet: true
2675
+ * }
2676
+ * }
2677
+ * // Now ChainIdentifier includes 'MyChain' | 'MyTestnet' | ...
2678
+ * ```
2679
+ *
2680
+ * The value (`true`) is a placeholder—only the keys matter.
2681
+ *
2682
+ * NOTE: The eslint-disable below suppresses warnings about empty interfaces.
2683
+ * This is intentional—the interface exists solely as an augmentation target.
2560
2684
  */
2561
- TChainDefinition extends ChainDefinition = ChainDefinition> {
2562
- /** The source adapter containing wallet and chain information */
2563
- source: WalletContext<TFromCapabilities, TChainDefinition>;
2564
- /** The destination adapter containing wallet and chain information */
2565
- destination: DestinationWalletContext<TToCapabilities, TChainDefinition>;
2566
- /** The amount to transfer (as a string to avoid precision issues) */
2567
- amount: string;
2568
- /** The token to transfer (currently only USDC is supported) */
2569
- token: 'USDC';
2570
- /** Bridge configuration (e.g., fast burn settings) */
2571
- config: BridgeConfig;
2685
+ interface ChainRegistry {
2572
2686
  }
2573
2687
  /**
2574
- * A step in the bridge process.
2688
+ * Union of all registered chain identifiers.
2575
2689
  *
2576
2690
  * @remarks
2577
- * This interface represents a single step in the bridge process,
2578
- * such as approval, burn, or mint.
2691
+ * Derived from `ChainRegistry` keys:
2692
+ * - Without augmentation: `string`
2693
+ * - With `@core/chains`: `'Ethereum' | 'Solana' | ...` plus any string
2694
+ *
2695
+ * Uses `LiteralUnion` to preserve IDE autocomplete while allowing
2696
+ * arbitrary strings at runtime.
2579
2697
  *
2580
2698
  * @example
2581
2699
  * ```typescript
2582
- * const step: BridgeStep = {
2583
- * name: 'Approve',
2584
- * state: 'success',
2585
- * txHash: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
2586
- * explorerUrl: 'https://etherscan.io/tx/0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
2587
- * }
2700
+ * const chain: ChainIdentifier = 'Ethereum' // Autocomplete works
2701
+ * const custom: ChainIdentifier = 'my-chain' // Also valid
2588
2702
  * ```
2589
2703
  */
2590
- interface BridgeStep {
2591
- /** Human-readable name of the step (e.g., "Approve", "Burn", "Mint") */
2592
- name: string;
2593
- /** The state of the step */
2594
- state: 'pending' | 'success' | 'error' | 'noop';
2595
- /** Optional transaction hash for this step (if applicable) */
2596
- txHash?: string;
2597
- /** Optional explorer URL for viewing this transaction on a block explorer */
2598
- explorerUrl?: string;
2599
- /** Optional data for the step */
2600
- data?: unknown;
2601
- /** Optional human-readable error message */
2602
- errorMessage?: string;
2603
- /** Optional raw error object (can be Viem/Ethers/Chain error) */
2604
- error?: unknown;
2605
- }
2704
+ type ChainIdentifier = keyof ChainRegistry extends never ? string : LiteralUnion<Extract<keyof ChainRegistry, string>>;
2606
2705
  /**
2607
- * Result object returned after a successful cross-chain bridge operation.
2706
+ * Maps chain identifiers to their token locators.
2608
2707
  *
2609
- * This interface contains all the details about a completed bridge, including
2610
- * the bridge parameters, source and destination information,
2611
- * and the sequence of steps that were executed.
2708
+ * @remarks
2709
+ * The key is a chain identifier (type-safe when `KnownChainIdentifiers` is
2710
+ * augmented). This enables a single token definition to work across chains.
2711
+ *
2712
+ * When `@core/chains` is imported, you get autocomplete for known chains
2713
+ * like `Ethereum`, `Base`, `Solana`, etc.
2612
2714
  *
2613
2715
  * @example
2614
2716
  * ```typescript
2615
- * const result: BridgeResult = await provider.bridge(source, dest, '100')
2616
- * console.log(`Transferred ${result.amount} ${result.token}`)
2617
- * console.log(`Steps executed: ${result.steps.length}`)
2717
+ * import { Blockchain } from '@core/chains'
2718
+ *
2719
+ * const usdcLocators: ChainLocatorMap = {
2720
+ * [Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
2721
+ * [Blockchain.Solana]: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
2722
+ * [Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
2723
+ * }
2724
+ *
2725
+ * // Or with string keys (always works)
2726
+ * const locators: ChainLocatorMap = {
2727
+ * 'ethereum': '0xa0b86991...',
2728
+ * 'my-custom-chain': '0x1234...',
2729
+ * }
2618
2730
  * ```
2619
2731
  */
2620
- interface BridgeResult {
2621
- /** The amount that was transferred (as a string to avoid precision issues) */
2622
- amount: string;
2623
- /** The token that was transferred (currently only USDC is supported) */
2624
- token: 'USDC';
2625
- /** The state of the transfer */
2626
- state: 'pending' | 'success' | 'error';
2627
- /** The bridge configuration that was used for this operation */
2628
- config?: BridgeConfig;
2629
- /** The provider that was used for this operation */
2630
- provider: string;
2631
- /** Information about the source chain and address */
2632
- source: {
2633
- /** The source wallet/contract address */
2634
- address: string;
2635
- /** The source blockchain network */
2636
- chain: ChainDefinition;
2637
- };
2638
- /** Information about the destination chain and address */
2639
- destination: {
2640
- /** The destination wallet/contract address */
2641
- address: string;
2642
- /** The destination blockchain network */
2643
- chain: ChainDefinition;
2644
- /**
2645
- * Optional custom recipient address for minted funds.
2646
- *
2647
- * When provided during the bridge operation, minted tokens are sent to this
2648
- * address instead of the destination address. This field is preserved in the
2649
- * result for retry operations to maintain consistency with the original burn.
2650
- */
2651
- recipientAddress?: string;
2652
- };
2653
- /** Array of steps that were executed during the bridge process */
2654
- steps: BridgeStep[];
2655
- }
2732
+ type ChainLocatorMap = Record<ChainIdentifier, string>;
2656
2733
  /**
2657
- * Cost estimation result for a cross-chain transfer operation.
2734
+ * Complete definition of a token including metadata and chain locators.
2658
2735
  *
2659
- * This interface provides detailed information about the expected costs
2660
- * for a transfer, including gas fees on different chains and protocol fees.
2661
- * It also includes the input context (token, amount, source, destination) to
2662
- * provide a complete view of the transfer being estimated.
2736
+ * @remarks
2737
+ * This is the canonical representation of a token in the registry.
2738
+ * It includes the symbol, decimals, and chain-specific locators.
2663
2739
  *
2664
2740
  * @example
2665
2741
  * ```typescript
2666
- * const estimate: EstimateResult = await provider.estimate(source, dest, '100')
2667
- * console.log('Estimating transfer of', estimate.amount, estimate.token)
2668
- * console.log('From', estimate.source.chain.name, 'to', estimate.destination.chain.name)
2669
- * console.log('Total gas fees:', estimate.gasFees.length)
2670
- * console.log('Protocol fees:', estimate.fees.length)
2742
+ * const usdc: TokenDefinition = {
2743
+ * symbol: 'USDC',
2744
+ * decimals: 6,
2745
+ * locators: {
2746
+ * [Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
2747
+ * [Blockchain.Solana]: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
2748
+ * },
2749
+ * }
2671
2750
  * ```
2672
2751
  */
2673
- interface EstimateResult {
2674
- /** The token being transferred */
2675
- token: 'USDC';
2752
+ interface TokenDefinition {
2753
+ /**
2754
+ * The token symbol (e.g., "USDC", "EURC").
2755
+ */
2756
+ readonly symbol: string;
2757
+ /**
2758
+ * The number of decimal places for the token.
2759
+ * @example 6 for USDC, 18 for most ERC20 tokens
2760
+ */
2761
+ readonly decimals: number;
2762
+ /**
2763
+ * Chain-specific locators for the token.
2764
+ * Keys are chain identifiers, values are the token address/locator on that chain.
2765
+ * Not all chains need to be present - tokens may only exist on a subset of chains.
2766
+ */
2767
+ readonly locators: Partial<ChainLocatorMap>;
2768
+ }
2769
+ /**
2770
+ * A raw token locator selector with explicit decimals.
2771
+ *
2772
+ * @remarks
2773
+ * Use this form when working with arbitrary tokens not in the registry.
2774
+ * The `locator` is the chain-specific address, and `decimals` is required
2775
+ * unless using lenient mode.
2776
+ *
2777
+ * @example
2778
+ * ```typescript
2779
+ * // Selecting a custom token by address
2780
+ * const selector: RawTokenSelector = {
2781
+ * locator: '0x1234567890abcdef1234567890abcdef12345678',
2782
+ * decimals: 18,
2783
+ * }
2784
+ * ```
2785
+ */
2786
+ interface RawTokenSelector {
2787
+ /**
2788
+ * The chain-specific token locator (address, program ID, etc.).
2789
+ */
2790
+ readonly locator: string;
2791
+ /**
2792
+ * The number of decimal places.
2793
+ * Required in strict mode, optional in lenient mode.
2794
+ */
2795
+ readonly decimals?: number;
2796
+ }
2797
+ /**
2798
+ * Registry for known token symbols (augmentation target).
2799
+ *
2800
+ * @remarks
2801
+ * This empty interface exists solely for module augmentation. Extend it to
2802
+ * register token symbols for type-safe selection.
2803
+ *
2804
+ * **Why an interface?** TypeScript only allows module augmentation on
2805
+ * interfaces, not type aliases.
2806
+ *
2807
+ * **Usage**
2808
+ *
2809
+ * Without augmentation, `TokenSymbol` defaults to `string`.
2810
+ *
2811
+ * ```typescript
2812
+ * declare module '@core/tokens' {
2813
+ * interface TokenSymbolRegistry {
2814
+ * USDC: true
2815
+ * EURC: true
2816
+ * }
2817
+ * }
2818
+ * // Now TokenSymbol includes 'USDC' | 'EURC' | ...
2819
+ * ```
2820
+ *
2821
+ * NOTE: The eslint-disable below suppresses warnings about empty interfaces.
2822
+ * This is intentional—the interface exists solely as an augmentation target.
2823
+ */
2824
+ interface TokenSymbolRegistry {
2825
+ }
2826
+ /**
2827
+ * Union type of all registered token symbols.
2828
+ *
2829
+ * @remarks
2830
+ * This type is derived from the keys of `TokenSymbolRegistry`:
2831
+ * - **Without augmentation** — Simply `string` (any value)
2832
+ * - **With augmentation** — `'USDC' | 'USDT' | ...` plus any string
2833
+ *
2834
+ * Uses `LiteralUnion` to preserve autocomplete for known values while
2835
+ * still accepting any string at runtime.
2836
+ *
2837
+ * @example
2838
+ * ```typescript
2839
+ * // With symbols.augment imported - autocomplete works
2840
+ * const symbol: TokenSymbol = 'USDC'
2841
+ *
2842
+ * // Custom strings still accepted
2843
+ * const symbol: TokenSymbol = 'MY_TOKEN'
2844
+ * ```
2845
+ */
2846
+ type TokenSymbol = keyof TokenSymbolRegistry extends never ? string : LiteralUnion<Extract<keyof TokenSymbolRegistry, string>>;
2847
+ /**
2848
+ * Selector for identifying a token.
2849
+ *
2850
+ * @remarks
2851
+ * Can be one of:
2852
+ * - A symbol string (e.g., "USDC") - resolves from registry
2853
+ * - A raw locator object with explicit decimals - for arbitrary tokens
2854
+ *
2855
+ * Using a symbol is preferred when the token is in the registry, as it
2856
+ * automatically resolves decimals and the correct chain address.
2857
+ *
2858
+ * @example
2859
+ * ```typescript
2860
+ * // By symbol (preferred for known tokens)
2861
+ * const selector1: TokenSelector = 'USDC'
2862
+ *
2863
+ * // By raw locator (for arbitrary tokens)
2864
+ * const selector2: TokenSelector = {
2865
+ * locator: '0x1234...',
2866
+ * decimals: 18,
2867
+ * }
2868
+ * ```
2869
+ */
2870
+ type TokenSelector = TokenSymbol | RawTokenSelector;
2871
+ /**
2872
+ * The resolved token information after registry lookup.
2873
+ *
2874
+ * @remarks
2875
+ * This is the result of resolving a `TokenSelector` against a chain.
2876
+ * It always contains the locator and decimals, and optionally the symbol
2877
+ * if the token was resolved from the registry.
2878
+ */
2879
+ interface ResolvedToken {
2880
+ /**
2881
+ * The token symbol, if known.
2882
+ * Present when resolved from registry, absent for raw locators.
2883
+ */
2884
+ readonly symbol?: string;
2885
+ /**
2886
+ * The number of decimal places for the token.
2887
+ */
2888
+ readonly decimals: number;
2889
+ /**
2890
+ * The chain-specific token locator (address, program ID, etc.).
2891
+ */
2892
+ readonly locator: string;
2893
+ }
2894
+ /**
2895
+ * Interface for the token registry.
2896
+ *
2897
+ * @remarks
2898
+ * The registry is the sole source of truth for token information.
2899
+ * It supports both symbol-based and raw locator-based token selection.
2900
+ *
2901
+ * @example
2902
+ * ```typescript
2903
+ * import { createTokenRegistry } from '@core/tokens'
2904
+ *
2905
+ * // Create registry (includes built-in tokens like USDC)
2906
+ * const registry = createTokenRegistry()
2907
+ *
2908
+ * // Resolve by symbol
2909
+ * const usdc = registry.resolve('USDC', 'Ethereum')
2910
+ * console.log(usdc.locator) // '0xa0b86991...'
2911
+ *
2912
+ * // Resolve raw locator
2913
+ * const custom = registry.resolve({ locator: '0x...', decimals: 18 }, 'Ethereum')
2914
+ * ```
2915
+ */
2916
+ interface TokenRegistry {
2917
+ /**
2918
+ * Resolve a token selector to concrete token information for a chain.
2919
+ *
2920
+ * @param selector - The token to resolve (symbol or raw locator).
2921
+ * @param chainId - The chain identifier to resolve for.
2922
+ * @returns The resolved token information.
2923
+ * @throws When the token cannot be resolved (unknown symbol, missing decimals, etc.).
2924
+ */
2925
+ resolve(selector: TokenSelector, chainId: ChainIdentifier): ResolvedToken;
2926
+ /**
2927
+ * Get a token definition by symbol.
2928
+ *
2929
+ * @param symbol - The token symbol (e.g., "USDC").
2930
+ * @returns The token definition, or undefined if not found.
2931
+ */
2932
+ get(symbol: string): TokenDefinition | undefined;
2933
+ /**
2934
+ * Check if a symbol is registered.
2935
+ *
2936
+ * @param symbol - The token symbol to check.
2937
+ * @returns True if the symbol is in the registry.
2938
+ */
2939
+ has(symbol: string): boolean;
2940
+ /**
2941
+ * Get all registered token symbols.
2942
+ *
2943
+ * @returns An array of registered symbol strings.
2944
+ */
2945
+ symbols(): string[];
2946
+ /**
2947
+ * Get all registered token definitions.
2948
+ *
2949
+ * @returns An array of all TokenDefinition objects in the registry.
2950
+ */
2951
+ entries(): TokenDefinition[];
2952
+ }
2953
+
2954
+ /**
2955
+ * Structured fields that can be attached to log entries.
2956
+ */
2957
+ type LogFields = Record<string, unknown>;
2958
+ /**
2959
+ * Logger interface providing structured logging with child scoping.
2960
+ *
2961
+ * @remarks
2962
+ * This interface defines a minimal, framework-agnostic logging contract.
2963
+ * The underlying implementation uses pino for transport handling (console,
2964
+ * file, remote, JSON, pretty, etc.) but consumers only interact with this
2965
+ * stable interface.
2966
+ *
2967
+ * @example
2968
+ * ```typescript
2969
+ * import { createLogger } from '@core/runtime'
2970
+ *
2971
+ * const logger = createLogger({ level: 'debug' })
2972
+ *
2973
+ * // Simple message
2974
+ * logger.info('Server started')
2975
+ *
2976
+ * // Message with structured fields
2977
+ * logger.info('Request received', { method: 'POST', path: '/api/transfer' })
2978
+ *
2979
+ * // Create child logger with context
2980
+ * const requestLogger = logger.child({ requestId: 'abc-123' })
2981
+ * requestLogger.debug('Processing transfer')
2982
+ * // Output includes: requestId in all subsequent logs
2983
+ * ```
2984
+ */
2985
+ interface Logger {
2986
+ /**
2987
+ * Log a debug-level message.
2988
+ * @param message - The log message.
2989
+ * @param fields - Optional structured fields.
2990
+ * @returns void
2991
+ */
2992
+ debug(message: string, fields?: LogFields): void;
2993
+ /**
2994
+ * Log an info-level message.
2995
+ * @param message - The log message.
2996
+ * @param fields - Optional structured fields.
2997
+ * @returns void
2998
+ */
2999
+ info(message: string, fields?: LogFields): void;
3000
+ /**
3001
+ * Log a warning-level message.
3002
+ * @param message - The log message.
3003
+ * @param fields - Optional structured fields.
3004
+ * @returns void
3005
+ */
3006
+ warn(message: string, fields?: LogFields): void;
3007
+ /**
3008
+ * Log an error-level message.
3009
+ * @param message - The log message.
3010
+ * @param fields - Optional structured fields.
3011
+ * @returns void
3012
+ */
3013
+ error(message: string, fields?: LogFields): void;
3014
+ /**
3015
+ * Create a child logger with additional contextual bindings.
3016
+ *
3017
+ * @param tags - Key-value pairs to add to the child logger's context.
3018
+ * Undefined values are filtered out automatically.
3019
+ * @returns A new Logger instance with merged bindings.
3020
+ *
3021
+ * @example
3022
+ * ```typescript
3023
+ * const requestLogger = logger.child({ requestId: 'req-123' })
3024
+ * const userLogger = requestLogger.child({ userId: 'user-456' })
3025
+ * // All logs from userLogger include both requestId and userId
3026
+ * ```
3027
+ */
3028
+ child(tags: LogFields): Logger;
3029
+ }
3030
+
3031
+ /**
3032
+ * Handler function for event subscriptions.
3033
+ */
3034
+ type EventHandler = (event: Event) => void | Promise<void>;
3035
+ /**
3036
+ * Event bus for publishing and subscribing to events.
3037
+ *
3038
+ * @remarks
3039
+ * Supports wildcard topic subscriptions:
3040
+ * - `*` matches exactly one segment
3041
+ * - `**` matches zero or more segments
3042
+ *
3043
+ * @example
3044
+ * ```typescript
3045
+ * const bus = createEventBus()
3046
+ *
3047
+ * // Subscribe to all events
3048
+ * bus.on((event) => console.log(event))
3049
+ *
3050
+ * // Subscribe to specific topic
3051
+ * bus.on('tx.wait.started', (event) => console.log(event))
3052
+ *
3053
+ * // Subscribe with wildcard
3054
+ * bus.on('tx.wait.*', (event) => console.log(event))
3055
+ * bus.on('tx.**', (event) => console.log(event))
3056
+ *
3057
+ * // Emit events
3058
+ * bus.emit({ name: 'tx.wait.started', data: { txId: '0x123' } })
3059
+ * ```
3060
+ */
3061
+ interface EventBus {
3062
+ /**
3063
+ * Emit an event to all matching subscribers.
3064
+ *
3065
+ * @param event - The event to emit.
3066
+ * @remarks
3067
+ * Synchronous and never throws. Handler errors are isolated.
3068
+ */
3069
+ emit(event: Event): void;
3070
+ /**
3071
+ * Create a child event bus with scoped tags.
3072
+ *
3073
+ * @param tags - Tags to merge into all emitted events.
3074
+ * @returns A new EventBus with merged tags.
3075
+ */
3076
+ child(tags: Tags): EventBus;
3077
+ /**
3078
+ * Subscribe to all events.
3079
+ *
3080
+ * @param handler - Function called for every event.
3081
+ * @returns Unsubscribe function.
3082
+ */
3083
+ on(handler: EventHandler): () => void;
3084
+ /**
3085
+ * Subscribe to events matching a pattern.
3086
+ *
3087
+ * @param pattern - Topic pattern (supports `*` and `**` wildcards).
3088
+ * @param handler - Function called for matching events.
3089
+ * @returns Unsubscribe function.
3090
+ *
3091
+ * @remarks
3092
+ * Wildcard semantics:
3093
+ * - `*` matches exactly one segment (no dots)
3094
+ * - `**` matches zero or more segments (only valid at end)
3095
+ *
3096
+ * @example
3097
+ * ```typescript
3098
+ * bus.on('*', handler) // matches 'tx', 'user' (single segment only)
3099
+ * bus.on('tx.wait.*', handler) // matches tx.wait.started, tx.wait.failed
3100
+ * bus.on('tx.wait.**', handler) // matches tx.wait, tx.wait.started, tx.wait.foo.bar
3101
+ * bus.on('**', handler) // matches all events
3102
+ * ```
3103
+ */
3104
+ on(pattern: string, handler: EventHandler): () => void;
3105
+ }
3106
+
3107
+ /**
3108
+ * Metrics type definitions for the Runtime module.
3109
+ *
3110
+ * @remarks
3111
+ * Define a minimal, pluggable metrics interface that can be backed by any
3112
+ * metrics library (hot-shots, dd-trace, prom-client, etc.).
3113
+ *
3114
+ * The interface supports:
3115
+ * - Counters for monotonically increasing values
3116
+ * - Histograms for distributions (latencies, sizes)
3117
+ * - Timers as a convenience wrapper for timing operations
3118
+ * - Label scoping via `child()` for dimensional metrics
3119
+ *
3120
+ * @example
3121
+ * ```typescript
3122
+ * // Basic usage
3123
+ * metrics.counter('requests.total').inc({ method: 'POST' })
3124
+ * metrics.histogram('request.duration').observe({ status: 200 }, 42.5)
3125
+ *
3126
+ * // Timer convenience
3127
+ * const stop = metrics.timer('db.query').start({ table: 'users' })
3128
+ * await query()
3129
+ * stop() // Records duration automatically
3130
+ *
3131
+ * // Scoping adds base labels to all metrics
3132
+ * const scoped = metrics.child({ service: 'bridge', env: 'prod' })
3133
+ * scoped.counter('transfers').inc() // Includes service + env labels
3134
+ * ```
3135
+ */
3136
+ /**
3137
+ * Labels for dimensional metrics.
3138
+ *
3139
+ * @remarks
3140
+ * Labels (also called tags in some systems) are key-value pairs that
3141
+ * provide dimensions for metric aggregation and filtering.
3142
+ * Values must be primitives for serialization compatibility.
3143
+ *
3144
+ * @example
3145
+ * ```typescript
3146
+ * const labels: MetricLabels = {
3147
+ * chain: 'Ethereum',
3148
+ * status: 'success',
3149
+ * retries: 3,
3150
+ * cached: true,
3151
+ * }
3152
+ * ```
3153
+ */
3154
+ type MetricLabels = Record<string, string | number | boolean>;
3155
+ /**
3156
+ * A counter metric for monotonically increasing values.
3157
+ *
3158
+ * @remarks
3159
+ * Use counters for values that only go up: request counts, error counts,
3160
+ * bytes processed, etc. The value resets only on process restart.
3161
+ *
3162
+ * @see {@link Metrics.counter} to obtain a Counter instance.
3163
+ *
3164
+ * @example
3165
+ * ```typescript
3166
+ * const counter = metrics.counter('http.requests')
3167
+ *
3168
+ * // Increment by 1
3169
+ * counter.inc()
3170
+ * counter.inc({ method: 'GET' })
3171
+ *
3172
+ * // Increment by specific value
3173
+ * counter.inc(5)
3174
+ * counter.inc({ method: 'POST' }, 3)
3175
+ * ```
3176
+ */
3177
+ interface Counter {
3178
+ /**
3179
+ * Increment the counter value.
3180
+ *
3181
+ * @param labelsOrValue - The labels object or increment value.
3182
+ * When a number, increments by that amount with no labels.
3183
+ * When an object, uses as labels with optional value in second param.
3184
+ * @param value - The increment value when first arg is labels. Default: 1.
3185
+ * @returns void
3186
+ *
3187
+ * @example
3188
+ * ```typescript
3189
+ * counter.inc() // +1, no labels
3190
+ * counter.inc(5) // +5, no labels
3191
+ * counter.inc({ method: 'GET' }) // +1, with labels
3192
+ * counter.inc({ method: 'POST' }, 3) // +3, with labels
3193
+ * ```
3194
+ */
3195
+ inc(labelsOrValue?: MetricLabels | number, value?: number): void;
3196
+ }
3197
+ /**
3198
+ * A histogram metric for recording value distributions.
3199
+ *
3200
+ * @remarks
3201
+ * Use histograms for values that vary and need percentile analysis:
3202
+ * request durations, response sizes, queue depths, etc.
3203
+ *
3204
+ * @see {@link Metrics.histogram} to obtain a Histogram instance.
3205
+ *
3206
+ * @example
3207
+ * ```typescript
3208
+ * const histogram = metrics.histogram('http.duration')
3209
+ *
3210
+ * // Record a value
3211
+ * histogram.observe(42.5)
3212
+ * histogram.observe({ status: 200 }, 42.5)
3213
+ * ```
3214
+ */
3215
+ interface Histogram {
3216
+ /**
3217
+ * Record an observation value.
3218
+ *
3219
+ * @param labelsOrValue - The labels object or observed value.
3220
+ * When a number, records that value with no labels.
3221
+ * When an object, uses as labels with value in second param.
3222
+ * @param value - The observed value when first arg is labels. Default: 0.
3223
+ * @returns void
3224
+ *
3225
+ * @example
3226
+ * ```typescript
3227
+ * histogram.observe(42.5) // Value only
3228
+ * histogram.observe({ status: 200 }, 42.5) // With labels
3229
+ * ```
3230
+ */
3231
+ observe(labelsOrValue?: MetricLabels | number, value?: number): void;
3232
+ }
3233
+ /**
3234
+ * A timer metric for measuring operation durations.
3235
+ *
3236
+ * @remarks
3237
+ * Timers provide a convenience wrapper that automatically records durations
3238
+ * to an underlying histogram. Call `start()` to begin timing and the
3239
+ * returned function to stop and record the elapsed time in milliseconds.
3240
+ *
3241
+ * @see {@link Metrics.timer} to obtain a Timer instance.
3242
+ *
3243
+ * @example
3244
+ * ```typescript
3245
+ * const timer = metrics.timer('db.query')
3246
+ *
3247
+ * // Start timing
3248
+ * const stop = timer.start({ table: 'users' })
3249
+ * await performQuery()
3250
+ * stop() // Records duration in milliseconds
3251
+ * ```
3252
+ */
3253
+ interface Timer {
3254
+ /**
3255
+ * Start timing an operation.
3256
+ *
3257
+ * @param labels - The optional labels for the timing observation.
3258
+ * @returns A stop function that records the duration when called.
3259
+ *
3260
+ * @example
3261
+ * ```typescript
3262
+ * const stop = timer.start({ operation: 'fetch' })
3263
+ * await fetchData()
3264
+ * stop() // Records elapsed time
3265
+ * ```
3266
+ */
3267
+ start(labels?: MetricLabels): () => void;
3268
+ }
3269
+ /**
3270
+ * Main metrics interface for instrumentation.
3271
+ *
3272
+ * @remarks
3273
+ * This interface is designed to be thin and pluggable. Implementations
3274
+ * can delegate to any metrics library:
3275
+ *
3276
+ * - **hot-shots**: StatsD/DogStatsD client
3277
+ * - **dd-trace**: Datadog APM
3278
+ * - **prom-client**: Prometheus
3279
+ * - **opentelemetry-js**: OpenTelemetry
3280
+ *
3281
+ * The `child()` method creates a scoped metrics instance that automatically
3282
+ * includes base labels on all metric operations.
3283
+ *
3284
+ * @see {@link createMockMetrics} for testing.
3285
+ * @see {@link noopMetrics} for a no-op implementation.
3286
+ *
3287
+ * @example
3288
+ * ```typescript
3289
+ * // Create a scoped metrics instance
3290
+ * const appMetrics = metrics.child({
3291
+ * service: 'stablecoin-kit',
3292
+ * version: '1.0.0',
3293
+ * })
3294
+ *
3295
+ * // All metrics include service + version labels
3296
+ * appMetrics.counter('transfers.initiated').inc({ chain: 'ethereum' })
3297
+ * ```
3298
+ */
3299
+ interface Metrics {
3300
+ /**
3301
+ * Get or create a counter metric by name.
3302
+ *
3303
+ * @param name - The metric name (e.g., 'http.requests.total').
3304
+ * @returns A Counter instance for the given name.
3305
+ *
3306
+ * @example
3307
+ * ```typescript
3308
+ * const counter = metrics.counter('requests.total')
3309
+ * counter.inc({ method: 'GET' })
3310
+ * ```
3311
+ */
3312
+ counter(name: string): Counter;
3313
+ /**
3314
+ * Get or create a histogram metric by name.
3315
+ *
3316
+ * @param name - The metric name (e.g., 'http.request.duration').
3317
+ * @returns A Histogram instance for the given name.
3318
+ *
3319
+ * @example
3320
+ * ```typescript
3321
+ * const histogram = metrics.histogram('request.duration')
3322
+ * histogram.observe({ status: 200 }, 42.5)
3323
+ * ```
3324
+ */
3325
+ histogram(name: string): Histogram;
3326
+ /**
3327
+ * Get or create a timer metric by name.
3328
+ *
3329
+ * @param name - The metric name (e.g., 'db.query.duration').
3330
+ * @returns A Timer instance for the given name.
3331
+ *
3332
+ * @example
3333
+ * ```typescript
3334
+ * const stop = metrics.timer('db.query').start()
3335
+ * await query()
3336
+ * stop()
3337
+ * ```
3338
+ */
3339
+ timer(name: string): Timer;
3340
+ /**
3341
+ * Create a child metrics instance with scoped labels.
3342
+ *
3343
+ * @param labels - The base labels to include on all metric operations.
3344
+ * @returns A new Metrics instance with merged labels.
3345
+ *
3346
+ * @remarks
3347
+ * Labels from the child are merged with any labels passed to individual
3348
+ * metric operations. Call-site labels take precedence for the same key.
3349
+ *
3350
+ * @example
3351
+ * ```typescript
3352
+ * const scoped = metrics.child({ chain: 'Ethereum' })
3353
+ * scoped.counter('transfers').inc({ status: 'success' })
3354
+ * // Labels: { chain: 'Ethereum', status: 'success' }
3355
+ * ```
3356
+ */
3357
+ child(labels: MetricLabels): Metrics;
3358
+ }
3359
+
3360
+ /**
3361
+ * Core type definitions for the runtime package.
3362
+ *
3363
+ * @remarks
3364
+ * This module defines the foundational types used throughout the SDK:
3365
+ *
3366
+ * - {@link Runtime} - Complete runtime with all services (clock, logger, metrics, events)
3367
+ * - {@link ExecutionContext} - Context for middleware with observability surface
3368
+ * - {@link Clock}, {@link Tags}, {@link Event} - Supporting types
3369
+ *
3370
+ * **Naming Convention**
3371
+ *
3372
+ * | Input Type | Resolved Type | Description |
3373
+ * |------------|---------------|-------------|
3374
+ * | `Partial<Runtime>` | `Runtime` | Runtime services |
3375
+ * | `OperationMeta` | `OperationContext` | WHAT - operation target |
3376
+ * | `InvocationMeta` | `InvocationContext` | WHO/HOW - call chain |
3377
+ *
3378
+ * @packageDocumentation
3379
+ */
3380
+
3381
+ /**
3382
+ * Clock interface for time operations.
3383
+ *
3384
+ * @remarks
3385
+ * Abstracting time allows tests to control timing without real delays.
3386
+ * Production code uses {@link defaultClock}, tests use mock implementations.
3387
+ *
3388
+ * @example
3389
+ * ```typescript
3390
+ * import { defaultClock, type Clock } from '@core/runtime'
3391
+ *
3392
+ * const start = defaultClock.now()
3393
+ * // ... do work ...
3394
+ * const elapsed = defaultClock.since(start)
3395
+ * ```
3396
+ */
3397
+ interface Clock {
3398
+ /**
3399
+ * Return the current timestamp in milliseconds since Unix epoch.
3400
+ *
3401
+ * @returns Current time in milliseconds.
3402
+ */
3403
+ now(): number;
3404
+ /**
3405
+ * Calculate elapsed time since a given timestamp.
3406
+ *
3407
+ * @param start - The start timestamp in milliseconds.
3408
+ * @returns Elapsed time in milliseconds (`now() - start`).
3409
+ */
3410
+ since: (start: number) => number;
3411
+ }
3412
+ /**
3413
+ * Contextual metadata tags for logging and metrics.
3414
+ *
3415
+ * @remarks
3416
+ * Tags are key-value pairs attached to log entries and metrics.
3417
+ * Values can be primitives or undefined (undefined values are filtered out).
3418
+ *
3419
+ * Common tags include:
3420
+ * - `opId` - Operation identifier for correlation
3421
+ * - `chain` - Blockchain network name
3422
+ * - `phase` - Current pipeline phase
3423
+ *
3424
+ * @example
3425
+ * ```typescript
3426
+ * import type { Tags } from '@core/runtime'
3427
+ *
3428
+ * const tags: Tags = {
3429
+ * opId: 'op-abc123',
3430
+ * chain: 'Ethereum',
3431
+ * phase: 'validate',
3432
+ * optional: undefined, // Will be filtered out
3433
+ * }
3434
+ * ```
3435
+ */
3436
+ type Tags = Record<string, string | number | boolean | undefined>;
3437
+ /**
3438
+ * A structured event emitted by the runtime.
3439
+ *
3440
+ * @remarks
3441
+ * Events provide a standardized way to capture lifecycle moments,
3442
+ * actions, and state changes throughout the SDK.
3443
+ */
3444
+ interface Event {
3445
+ /** The event name/identifier. */
3446
+ name: string;
3447
+ /** Log level for the event. */
3448
+ level?: 'debug' | 'info' | 'warn' | 'error';
3449
+ /** Timestamp (epoch ms) when the event occurred. */
3450
+ at?: number;
3451
+ /** Contextual tags for filtering/categorization. */
3452
+ tags?: Tags;
3453
+ /** Arbitrary payload data associated with the event. */
3454
+ data?: unknown;
3455
+ }
3456
+ /**
3457
+ * Complete runtime with all services guaranteed present.
3458
+ *
3459
+ * @remarks
3460
+ * The runtime is the container for all cross-cutting concerns: logging,
3461
+ * timing, events, and metrics. All services are guaranteed to be available.
3462
+ *
3463
+ * **Creating a Runtime**
3464
+ *
3465
+ * Use {@link createRuntime} to create a fully-configured runtime:
3466
+ * ```typescript
3467
+ * import { createRuntime } from '@core/runtime'
3468
+ *
3469
+ * const runtime = createRuntime()
3470
+ * runtime.logger.info('Hello')
3471
+ * runtime.metrics.counter('requests').inc()
3472
+ * ```
3473
+ *
3474
+ * **Partial Runtime Input**
3475
+ *
3476
+ * When accepting runtime configuration as input, use `Partial<Runtime>`:
3477
+ * ```typescript
3478
+ * function myFunction(options: { runtime?: Partial<Runtime> }) {
3479
+ * const runtime = createRuntime(options.runtime)
3480
+ * // ...
3481
+ * }
3482
+ * ```
3483
+ *
3484
+ * @example
3485
+ * ```typescript
3486
+ * import { createRuntime, type Runtime } from '@core/runtime'
3487
+ *
3488
+ * const runtime: Runtime = createRuntime()
3489
+ *
3490
+ * // All services are guaranteed present
3491
+ * runtime.logger.info('Processing request')
3492
+ * runtime.metrics.counter('requests').inc()
3493
+ * runtime.events.emit({ name: 'request.received' })
3494
+ * const now = runtime.clock.now()
3495
+ * ```
3496
+ */
3497
+ interface Runtime {
3498
+ /**
3499
+ * Clock for time operations.
3500
+ *
3501
+ * @remarks
3502
+ * Provides the current timestamp. Use {@link defaultClock} for production
3503
+ * or custom clocks for deterministic testing.
3504
+ */
3505
+ clock: Clock;
3506
+ /**
3507
+ * Logger for structured logging.
3508
+ *
3509
+ * @remarks
3510
+ * Provides debug, info, warn, error methods with structured data support.
3511
+ */
3512
+ logger: Logger;
3513
+ /**
3514
+ * Metrics collector for observability.
3515
+ *
3516
+ * @remarks
3517
+ * Provides counters, histograms, and timers for application metrics.
3518
+ */
3519
+ metrics: Metrics;
3520
+ /**
3521
+ * Event bus for pub/sub events.
3522
+ *
3523
+ * @remarks
3524
+ * Enables decoupled event emission and subscription across the SDK.
3525
+ */
3526
+ events: EventBus;
3527
+ }
3528
+ /**
3529
+ * A component in the call chain.
3530
+ *
3531
+ * @remarks
3532
+ * Each caller identifies itself with a type (app, kit, provider, adapter)
3533
+ * and a name/version. This enables proper attribution in logs, metrics, and traces.
3534
+ *
3535
+ * @example
3536
+ * ```typescript
3537
+ * import type { Caller } from '@core/runtime'
3538
+ *
3539
+ * const appCaller: Caller = { type: 'app', name: 'MyDApp', version: '1.0.0' }
3540
+ * const kitCaller: Caller = { type: 'kit', name: 'BridgeKit', version: '2.0.0' }
3541
+ * ```
3542
+ */
3543
+ interface Caller {
3544
+ /**
3545
+ * Type of component in the call hierarchy.
3546
+ *
3547
+ * @remarks
3548
+ * Common types: `app`, `kit`, `provider`, `adapter`
3549
+ */
3550
+ readonly type: string;
3551
+ /** Name of the component (e.g., 'BridgeKit', 'cctp-v2'). */
3552
+ readonly name: string;
3553
+ /** Version of the component (e.g., '1.0.0'). */
3554
+ readonly version?: string | undefined;
3555
+ }
3556
+ /**
3557
+ * User input for invocation metadata.
3558
+ *
3559
+ * @remarks
3560
+ * Defines **WHO** called and **HOW** to observe: trace correlation, runtime override,
3561
+ * and caller chain. This is the user-facing input type, resolved to `InvocationContext`.
3562
+ *
3563
+ * Passed as the optional invocation argument to actions and primitives.
3564
+ *
3565
+ * @example
3566
+ * ```typescript
3567
+ * import type { InvocationMeta } from '@core/runtime'
3568
+ *
3569
+ * // Minimal - just traceId
3570
+ * const meta: InvocationMeta = { traceId: 'abc-123' }
3571
+ *
3572
+ * // Full - with runtime override and caller chain
3573
+ * const meta: InvocationMeta = {
3574
+ * traceId: 'abc-123',
3575
+ * runtime: myRuntime,
3576
+ * callers: [
3577
+ * { type: 'app', name: 'MyDApp', version: '1.0.0' },
3578
+ * ],
3579
+ * }
3580
+ * ```
3581
+ */
3582
+ interface InvocationMeta {
3583
+ /**
3584
+ * Trace ID for distributed tracing correlation.
3585
+ *
3586
+ * @remarks
3587
+ * If not provided, generated automatically.
3588
+ */
3589
+ readonly traceId?: string | undefined;
3590
+ /**
3591
+ * Runtime override (complete replacement).
3592
+ *
3593
+ * @remarks
3594
+ * When provided, this runtime completely replaces the default runtime.
3595
+ * Must be a complete Runtime instance (e.g., from `createRuntime()`).
3596
+ * If not provided, the default runtime is used.
3597
+ */
3598
+ readonly runtime?: Runtime | undefined;
3599
+ /**
3600
+ * Token registry override (complete replacement).
3601
+ *
3602
+ * @remarks
3603
+ * When provided, this registry completely replaces the default token registry.
3604
+ * Enables kits to pass their token registry to adapters.
3605
+ * If not provided, the default token registry is used.
3606
+ */
3607
+ readonly tokens?: TokenRegistry | undefined;
3608
+ /**
3609
+ * Call chain - each caller appends itself.
3610
+ *
3611
+ * @remarks
3612
+ * Ordered from outermost (first) to innermost (last).
3613
+ * Example: [app, kit, provider]
3614
+ */
3615
+ readonly callers?: readonly Caller[] | undefined;
3616
+ }
3617
+
3618
+ /**
3619
+ * Transfer speed options for cross-chain operations.
3620
+ *
3621
+ * Defines the available speed modes for CCTPv2 transfers, affecting
3622
+ * both transfer time and potential fee implications.
3623
+ */
3624
+ declare enum TransferSpeed {
3625
+ /** Fast burn mode - reduces transfer time but may have different fee implications */
3626
+ FAST = "FAST",
3627
+ /** Standard burn mode - normal transfer time with standard fees */
3628
+ SLOW = "SLOW"
3629
+ }
3630
+ /**
3631
+ * Context object representing a wallet and signing authority on a specific blockchain network.
3632
+ *
3633
+ * Combines a wallet or contract address, the blockchain it resides on, and the adapter (signer)
3634
+ * responsible for authorizing transactions. Used to specify the source or destination in cross-chain
3635
+ * transfer operations.
3636
+ *
3637
+ * @remarks
3638
+ * The `adapter` (signer) and `address` do not always have to belong to the same entity. For example,
3639
+ * in minting or withdrawal scenarios, the signing adapter may authorize a transaction that credits
3640
+ * funds to a different recipient address. This context is essential for cross-chain operations,
3641
+ * ensuring that both the address and the associated adapter are correctly paired with the intended
3642
+ * blockchain, but not necessarily with each other.
3643
+ *
3644
+ * @example
3645
+ * ```typescript
3646
+ * import type { WalletContext } from '@core/provider'
3647
+ * import { adapter, blockchain } from './setup'
3648
+ *
3649
+ * const wallet: WalletContext = {
3650
+ * adapter,
3651
+ * address: '0x1234...abcd',
3652
+ * chain: blockchain,
3653
+ * }
3654
+ * ```
3655
+ */
3656
+ interface WalletContext<TAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities,
3657
+ /**
3658
+ * The chain definition type to use for the wallet context.
3659
+ *
3660
+ * @defaultValue ChainDefinition
3661
+ */
3662
+ TChainDefinition extends ChainDefinition = ChainDefinition> {
3663
+ /**
3664
+ * The adapter (signer) for the wallet on the specified chain.
3665
+ *
3666
+ * Responsible for authorizing transactions and signing messages on behalf of the wallet or
3667
+ * for a different recipient, depending on the use case.
3668
+ */
3669
+ adapter: Adapter<TAdapterCapabilities>;
3670
+ /**
3671
+ * The wallet or contract address.
3672
+ *
3673
+ * Must be a valid address format for the specified blockchain. May differ from the adapter's
3674
+ * own address in scenarios such as relayed transactions or third-party minting.
3675
+ */
3676
+ address: string;
3677
+ /**
3678
+ * The blockchain network where the wallet or contract address resides.
3679
+ *
3680
+ * Determines the context and format for the address and adapter.
3681
+ */
3682
+ chain: TChainDefinition;
3683
+ }
3684
+ /**
3685
+ * Wallet context for bridge destinations with optional custom recipient.
3686
+ *
3687
+ * Extends WalletContext to support scenarios where the recipient address
3688
+ * differs from the signer address (e.g., bridging to a third-party wallet).
3689
+ * The signer address is used for transaction authorization, while the
3690
+ * recipient address specifies where the minted funds should be sent.
3691
+ *
3692
+ * @typeParam TAdapterCapabilities - The adapter capabilities type to use for the wallet context.
3693
+ * @typeParam TChainDefinition - The chain definition type to use for the wallet context.
3694
+ *
3695
+ * @example
3696
+ * ```typescript
3697
+ * import type { DestinationWalletContext } from '@core/provider'
3698
+ * import { adapter, blockchain } from './setup'
3699
+ *
3700
+ * // Bridge to a custom recipient address
3701
+ * const destination: DestinationWalletContext = {
3702
+ * adapter,
3703
+ * address: '0x1234...abcd', // Signer address
3704
+ * chain: blockchain,
3705
+ * recipientAddress: '0x9876...fedc' // Custom recipient
3706
+ * }
3707
+ * ```
3708
+ */
3709
+ interface DestinationWalletContext<TAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities,
3710
+ /**
3711
+ * The chain definition type to use for the wallet context.
3712
+ *
3713
+ * @defaultValue ChainDefinition
3714
+ */
3715
+ TChainDefinition extends ChainDefinition = ChainDefinition> extends WalletContext<TAdapterCapabilities, TChainDefinition> {
3716
+ /**
3717
+ * Optional custom recipient address for minted funds.
3718
+ *
3719
+ * When provided, minted tokens will be sent to this address instead of
3720
+ * the address specified in the wallet context. The wallet context address
3721
+ * is still used for transaction signing and authorization.
3722
+ *
3723
+ * Must be a valid address format for the specified blockchain.
3724
+ */
3725
+ recipientAddress?: string;
3726
+ }
3727
+ /**
3728
+ * Parameters for executing a cross-chain bridge operation.
3729
+ */
3730
+ interface BridgeParams<TFromCapabilities extends AdapterCapabilities = AdapterCapabilities, TToCapabilities extends AdapterCapabilities = AdapterCapabilities,
3731
+ /**
3732
+ * The chain definition type to use for the wallet context.
3733
+ *
3734
+ * @defaultValue ChainDefinition
3735
+ */
3736
+ TChainDefinition extends ChainDefinition = ChainDefinition> {
3737
+ /** The source adapter containing wallet and chain information */
3738
+ source: WalletContext<TFromCapabilities, TChainDefinition>;
3739
+ /** The destination adapter containing wallet and chain information */
3740
+ destination: DestinationWalletContext<TToCapabilities, TChainDefinition>;
3741
+ /** The amount to transfer (as a string to avoid precision issues) */
3742
+ amount: string;
3743
+ /** The token to transfer (currently only USDC is supported) */
3744
+ token: 'USDC';
3745
+ /** Bridge configuration (e.g., fast burn settings) */
3746
+ config: BridgeConfig;
3747
+ /**
3748
+ * Optional invocation metadata for tracing and correlation.
3749
+ *
3750
+ * When provided, the `traceId` is used to correlate all events emitted during
3751
+ * the bridge operation. If not provided, an OpenTelemetry-compatible traceId
3752
+ * will be auto-generated.
3753
+ */
3754
+ invocationMeta?: InvocationMeta;
3755
+ }
3756
+ /**
3757
+ * A step in the bridge process.
3758
+ *
3759
+ * @remarks
3760
+ * This interface represents a single step in the bridge process,
3761
+ * such as approval, burn, or mint.
3762
+ *
3763
+ * @example
3764
+ * ```typescript
3765
+ * const step: BridgeStep = {
3766
+ * name: 'Approve',
3767
+ * state: 'success',
3768
+ * txHash: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
3769
+ * explorerUrl: 'https://etherscan.io/tx/0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
3770
+ * }
3771
+ * ```
3772
+ */
3773
+ interface BridgeStep {
3774
+ /** Human-readable name of the step (e.g., "Approve", "Burn", "Mint") */
3775
+ name: string;
3776
+ /** The state of the step */
3777
+ state: 'pending' | 'success' | 'error' | 'noop';
3778
+ /** Optional transaction hash for this step (if applicable) */
3779
+ txHash?: string;
3780
+ /** Optional explorer URL for viewing this transaction on a block explorer */
3781
+ explorerUrl?: string;
3782
+ /** Optional data for the step */
3783
+ data?: unknown;
3784
+ /**
3785
+ * Whether this step was executed via Circle's Forwarder (relay service).
3786
+ * Only applicable for mint steps.
3787
+ *
3788
+ * - `true`: The mint was handled by Circle's Orbit relayer
3789
+ * - `false`: The user submitted the mint transaction directly
3790
+ * - `undefined`: Not applicable (non-mint steps)
3791
+ */
3792
+ forwarded?: boolean;
3793
+ /** Optional human-readable error message */
3794
+ errorMessage?: string;
3795
+ /** Optional raw error object (can be Viem/Ethers/Chain error) */
3796
+ error?: unknown;
3797
+ }
3798
+ /**
3799
+ * Result object returned after a successful cross-chain bridge operation.
3800
+ *
3801
+ * This interface contains all the details about a completed bridge, including
3802
+ * the bridge parameters, source and destination information,
3803
+ * and the sequence of steps that were executed.
3804
+ *
3805
+ * @example
3806
+ * ```typescript
3807
+ * const result: BridgeResult = await provider.bridge(source, dest, '100')
3808
+ * console.log(`Transferred ${result.amount} ${result.token}`)
3809
+ * console.log(`Steps executed: ${result.steps.length}`)
3810
+ * ```
3811
+ */
3812
+ interface BridgeResult {
3813
+ /** The amount that was transferred (as a string to avoid precision issues) */
3814
+ amount: string;
3815
+ /** The token that was transferred (currently only USDC is supported) */
3816
+ token: 'USDC';
3817
+ /** The state of the transfer */
3818
+ state: 'pending' | 'success' | 'error';
3819
+ /** The bridge configuration that was used for this operation */
3820
+ config?: BridgeConfig;
3821
+ /** The provider that was used for this operation */
3822
+ provider: string;
3823
+ /** Information about the source chain and address */
3824
+ source: {
3825
+ /** The source wallet/contract address */
3826
+ address: string;
3827
+ /** The source blockchain network */
3828
+ chain: ChainDefinition;
3829
+ };
3830
+ /** Information about the destination chain and address */
3831
+ destination: {
3832
+ /** The destination wallet/contract address */
3833
+ address: string;
3834
+ /** The destination blockchain network */
3835
+ chain: ChainDefinition;
3836
+ /**
3837
+ * Optional custom recipient address for minted funds.
3838
+ *
3839
+ * When provided during the bridge operation, minted tokens are sent to this
3840
+ * address instead of the destination address. This field is preserved in the
3841
+ * result for retry operations to maintain consistency with the original burn.
3842
+ */
3843
+ recipientAddress?: string;
3844
+ /**
3845
+ * Whether Circle's Forwarder was used for this bridge operation.
3846
+ *
3847
+ * When true, the mint transaction was handled by Circle's Orbit relayer
3848
+ * instead of requiring the user to submit it manually.
3849
+ */
3850
+ useForwarder?: boolean;
3851
+ };
3852
+ /** Array of steps that were executed during the bridge process */
3853
+ steps: BridgeStep[];
3854
+ }
3855
+ /**
3856
+ * Cost estimation result for a cross-chain transfer operation.
3857
+ *
3858
+ * This interface provides detailed information about the expected costs
3859
+ * for a transfer, including gas fees on different chains and protocol fees.
3860
+ * It also includes the input context (token, amount, source, destination) to
3861
+ * provide a complete view of the transfer being estimated.
3862
+ *
3863
+ * @example
3864
+ * ```typescript
3865
+ * const estimate: EstimateResult = await provider.estimate(source, dest, '100')
3866
+ * console.log('Estimating transfer of', estimate.amount, estimate.token)
3867
+ * console.log('From', estimate.source.chain.name, 'to', estimate.destination.chain.name)
3868
+ * console.log('Total gas fees:', estimate.gasFees.length)
3869
+ * console.log('Protocol fees:', estimate.fees.length)
3870
+ * ```
3871
+ */
3872
+ interface EstimateResult {
3873
+ /** The token being transferred */
3874
+ token: 'USDC';
2676
3875
  /** The amount being transferred */
2677
3876
  amount: string;
2678
3877
  /** Information about the source chain and address */
@@ -2706,8 +3905,8 @@ interface EstimateResult {
2706
3905
  }[];
2707
3906
  /** Array of protocol and service fees for the transfer */
2708
3907
  fees: {
2709
- /** The type of fee - either from the bridge kit or the underlying provider */
2710
- type: 'kit' | 'provider';
3908
+ /** The type of fee - from the bridge kit, provider (CCTP), or forwarder (Circle Orbit relayer) */
3909
+ type: 'kit' | 'provider' | 'forwarder';
2711
3910
  /** The token in which the fee is charged (currently only USDC) */
2712
3911
  token: 'USDC';
2713
3912
  /** The fee amount (as a string to avoid precision issues) */
@@ -2857,19 +4056,38 @@ interface CustomFee {
2857
4056
  * have access to both the source and destination chain information needed for
2858
4057
  * validation and execution.
2859
4058
  *
4059
+ * The destination adapter (`to`) is optional to support forwarder-only destinations
4060
+ * where Circle's Orbit relayer handles the mint transaction without requiring a
4061
+ * destination adapter. When `to` is undefined, the retry operation relies on
4062
+ * IRIS API confirmation instead of on-chain transaction confirmation.
4063
+ *
2860
4064
  * @example
2861
4065
  * ```typescript
4066
+ * // Standard retry with both adapters
2862
4067
  * const retryContext: RetryContext = {
2863
- * from: { adapter: sourceAdapter, chain: 'Ethereum' },
2864
- * to: { adapter: destAdapter, chain: 'Base' }
4068
+ * from: sourceAdapter,
4069
+ * to: destAdapter
4070
+ * }
4071
+ *
4072
+ * // Forwarder-only retry (no destination adapter)
4073
+ * const forwarderRetryContext: RetryContext = {
4074
+ * from: sourceAdapter,
4075
+ * to: undefined // Forwarder handles mint
2865
4076
  * }
2866
4077
  * ```
2867
4078
  */
2868
4079
  interface RetryContext<TFromAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities, TToAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities> {
2869
4080
  /** The source adapter context for the retry operation */
2870
4081
  from: Adapter<TFromAdapterCapabilities>;
2871
- /** The destination adapter context for the retry operation */
2872
- to: Adapter<TToAdapterCapabilities>;
4082
+ /**
4083
+ * The destination adapter context for the retry operation.
4084
+ *
4085
+ * Optional for forwarder-only destinations where Circle's Orbit relayer
4086
+ * handles the mint transaction. When undefined, the retry operation relies
4087
+ * on IRIS API confirmation (`forwardState === 'CONFIRMED'`) instead of
4088
+ * on-chain transaction confirmation via the adapter.
4089
+ */
4090
+ to?: Adapter<TToAdapterCapabilities>;
2873
4091
  }
2874
4092
  /**
2875
4093
  * Result of analyzing bridge steps to determine retry feasibility and continuation point.
@@ -2966,6 +4184,7 @@ declare abstract class BridgingProvider<TProviderActions = Record<string, unknow
2966
4184
  * @param source - The source chain definition
2967
4185
  * @param destination - The destination chain definition
2968
4186
  * @param token - The token to transfer (currently only USDC is supported)
4187
+ * @param useForwarder - When `true`, also checks that the route supports forwarding
2969
4188
  * @returns `true` if the provider supports this route, `false` otherwise
2970
4189
  *
2971
4190
  * @example
@@ -2977,7 +4196,7 @@ declare abstract class BridgingProvider<TProviderActions = Record<string, unknow
2977
4196
  * }
2978
4197
  * ```
2979
4198
  */
2980
- abstract supportsRoute(source: ChainDefinition, destination: ChainDefinition, token: 'USDC'): boolean;
4199
+ abstract supportsRoute(source: ChainDefinition, destination: ChainDefinition, token: 'USDC', useForwarder?: boolean): boolean;
2981
4200
  /**
2982
4201
  * Executes a cross-chain bridge operation between the specified source and destination chains.
2983
4202
  *
@@ -3098,6 +4317,8 @@ declare abstract class BridgingProvider<TProviderActions = Record<string, unknow
3098
4317
  *
3099
4318
  * @param result - The failed bridge result to retry
3100
4319
  * @param context - The retry context containing source and destination adapter contexts
4320
+ * @param invocationMeta - Optional invocation metadata for tracing and correlation.
4321
+ * When provided, enables custom traceId, runtime overrides, and caller chain tracking.
3101
4322
  * @returns Promise resolving to the retry bridge result
3102
4323
  * @throws {Error} If retry is not supported by this provider
3103
4324
  *
@@ -3113,7 +4334,7 @@ declare abstract class BridgingProvider<TProviderActions = Record<string, unknow
3113
4334
  * }
3114
4335
  * ```
3115
4336
  */
3116
- retry<TFromAdapterCapabilities extends AdapterCapabilities, TToAdapterCapabilities extends AdapterCapabilities>(result: BridgeResult, context: RetryContext<TFromAdapterCapabilities, TToAdapterCapabilities>): Promise<BridgeResult>;
4337
+ retry<TFromAdapterCapabilities extends AdapterCapabilities, TToAdapterCapabilities extends AdapterCapabilities>(result: BridgeResult, context: RetryContext<TFromAdapterCapabilities, TToAdapterCapabilities>, invocationMeta?: InvocationMeta): Promise<BridgeResult>;
3117
4338
  /**
3118
4339
  * Analyzes bridge steps to determine retry feasibility and continuation point.
3119
4340
  *
@@ -3286,6 +4507,21 @@ interface AttestationMessage {
3286
4507
  * The delay reason if the attestation is delayed.
3287
4508
  */
3288
4509
  delayReason?: string | null;
4510
+ /**
4511
+ * Forwarding state from Circle's relayer.
4512
+ * Only present when useForwarder was enabled during burn.
4513
+ * @description
4514
+ * - 'PENDING': Relayer is processing the mint
4515
+ * - 'CONFIRMED': Relayer has submitted the mint tx (waiting for finality)
4516
+ * - 'COMPLETE': Relayer has successfully completed the mint tx with finality
4517
+ * - 'FAILED': Relayer failed to process the mint (user may need manual mint)
4518
+ */
4519
+ forwardState?: 'PENDING' | 'CONFIRMED' | 'COMPLETE' | 'FAILED' | null;
4520
+ /**
4521
+ * Transaction hash of the mint tx submitted by Circle's relayer.
4522
+ * Only present when forwardState is 'CONFIRMED' or 'COMPLETE'.
4523
+ */
4524
+ forwardTxHash?: string | null;
3289
4525
  }
3290
4526
 
3291
4527
  /**
@@ -3319,6 +4555,66 @@ type BridgeFetchAttestationStep = BridgeStep &
3319
4555
  data?: undefined;
3320
4556
  });
3321
4557
 
4558
+ /**
4559
+ * Forwarder-only destination for CCTP v2 transfers without an adapter.
4560
+ *
4561
+ * Used when Circle's Forwarder handles the mint transaction and no destination
4562
+ * adapter is available. Requires both `useForwarder: true` and a `recipientAddress`.
4563
+ *
4564
+ * When using this destination type:
4565
+ * - The mint step completes when the IRIS API confirms `forwardState === 'CONFIRMED'`
4566
+ * - No on-chain transaction confirmation is performed (no adapter available)
4567
+ * - The mint step's `data` field will be undefined (no transaction receipt)
4568
+ */
4569
+ interface CCTPV2ForwarderOnlyDestination<TChainDefinition extends ChainDefinitionWithCCTPv2 = ChainDefinitionWithCCTPv2> {
4570
+ /** The destination chain where USDC will be minted */
4571
+ chain: TChainDefinition;
4572
+ /** The recipient address that will receive the minted USDC */
4573
+ recipientAddress: string;
4574
+ /** Must be true for forwarder-only destinations */
4575
+ useForwarder: true;
4576
+ /** The resolved address (same as recipientAddress for forwarder-only) */
4577
+ address?: string;
4578
+ }
4579
+ /**
4580
+ * Destination context for CCTP v2 transfers with optional forwarder support.
4581
+ *
4582
+ * Supports two modes:
4583
+ * 1. **With adapter**: Standard destination where user or forwarder submits mint transaction.
4584
+ * The adapter is used for chain validation and transaction confirmation.
4585
+ * 2. **Forwarder-only**: No adapter provided. Circle's Orbit relayer handles the mint
4586
+ * and confirmation is based on IRIS API response only.
4587
+ *
4588
+ * @example
4589
+ * ```typescript
4590
+ * // With adapter (standard or forwarder-assisted)
4591
+ * const dest1: CCTPV2DestinationContext = {
4592
+ * adapter,
4593
+ * chain: BaseSepolia,
4594
+ * address: '0x...',
4595
+ * useForwarder: true // optional
4596
+ * }
4597
+ *
4598
+ * // Forwarder-only (no adapter)
4599
+ * const dest2: CCTPV2DestinationContext = {
4600
+ * chain: BaseSepolia,
4601
+ * recipientAddress: '0x...',
4602
+ * useForwarder: true
4603
+ * }
4604
+ * ```
4605
+ */
4606
+ type CCTPV2DestinationContext<TAdapterCapabilities extends AdapterCapabilities = AdapterCapabilities, TChainDefinition extends ChainDefinitionWithCCTPv2 = ChainDefinitionWithCCTPv2> = (DestinationWalletContext<TAdapterCapabilities, TChainDefinition> & {
4607
+ /**
4608
+ * Enable Circle's Forwarder to handle the mint transaction.
4609
+ *
4610
+ * When true, Circle's Orbit relayer will fetch the attestation and submit
4611
+ * the mint transaction on the user's behalf. The relay fee is deducted from
4612
+ * the minted USDC at mint time.
4613
+ *
4614
+ * @defaultValue false
4615
+ */
4616
+ useForwarder?: boolean;
4617
+ }) | CCTPV2ForwarderOnlyDestination<TChainDefinition>;
3322
4618
  /**
3323
4619
  * CCTPv2 bridge parameters.
3324
4620
  *
@@ -3332,31 +4628,56 @@ type CCTPV2BridgeParams<TFromAdapterCapabilities extends AdapterCapabilities = A
3332
4628
  */
3333
4629
  source: WalletContext<TFromAdapterCapabilities, ChainDefinitionWithCCTPv2>;
3334
4630
  /**
3335
- * The destination wallet context containing the chain definition and wallet address.
4631
+ * The destination wallet context containing the chain definition, wallet address,
4632
+ * and optional forwarder configuration.
3336
4633
  */
3337
- destination: DestinationWalletContext<TToAdapterCapabilities, ChainDefinitionWithCCTPv2>;
4634
+ destination: CCTPV2DestinationContext<TToAdapterCapabilities>;
3338
4635
  /**
3339
4636
  * The bridge configuration for the CCTPv2 transfer.
3340
4637
  */
3341
4638
  config: BridgeConfig;
3342
4639
  };
4640
+ /**
4641
+ * Base payload structure for CCTP v2 action events.
4642
+ *
4643
+ * @remarks
4644
+ * All CCTP v2 actions share these common fields for protocol identification
4645
+ * and tracing support.
4646
+ */
4647
+ interface CCTPV2ActionBase {
4648
+ /** The protocol identifier */
4649
+ protocol: 'cctp';
4650
+ /** The protocol version */
4651
+ version: 'v2';
4652
+ /**
4653
+ * Optional trace ID for end-to-end correlation.
4654
+ *
4655
+ * When provided, this ID links all events in a single bridge operation, enabling
4656
+ * integration with distributed tracing systems (OpenTelemetry, Datadog, etc.).
4657
+ *
4658
+ * Format: 32-character hex string or custom string (user-provided via invocation context).
4659
+ */
4660
+ traceId?: string;
4661
+ }
3343
4662
  /**
3344
4663
  * Action types supported by the CCTP v2 provider.
3345
4664
  *
3346
4665
  * @remarks
3347
4666
  * This interface defines the structure of actions that can be dispatched during
3348
- * CCTP v2 transfer operations. Each action includes protocol metadata and a
3349
- * `values` field containing the full bridge step with transaction details.
4667
+ * CCTP v2 transfer operations. Each action includes protocol metadata, an optional
4668
+ * `traceId` for correlation, and a `values` field containing the full bridge step
4669
+ * with transaction details.
3350
4670
  *
3351
4671
  * All transaction-based steps (approve, burn, mint) include `txHash` and
3352
4672
  * `explorerUrl` fields for direct links to block explorers.
3353
4673
  *
3354
4674
  * @example
3355
4675
  * ```typescript
3356
- * // Action structure received by event listeners
4676
+ * // Action structure received by event listeners (with traceId)
3357
4677
  * const burnAction: CCTPV2Actions['burn'] = {
3358
4678
  * protocol: 'cctp',
3359
4679
  * version: 'v2',
4680
+ * traceId: '550e8400-e29b-41d4-a716-446655440000', // optional
3360
4681
  * method: 'burn',
3361
4682
  * values: {
3362
4683
  * name: 'burn',
@@ -3373,9 +4694,7 @@ interface CCTPV2Actions {
3373
4694
  * Approval action for CCTP v2 transfers.
3374
4695
  * Used to approve token spending before initiating a burn operation.
3375
4696
  */
3376
- approve: {
3377
- protocol: 'cctp';
3378
- version: 'v2';
4697
+ approve: CCTPV2ActionBase & {
3379
4698
  method: 'approve';
3380
4699
  values: BridgeStep;
3381
4700
  };
@@ -3383,9 +4702,7 @@ interface CCTPV2Actions {
3383
4702
  * Burn action for CCTP v2 transfers.
3384
4703
  * Used to burn tokens on the source chain to initiate a cross-chain transfer.
3385
4704
  */
3386
- burn: {
3387
- protocol: 'cctp';
3388
- version: 'v2';
4705
+ burn: CCTPV2ActionBase & {
3389
4706
  method: 'burn';
3390
4707
  values: BridgeStep;
3391
4708
  };
@@ -3393,9 +4710,7 @@ interface CCTPV2Actions {
3393
4710
  * Attestation action for CCTP v2 transfers.
3394
4711
  * Used to fetch the attestation message for the source wallet.
3395
4712
  */
3396
- fetchAttestation: {
3397
- protocol: 'cctp';
3398
- version: 'v2';
4713
+ fetchAttestation: CCTPV2ActionBase & {
3399
4714
  method: 'fetchAttestation';
3400
4715
  values: BridgeFetchAttestationStep;
3401
4716
  };
@@ -3403,9 +4718,7 @@ interface CCTPV2Actions {
3403
4718
  * Mint action for CCTP v2 transfers.
3404
4719
  * Used to mint tokens on the destination chain after a successful burn.
3405
4720
  */
3406
- mint: {
3407
- protocol: 'cctp';
3408
- version: 'v2';
4721
+ mint: CCTPV2ActionBase & {
3409
4722
  method: 'mint';
3410
4723
  values: BridgeStep;
3411
4724
  };
@@ -3413,9 +4726,7 @@ interface CCTPV2Actions {
3413
4726
  * Re-attestation action for CCTP v2 transfers.
3414
4727
  * Used to request a fresh attestation when the original has expired.
3415
4728
  */
3416
- reAttest: {
3417
- protocol: 'cctp';
3418
- version: 'v2';
4729
+ reAttest: CCTPV2ActionBase & {
3419
4730
  method: 'reAttest';
3420
4731
  values: BridgeFetchAttestationStep;
3421
4732
  };
@@ -3607,7 +4918,7 @@ declare class CCTPV2BridgingProvider extends BridgingProvider<CCTPV2Actions> imp
3607
4918
  * const retryResult = await provider.retry(failedResult, retryContext)
3608
4919
  * ```
3609
4920
  */
3610
- retry<TFromAdapterCapabilities extends AdapterCapabilities, TToAdapterCapabilities extends AdapterCapabilities>(result: BridgeResult, context: RetryContext<TFromAdapterCapabilities, TToAdapterCapabilities>): Promise<BridgeResult>;
4921
+ retry<TFromAdapterCapabilities extends AdapterCapabilities, TToAdapterCapabilities extends AdapterCapabilities>(result: BridgeResult, context: RetryContext<TFromAdapterCapabilities, TToAdapterCapabilities>, invocationMeta?: InvocationMeta): Promise<BridgeResult>;
3611
4922
  /**
3612
4923
  * Estimate the cost and fees for a CCTP v2 cross-chain bridge operation.
3613
4924
  *
@@ -3616,7 +4927,9 @@ declare class CCTPV2BridgingProvider extends BridgingProvider<CCTPV2Actions> imp
3616
4927
  * chains, as well as any applicable protocol fees.
3617
4928
  *
3618
4929
  * @param params - The bridge parameters containing source, destination, amount, and optional config.
4930
+ * Supports optional `invocation` for tracing and correlation.
3619
4931
  * @returns Promise resolving to detailed cost breakdown including:
4932
+ * - `traceId`: Correlation ID from invocation context (if provided)
3620
4933
  * - `gasFees`: Array of gas estimates for each step (Approve, Burn, Mint)
3621
4934
  * - Gas amounts in native token smallest units (wei for ETH, lamports for SOL, etc.)
3622
4935
  * - `fees`: Array of protocol and kit fees
@@ -3627,16 +4940,29 @@ declare class CCTPV2BridgingProvider extends BridgingProvider<CCTPV2Actions> imp
3627
4940
  *
3628
4941
  * @example
3629
4942
  * ```typescript
4943
+ * import {
4944
+ * resolveInvocationContext,
4945
+ * createRuntime,
4946
+ * } from '\@core/runtime'
4947
+ * import { createTokenRegistry } from '\@core/tokens'
4948
+ *
4949
+ * const defaults = {
4950
+ * runtime: createRuntime(),
4951
+ * tokens: createTokenRegistry(),
4952
+ * }
4953
+ *
3630
4954
  * const estimate = await provider.estimate({
3631
4955
  * source: { adapter: sourceAdapter, chain: 'Ethereum' },
3632
4956
  * destination: { adapter: destAdapter, chain: 'Base' },
3633
4957
  * amount: '10.50',
3634
- * token: 'USDC'
4958
+ * token: 'USDC',
4959
+ * invocationMeta: {
4960
+ * callers: [{ type: 'app', name: 'MyDApp', version: '1.0.0' }],
4961
+ * },
3635
4962
  * })
3636
4963
  *
3637
- * console.log('Total cost:', estimate.totalCost)
3638
- * console.log('Source gas:', estimate.sourceGas)
3639
- * console.log('Destination gas:', estimate.destinationGas)
4964
+ * console.log('Total gas fees:', estimate.gasFees.length)
4965
+ * console.log('Protocol fees:', estimate.fees.length)
3640
4966
  * ```
3641
4967
  */
3642
4968
  estimate<TFromAdapterCapabilities extends AdapterCapabilities, TToAdapterCapabilities extends AdapterCapabilities>(params: CCTPV2BridgeParams<TFromAdapterCapabilities, TToAdapterCapabilities>): Promise<EstimateResult>;
@@ -3655,7 +4981,8 @@ declare class CCTPV2BridgingProvider extends BridgingProvider<CCTPV2Actions> imp
3655
4981
  */
3656
4982
  private addGasFeeEstimate;
3657
4983
  /**
3658
- * Helper method to add provider fee estimates to the result.
4984
+ * Helper method to add provider and forwarder fee estimates to the result.
4985
+ * Only adds fee entries when the fee is greater than 0.
3659
4986
  */
3660
4987
  private addProviderFeeEstimate;
3661
4988
  /**
@@ -3832,10 +5159,14 @@ declare class CCTPV2BridgingProvider extends BridgingProvider<CCTPV2Actions> imp
3832
5159
  *
3833
5160
  * This method validates that both chains have CCTP v2 contracts deployed and configured.
3834
5161
  * It uses the `isCCTPV2Supported` guard function to check each chain individually.
5162
+ * When `useForwarder` is `true`, additionally checks that the source chain supports
5163
+ * forwarding as source and the destination chain supports forwarding as destination.
3835
5164
  *
3836
5165
  * @param source - The source chain definition to check for CCTP v2 support
3837
5166
  * @param destination - The destination chain definition to check for CCTP v2 support
3838
- * @returns `true` if both chains support CCTP v2, `false` otherwise
5167
+ * @param token - The token to transfer (currently only USDC is supported)
5168
+ * @param useForwarder - When `true`, also checks that the route supports forwarding
5169
+ * @returns `true` if both chains support CCTP v2 (and forwarding if requested), `false` otherwise
3839
5170
  *
3840
5171
  * @example
3841
5172
  * ```typescript
@@ -3844,19 +5175,30 @@ declare class CCTPV2BridgingProvider extends BridgingProvider<CCTPV2Actions> imp
3844
5175
  *
3845
5176
  * if (canTransfer) {
3846
5177
  * console.log('CCTP v2 transfer is supported between these chains')
3847
- * } else {
3848
- * console.log('One or both chains do not support CCTP v2')
5178
+ * }
5179
+ *
5180
+ * const canForward = provider.supportsRoute(Ethereum, Base, 'USDC', true)
5181
+ *
5182
+ * if (canForward) {
5183
+ * console.log('CCTP v2 transfer with forwarding is supported')
3849
5184
  * }
3850
5185
  * ```
3851
5186
  */
3852
- supportsRoute(source: ChainDefinition, destination: ChainDefinition, token: 'USDC'): boolean;
5187
+ supportsRoute(source: ChainDefinition, destination: ChainDefinition, token: 'USDC', useForwarder?: boolean): boolean;
3853
5188
  /**
3854
5189
  * Determines the appropriate maximum fee for a cross-chain bridge operation.
3855
5190
  *
3856
- * For FAST bridge operations, it calculates a dynamic fee based on the bridge amount
3857
- * and fast bridge burn fee, or uses a provided maxFee if specified.
5191
+ * The fee calculation depends on transfer speed and forwarding settings:
3858
5192
  *
3859
- * For SLOW bridge operations, it returns 0 as there are no additional fees.
5193
+ * | Transfer Speed | useForwarder | maxFee provided | Behavior |
5194
+ * |----------------|--------------|-----------------|----------|
5195
+ * | SLOW | false | N/A | maxFee = 0 |
5196
+ * | SLOW | true | No | maxFee = forwardingFee |
5197
+ * | SLOW | true | Yes | maxFee = config.maxFee |
5198
+ * | FAST | false | No | maxFee = calculatedBurnFee |
5199
+ * | FAST | false | Yes | maxFee = config.maxFee |
5200
+ * | FAST | true | No | maxFee = calculatedBurnFee + forwardingFee |
5201
+ * | FAST | true | Yes | maxFee = config.maxFee |
3860
5202
  *
3861
5203
  * @param params - The bridge parameters object containing:
3862
5204
  * - `source`: The source wallet context with chain definition and adapter
@@ -3882,7 +5224,10 @@ declare class CCTPV2BridgingProvider extends BridgingProvider<CCTPV2Actions> imp
3882
5224
  * console.log('Max fee:', maxFee)
3883
5225
  * ```
3884
5226
  */
3885
- getMaxFee<TFromAdapterCapabilities extends AdapterCapabilities, TToAdapterCapabilities extends AdapterCapabilities>(params: BridgeParams<TFromAdapterCapabilities, TToAdapterCapabilities>): Promise<bigint>;
5227
+ getMaxFee<TFromAdapterCapabilities extends AdapterCapabilities, TToAdapterCapabilities extends AdapterCapabilities>(params: BridgeParams<TFromAdapterCapabilities, TToAdapterCapabilities>): Promise<{
5228
+ providerFee: bigint;
5229
+ forwarderFee: bigint;
5230
+ }>;
3886
5231
  /**
3887
5232
  * Prepares a CCTP v2 burn operation to initiate a cross-chain bridge operation.
3888
5233
  *
@@ -3971,6 +5316,29 @@ rawAddress: string,
3971
5316
  /** The USDC mint address (ignored for EVM chains, required base58 address for Solana) */
3972
5317
  mintAddress: string) => Promise<string>;
3973
5318
 
5319
+ /**
5320
+ * Validates and converts a fee value to bigint.
5321
+ *
5322
+ * This utility performs:
5323
+ * 1. Conversion from string or number to bigint
5324
+ * 2. Validation that the value is non-negative
5325
+ *
5326
+ * @param value - The fee value to validate and convert (string or number)
5327
+ * @param fieldName - The name of the field for error messages
5328
+ * @returns The validated fee as a bigint
5329
+ * @throws {KitError} If the value cannot be converted to bigint or is negative
5330
+ *
5331
+ * @example
5332
+ * ```typescript
5333
+ * const fee = validateAndConvertFee('1000000', 'minimumFee')
5334
+ * console.log(fee) // 1000000n
5335
+ *
5336
+ * const fee2 = validateAndConvertFee(500, 'forwardingFee')
5337
+ * console.log(fee2) // 500n
5338
+ * ```
5339
+ */
5340
+ declare function validateAndConvertFee(value: number | string, fieldName: string): bigint;
5341
+
3974
5342
  /** A block number value that can be provided as bigint, number, or string. */
3975
5343
  type BlockNumberInput = bigint | number | string | undefined;
3976
5344
  /**
@@ -4068,5 +5436,5 @@ declare const getBlocksUntilExpiry: (attestation: AttestationMessage, currentBlo
4068
5436
  */
4069
5437
  declare const isMintFailureRelatedToAttestation: (error: unknown) => boolean;
4070
5438
 
4071
- export { CCTPV2BridgingProvider, getBlocksUntilExpiry, getMintRecipientAccount, isAttestationExpired, isMintFailureRelatedToAttestation };
5439
+ export { CCTPV2BridgingProvider, getBlocksUntilExpiry, getMintRecipientAccount, isAttestationExpired, isMintFailureRelatedToAttestation, validateAndConvertFee };
4072
5440
  export type { CCTPV2Config };