@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
package/swap.cjs CHANGED
@@ -2010,22 +2010,73 @@ class KitError extends Error {
2010
2010
  '0x9147d463': 'Final balance is less than the initial balance',
2011
2011
  '0xf4b3b1bc': 'Native token transfer to the beneficiary failed'
2012
2012
  };
2013
+ /**
2014
+ * Matches revert data: a 4-byte selector followed by whole ABI-encoded bytes.
2015
+ */ const REVERT_DATA_PATTERN = /^0x[0-9a-f]{8}(?:[0-9a-f]{2})*$/i;
2016
+ /**
2017
+ * Returns the revert data held by one error in a `cause` chain.
2018
+ *
2019
+ * Browser wallets (EIP-1193) wrap the node's error, so the revert data sits
2020
+ * one level down as `data.data`. viem's `getContractError` reads it the same
2021
+ * way, then keeps it on `ContractFunctionRevertedError.raw` and drops the
2022
+ * node's error from the chain.
2023
+ *
2024
+ * @param link - One error in the `cause` chain
2025
+ * @returns The `raw` or `data` string, or undefined if there is none
2026
+ */ function getRevertData(link) {
2027
+ if ('raw' in link && typeof link.raw === 'string' && REVERT_DATA_PATTERN.test(link.raw)) {
2028
+ return link.raw;
2029
+ }
2030
+ if (!('data' in link)) {
2031
+ return undefined;
2032
+ }
2033
+ const { data } = link;
2034
+ if (typeof data === 'string') {
2035
+ return data;
2036
+ }
2037
+ if (data !== null && typeof data === 'object' && 'data' in data && typeof data.data === 'string') {
2038
+ return data.data;
2039
+ }
2040
+ return undefined;
2041
+ }
2042
+ /**
2043
+ * Finds the first revert data on the error or in its `cause` chain that
2044
+ * `accept` takes.
2045
+ *
2046
+ * viem keeps the node's revert data on an inner `RpcRequestError`, not on
2047
+ * the error it throws. The `seen` set stops a self-referencing `cause` chain.
2048
+ *
2049
+ * @param error - The error object
2050
+ * @param accept - Returns true for the data shape the caller wants
2051
+ * @returns The data as written on the error, or undefined if not found
2052
+ */ function findRevertData(error, accept) {
2053
+ const seen = new Set();
2054
+ let current = error;
2055
+ while(current !== null && typeof current === 'object' && !seen.has(current)){
2056
+ seen.add(current);
2057
+ const data = getRevertData(current);
2058
+ if (data !== undefined && accept(data)) {
2059
+ return data;
2060
+ }
2061
+ current = 'cause' in current ? current.cause : undefined;
2062
+ }
2063
+ return undefined;
2064
+ }
2013
2065
  /**
2014
2066
  * Attempts to extract an error selector from an error object or message.
2015
2067
  *
2016
2068
  * Checks multiple sources in priority order:
2017
- * 1. `error.data` field
2069
+ * 1. `raw` or `data` field (or nested `data.data`) on the error or anywhere
2070
+ * in its `cause` chain
2018
2071
  * 2. Message pattern: "custom error 0x8baa579f"
2019
2072
  *
2020
2073
  * @param msg - The error message
2021
2074
  * @param error - The error object (optional)
2022
2075
  * @returns The 4 bytes selector , or undefined if not found
2023
2076
  */ function extractErrorSelector(msg, error) {
2024
- // Check error.data field
2025
- if (error !== null && typeof error === 'object' && 'data' in error) {
2026
- if (typeof error.data === 'string' && /^0x[0-9a-f]{8}$/i.test(error.data)) {
2027
- return error.data.toLowerCase();
2028
- }
2077
+ const data = findRevertData(error, (value)=>/^0x[0-9a-f]{8}$/i.test(value));
2078
+ if (data !== undefined) {
2079
+ return data.toLowerCase();
2029
2080
  }
2030
2081
  // Check for "custom error 0x8baa579f" in the message
2031
2082
  const match = /custom error (0x[0-9a-f]{8})\b/i.exec(msg);
@@ -3151,6 +3202,8 @@ var SwapChain;
3151
3202
  SwapChain["HyperEVM"] = "HyperEVM";
3152
3203
  SwapChain["Monad"] = "Monad";
3153
3204
  SwapChain["Arc"] = "Arc";
3205
+ SwapChain["Cronos"] = "Cronos";
3206
+ SwapChain["Morph"] = "Morph";
3154
3207
  // Testnet chains with swap support
3155
3208
  SwapChain["Arc_Testnet"] = "Arc_Testnet";
3156
3209
  })(SwapChain || (SwapChain = {}));
