@circle-fin/app-kit 1.16.0 → 1.18.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 (52) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/borrow.cjs +150 -32
  3. package/borrow.d.cts +38 -9
  4. package/borrow.d.mts +38 -9
  5. package/borrow.d.ts +38 -9
  6. package/borrow.mjs +150 -32
  7. package/bridge.cjs +454 -53
  8. package/bridge.d.cts +38 -9
  9. package/bridge.d.mts +38 -9
  10. package/bridge.d.ts +38 -9
  11. package/bridge.mjs +454 -53
  12. package/chains.cjs +10 -6
  13. package/chains.d.cts +1 -1
  14. package/chains.d.mts +1 -1
  15. package/chains.d.ts +1 -1
  16. package/chains.mjs +10 -6
  17. package/context.d.cts +38 -9
  18. package/context.d.mts +38 -9
  19. package/context.d.ts +38 -9
  20. package/earn.cjs +830 -43
  21. package/earn.d.cts +38 -9
  22. package/earn.d.mts +38 -9
  23. package/earn.d.ts +38 -9
  24. package/earn.mjs +830 -43
  25. package/estimateBridge.cjs +454 -53
  26. package/estimateBridge.d.cts +38 -9
  27. package/estimateBridge.d.mts +38 -9
  28. package/estimateBridge.d.ts +38 -9
  29. package/estimateBridge.mjs +454 -53
  30. package/estimateSwap.cjs +265 -45
  31. package/estimateSwap.d.cts +86 -9
  32. package/estimateSwap.d.mts +86 -9
  33. package/estimateSwap.d.ts +86 -9
  34. package/estimateSwap.mjs +265 -45
  35. package/index.cjs +1019 -73
  36. package/index.d.cts +373 -210
  37. package/index.d.mts +373 -210
  38. package/index.d.ts +373 -210
  39. package/index.mjs +1019 -73
  40. package/package.json +8 -8
  41. package/server.cjs +35 -9
  42. package/server.d.cts +29 -10
  43. package/server.d.mts +29 -10
  44. package/server.d.ts +29 -10
  45. package/server.mjs +35 -9
  46. package/swap.cjs +265 -45
  47. package/swap.d.cts +86 -9
  48. package/swap.d.mts +86 -9
  49. package/swap.d.ts +86 -9
  50. package/swap.mjs +265 -45
  51. package/unifiedBalance.cjs +139 -20
  52. package/unifiedBalance.mjs +139 -20
@@ -2522,22 +2522,73 @@ let activeRedactor = defaultMessageRedactor;
2522
2522
  '0x9147d463': 'Final balance is less than the initial balance',
2523
2523
  '0xf4b3b1bc': 'Native token transfer to the beneficiary failed'
2524
2524
  };
2525
+ /**
2526
+ * Matches revert data: a 4-byte selector followed by whole ABI-encoded bytes.
2527
+ */ const REVERT_DATA_PATTERN = /^0x[0-9a-f]{8}(?:[0-9a-f]{2})*$/i;
2528
+ /**
2529
+ * Returns the revert data held by one error in a `cause` chain.
2530
+ *
2531
+ * Browser wallets (EIP-1193) wrap the node's error, so the revert data sits
2532
+ * one level down as `data.data`. viem's `getContractError` reads it the same
2533
+ * way, then keeps it on `ContractFunctionRevertedError.raw` and drops the
2534
+ * node's error from the chain.
2535
+ *
2536
+ * @param link - One error in the `cause` chain
2537
+ * @returns The `raw` or `data` string, or undefined if there is none
2538
+ */ function getRevertData(link) {
2539
+ if ('raw' in link && typeof link.raw === 'string' && REVERT_DATA_PATTERN.test(link.raw)) {
2540
+ return link.raw;
2541
+ }
2542
+ if (!('data' in link)) {
2543
+ return undefined;
2544
+ }
2545
+ const { data } = link;
2546
+ if (typeof data === 'string') {
2547
+ return data;
2548
+ }
2549
+ if (data !== null && typeof data === 'object' && 'data' in data && typeof data.data === 'string') {
2550
+ return data.data;
2551
+ }
2552
+ return undefined;
2553
+ }
2554
+ /**
2555
+ * Finds the first revert data on the error or in its `cause` chain that
2556
+ * `accept` takes.
2557
+ *
2558
+ * viem keeps the node's revert data on an inner `RpcRequestError`, not on
2559
+ * the error it throws. The `seen` set stops a self-referencing `cause` chain.
2560
+ *
2561
+ * @param error - The error object
2562
+ * @param accept - Returns true for the data shape the caller wants
2563
+ * @returns The data as written on the error, or undefined if not found
2564
+ */ function findRevertData(error, accept) {
2565
+ const seen = new Set();
2566
+ let current = error;
2567
+ while(current !== null && typeof current === 'object' && !seen.has(current)){
2568
+ seen.add(current);
2569
+ const data = getRevertData(current);
2570
+ if (data !== undefined && accept(data)) {
2571
+ return data;
2572
+ }
2573
+ current = 'cause' in current ? current.cause : undefined;
2574
+ }
2575
+ return undefined;
2576
+ }
2525
2577
  /**
2526
2578
  * Attempts to extract an error selector from an error object or message.
2527
2579
  *
2528
2580
  * Checks multiple sources in priority order:
2529
- * 1. `error.data` field
2581
+ * 1. `raw` or `data` field (or nested `data.data`) on the error or anywhere
2582
+ * in its `cause` chain
2530
2583
  * 2. Message pattern: "custom error 0x8baa579f"
2531
2584
  *
2532
2585
  * @param msg - The error message
2533
2586
  * @param error - The error object (optional)
2534
2587
  * @returns The 4 bytes selector , or undefined if not found
2535
2588
  */ function extractErrorSelector(msg, error) {
2536
- // Check error.data field
2537
- if (error !== null && typeof error === 'object' && 'data' in error) {
2538
- if (typeof error.data === 'string' && /^0x[0-9a-f]{8}$/i.test(error.data)) {
2539
- return error.data.toLowerCase();
2540
- }
2589
+ const data = findRevertData(error, (value)=>/^0x[0-9a-f]{8}$/i.test(value));
2590
+ if (data !== undefined) {
2591
+ return data.toLowerCase();
2541
2592
  }
2542
2593
  // Check for "custom error 0x8baa579f" in the message
2543
2594
  const match = /custom error (0x[0-9a-f]{8})\b/i.exec(msg);
@@ -3810,6 +3861,8 @@ var SwapChain;
3810
3861
  SwapChain["HyperEVM"] = "HyperEVM";
3811
3862
  SwapChain["Monad"] = "Monad";
3812
3863
  SwapChain["Arc"] = "Arc";
3864
+ SwapChain["Cronos"] = "Cronos";
3865
+ SwapChain["Morph"] = "Morph";
3813
3866
  // Testnet chains with swap support
3814
3867
  SwapChain["Arc_Testnet"] = "Arc_Testnet";
3815
3868
  })(SwapChain || (SwapChain = {}));
