@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/earn.cjs CHANGED
@@ -749,6 +749,11 @@ class KitError extends Error {
749
749
  code: 5001,
750
750
  name: 'ONCHAIN_TRANSACTION_REVERTED',
751
751
  type: 'ONCHAIN'
752
+ },
753
+ /** Pre-flight transaction simulation failed */ SIMULATION_FAILED: {
754
+ code: 5002,
755
+ name: 'ONCHAIN_SIMULATION_FAILED',
756
+ type: 'ONCHAIN'
752
757
  }};
753
758
  /**
754
759
  * Standardized error definitions for LIQUIDITY type errors.
@@ -1171,6 +1176,49 @@ class KitError extends Error {
1171
1176
  return new KitError(errorDetails);
1172
1177
  }
1173
1178
 
1179
+ /**
1180
+ * Creates error for transaction simulation failures.
1181
+ *
1182
+ * This error is thrown when a pre-flight transaction simulation fails,
1183
+ * typically due to contract logic that would revert. The error is FATAL
1184
+ * as it indicates the transaction would fail if submitted.
1185
+ *
1186
+ * @param chain - The blockchain network where the simulation failed
1187
+ * @param reason - The reason for simulation failure (e.g., revert message)
1188
+ * @param trace - Optional trace context to include in error (can include rawError and additional debugging data)
1189
+ * @returns KitError with simulation failure details
1190
+ *
1191
+ * @example
1192
+ * ```typescript
1193
+ * import { createSimulationFailedError } from '@core/errors'
1194
+ *
1195
+ * throw createSimulationFailedError('Ethereum', 'ERC20: insufficient allowance')
1196
+ * // Message: "Simulation failed on Ethereum: ERC20: insufficient allowance"
1197
+ * ```
1198
+ *
1199
+ * @example
1200
+ * ```typescript
1201
+ * // With trace context for debugging
1202
+ * throw createSimulationFailedError('Ethereum', 'ERC20: insufficient allowance', {
1203
+ * rawError: error,
1204
+ * txHash: '0x1234...',
1205
+ * gasLimit: '21000',
1206
+ * })
1207
+ * ```
1208
+ */ function createSimulationFailedError(chain, reason, trace) {
1209
+ return new KitError({
1210
+ ...OnchainError.SIMULATION_FAILED,
1211
+ recoverability: 'FATAL',
1212
+ message: `Simulation failed on ${chain}: ${reason}`,
1213
+ cause: {
1214
+ trace: {
1215
+ ...trace,
1216
+ chain,
1217
+ reason
1218
+ }
1219
+ }
1220
+ });
1221
+ }
1174
1222
  /**
1175
1223
  * Creates error for transaction reverts.
1176
1224
  *
@@ -1225,6 +1273,82 @@ class KitError extends Error {
1225
1273
  });
1226
1274
  }
1227
1275
 
1276
+ /**
1277
+ * Matches revert data: a 4-byte selector followed by whole ABI-encoded bytes.
1278
+ */ const REVERT_DATA_PATTERN = /^0x[0-9a-f]{8}(?:[0-9a-f]{2})*$/i;
1279
+ /**
1280
+ * Returns the revert data held by one error in a `cause` chain.
1281
+ *
1282
+ * Browser wallets (EIP-1193) wrap the node's error, so the revert data sits
1283
+ * one level down as `data.data`. viem's `getContractError` reads it the same
1284
+ * way, then keeps it on `ContractFunctionRevertedError.raw` and drops the
1285
+ * node's error from the chain.
1286
+ *
1287
+ * @param link - One error in the `cause` chain
1288
+ * @returns The `raw` or `data` string, or undefined if there is none
1289
+ */ function getRevertData(link) {
1290
+ if ('raw' in link && typeof link.raw === 'string' && REVERT_DATA_PATTERN.test(link.raw)) {
1291
+ return link.raw;
1292
+ }
1293
+ if (!('data' in link)) {
1294
+ return undefined;
1295
+ }
1296
+ const { data } = link;
1297
+ if (typeof data === 'string') {
1298
+ return data;
1299
+ }
1300
+ if (data !== null && typeof data === 'object' && 'data' in data && typeof data.data === 'string') {
1301
+ return data.data;
1302
+ }
1303
+ return undefined;
1304
+ }
1305
+ /**
1306
+ * Finds the first revert data on the error or in its `cause` chain that
1307
+ * `accept` takes.
1308
+ *
1309
+ * viem keeps the node's revert data on an inner `RpcRequestError`, not on
1310
+ * the error it throws. The `seen` set stops a self-referencing `cause` chain.
1311
+ *
1312
+ * @param error - The error object
1313
+ * @param accept - Returns true for the data shape the caller wants
1314
+ * @returns The data as written on the error, or undefined if not found
1315
+ */ function findRevertData(error, accept) {
1316
+ const seen = new Set();
1317
+ let current = error;
1318
+ while(current !== null && typeof current === 'object' && !seen.has(current)){
1319
+ seen.add(current);
1320
+ const data = getRevertData(current);
1321
+ if (data !== undefined && accept(data)) {
1322
+ return data;
1323
+ }
1324
+ current = 'cause' in current ? current.cause : undefined;
1325
+ }
1326
+ return undefined;
1327
+ }
1328
+ /**
1329
+ * Finds the raw revert data on an error or anywhere in its `cause` chain.
1330
+ *
1331
+ * Reads `data`, the nested `data.data` from browser wallets, and viem's
1332
+ * `raw`. Only hex of at least 4 bytes counts, so decoded `data` objects and
1333
+ * empty `0x` data are skipped.
1334
+ *
1335
+ * Revert data is public: it is what the contract returned. Keep it when the
1336
+ * rest of a raw error is redacted, so callers can still decode the revert.
1337
+ *
1338
+ * @param error - The raw error from the blockchain library
1339
+ * @returns The revert data in lowercase, or undefined if there is none
1340
+ *
1341
+ * @example
1342
+ * ```typescript
1343
+ * import { extractRevertData } from '@core/errors'
1344
+ *
1345
+ * extractRevertData({ cause: { data: { data: '0xF64059DB' } } })
1346
+ * // Returns: '0xf64059db'
1347
+ * ```
1348
+ */ function extractRevertData(error) {
1349
+ return findRevertData(error, (data)=>REVERT_DATA_PATTERN.test(data))?.toLowerCase();
1350
+ }
1351
+
1228
1352
  /**
1229
1353
  * Type guard to check if an error is a KitError instance.
1230
1354
  *
@@ -2010,7 +2134,7 @@ class KitError extends Error {
2010
2134
  * between input errors (fix your request) and service errors (retry later).
2011
2135
  *
2012
2136
  * Error code ranges:
2013
- * - 1100-1106: INPUT errors — invalid, unsupported, or stale request state
2137
+ * - 1100-1107: INPUT errors — invalid, unsupported, or stale request state
2014
2138
  * - 8100-8105: SERVICE errors — retryable backend/provider failures
2015
2139
  *
2016
2140
  * @example
@@ -2071,6 +2195,15 @@ class KitError extends Error {
2071
2195
  name: 'EARN_BRIDGE_QUOTE_EXPIRED',
2072
2196
  type: 'INPUT'
2073
2197
  },
2198
+ /**
2199
+ * The wallet's vault shares are inside the vault's share lock period, which
2200
+ * starts at deposit. Surfaced as FATAL rather than RETRYABLE because the
2201
+ * lock can last hours, so an immediate retry fails the same way.
2202
+ */ SHARES_LOCKED: {
2203
+ code: 1107,
2204
+ name: 'EARN_SHARES_LOCKED',
2205
+ type: 'INPUT'
2206
+ },
2074
2207
  /** The proxy signing call failed — retryable. */ SIGNING_FAILED: {
2075
2208
  code: 8100,
2076
2209
  name: 'EARN_SIGNING_FAILED',
@@ -2543,6 +2676,8 @@ var SwapChain;
2543
2676
  SwapChain["HyperEVM"] = "HyperEVM";
2544
2677
  SwapChain["Monad"] = "Monad";
2545
2678
  SwapChain["Arc"] = "Arc";
2679
+ SwapChain["Cronos"] = "Cronos";
2680
+ SwapChain["Morph"] = "Morph";
2546
2681
  // Testnet chains with swap support
2547
2682
  SwapChain["Arc_Testnet"] = "Arc_Testnet";
2548
2683
  })(SwapChain || (SwapChain = {}));
