@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/swap.mjs CHANGED
@@ -2003,22 +2003,73 @@ class KitError extends Error {
2003
2003
  '0x9147d463': 'Final balance is less than the initial balance',
2004
2004
  '0xf4b3b1bc': 'Native token transfer to the beneficiary failed'
2005
2005
  };
2006
+ /**
2007
+ * Matches revert data: a 4-byte selector followed by whole ABI-encoded bytes.
2008
+ */ const REVERT_DATA_PATTERN = /^0x[0-9a-f]{8}(?:[0-9a-f]{2})*$/i;
2009
+ /**
2010
+ * Returns the revert data held by one error in a `cause` chain.
2011
+ *
2012
+ * Browser wallets (EIP-1193) wrap the node's error, so the revert data sits
2013
+ * one level down as `data.data`. viem's `getContractError` reads it the same
2014
+ * way, then keeps it on `ContractFunctionRevertedError.raw` and drops the
2015
+ * node's error from the chain.
2016
+ *
2017
+ * @param link - One error in the `cause` chain
2018
+ * @returns The `raw` or `data` string, or undefined if there is none
2019
+ */ function getRevertData(link) {
2020
+ if ('raw' in link && typeof link.raw === 'string' && REVERT_DATA_PATTERN.test(link.raw)) {
2021
+ return link.raw;
2022
+ }
2023
+ if (!('data' in link)) {
2024
+ return undefined;
2025
+ }
2026
+ const { data } = link;
2027
+ if (typeof data === 'string') {
2028
+ return data;
2029
+ }
2030
+ if (data !== null && typeof data === 'object' && 'data' in data && typeof data.data === 'string') {
2031
+ return data.data;
2032
+ }
2033
+ return undefined;
2034
+ }
2035
+ /**
2036
+ * Finds the first revert data on the error or in its `cause` chain that
2037
+ * `accept` takes.
2038
+ *
2039
+ * viem keeps the node's revert data on an inner `RpcRequestError`, not on
2040
+ * the error it throws. The `seen` set stops a self-referencing `cause` chain.
2041
+ *
2042
+ * @param error - The error object
2043
+ * @param accept - Returns true for the data shape the caller wants
2044
+ * @returns The data as written on the error, or undefined if not found
2045
+ */ function findRevertData(error, accept) {
2046
+ const seen = new Set();
2047
+ let current = error;
2048
+ while(current !== null && typeof current === 'object' && !seen.has(current)){
2049
+ seen.add(current);
2050
+ const data = getRevertData(current);
2051
+ if (data !== undefined && accept(data)) {
2052
+ return data;
2053
+ }
2054
+ current = 'cause' in current ? current.cause : undefined;
2055
+ }
2056
+ return undefined;
2057
+ }
2006
2058
  /**
2007
2059
  * Attempts to extract an error selector from an error object or message.
2008
2060
  *
2009
2061
  * Checks multiple sources in priority order:
2010
- * 1. `error.data` field
2062
+ * 1. `raw` or `data` field (or nested `data.data`) on the error or anywhere
2063
+ * in its `cause` chain
2011
2064
  * 2. Message pattern: "custom error 0x8baa579f"
2012
2065
  *
2013
2066
  * @param msg - The error message
2014
2067
  * @param error - The error object (optional)
2015
2068
  * @returns The 4 bytes selector , or undefined if not found
2016
2069
  */ function extractErrorSelector(msg, error) {
2017
- // Check error.data field
2018
- if (error !== null && typeof error === 'object' && 'data' in error) {
2019
- if (typeof error.data === 'string' && /^0x[0-9a-f]{8}$/i.test(error.data)) {
2020
- return error.data.toLowerCase();
2021
- }
2070
+ const data = findRevertData(error, (value)=>/^0x[0-9a-f]{8}$/i.test(value));
2071
+ if (data !== undefined) {
2072
+ return data.toLowerCase();
2022
2073
  }
2023
2074
  // Check for "custom error 0x8baa579f" in the message
2024
2075
  const match = /custom error (0x[0-9a-f]{8})\b/i.exec(msg);
@@ -3144,6 +3195,8 @@ var SwapChain;
3144
3195
  SwapChain["HyperEVM"] = "HyperEVM";
3145
3196
  SwapChain["Monad"] = "Monad";
3146
3197
  SwapChain["Arc"] = "Arc";
3198
+ SwapChain["Cronos"] = "Cronos";
3199
+ SwapChain["Morph"] = "Morph";
3147
3200
  // Testnet chains with swap support
3148
3201
  SwapChain["Arc_Testnet"] = "Arc_Testnet";
3149
3202
  })(SwapChain || (SwapChain = {}));