@@ -4490,14 +4543,14 @@ var BorrowChain;
4490
4543
  symbol: 'USDC',
4491
4544
  // Arc uses native USDC with 18 decimals for gas payments (EVM standard).
4492
4545
  // Note: The ERC-20 USDC contract at usdcAddress uses 6 decimals.
4493
- // See: https://docs.arc.network/arc/references/contract-addresses
4546
+ // See: https://docs.arc.io/arc/references/contract-addresses
4494
4547
  decimals: 18
4495
4548
  },
4496
4549
  chainId: 5042002,
4497
4550
  isTestnet: true,
4498
4551
  explorerUrl: 'https://testnet.arcscan.app/tx/{hash}',
4499
4552
  rpcEndpoints: [
4500
- 'https://rpc.testnet.arc.network/'
4553
+ 'https://rpc.testnet.arc.io'
4501
4554
  ],
4502
4555
  eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
4503
4556
  usdcAddress: '0x3600000000000000000000000000000000000000',
@@ -5142,7 +5195,8 @@ var BorrowChain;
5142
5195
  }
5143
5196
  },
5144
5197
  kitContracts: {
5145
- bridge: BRIDGE_CONTRACT_EVM_MAINNET
5198
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
5199
+ adapter: ADAPTER_CONTRACT_EVM_MAINNET
5146
5200
  }
5147
5201
  });
5148
5202
 
@@ -6011,7 +6065,8 @@ var BorrowChain;
6011
6065
  }
6012
6066
  },
6013
6067
  kitContracts: {
6014
- bridge: BRIDGE_CONTRACT_EVM_MAINNET
6068
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
6069
+ adapter: ADAPTER_CONTRACT_EVM_MAINNET
6015
6070
  }
6016
6071
  });
6017
6072
 