@@ -3842,14 +3895,14 @@ var BorrowChain;
3842
3895
  symbol: 'USDC',
3843
3896
  // Arc uses native USDC with 18 decimals for gas payments (EVM standard).
3844
3897
  // Note: The ERC-20 USDC contract at usdcAddress uses 6 decimals.
3845
- // See: https://docs.arc.network/arc/references/contract-addresses
3898
+ // See: https://docs.arc.io/arc/references/contract-addresses
3846
3899
  decimals: 18
3847
3900
  },
3848
3901
  chainId: 5042002,
3849
3902
  isTestnet: true,
3850
3903
  explorerUrl: 'https://testnet.arcscan.app/tx/{hash}',
3851
3904
  rpcEndpoints: [
3852
- 'https://rpc.testnet.arc.network/'
3905
+ 'https://rpc.testnet.arc.io'
3853
3906
  ],
3854
3907
  eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
3855
3908
  usdcAddress: '0x3600000000000000000000000000000000000000',
@@ -4494,7 +4547,8 @@ var BorrowChain;
4494
4547
  }
4495
4548
  },
4496
4549
  kitContracts: {
4497
- bridge: BRIDGE_CONTRACT_EVM_MAINNET
4550
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
4551
+ adapter: ADAPTER_CONTRACT_EVM_MAINNET
4498
4552
  }
4499
4553
  });
4500
4554
 
@@ -5363,7 +5417,8 @@ var BorrowChain;
5363
5417
  }
5364
5418
  },
5365
5419
  kitContracts: {
5366
- bridge: BRIDGE_CONTRACT_EVM_MAINNET
5420
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
5421
+ adapter: ADAPTER_CONTRACT_EVM_MAINNET
5367
5422
  }
5368
5423
  });
5369
5424
 
@@ -7253,6 +7308,56 @@ var Chains = {
7253
7308
  Blockchain.World_Chain_Sepolia
7254
7309
  ]);
7255
7310
 
