@circle-fin/app-kit 1.4.2 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.mjs CHANGED
@@ -3398,6 +3398,8 @@ var Blockchain;
3398
3398
  Blockchain["Hedera_Testnet"] = "Hedera_Testnet";
3399
3399
  Blockchain["HyperEVM"] = "HyperEVM";
3400
3400
  Blockchain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
3401
+ Blockchain["Injective"] = "Injective";
3402
+ Blockchain["Injective_Testnet"] = "Injective_Testnet";
3401
3403
  Blockchain["Ink"] = "Ink";
3402
3404
  Blockchain["Ink_Testnet"] = "Ink_Testnet";
3403
3405
  Blockchain["Linea"] = "Linea";
@@ -3617,6 +3619,7 @@ var BridgeChain;
3617
3619
  BridgeChain["Edge"] = "Edge";
3618
3620
  BridgeChain["Ethereum"] = "Ethereum";
3619
3621
  BridgeChain["HyperEVM"] = "HyperEVM";
3622
+ BridgeChain["Injective"] = "Injective";
3620
3623
  BridgeChain["Ink"] = "Ink";
3621
3624
  BridgeChain["Linea"] = "Linea";
3622
3625
  BridgeChain["Monad"] = "Monad";
@@ -3640,6 +3643,7 @@ var BridgeChain;
3640
3643
  BridgeChain["Edge_Testnet"] = "Edge_Testnet";
3641
3644
  BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
3642
3645
  BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
3646
+ BridgeChain["Injective_Testnet"] = "Injective_Testnet";
3643
3647
  BridgeChain["Ink_Testnet"] = "Ink_Testnet";
3644
3648
  BridgeChain["Linea_Sepolia"] = "Linea_Sepolia";
3645
3649
  BridgeChain["Monad_Testnet"] = "Monad_Testnet";
@@ -5084,6 +5088,98 @@ const HyperEVMTestnet = defineChain({
5084
5088
  },
5085
5089
  });
5086
5090
 
