@circle-fin/app-kit 1.16.0 → 1.17.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/bridge.d.ts CHANGED
@@ -899,10 +899,10 @@ declare enum Blockchain {
899
899
  *
900
900
  * Unlike the full {@link Blockchain} enum, SwapChain includes mainnet
901
901
  * networks and explicitly whitelisted testnets (e.g., {@link Arc_Testnet})
902
- * where adapter contracts are deployed (CCTPv2 support).
902
+ * where Adapter contracts are deployed.
903
903
  *
904
904
  * Dynamic validation via {@link isSwapSupportedChain} ensures chains
905
- * automatically work when adapter contracts and supported tokens are deployed.
905
+ * automatically work when Adapter contracts and supported tokens are deployed.
906
906
  *
907
907
  * @example
908
908
  * ```typescript
@@ -942,20 +942,22 @@ declare enum SwapChain {
942
942
  HyperEVM = "HyperEVM",
943
943
  Monad = "Monad",
944
944
  Arc = "Arc",
945
+ Cronos = "Cronos",
946
+ Morph = "Morph",
945
947
  Arc_Testnet = "Arc_Testnet"
946
948
  }
947
949
  /**
948
950
  * Chain definition that supports swap operations.
949
951
  *
950
952
  * @remarks
951
- * Expanded from 4 to ~18 supported chains based on:
952
- * - CCTPv2 support (adapter contract deployed)
953
+ * Expanded from 4 to supported mainnets and whitelisted testnets based on:
954
+ * - A deployed Adapter contract, configured directly or through CCTP v2
953
955
  * - Mainnet chains plus whitelisted testnets (e.g., Arc Testnet)
954
956
  *
955
957
  * Use `isSwapSupportedChain()` for runtime validation.
956
958
  */
957
959
  type SwapChainDefinition = ChainDefinition & {
958
- chain: Blockchain.Ethereum | Blockchain.Base | Blockchain.Polygon | Blockchain.Solana | Blockchain.Arbitrum | Blockchain.Optimism | Blockchain.Avalanche | Blockchain.Linea | Blockchain.Ink | Blockchain.World_Chain | Blockchain.Unichain | Blockchain.Plume | Blockchain.Sei | Blockchain.Sonic | Blockchain.XDC | Blockchain.HyperEVM | Blockchain.Monad | Blockchain.Arc | Blockchain.Arc_Testnet;
960
+ chain: Blockchain.Ethereum | Blockchain.Base | Blockchain.Polygon | Blockchain.Solana | Blockchain.Arbitrum | Blockchain.Optimism | Blockchain.Avalanche | Blockchain.Linea | Blockchain.Ink | Blockchain.World_Chain | Blockchain.Unichain | Blockchain.Plume | Blockchain.Sei | Blockchain.Sonic | Blockchain.XDC | Blockchain.HyperEVM | Blockchain.Monad | Blockchain.Arc | Blockchain.Cronos | Blockchain.Morph | Blockchain.Arc_Testnet;
959
961
  };
960
962
  /**
961
963
  * Chain identifier accepted by swap operations.
@@ -6975,7 +6977,7 @@ interface ServiceSwapConfig {
6975
6977
  *
6976
6978
  * @defaultValue true
6977
6979
  */
6978
- batchTransactions?: boolean;
6980
+ batchTransactions?: boolean | undefined;
6979
6981
  }
6980
6982
  /**
6981
6983
  * Parameters for initiating a swap operation through the Stablecoin Service.
@@ -7439,6 +7441,33 @@ interface SwapConfig {
7439
7441
  * `apiKey` is omitted, and `apiKey` takes precedence when both are set.
7440
7442
  */
7441
7443
  kitKey?: string;
7444
+ /**
7445
+ * Enable or disable atomic batched execution of the approval and swap.
7446
+ *
7447
+ * When `true` (or omitted), an EVM swap that needs an on-chain ERC-20
7448
+ * approval submits the approval and the swap as one atomic batch if the
7449
+ * connected wallet supports it (EIP-5792, or a signing strategy that
7450
+ * declares atomic batching). Set to `false` to force the sequential
7451
+ * approve-then-swap flow.
7452
+ *
7453
+ * @remarks
7454
+ * Has no effect on the gasless permit path, native-token swaps, or Solana,
7455
+ * which already execute as a single transaction. USDT input always uses the
7456
+ * sequential path because its allowance must be reset to zero first. The
7457
+ * batched path relies on the wallet's own gas estimation for the swap call;
7458
+ * set `false` if your wallet under-estimates gas for complex routes or
7459
+ * rejects batched calls.
7460
+ *
7461
+ * @defaultValue `undefined` (batching attempted when the wallet supports it)
7462
+ *
7463
+ * @example
7464
+ * ```typescript
7465
+ * const config: SwapConfig = {
7466
+ * batchTransactions: false, // force sequential approve → swap
7467
+ * }
7468
+ * ```
7469
+ */
7470
+ batchTransactions?: boolean | undefined;
7442
7471
  }
7443
7472
  /**
7444
7473
  * Resolved parameters for swap operations after validation and normalization.
package/bridge.mjs CHANGED
@@ -2515,22 +2515,73 @@ let activeRedactor = defaultMessageRedactor;
2515
2515
  '0x9147d463': 'Final balance is less than the initial balance',
2516
2516
  '0xf4b3b1bc': 'Native token transfer to the beneficiary failed'
2517
2517
  };
2518
+ /**
2519
+ * Matches revert data: a 4-byte selector followed by whole ABI-encoded bytes.
2520
+ */ const REVERT_DATA_PATTERN = /^0x[0-9a-f]{8}(?:[0-9a-f]{2})*$/i;
2521
+ /**
2522
+ * Returns the revert data held by one error in a `cause` chain.
2523
+ *
2524
+ * Browser wallets (EIP-1193) wrap the node's error, so the revert data sits
2525
+ * one level down as `data.data`. viem's `getContractError` reads it the same
2526
+ * way, then keeps it on `ContractFunctionRevertedError.raw` and drops the
2527
+ * node's error from the chain.
2528
+ *
2529
+ * @param link - One error in the `cause` chain
2530
+ * @returns The `raw` or `data` string, or undefined if there is none
2531
+ */ function getRevertData(link) {
2532
+ if ('raw' in link && typeof link.raw === 'string' && REVERT_DATA_PATTERN.test(link.raw)) {
2533
+ return link.raw;
2534
+ }
2535
+ if (!('data' in link)) {
2536
+ return undefined;
2537
+ }
2538
+ const { data } = link;
2539
+ if (typeof data === 'string') {
2540
+ return data;
2541
+ }
2542
+ if (data !== null && typeof data === 'object' && 'data' in data && typeof data.data === 'string') {
2543
+ return data.data;
2544
+ }
2545
+ return undefined;
2546
+ }
2547
+ /**
2548
+ * Finds the first revert data on the error or in its `cause` chain that
2549
+ * `accept` takes.
2550
+ *
2551
+ * viem keeps the node's revert data on an inner `RpcRequestError`, not on
2552
+ * the error it throws. The `seen` set stops a self-referencing `cause` chain.
2553
+ *
2554
+ * @param error - The error object
2555
+ * @param accept - Returns true for the data shape the caller wants
2556
+ * @returns The data as written on the error, or undefined if not found
2557
+ */ function findRevertData(error, accept) {
2558
+ const seen = new Set();
2559
+ let current = error;
2560
+ while(current !== null && typeof current === 'object' && !seen.has(current)){
2561
+ seen.add(current);
2562
+ const data = getRevertData(current);
2563
+ if (data !== undefined && accept(data)) {
2564
+ return data;
2565
+ }
2566
+ current = 'cause' in current ? current.cause : undefined;
2567
+ }
2568
+ return undefined;
2569
+ }
2518
2570
  /**
2519
2571
  * Attempts to extract an error selector from an error object or message.
2520
2572
  *
2521
2573
  * Checks multiple sources in priority order:
2522
- * 1. `error.data` field
2574
+ * 1. `raw` or `data` field (or nested `data.data`) on the error or anywhere
2575
+ * in its `cause` chain
2523
2576
  * 2. Message pattern: "custom error 0x8baa579f"
2524
2577
  *
2525
2578
  * @param msg - The error message
2526
2579
  * @param error - The error object (optional)
2527
2580
  * @returns The 4 bytes selector , or undefined if not found
2528
2581
  */ function extractErrorSelector(msg, error) {
2529
- // Check error.data field
2530
- if (error !== null && typeof error === 'object' && 'data' in error) {
2531
- if (typeof error.data === 'string' && /^0x[0-9a-f]{8}$/i.test(error.data)) {
2532
- return error.data.toLowerCase();
2533
- }
2582
+ const data = findRevertData(error, (value)=>/^0x[0-9a-f]{8}$/i.test(value));
2583
+ if (data !== undefined) {
2584
+ return data.toLowerCase();
2534
2585
  }
2535
2586
  // Check for "custom error 0x8baa579f" in the message
2536
2587
  const match = /custom error (0x[0-9a-f]{8})\b/i.exec(msg);
@@ -3803,6 +3854,8 @@ var SwapChain;
3803
3854
  SwapChain["HyperEVM"] = "HyperEVM";
3804
3855
  SwapChain["Monad"] = "Monad";
3805
3856
  SwapChain["Arc"] = "Arc";
3857
+ SwapChain["Cronos"] = "Cronos";
3858
+ SwapChain["Morph"] = "Morph";
3806
3859
  // Testnet chains with swap support
3807
3860
  SwapChain["Arc_Testnet"] = "Arc_Testnet";
3808
3861
  })(SwapChain || (SwapChain = {}));
@@ -5135,7 +5188,8 @@ var BorrowChain;
5135
5188
  }
5136
5189
  },
5137
5190
  kitContracts: {
5138
- bridge: BRIDGE_CONTRACT_EVM_MAINNET
5191
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
5192
+ adapter: ADAPTER_CONTRACT_EVM_MAINNET
5139
5193
  }
5140
5194
  });
5141
5195
 
@@ -6004,7 +6058,8 @@ var BorrowChain;
6004
6058
  }
6005
6059
  },
6006
6060
  kitContracts: {
6007
- bridge: BRIDGE_CONTRACT_EVM_MAINNET
6061
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
6062
+ adapter: ADAPTER_CONTRACT_EVM_MAINNET
6008
6063
  }
6009
6064
  });
6010
6065
 
@@ -8302,8 +8357,8 @@ var Chains = /*#__PURE__*/Object.freeze({
8302
8357
  * Zod schema for validating swap-specific chain identifiers.
8303
8358
  *
8304
8359
  * Validates chains based on:
8305
- * - CCTPv2 support (adapter contract deployed)
8306
- * - Mainnet only (no testnets)
8360
+ * - Membership in the SwapChain enum
8361
+ * - Mainnet or explicitly allowlisted testnet
8307
8362
  * - At least one supported token available
8308
8363
  *
8309
8364
  */ const swapChainIdentifierSchema = z.union([
@@ -8782,7 +8837,7 @@ const swapTokenEnumSchema = z.enum([
8782
8837
  *
8783
8838
  * A chain supports swaps if ALL conditions are met:
8784
8839
  * 1. Is a member of the {@link SwapChain} enum
8785
- * 2. Has CCTPv2 support (adapter contract deployed)
8840
+ * 2. Has an Adapter contract configured directly or through CCTP v2
8786
8841
  *
8787
8842
  * Testnets are allowed only when explicitly listed in the
8788
8843
  * {@link SwapChain} enum (e.g., Arc_Testnet).
@@ -8803,14 +8858,14 @@ const swapTokenEnumSchema = z.enum([
8803
8858
  * @remarks
8804
8859
  * Chains automatically become swap-enabled when:
8805
8860
  * - Added to the {@link SwapChain} enum
8806
- * - Adapter contract is deployed (CCTPv2)
8861
+ * - An Adapter contract is deployed and configured
8807
8862
  *
8808
8863
  * No code changes needed when new chains are added!
8809
8864
  */ function isSwapSupportedChain(chain) {
8810
8865
  if (!(chain.chain in SwapChain)) {
8811
8866
  return false;
8812
8867
  }
8813
- if (!isCCTPV2Supported(chain)) {
8868
+ if (!isCCTPV2Supported(chain) && !hasCustomContractSupport(chain, 'adapter')) {
8814
8869
  return false;
8815
8870
  }
8816
8871
  return true;
@@ -8821,7 +8876,7 @@ const swapTokenEnumSchema = z.enum([
8821
8876
  *
8822
8877
  * Dynamically filter chain definitions to include only those that:
8823
8878
  * - Are members of the {@link SwapChain} enum
8824
- * - Have CCTPv2 support
8879
+ * - Have an Adapter contract configured directly or through CCTP v2
8825
8880
  *
8826
8881
  * This function is pure and accepts chains as parameter to avoid
8827
8882
  * circular dependencies.
@@ -10255,11 +10310,13 @@ function parseOrThrow(value, schema, context) {
10255
10310
  [Blockchain.Arbitrum]: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
10256
10311
  [Blockchain.Avalanche]: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7',
10257
10312
  [Blockchain.Celo]: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
10313
+ [Blockchain.Cronos]: '0x66e428c3f67a68878562e79A0234c1F83c208770',
10258
10314
  [Blockchain.Ethereum]: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
10259
10315
  [Blockchain.HyperEVM]: '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb',
10260
10316
  [Blockchain.Ink]: '0x0200C29006150606B650577BBE7B6248F58470c1',
10261
10317
  [Blockchain.Linea]: '0xA219439258ca9da29E9Cc4cE5596924745e12B93',
10262
10318
  [Blockchain.Monad]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
10319
+ [Blockchain.Morph]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
10263
10320
  [Blockchain.NEAR]: 'usdt.tether-token.near',
10264
10321
  [Blockchain.Optimism]: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58',
10265
10322
  [Blockchain.Polkadot_Asset_Hub]: '1984',
@@ -10318,6 +10375,7 @@ function parseOrThrow(value, schema, context) {
10318
10375
  [Blockchain.Arbitrum]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
10319
10376
  [Blockchain.Avalanche]: '0xd586E7F844cEa2F87f50152665BCbc2C279D8d70',
10320
10377
  [Blockchain.Base]: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb',
10378
+ [Blockchain.Cronos]: '0xF2001B145b43032AAF5Ee2884e456CCd805F677D',
10321
10379
  [Blockchain.Ethereum]: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
10322
10380
  [Blockchain.Linea]: '0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5',
10323
10381
  [Blockchain.Optimism]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
@@ -10380,7 +10438,9 @@ function parseOrThrow(value, schema, context) {
10380
10438
  [Blockchain.Arbitrum]: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
10381
10439
  [Blockchain.Avalanche]: '0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB',
10382
10440
  [Blockchain.Base]: '0x4200000000000000000000000000000000000006',
10441
+ [Blockchain.Cronos]: '0xe44Fd7fCb2b1581822D0c862B68222998a0c299a',
10383
10442
  [Blockchain.Ethereum]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
10443
+ [Blockchain.Morph]: '0x5300000000000000000000000000000000000011',
10384
10444
  [Blockchain.Optimism]: '0x4200000000000000000000000000000000000006',
10385
10445
  [Blockchain.Polygon]: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619',
10386
10446
  [Blockchain.Solana]: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs'
@@ -10399,6 +10459,7 @@ function parseOrThrow(value, schema, context) {
10399
10459
  locators: {
10400
10460
  [Blockchain.Ethereum]: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
10401
10461
  [Blockchain.Arbitrum]: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f',
10462
+ [Blockchain.Cronos]: '0x062E66477Faf219F25D27dCED647BF57C3107d52',
10402
10463
  [Blockchain.Avalanche]: '0x50b7545627a5162F82A992c33b87aDc75187B218'
10403
10464
  }
10404
10465
  };
@@ -12229,7 +12290,7 @@ function resolveOptions(options) {
12229
12290
  }
12230
12291
 
12231
12292
  var name$3 = "@circle-fin/bridge-kit";
12232
- var version$4 = "1.15.2";
12293
+ var version$4 = "1.15.3";
12233
12294
  var pkg$4 = {
12234
12295
  name: name$3,
12235
12296
  version: version$4};
@@ -14794,7 +14855,11 @@ function createNoopLogger() {
14794
14855
  tokenId: bytes32Hex,
14795
14856
  domainId: nonNegativeInteger,
14796
14857
  tokenAddress: z.string(),
14797
- tokenManagerAddress: z.string()
14858
+ tokenManagerAddress: z.string(),
14859
+ // Operator-controlled per-chain kill switch (CCTPE-3979). Optional for
14860
+ // back-compat with older IRIS versions that do not surface it. Downstream
14861
+ // consumers in `findCCTPXDeployment` treat a missing value as `true`.
14862
+ enabled: z.boolean().optional()
14798
14863
  });
14799
14864
  /**
14800
14865
  * Schema for one token entry in the token registry response.
@@ -15278,17 +15343,23 @@ function createNoopLogger() {
15278
15343
  /**
15279
15344
  * Find a token's deployment on the given CCTP domain.
15280
15345
  *
15346
+ * A deployment row with `enabled === false` is treated as missing: an IRIS
15347
+ * operator has flipped the per-chain kill switch (CCTPE-3979), so the SDK must
15348
+ * not route through it even though the row still exists in the registry. A
15349
+ * missing or `true` `enabled` value remains routable — the field is optional on
15350
+ * older IRIS versions and absence is read as "allowed".
15351
+ *
15281
15352
  * @param token - The registry token whose deployments are searched.
15282
15353
  * @param domain - The CCTP domain id to match.
15283
15354
  * @returns The matching {@link CCTPXTokenDeployment}, or `undefined` when the
15284
- * token has no deployment on that domain.
15355
+ * token has no deployment on that domain or the deployment is disabled.
15285
15356
  *
15286
15357
  * @example
15287
15358
  * ```typescript
15288
15359
  * const deployment = findCCTPXDeployment(token, 0)
15289
15360
  * ```
15290
15361
  */ function findCCTPXDeployment(token, domain) {
15291
- return token.deployments.find((deployment)=>deployment.domainId === domain);
15362
+ return token.deployments.find((deployment)=>deployment.domainId === domain && deployment.enabled !== false);
15292
15363
  }
15293
15364
 
15294
15365
  /**
@@ -15390,6 +15461,24 @@ function createNoopLogger() {
15390
15461
  }
15391
15462
  }
15392
15463
  })
15464
+ ],
15465
+ // The token is not deployed on one of the route chains, or an operator has
15466
+ // flipped the per-chain `enabled` kill switch on the IRIS deployment row.
15467
+ // Either way the route is permanently unavailable until the operator intervenes;
15468
+ // a retry at the same source/destination will keep returning this error.
15469
+ [
15470
+ 'TOKEN_NOT_SUPPORTED_ON_ROUTE',
15471
+ ({ sourceDomain, destinationDomain })=>new KitError({
15472
+ ...InputError.UNSUPPORTED_ROUTE,
15473
+ recoverability: 'FATAL',
15474
+ message: 'CCTPx fee quote rejected the route: the token is not supported on ' + 'the source or destination chain (missing deployment or operator-disabled).',
15475
+ cause: {
15476
+ trace: {
15477
+ sourceDomain,
15478
+ destinationDomain
15479
+ }
15480
+ }
15481
+ })
15393
15482
  ]
15394
15483
  ]);
15395
15484
  /**
@@ -23400,7 +23489,7 @@ const mockAttestationMessage = {
23400
23489
  return step;
23401
23490
  }
23402
23491
 
23403
- var version$3 = "1.14.1";
23492
+ var version$3 = "1.14.2";
23404
23493
  var pkg$3 = {
23405
23494
  version: version$3};
23406
23495
 
@@ -27651,7 +27740,7 @@ registerKit(`${pkg$4.name}/${pkg$4.version}`);
27651
27740
  };
27652
27741
 
27653
27742
  var name$2 = "@circle-fin/swap-kit";
27654
- var version$2 = "1.7.1";
27743
+ var version$2 = "1.8.0";
27655
27744
  var pkg$2 = {
27656
27745
  name: name$2,
27657
27746
  version: version$2};
@@ -27993,6 +28082,64 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
27993
28082
  }, {
27994
28083
  message: 'fee amount must be non-negative (>= 0)'
27995
28084
  });
28085
+ /**
28086
+ * Parses a display-only field leniently: a value `schema` rejects is replaced
28087
+ * with `fallback` instead of failing the response that carries it.
28088
+ * Implemented with `preprocess` rather than Zod's `.catch()` because static
28089
+ * analysis misreads `.catch` on the schema chain as an unhandled Promise
28090
+ * (S7785).
28091
+ */ const withFallback = (schema, fallback)=>z.preprocess((value)=>schema.safeParse(value).success ? value : fallback, schema);
28092
+ const swapRouteTokenSchema = z.object({
28093
+ symbol: z.string(),
28094
+ address: z.string(),
28095
+ decimals: z.number()
28096
+ });
28097
+ const swapRouteMetadataSchema = z.record(z.unknown()).optional();
28098
+ const swapRouteStepSchema = z.object({
28099
+ type: z.string(),
28100
+ tool: z.string(),
28101
+ toolName: z.string(),
28102
+ fromToken: swapRouteTokenSchema,
28103
+ toToken: swapRouteTokenSchema,
28104
+ estimate: z.object({
28105
+ fromAmount: z.string(),
28106
+ toAmount: z.string(),
28107
+ gasCostUSD: z.string().optional()
28108
+ }),
28109
+ metadata: swapRouteMetadataSchema
28110
+ });
28111
+ /**
28112
+ * Strict schema for a `SwapRoute`. Module-private: service responses
28113
+ * parse routes leniently through {@link responseSwapRouteSchema}.
28114
+ */ const swapRouteSchema = z.object({
28115
+ provider: z.string().min(1, 'provider must be a non-empty string'),
28116
+ steps: z.array(swapRouteStepSchema),
28117
+ metadata: swapRouteMetadataSchema
28118
+ });
28119
+ /**
28120
+ * Route details are display-only, so service responses parse them leniently:
28121
+ * steps or metadata in a shape the SDK does not know are dropped rather than
28122
+ * failing the quote or swap they describe. Steps are all-or-nothing: if any
28123
+ * step is malformed, `steps` is empty, so a route never silently loses a hop.
28124
+ */ const responseSwapRouteSchema = swapRouteSchema.extend({
28125
+ steps: withFallback(swapRouteSchema.shape.steps, []),
28126
+ metadata: withFallback(swapRouteMetadataSchema, undefined)
28127
+ });
28128
+ const createSwapFeeItemSchema = z.object({
28129
+ token: z.string({
28130
+ required_error: 'fee token is required',
28131
+ invalid_type_error: 'fee token must be a string'
28132
+ }).min(1, 'fee token must be a non-empty string'),
28133
+ amount: feeAmountSchema,
28134
+ decimals: z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
28135
+ symbol: z.string({
28136
+ invalid_type_error: 'fee token symbol must be a string'
28137
+ }).min(1, 'fee token symbol must be a non-empty string').optional(),
28138
+ // Descriptive metadata: a value the SDK cannot use is dropped rather than
28139
+ // failing the response that carries the fee.
28140
+ type: withFallback(z.string().min(1).optional(), undefined),
28141
+ chain: withFallback(z.string().min(1).optional(), undefined)
28142
+ });
27996
28143
  /**
27997
28144
  * Zod schema for validating API keys.
27998
28145
  *
@@ -28078,10 +28225,7 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
28078
28225
  /** Quote information with estimated amounts and route */ quote: z.object({
28079
28226
  /** Estimated output amount (base units) */ estimatedAmount: z.string().min(1, 'estimatedAmount must be a non-empty string').regex(/^\d+$/, 'estimatedAmount must be a numeric string'),
28080
28227
  /** Guaranteed minimum output amount (base units) */ minAmount: z.string().min(1, 'minAmount must be a non-empty string').regex(/^\d+$/, 'minAmount must be a numeric string'),
28081
- /** Route information from DEX aggregator */ route: z.object({
28082
- provider: z.string().min(1, 'provider must be a non-empty string'),
28083
- steps: z.array(z.unknown())
28084
- })
28228
+ /** Route information from DEX aggregator */ route: responseSwapRouteSchema
28085
28229
  }),
28086
28230
  /** Fee context indicating where fees should be collected */ feeContext: quoteFeeContextSchema
28087
28231
  });
@@ -28297,19 +28441,6 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
28297
28441
  }).min(1, 'toChain must be a non-empty string if provided').optional(),
28298
28442
  apiKey: apiKeySchema.optional()
28299
28443
  });
28300
- /**
28301
- * Zod schema for validating CreateSwapResponse payloads.
28302
- */ const createSwapFeeItemSchema = z.object({
28303
- token: z.string({
28304
- required_error: 'fee token is required',
28305
- invalid_type_error: 'fee token must be a string'
28306
- }).min(1, 'fee token must be a non-empty string'),
28307
- amount: feeAmountSchema,
28308
- decimals: z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
28309
- symbol: z.string({
28310
- invalid_type_error: 'fee token symbol must be a string'
28311
- }).min(1, 'fee token symbol must be a non-empty string').optional()
28312
- });
28313
28444
  /**
28314
28445
  * Developer fee item schema with basis field.
28315
28446
  */ const createSwapDeveloperFeeItemSchema = createSwapFeeItemSchema.extend({
@@ -28447,6 +28578,8 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
28447
28578
  correlationId: z.preprocess((value)=>z.string().uuid().safeParse(value).success ? value : undefined, z.string().optional()),
28448
28579
  config: createSwapRequestBaseSchema.shape.config.optional(),
28449
28580
  fees: createSwapFeesSchema.optional(),
28581
+ // A route the SDK cannot parse is dropped instead of failing the swap.
28582
+ route: withFallback(responseSwapRouteSchema.optional(), undefined),
28450
28583
  transaction: createSwapTransactionSchema
28451
28584
  });
28452
28585
 
@@ -29574,6 +29707,16 @@ createTokenRegistry();
29574
29707
  name: 'USDC',
29575
29708
  version: '2'
29576
29709
  },
29710
+ Cronos: {
29711
+ chainId: Cronos.chainId,
29712
+ name: 'USDC',
29713
+ version: '2'
29714
+ },
29715
+ Morph: {
29716
+ chainId: Morph.chainId,
29717
+ name: 'USDC',
29718
+ version: '2'
29719
+ },
29577
29720
  Arc_Testnet: {
29578
29721
  chainId: ArcTestnet.chainId,
29579
29722
  name: 'USDC',
@@ -29662,6 +29805,7 @@ const optionalSwapChainIdentifierField = swapChainIdentifierField.optional();
29662
29805
  * - customFee: Optional fee configuration
29663
29806
  * - apiKey: Optional credential string
29664
29807
  * - kitKey: Optional credential string (deprecated alias for apiKey)
29808
+ * - batchTransactions: Optional boolean to opt out of atomic batching
29665
29809
  */ const swapConfigSchema = z.object({
29666
29810
  allowanceStrategy: allowanceStrategySchema.optional(),
29667
29811
  slippageBps: z.number().int().min(0).optional(),
@@ -29672,7 +29816,10 @@ const optionalSwapChainIdentifierField = swapChainIdentifierField.optional();
29672
29816
  })(z.string())).optional(),
29673
29817
  customFee: swapCustomFeeSchema.optional(),
29674
29818
  apiKey: z.string().optional(),
29675
- kitKey: z.string().optional()
29819
+ kitKey: z.string().optional(),
29820
+ batchTransactions: z.boolean({
29821
+ invalid_type_error: 'batchTransactions must be a boolean'
29822
+ }).optional()
29676
29823
  });
29677
29824
  const swapDestinationSchema = z.object({
29678
29825
  chain: optionalSwapChainIdentifierField,
@@ -29865,7 +30012,7 @@ new Set(Object.values(Blockchain));
29865
30012
  registerKit(`${pkg$2.name}/${pkg$2.version}`);
29866
30013
 
29867
30014
  var name$1 = "@circle-fin/earn-kit";
29868
- var version$1 = "1.8.1";
30015
+ var version$1 = "1.9.0";
29869
30016
  var pkg$1 = {
29870
30017
  name: name$1,
29871
30018
  version: version$1};
@@ -31369,7 +31516,7 @@ registerKit(`${pkg$1.name}/${pkg$1.version}`);
31369
31516
  };
31370
31517
 
31371
31518
  var name = "@circle-fin/borrow-kit";
31372
- var version = "1.0.0";
31519
+ var version = "1.1.0";
31373
31520
  var pkg = {
31374
31521
  name: name,
31375
31522
  version: version};
package/chains.cjs CHANGED
@@ -154,6 +154,8 @@ var SwapChain;
154
154
  SwapChain["HyperEVM"] = "HyperEVM";
155
155
  SwapChain["Monad"] = "Monad";
156
156
  SwapChain["Arc"] = "Arc";
157
+ SwapChain["Cronos"] = "Cronos";
158
+ SwapChain["Morph"] = "Morph";
157
159
  // Testnet chains with swap support
158
160
  SwapChain["Arc_Testnet"] = "Arc_Testnet";
159
161
  })(SwapChain || (SwapChain = {}));
@@ -1486,7 +1488,8 @@ var BorrowChain;
1486
1488
  }
1487
1489
  },
1488
1490
  kitContracts: {
1489
- bridge: BRIDGE_CONTRACT_EVM_MAINNET
1491
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
1492
+ adapter: ADAPTER_CONTRACT_EVM_MAINNET
1490
1493
  }
1491
1494
  });
1492
1495
 
@@ -2355,7 +2358,8 @@ var BorrowChain;
2355
2358
  }
2356
2359
  },
2357
2360
  kitContracts: {
2358
- bridge: BRIDGE_CONTRACT_EVM_MAINNET
2361
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
2362
+ adapter: ADAPTER_CONTRACT_EVM_MAINNET
2359
2363
  }
2360
2364
  });
2361
2365
 
@@ -4401,8 +4405,8 @@ var BorrowChain;
4401
4405
  * Zod schema for validating swap-specific chain identifiers.
4402
4406
  *
4403
4407
  * Validates chains based on:
4404
- * - CCTPv2 support (adapter contract deployed)
4405
- * - Mainnet only (no testnets)
4408
+ * - Membership in the SwapChain enum
4409
+ * - Mainnet or explicitly allowlisted testnet
4406
4410
  * - At least one supported token available
4407
4411
  *
4408
4412
  */ zod.z.union([
package/chains.mjs CHANGED
@@ -152,6 +152,8 @@ var SwapChain;
152
152
  SwapChain["HyperEVM"] = "HyperEVM";
153
153
  SwapChain["Monad"] = "Monad";
154
154
  SwapChain["Arc"] = "Arc";
155
+ SwapChain["Cronos"] = "Cronos";
156
+ SwapChain["Morph"] = "Morph";
155
157
  // Testnet chains with swap support
156
158
  SwapChain["Arc_Testnet"] = "Arc_Testnet";
157
159
  })(SwapChain || (SwapChain = {}));
@@ -1484,7 +1486,8 @@ var BorrowChain;
1484
1486
  }
1485
1487
  },
1486
1488
  kitContracts: {
1487
- bridge: BRIDGE_CONTRACT_EVM_MAINNET
1489
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
1490
+ adapter: ADAPTER_CONTRACT_EVM_MAINNET
1488
1491
  }
1489
1492
  });
1490
1493
 
@@ -2353,7 +2356,8 @@ var BorrowChain;
2353
2356
  }
2354
2357
  },
2355
2358
  kitContracts: {
2356
- bridge: BRIDGE_CONTRACT_EVM_MAINNET
2359
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
2360
+ adapter: ADAPTER_CONTRACT_EVM_MAINNET
2357
2361
  }
2358
2362
  });
2359
2363
 
@@ -4399,8 +4403,8 @@ var BorrowChain;
4399
4403
  * Zod schema for validating swap-specific chain identifiers.
4400
4404
  *
4401
4405
  * Validates chains based on:
4402
- * - CCTPv2 support (adapter contract deployed)
4403
- * - Mainnet only (no testnets)
4406
+ * - Membership in the SwapChain enum
4407
+ * - Mainnet or explicitly allowlisted testnet
4404
4408
  * - At least one supported token available
4405
4409
  *
4406
4410
  */ z.union([
package/context.d.cts CHANGED
@@ -899,10 +899,10 @@ declare enum Blockchain {
899
899
  *
900
900
  * Unlike the full {@link Blockchain} enum, SwapChain includes mainnet
901
901
  * networks and explicitly whitelisted testnets (e.g., {@link Arc_Testnet})
902
- * where adapter contracts are deployed (CCTPv2 support).
902
+ * where Adapter contracts are deployed.
903
903
  *
904
904
  * Dynamic validation via {@link isSwapSupportedChain} ensures chains
905
- * automatically work when adapter contracts and supported tokens are deployed.
905
+ * automatically work when Adapter contracts and supported tokens are deployed.
906
906
  *
907
907
  * @example
908
908
  * ```typescript
@@ -942,20 +942,22 @@ declare enum SwapChain {
942
942
  HyperEVM = "HyperEVM",
943
943
  Monad = "Monad",
944
944
  Arc = "Arc",
945
+ Cronos = "Cronos",
946
+ Morph = "Morph",
945
947
  Arc_Testnet = "Arc_Testnet"
946
948
  }
947
949
  /**
948
950
  * Chain definition that supports swap operations.
949
951
  *
950
952
  * @remarks
951
- * Expanded from 4 to ~18 supported chains based on:
952
- * - CCTPv2 support (adapter contract deployed)
953
+ * Expanded from 4 to supported mainnets and whitelisted testnets based on:
954
+ * - A deployed Adapter contract, configured directly or through CCTP v2
953
955
  * - Mainnet chains plus whitelisted testnets (e.g., Arc Testnet)
954
956
  *
955
957
  * Use `isSwapSupportedChain()` for runtime validation.
956
958
  */
957
959
  type SwapChainDefinition = ChainDefinition & {
958
- chain: Blockchain.Ethereum | Blockchain.Base | Blockchain.Polygon | Blockchain.Solana | Blockchain.Arbitrum | Blockchain.Optimism | Blockchain.Avalanche | Blockchain.Linea | Blockchain.Ink | Blockchain.World_Chain | Blockchain.Unichain | Blockchain.Plume | Blockchain.Sei | Blockchain.Sonic | Blockchain.XDC | Blockchain.HyperEVM | Blockchain.Monad | Blockchain.Arc | Blockchain.Arc_Testnet;
960
+ chain: Blockchain.Ethereum | Blockchain.Base | Blockchain.Polygon | Blockchain.Solana | Blockchain.Arbitrum | Blockchain.Optimism | Blockchain.Avalanche | Blockchain.Linea | Blockchain.Ink | Blockchain.World_Chain | Blockchain.Unichain | Blockchain.Plume | Blockchain.Sei | Blockchain.Sonic | Blockchain.XDC | Blockchain.HyperEVM | Blockchain.Monad | Blockchain.Arc | Blockchain.Cronos | Blockchain.Morph | Blockchain.Arc_Testnet;
959
961
  };
960
962
  /**
961
963
  * Chain identifier accepted by swap operations.
@@ -6733,7 +6735,7 @@ interface ServiceSwapConfig {
6733
6735
  *
6734
6736
  * @defaultValue true
6735
6737
  */
6736
- batchTransactions?: boolean;
6738
+ batchTransactions?: boolean | undefined;
6737
6739
  }