@@ -8309,8 +8364,8 @@ var Chains = {
8309
8364
  * Zod schema for validating swap-specific chain identifiers.
8310
8365
  *
8311
8366
  * Validates chains based on:
8312
- * - CCTPv2 support (adapter contract deployed)
8313
- * - Mainnet only (no testnets)
8367
+ * - Membership in the SwapChain enum
8368
+ * - Mainnet or explicitly allowlisted testnet
8314
8369
  * - At least one supported token available
8315
8370
  *
8316
8371
  */ const swapChainIdentifierSchema = zod.z.union([
@@ -8789,7 +8844,7 @@ const swapTokenEnumSchema = zod.z.enum([
8789
8844
  *
8790
8845
  * A chain supports swaps if ALL conditions are met:
8791
8846
  * 1. Is a member of the {@link SwapChain} enum
8792
- * 2. Has CCTPv2 support (adapter contract deployed)
8847
+ * 2. Has an Adapter contract configured directly or through CCTP v2
8793
8848
  *
8794
8849
  * Testnets are allowed only when explicitly listed in the
8795
8850
  * {@link SwapChain} enum (e.g., Arc_Testnet).
@@ -8810,14 +8865,14 @@ const swapTokenEnumSchema = zod.z.enum([
8810
8865
  * @remarks
8811
8866
  * Chains automatically become swap-enabled when:
8812
8867
  * - Added to the {@link SwapChain} enum
8813
- * - Adapter contract is deployed (CCTPv2)
8868
+ * - An Adapter contract is deployed and configured
8814
8869
  *
8815
8870
  * No code changes needed when new chains are added!
8816
8871
  */ function isSwapSupportedChain(chain) {
8817
8872
  if (!(chain.chain in SwapChain)) {
8818
8873
  return false;
8819
8874
  }
8820
- if (!isCCTPV2Supported(chain)) {
8875
+ if (!isCCTPV2Supported(chain) && !hasCustomContractSupport(chain, 'adapter')) {
8821
8876
  return false;
8822
8877
  }
8823
8878
  return true;
@@ -8828,7 +8883,7 @@ const swapTokenEnumSchema = zod.z.enum([
8828
8883
  *
8829
8884
  * Dynamically filter chain definitions to include only those that:
8830
8885
  * - Are members of the {@link SwapChain} enum
8831
- * - Have CCTPv2 support
8886
+ * - Have an Adapter contract configured directly or through CCTP v2
8832
8887
  *
8833
8888
  * This function is pure and accepts chains as parameter to avoid
8834
8889
  * circular dependencies.
@@ -10262,11 +10317,13 @@ function parseOrThrow(value, schema, context) {
10262
10317
  [Blockchain.Arbitrum]: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
10263
10318
  [Blockchain.Avalanche]: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7',
10264
10319
  [Blockchain.Celo]: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
10320
+ [Blockchain.Cronos]: '0x66e428c3f67a68878562e79A0234c1F83c208770',
10265
10321
  [Blockchain.Ethereum]: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
10266
10322
  [Blockchain.HyperEVM]: '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb',
10267
10323
  [Blockchain.Ink]: '0x0200C29006150606B650577BBE7B6248F58470c1',
10268
10324
  [Blockchain.Linea]: '0xA219439258ca9da29E9Cc4cE5596924745e12B93',
10269
10325
  [Blockchain.Monad]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
10326
+ [Blockchain.Morph]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
10270
10327
  [Blockchain.NEAR]: 'usdt.tether-token.near',
10271
10328
  [Blockchain.Optimism]: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58',
10272
10329
  [Blockchain.Polkadot_Asset_Hub]: '1984',
@@ -10325,6 +10382,7 @@ function parseOrThrow(value, schema, context) {
10325
10382
  [Blockchain.Arbitrum]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
10326
10383
  [Blockchain.Avalanche]: '0xd586E7F844cEa2F87f50152665BCbc2C279D8d70',
10327
10384
  [Blockchain.Base]: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb',
10385
+ [Blockchain.Cronos]: '0xF2001B145b43032AAF5Ee2884e456CCd805F677D',
10328
10386
  [Blockchain.Ethereum]: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
10329
10387
  [Blockchain.Linea]: '0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5',
10330
10388
  [Blockchain.Optimism]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
@@ -10387,7 +10445,9 @@ function parseOrThrow(value, schema, context) {
10387
10445
  [Blockchain.Arbitrum]: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
10388
10446
  [Blockchain.Avalanche]: '0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB',
10389
10447
  [Blockchain.Base]: '0x4200000000000000000000000000000000000006',
10448
+ [Blockchain.Cronos]: '0xe44Fd7fCb2b1581822D0c862B68222998a0c299a',
10390
10449
  [Blockchain.Ethereum]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
10450
+ [Blockchain.Morph]: '0x5300000000000000000000000000000000000011',
10391
10451
  [Blockchain.Optimism]: '0x4200000000000000000000000000000000000006',
10392
10452
  [Blockchain.Polygon]: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619',
10393
10453
  [Blockchain.Solana]: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs'
@@ -10406,6 +10466,7 @@ function parseOrThrow(value, schema, context) {
10406
10466
  locators: {
10407
10467
  [Blockchain.Ethereum]: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
10408
10468
  [Blockchain.Arbitrum]: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f',
10469
+ [Blockchain.Cronos]: '0x062E66477Faf219F25D27dCED647BF57C3107d52',
10409
10470
  [Blockchain.Avalanche]: '0x50b7545627a5162F82A992c33b87aDc75187B218'
10410
10471
  }
10411
10472
  };
@@ -12126,6 +12187,39 @@ function resolveOptions(options) {
12126
12187
  }
12127
12188
  };
12128
12189
  }
12190
+ /**
12191
+ * Emit telemetry for a completed operation without affecting its caller.
12192
+ *
12193
+ * No-ops when `config.disabled` is `true`. Like {@link withErrorTelemetry},
12194
+ * failures while constructing or submitting the telemetry payload are reported
12195
+ * as a soft warning and never change a completed operation's result.
12196
+ *
12197
+ * @param eventType - The telemetry event type for the completed operation.
12198
+ * @param config - Per-kit SDK identity and disabled flag.
12199
+ * @param context - Optional chain, token, and transaction context.
12200
+ * @returns Nothing.
12201
+ * @throws Never — telemetry failures are reported as warnings.
12202
+ *
12203
+ * @example
12204
+ * ```typescript
12205
+ * import { emitSuccessTelemetry } from '@core/utils'
12206
+ *
12207
+ * emitSuccessTelemetry(
12208
+ * 'bridge_bridge',
12209
+ * { sdkName: 'bridge-kit', sdkVersion: '1.0.0', disabled: false },
12210
+ * { sourceChain: 'Ethereum', destinationChain: 'Base', tokenIn: 'USDC' },
12211
+ * )
12212
+ * ```
12213
+ */ function emitSuccessTelemetry(eventType, config, context) {
12214
+ if (config.disabled) {
12215
+ return;
12216
+ }
12217
+ try {
12218
+ void emitAnalyticsLog(buildPayload(config, eventType, undefined, context));
12219
+ } catch (telemetryError) {
12220
+ warnTelemetryDrop(eventType, telemetryError);
12221
+ }
12222
+ }
12129
12223
  /**
12130
12224
  * Wrap an async operation with error telemetry.
12131
12225
  *
@@ -12236,7 +12330,7 @@ function resolveOptions(options) {
12236
12330
  }
12237
12331
 
12238
12332
  var name$3 = "@circle-fin/bridge-kit";
12239
- var version$4 = "1.15.2";
12333
+ var version$4 = "1.16.0";
12240
12334
  var pkg$4 = {
12241
12335
  name: name$3,
12242
12336
  version: version$4};
@@ -13497,6 +13591,53 @@ const EURC_MAINNET_TOKEN_ID = '0x6ca9e29fa53becc29becaf4a90b9ca7a995ad4d2234880d
13497
13591
  }
13498
13592
  };
13499
13593
 
13594
+ /**
13595
+ * Map a CCTPx bytes32 token id back to its known display symbol.
13596
+ *
13597
+ * The inverse of the provider's internal symbol -> id resolution: a bridge
13598
+ * resolves a symbol such as `'cirBTC'` to its canonical bytes32 id and reports
13599
+ * that id on `result.token`, dropping the symbol. This helper recovers the
13600
+ * symbol for display. It is scoped to {@link KNOWN_TOKEN_SYMBOLS} — the same
13601
+ * known set the forward resolution covers — and is keyed by network, because a
13602
+ * symbol names a separate registration on each network, whose ids are
13603
+ * unrelated.
13604
+ *
13605
+ * The lookup is best-effort by design: an arbitrary registry token, a
13606
+ * non-canonical bridge of a known symbol, or any unrecognized id has no known
13607
+ * symbol and yields `undefined`. The id is matched case-insensitively (bytes32
13608
+ * ids have no checksum casing).
13609
+ *
13610
+ * @param id - The bytes32 token id to decode (e.g. a `result.token` value).
13611
+ * @param network - The network the id belongs to (`'testnet'` or `'mainnet'`);
13612
+ * derive it from the source chain, e.g. `chain.isTestnet ? 'testnet' :
13613
+ * 'mainnet'`.
13614
+ * @returns The matching {@link KnownTokenSymbol}, or `undefined` when `id` is
13615
+ * not one of the known canonical ids for `network`.
13616
+ * @throws A `KitError` (`INPUT_VALIDATION_FAILED`, FATAL) when `id` is not a
13617
+ * string or `network` is not a recognized network.
13618
+ *
13619
+ * @example
13620
+ * ```typescript
13621
+ * import { resolveToKnownTokenSymbol } from '@circle-fin/provider-cctpx'
13622
+ *
13623
+ * const result = await provider.bridge(params) // params.token === 'cirBTC'
13624
+ * const network = result.source.chain.isTestnet ? 'testnet' : 'mainnet'
13625
+ *
13626
+ * resolveToKnownTokenSymbol(result.token, network) // 'cirBTC'
13627
+ * resolveToKnownTokenSymbol('0xdeadbeef…', network) // undefined (not known)
13628
+ * ```
13629
+ */ function resolveToKnownTokenSymbol(id, network) {
13630
+ if (typeof id !== 'string') {
13631
+ throw createValidationFailedError$1('id', id, 'must be a string');
13632
+ }
13633
+ if (network !== 'testnet' && network !== 'mainnet') {
13634
+ throw createValidationFailedError$1('network', network, "must be 'testnet' or 'mainnet'");
13635
+ }
13636
+ const row = KNOWN_TOKEN_IDS_BY_NETWORK[network];
13637
+ const target = id.toLowerCase();
13638
+ return KNOWN_TOKEN_SYMBOLS.find((symbol)=>row[symbol].toLowerCase() === target);
13639
+ }
13640
+
13500
13641
  /**
13501
13642
  * Default clock implementation.
13502
13643
  *
@@ -14801,7 +14942,11 @@ function createNoopLogger() {
14801
14942
  tokenId: bytes32Hex,
14802
14943
  domainId: nonNegativeInteger,
14803
14944
  tokenAddress: zod.z.string(),
14804
- tokenManagerAddress: zod.z.string()
14945
+ tokenManagerAddress: zod.z.string(),
14946
+ // Operator-controlled per-chain kill switch (CCTPE-3979). Optional for
14947
+ // back-compat with older IRIS versions that do not surface it. Downstream
14948
+ // consumers in `findCCTPXDeployment` treat a missing value as `true`.
14949
+ enabled: zod.z.boolean().optional()
14805
14950
  });
14806
14951
  /**
14807
14952
  * Schema for one token entry in the token registry response.
@@ -15285,17 +15430,23 @@ function createNoopLogger() {
15285
15430
  /**
15286
15431
  * Find a token's deployment on the given CCTP domain.
15287
15432
  *
15433
+ * A deployment row with `enabled === false` is treated as missing: an IRIS
15434
+ * operator has flipped the per-chain kill switch (CCTPE-3979), so the SDK must
15435
+ * not route through it even though the row still exists in the registry. A
15436
+ * missing or `true` `enabled` value remains routable — the field is optional on
15437
+ * older IRIS versions and absence is read as "allowed".
15438
+ *
15288
15439
  * @param token - The registry token whose deployments are searched.
15289
15440
  * @param domain - The CCTP domain id to match.
15290
15441
  * @returns The matching {@link CCTPXTokenDeployment}, or `undefined` when the
15291
- * token has no deployment on that domain.
15442
+ * token has no deployment on that domain or the deployment is disabled.
15292
15443
  *
15293
15444
  * @example
15294
15445
  * ```typescript
15295
15446
  * const deployment = findCCTPXDeployment(token, 0)
15296
15447
  * ```
15297
15448
  */ function findCCTPXDeployment(token, domain) {
15298
- return token.deployments.find((deployment)=>deployment.domainId === domain);
15449
+ return token.deployments.find((deployment)=>deployment.domainId === domain && deployment.enabled !== false);
15299
15450
  }
15300
15451
 
15301
15452
  /**
@@ -15397,6 +15548,24 @@ function createNoopLogger() {
15397
15548
  }
15398
15549
  }
15399
15550
  })
15551
+ ],
15552
+ // The token is not deployed on one of the route chains, or an operator has
15553
+ // flipped the per-chain `enabled` kill switch on the IRIS deployment row.
15554
+ // Either way the route is permanently unavailable until the operator intervenes;
15555
+ // a retry at the same source/destination will keep returning this error.
15556
+ [
15557
+ 'TOKEN_NOT_SUPPORTED_ON_ROUTE',
15558
+ ({ sourceDomain, destinationDomain })=>new KitError({
15559
+ ...InputError.UNSUPPORTED_ROUTE,
15560
+ recoverability: 'FATAL',
15561
+ message: 'CCTPx fee quote rejected the route: the token is not supported on ' + 'the source or destination chain (missing deployment or operator-disabled).',
15562
+ cause: {
15563
+ trace: {
15564
+ sourceDomain,
15565
+ destinationDomain
15566
+ }
15567
+ }
15568
+ })
15400
15569
  ]
15401
15570
  ]);
15402
15571
  /**
@@ -20653,6 +20822,24 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
20653
20822
  }
20654
20823
  };
20655
20824
 
20825
+ /**
20826
+ * Check whether a forwarded burn to the given destination asks Circle's
20827
+ * Forwarding Service to set up the recipient's token account before minting.
20828
+ *
20829
+ * Must return `true` exactly for the destinations where
20830
+ * {@link getForwarderHookData} emits the `createAta` frame, so the forwarding
20831
+ * fee quote includes the setup rent whenever the burn requests it.
20832
+ *
20833
+ * @internal
20834
+ * @param chainType - The destination blockchain type.
20835
+ * @returns `true` for Solana destinations, `false` otherwise.
20836
+ *
20837
+ * @example
20838
+ * ```typescript
20839
+ * requiresRecipientSetup('solana') // true
20840
+ * requiresRecipientSetup('evm') // false
20841
+ * ```
20842
+ */ const requiresRecipientSetup = (chainType)=>chainType === 'solana';
20656
20843
  /**
20657
20844
  * Build the forwarding `hookData` for a forwarded (Orbit-relayed) CCTP v2 burn,
20658
20845
  * tailored to the destination chain.
@@ -21003,10 +21190,12 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
21003
21190
  * @param sourceDomain - The source domain
21004
21191
  * @param destinationDomain - The destination domain
21005
21192
  * @param isTestnet - Whether the request is for a testnet chain
21193
+ * @param includeRecipientSetup - Whether the quote includes recipient account setup rent
21006
21194
  * @returns The complete API URL with forward=true query parameter
21007
- */ function buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet) {
21195
+ */ function buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet, includeRecipientSetup) {
21008
21196
  const baseUrl = isTestnet ? IRIS_API_SANDBOX_BASE_URL$1 : IRIS_API_BASE_URL$1;
21009
- return `${baseUrl}/v2/burn/USDC/fees/${sourceDomain.toString()}/${destinationDomain.toString()}?forward=true`;
21197
+ const recipientSetupQuery = includeRecipientSetup ? '&includeRecipientSetup=true' : '';
21198
+ return `${baseUrl}/v2/burn/USDC/fees/${sourceDomain.toString()}/${destinationDomain.toString()}?forward=true${recipientSetupQuery}`;
21010
21199
  }
21011
21200
  /**
21012
21201
  * Fetches the forwarding fee for a USDC transfer operation with retry and timeout handling.
@@ -21023,6 +21212,10 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
21023
21212
  *
21024
21213
  * The high fee tier is always used to provide buffer for destination gas fluctuations.
21025
21214
  *
21215
+ * Pass `includeRecipientSetup: true` when the burn asks the Forwarding Service to create
21216
+ * the recipient's token account (Solana destinations). The quote then includes the
21217
+ * account rent, which the quote without this flag leaves out.
21218
+ *
21026
21219
  * Implements timeout and retry logic to handle network issues and temporary API failures.
21027
21220
  * Each HTTP request is given a maximum of 2 seconds before it is aborted.
21028
21221
  * We retry up to 10 times, waiting 200ms between attempts.
@@ -21031,6 +21224,8 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
21031
21224
  * @param destinationDomain - The destination domain
21032
21225
  * @param isTestnet - Whether the request is for a testnet chain
21033
21226
  * @param finalityThreshold - The finality threshold to select the fee tier (1000 for FAST, 2000 for SLOW)
21227
+ * @param includeRecipientSetup - Whether to include recipient account setup rent in the
21228
+ * quote. Defaults to `false`.
21034
21229
  * @returns The high-tier forwarding fee in USDC minor units (6 decimals)
21035
21230
  * @throws Error if the input domains are invalid, the API request fails, returns invalid data, or network errors occur
21036
21231
  *
@@ -21042,8 +21237,11 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
21042
21237
  *
21043
21238
  * // SLOW transfer - use 2000ms finality threshold
21044
21239
  * const slowForwardingFee = await fetchForwardingFee(0, 6, false, 2000)
21240
+ *
21241
+ * // Ethereum -> Solana: include the recipient token account rent
21242
+ * const solanaForwardingFee = await fetchForwardingFee(0, 5, false, 1000, true)
21045
21243
  * ```
21046
- */ async function fetchForwardingFee(sourceDomain, destinationDomain, isTestnet, finalityThreshold) {
21244
+ */ async function fetchForwardingFee(sourceDomain, destinationDomain, isTestnet, finalityThreshold, includeRecipientSetup = false) {
21047
21245
  // Validate source domain
21048
21246
  if (!Number.isInteger(sourceDomain) || sourceDomain < 0) {
21049
21247
  throw new KitError({
@@ -21071,7 +21269,7 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
21071
21269
  });
21072
21270
  }
21073
21271
  // Fetch the fee tiers from the API with forward=true
21074
- const url = buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet);
21272
+ const url = buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet, includeRecipientSetup);
21075
21273
  const response = await pollApiGet(url, isForwardingFeeResponse, DEFAULT_CONFIG$1);
21076
21274
  // Validate that we have at least one fee tier
21077
21275
  if (response.length === 0) {
@@ -23407,7 +23605,7 @@ const mockAttestationMessage = {
23407
23605
  return step;
23408
23606
  }
23409
23607
 
23410
- var version$3 = "1.14.1";
23608
+ var version$3 = "1.14.3";
23411
23609
  var pkg$3 = {
23412
23610
  version: version$3};
23413
23611
 
@@ -24326,9 +24524,34 @@ function assertCCTPV2Config(config) {
24326
24524
  tokenAddress: source.chain.usdcAddress,
24327
24525
  operationContext: sourceOperationContext
24328
24526
  });
24527
+ await this.assertAmountCoversRecipientSetupFee(params);
24329
24528
  return bridge(params, this);
24330
24529
  }
24331
24530
  /**
24531
+ * Reject a forwarded transfer to Solana whose amount does not exceed the fee.
24532
+ *
24533
+ * CCTP v2 reverts a burn whose `maxFee` is not less than its amount, and the Solana
24534
+ * forwarding fee includes the recipient token account rent. Checking before the
24535
+ * approval avoids sending a transaction that can never be followed by a burn.
24536
+ * Skipped when the caller provides `config.maxFee`.
24537
+ *
24538
+ * @param params - The validated CCTP v2 bridge parameters.
24539
+ * @returns A promise that resolves when the amount covers the fee.
24540
+ * @throws {KitError} INPUT_INVALID_AMOUNT (FATAL) when the fee is greater than or equal
24541
+ * to the amount.
24542
+ */ async assertAmountCoversRecipientSetupFee(params) {
24543
+ const { destination, amount, config } = params;
24544
+ if (destination.useForwarder !== true || config.maxFee !== undefined || !requiresRecipientSetup(destination.chain.type)) {
24545
+ return;
24546
+ }
24547
+ const { providerFee, forwarderFee } = await this.getMaxFee(params);
24548
+ const maxFee = providerFee + forwarderFee;
24549
+ if (maxFee >= BigInt(amount)) {
24550
+ // Amounts and fees are in USDC minor units (6 decimals)
24551
+ throw createInvalidAmountError(formatUnits(amount, 6), `Amount must be greater than the ${formatUnits(String(maxFee), 6)} USDC fee for forwarded transfers to ${destination.chain.name}, which includes creating the recipient's token account`);
24552
+ }
24553
+ }
24554
+ /**
24332
24555
  * Retry a failed or incomplete CCTP v2 bridge operation.
24333
24556
  *
24334
24557
  * Analyzes the bridge result to determine where to continue and executes
@@ -25045,6 +25268,9 @@ function assertCCTPV2Config(config) {
25045
25268
  * | FAST | true | No | maxFee = calculatedBurnFee + forwardingFee |
25046
25269
  * | FAST | true | Yes | maxFee = config.maxFee |
25047
25270
  *
25271
+ * For forwarded burns to Solana, the forwarding fee includes the rent for creating the
25272
+ * recipient's token account. A caller-provided `maxFee` must cover it too.
25273
+ *
25048
25274
  * @param params - The bridge parameters object containing:
25049
25275
  * - `source`: The source wallet context with chain definition and adapter
25050
25276
  * - `destination`: The destination wallet context with chain definition and adapter
@@ -25083,6 +25309,7 @@ function assertCCTPV2Config(config) {
25083
25309
  }
25084
25310
  // Get the min finality threshold based on the transfer speed
25085
25311
  const minFinalityThreshold = CCTPv2MinFinalityThreshold[transferSpeed];
25312
+ const includeRecipientSetup = requiresRecipientSetup(destination.chain.type);
25086
25313
  // SLOW transfer without forwarder: no fee
25087
25314
  if (transferSpeed === TransferSpeed.SLOW && !useForwarder) {
25088
25315
  return {
@@ -25092,7 +25319,7 @@ function assertCCTPV2Config(config) {
25092
25319
  }
25093
25320
  // SLOW transfer with forwarder: only forwarding fee
25094
25321
  if (transferSpeed === TransferSpeed.SLOW && useForwarder) {
25095
- const forwarderFee = await fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold);
25322
+ const forwarderFee = await fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold, includeRecipientSetup);
25096
25323
  return {
25097
25324
  providerFee: 0n,
25098
25325
  forwarderFee
@@ -25102,7 +25329,7 @@ function assertCCTPV2Config(config) {
25102
25329
  // Fetch fees in parallel when forwarder is enabled
25103
25330
  const [scaledBps, forwarderFee] = await Promise.all([
25104
25331
  fetchUsdcFastBurnFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet),
25105
- useForwarder ? fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold) : Promise.resolve(0n)
25332
+ useForwarder ? fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold, includeRecipientSetup) : Promise.resolve(0n)
25106
25333
  ]);
25107
25334
  // Calculate fee proportional to the transfer amount
25108
25335
  const amountInMinorUnits = BigInt(amount);
@@ -25652,6 +25879,21 @@ function assertCCTPV2Config(config) {
25652
25879
  'bridge_forward'
25653
25880
  ]
25654
25881
  ];
25882
+ /**
25883
+ * Provider step names whose `txHash` is the source-chain transaction that
25884
+ * moves funds into the bridge protocol.
25885
+ *
25886
+ * @remarks
25887
+ * The success event carries this hash so the backend can join it to the
25888
+ * on-chain CCTP / CCTPx event for the same transfer. `burn` is the CCTP v2
25889
+ * step (including batched and source-fee flows); `transfer` is the CCTPx
25890
+ * `CrossChainTokenService` step.
25891
+ *
25892
+ * @internal
25893
+ */ const BRIDGE_SOURCE_TX_STEP_NAMES = [
25894
+ 'burn',
25895
+ 'transfer'
25896
+ ];
25655
25897
 
25656
25898
  /**
25657
25899
  * Base URL for Circle's Quote API (hosted in Iris) on mainnet/production.
@@ -26709,6 +26951,85 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
26709
26951
  }
26710
26952
  return undefined;
26711
26953
  }
26954
+ /**
26955
+ * Pick the source-chain transaction hash from a bridge result.
26956
+ *
26957
+ * Walk the steps from the end and return the hash of the most recent
26958
+ * successful source step (`burn` for CCTP v2, `transfer` for CCTPx). Walking
26959
+ * backwards selects the attempt that landed when a retry appended a new
26960
+ * source step after a failed one.
26961
+ *
26962
+ * @param steps - All steps from the bridge result.
26963
+ * @returns The source transaction hash, or `undefined` if no source step recorded one.
26964
+ *
26965
+ * @internal
26966
+ */ function pickSourceTxHash(steps) {
26967
+ for(let i = steps.length - 1; i >= 0; i--){
26968
+ const step = steps[i];
26969
+ if (step?.txHash != null && step.state === 'success' && BRIDGE_SOURCE_TX_STEP_NAMES.includes(step.name)) {
26970
+ return step.txHash;
26971
+ }
26972
+ }
26973
+ return undefined;
26974
+ }
26975
+ /**
26976
+ * Resolve the token value reported in telemetry.
26977
+ *
26978
+ * CCTPx reports `result.token` as a bytes32 token id, while the backend's
26979
+ * canonical tables key tokens by symbol. Map the canonical id of a known CCTPx
26980
+ * token back to its symbol and pass any other value (USDC, or a registry token
26981
+ * without a known symbol) through unchanged. Registry symbols are not used
26982
+ * because they are not unique across CCTPx tokens. Never throws.
26983
+ *
26984
+ * @param token - The token from a bridge result.
26985
+ * @param sourceChain - The result's source chain; selects testnet or mainnet ids.
26986
+ * @returns The known symbol, or `token` unchanged.
26987
+ *
26988
+ * @internal
26989
+ */ function toTelemetryToken(token, sourceChain) {
26990
+ try {
26991
+ const network = sourceChain.isTestnet ? 'testnet' : 'mainnet';
26992
+ return resolveToKnownTokenSymbol(token, network) ?? token;
26993
+ } catch {
26994
+ return token;
26995
+ }
26996
+ }
26997
+ /**
26998
+ * Emit the `bridge_bridge` success event for a completed transfer.
26999
+ *
27000
+ * No-ops unless `result.state` is `'success'`. Failed results are already
27001
+ * reported by error telemetry. Never throws: a malformed result (for example
27002
+ * from a custom provider) is reported as a telemetry drop warning and the
27003
+ * caller's result is returned unchanged.
27004
+ *
27005
+ * @param result - The human-readable bridge result returned to the caller.
27006
+ * @param config - Analytics telemetry identity, gated by `disableAnalytics`.
27007
+ *
27008
+ * @internal
27009
+ */ function emitBridgeSuccessTelemetry(result, config) {
27010
+ if (config.disabled || result.state !== 'success') {
27011
+ return;
27012
+ }
27013
+ try {
27014
+ const txHash = pickSourceTxHash(result.steps);
27015
+ // `JSON.stringify` turns a non-finite number into `null`, which the logs
27016
+ // endpoint's strict schema rejects along with the whole event.
27017
+ const amountIn = Number.parseFloat(result.amount);
27018
+ emitSuccessTelemetry(BRIDGE_EVENT_TYPES.BRIDGE, config, {
27019
+ sourceChain: result.source.chain.chain,
27020
+ destinationChain: result.destination.chain.chain,
27021
+ tokenIn: toTelemetryToken(result.token, result.source.chain),
27022
+ ...Number.isFinite(amountIn) && {
27023
+ amountIn
27024
+ },
27025
+ ...txHash != null && {
27026
+ txHash
27027
+ }
27028
+ });
27029
+ } catch (telemetryError) {
27030
+ warnTelemetryDrop(BRIDGE_EVENT_TYPES.BRIDGE, telemetryError);
27031
+ }
27032
+ }
26712
27033
  /**
26713
27034
  * BridgeKit caller component for retry and estimate operations.
26714
27035
  */ const BRIDGE_KIT_CALLER = {
@@ -26839,6 +27160,10 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
26839
27160
  /** Whether error telemetry is disabled. */ disableErrorReporting;
26840
27161
  /** Per-kit telemetry identity for shared helpers. */ telemetryConfig;
26841
27162
  /**
27163
+ * Per-kit telemetry identity for success events. Gated by `disableAnalytics`
27164
+ * independently of `disableErrorReporting`.
27165
+ */ analyticsTelemetryConfig;
27166
+ /**
26842
27167
  * Create a new BridgeKit instance.
26843
27168
  *
26844
27169
  * @param config - The configuration containing the CCTPv2 provider
@@ -26865,6 +27190,11 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
26865
27190
  sdkVersion: pkg$4.version,
26866
27191
  disabled: this.disableErrorReporting
26867
27192
  };
27193
+ this.analyticsTelemetryConfig = {
27194
+ sdkName: SDK_NAME,
27195
+ sdkVersion: pkg$4.version,
27196
+ disabled: config.disableAnalytics === true
27197
+ };
26868
27198
  for (const provider of this.providers){
26869
27199
  provider.registerDispatcher(this.actionDispatcher);
26870
27200
  }
@@ -26878,7 +27208,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
26878
27208
  this.actionDispatcher.off(actionOrWildCard, handler);
26879
27209
  }
26880
27210
  async bridge(params) {
26881
- return withErrorTelemetry(async ()=>{
27211
+ const bridgeResult = await withErrorTelemetry(async ()=>{
26882
27212
  // First validate the parameters
26883
27213
  assertBridgeParams(params, bridgeParamsWithChainIdentifierSchema);
26884
27214
  // Then resolve chain definitions (includes adapter chain support validation)
@@ -26915,7 +27245,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
26915
27245
  emitResultStepErrorTelemetry(failedStep, BRIDGE_STEP_EVENT_MAP, BRIDGE_EVENT_TYPES.BRIDGE, this.telemetryConfig, {
26916
27246
  sourceChain: resolveChainName(params.from.chain),
26917
27247
  destinationChain: resolveChainName(params.to.chain),
26918
- tokenIn: params.token,
27248
+ tokenIn: toTelemetryToken(result.token, result.source.chain),
26919
27249
  ...txHash != null && {
26920
27250
  txHash
26921
27251
  }
@@ -26927,6 +27257,8 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
26927
27257
  destinationChain: resolveChainName(params.to.chain),
26928
27258
  tokenIn: params.token
26929
27259
  });
27260
+ emitBridgeSuccessTelemetry(bridgeResult, this.analyticsTelemetryConfig);
27261
+ return bridgeResult;
26930
27262
  }
26931
27263
  /**
26932
27264
  * Retry a failed or incomplete cross-chain USDC bridge operation.
@@ -26997,7 +27329,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
26997
27329
  * )
26998
27330
  * ```
26999
27331
  */ async retry(result, context, invocationMeta) {
27000
- return withErrorTelemetry(async ()=>{
27332
+ const retriedResult = await withErrorTelemetry(async ()=>{
27001
27333
  // Cast the providers list to the wide view here. The tuple
27002
27334
  // type on `this.providers` retains concrete provider types
27003
27335
  // (CCTPv2 narrows `TToken` to `'USDC'`); calling `.retry`
@@ -27025,7 +27357,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
27025
27357
  emitResultStepErrorTelemetry(failedStep, BRIDGE_STEP_EVENT_MAP, BRIDGE_EVENT_TYPES.RETRY, this.telemetryConfig, {
27026
27358
  sourceChain: result.source.chain.chain,
27027
27359
  destinationChain: result.destination.chain.chain,
27028
- tokenIn: result.token,
27360
+ tokenIn: toTelemetryToken(result.token, result.source.chain),
27029
27361
  ...txHash != null && {
27030
27362
  txHash
27031
27363
  }
@@ -27039,8 +27371,16 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
27039
27371
  }, BRIDGE_EVENT_TYPES.RETRY, this.telemetryConfig, {
27040
27372
  sourceChain: result.source.chain.chain,
27041
27373
  destinationChain: result.destination.chain.chain,
27042
- tokenIn: result.token
27374
+ tokenIn: toTelemetryToken(result.token, result.source.chain)
27043
27375
  });
27376
+ // A retry that completes the transfer is the transfer's only success
27377
+ // event, so it reports the same `bridge_bridge` type as `bridge()`. An
27378
+ // input that already succeeded was reported by the call that completed it
27379
+ // (CCTP v2 returns such a result unchanged), so it is not reported again.
27380
+ if (result.state !== 'success') {
27381
+ emitBridgeSuccessTelemetry(retriedResult, this.analyticsTelemetryConfig);
27382
+ }
27383
+ return retriedResult;
27044
27384
  }
27045
27385
  async estimate(params) {
27046
27386
  return withErrorTelemetry(async ()=>{
@@ -27636,6 +27976,9 @@ registerKit(`${pkg$4.name}/${pkg$4.version}`);
27636
27976
  ...context.disableErrorReporting != null && {
27637
27977
  disableErrorReporting: context.disableErrorReporting
27638
27978
  },
27979
+ ...context.disableAnalytics != null && {
27980
+ disableAnalytics: context.disableAnalytics
27981
+ },
27639
27982
  ...context.headers != null && {
27640
27983
  headers: context.headers
27641
27984
  }
@@ -27658,7 +28001,7 @@ registerKit(`${pkg$4.name}/${pkg$4.version}`);
27658
28001
  };
27659
28002
 
27660
28003
  var name$2 = "@circle-fin/swap-kit";
27661
- var version$2 = "1.7.1";
28004
+ var version$2 = "1.8.1";
27662
28005
  var pkg$2 = {
27663
28006
  name: name$2,
27664
28007
  version: version$2};
@@ -28000,6 +28343,64 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
28000
28343
  }, {
28001
28344
  message: 'fee amount must be non-negative (>= 0)'
28002
28345
  });
28346
+ /**
28347
+ * Parses a display-only field leniently: a value `schema` rejects is replaced
28348
+ * with `fallback` instead of failing the response that carries it.
28349
+ * Implemented with `preprocess` rather than Zod's `.catch()` because static
28350
+ * analysis misreads `.catch` on the schema chain as an unhandled Promise
28351
+ * (S7785).
28352
+ */ const withFallback = (schema, fallback)=>zod.z.preprocess((value)=>schema.safeParse(value).success ? value : fallback, schema);
28353
+ const swapRouteTokenSchema = zod.z.object({
28354
+ symbol: zod.z.string(),
28355
+ address: zod.z.string(),
28356
+ decimals: zod.z.number()
28357
+ });
28358
+ const swapRouteMetadataSchema = zod.z.record(zod.z.unknown()).optional();
28359
+ const swapRouteStepSchema = zod.z.object({
28360
+ type: zod.z.string(),
28361
+ tool: zod.z.string(),
28362
+ toolName: zod.z.string(),
28363
+ fromToken: swapRouteTokenSchema,
28364
+ toToken: swapRouteTokenSchema,
28365
+ estimate: zod.z.object({
28366
+ fromAmount: zod.z.string(),
28367
+ toAmount: zod.z.string(),
28368
+ gasCostUSD: zod.z.string().optional()
28369
+ }),
28370
+ metadata: swapRouteMetadataSchema
28371
+ });
28372
+ /**
28373
+ * Strict schema for a `SwapRoute`. Module-private: service responses
28374
+ * parse routes leniently through {@link responseSwapRouteSchema}.
28375
+ */ const swapRouteSchema = zod.z.object({
28376
+ provider: zod.z.string().min(1, 'provider must be a non-empty string'),
28377
+ steps: zod.z.array(swapRouteStepSchema),
28378
+ metadata: swapRouteMetadataSchema
28379
+ });
28380
+ /**
28381
+ * Route details are display-only, so service responses parse them leniently:
28382
+ * steps or metadata in a shape the SDK does not know are dropped rather than
28383
+ * failing the quote or swap they describe. Steps are all-or-nothing: if any
28384
+ * step is malformed, `steps` is empty, so a route never silently loses a hop.
28385
+ */ const responseSwapRouteSchema = swapRouteSchema.extend({
28386
+ steps: withFallback(swapRouteSchema.shape.steps, []),
28387
+ metadata: withFallback(swapRouteMetadataSchema, undefined)
28388
+ });
28389
+ const createSwapFeeItemSchema = zod.z.object({
28390
+ token: zod.z.string({
28391
+ required_error: 'fee token is required',
28392
+ invalid_type_error: 'fee token must be a string'
28393
+ }).min(1, 'fee token must be a non-empty string'),
28394
+ amount: feeAmountSchema,
28395
+ decimals: zod.z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
28396
+ symbol: zod.z.string({
28397
+ invalid_type_error: 'fee token symbol must be a string'
28398
+ }).min(1, 'fee token symbol must be a non-empty string').optional(),
28399
+ // Descriptive metadata: a value the SDK cannot use is dropped rather than
28400
+ // failing the response that carries the fee.
28401
+ type: withFallback(zod.z.string().min(1).optional(), undefined),
28402
+ chain: withFallback(zod.z.string().min(1).optional(), undefined)
28403
+ });
28003
28404
  /**
28004
28405
  * Zod schema for validating API keys.
28005
28406
  *
@@ -28085,10 +28486,7 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
28085
28486
  /** Quote information with estimated amounts and route */ quote: zod.z.object({
28086
28487
  /** Estimated output amount (base units) */ estimatedAmount: zod.z.string().min(1, 'estimatedAmount must be a non-empty string').regex(/^\d+$/, 'estimatedAmount must be a numeric string'),
28087
28488
  /** Guaranteed minimum output amount (base units) */ minAmount: zod.z.string().min(1, 'minAmount must be a non-empty string').regex(/^\d+$/, 'minAmount must be a numeric string'),
28088
- /** Route information from DEX aggregator */ route: zod.z.object({
28089
- provider: zod.z.string().min(1, 'provider must be a non-empty string'),
28090
- steps: zod.z.array(zod.z.unknown())
28091
- })
28489
+ /** Route information from DEX aggregator */ route: responseSwapRouteSchema
28092
28490
  }),
28093
28491
  /** Fee context indicating where fees should be collected */ feeContext: quoteFeeContextSchema
28094
28492
  });
@@ -28304,19 +28702,6 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
28304
28702
  }).min(1, 'toChain must be a non-empty string if provided').optional(),
28305
28703
  apiKey: apiKeySchema.optional()
28306
28704
  });
28307
- /**
28308
- * Zod schema for validating CreateSwapResponse payloads.
28309
- */ const createSwapFeeItemSchema = zod.z.object({
28310
- token: zod.z.string({
28311
- required_error: 'fee token is required',
28312
- invalid_type_error: 'fee token must be a string'
28313
- }).min(1, 'fee token must be a non-empty string'),
28314
- amount: feeAmountSchema,
28315
- decimals: zod.z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
28316
- symbol: zod.z.string({
28317
- invalid_type_error: 'fee token symbol must be a string'
28318
- }).min(1, 'fee token symbol must be a non-empty string').optional()
28319
- });
28320
28705
  /**
28321
28706
  * Developer fee item schema with basis field.
28322
28707
  */ const createSwapDeveloperFeeItemSchema = createSwapFeeItemSchema.extend({
@@ -28454,6 +28839,8 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
28454
28839
  correlationId: zod.z.preprocess((value)=>zod.z.string().uuid().safeParse(value).success ? value : undefined, zod.z.string().optional()),
28455
28840
  config: createSwapRequestBaseSchema.shape.config.optional(),
28456
28841
  fees: createSwapFeesSchema.optional(),
28842
+ // A route the SDK cannot parse is dropped instead of failing the swap.
28843
+ route: withFallback(responseSwapRouteSchema.optional(), undefined),
28457
28844
  transaction: createSwapTransactionSchema
28458
28845
  });
28459
28846
 
@@ -29581,6 +29968,16 @@ createTokenRegistry();
29581
29968
  name: 'USDC',
29582
29969
  version: '2'
29583
29970
  },
29971
+ Cronos: {
29972
+ chainId: Cronos.chainId,
29973
+ name: 'USDC',
29974
+ version: '2'
29975
+ },
29976
+ Morph: {
29977
+ chainId: Morph.chainId,
29978
+ name: 'USDC',
29979
+ version: '2'
29980
+ },
29584
29981
  Arc_Testnet: {
29585
29982
  chainId: ArcTestnet.chainId,
29586
29983
  name: 'USDC',
@@ -29669,6 +30066,7 @@ const optionalSwapChainIdentifierField = swapChainIdentifierField.optional();
29669
30066
  * - customFee: Optional fee configuration
29670
30067
  * - apiKey: Optional credential string
29671
30068
  * - kitKey: Optional credential string (deprecated alias for apiKey)
30069
+ * - batchTransactions: Optional boolean to opt out of atomic batching
29672
30070
  */ const swapConfigSchema = zod.z.object({
29673
30071
  allowanceStrategy: allowanceStrategySchema.optional(),
29674
30072
  slippageBps: zod.z.number().int().min(0).optional(),
@@ -29679,7 +30077,10 @@ const optionalSwapChainIdentifierField = swapChainIdentifierField.optional();
29679
30077
  })(zod.z.string())).optional(),
29680
30078
  customFee: swapCustomFeeSchema.optional(),
29681
30079
  apiKey: zod.z.string().optional(),
29682
- kitKey: zod.z.string().optional()
30080
+ kitKey: zod.z.string().optional(),
30081
+ batchTransactions: zod.z.boolean({
30082
+ invalid_type_error: 'batchTransactions must be a boolean'
30083
+ }).optional()
29683
30084
  });
29684
30085
  const swapDestinationSchema = zod.z.object({
29685
30086
  chain: optionalSwapChainIdentifierField,
@@ -29872,7 +30273,7 @@ new Set(Object.values(Blockchain));
29872
30273
  registerKit(`${pkg$2.name}/${pkg$2.version}`);
29873
30274
 
29874
30275
  var name$1 = "@circle-fin/earn-kit";
29875
- var version$1 = "1.8.1";
30276
+ var version$1 = "1.10.0";
29876
30277
  var pkg$1 = {
29877
30278
  name: name$1,
29878
30279
  version: version$1};
@@ -31312,7 +31713,7 @@ function hasCrossChainDepositQuoteShape(params) {
31312
31713
  registerKit(`${pkg$1.name}/${pkg$1.version}`);
31313
31714
 
31314
31715
  var name = "@circle-fin/borrow-kit";
31315
- var version = "1.0.0";
31716
+ var version = "1.1.1";
31316
31717
  var pkg = {
31317
31718
  name: name,
31318
31719
  version: version};