7311
+ /**
7312
+ * Check if a chain supports a specific type of custom smart contract logic.
7313
+ *
7314
+ * This function examines a chain definition to determine if it has a specific
7315
+ * contract type configured. When a chain has custom contract support, it can
7316
+ * use enhanced features and custom business logic in addition to the standard
7317
+ * CCTP approve/burn/mint flow.
7318
+ *
7319
+ * @param chain - The chain definition to examine for custom contract support.
7320
+ * @param contractType - The type of contract to check for (e.g., 'bridge').
7321
+ * @returns True if the chain supports the specified contract type with a valid address configured.
7322
+ *
7323
+ * @example
7324
+ * ```typescript
7325
+ * import { hasCustomContractSupport, Ethereum } from '@core/chains'
7326
+ *
7327
+ * // Check if a chain supports bridge contracts
7328
+ * if (hasCustomContractSupport(Ethereum, 'bridge')) {
7329
+ * // Runtime validation confirmed kitContracts.bridge exists
7330
+ * console.log('Bridge contract:', Ethereum.kitContracts?.bridge)
7331
+ * return executeCustomFlow(Ethereum.kitContracts?.bridge!, params)
7332
+ * } else {
7333
+ * console.log('Using standard CCTP flow')
7334
+ * return executeStandardFlow(params)
7335
+ * }
7336
+ * ```
7337
+ *
7338
+ * @example
7339
+ * ```typescript
7340
+ * // Usage in flow determination
7341
+ * function determineBridgingFlow(chain: ChainDefinition, params: BridgeParams) {
7342
+ * if (hasCustomContractSupport(chain, 'bridge')) {
7343
+ * return 'custom'
7344
+ * } else if (isCCTPV2Supported(chain)) {
7345
+ * return 'standard'
7346
+ * } else {
7347
+ * throw new Error(`Chain ${chain.name} is not supported for bridging`)
7348
+ * }
7349
+ * }
7350
+ *
7351
+ * // Future usage with other contract types (when added to KitContractType)
7352
+ * // if (hasCustomContractSupport(someChain, 'customType')) {
7353
+ * // console.log('Custom contract:', someChain.kitContracts?.customType)
7354
+ * // }
7355
+ * ```
7356
+ */ function hasCustomContractSupport(chain, contractType) {
7357
+ const contractAddress = chain.kitContracts?.[contractType];
7358
+ return typeof contractAddress === 'string' && contractAddress.trim().length > 0;
7359
+ }
7360
+
7256
7361
  /**
7257
7362
  * Temporary allowlist of chains permitted to initiate Gateway fast deposits.
7258
7363
  * Only chains keyed here are eligible; all others are rejected. Using the
@@ -7506,8 +7611,8 @@ var Chains = {
7506
7611
  * Zod schema for validating swap-specific chain identifiers.
7507
7612
  *
7508
7613
  * Validates chains based on:
7509
- * - CCTPv2 support (adapter contract deployed)
7510
- * - Mainnet only (no testnets)
7614
+ * - Membership in the SwapChain enum
7615
+ * - Mainnet or explicitly allowlisted testnet
7511
7616
  * - At least one supported token available
7512
7617
  *
7513
7618
  */ const swapChainIdentifierSchema = zod.z.union([
@@ -8062,7 +8167,7 @@ const swapTokenEnumSchema = zod.z.enum([
8062
8167
  *
8063
8168
  * A chain supports swaps if ALL conditions are met:
8064
8169
  * 1. Is a member of the {@link SwapChain} enum
8065
- * 2. Has CCTPv2 support (adapter contract deployed)
8170
+ * 2. Has an Adapter contract configured directly or through CCTP v2
8066
8171
  *
8067
8172
  * Testnets are allowed only when explicitly listed in the
8068
8173
  * {@link SwapChain} enum (e.g., Arc_Testnet).
@@ -8083,14 +8188,14 @@ const swapTokenEnumSchema = zod.z.enum([
8083
8188
  * @remarks
8084
8189
  * Chains automatically become swap-enabled when:
8085
8190
  * - Added to the {@link SwapChain} enum
8086
- * - Adapter contract is deployed (CCTPv2)
8191
+ * - An Adapter contract is deployed and configured
8087
8192
  *
8088
8193
  * No code changes needed when new chains are added!
8089
8194
  */ function isSwapSupportedChain(chain) {
8090
8195
  if (!(chain.chain in SwapChain)) {
8091
8196
  return false;
8092
8197
  }
8093
- if (!isCCTPV2Supported(chain)) {
8198
+ if (!isCCTPV2Supported(chain) && !hasCustomContractSupport(chain, 'adapter')) {
8094
8199
  return false;
8095
8200
  }
8096
8201
  return true;
@@ -8101,7 +8206,7 @@ const swapTokenEnumSchema = zod.z.enum([
8101
8206
  *
8102
8207
  * Dynamically filter chain definitions to include only those that:
8103
8208
  * - Are members of the {@link SwapChain} enum
8104
- * - Have CCTPv2 support
8209
+ * - Have an Adapter contract configured directly or through CCTP v2
8105
8210
  *
8106
8211
  * This function is pure and accepts chains as parameter to avoid
8107
8212
  * circular dependencies.
@@ -9421,11 +9526,13 @@ const swapTokenEnumSchema = zod.z.enum([
9421
9526
  [Blockchain.Arbitrum]: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
9422
9527
  [Blockchain.Avalanche]: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7',
9423
9528
  [Blockchain.Celo]: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
9529
+ [Blockchain.Cronos]: '0x66e428c3f67a68878562e79A0234c1F83c208770',
9424
9530
  [Blockchain.Ethereum]: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
9425
9531
  [Blockchain.HyperEVM]: '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb',
9426
9532
  [Blockchain.Ink]: '0x0200C29006150606B650577BBE7B6248F58470c1',
9427
9533
  [Blockchain.Linea]: '0xA219439258ca9da29E9Cc4cE5596924745e12B93',
9428
9534
  [Blockchain.Monad]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
9535
+ [Blockchain.Morph]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
9429
9536
  [Blockchain.NEAR]: 'usdt.tether-token.near',
9430
9537
  [Blockchain.Optimism]: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58',
9431
9538
  [Blockchain.Polkadot_Asset_Hub]: '1984',
@@ -9484,6 +9591,7 @@ const swapTokenEnumSchema = zod.z.enum([
9484
9591
  [Blockchain.Arbitrum]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
9485
9592
  [Blockchain.Avalanche]: '0xd586E7F844cEa2F87f50152665BCbc2C279D8d70',
9486
9593
  [Blockchain.Base]: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb',
9594
+ [Blockchain.Cronos]: '0xF2001B145b43032AAF5Ee2884e456CCd805F677D',
9487
9595
  [Blockchain.Ethereum]: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
9488
9596
  [Blockchain.Linea]: '0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5',
9489
9597
  [Blockchain.Optimism]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
@@ -9546,7 +9654,9 @@ const swapTokenEnumSchema = zod.z.enum([
9546
9654
  [Blockchain.Arbitrum]: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
9547
9655
  [Blockchain.Avalanche]: '0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB',
9548
9656
  [Blockchain.Base]: '0x4200000000000000000000000000000000000006',
9657
+ [Blockchain.Cronos]: '0xe44Fd7fCb2b1581822D0c862B68222998a0c299a',
9549
9658
  [Blockchain.Ethereum]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
9659
+ [Blockchain.Morph]: '0x5300000000000000000000000000000000000011',
9550
9660
  [Blockchain.Optimism]: '0x4200000000000000000000000000000000000006',
9551
9661
  [Blockchain.Polygon]: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619',
9552
9662
  [Blockchain.Solana]: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs'
@@ -9565,6 +9675,7 @@ const swapTokenEnumSchema = zod.z.enum([
9565
9675
  locators: {
9566
9676
  [Blockchain.Ethereum]: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
9567
9677
  [Blockchain.Arbitrum]: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f',
9678
+ [Blockchain.Cronos]: '0x062E66477Faf219F25D27dCED647BF57C3107d52',
9568
9679
  [Blockchain.Avalanche]: '0x50b7545627a5162F82A992c33b87aDc75187B218'
9569
9680
  }
9570
9681
  };
@@ -10737,7 +10848,7 @@ const swapTokenEnumSchema = zod.z.enum([
10737
10848
  }
10738
10849
 
10739
10850
  var name$3 = "@circle-fin/bridge-kit";
10740
- var version$3 = "1.15.2";
10851
+ var version$3 = "1.16.0";
10741
10852
  var pkg$3 = {
10742
10853
  name: name$3,
10743
10854
  version: version$3};
@@ -12392,7 +12503,7 @@ const validateQuoteItemSchema = zod.z.object({
12392
12503
  registerKit(`${pkg$3.name}/${pkg$3.version}`);
12393
12504
 
12394
12505
  var name$2 = "@circle-fin/swap-kit";
12395
- var version$2 = "1.7.1";
12506
+ var version$2 = "1.8.1";
12396
12507
  var pkg$2 = {
12397
12508
  name: name$2,
12398
12509
  version: version$2};
@@ -12852,6 +12963,64 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
12852
12963
  }, {
12853
12964
  message: 'fee amount must be non-negative (>= 0)'
12854
12965
  });
12966
+ /**
12967
+ * Parses a display-only field leniently: a value `schema` rejects is replaced
12968
+ * with `fallback` instead of failing the response that carries it.
12969
+ * Implemented with `preprocess` rather than Zod's `.catch()` because static
12970
+ * analysis misreads `.catch` on the schema chain as an unhandled Promise
12971
+ * (S7785).
12972
+ */ const withFallback = (schema, fallback)=>zod.z.preprocess((value)=>schema.safeParse(value).success ? value : fallback, schema);
12973
+ const swapRouteTokenSchema = zod.z.object({
12974
+ symbol: zod.z.string(),
12975
+ address: zod.z.string(),
12976
+ decimals: zod.z.number()
12977
+ });
12978
+ const swapRouteMetadataSchema = zod.z.record(zod.z.unknown()).optional();
12979
+ const swapRouteStepSchema = zod.z.object({
12980
+ type: zod.z.string(),
12981
+ tool: zod.z.string(),
12982
+ toolName: zod.z.string(),
12983
+ fromToken: swapRouteTokenSchema,
12984
+ toToken: swapRouteTokenSchema,
12985
+ estimate: zod.z.object({
12986
+ fromAmount: zod.z.string(),
12987
+ toAmount: zod.z.string(),
12988
+ gasCostUSD: zod.z.string().optional()
12989
+ }),
12990
+ metadata: swapRouteMetadataSchema
12991
+ });
12992
+ /**
12993
+ * Strict schema for a `SwapRoute`. Module-private: service responses
12994
+ * parse routes leniently through {@link responseSwapRouteSchema}.
12995
+ */ const swapRouteSchema = zod.z.object({
12996
+ provider: zod.z.string().min(1, 'provider must be a non-empty string'),
12997
+ steps: zod.z.array(swapRouteStepSchema),
12998
+ metadata: swapRouteMetadataSchema
12999
+ });
13000
+ /**
13001
+ * Route details are display-only, so service responses parse them leniently:
13002
+ * steps or metadata in a shape the SDK does not know are dropped rather than
13003
+ * failing the quote or swap they describe. Steps are all-or-nothing: if any
13004
+ * step is malformed, `steps` is empty, so a route never silently loses a hop.
13005
+ */ const responseSwapRouteSchema = swapRouteSchema.extend({
13006
+ steps: withFallback(swapRouteSchema.shape.steps, []),
13007
+ metadata: withFallback(swapRouteMetadataSchema, undefined)
13008
+ });
13009
+ const createSwapFeeItemSchema = zod.z.object({
13010
+ token: zod.z.string({
13011
+ required_error: 'fee token is required',
13012
+ invalid_type_error: 'fee token must be a string'
13013
+ }).min(1, 'fee token must be a non-empty string'),
13014
+ amount: feeAmountSchema,
13015
+ decimals: zod.z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
13016
+ symbol: zod.z.string({
13017
+ invalid_type_error: 'fee token symbol must be a string'
13018
+ }).min(1, 'fee token symbol must be a non-empty string').optional(),
13019
+ // Descriptive metadata: a value the SDK cannot use is dropped rather than
13020
+ // failing the response that carries the fee.
13021
+ type: withFallback(zod.z.string().min(1).optional(), undefined),
13022
+ chain: withFallback(zod.z.string().min(1).optional(), undefined)
13023
+ });
12855
13024
  /**
12856
13025
  * Zod schema for validating API keys.
12857
13026
  *
@@ -12937,10 +13106,7 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
12937
13106
  /** Quote information with estimated amounts and route */ quote: zod.z.object({
12938
13107
  /** 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'),
12939
13108
  /** 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'),
12940
- /** Route information from DEX aggregator */ route: zod.z.object({
12941
- provider: zod.z.string().min(1, 'provider must be a non-empty string'),
12942
- steps: zod.z.array(zod.z.unknown())
12943
- })
13109
+ /** Route information from DEX aggregator */ route: responseSwapRouteSchema
12944
13110
  }),
12945
13111
  /** Fee context indicating where fees should be collected */ feeContext: quoteFeeContextSchema
12946
13112
  });
@@ -13156,19 +13322,6 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
13156
13322
  }).min(1, 'toChain must be a non-empty string if provided').optional(),
13157
13323
  apiKey: apiKeySchema.optional()
13158
13324
  });
13159
- /**
13160
- * Zod schema for validating CreateSwapResponse payloads.
13161
- */ const createSwapFeeItemSchema = zod.z.object({
13162
- token: zod.z.string({
13163
- required_error: 'fee token is required',
13164
- invalid_type_error: 'fee token must be a string'
13165
- }).min(1, 'fee token must be a non-empty string'),
13166
- amount: feeAmountSchema,
13167
- decimals: zod.z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
13168
- symbol: zod.z.string({
13169
- invalid_type_error: 'fee token symbol must be a string'
13170
- }).min(1, 'fee token symbol must be a non-empty string').optional()
13171
- });
13172
13325
  /**
13173
13326
  * Developer fee item schema with basis field.
13174
13327
  */ const createSwapDeveloperFeeItemSchema = createSwapFeeItemSchema.extend({
@@ -13306,6 +13459,8 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
13306
13459
  correlationId: zod.z.preprocess((value)=>zod.z.string().uuid().safeParse(value).success ? value : undefined, zod.z.string().optional()),
13307
13460
  config: createSwapRequestBaseSchema.shape.config.optional(),
13308
13461
  fees: createSwapFeesSchema.optional(),
13462
+ // A route the SDK cannot parse is dropped instead of failing the swap.
13463
+ route: withFallback(responseSwapRouteSchema.optional(), undefined),
13309
13464
  transaction: createSwapTransactionSchema
13310
13465
  });
13311
13466
 
@@ -13333,6 +13488,25 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
13333
13488
  * }
13334
13489
  * ```
13335
13490
  */ const isGetQuoteResponse = (obj)=>getQuoteResponseSchema.safeParse(obj).success;
13491
+ /**
13492
+ * Parse and transform a GetQuoteResponse object.
13493
+ *
13494
+ * Applies the schema's lenient route and fee parsing: entries the SDK does
13495
+ * not recognise are dropped and undeclared fields are stripped, rather than
13496
+ * passed through to callers as the type guard alone would.
13497
+ *
13498
+ * @param obj - The raw API response object to parse.
13499
+ * @returns The validated and transformed GetQuoteResponse.
13500
+ * @throws If validation fails.
13501
+ *
13502
+ * @example
13503
+ * ```typescript
13504
+ * import { parseGetQuoteResponse } from '@core/service-client'
13505
+ *
13506
+ * const quote = parseGetQuoteResponse(await response.json())
13507
+ * console.log(quote.quote.route.steps.length)
13508
+ * ```
13509
+ */ const parseGetQuoteResponse = (obj)=>getQuoteResponseSchema.parse(obj);
13336
13510
  /**
13337
13511
  * Type guard to validate CreateSwapResponse objects.
13338
13512
  *
@@ -13692,7 +13866,9 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
13692
13866
  }
13693
13867
  }
13694
13868
  };
13695
- return pollApiGet(url, isGetQuoteResponse, effectiveConfig);
13869
+ // Use type guard for validation in polling, then parse for transformation
13870
+ const rawResponse = await pollApiGet(url, isGetQuoteResponse, effectiveConfig);
13871
+ return parseGetQuoteResponse(rawResponse);
13696
13872
  };
13697
13873
 
13698
13874
  /**
@@ -17089,6 +17265,16 @@ function resolveFeePayoutChain(tokenIn, tokenOut, sourceChain, destinationChain)
17089
17265
  name: 'USDC',
17090
17266
  version: '2'
17091
17267
  },
17268
+ Cronos: {
17269
+ chainId: Cronos.chainId,
17270
+ name: 'USDC',
17271
+ version: '2'
17272
+ },
17273
+ Morph: {
17274
+ chainId: Morph.chainId,
17275
+ name: 'USDC',
17276
+ version: '2'
17277
+ },
17092
17278
  Arc_Testnet: {
17093
17279
  chainId: ArcTestnet.chainId,
17094
17280
  name: 'USDC',
@@ -18657,6 +18843,12 @@ const TOKEN_REGISTRY$1 = createTokenRegistry();
18657
18843
  * i.e. 1 + 0.2 + 0.1 = 1.3. Use the greater of (local estimate × this multiplier)
18658
18844
  * or the proxy's gasLimit.
18659
18845
  */ const GAS_SAFETY_MULTIPLIER = 1.3;
18846
+ /**
18847
+ * Gas units used to estimate the displayed gas fee when the service returns an
18848
+ * EVM route without a gasLimit, as direct Circle CCTP plans do. Sized from
18849
+ * observed Adapter executions of those plans. Display-only: it never becomes an
18850
+ * execution gas limit.
18851
+ */ const DEFAULT_EVM_SWAP_GAS_LIMIT = 500_000n;
18660
18852
  const TOKEN_REGISTRY = createTokenRegistry();
18661
18853
  /**
18662
18854
  * Enhances a KitError with transaction details (txHash and explorerUrl).
@@ -19173,9 +19365,9 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
19173
19365
  // Calculate estimated gas/transaction fee based on chain type
19174
19366
  let estimatedGasFee = '0';
19175
19367
  const evmGasLimit = 'gasLimit' in serviceResponse.transaction ? serviceResponse.transaction.gasLimit : undefined;
19176
- if (chain.type === 'evm' && evmGasLimit !== undefined) {
19368
+ if (chain.type === 'evm') {
19177
19369
  // EVM: gasLimit (units) × gasPrice (wei/unit) = estimated gas fee (wei)
19178
- const gasLimitUnits = BigInt(evmGasLimit);
19370
+ const gasLimitUnits = evmGasLimit === undefined ? DEFAULT_EVM_SWAP_GAS_LIMIT : BigInt(evmGasLimit);
19179
19371
  // Use calculateTransactionFee which fetches current gas price and applies buffer
19180
19372
  const gasEstimate = await params.from.adapter.calculateTransactionFee(gasLimitUnits, undefined, chain);
19181
19373
  // Format the fee from wei to human-readable native currency amount
@@ -19219,7 +19411,10 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
19219
19411
  const estimateResult = {
19220
19412
  stopLimit: formattedStopLimit,
19221
19413
  estimatedOutput: formattedEstimatedOutput,
19222
- fees
19414
+ fees,
19415
+ ...serviceResponse.route !== undefined && {
19416
+ route: serviceResponse.route
19417
+ }
19223
19418
  };
19224
19419
  return estimateResult;
19225
19420
  }
@@ -19604,7 +19799,7 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
19604
19799
  * }
19605
19800
  * ```
19606
19801
  */ async swap(params) {
19607
- // Extract wallet context & validate
19802
+ validateServiceSwapParams(params);
19608
19803
  const { from, tokenIn, tokenOut, config } = params;
19609
19804
  const { adapter, chain } = from;
19610
19805
  const destinationChain = params.toChain ?? chain;
@@ -19741,6 +19936,9 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
19741
19936
  ...swapResultFees !== undefined && {
19742
19937
  fees: swapResultFees
19743
19938
  },
19939
+ ...serviceResponse.route !== undefined && {
19940
+ route: serviceResponse.route
19941
+ },
19744
19942
  progress: statusSnapshot.progress,
19745
19943
  ...statusSnapshot.amountOut !== undefined && {
19746
19944
  amountOut: statusSnapshot.amountOut
@@ -19941,7 +20139,13 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
19941
20139
  return {
19942
20140
  token: formatted.token,
19943
20141
  amount: formatted.amount,
19944
- type
20142
+ type,
20143
+ ...fee.type !== undefined && {
20144
+ component: fee.type
20145
+ },
20146
+ ...fee.chain !== undefined && {
20147
+ chain: fee.chain
20148
+ }
19945
20149
  };
19946
20150
  }));
19947
20151
  }
@@ -19962,7 +20166,13 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
19962
20166
  token: formatted.token,
19963
20167
  amount: formatted.amount,
19964
20168
  type: 'developer',
19965
- recipientAddress
20169
+ recipientAddress,
20170
+ ...fee.type !== undefined && {
20171
+ component: fee.type
20172
+ },
20173
+ ...fee.chain !== undefined && {
20174
+ chain: fee.chain
20175
+ }
19966
20176
  };
19967
20177
  }));
19968
20178
  }
@@ -20019,6 +20229,7 @@ const optionalSwapChainIdentifierField = swapChainIdentifierField.optional();
20019
20229
  * - customFee: Optional fee configuration
20020
20230
  * - apiKey: Optional credential string
20021
20231
  * - kitKey: Optional credential string (deprecated alias for apiKey)
20232
+ * - batchTransactions: Optional boolean to opt out of atomic batching
20022
20233
  */ const swapConfigSchema = zod.z.object({
20023
20234
  allowanceStrategy: allowanceStrategySchema.optional(),
20024
20235
  slippageBps: zod.z.number().int().min(0).optional(),
@@ -20029,7 +20240,10 @@ const optionalSwapChainIdentifierField = swapChainIdentifierField.optional();
20029
20240
  })(zod.z.string())).optional(),
20030
20241
  customFee: swapCustomFeeSchema.optional(),
20031
20242
  apiKey: zod.z.string().optional(),
20032
- kitKey: zod.z.string().optional()
20243
+ kitKey: zod.z.string().optional(),
20244
+ batchTransactions: zod.z.boolean({
20245
+ invalid_type_error: 'batchTransactions must be a boolean'
20246
+ }).optional()
20033
20247
  });
20034
20248
  const swapDestinationSchema = zod.z.object({
20035
20249
  chain: optionalSwapChainIdentifierField,
@@ -21004,6 +21218,9 @@ const transformAmount = (value, direction, decimals)=>formatUnits(value, decimal
21004
21218
  ...formattedFees && {
21005
21219
  fees: formattedFees
21006
21220
  },
21221
+ ...result.route !== undefined && {
21222
+ route: result.route
21223
+ },
21007
21224
  ...formattedConfig && {
21008
21225
  config: formattedConfig
21009
21226
  },
@@ -21265,6 +21482,9 @@ const transformAmount = (value, direction, decimals)=>formatUnits(value, decimal
21265
21482
  estimatedOutput: providerEstimate.estimatedOutput,
21266
21483
  ...providerEstimate.fees !== undefined && {
21267
21484
  fees: providerEstimate.fees
21485
+ },
21486
+ ...providerEstimate.route !== undefined && {
21487
+ route: providerEstimate.route
21268
21488
  }
21269
21489
  };
21270
21490
  }
@@ -22956,7 +23176,7 @@ registerKit(`${pkg$2.name}/${pkg$2.version}`);
22956
23176
  };
22957
23177
 
22958
23178
  var name$1 = "@circle-fin/earn-kit";
22959
- var version$1 = "1.8.1";
23179
+ var version$1 = "1.10.0";
22960
23180
  var pkg$1 = {
22961
23181
  name: name$1,
22962
23182
  version: version$1};
@@ -24396,7 +24616,7 @@ function hasCrossChainDepositQuoteShape(params) {
24396
24616
  registerKit(`${pkg$1.name}/${pkg$1.version}`);
24397
24617
 
24398
24618
  var name = "@circle-fin/borrow-kit";
24399
- var version = "1.0.0";
24619
+ var version = "1.1.1";
24400
24620
  var pkg = {
24401
24621
  name: name,
24402
24622
  version: version};