@@ -4487,7 +4540,8 @@ var BorrowChain;
4487
4540
  }
4488
4541
  },
4489
4542
  kitContracts: {
4490
- bridge: BRIDGE_CONTRACT_EVM_MAINNET
4543
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
4544
+ adapter: ADAPTER_CONTRACT_EVM_MAINNET
4491
4545
  }
4492
4546
  });
4493
4547
 
@@ -5356,7 +5410,8 @@ var BorrowChain;
5356
5410
  }
5357
5411
  },
5358
5412
  kitContracts: {
5359
- bridge: BRIDGE_CONTRACT_EVM_MAINNET
5413
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
5414
+ adapter: ADAPTER_CONTRACT_EVM_MAINNET
5360
5415
  }
5361
5416
  });
5362
5417
 
@@ -7246,6 +7301,56 @@ var Chains = /*#__PURE__*/Object.freeze({
7246
7301
  Blockchain.World_Chain_Sepolia
7247
7302
  ]);
7248
7303
 
7304
+ /**
7305
+ * Check if a chain supports a specific type of custom smart contract logic.
7306
+ *
7307
+ * This function examines a chain definition to determine if it has a specific
7308
+ * contract type configured. When a chain has custom contract support, it can
7309
+ * use enhanced features and custom business logic in addition to the standard
7310
+ * CCTP approve/burn/mint flow.
7311
+ *
7312
+ * @param chain - The chain definition to examine for custom contract support.
7313
+ * @param contractType - The type of contract to check for (e.g., 'bridge').
7314
+ * @returns True if the chain supports the specified contract type with a valid address configured.
7315
+ *
7316
+ * @example
7317
+ * ```typescript
7318
+ * import { hasCustomContractSupport, Ethereum } from '@core/chains'
7319
+ *
7320
+ * // Check if a chain supports bridge contracts
7321
+ * if (hasCustomContractSupport(Ethereum, 'bridge')) {
7322
+ * // Runtime validation confirmed kitContracts.bridge exists
7323
+ * console.log('Bridge contract:', Ethereum.kitContracts?.bridge)
7324
+ * return executeCustomFlow(Ethereum.kitContracts?.bridge!, params)
7325
+ * } else {
7326
+ * console.log('Using standard CCTP flow')
7327
+ * return executeStandardFlow(params)
7328
+ * }
7329
+ * ```
7330
+ *
7331
+ * @example
7332
+ * ```typescript
7333
+ * // Usage in flow determination
7334
+ * function determineBridgingFlow(chain: ChainDefinition, params: BridgeParams) {
7335
+ * if (hasCustomContractSupport(chain, 'bridge')) {
7336
+ * return 'custom'
7337
+ * } else if (isCCTPV2Supported(chain)) {
7338
+ * return 'standard'
7339
+ * } else {
7340
+ * throw new Error(`Chain ${chain.name} is not supported for bridging`)
7341
+ * }
7342
+ * }
7343
+ *
7344
+ * // Future usage with other contract types (when added to KitContractType)
7345
+ * // if (hasCustomContractSupport(someChain, 'customType')) {
7346
+ * // console.log('Custom contract:', someChain.kitContracts?.customType)
7347
+ * // }
7348
+ * ```
7349
+ */ function hasCustomContractSupport(chain, contractType) {
7350
+ const contractAddress = chain.kitContracts?.[contractType];
7351
+ return typeof contractAddress === 'string' && contractAddress.trim().length > 0;
7352
+ }
7353
+
7249
7354
  /**
7250
7355
  * Temporary allowlist of chains permitted to initiate Gateway fast deposits.
7251
7356
  * Only chains keyed here are eligible; all others are rejected. Using the
@@ -7499,8 +7604,8 @@ var Chains = /*#__PURE__*/Object.freeze({
7499
7604
  * Zod schema for validating swap-specific chain identifiers.
7500
7605
  *
7501
7606
  * Validates chains based on:
7502
- * - CCTPv2 support (adapter contract deployed)
7503
- * - Mainnet only (no testnets)
7607
+ * - Membership in the SwapChain enum
7608
+ * - Mainnet or explicitly allowlisted testnet
7504
7609
  * - At least one supported token available
7505
7610
  *
7506
7611
  */ const swapChainIdentifierSchema = z.union([
@@ -8055,7 +8160,7 @@ const swapTokenEnumSchema = z.enum([
8055
8160
  *
8056
8161
  * A chain supports swaps if ALL conditions are met:
8057
8162
  * 1. Is a member of the {@link SwapChain} enum
8058
- * 2. Has CCTPv2 support (adapter contract deployed)
8163
+ * 2. Has an Adapter contract configured directly or through CCTP v2
8059
8164
  *
8060
8165
  * Testnets are allowed only when explicitly listed in the
8061
8166
  * {@link SwapChain} enum (e.g., Arc_Testnet).
@@ -8076,14 +8181,14 @@ const swapTokenEnumSchema = z.enum([
8076
8181
  * @remarks
8077
8182
  * Chains automatically become swap-enabled when:
8078
8183
  * - Added to the {@link SwapChain} enum
8079
- * - Adapter contract is deployed (CCTPv2)
8184
+ * - An Adapter contract is deployed and configured
8080
8185
  *
8081
8186
  * No code changes needed when new chains are added!
8082
8187
  */ function isSwapSupportedChain(chain) {
8083
8188
  if (!(chain.chain in SwapChain)) {
8084
8189
  return false;
8085
8190
  }
8086
- if (!isCCTPV2Supported(chain)) {
8191
+ if (!isCCTPV2Supported(chain) && !hasCustomContractSupport(chain, 'adapter')) {
8087
8192
  return false;
8088
8193
  }
8089
8194
  return true;
@@ -8094,7 +8199,7 @@ const swapTokenEnumSchema = z.enum([
8094
8199
  *
8095
8200
  * Dynamically filter chain definitions to include only those that:
8096
8201
  * - Are members of the {@link SwapChain} enum
8097
- * - Have CCTPv2 support
8202
+ * - Have an Adapter contract configured directly or through CCTP v2
8098
8203
  *
8099
8204
  * This function is pure and accepts chains as parameter to avoid
8100
8205
  * circular dependencies.
@@ -9414,11 +9519,13 @@ const swapTokenEnumSchema = z.enum([
9414
9519
  [Blockchain.Arbitrum]: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
9415
9520
  [Blockchain.Avalanche]: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7',
9416
9521
  [Blockchain.Celo]: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
9522
+ [Blockchain.Cronos]: '0x66e428c3f67a68878562e79A0234c1F83c208770',
9417
9523
  [Blockchain.Ethereum]: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
9418
9524
  [Blockchain.HyperEVM]: '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb',
9419
9525
  [Blockchain.Ink]: '0x0200C29006150606B650577BBE7B6248F58470c1',
9420
9526
  [Blockchain.Linea]: '0xA219439258ca9da29E9Cc4cE5596924745e12B93',
9421
9527
  [Blockchain.Monad]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
9528
+ [Blockchain.Morph]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
9422
9529
  [Blockchain.NEAR]: 'usdt.tether-token.near',
9423
9530
  [Blockchain.Optimism]: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58',
9424
9531
  [Blockchain.Polkadot_Asset_Hub]: '1984',
@@ -9477,6 +9584,7 @@ const swapTokenEnumSchema = z.enum([
9477
9584
  [Blockchain.Arbitrum]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
9478
9585
  [Blockchain.Avalanche]: '0xd586E7F844cEa2F87f50152665BCbc2C279D8d70',
9479
9586
  [Blockchain.Base]: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb',
9587
+ [Blockchain.Cronos]: '0xF2001B145b43032AAF5Ee2884e456CCd805F677D',
9480
9588
  [Blockchain.Ethereum]: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
9481
9589
  [Blockchain.Linea]: '0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5',
9482
9590
  [Blockchain.Optimism]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
@@ -9539,7 +9647,9 @@ const swapTokenEnumSchema = z.enum([
9539
9647
  [Blockchain.Arbitrum]: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
9540
9648
  [Blockchain.Avalanche]: '0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB',
9541
9649
  [Blockchain.Base]: '0x4200000000000000000000000000000000000006',
9650
+ [Blockchain.Cronos]: '0xe44Fd7fCb2b1581822D0c862B68222998a0c299a',
9542
9651
  [Blockchain.Ethereum]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
9652
+ [Blockchain.Morph]: '0x5300000000000000000000000000000000000011',
9543
9653
  [Blockchain.Optimism]: '0x4200000000000000000000000000000000000006',
9544
9654
  [Blockchain.Polygon]: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619',
9545
9655
  [Blockchain.Solana]: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs'
@@ -9558,6 +9668,7 @@ const swapTokenEnumSchema = z.enum([
9558
9668
  locators: {
9559
9669
  [Blockchain.Ethereum]: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
9560
9670
  [Blockchain.Arbitrum]: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f',
9671
+ [Blockchain.Cronos]: '0x062E66477Faf219F25D27dCED647BF57C3107d52',
9561
9672
  [Blockchain.Avalanche]: '0x50b7545627a5162F82A992c33b87aDc75187B218'
9562
9673
  }
9563
9674
  };
@@ -10730,7 +10841,7 @@ const swapTokenEnumSchema = z.enum([
10730
10841
  }
10731
10842
 
10732
10843
  var name$3 = "@circle-fin/bridge-kit";
10733
- var version$3 = "1.15.2";
10844
+ var version$3 = "1.15.3";
10734
10845
  var pkg$3 = {
10735
10846
  name: name$3,
10736
10847
  version: version$3};
@@ -12385,7 +12496,7 @@ const validateQuoteItemSchema = z.object({
12385
12496
  registerKit(`${pkg$3.name}/${pkg$3.version}`);
12386
12497
 
12387
12498
  var name$2 = "@circle-fin/swap-kit";
12388
- var version$2 = "1.7.1";
12499
+ var version$2 = "1.8.0";
12389
12500
  var pkg$2 = {
12390
12501
  name: name$2,
12391
12502
  version: version$2};
@@ -12845,6 +12956,64 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
12845
12956
  }, {
12846
12957
  message: 'fee amount must be non-negative (>= 0)'
12847
12958
  });
12959
+ /**
12960
+ * Parses a display-only field leniently: a value `schema` rejects is replaced
12961
+ * with `fallback` instead of failing the response that carries it.
12962
+ * Implemented with `preprocess` rather than Zod's `.catch()` because static
12963
+ * analysis misreads `.catch` on the schema chain as an unhandled Promise
12964
+ * (S7785).
12965
+ */ const withFallback = (schema, fallback)=>z.preprocess((value)=>schema.safeParse(value).success ? value : fallback, schema);
12966
+ const swapRouteTokenSchema = z.object({
12967
+ symbol: z.string(),
12968
+ address: z.string(),
12969
+ decimals: z.number()
12970
+ });
12971
+ const swapRouteMetadataSchema = z.record(z.unknown()).optional();
12972
+ const swapRouteStepSchema = z.object({
12973
+ type: z.string(),
12974
+ tool: z.string(),
12975
+ toolName: z.string(),
12976
+ fromToken: swapRouteTokenSchema,
12977
+ toToken: swapRouteTokenSchema,
12978
+ estimate: z.object({
12979
+ fromAmount: z.string(),
12980
+ toAmount: z.string(),
12981
+ gasCostUSD: z.string().optional()
12982
+ }),
12983
+ metadata: swapRouteMetadataSchema
12984
+ });
12985
+ /**
12986
+ * Strict schema for a `SwapRoute`. Module-private: service responses
12987
+ * parse routes leniently through {@link responseSwapRouteSchema}.
12988
+ */ const swapRouteSchema = z.object({
12989
+ provider: z.string().min(1, 'provider must be a non-empty string'),
12990
+ steps: z.array(swapRouteStepSchema),
12991
+ metadata: swapRouteMetadataSchema
12992
+ });
12993
+ /**
12994
+ * Route details are display-only, so service responses parse them leniently:
12995
+ * steps or metadata in a shape the SDK does not know are dropped rather than
12996
+ * failing the quote or swap they describe. Steps are all-or-nothing: if any
12997
+ * step is malformed, `steps` is empty, so a route never silently loses a hop.
12998
+ */ const responseSwapRouteSchema = swapRouteSchema.extend({
12999
+ steps: withFallback(swapRouteSchema.shape.steps, []),
13000
+ metadata: withFallback(swapRouteMetadataSchema, undefined)
13001
+ });
13002
+ const createSwapFeeItemSchema = z.object({
13003
+ token: z.string({
13004
+ required_error: 'fee token is required',
13005
+ invalid_type_error: 'fee token must be a string'
13006
+ }).min(1, 'fee token must be a non-empty string'),
13007
+ amount: feeAmountSchema,
13008
+ decimals: z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
13009
+ symbol: z.string({
13010
+ invalid_type_error: 'fee token symbol must be a string'
13011
+ }).min(1, 'fee token symbol must be a non-empty string').optional(),
13012
+ // Descriptive metadata: a value the SDK cannot use is dropped rather than
13013
+ // failing the response that carries the fee.
13014
+ type: withFallback(z.string().min(1).optional(), undefined),
13015
+ chain: withFallback(z.string().min(1).optional(), undefined)
13016
+ });
12848
13017
  /**
12849
13018
  * Zod schema for validating API keys.
12850
13019
  *
@@ -12930,10 +13099,7 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
12930
13099
  /** Quote information with estimated amounts and route */ quote: z.object({
12931
13100
  /** 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'),
12932
13101
  /** 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'),
12933
- /** Route information from DEX aggregator */ route: z.object({
12934
- provider: z.string().min(1, 'provider must be a non-empty string'),
12935
- steps: z.array(z.unknown())
12936
- })
13102
+ /** Route information from DEX aggregator */ route: responseSwapRouteSchema
12937
13103
  }),
12938
13104
  /** Fee context indicating where fees should be collected */ feeContext: quoteFeeContextSchema
12939
13105
  });
@@ -13149,19 +13315,6 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
13149
13315
  }).min(1, 'toChain must be a non-empty string if provided').optional(),
13150
13316
  apiKey: apiKeySchema.optional()
13151
13317
  });
13152
- /**
13153
- * Zod schema for validating CreateSwapResponse payloads.
13154
- */ const createSwapFeeItemSchema = z.object({
13155
- token: z.string({
13156
- required_error: 'fee token is required',
13157
- invalid_type_error: 'fee token must be a string'
13158
- }).min(1, 'fee token must be a non-empty string'),
13159
- amount: feeAmountSchema,
13160
- decimals: z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
13161
- symbol: z.string({
13162
- invalid_type_error: 'fee token symbol must be a string'
13163
- }).min(1, 'fee token symbol must be a non-empty string').optional()
13164
- });
13165
13318
  /**
13166
13319
  * Developer fee item schema with basis field.
13167
13320
  */ const createSwapDeveloperFeeItemSchema = createSwapFeeItemSchema.extend({
@@ -13299,6 +13452,8 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
13299
13452
  correlationId: z.preprocess((value)=>z.string().uuid().safeParse(value).success ? value : undefined, z.string().optional()),
13300
13453
  config: createSwapRequestBaseSchema.shape.config.optional(),
13301
13454
  fees: createSwapFeesSchema.optional(),
13455
+ // A route the SDK cannot parse is dropped instead of failing the swap.
13456
+ route: withFallback(responseSwapRouteSchema.optional(), undefined),
13302
13457
  transaction: createSwapTransactionSchema
13303
13458
  });
13304
13459
 
@@ -13326,6 +13481,25 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
13326
13481
  * }
13327
13482
  * ```
13328
13483
  */ const isGetQuoteResponse = (obj)=>getQuoteResponseSchema.safeParse(obj).success;
13484
+ /**
13485
+ * Parse and transform a GetQuoteResponse object.
13486
+ *
13487
+ * Applies the schema's lenient route and fee parsing: entries the SDK does
13488
+ * not recognise are dropped and undeclared fields are stripped, rather than
13489
+ * passed through to callers as the type guard alone would.
13490
+ *
13491
+ * @param obj - The raw API response object to parse.
13492
+ * @returns The validated and transformed GetQuoteResponse.
13493
+ * @throws If validation fails.
13494
+ *
13495
+ * @example
13496
+ * ```typescript
13497
+ * import { parseGetQuoteResponse } from '@core/service-client'
13498
+ *
13499
+ * const quote = parseGetQuoteResponse(await response.json())
13500
+ * console.log(quote.quote.route.steps.length)
13501
+ * ```
13502
+ */ const parseGetQuoteResponse = (obj)=>getQuoteResponseSchema.parse(obj);
13329
13503
  /**
13330
13504
  * Type guard to validate CreateSwapResponse objects.
13331
13505
  *
@@ -13685,7 +13859,9 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
13685
13859
  }
13686
13860
  }
13687
13861
  };
13688
- return pollApiGet(url, isGetQuoteResponse, effectiveConfig);
13862
+ // Use type guard for validation in polling, then parse for transformation
13863
+ const rawResponse = await pollApiGet(url, isGetQuoteResponse, effectiveConfig);
13864
+ return parseGetQuoteResponse(rawResponse);
13689
13865
  };
13690
13866
 
13691
13867
  /**
@@ -17082,6 +17258,16 @@ function resolveFeePayoutChain(tokenIn, tokenOut, sourceChain, destinationChain)
17082
17258
  name: 'USDC',
17083
17259
  version: '2'
17084
17260
  },
17261
+ Cronos: {
17262
+ chainId: Cronos.chainId,
17263
+ name: 'USDC',
17264
+ version: '2'
17265
+ },
17266
+ Morph: {
17267
+ chainId: Morph.chainId,
17268
+ name: 'USDC',
17269
+ version: '2'
17270
+ },
17085
17271
  Arc_Testnet: {
17086
17272
  chainId: ArcTestnet.chainId,
17087
17273
  name: 'USDC',
@@ -18650,6 +18836,12 @@ const TOKEN_REGISTRY$1 = createTokenRegistry();
18650
18836
  * i.e. 1 + 0.2 + 0.1 = 1.3. Use the greater of (local estimate × this multiplier)
18651
18837
  * or the proxy's gasLimit.
18652
18838
  */ const GAS_SAFETY_MULTIPLIER = 1.3;
18839
+ /**
18840
+ * Gas units used to estimate the displayed gas fee when the service returns an
18841
+ * EVM route without a gasLimit, as direct Circle CCTP plans do. Sized from
18842
+ * observed Adapter executions of those plans. Display-only: it never becomes an
18843
+ * execution gas limit.
18844
+ */ const DEFAULT_EVM_SWAP_GAS_LIMIT = 500_000n;
18653
18845
  const TOKEN_REGISTRY = createTokenRegistry();
18654
18846
  /**
18655
18847
  * Enhances a KitError with transaction details (txHash and explorerUrl).
@@ -19166,9 +19358,9 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
19166
19358
  // Calculate estimated gas/transaction fee based on chain type
19167
19359
  let estimatedGasFee = '0';
19168
19360
  const evmGasLimit = 'gasLimit' in serviceResponse.transaction ? serviceResponse.transaction.gasLimit : undefined;
19169
- if (chain.type === 'evm' && evmGasLimit !== undefined) {
19361
+ if (chain.type === 'evm') {
19170
19362
  // EVM: gasLimit (units) × gasPrice (wei/unit) = estimated gas fee (wei)
19171
- const gasLimitUnits = BigInt(evmGasLimit);
19363
+ const gasLimitUnits = evmGasLimit === undefined ? DEFAULT_EVM_SWAP_GAS_LIMIT : BigInt(evmGasLimit);
19172
19364
  // Use calculateTransactionFee which fetches current gas price and applies buffer
19173
19365
  const gasEstimate = await params.from.adapter.calculateTransactionFee(gasLimitUnits, undefined, chain);
19174
19366
  // Format the fee from wei to human-readable native currency amount
@@ -19212,7 +19404,10 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
19212
19404
  const estimateResult = {
19213
19405
  stopLimit: formattedStopLimit,
19214
19406
  estimatedOutput: formattedEstimatedOutput,
19215
- fees
19407
+ fees,
19408
+ ...serviceResponse.route !== undefined && {
19409
+ route: serviceResponse.route
19410
+ }
19216
19411
  };
19217
19412
  return estimateResult;
19218
19413
  }
@@ -19597,7 +19792,7 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
19597
19792
  * }
19598
19793
  * ```
19599
19794
  */ async swap(params) {
19600
- // Extract wallet context & validate
19795
+ validateServiceSwapParams(params);
19601
19796
  const { from, tokenIn, tokenOut, config } = params;
19602
19797
  const { adapter, chain } = from;
19603
19798
  const destinationChain = params.toChain ?? chain;
@@ -19734,6 +19929,9 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
19734
19929
  ...swapResultFees !== undefined && {
19735
19930
  fees: swapResultFees
19736
19931
  },
19932
+ ...serviceResponse.route !== undefined && {
19933
+ route: serviceResponse.route
19934
+ },
19737
19935
  progress: statusSnapshot.progress,
19738
19936
  ...statusSnapshot.amountOut !== undefined && {
19739
19937
  amountOut: statusSnapshot.amountOut
@@ -19934,7 +20132,13 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
19934
20132
  return {
19935
20133
  token: formatted.token,
19936
20134
  amount: formatted.amount,
19937
- type
20135
+ type,
20136
+ ...fee.type !== undefined && {
20137
+ component: fee.type
20138
+ },
20139
+ ...fee.chain !== undefined && {
20140
+ chain: fee.chain
20141
+ }
19938
20142
  };
19939
20143
  }));
19940
20144
  }
@@ -19955,7 +20159,13 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
19955
20159
  token: formatted.token,
19956
20160
  amount: formatted.amount,
19957
20161
  type: 'developer',
19958
- recipientAddress
20162
+ recipientAddress,
20163
+ ...fee.type !== undefined && {
20164
+ component: fee.type
20165
+ },
20166
+ ...fee.chain !== undefined && {
20167
+ chain: fee.chain
20168
+ }
19959
20169
  };
19960
20170
  }));
19961
20171
  }
@@ -20012,6 +20222,7 @@ const optionalSwapChainIdentifierField = swapChainIdentifierField.optional();
20012
20222
  * - customFee: Optional fee configuration
20013
20223
  * - apiKey: Optional credential string
20014
20224
  * - kitKey: Optional credential string (deprecated alias for apiKey)
20225
+ * - batchTransactions: Optional boolean to opt out of atomic batching
20015
20226
  */ const swapConfigSchema = z.object({
20016
20227
  allowanceStrategy: allowanceStrategySchema.optional(),
20017
20228
  slippageBps: z.number().int().min(0).optional(),
@@ -20022,7 +20233,10 @@ const optionalSwapChainIdentifierField = swapChainIdentifierField.optional();
20022
20233
  })(z.string())).optional(),
20023
20234
  customFee: swapCustomFeeSchema.optional(),
20024
20235
  apiKey: z.string().optional(),
20025
- kitKey: z.string().optional()
20236
+ kitKey: z.string().optional(),
20237
+ batchTransactions: z.boolean({
20238
+ invalid_type_error: 'batchTransactions must be a boolean'
20239
+ }).optional()
20026
20240
  });
20027
20241
  const swapDestinationSchema = z.object({
20028
20242
  chain: optionalSwapChainIdentifierField,
@@ -20997,6 +21211,9 @@ const transformAmount = (value, direction, decimals)=>formatUnits(value, decimal
20997
21211
  ...formattedFees && {
20998
21212
  fees: formattedFees
20999
21213
  },
21214
+ ...result.route !== undefined && {
21215
+ route: result.route
21216
+ },
21000
21217
  ...formattedConfig && {
21001
21218
  config: formattedConfig
21002
21219
  },
@@ -21258,6 +21475,9 @@ const transformAmount = (value, direction, decimals)=>formatUnits(value, decimal
21258
21475
  estimatedOutput: providerEstimate.estimatedOutput,
21259
21476
  ...providerEstimate.fees !== undefined && {
21260
21477
  fees: providerEstimate.fees
21478
+ },
21479
+ ...providerEstimate.route !== undefined && {
21480
+ route: providerEstimate.route
21261
21481
  }
21262
21482
  };
21263
21483
  }
@@ -22949,7 +23169,7 @@ registerKit(`${pkg$2.name}/${pkg$2.version}`);
22949
23169
  };
22950
23170
 
22951
23171
  var name$1 = "@circle-fin/earn-kit";
22952
- var version$1 = "1.8.1";
23172
+ var version$1 = "1.9.0";
22953
23173
  var pkg$1 = {
22954
23174
  name: name$1,
22955
23175
  version: version$1};
@@ -24389,7 +24609,7 @@ function hasCrossChainDepositQuoteShape(params) {
24389
24609
  registerKit(`${pkg$1.name}/${pkg$1.version}`);
24390
24610
 
24391
24611
  var name = "@circle-fin/borrow-kit";
24392
- var version = "1.0.0";
24612
+ var version = "1.1.0";
24393
24613
  var pkg = {
24394
24614
  name: name,
24395
24615
  version: version};