5091
+ /**
5092
+ * Injective Mainnet chain definition
5093
+ * @remarks
5094
+ * This represents the official production network for the Injective blockchain.
5095
+ * Injective is a high-performance, interoperable Layer-1 blockchain built for
5096
+ * finance, with an EVM execution layer on top of a Cosmos SDK base and
5097
+ * sub-second block finality.
5098
+ */
5099
+ const Injective = defineChain({
5100
+ type: 'evm',
5101
+ chain: Blockchain.Injective,
5102
+ name: 'Injective',
5103
+ title: 'Injective Mainnet',
5104
+ nativeCurrency: {
5105
+ name: 'Injective',
5106
+ symbol: 'INJ',
5107
+ decimals: 18,
5108
+ },
5109
+ chainId: 1776,
5110
+ isTestnet: false,
5111
+ explorerUrl: 'https://injscan.com/transaction/{hash}',
5112
+ rpcEndpoints: ['https://sentry.evm-rpc.injective.network'],
5113
+ eurcAddress: null,
5114
+ usdcAddress: '0xa00C59fF5a080D2b954d0c75e46E22a0c371235a',
5115
+ usdtAddress: null,
5116
+ cctp: {
5117
+ domain: 29,
5118
+ contracts: {
5119
+ v2: {
5120
+ type: 'split',
5121
+ tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5122
+ messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5123
+ confirmations: 1,
5124
+ fastConfirmations: 1,
5125
+ },
5126
+ },
5127
+ forwarderSupported: {
5128
+ source: false,
5129
+ destination: false,
5130
+ },
5131
+ },
5132
+ kitContracts: {
5133
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
5134
+ },
5135
+ });
5136
+
5137
+ /**
5138
+ * Injective Testnet chain definition
5139
+ * @remarks
5140
+ * This represents the official test network for the Injective blockchain.
5141
+ * Injective is a high-performance, interoperable Layer-1 blockchain built for
5142
+ * finance, with an EVM execution layer on top of a Cosmos SDK base and
5143
+ * sub-second block finality.
5144
+ */
5145
+ const InjectiveTestnet = defineChain({
5146
+ type: 'evm',
5147
+ chain: Blockchain.Injective_Testnet,
5148
+ name: 'Injective Testnet',
5149
+ title: 'Injective Testnet',
5150
+ nativeCurrency: {
5151
+ name: 'Injective',
5152
+ symbol: 'INJ',
5153
+ decimals: 18,
5154
+ },
5155
+ chainId: 1439,
5156
+ isTestnet: true,
5157
+ explorerUrl: 'https://testnet.explorer.injective.network/transaction/{hash}',
5158
+ rpcEndpoints: ['https://k8s.testnet.json-rpc.injective.network'],
5159
+ eurcAddress: null,
5160
+ usdcAddress: '0x0C382e685bbeeFE5d3d9C29e29E341fEE8E84C5d',
5161
+ usdtAddress: null,
5162
+ cctp: {
5163
+ domain: 29,
5164
+ contracts: {
5165
+ v2: {
5166
+ type: 'split',
5167
+ tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5168
+ messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
5169
+ confirmations: 1,
5170
+ fastConfirmations: 1,
5171
+ },
5172
+ },
5173
+ forwarderSupported: {
5174
+ source: false,
5175
+ destination: false,
5176
+ },
5177
+ },
5178
+ kitContracts: {
5179
+ bridge: BRIDGE_CONTRACT_EVM_TESTNET,
5180
+ },
5181
+ });
5182
+
5087
5183
  /**
5088
5184
  * Ink Mainnet chain definition
5089
5185
  * @remarks
@@ -6926,6 +7022,8 @@ var Chains = /*#__PURE__*/Object.freeze({
6926
7022
  HederaTestnet: HederaTestnet,
6927
7023
  HyperEVM: HyperEVM,
6928
7024
  HyperEVMTestnet: HyperEVMTestnet,
7025
+ Injective: Injective,
7026
+ InjectiveTestnet: InjectiveTestnet,
6929
7027
  Ink: Ink,
6930
7028
  InkTestnet: InkTestnet,
6931
7029
  Linea: Linea,
@@ -7547,6 +7645,44 @@ function resolveChainIdentifier(chainIdentifier) {
7547
7645
  throw new Error(`Invalid chain identifier type: ${typeof chainIdentifier}. Expected ChainDefinition object, Blockchain enum, or string literal.`);
7548
7646
  }
7549
7647
 
7648
+ /**
7649
+ * Resolve a chain identifier to a plain chain-name string.
7650
+ *
7651
+ * Accept a string literal (`'Ethereum'`), a `ChainDefinition`-like
7652
+ * object (`{ chain: 'Ethereum' }`), or `null`/`undefined` and return
7653
+ * the chain name as a string. Return `undefined` when the value
7654
+ * cannot be resolved.
7655
+ *
7656
+ * @remarks
7657
+ * Unlike `resolveChainIdentifier` (which returns a full `ChainDefinition`
7658
+ * and throws on invalid input), this helper is intentionally lenient and
7659
+ * never throws — it is safe to call in error-handling and telemetry paths.
7660
+ *
7661
+ * @param value - A string, chain-definition object, or nullish value.
7662
+ * @returns The chain name string, or `undefined`.
7663
+ *
7664
+ * @example
7665
+ * ```typescript
7666
+ * import { resolveChainName } from '@core/chains'
7667
+ *
7668
+ * resolveChainName('Ethereum') // 'Ethereum'
7669
+ * resolveChainName({ chain: 'Ethereum' }) // 'Ethereum'
7670
+ * resolveChainName(undefined) // undefined
7671
+ * ```
7672
+ */
7673
+ function resolveChainName(value) {
7674
+ if (value == null)
7675
+ return undefined;
7676
+ if (typeof value === 'string')
7677
+ return value;
7678
+ if (typeof value === 'object' &&
7679
+ 'chain' in value &&
7680
+ typeof value.chain === 'string') {
7681
+ return value.chain;
7682
+ }
7683
+ return undefined;
7684
+ }
7685
+
7550
7686
  /**
7551
7687
  * @packageDocumentation
7552
7688
  * @module SwapTokenUtils
@@ -9203,6 +9339,7 @@ const USDC = {
9203
9339
  [Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
9204
9340
  [Blockchain.Hedera]: '0.0.456858',
9205
9341
  [Blockchain.HyperEVM]: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
9342
+ [Blockchain.Injective]: '0xa00C59fF5a080D2b954d0c75e46E22a0c371235a',
9206
9343
  [Blockchain.Ink]: '0x2D270e6886d130D724215A266106e6832161EAEd',
9207
9344
  [Blockchain.Linea]: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
9208
9345
  [Blockchain.Monad]: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
@@ -9235,6 +9372,7 @@ const USDC = {
9235
9372
  [Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
9236
9373
  [Blockchain.Hedera_Testnet]: '0.0.429274',
9237
9374
  [Blockchain.HyperEVM_Testnet]: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
9375
+ [Blockchain.Injective_Testnet]: '0x0C382e685bbeeFE5d3d9C29e29E341fEE8E84C5d',
9238
9376
  [Blockchain.Ink_Testnet]: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
9239
9377
  [Blockchain.Linea_Sepolia]: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
9240
9378
  [Blockchain.Monad_Testnet]: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
@@ -10336,8 +10474,325 @@ async function retryAsync(fn, options) {
10336
10474
  throw new Error('retryAsync: unreachable');
10337
10475
  }
10338
10476
 
10477
+ /**
10478
+ * Default telemetry endpoint.
10479
+ *
10480
+ * Override via the `STABLECOIN_KITS_TELEMETRY_URL` environment variable
10481
+ * (e.g. for staging or local development).
10482
+ *
10483
+ * @internal
10484
+ */
10485
+ const DEFAULT_LOGS_URL = 'https://api.circle.com/v1/stablecoinKits/logs';
10486
+ /**
10487
+ * Resolve the telemetry endpoint URL.
10488
+ *
10489
+ * @internal
10490
+ */
10491
+ function getLogsUrl() {
10492
+ if (isNodeEnvironment() &&
10493
+ typeof process.env['STABLECOIN_KITS_TELEMETRY_URL'] === 'string' &&
10494
+ process.env['STABLECOIN_KITS_TELEMETRY_URL'].length > 0) {
10495
+ return process.env['STABLECOIN_KITS_TELEMETRY_URL'];
10496
+ }
10497
+ return DEFAULT_LOGS_URL;
10498
+ }
10499
+ /**
10500
+ * Send a telemetry event to the proxy service.
10501
+ *
10502
+ * @remarks
10503
+ * Fire-and-forget: the returned promise is intentionally not awaited
10504
+ * by the caller. A fetch failure (network error, non-2xx, timeout)
10505
+ * is silently swallowed so telemetry never blocks or fails user
10506
+ * operations.
10507
+ *
10508
+ * @param payload - The structured log payload matching the server schema.
10509
+ *
10510
+ * @example
10511
+ * ```typescript
10512
+ * import { emitAnalyticsLog } from '@core/utils'
10513
+ *
10514
+ * // Fire-and-forget — do not await
10515
+ * void emitAnalyticsLog(payload)
10516
+ * ```
10517
+ */
10518
+ async function emitAnalyticsLog(payload) {
10519
+ try {
10520
+ const isNode = isNodeEnvironment();
10521
+ const userAgent = getUserAgent();
10522
+ await fetch(getLogsUrl(), {
10523
+ method: 'POST',
10524
+ headers: {
10525
+ 'Content-Type': 'application/json',
10526
+ // Browser restricts setting User-Agent; use X-User-Agent instead.
10527
+ ...(isNode
10528
+ ? { 'User-Agent': userAgent }
10529
+ : { 'X-User-Agent': userAgent }),
10530
+ },
10531
+ body: JSON.stringify(payload),
10532
+ signal: AbortSignal.timeout(5_000),
10533
+ });
10534
+ }
10535
+ catch {
10536
+ // Silently swallow — telemetry must never break user operations.
10537
+ }
10538
+ }
10539
+
10540
+ /**
10541
+ * Build the `clientContext` object for telemetry payloads.
10542
+ *
10543
+ * @remarks
10544
+ * Use the exported `getRuntime()` and `isNodeEnvironment()` from
10545
+ * `@core/utils` to detect the runtime environment. The returned
10546
+ * string is parsed into the structured `ClientContext` fields
10547
+ * expected by the server schema.
10548
+ *
10549
+ * @returns A {@link ClientContext} with platform, OS, and runtime name
10550
+ * populated from the current environment.
10551
+ *
10552
+ * @example
10553
+ * ```typescript
10554
+ * import { buildClientContext } from '@core/utils'
10555
+ *
10556
+ * const ctx = buildClientContext()
10557
+ * // Node: { platform: 'node', os: 'darwin', runtimeName: null }
10558
+ * // Browser: { platform: 'browser', os: null, runtimeName: 'chrome' }
10559
+ * ```
10560
+ */
10561
+ function buildClientContext() {
10562
+ const runtime = getRuntime();
10563
+ if (runtime.startsWith('browser/')) {
10564
+ return {
10565
+ platform: 'browser',
10566
+ os: null,
10567
+ runtimeName: runtime.slice('browser/'.length).toLowerCase(),
10568
+ };
10569
+ }
10570
+ if (runtime.startsWith('node/')) {
10571
+ return {
10572
+ platform: 'node',
10573
+ os: isNodeEnvironment() ? process.platform : null,
10574
+ runtimeName: null,
10575
+ };
10576
+ }
10577
+ return {
10578
+ platform: 'node',
10579
+ os: null,
10580
+ runtimeName: null,
10581
+ };
10582
+ }
10583
+
10584
+ /**
10585
+ * Extract structured error details from an unknown error value.
10586
+ *
10587
+ * @remarks
10588
+ * Handle three cases:
10589
+ * - `KitError` — extract `code` and `name`.
10590
+ * - `Error` — extract `name`.
10591
+ * - Anything else — return empty details.
10592
+ *
10593
+ * Only structured, bounded fields (`errorCode`, `errorType`) are
10594
+ * included. Free-text fields (`message`, `stack`) are intentionally
10595
+ * omitted to avoid leaking secrets or PII through vendor telemetry.
10596
+ *
10597
+ * @param error - The thrown value to extract details from.
10598
+ * @returns A {@link ErrorDetails} object suitable for telemetry payloads.
10599
+ *
10600
+ * @example
10601
+ * ```typescript
10602
+ * import { extractErrorDetails } from '@core/utils'
10603
+ *
10604
+ * try {
10605
+ * await riskyOperation()
10606
+ * } catch (error) {
10607
+ * const details = extractErrorDetails(error)
10608
+ * // { errorCode: '1001', errorType: 'INPUT_NETWORK_MISMATCH' }
10609
+ * }
10610
+ * ```
10611
+ */
10612
+ function extractErrorDetails(error) {
10613
+ if (error instanceof KitError) {
10614
+ return {
10615
+ errorCode: String(error.code),
10616
+ errorType: error.name,
10617
+ };
10618
+ }
10619
+ if (error instanceof Error) {
10620
+ return {
10621
+ errorType: error.name,
10622
+ };
10623
+ }
10624
+ return {};
10625
+ }
10626
+
10627
+ /**
10628
+ * Register event handlers on an action dispatcher that emit analytics
10629
+ * telemetry for the configured events.
10630
+ *
10631
+ * @remarks
10632
+ * Subscribe to each action name in `actionEventMap`, call `mapEventToPayload`
10633
+ * for each event, and fire-and-forget `emitAnalyticsLog` if a non-null
10634
+ * payload is returned. All errors are silently swallowed so telemetry
10635
+ * never blocks or fails user operations.
10636
+ *
10637
+ * @param dispatcher - The `Actionable` instance from the kit.
10638
+ * @param sdkName - SDK package name (e.g. `'unified-balance-kit'`).
10639
+ * @param sdkVersion - SDK version string (e.g. `'1.0.0'`).
10640
+ * @param actionEventMap - Map of action names to subscribe to.
10641
+ * @param mapEventToPayload - Function that maps an action name and payload
10642
+ * to a {@link ClientLogPayload}, or `null` to skip logging.
10643
+ *
10644
+ * @example
10645
+ * ```typescript
10646
+ * import { registerTelemetryHandler } from '@core/utils'
10647
+ *
10648
+ * registerTelemetryHandler(
10649
+ * dispatcher,
10650
+ * 'unified-balance-kit',
10651
+ * '1.0.0',
10652
+ * VERB_EVENT_MAP,
10653
+ * mapSucceededEventToLog,
10654
+ * )
10655
+ * ```
10656
+ */
10657
+ function registerTelemetryHandler$1(dispatcher, sdkName, sdkVersion, actionEventMap, mapEventToPayload) {
10658
+ for (const actionName of Object.keys(actionEventMap)) {
10659
+ dispatcher.on(actionName, (payload) => {
10660
+ try {
10661
+ const log = mapEventToPayload(actionName, payload, sdkName, sdkVersion);
10662
+ if (log) {
10663
+ // Fire-and-forget — intentionally not awaited.
10664
+ void emitAnalyticsLog(log);
10665
+ }
10666
+ }
10667
+ catch {
10668
+ // Silently swallow — telemetry must never break user operations.
10669
+ }
10670
+ });
10671
+ }
10672
+ }
10673
+
10674
+ /**
10675
+ * Strip the `@circle-fin/` scope from a kit package name to produce the
10676
+ * short SDK name used in telemetry payloads.
10677
+ *
10678
+ * @param pkgName - The full npm package name (e.g. `@circle-fin/bridge-kit`).
10679
+ * @returns The unscoped kit name (e.g. `bridge-kit`).
10680
+ *
10681
+ * @example
10682
+ * ```typescript
10683
+ * import pkg from '../../package.json'
10684
+ * import { resolveKitSdkName } from '@core/utils'
10685
+ *
10686
+ * const SDK_NAME = resolveKitSdkName(pkg.name) // 'bridge-kit'
10687
+ * ```
10688
+ */
10689
+ function resolveKitSdkName(pkgName) {
10690
+ return pkgName.replace('@circle-fin/', '');
10691
+ }
10692
+
10693
+ /**
10694
+ * Build a telemetry payload from common fields.
10695
+ *
10696
+ * @internal
10697
+ */
10698
+ function buildPayload$1(config, eventType, errorDetails, context) {
10699
+ return {
10700
+ sdkName: config.sdkName,
10701
+ sdkVersion: config.sdkVersion,
10702
+ eventType,
10703
+ timestamp: new Date().toISOString(),
10704
+ errorDetails,
10705
+ clientContext: buildClientContext(),
10706
+ ...(context?.sourceChain != null && {
10707
+ sourceChain: context.sourceChain,
10708
+ }),
10709
+ ...(context?.destinationChain != null && {
10710
+ destinationChain: context.destinationChain,
10711
+ }),
10712
+ ...(context?.tokenIn != null && { tokenIn: context.tokenIn }),
10713
+ ...(context?.tokenOut != null && { tokenOut: context.tokenOut }),
10714
+ };
10715
+ }
10716
+ /**
10717
+ * Wrap an async operation with error telemetry.
10718
+ *
10719
+ * Execute `fn` and, if it throws, emit an error telemetry payload
10720
+ * before re-throwing. No-ops when `config.disabled` is `true`.
10721
+ *
10722
+ * @param fn - The async operation to execute.
10723
+ * @param eventType - The telemetry event type for this operation.
10724
+ * @param config - Per-kit SDK identity and disabled flag.
10725
+ * @param context - Optional chain/token context.
10726
+ * @returns The result of the operation.
10727
+ * @throws Re-throws any error after emitting telemetry.
10728
+ *
10729
+ * @example
10730
+ * ```typescript
10731
+ * import { withErrorTelemetry } from '@core/utils'
10732
+ *
10733
+ * const result = await withErrorTelemetry(
10734
+ * () => provider.bridge(params),
10735
+ * 'bridge_bridge',
10736
+ * { sdkName: 'bridge-kit', sdkVersion: '1.0.0', disabled: false },
10737
+ * { sourceChain: 'Ethereum', destinationChain: 'Base', tokenIn: 'USDC' },
10738
+ * )
10739
+ * ```
10740
+ */
10741
+ async function withErrorTelemetry(fn, eventType, config, context) {
10742
+ try {
10743
+ return await fn();
10744
+ }
10745
+ catch (error) {
10746
+ if (!config.disabled) {
10747
+ void emitAnalyticsLog(buildPayload$1(config, eventType, extractErrorDetails(error), context));
10748
+ }
10749
+ throw error;
10750
+ }
10751
+ }
10752
+ /**
10753
+ * Emit error telemetry for a result-reported step error.
10754
+ *
10755
+ * Handle the case where a provider reports a step failure inside a
10756
+ * result object (e.g. `BridgeResult.state === 'error'`) rather than
10757
+ * throwing. The caller extracts the failed step as a simple
10758
+ * {@link FailedStepInfo} — this function handles sanitization,
10759
+ * step-to-event mapping, and emission.
10760
+ *
10761
+ * No-ops when `config.disabled` is `true`.
10762
+ *
10763
+ * @param failedStep - The failed step info, or undefined if none found.
10764
+ * @param stepEventMap - Ordered mapping from step names to event types.
10765
+ * @param fallbackEventType - Event type when step is not in the map.
10766
+ * @param config - Per-kit SDK identity and disabled flag.
10767
+ * @param context - Optional chain/token context.
10768
+ *
10769
+ * @example
10770
+ * ```typescript
10771
+ * import { emitResultStepErrorTelemetry } from '@core/utils'
10772
+ *
10773
+ * const failedStep = result.steps.find((s) => s.state === 'error')
10774
+ * emitResultStepErrorTelemetry(
10775
+ * failedStep,
10776
+ * BRIDGE_STEP_EVENT_MAP,
10777
+ * 'bridge_bridge',
10778
+ * { sdkName: 'bridge-kit', sdkVersion: '1.0.0', disabled: false },
10779
+ * { sourceChain: 'Ethereum', tokenIn: 'USDC' },
10780
+ * )
10781
+ * ```
10782
+ */
10783
+ function emitResultStepErrorTelemetry(failedStep, stepEventMap, fallbackEventType, config, context) {
10784
+ if (config.disabled) {
10785
+ return;
10786
+ }
10787
+ const stepEntry = stepEventMap.find(([name]) => name === failedStep?.name);
10788
+ const errorDetails = {
10789
+ ...(failedStep?.name != null && { errorType: failedStep.name }),
10790
+ };
10791
+ void emitAnalyticsLog(buildPayload$1(config, stepEntry?.[1] ?? fallbackEventType, errorDetails, context));
10792
+ }
10793
+
10339
10794
  var name$2 = "@circle-fin/bridge-kit";
10340
- var version$3 = "1.9.0";
10795
+ var version$3 = "1.10.0";
10341
10796
  var pkg$3 = {
10342
10797
  name: name$2,
10343
10798
  version: version$3};
@@ -13302,18 +13757,16 @@ const buildIrisUrl = (sourceDomainId, transactionHash, isTestnet) => {
13302
13757
  };
13303
13758
  /**
13304
13759
  * Fetches attestation data from the IRIS API with retry and timeout handling.
13305
- * Since fetching starts after a confirmed burn transaction, we attempt up to 10 retries.
13306
- * Implements a conservative delay between requests to respect the API rate
13307
- * limit of 35 requests per second. To avoid rate limiting when multiple processes are
13308
- * running concurrently, we enforce a 200ms delay between retries.
13309
13760
  *
13310
- * Each HTTP request is given a maximum of 2 seconds before it is aborted.
13311
- * We retry up to 10 times, waiting 200ms between attempts.
13761
+ * Polls the IRIS API until a complete attestation is available. The default
13762
+ * window is sized for slow source chains where finality may take many
13763
+ * confirmations.
13312
13764
  *
13313
- * The total maximum time this function might take (worst case) is:
13314
- * - Perattempt timeout: 2 000 ms
13315
- * - Retry delays: 9 × 200 ms = 1 800 ms
13316
- * - Total max time: 2 000 ms + 1 800 ms = 3 800 ms
13765
+ * Defaults (see `DEFAULT_CONFIG`):
13766
+ * - Per-attempt timeout: 2 000 ms (each HTTP request aborts after 2 s)
13767
+ * - Retry delay: 2 000 ms between attempts
13768
+ * - Max retries: 600 (30 × 20)
13769
+ * - Total worst-case polling window: 600 × (2 000 ms + 2 000 ms) ≈ 40 minutes
13317
13770
  *
13318
13771
  * @param sourceDomainId - The CCTP domain ID.
13319
13772
  * @param transactionHash - The transaction hash to fetch attestation for.
@@ -15290,7 +15743,7 @@ async function buildBatchedStep(name, receipt, batchId, adapter, chain, statusCo
15290
15743
  return step;
15291
15744
  }
15292
15745
 
15293
- var version$2 = "1.7.0";
15746
+ var version$2 = "1.8.0";
15294
15747
  var pkg$2 = {
15295
15748
  version: version$2};
15296
15749
 
@@ -16956,6 +17409,35 @@ const formatBridgeResult = (result, formatDirection) => {
16956
17409
  };
16957
17410
  };
16958
17411
 
17412
+ /**
17413
+ * Telemetry event type identifiers for bridge-kit operations.
17414
+ *
17415
+ * @internal
17416
+ */
17417
+ const BRIDGE_EVENT_TYPES = {
17418
+ BRIDGE: 'bridge_bridge',
17419
+ RETRY: 'bridge_retry',
17420
+ ESTIMATE: 'bridge_estimate',
17421
+ };
17422
+ /**
17423
+ * Ordered mapping from provider step event names to telemetry event types.
17424
+ *
17425
+ * @remarks
17426
+ * The order matches the CCTP v2 bridge execution sequence. During
17427
+ * `bridge()`, completed step events are counted so the failing step
17428
+ * can be identified by its index.
17429
+ *
17430
+ * @internal
17431
+ */
17432
+ const BRIDGE_STEP_EVENT_MAP = [
17433
+ ['approve', 'bridge_approve'],
17434
+ ['burn', 'bridge_burn'],
17435
+ ['fetchAttestation', 'bridge_fetch_attestation'],
17436
+ ['mint', 'bridge_mint'],
17437
+ ];
17438
+
17439
+ /** SDK name used in telemetry payloads. */
17440
+ const SDK_NAME$2 = resolveKitSdkName(pkg$3.name);
16959
17441
  /**
16960
17442
  * BridgeKit caller component for retry and estimate operations.
16961
17443
  */
@@ -17039,6 +17521,10 @@ class BridgeKit {
17039
17521
  * A custom fee policy for the kit.
17040
17522
  */
17041
17523
  customFeePolicy;
17524
+ /** Whether error telemetry is disabled. */
17525
+ disableErrorReporting;
17526
+ /** Per-kit telemetry identity for shared helpers. */
17527
+ telemetryConfig;
17042
17528
  /**
17043
17529
  * Create a new BridgeKit instance.
17044
17530
  *
@@ -17056,6 +17542,12 @@ class BridgeKit {
17056
17542
  const defaultProviders = getDefaultProviders$2();
17057
17543
  this.providers = [...defaultProviders, ...(config.providers ?? [])];
17058
17544
  this.actionDispatcher = new Actionable();
17545
+ this.disableErrorReporting = config.disableErrorReporting === true;
17546
+ this.telemetryConfig = {
17547
+ sdkName: SDK_NAME$2,
17548
+ sdkVersion: pkg$3.version,
17549
+ disabled: this.disableErrorReporting,
17550
+ };
17059
17551
  for (const provider of this.providers) {
17060
17552
  provider.registerDispatcher(this.actionDispatcher);
17061
17553
  }
@@ -17129,19 +17621,36 @@ class BridgeKit {
17129
17621
  * ```
17130
17622
  */
17131
17623
  async bridge(params) {
17132
- // First validate the parameters
17133
- assertBridgeParams(params, bridgeParamsWithChainIdentifierSchema);
17134
- // Then resolve chain definitions (includes adapter chain support validation)
17135
- const resolvedParams = await resolveBridgeParams(params);
17136
- // Validate network compatibility
17137
- this.validateNetworkCompatibility(resolvedParams);
17138
- // Merge the custom fee config into the resolved params
17139
- const finalResolvedParams = await this.mergeCustomFeeConfig(resolvedParams);
17140
- // Find a provider that supports this route
17141
- const provider = this.findProviderForRoute(finalResolvedParams);
17142
- // Execute the transfer using the provider
17143
- // Format the bridge result into human-readable string values for the user
17144
- return formatBridgeResult(await provider.bridge(finalResolvedParams), 'to-human-readable');
17624
+ return withErrorTelemetry(async () => {
17625
+ // First validate the parameters
17626
+ assertBridgeParams(params, bridgeParamsWithChainIdentifierSchema);
17627
+ // Then resolve chain definitions (includes adapter chain support validation)
17628
+ const resolvedParams = await resolveBridgeParams(params);
17629
+ // Validate network compatibility
17630
+ this.validateNetworkCompatibility(resolvedParams);
17631
+ // Merge the custom fee config into the resolved params
17632
+ const finalResolvedParams = await this.mergeCustomFeeConfig(resolvedParams);
17633
+ // Find a provider that supports this route
17634
+ const provider = this.findProviderForRoute(finalResolvedParams);
17635
+ // Execute the transfer using the provider
17636
+ // Format the bridge result into human-readable string values for the user
17637
+ const result = formatBridgeResult(await provider.bridge(finalResolvedParams), 'to-human-readable');
17638
+ // Emit error telemetry when the provider returns an error state
17639
+ // (provider records step failures in the result instead of throwing).
17640
+ if (result.state === 'error') {
17641
+ const failedStep = result.steps.find((s) => s.state === 'error');
17642
+ emitResultStepErrorTelemetry(failedStep, BRIDGE_STEP_EVENT_MAP, BRIDGE_EVENT_TYPES.BRIDGE, this.telemetryConfig, {
17643
+ sourceChain: resolveChainName(params.from.chain),
17644
+ destinationChain: resolveChainName(params.to.chain),
17645
+ tokenIn: params.token,
17646
+ });
17647
+ }
17648
+ return result;
17649
+ }, BRIDGE_EVENT_TYPES.BRIDGE, this.telemetryConfig, {
17650
+ sourceChain: resolveChainName(params.from.chain),
17651
+ destinationChain: resolveChainName(params.to.chain),
17652
+ tokenIn: params.token,
17653
+ });
17145
17654
  }
17146
17655
  /**
17147
17656
  * Retry a failed or incomplete cross-chain USDC bridge operation.
@@ -17213,17 +17722,33 @@ class BridgeKit {
17213
17722
  * ```
17214
17723
  */
17215
17724
  async retry(result, context, invocationMeta) {
17216
- const provider = this.providers.find((p) => p.name === result.provider);
17217
- if (!provider) {
17218
- throw new Error(`Provider ${result.provider} not found`);
17219
- }
17220
- // Merge BridgeKit caller into invocation metadata for retry operation
17221
- const mergedMeta = mergeRetryInvocationMeta(invocationMeta);
17222
- // Format the bridge result into bigint string values for internal use
17223
- const formattedBridgeResultInternal = formatBridgeResult(result, 'to-internal');
17224
- // Execute the retry using the provider
17225
- // Format the bridge result into human-readable string values for the user
17226
- return formatBridgeResult(await provider.retry(formattedBridgeResultInternal, context, mergedMeta), 'to-human-readable');
17725
+ return withErrorTelemetry(async () => {
17726
+ const provider = this.providers.find((p) => p.name === result.provider);
17727
+ if (!provider) {
17728
+ throw new Error(`Provider ${result.provider} not found`);
17729
+ }
17730
+ // Merge BridgeKit caller into invocation metadata for retry operation
17731
+ const mergedMeta = mergeRetryInvocationMeta(invocationMeta);
17732
+ // Format the bridge result into bigint string values for internal use
17733
+ const formattedBridgeResultInternal = formatBridgeResult(result, 'to-internal');
17734
+ // Execute the retry using the provider
17735
+ // Format the bridge result into human-readable string values for the user
17736
+ const retryResult = formatBridgeResult(await provider.retry(formattedBridgeResultInternal, context, mergedMeta), 'to-human-readable');
17737
+ // Emit error telemetry when the provider returns an error state.
17738
+ if (retryResult.state === 'error') {
17739
+ const failedStep = retryResult.steps.find((s) => s.state === 'error');
17740
+ emitResultStepErrorTelemetry(failedStep, BRIDGE_STEP_EVENT_MAP, BRIDGE_EVENT_TYPES.RETRY, this.telemetryConfig, {
17741
+ sourceChain: result.source.chain.chain,
17742
+ destinationChain: result.destination.chain.chain,
17743
+ tokenIn: result.token,
17744
+ });
17745
+ }
17746
+ return retryResult;
17747
+ }, BRIDGE_EVENT_TYPES.RETRY, this.telemetryConfig, {
17748
+ sourceChain: result.source.chain.chain,
17749
+ destinationChain: result.destination.chain.chain,
17750
+ tokenIn: result.token,
17751
+ });
17227
17752
  }
17228
17753
  /**
17229
17754
  * Estimate the cost and fees for a cross-chain USDC bridge operation.
@@ -17262,18 +17787,24 @@ class BridgeKit {
17262
17787
  * ```
17263
17788
  */
17264
17789
  async estimate(params) {
17265
- // First validate the parameters
17266
- assertBridgeParams(params, bridgeParamsWithChainIdentifierSchema);
17267
- // Then resolve chain definitions (includes adapter chain support validation)
17268
- const resolvedParams = await resolveBridgeParams(params);
17269
- // Validate network compatibility
17270
- this.validateNetworkCompatibility(resolvedParams);
17271
- // Merge the custom fee config into the resolved params
17272
- const finalResolvedParams = await this.mergeCustomFeeConfig(resolvedParams);
17273
- // Find a provider that supports this route
17274
- const provider = this.findProviderForRoute(finalResolvedParams);
17275
- // Estimate the transfer using the provider and format amounts to human-readable strings
17276
- return formatBridgeResult(await provider.estimate(finalResolvedParams), 'to-human-readable');
17790
+ return withErrorTelemetry(async () => {
17791
+ // First validate the parameters
17792
+ assertBridgeParams(params, bridgeParamsWithChainIdentifierSchema);
17793
+ // Then resolve chain definitions (includes adapter chain support validation)
17794
+ const resolvedParams = await resolveBridgeParams(params);
17795
+ // Validate network compatibility
17796
+ this.validateNetworkCompatibility(resolvedParams);
17797
+ // Merge the custom fee config into the resolved params
17798
+ const finalResolvedParams = await this.mergeCustomFeeConfig(resolvedParams);
17799
+ // Find a provider that supports this route
17800
+ const provider = this.findProviderForRoute(finalResolvedParams);
17801
+ // Estimate the transfer using the provider and format amounts to human-readable strings
17802
+ return formatBridgeResult(await provider.estimate(finalResolvedParams), 'to-human-readable');
17803
+ }, BRIDGE_EVENT_TYPES.ESTIMATE, this.telemetryConfig, {
17804
+ sourceChain: resolveChainName(params.from.chain),
17805
+ destinationChain: resolveChainName(params.to.chain),
17806
+ tokenIn: params.token,
17807
+ });
17277
17808
  }
17278
17809
  /**
17279
17810
  * Get all chains supported by any provider in the kit, with optional filtering.
@@ -17590,7 +18121,11 @@ const createBridgeKit = (context) => {
17590
18121
  const getFee = context.getFee?.bind(context);
17591
18122
  const getFeeRecipient = context.getFeeRecipient?.bind(context);
17592
18123
  const hasBoth = typeof getFee === 'function' && typeof getFeeRecipient === 'function';
17593
- const kit = new BridgeKit();
18124
+ const kit = new BridgeKit({
18125
+ ...(context.disableErrorReporting != null && {
18126
+ disableErrorReporting: context.disableErrorReporting,
18127
+ }),
18128
+ });
17594
18129
  if (hasBoth) {
17595
18130
  kit.setCustomFeePolicy({
17596
18131
  calculateFee: async (params) => {
@@ -17607,7 +18142,7 @@ const createBridgeKit = (context) => {
17607
18142
  };
17608
18143
 
17609
18144
  var name$1 = "@circle-fin/swap-kit";
17610
- var version$1 = "1.1.1";
18145
+ var version$1 = "1.2.0";
17611
18146
  var pkg$1 = {
17612
18147
  name: name$1,
17613
18148
  version: version$1};
@@ -28068,6 +28603,18 @@ function createSwapKitContext(config = {}) {
28068
28603
  return context;
28069
28604
  }
28070
28605
 
28606
+ /**
28607
+ * Telemetry event type identifiers for swap-kit operations.
28608
+ *
28609
+ * @internal
28610
+ */
28611
+ const SWAP_EVENT_TYPES = {
28612
+ SWAP: 'swap_swap',
28613
+ ESTIMATE: 'swap_estimate',
28614
+ };
28615
+
28616
+ /** SDK name used in telemetry payloads. */
28617
+ const SDK_NAME$1 = resolveKitSdkName(pkg$1.name);
28071
28618
  /**
28072
28619
  * A high-level class-based interface for single-chain token swap operations.
28073
28620
  *
@@ -28139,6 +28686,10 @@ function createSwapKitContext(config = {}) {
28139
28686
  */
28140
28687
  class SwapKit {
28141
28688
  context;
28689
+ /** Whether error telemetry is disabled. */
28690
+ disableErrorReporting;
28691
+ /** Per-kit telemetry identity for shared helpers. */
28692
+ telemetryConfig;
28142
28693
  /**
28143
28694
  * Create a new SwapKit instance.
28144
28695
  *
@@ -28187,6 +28738,12 @@ class SwapKit {
28187
28738
  */
28188
28739
  constructor(config = {}) {
28189
28740
  this.context = createSwapKitContext(config);
28741
+ this.disableErrorReporting = config.disableErrorReporting === true;
28742
+ this.telemetryConfig = {
28743
+ sdkName: SDK_NAME$1,
28744
+ sdkVersion: pkg$1.version,
28745
+ disabled: this.disableErrorReporting,
28746
+ };
28190
28747
  }
28191
28748
  /**
28192
28749
  * Estimate the output amount and fees for a swap operation.
@@ -28228,7 +28785,11 @@ class SwapKit {
28228
28785
  * ```
28229
28786
  */
28230
28787
  async estimate(params) {
28231
- return estimate(this.context, params);
28788
+ return withErrorTelemetry(async () => estimate(this.context, params), SWAP_EVENT_TYPES.ESTIMATE, this.telemetryConfig, {
28789
+ sourceChain: resolveChainName(params.from.chain),
28790
+ tokenIn: params.tokenIn,
28791
+ tokenOut: params.tokenOut,
28792
+ });
28232
28793
  }
28233
28794
  /**
28234
28795
  * Execute a token swap operation on a single chain.
@@ -28284,7 +28845,11 @@ class SwapKit {
28284
28845
  * ```
28285
28846
  */
28286
28847
  async swap(params) {
28287
- return swap$1(this.context, params);
28848
+ return withErrorTelemetry(async () => swap$1(this.context, params), SWAP_EVENT_TYPES.SWAP, this.telemetryConfig, {
28849
+ sourceChain: resolveChainName(params.from.chain),
28850
+ tokenIn: params.tokenIn,
28851
+ tokenOut: params.tokenOut,
28852
+ });
28288
28853
  }
28289
28854
  /**
28290
28855
  * Get all chains supported by the configured swap providers.
@@ -28477,7 +29042,11 @@ const createSwapKit = (context) => {
28477
29042
  const getFee = context.getFee?.bind(context);
28478
29043
  const getFeeRecipient = context.getFeeRecipient?.bind(context);
28479
29044
  const hasBoth = typeof getFee === 'function' && typeof getFeeRecipient === 'function';
28480
- const kit = new SwapKit();
29045
+ const kit = new SwapKit({
29046
+ ...(context.disableErrorReporting != null && {
29047
+ disableErrorReporting: context.disableErrorReporting,
29048
+ }),
29049
+ });
28481
29050
  if (hasBoth) {
28482
29051
  kit.setCustomFeePolicy({
28483
29052
  computeFee: async (params) => {
@@ -29426,121 +29995,11 @@ const getSupportedChains$2 = (context, operationType, unifiedBalance) => {
29426
29995
  };
29427
29996
 
29428
29997
  var name = "@circle-fin/unified-balance-kit";
29429
- var version = "1.0.2";
29998
+ var version = "1.1.0";
29430
29999
  var pkg = {
29431
30000
  name: name,
29432
30001
  version: version};
29433
30002
 
29434
- /**
29435
- * Default telemetry endpoint.
29436
- *
29437
- * Override via the `STABLECOIN_KITS_TELEMETRY_URL` environment variable
29438
- * (e.g. for staging or local development).
29439
- *
29440
- * @internal
29441
- */
29442
- const DEFAULT_LOGS_URL = 'https://api.circle.com/v1/stablecoinKits/logs';
29443
- /**
29444
- * Resolve the telemetry endpoint URL.
29445
- *
29446
- * @internal
29447
- */
29448
- function getLogsUrl() {
29449
- if (isNodeEnvironment() &&
29450
- typeof process.env['STABLECOIN_KITS_TELEMETRY_URL'] === 'string' &&
29451
- process.env['STABLECOIN_KITS_TELEMETRY_URL'].length > 0) {
29452
- return process.env['STABLECOIN_KITS_TELEMETRY_URL'];
29453
- }
29454
- return DEFAULT_LOGS_URL;
29455
- }
29456
- /**
29457
- * Send a telemetry event to the proxy service.
29458
- *
29459
- * @remarks
29460
- * Fire-and-forget: the returned promise is intentionally not awaited
29461
- * by the caller. A fetch failure (network error, non-2xx, timeout)
29462
- * is silently swallowed so telemetry never blocks or fails user
29463
- * operations.
29464
- *
29465
- * @param payload - The structured log payload matching the server schema.
29466
- *
29467
- * @example
29468
- * ```typescript
29469
- * import { emitAnalyticsLog } from './emitLog'
29470
- *
29471
- * // Fire-and-forget — do not await
29472
- * emitAnalyticsLog(payload).catch(() => {})
29473
- * ```
29474
- *
29475
- * @internal
29476
- */
29477
- async function emitAnalyticsLog(payload) {
29478
- try {
29479
- const isNode = isNodeEnvironment();
29480
- const userAgent = getUserAgent();
29481
- await fetch(getLogsUrl(), {
29482
- method: 'POST',
29483
- headers: {
29484
- 'Content-Type': 'application/json',
29485
- // Browser restricts setting User-Agent; use X-User-Agent instead.
29486
- ...(isNode
29487
- ? { 'User-Agent': userAgent }
29488
- : { 'X-User-Agent': userAgent }),
29489
- },
29490
- body: JSON.stringify(payload),
29491
- signal: AbortSignal.timeout(5_000),
29492
- });
29493
- }
29494
- catch {
29495
- // Silently swallow — telemetry must never break user operations.
29496
- }
29497
- }
29498
-
29499
- /**
29500
- * Build the `clientContext` object for telemetry payloads.
29501
- *
29502
- * @remarks
29503
- * Uses the exported `getRuntime()` and `isNodeEnvironment()` from
29504
- * `@core/utils` to detect the runtime environment (per Dominik's
29505
- * feedback to reuse existing infrastructure). The returned string
29506
- * is parsed into the structured `ClientContext` fields expected by
29507
- * the server schema.
29508
- *
29509
- * @returns A {@link ClientContext} with platform, OS, and runtime name
29510
- * populated from the current environment.
29511
- *
29512
- * @example
29513
- * ```typescript
29514
- * import { buildClientContext } from './clientContext'
29515
- *
29516
- * const ctx = buildClientContext()
29517
- * // Node: { platform: 'node', os: 'darwin', runtimeName: null }
29518
- * // Browser: { platform: 'browser', os: null, runtimeName: 'chrome' }
29519
- * ```
29520
- */
29521
- function buildClientContext() {
29522
- const runtime = getRuntime();
29523
- if (runtime.startsWith('browser/')) {
29524
- return {
29525
- platform: 'browser',
29526
- os: null,
29527
- runtimeName: runtime.slice('browser/'.length).toLowerCase(),
29528
- };
29529
- }
29530
- if (runtime.startsWith('node/')) {
29531
- return {
29532
- platform: 'node',
29533
- os: isNodeEnvironment() ? process.platform : null,
29534
- runtimeName: null,
29535
- };
29536
- }
29537
- return {
29538
- platform: 'node',
29539
- os: null,
29540
- runtimeName: null,
29541
- };
29542
- }
29543
-
29544
30003
  /**
29545
30004
  * Event type identifiers accepted by the server-side logs endpoint.
29546
30005
  *
@@ -29553,6 +30012,11 @@ const EVENT_TYPES = {
29553
30012
  DEPOSIT_FOR: 'unified_balance_deposit_for',
29554
30013
  SPEND: 'unified_balance_spend',
29555
30014
  SPEND_FORWARDER: 'unified_balance_spend_forwarder',
30015
+ ESTIMATE_SPEND: 'unified_balance_estimate_spend',
30016
+ GET_BALANCES: 'unified_balance_get_balances',
30017
+ ADD_DELEGATE: 'unified_balance_add_delegate',
30018
+ REMOVE_DELEGATE: 'unified_balance_remove_delegate',
30019
+ GET_DELEGATE_STATUS: 'unified_balance_get_delegate_status',
29556
30020
  INITIATE_REMOVE_FUND: 'unified_balance_initiate_remove_fund',
29557
30021
  REMOVE_FUND: 'unified_balance_remove_fund',
29558
30022
  };
@@ -29590,33 +30054,29 @@ function extractSingleChainResult(data) {
29590
30054
  txHash: data.txHash,
29591
30055
  };
29592
30056
  }
29593
- /**
29594
- * Resolve a chain identifier that may be a string or a
29595
- * `ChainDefinition` object to a plain string.
29596
- *
29597
- * @internal
29598
- */
29599
- function resolveChainString(chain) {
29600
- if (typeof chain === 'string')
29601
- return chain;
29602
- return chain.chain;
29603
- }
29604
30057
  /**
29605
30058
  * Extract log-relevant fields from a spend result.
29606
30059
  *
30060
+ * @remarks
30061
+ * Collects all source chains from allocations and joins them with
30062
+ * commas so multi-chain spends are fully represented.
30063
+ *
29607
30064
  * @internal
29608
30065
  */
29609
30066
  function extractSpend(data) {
29610
- const rawChain = data.allocations?.[0]?.chain;
29611
- let firstSourceChain;
29612
- if (rawChain != null) {
29613
- firstSourceChain = resolveChainString(rawChain);
30067
+ const allocs = data.allocations ?? [];
30068
+ const chains = [];
30069
+ for (const alloc of allocs) {
30070
+ const name = resolveChainName(alloc.chain);
30071
+ if (name != null) {
30072
+ chains.push(name);
30073
+ }
29614
30074
  }
29615
- const hasAllocations = data.allocations?.[0] != null;
30075
+ const sourceChain = chains.length > 0 ? chains.join(',') : undefined;
29616
30076
  return {
29617
- ...(firstSourceChain != null && { sourceChain: firstSourceChain }),
30077
+ ...(sourceChain != null && { sourceChain }),
29618
30078
  destinationChain: data.destinationChain,
29619
- ...(hasAllocations && { tokenIn: 'USDC' }),
30079
+ ...(allocs.length > 0 && { tokenIn: 'USDC' }),
29620
30080
  txHash: data.txHash,
29621
30081
  };
29622
30082
  }
@@ -29715,10 +30175,9 @@ function mapSucceededEventToLog(actionName, payload, sdkName, sdkVersion) {
29715
30175
  * telemetry for successful verb operations.
29716
30176
  *
29717
30177
  * @remarks
29718
- * Follows Dominik's feedback to reuse the existing event bus as the
29719
- * SDK-side hook for telemetry. Registers a handler for each verb's
29720
- * `.succeeded` event. Non-verb and non-succeeded events are not
29721
- * subscribed to.
30178
+ * Registers a handler for each verb's `.succeeded` event using the
30179
+ * shared `registerTelemetryHandler` from `@core/utils`. Non-verb and
30180
+ * non-succeeded events are not subscribed to.
29722
30181
  *
29723
30182
  * The HTTP POST is fire-and-forget — telemetry never blocks or fails
29724
30183
  * user operations.
@@ -29738,20 +30197,7 @@ function mapSucceededEventToLog(actionName, payload, sdkName, sdkVersion) {
29738
30197
  * @internal
29739
30198
  */
29740
30199
  function registerTelemetryHandler(dispatcher, sdkName, sdkVersion) {
29741
- for (const actionName of Object.keys(VERB_EVENT_MAP)) {
29742
- dispatcher.on(actionName, (payload) => {
29743
- try {
29744
- const log = mapSucceededEventToLog(actionName, payload, sdkName, sdkVersion);
29745
- if (log) {
29746
- // Fire-and-forget — intentionally not awaited.
29747
- void emitAnalyticsLog(log);
29748
- }
29749
- }
29750
- catch {
29751
- // Silently swallow — telemetry must never break user operations.
29752
- }
29753
- });
29754
- }
30200
+ registerTelemetryHandler$1(dispatcher, sdkName, sdkVersion, VERB_EVENT_MAP, mapSucceededEventToLog);
29755
30201
  }
29756
30202
 
29757
30203
  /**
@@ -35781,6 +36227,8 @@ function getSupportedChains(context, token, options) {
35781
36227
  return Object.values(Object.fromEntries(filtered.map((chain) => [chain.chain, chain])));
35782
36228
  }
35783
36229
 
36230
+ /** SDK name used in telemetry payloads. */
36231
+ const SDK_NAME = resolveKitSdkName(pkg.name);
35784
36232
  /**
35785
36233
  * A high-level class-based interface for cross-chain USDC deposits,
35786
36234
  * spending, balance queries, delegation management, and withdrawals.
@@ -35828,6 +36276,10 @@ class UnifiedBalanceKit {
35828
36276
  * The action dispatcher for the kit.
35829
36277
  */
35830
36278
  actionDispatcher;
36279
+ /** Whether error telemetry is disabled. */
36280
+ disableErrorReporting;
36281
+ /** Per-kit telemetry identity for shared helpers. */
36282
+ telemetryConfig;
35831
36283
  /**
35832
36284
  * Create a new UnifiedBalanceKit instance.
35833
36285
  *
@@ -35840,13 +36292,48 @@ class UnifiedBalanceKit {
35840
36292
  constructor(config = {}) {
35841
36293
  this.context = createUnifiedBalanceKitContext(config);
35842
36294
  this.actionDispatcher = new Actionable();
36295
+ this.disableErrorReporting = config.disableErrorReporting === true;
36296
+ this.telemetryConfig = {
36297
+ sdkName: SDK_NAME,
36298
+ sdkVersion: pkg.version,
36299
+ disabled: this.disableErrorReporting,
36300
+ };
35843
36301
  for (const provider of this.context.providers) {
35844
36302
  provider.registerDispatcher(this.actionDispatcher);
35845
36303
  }
35846
36304
  if (!config.disableAnalytics) {
35847
- const sdkName = pkg.name.replace('@circle-fin/', '');
35848
- registerTelemetryHandler(this.actionDispatcher, sdkName, pkg.version);
36305
+ registerTelemetryHandler(this.actionDispatcher, SDK_NAME, pkg.version);
36306
+ }
36307
+ }
36308
+ /**
36309
+ * Extract comma-separated source chain names from spend params.
36310
+ *
36311
+ * @internal
36312
+ */
36313
+ static extractSpendSourceChains(params) {
36314
+ if (params == null || typeof params !== 'object' || !('from' in params)) {
36315
+ return undefined;
36316
+ }
36317
+ const fromVal = params.from;
36318
+ const sources = Array.isArray(fromVal) ? fromVal : [fromVal];
36319
+ const chains = [];
36320
+ for (const src of sources) {
36321
+ const allocs = src?.allocations;
36322
+ let allocArr;
36323
+ if (allocs == null) {
36324
+ allocArr = [];
36325
+ }
36326
+ else {
36327
+ allocArr = Array.isArray(allocs) ? allocs : [allocs];
36328
+ }
36329
+ for (const alloc of allocArr) {
36330
+ const name = resolveChainName(alloc.chain);
36331
+ if (name != null) {
36332
+ chains.push(name);
36333
+ }
36334
+ }
35849
36335
  }
36336
+ return chains.length > 0 ? chains.join(',') : undefined;
35850
36337
  }
35851
36338
  // implementation just forwards to the bus
35852
36339
  on(actionOrWildcard, handler) {
@@ -35870,7 +36357,10 @@ class UnifiedBalanceKit {
35870
36357
  * @see UnifiedBalanceKit.depositFor to deposit into another account.
35871
36358
  */
35872
36359
  async deposit(params) {
35873
- return deposit(this.context, params);
36360
+ return withErrorTelemetry(async () => deposit(this.context, params), EVENT_TYPES.DEPOSIT, this.telemetryConfig, {
36361
+ sourceChain: resolveChainName(params.from?.chain),
36362
+ tokenIn: params.token ?? 'USDC',
36363
+ });
35874
36364
  }
35875
36365
  /**
35876
36366
  * Deposit USDC into another account (not the caller's).
@@ -35882,7 +36372,10 @@ class UnifiedBalanceKit {
35882
36372
  * @see UnifiedBalanceKit.deposit to deposit into your own account.
35883
36373
  */
35884
36374
  async depositFor(params) {
35885
- return depositFor(this.context, params);
36375
+ return withErrorTelemetry(async () => depositFor(this.context, params), EVENT_TYPES.DEPOSIT_FOR, this.telemetryConfig, {
36376
+ sourceChain: resolveChainName(params.from?.chain),
36377
+ tokenIn: params.token ?? 'USDC',
36378
+ });
35886
36379
  }
35887
36380
  /**
35888
36381
  * Spend (mint) USDC on a destination chain by pulling funds from one
@@ -35895,7 +36388,17 @@ class UnifiedBalanceKit {
35895
36388
  * @see UnifiedBalanceKit.estimateSpend to preview fees before spending.
35896
36389
  */
35897
36390
  async spend(params) {
35898
- return spend(this.context, params);
36391
+ const destChain = 'to' in params
36392
+ ? resolveChainName(params.to.chain)
36393
+ : undefined;
36394
+ const tokenIn = 'token' in params
36395
+ ? (params.token ?? 'USDC')
36396
+ : 'USDC';
36397
+ return withErrorTelemetry(async () => spend(this.context, params), EVENT_TYPES.SPEND, this.telemetryConfig, {
36398
+ sourceChain: UnifiedBalanceKit.extractSpendSourceChains(params),
36399
+ ...(destChain != null && { destinationChain: destChain }),
36400
+ tokenIn,
36401
+ });
35899
36402
  }
35900
36403
  /**
35901
36404
  * Estimate the fees for a spend operation without executing it.
@@ -35905,7 +36408,17 @@ class UnifiedBalanceKit {
35905
36408
  * @returns Promise resolving to the fee estimate.
35906
36409
  */
35907
36410
  async estimateSpend(params) {
35908
- return estimateSpend(this.context, params);
36411
+ const destChain = 'to' in params
36412
+ ? resolveChainName(params.to.chain)
36413
+ : undefined;
36414
+ const sourceChain = UnifiedBalanceKit.extractSpendSourceChains(params);
36415
+ return withErrorTelemetry(async () => estimateSpend(this.context, params), EVENT_TYPES.ESTIMATE_SPEND, this.telemetryConfig, {
36416
+ ...(sourceChain != null && { sourceChain }),
36417
+ ...(destChain != null && { destinationChain: destChain }),
36418
+ tokenIn: 'token' in params
36419
+ ? (params.token ?? 'USDC')
36420
+ : 'USDC',
36421
+ });
35909
36422
  }
35910
36423
  /**
35911
36424
  * Fetch aggregated and per-chain balances for one or more accounts.
@@ -35914,7 +36427,7 @@ class UnifiedBalanceKit {
35914
36427
  * @returns Promise resolving to the aggregated balance result.
35915
36428
  */
35916
36429
  async getBalances(params) {
35917
- return getBalances(this.context, params);
36430
+ return withErrorTelemetry(async () => getBalances(this.context, params), EVENT_TYPES.GET_BALANCES, this.telemetryConfig);
35918
36431
  }
35919
36432
  /**
35920
36433
  * Grant spending rights to another address on the owner's account.
@@ -35929,7 +36442,7 @@ class UnifiedBalanceKit {
35929
36442
  * @see UnifiedBalanceKit.getDelegateStatus to check delegate status.
35930
36443
  */
35931
36444
  async addDelegate(params) {
35932
- return addDelegate(this.context, params);
36445
+ return withErrorTelemetry(async () => addDelegate(this.context, params), EVENT_TYPES.ADD_DELEGATE, this.telemetryConfig, { sourceChain: resolveChainName(params.from?.chain) });
35933
36446
  }
35934
36447
  /**
35935
36448
  * Revoke spending rights from a delegate on the owner's account.
@@ -35944,7 +36457,7 @@ class UnifiedBalanceKit {
35944
36457
  * @see UnifiedBalanceKit.getDelegateStatus to check delegate status.
35945
36458
  */
35946
36459
  async removeDelegate(params) {
35947
- return removeDelegate(this.context, params);
36460
+ return withErrorTelemetry(async () => removeDelegate(this.context, params), EVENT_TYPES.REMOVE_DELEGATE, this.telemetryConfig, { sourceChain: resolveChainName(params.from?.chain) });
35948
36461
  }
35949
36462
  /**
35950
36463
  * Kick off a delayed fund removal from an account.
@@ -35956,7 +36469,10 @@ class UnifiedBalanceKit {
35956
36469
  * @see UnifiedBalanceKit.removeFund to complete the fund removal.
35957
36470
  */
35958
36471
  async initiateRemoveFund(params) {
35959
- return initiateRemoveFund(this.context, params);
36472
+ return withErrorTelemetry(async () => initiateRemoveFund(this.context, params), EVENT_TYPES.INITIATE_REMOVE_FUND, this.telemetryConfig, {
36473
+ sourceChain: resolveChainName(params.from?.chain),
36474
+ tokenIn: params.token ?? 'USDC',
36475
+ });
35960
36476
  }
35961
36477
  /**
35962
36478
  * Complete a fund removal once the activation period has passed.
@@ -35968,7 +36484,10 @@ class UnifiedBalanceKit {
35968
36484
  * @see UnifiedBalanceKit.initiateRemoveFund to start the process.
35969
36485
  */
35970
36486
  async removeFund(params) {
35971
- return removeFund(this.context, params);
36487
+ return withErrorTelemetry(async () => removeFund(this.context, params), EVENT_TYPES.REMOVE_FUND, this.telemetryConfig, {
36488
+ sourceChain: resolveChainName(params.from?.chain),
36489
+ tokenIn: params.token ?? 'USDC',
36490
+ });
35972
36491
  }
35973
36492
  /**
35974
36493
  * Check the finality-aware delegate status of an address.
@@ -35996,7 +36515,7 @@ class UnifiedBalanceKit {
35996
36515
  * ```
35997
36516
  */
35998
36517
  async getDelegateStatus(params) {
35999
- return getDelegateStatus(this.context, params);
36518
+ return withErrorTelemetry(async () => getDelegateStatus(this.context, params), EVENT_TYPES.GET_DELEGATE_STATUS, this.telemetryConfig, { sourceChain: resolveChainName(params.from?.chain) });
36000
36519
  }
36001
36520
  /**
36002
36521
  * Get all chains supported by the kit.
@@ -36486,8 +37005,18 @@ class AppKit {
36486
37005
  * ```
36487
37006
  */
36488
37007
  constructor(config = {}) {
36489
- this.context = createContext(config);
36490
- this.unifiedBalance = new AppKitUnifiedBalance(config.unifiedBalance);
37008
+ this.context = createContext({
37009
+ ...config,
37010
+ ...(config.disableErrorReporting != null && {
37011
+ disableErrorReporting: config.disableErrorReporting,
37012
+ }),
37013
+ });
37014
+ this.unifiedBalance = new AppKitUnifiedBalance({
37015
+ ...config.unifiedBalance,
37016
+ ...(config.disableErrorReporting != null && {
37017
+ disableErrorReporting: config.disableErrorReporting,
37018
+ }),
37019
+ });
36491
37020
  }
36492
37021
  /**
36493
37022
  * Execute a cross-chain USDC bridge transfer.