6738
6740
  /**
6739
6741
  * Parameters for initiating a swap operation through the Stablecoin Service.
@@ -7197,6 +7199,33 @@ interface SwapConfig {
7197
7199
  * `apiKey` is omitted, and `apiKey` takes precedence when both are set.
7198
7200
  */
7199
7201
  kitKey?: string;
7202
+ /**
7203
+ * Enable or disable atomic batched execution of the approval and swap.
7204
+ *
7205
+ * When `true` (or omitted), an EVM swap that needs an on-chain ERC-20
7206
+ * approval submits the approval and the swap as one atomic batch if the
7207
+ * connected wallet supports it (EIP-5792, or a signing strategy that
7208
+ * declares atomic batching). Set to `false` to force the sequential
7209
+ * approve-then-swap flow.
7210
+ *
7211
+ * @remarks
7212
+ * Has no effect on the gasless permit path, native-token swaps, or Solana,
7213
+ * which already execute as a single transaction. USDT input always uses the
7214
+ * sequential path because its allowance must be reset to zero first. The
7215
+ * batched path relies on the wallet's own gas estimation for the swap call;
7216
+ * set `false` if your wallet under-estimates gas for complex routes or
7217
+ * rejects batched calls.
7218
+ *
7219
+ * @defaultValue `undefined` (batching attempted when the wallet supports it)
7220
+ *
7221
+ * @example
7222
+ * ```typescript
7223
+ * const config: SwapConfig = {
7224
+ * batchTransactions: false, // force sequential approve → swap
7225
+ * }
7226
+ * ```
7227
+ */
7228
+ batchTransactions?: boolean | undefined;
7200
7229
  }
7201
7230
  /**
7202
7231
  * Resolved parameters for swap operations after validation and normalization.