@@ -3875,7 +4010,8 @@ var BorrowChain;
3875
4010
  }
3876
4011
  },
3877
4012
  kitContracts: {
3878
- bridge: BRIDGE_CONTRACT_EVM_MAINNET
4013
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
4014
+ adapter: ADAPTER_CONTRACT_EVM_MAINNET
3879
4015
  }
3880
4016
  });
3881
4017
 
@@ -4744,7 +4880,8 @@ var BorrowChain;
4744
4880
  }
4745
4881
  },
4746
4882
  kitContracts: {
4747
- bridge: BRIDGE_CONTRACT_EVM_MAINNET
4883
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET,
4884
+ adapter: ADAPTER_CONTRACT_EVM_MAINNET
4748
4885
  }
4749
4886
  });
4750
4887
 
@@ -6634,6 +6771,56 @@ var Chains = {
6634
6771
  Blockchain.World_Chain_Sepolia
6635
6772
  ]);
6636
6773
 
6774
+ /**
6775
+ * Check if a chain supports a specific type of custom smart contract logic.
6776
+ *
6777
+ * This function examines a chain definition to determine if it has a specific
6778
+ * contract type configured. When a chain has custom contract support, it can
6779
+ * use enhanced features and custom business logic in addition to the standard
6780
+ * CCTP approve/burn/mint flow.
6781
+ *
6782
+ * @param chain - The chain definition to examine for custom contract support.
6783
+ * @param contractType - The type of contract to check for (e.g., 'bridge').
6784
+ * @returns True if the chain supports the specified contract type with a valid address configured.
6785
+ *
6786
+ * @example
6787
+ * ```typescript
6788
+ * import { hasCustomContractSupport, Ethereum } from '@core/chains'
6789
+ *
6790
+ * // Check if a chain supports bridge contracts
6791
+ * if (hasCustomContractSupport(Ethereum, 'bridge')) {
6792
+ * // Runtime validation confirmed kitContracts.bridge exists
6793
+ * console.log('Bridge contract:', Ethereum.kitContracts?.bridge)
6794
+ * return executeCustomFlow(Ethereum.kitContracts?.bridge!, params)
6795
+ * } else {
6796
+ * console.log('Using standard CCTP flow')
6797
+ * return executeStandardFlow(params)
6798
+ * }
6799
+ * ```
6800
+ *
6801
+ * @example
6802
+ * ```typescript
6803
+ * // Usage in flow determination
6804
+ * function determineBridgingFlow(chain: ChainDefinition, params: BridgeParams) {
6805
+ * if (hasCustomContractSupport(chain, 'bridge')) {
6806
+ * return 'custom'
6807
+ * } else if (isCCTPV2Supported(chain)) {
6808
+ * return 'standard'
6809
+ * } else {
6810
+ * throw new Error(`Chain ${chain.name} is not supported for bridging`)
6811
+ * }
6812
+ * }
6813
+ *
6814
+ * // Future usage with other contract types (when added to KitContractType)
6815
+ * // if (hasCustomContractSupport(someChain, 'customType')) {
6816
+ * // console.log('Custom contract:', someChain.kitContracts?.customType)
6817
+ * // }
6818
+ * ```
6819
+ */ function hasCustomContractSupport(chain, contractType) {
6820
+ const contractAddress = chain.kitContracts?.[contractType];
6821
+ return typeof contractAddress === 'string' && contractAddress.trim().length > 0;
6822
+ }
6823
+
6637
6824
  /**
6638
6825
  * Temporary allowlist of chains permitted to initiate Gateway fast deposits.
6639
6826
  * Only chains keyed here are eligible; all others are rejected. Using the
@@ -6887,8 +7074,8 @@ var Chains = {
6887
7074
  * Zod schema for validating swap-specific chain identifiers.
6888
7075
  *
6889
7076
  * Validates chains based on:
6890
- * - CCTPv2 support (adapter contract deployed)
6891
- * - Mainnet only (no testnets)
7077
+ * - Membership in the SwapChain enum
7078
+ * - Mainnet or explicitly allowlisted testnet
6892
7079
  * - At least one supported token available
6893
7080
  *
6894
7081
  */ const swapChainIdentifierSchema = zod.z.union([
@@ -7293,7 +7480,7 @@ const swapTokenEnumSchema = zod.z.enum([
7293
7480
  *
7294
7481
  * A chain supports swaps if ALL conditions are met:
7295
7482
  * 1. Is a member of the {@link SwapChain} enum
7296
- * 2. Has CCTPv2 support (adapter contract deployed)
7483
+ * 2. Has an Adapter contract configured directly or through CCTP v2
7297
7484
  *
7298
7485
  * Testnets are allowed only when explicitly listed in the
7299
7486
  * {@link SwapChain} enum (e.g., Arc_Testnet).
@@ -7314,14 +7501,14 @@ const swapTokenEnumSchema = zod.z.enum([
7314
7501
  * @remarks
7315
7502
  * Chains automatically become swap-enabled when:
7316
7503
  * - Added to the {@link SwapChain} enum
7317
- * - Adapter contract is deployed (CCTPv2)
7504
+ * - An Adapter contract is deployed and configured
7318
7505
  *
7319
7506
  * No code changes needed when new chains are added!
7320
7507
  */ function isSwapSupportedChain(chain) {
7321
7508
  if (!(chain.chain in SwapChain)) {
7322
7509
  return false;
7323
7510
  }
7324
- if (!isCCTPV2Supported(chain)) {
7511
+ if (!isCCTPV2Supported(chain) && !hasCustomContractSupport(chain, 'adapter')) {
7325
7512
  return false;
7326
7513
  }
7327
7514
  return true;
@@ -7332,7 +7519,7 @@ const swapTokenEnumSchema = zod.z.enum([
7332
7519
  *
7333
7520
  * Dynamically filter chain definitions to include only those that:
7334
7521
  * - Are members of the {@link SwapChain} enum
7335
- * - Have CCTPv2 support
7522
+ * - Have an Adapter contract configured directly or through CCTP v2
7336
7523
  *
7337
7524
  * This function is pure and accepts chains as parameter to avoid
7338
7525
  * circular dependencies.
@@ -8205,11 +8392,13 @@ const swapTokenEnumSchema = zod.z.enum([
8205
8392
  [Blockchain.Arbitrum]: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
8206
8393
  [Blockchain.Avalanche]: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7',
8207
8394
  [Blockchain.Celo]: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
8395
+ [Blockchain.Cronos]: '0x66e428c3f67a68878562e79A0234c1F83c208770',
8208
8396
  [Blockchain.Ethereum]: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
8209
8397
  [Blockchain.HyperEVM]: '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb',
8210
8398
  [Blockchain.Ink]: '0x0200C29006150606B650577BBE7B6248F58470c1',
8211
8399
  [Blockchain.Linea]: '0xA219439258ca9da29E9Cc4cE5596924745e12B93',
8212
8400
  [Blockchain.Monad]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
8401
+ [Blockchain.Morph]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
8213
8402
  [Blockchain.NEAR]: 'usdt.tether-token.near',
8214
8403
  [Blockchain.Optimism]: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58',
8215
8404
  [Blockchain.Polkadot_Asset_Hub]: '1984',
@@ -8268,6 +8457,7 @@ const swapTokenEnumSchema = zod.z.enum([
8268
8457
  [Blockchain.Arbitrum]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
8269
8458
  [Blockchain.Avalanche]: '0xd586E7F844cEa2F87f50152665BCbc2C279D8d70',
8270
8459
  [Blockchain.Base]: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb',
8460
+ [Blockchain.Cronos]: '0xF2001B145b43032AAF5Ee2884e456CCd805F677D',
8271
8461
  [Blockchain.Ethereum]: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
8272
8462
  [Blockchain.Linea]: '0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5',
8273
8463
  [Blockchain.Optimism]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
@@ -8330,7 +8520,9 @@ const swapTokenEnumSchema = zod.z.enum([
8330
8520
  [Blockchain.Arbitrum]: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
8331
8521
  [Blockchain.Avalanche]: '0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB',
8332
8522
  [Blockchain.Base]: '0x4200000000000000000000000000000000000006',
8523
+ [Blockchain.Cronos]: '0xe44Fd7fCb2b1581822D0c862B68222998a0c299a',
8333
8524
  [Blockchain.Ethereum]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
8525
+ [Blockchain.Morph]: '0x5300000000000000000000000000000000000011',
8334
8526
  [Blockchain.Optimism]: '0x4200000000000000000000000000000000000006',
8335
8527
  [Blockchain.Polygon]: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619',
8336
8528
  [Blockchain.Solana]: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs'
@@ -8349,6 +8541,7 @@ const swapTokenEnumSchema = zod.z.enum([
8349
8541
  locators: {
8350
8542
  [Blockchain.Ethereum]: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
8351
8543
  [Blockchain.Arbitrum]: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f',
8544
+ [Blockchain.Cronos]: '0x062E66477Faf219F25D27dCED647BF57C3107d52',
8352
8545
  [Blockchain.Avalanche]: '0x50b7545627a5162F82A992c33b87aDc75187B218'
8353
8546
  }
8354
8547
  };
@@ -9367,7 +9560,7 @@ const swapTokenEnumSchema = zod.z.enum([
9367
9560
  }
9368
9561
 
9369
9562
  var name$4 = "@circle-fin/bridge-kit";
9370
- var version$4 = "1.15.2";
9563
+ var version$4 = "1.15.3";
9371
9564
  var pkg$4 = {
9372
9565
  name: name$4,
9373
9566
  version: version$4};
@@ -11163,7 +11356,7 @@ const validateQuoteItemSchema = zod.z.object({
11163
11356
  registerKit(`${pkg$4.name}/${pkg$4.version}`);
11164
11357
 
11165
11358
  var name$3 = "@circle-fin/swap-kit";
11166
- var version$3 = "1.7.1";
11359
+ var version$3 = "1.8.0";
11167
11360
  var pkg$3 = {
11168
11361
  name: name$3,
11169
11362
  version: version$3};
@@ -11505,6 +11698,64 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
11505
11698
  }, {
11506
11699
  message: 'fee amount must be non-negative (>= 0)'
11507
11700
  });
11701
+ /**
11702
+ * Parses a display-only field leniently: a value `schema` rejects is replaced
11703
+ * with `fallback` instead of failing the response that carries it.
11704
+ * Implemented with `preprocess` rather than Zod's `.catch()` because static
11705
+ * analysis misreads `.catch` on the schema chain as an unhandled Promise
11706
+ * (S7785).
11707
+ */ const withFallback = (schema, fallback)=>zod.z.preprocess((value)=>schema.safeParse(value).success ? value : fallback, schema);
11708
+ const swapRouteTokenSchema = zod.z.object({
11709
+ symbol: zod.z.string(),
11710
+ address: zod.z.string(),
11711
+ decimals: zod.z.number()
11712
+ });
11713
+ const swapRouteMetadataSchema = zod.z.record(zod.z.unknown()).optional();
11714
+ const swapRouteStepSchema = zod.z.object({
11715
+ type: zod.z.string(),
11716
+ tool: zod.z.string(),
11717
+ toolName: zod.z.string(),
11718
+ fromToken: swapRouteTokenSchema,
11719
+ toToken: swapRouteTokenSchema,
11720
+ estimate: zod.z.object({
11721
+ fromAmount: zod.z.string(),
11722
+ toAmount: zod.z.string(),
11723
+ gasCostUSD: zod.z.string().optional()
11724
+ }),
11725
+ metadata: swapRouteMetadataSchema
11726
+ });
11727
+ /**
11728
+ * Strict schema for a `SwapRoute`. Module-private: service responses
11729
+ * parse routes leniently through {@link responseSwapRouteSchema}.
11730
+ */ const swapRouteSchema = zod.z.object({
11731
+ provider: zod.z.string().min(1, 'provider must be a non-empty string'),
11732
+ steps: zod.z.array(swapRouteStepSchema),
11733
+ metadata: swapRouteMetadataSchema
11734
+ });
11735
+ /**
11736
+ * Route details are display-only, so service responses parse them leniently:
11737
+ * steps or metadata in a shape the SDK does not know are dropped rather than
11738
+ * failing the quote or swap they describe. Steps are all-or-nothing: if any
11739
+ * step is malformed, `steps` is empty, so a route never silently loses a hop.
11740
+ */ const responseSwapRouteSchema = swapRouteSchema.extend({
11741
+ steps: withFallback(swapRouteSchema.shape.steps, []),
11742
+ metadata: withFallback(swapRouteMetadataSchema, undefined)
11743
+ });
11744
+ const createSwapFeeItemSchema = zod.z.object({
11745
+ token: zod.z.string({
11746
+ required_error: 'fee token is required',
11747
+ invalid_type_error: 'fee token must be a string'
11748
+ }).min(1, 'fee token must be a non-empty string'),
11749
+ amount: feeAmountSchema,
11750
+ decimals: zod.z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
11751
+ symbol: zod.z.string({
11752
+ invalid_type_error: 'fee token symbol must be a string'
11753
+ }).min(1, 'fee token symbol must be a non-empty string').optional(),
11754
+ // Descriptive metadata: a value the SDK cannot use is dropped rather than
11755
+ // failing the response that carries the fee.
11756
+ type: withFallback(zod.z.string().min(1).optional(), undefined),
11757
+ chain: withFallback(zod.z.string().min(1).optional(), undefined)
11758
+ });
11508
11759
  /**
11509
11760
  * Zod schema for validating API keys.
11510
11761
  *
@@ -11590,10 +11841,7 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
11590
11841
  /** Quote information with estimated amounts and route */ quote: zod.z.object({
11591
11842
  /** 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'),
11592
11843
  /** 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'),
11593
- /** Route information from DEX aggregator */ route: zod.z.object({
11594
- provider: zod.z.string().min(1, 'provider must be a non-empty string'),
11595
- steps: zod.z.array(zod.z.unknown())
11596
- })
11844
+ /** Route information from DEX aggregator */ route: responseSwapRouteSchema
11597
11845
  }),
11598
11846
  /** Fee context indicating where fees should be collected */ feeContext: quoteFeeContextSchema
11599
11847
  });
@@ -11809,19 +12057,6 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
11809
12057
  }).min(1, 'toChain must be a non-empty string if provided').optional(),
11810
12058
  apiKey: apiKeySchema.optional()
11811
12059
  });
11812
- /**
11813
- * Zod schema for validating CreateSwapResponse payloads.
11814
- */ const createSwapFeeItemSchema = zod.z.object({
11815
- token: zod.z.string({
11816
- required_error: 'fee token is required',
11817
- invalid_type_error: 'fee token must be a string'
11818
- }).min(1, 'fee token must be a non-empty string'),
11819
- amount: feeAmountSchema,
11820
- decimals: zod.z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
11821
- symbol: zod.z.string({
11822
- invalid_type_error: 'fee token symbol must be a string'
11823
- }).min(1, 'fee token symbol must be a non-empty string').optional()
11824
- });
11825
12060
  /**
11826
12061
  * Developer fee item schema with basis field.
11827
12062
  */ const createSwapDeveloperFeeItemSchema = createSwapFeeItemSchema.extend({
@@ -11959,6 +12194,8 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
11959
12194
  correlationId: zod.z.preprocess((value)=>zod.z.string().uuid().safeParse(value).success ? value : undefined, zod.z.string().optional()),
11960
12195
  config: createSwapRequestBaseSchema.shape.config.optional(),
11961
12196
  fees: createSwapFeesSchema.optional(),
12197
+ // A route the SDK cannot parse is dropped instead of failing the swap.
12198
+ route: withFallback(responseSwapRouteSchema.optional(), undefined),
11962
12199
  transaction: createSwapTransactionSchema
11963
12200
  });
11964
12201
 
@@ -14921,6 +15158,16 @@ createTokenRegistry();
14921
15158
  name: 'USDC',
14922
15159
  version: '2'
14923
15160
  },
15161
+ Cronos: {
15162
+ chainId: Cronos.chainId,
15163
+ name: 'USDC',
15164
+ version: '2'
15165
+ },
15166
+ Morph: {
15167
+ chainId: Morph.chainId,
15168
+ name: 'USDC',
15169
+ version: '2'
15170
+ },
14924
15171
  Arc_Testnet: {
14925
15172
  chainId: ArcTestnet.chainId,
14926
15173
  name: 'USDC',
@@ -15009,6 +15256,7 @@ const optionalSwapChainIdentifierField = swapChainIdentifierField.optional();
15009
15256
  * - customFee: Optional fee configuration
15010
15257
  * - apiKey: Optional credential string
15011
15258
  * - kitKey: Optional credential string (deprecated alias for apiKey)
15259
+ * - batchTransactions: Optional boolean to opt out of atomic batching
15012
15260
  */ const swapConfigSchema = zod.z.object({
15013
15261
  allowanceStrategy: allowanceStrategySchema.optional(),
15014
15262
  slippageBps: zod.z.number().int().min(0).optional(),
@@ -15019,7 +15267,10 @@ const optionalSwapChainIdentifierField = swapChainIdentifierField.optional();
15019
15267
  })(zod.z.string())).optional(),
15020
15268
  customFee: swapCustomFeeSchema.optional(),
15021
15269
  apiKey: zod.z.string().optional(),
15022
- kitKey: zod.z.string().optional()
15270
+ kitKey: zod.z.string().optional(),
15271
+ batchTransactions: zod.z.boolean({
15272
+ invalid_type_error: 'batchTransactions must be a boolean'
15273
+ }).optional()
15023
15274
  });
15024
15275
  const swapDestinationSchema = zod.z.object({
15025
15276
  chain: optionalSwapChainIdentifierField,
@@ -15212,7 +15463,7 @@ new Set(Object.values(Blockchain));
15212
15463
  registerKit(`${pkg$3.name}/${pkg$3.version}`);
15213
15464
 
15214
15465
  var name$2 = "@circle-fin/earn-kit";
15215
- var version$2 = "1.8.1";
15466
+ var version$2 = "1.9.0";
15216
15467
  var pkg$2 = {
15217
15468
  name: name$2,
15218
15469
  version: version$2};
@@ -16962,6 +17213,187 @@ function isCrossChainDepositStatusStep(step) {
16962
17213
  return step.name === 'status';
16963
17214
  }
16964
17215
 
17216
+ /**
17217
+ * Selector of `TellerWithMultiAssetSupport__SharesAreLocked()`.
17218
+ */ const SHARES_LOCKED_SELECTOR = '0xf64059db';
17219
+ /**
17220
+ * Readable reasons for Veda BoringVault Teller and Accountant reverts.
17221
+ */ const VEDA_REVERT_REASONS = {
17222
+ '0xe0f9e71d': 'The vault is paused',
17223
+ '0x3b3132f6': 'The vault exchange rate is paused',
17224
+ '0xc8bfa33e': 'The vault does not support this asset for this operation',
17225
+ '0x4b37cd2a': 'The asset amount must be greater than zero',
17226
+ '0x3a8c54c4': 'The share amount must be greater than zero',
17227
+ '0x4bd956a8': 'The deposit would mint fewer vault shares than the signed minimum',
17228
+ '0x9883d840': 'The withdrawal would pay out fewer assets than the signed minimum',
17229
+ '0xed32f3bb': 'The deposit would exceed the vault deposit cap',
17230
+ '0x1b8851f0': 'The permit failed and the token allowance is too low',
17231
+ '0x2821264f': 'The vault denied the share transfer'
17232
+ };
17233
+ /**
17234
+ * Matches a 4-byte selector in a message. The lookarounds stop a longer hex
17235
+ * value, such as an address or a hash, from matching.
17236
+ */ const SELECTOR_IN_TEXT = /(?<![0-9a-fx])0x[0-9a-f]{8}(?![0-9a-f])/gi;
17237
+ function toRecord(value) {
17238
+ return typeof value === 'object' && value !== null ? value : {};
17239
+ }
17240
+ function isVedaSelector(selector) {
17241
+ return selector === SHARES_LOCKED_SELECTOR || selector in VEDA_REVERT_REASONS;
17242
+ }
17243
+ /**
17244
+ * Reads the selector from the revert data on a trace. The `/next` adapters
17245
+ * keep it on `revertData`. The default adapters keep the whole raw error on
17246
+ * `rawError`.
17247
+ */ function selectorFromData(trace) {
17248
+ const data = typeof trace['revertData'] === 'string' ? trace['revertData'] : extractRevertData(trace['rawError']);
17249
+ const selector = data?.slice(0, 10).toLowerCase();
17250
+ return selector !== undefined && isVedaSelector(selector) ? selector : undefined;
17251
+ }
17252
+ /**
17253
+ * Reads the selector from error text, for wallets that return no revert
17254
+ * data and put the selector or the decoded error name in the message.
17255
+ */ function selectorFromText(texts) {
17256
+ for (const text of texts){
17257
+ if (typeof text !== 'string') {
17258
+ continue;
17259
+ }
17260
+ if (/SharesAreLocked/i.test(text)) {
17261
+ return SHARES_LOCKED_SELECTOR;
17262
+ }
17263
+ const selector = text.match(SELECTOR_IN_TEXT)?.map((match)=>match.toLowerCase()).find(isVedaSelector);
17264
+ if (selector !== undefined) {
17265
+ return selector;
17266
+ }
17267
+ }
17268
+ return undefined;
17269
+ }
17270
+ /**
17271
+ * Reads a Veda revert from one error, without looking at nested errors.
17272
+ */ function readVedaRevert(error) {
17273
+ const trace = toRecord(error.cause?.trace);
17274
+ const selector = selectorFromData(trace) ?? selectorFromText([
17275
+ error.message,
17276
+ trace['reason']
17277
+ ]);
17278
+ if (selector === undefined) {
17279
+ return undefined;
17280
+ }
17281
+ const chain = trace['chain'];
17282
+ return {
17283
+ selector,
17284
+ chain: typeof chain === 'string' ? chain : undefined
17285
+ };
17286
+ }
17287
+ /**
17288
+ * Returns the errors that a failed batch nests under `trace.cause` or
17289
+ * `trace.error`.
17290
+ */ function nestedErrors(error) {
17291
+ const trace = toRecord(error.cause?.trace);
17292
+ return [
17293
+ trace['cause'],
17294
+ trace['error']
17295
+ ].filter(isKitError);
17296
+ }
17297
+ /**
17298
+ * Finds a Veda revert on the error or on an error nested in its trace.
17299
+ */ function findVedaRevert(error) {
17300
+ const seen = new Set();
17301
+ const pending = [
17302
+ error
17303
+ ];
17304
+ let current = pending.pop();
17305
+ while(current !== undefined){
17306
+ if (!seen.has(current)) {
17307
+ seen.add(current);
17308
+ const revert = readVedaRevert(current);
17309
+ if (revert !== undefined) {
17310
+ return {
17311
+ ...revert,
17312
+ nested: current !== error
17313
+ };
17314
+ }
17315
+ pending.push(...nestedErrors(current));
17316
+ }
17317
+ current = pending.pop();
17318
+ }
17319
+ return undefined;
17320
+ }
17321
+ /**
17322
+ * Map a Veda vault revert to an Earn error.
17323
+ *
17324
+ * A Teller `SharesAreLocked()` revert becomes `EARN_SHARES_LOCKED`. Other
17325
+ * known Veda reverts keep their simulation failed or transaction reverted
17326
+ * code and get a readable reason. A failed batch that wraps a Veda revert
17327
+ * keeps its code, and the reason is added to its message. A timed out batch
17328
+ * is returned unchanged, because its outcome is unknown. Any other error is
17329
+ * returned unchanged.
17330
+ *
17331
+ * @param error - The error caught from an earn operation.
17332
+ * @returns The mapped error, or `error` when it is not a Veda revert.
17333
+ *
17334
+ * @example
17335
+ * ```typescript
17336
+ * import { mapVedaRevert } from './vedaRevert'
17337
+ *
17338
+ * const mapped = mapVedaRevert(error)
17339
+ * console.log(mapped.name) // 'EARN_SHARES_LOCKED' for a share lock revert
17340
+ * ```
17341
+ *
17342
+ * @internal
17343
+ */ function mapVedaRevert(error) {
17344
+ if (error.name === NetworkError.TIMEOUT.name) {
17345
+ return error;
17346
+ }
17347
+ const revert = findVedaRevert(error);
17348
+ if (revert === undefined) {
17349
+ return error;
17350
+ }
17351
+ const trace = toRecord(error.cause?.trace);
17352
+ const chain = typeof trace['chain'] === 'string' ? trace['chain'] : revert.chain ?? 'EVM';
17353
+ if (revert.selector === SHARES_LOCKED_SELECTOR) {
17354
+ return new KitError({
17355
+ ...EarnError.SHARES_LOCKED,
17356
+ // The lock can last hours, so an immediate retry fails the same way.
17357
+ recoverability: 'FATAL',
17358
+ message: `Vault shares on ${chain} are still locked after a recent deposit. Wait for the vault's share lock period to end, then try again.`,
17359
+ cause: {
17360
+ trace: {
17361
+ ...trace,
17362
+ selector: revert.selector,
17363
+ chain
17364
+ }
17365
+ }
17366
+ });
17367
+ }
17368
+ const readable = VEDA_REVERT_REASONS[revert.selector];
17369
+ if (readable === undefined) {
17370
+ return error;
17371
+ }
17372
+ const reason = `${readable} (${revert.selector})`;
17373
+ if (error.name === OnchainError.SIMULATION_FAILED.name) {
17374
+ return createSimulationFailedError(chain, reason, trace);
17375
+ }
17376
+ if (error.name === OnchainError.TRANSACTION_REVERTED.name) {
17377
+ return createTransactionRevertedError(chain, reason, trace);
17378
+ }
17379
+ if (!revert.nested) {
17380
+ return error;
17381
+ }
17382
+ return new KitError({
17383
+ code: error.code,
17384
+ name: error.name,
17385
+ type: error.type,
17386
+ recoverability: error.recoverability,
17387
+ message: `${error.message} Reason: ${reason}.`,
17388
+ cause: {
17389
+ trace: {
17390
+ ...trace,
17391
+ reason
17392
+ }
17393
+ }
17394
+ });
17395
+ }
17396
+
16965
17397
  const EARN_OPERATIONS = new Set([
16966
17398
  'deposit',
16967
17399
  'withdraw',
@@ -17007,6 +17439,10 @@ const EARN_OPERATIONS = new Set([
17007
17439
  * `RESUMABLE` so callers know `retry()` can resume from the failed phase. A
17008
17440
  * fatal underlying error stays fatal — it cannot be resumed.
17009
17441
  *
17442
+ * A Veda vault revert is mapped first (see {@link mapVedaRevert}): a share
17443
+ * lock becomes `EARN_SHARES_LOCKED`, and other known Veda reverts get a
17444
+ * readable reason.
17445
+ *
17010
17446
  * Non-{@link KitError} inputs (which should not occur on provider code paths)
17011
17447
  * are normalized to a retryable {@link ServiceError.INTERNAL_ERROR}.
17012
17448
  *
@@ -17028,7 +17464,7 @@ const EARN_OPERATIONS = new Set([
17028
17464
  * }
17029
17465
  * ```
17030
17466
  */ function augmentEarnError(error, context) {
17031
- const base = isKitError(error) ? error : new KitError({
17467
+ const base = isKitError(error) ? mapVedaRevert(error) : new KitError({
17032
17468
  ...ServiceError.INTERNAL_ERROR,
17033
17469
  recoverability: 'RETRYABLE',
17034
17470
  message: getErrorMessage(error)
@@ -17971,7 +18407,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
17971
18407
  }
17972
18408
 
17973
18409
  var name$1 = "@circle-fin/provider-earn-service";
17974
- var version$1 = "1.7.1";
18410
+ var version$1 = "1.7.2";
17975
18411
  var pkg$1 = {
17976
18412
  name: name$1,
17977
18413
  version: version$1};
@@ -19232,7 +19668,7 @@ function reportTransactionFailure(reportContext, action, error) {
19232
19668
  }
19233
19669
  function transactionReportErrorCode(error) {
19234
19670
  if (isKitError(error)) {
19235
- return error.name;
19671
+ return mapVedaRevert(error).name;
19236
19672
  }
19237
19673
  const message = getErrorMessage(error);
19238
19674
  if (/user (rejected|denied)|rejected by user/i.test(message)) {
@@ -22591,7 +23027,7 @@ registerKit(`${pkg$2.name}/${pkg$2.version}`);
22591
23027
  };
22592
23028
 
22593
23029
  var name = "@circle-fin/borrow-kit";
22594
- var version = "1.0.0";
23030
+ var version = "1.1.0";
22595
23031
  var pkg = {
22596
23032
  name: name,
22597
23033
  version: version};