@circle-fin/app-kit 1.15.2 → 1.16.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 (60) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/README.md +5 -2
  3. package/borrow.cjs +28028 -0
  4. package/borrow.cjs.map +1 -0
  5. package/borrow.d.cts +10723 -0
  6. package/borrow.d.mts +10723 -0
  7. package/borrow.d.ts +10723 -0
  8. package/borrow.mjs +28000 -0
  9. package/borrow.mjs.map +1 -0
  10. package/bridge.cjs +1942 -290
  11. package/bridge.d.cts +157 -12
  12. package/bridge.d.mts +157 -12
  13. package/bridge.d.ts +157 -12
  14. package/bridge.mjs +1942 -290
  15. package/chains.cjs +70 -3
  16. package/chains.d.cts +2 -0
  17. package/chains.d.mts +2 -0
  18. package/chains.d.ts +2 -0
  19. package/chains.mjs +70 -3
  20. package/context.cjs +1 -0
  21. package/context.d.cts +157 -12
  22. package/context.d.mts +157 -12
  23. package/context.d.ts +157 -12
  24. package/context.mjs +1 -0
  25. package/earn.cjs +5466 -3459
  26. package/earn.d.cts +1112 -983
  27. package/earn.d.mts +1112 -983
  28. package/earn.d.ts +1112 -983
  29. package/earn.mjs +5466 -3459
  30. package/estimateBridge.cjs +1940 -288
  31. package/estimateBridge.d.cts +157 -12
  32. package/estimateBridge.d.mts +157 -12
  33. package/estimateBridge.d.ts +157 -12
  34. package/estimateBridge.mjs +1940 -288
  35. package/estimateSwap.cjs +8497 -6831
  36. package/estimateSwap.d.cts +157 -12
  37. package/estimateSwap.d.mts +157 -12
  38. package/estimateSwap.d.ts +157 -12
  39. package/estimateSwap.mjs +8498 -6832
  40. package/index.cjs +30741 -18498
  41. package/index.d.cts +22724 -2322
  42. package/index.d.mts +22724 -2322
  43. package/index.d.ts +22724 -2322
  44. package/index.mjs +30682 -18492
  45. package/package.json +17 -7
  46. package/server.cjs +113 -22
  47. package/server.d.cts +10 -9
  48. package/server.d.mts +10 -9
  49. package/server.d.ts +10 -9
  50. package/server.mjs +113 -22
  51. package/swap.cjs +8497 -6831
  52. package/swap.d.cts +157 -12
  53. package/swap.d.mts +157 -12
  54. package/swap.d.ts +157 -12
  55. package/swap.mjs +8498 -6832
  56. package/unifiedBalance.cjs +457 -128
  57. package/unifiedBalance.d.cts +108 -11
  58. package/unifiedBalance.d.mts +108 -11
  59. package/unifiedBalance.d.ts +108 -11
  60. package/unifiedBalance.mjs +457 -128
@@ -1360,6 +1360,34 @@ let activeRedactor = defaultMessageRedactor;
1360
1360
  return redactErrorMessage(String(error));
1361
1361
  }
1362
1362
 
1363
+ /**
1364
+ * Render an object value for an error message without letting the rendering
1365
+ * itself throw.
1366
+ *
1367
+ * `JSON.stringify` rejects `BigInt` and circular structures, and a rejected
1368
+ * value is exactly the kind of thing a validation error is built from: an
1369
+ * on-chain read or a receipt log carries `bigint` fields, so serializing one
1370
+ * naively replaces the intended error with a `TypeError`.
1371
+ *
1372
+ * @param value - The value to render.
1373
+ * @returns A JSON string with `bigint` fields stringified, or
1374
+ * `'[unserializable object]'` if serialization still fails.
1375
+ * @throws Never; serialization failures are caught and rendered as a fallback string.
1376
+ * @example
1377
+ * ```typescript
1378
+ * import { describeObjectValue } from '@core/errors'
1379
+ *
1380
+ * describeObjectValue({ amount: 1n })
1381
+ * // '{"amount":"1"}'
1382
+ * ```
1383
+ */ function describeObjectValue(value) {
1384
+ try {
1385
+ return JSON.stringify(value, (_key, entry)=>typeof entry === 'bigint' ? entry.toString() : entry);
1386
+ } catch {
1387
+ return '[unserializable object]';
1388
+ }
1389
+ }
1390
+
1363
1391
  /**
1364
1392
  * Creates error for network type mismatch between source and destination.
1365
1393
  *
@@ -1622,7 +1650,7 @@ let activeRedactor = defaultMessageRedactor;
1622
1650
  * // Message: "Validation failed for 'chainId': 999 - Unsupported chain ID"
1623
1651
  *
1624
1652
  * throw createValidationFailedError('config', { invalid: true }, 'Missing required properties')
1625
- * // Message: "Validation failed for 'config': [object Object] - Missing required properties"
1653
+ * // Message: "Validation failed for 'config': {"invalid":true} - Missing required properties"
1626
1654
  * ```
1627
1655
  */ function createValidationFailedError$1(field, value, reason) {
1628
1656
  // Convert value to string for display, handling different types appropriately
@@ -1630,7 +1658,7 @@ let activeRedactor = defaultMessageRedactor;
1630
1658
  if (typeof value === 'string') {
1631
1659
  valueString = `'${value}'`;
1632
1660
  } else if (typeof value === 'object' && value !== null) {
1633
- valueString = JSON.stringify(value);
1661
+ valueString = describeObjectValue(value);
1634
1662
  } else {
1635
1663
  valueString = String(value);
1636
1664
  }
@@ -3128,6 +3156,105 @@ let activeRedactor = defaultMessageRedactor;
3128
3156
  return chain;
3129
3157
  }
3130
3158
 
3159
+ /**
3160
+ * Extracts the HTTP status code from an error message.
3161
+ *
3162
+ * Attempts to parse HTTP status codes from common error message formats,
3163
+ * such as "HTTP 404" or "Status: 500".
3164
+ *
3165
+ * Shared by `parseApiError` and the backend-error-code parsers that route on
3166
+ * status when no backend code is available, so all of them recognise the same
3167
+ * message shapes.
3168
+ *
3169
+ * @param msg - The error message to extract from
3170
+ * @returns The extracted HTTP status code, or null if not found
3171
+ *
3172
+ * @example
3173
+ * ```typescript
3174
+ * const code = extractHttpStatusCode('HTTP 404')
3175
+ * // Returns: 404
3176
+ * ```
3177
+ *
3178
+ * @example
3179
+ * ```typescript
3180
+ * const code = extractHttpStatusCode('Status: 500 Internal Server Error')
3181
+ * // Returns: 500
3182
+ * ```
3183
+ *
3184
+ * @internal
3185
+ */ function extractHttpStatusCode(msg) {
3186
+ // Pattern: "HTTP 404" or "HTTP 404 - some message" or "Status: 404"
3187
+ const patterns = [
3188
+ /HTTP (\d{3})/i,
3189
+ /Status:\s*(\d{3})/i,
3190
+ /^(\d{3}) -/
3191
+ ];
3192
+ for (const pattern of patterns){
3193
+ const match = pattern.exec(msg);
3194
+ const codeStr = match?.at(1);
3195
+ if (codeStr !== undefined) {
3196
+ const code = Number.parseInt(codeStr, 10);
3197
+ // Validate it's a valid HTTP status code
3198
+ if (code >= 100 && code < 600) {
3199
+ return code;
3200
+ }
3201
+ }
3202
+ }
3203
+ return null;
3204
+ }
3205
+
3206
+ /**
3207
+ * Type guard that narrows an unknown error to one carrying a non-null
3208
+ * object `responseBody` property (attached by `makeApiRequest`).
3209
+ *
3210
+ * Shared by backend-error-code parsers (`parseEarnApiError`,
3211
+ * `parseBorrowApiError`) so the narrowing logic lives in one place.
3212
+ *
3213
+ * @param error - The raw error from the HTTP layer
3214
+ * @returns `true` when `error.responseBody` is a non-null object
3215
+ * @internal
3216
+ */ function hasResponseBody(error) {
3217
+ return typeof error === 'object' && error !== null && 'responseBody' in error && typeof error['responseBody'] === 'object' && error['responseBody'] !== null;
3218
+ }
3219
+ /**
3220
+ * Narrow an unknown value to a non-null object.
3221
+ *
3222
+ * @param value - The value to check
3223
+ * @returns `true` when `value` is a non-null object
3224
+ * @internal
3225
+ */ function isRecord(value) {
3226
+ return typeof value === 'object' && value !== null;
3227
+ }
3228
+ /**
3229
+ * Read the machine-readable error fields (`code`, `message`,
3230
+ * `externalMessage`) that a Circle service attaches to an HTTP error body.
3231
+ *
3232
+ * `platform-common-go` serializes app-thrown errors under a nested envelope —
3233
+ * `{ response: { status: { code, message, externalMessage } } }` — for every
3234
+ * HTTP status, so this returns that inner `response.status` object when
3235
+ * present. It otherwise falls back to the top-level body so a flattened shape
3236
+ * (e.g. the stablecoin-kits-proxy) is still read. Callers read
3237
+ * `code` / `message` / `externalMessage` off the returned object uniformly.
3238
+ *
3239
+ * @param error - The raw error from the HTTP layer
3240
+ * @returns The error-status fields, or `undefined` when the error carries no
3241
+ * response body
3242
+ * @internal
3243
+ */ function extractResponseBody$1(error) {
3244
+ if (!hasResponseBody(error)) {
3245
+ return undefined;
3246
+ }
3247
+ const body = error.responseBody;
3248
+ const response = body['response'];
3249
+ if (isRecord(response)) {
3250
+ const status = response['status'];
3251
+ if (isRecord(status)) {
3252
+ return status;
3253
+ }
3254
+ }
3255
+ return body;
3256
+ }
3257
+
3131
3258
  /**
3132
3259
  * Proxy-specific structured error codes carried in `responseBody.code`.
3133
3260
  *
@@ -3428,29 +3555,22 @@ let activeRedactor = defaultMessageRedactor;
3428
3555
  });
3429
3556
  }
3430
3557
  /**
3431
- * Type guard that narrows an unknown error to one carrying a non-null
3432
- * object `responseBody` property (attached by `makeApiRequest`).
3558
+ * Extract the machine-readable error fields that `makeApiRequest` attaches to
3559
+ * HTTP error instances.
3433
3560
  *
3434
- * @param error - The raw error from the HTTP layer
3435
- * @returns `true` when `error.responseBody` is a non-null object
3436
- * @internal
3437
- */ function hasResponseBody(error) {
3438
- return typeof error === 'object' && error !== null && 'responseBody' in error && typeof error['responseBody'] === 'object' && error['responseBody'] !== null;
3439
- }
3440
- /**
3441
- * Extract the `responseBody` property that `makeApiRequest` attaches to
3442
- * HTTP error instances when the server returns a JSON body.
3561
+ * Delegates to the shared extractor so this fall-through path reads the same
3562
+ * shape as the backend-code parsers: it unwraps the nested
3563
+ * `{ response: { status } }` envelope when present, otherwise returns the
3564
+ * top-level body. Routing both halves through one extractor keeps an
3565
+ * unmapped-code error from losing the server's `externalMessage`.
3443
3566
  *
3444
3567
  * @param error - The raw error from the HTTP layer
3445
- * @returns The parsed body cast to {@link ApiErrorResponseBody}, or undefined
3568
+ * @returns The parsed body as {@link ApiErrorResponseBody}, or undefined
3446
3569
  * @throws Never. Returns `undefined` when the error does not carry a valid
3447
3570
  * `responseBody`.
3448
3571
  * @internal
3449
3572
  */ function extractResponseBody(error) {
3450
- if (!hasResponseBody(error)) {
3451
- return undefined;
3452
- }
3453
- return error.responseBody;
3573
+ return extractResponseBody$1(error);
3454
3574
  }
3455
3575
  /**
3456
3576
  * Extract a field name from an {@link ApiFieldError}.
@@ -3559,46 +3679,6 @@ let activeRedactor = defaultMessageRedactor;
3559
3679
  }
3560
3680
  return topMessage ?? fieldDetail;
3561
3681
  }
3562
- /**
3563
- * Extracts the HTTP status code from an error message.
3564
- *
3565
- * Attempts to parse HTTP status codes from common error message formats,
3566
- * such as "HTTP 404" or "Status: 500".
3567
- *
3568
- * @param msg - The error message to extract from
3569
- * @returns The extracted HTTP status code, or null if not found
3570
- *
3571
- * @example
3572
- * ```typescript
3573
- * const code = extractHttpStatusCode('HTTP 404')
3574
- * // Returns: 404
3575
- * ```
3576
- *
3577
- * @example
3578
- * ```typescript
3579
- * const code = extractHttpStatusCode('Status: 500 Internal Server Error')
3580
- * // Returns: 500
3581
- * ```
3582
- */ function extractHttpStatusCode(msg) {
3583
- // Pattern: "HTTP 404" or "HTTP 404 - some message" or "Status: 404"
3584
- const patterns = [
3585
- /HTTP (\d{3})/i,
3586
- /Status:\s*(\d{3})/i,
3587
- /^(\d{3}) -/
3588
- ];
3589
- for (const pattern of patterns){
3590
- const match = pattern.exec(msg);
3591
- const codeStr = match?.at(1);
3592
- if (codeStr !== undefined) {
3593
- const code = Number.parseInt(codeStr, 10);
3594
- // Validate it's a valid HTTP status code
3595
- if (code >= 100 && code < 600) {
3596
- return code;
3597
- }
3598
- }
3599
- }
3600
- return null;
3601
- }
3602
3682
 
3603
3683
  /**
3604
3684
  * @packageDocumentation
@@ -3854,6 +3934,11 @@ var EarnChain;
3854
3934
  "Arc",
3855
3935
  "Arc_Testnet"
3856
3936
  ];
3937
+ var BorrowChain;
3938
+ (function(BorrowChain) {
3939
+ BorrowChain["Arc"] = "Arc";
3940
+ BorrowChain["Arc_Testnet"] = "Arc_Testnet";
3941
+ })(BorrowChain || (BorrowChain = {}));
3857
3942
 
3858
3943
  /**
3859
3944
  * Helper function to define a chain with proper TypeScript typing.
@@ -4196,6 +4281,29 @@ var EarnChain;
4196
4281
  * on EVM-compatible testnet chains. Use this address for testnet adapter
4197
4282
  * integrations (e.g., Arc Testnet).
4198
4283
  */ const ADAPTER_CONTRACT_EVM_TESTNET = '0xBBD70b01a1CAbc96d5b7b129Ae1AAabdf50dd40b';
4284
+ /**
4285
+ * The sender-preserving batching contract on Arc (`Multicall3From`).
4286
+ *
4287
+ * This predeploy batches calls like the ubiquitous Multicall3, but routes each
4288
+ * subcall through Arc's `CallFrom` precompile
4289
+ * (`0x1800000000000000000000000000000000000003`), which executes on behalf of
4290
+ * the transaction's original sender. Every target therefore sees the calling
4291
+ * EOA as `msg.sender`, which is what makes a plain, un-upgraded EOA capable of
4292
+ * an atomic batch on Arc.
4293
+ *
4294
+ * Deployed at the same address on Arc Testnet and Arc Mainnet.
4295
+ *
4296
+ * @see https://docs.arc.io/arc/concepts/batched-transactions
4297
+ */ const BATCHER_CONTRACT_ARC_TESTNET = '0x522fAf9A91c41c443c66765030741e4AaCe147D0';
4298
+ /**
4299
+ * The sender-preserving batching contract on Arc Mainnet (`Multicall3From`).
4300
+ *
4301
+ * See {@link BATCHER_CONTRACT_ARC_TESTNET} for how this contract works.
4302
+ * Requires Arc's Zero7 hardfork, which activates the `CallFrom` precompile
4303
+ * this contract depends on.
4304
+ *
4305
+ * @see https://docs.arc.io/arc/concepts/batched-transactions
4306
+ */ const BATCHER_CONTRACT_ARC_MAINNET = '0x522fAf9A91c41c443c66765030741e4AaCe147D0';
4199
4307
  /**
4200
4308
  * The GatewayWallet contract address for EVM mainnet networks.
4201
4309
  *
@@ -4335,7 +4443,10 @@ var EarnChain;
4335
4443
  },
4336
4444
  kitContracts: {
4337
4445
  bridge: BRIDGE_CONTRACT_EVM_MAINNET,
4338
- adapter: ADAPTER_CONTRACT_EVM_MAINNET
4446
+ adapter: ADAPTER_CONTRACT_EVM_MAINNET,
4447
+ // Arc is the only chain with a sender-preserving batcher, because it
4448
+ // takes a precompile rather than an ordinary contract to build one.
4449
+ senderPreservingBatcher: BATCHER_CONTRACT_ARC_MAINNET
4339
4450
  },
4340
4451
  gateway: {
4341
4452
  domain: 26,
@@ -4406,7 +4517,10 @@ var EarnChain;
4406
4517
  },
4407
4518
  kitContracts: {
4408
4519
  bridge: BRIDGE_CONTRACT_EVM_TESTNET,
4409
- adapter: ADAPTER_CONTRACT_EVM_TESTNET
4520
+ adapter: ADAPTER_CONTRACT_EVM_TESTNET,
4521
+ // Arc is the only chain with a sender-preserving batcher, because it
4522
+ // takes a precompile rather than an ordinary contract to build one.
4523
+ senderPreservingBatcher: BATCHER_CONTRACT_ARC_TESTNET
4410
4524
  },
4411
4525
  gateway: {
4412
4526
  domain: 26,
@@ -8076,7 +8190,8 @@ var Chains = /*#__PURE__*/Object.freeze({
8076
8190
  cctpx: z.any().optional(),
8077
8191
  kitContracts: z.object({
8078
8192
  bridge: z.string().optional(),
8079
- adapter: z.string().optional()
8193
+ adapter: z.string().optional(),
8194
+ senderPreservingBatcher: z.string().optional()
8080
8195
  }).optional(),
8081
8196
  gateway: gatewayConfigSchema.optional()
8082
8197
  });
@@ -8272,6 +8387,38 @@ var Chains = /*#__PURE__*/Object.freeze({
8272
8387
  message: `"${chain.chain}" is not a supported earn chain. ` + `Supported chains: ${Object.values(EarnChain).join(', ')}`
8273
8388
  }))
8274
8389
  ]);
8390
+ /**
8391
+ * Zod schema for validating Borrow-specific chain identifiers.
8392
+ *
8393
+ * Validate that the provided chain is supported for Borrow Kit's loan
8394
+ * operations. Unlike {@link earnChainIdentifierSchema}, this includes Arc
8395
+ * mainnet as well as Arc Testnet.
8396
+ *
8397
+ * Accept a BorrowChain enum value, a matching string literal, or a
8398
+ * ChainDefinition for a supported chain.
8399
+ *
8400
+ * @example
8401
+ * ```typescript
8402
+ * import { borrowChainIdentifierSchema } from '@core/chains'
8403
+ * import { Arc, BorrowChain } from '@core/chains'
8404
+ *
8405
+ * // Valid
8406
+ * borrowChainIdentifierSchema.parse(BorrowChain.Arc)
8407
+ * borrowChainIdentifierSchema.parse('Arc')
8408
+ * borrowChainIdentifierSchema.parse(Arc)
8409
+ *
8410
+ * // Invalid (throws ZodError)
8411
+ * borrowChainIdentifierSchema.parse('Solana')
8412
+ * ```
8413
+ */ const borrowChainIdentifierSchema = z.union([
8414
+ z.string().refine((val)=>val in BorrowChain, (val)=>({
8415
+ message: `"${val}" is not a supported borrow chain. ` + `Supported chains: ${Object.values(BorrowChain).join(', ')}`
8416
+ })),
8417
+ z.nativeEnum(BorrowChain),
8418
+ chainDefinitionSchema$2.refine((chain)=>chain.chain in BorrowChain, (chain)=>({
8419
+ message: `"${chain.chain}" is not a supported borrow chain. ` + `Supported chains: ${Object.values(BorrowChain).join(', ')}`
8420
+ }))
8421
+ ]);
8275
8422
  // Widened views so `.includes()` accepts arbitrary strings under strict TS.
8276
8423
  const EARN_BRIDGE_SOURCE_CHAIN_VALUES = EARN_BRIDGE_SOURCE_BLOCKCHAINS;
8277
8424
  const EARN_BRIDGE_DESTINATION_CHAIN_VALUES = EARN_BRIDGE_DESTINATION_BLOCKCHAINS;
@@ -8482,8 +8629,13 @@ const swapTokenEnumSchema = z.enum([
8482
8629
  */ function resolveChainName(value) {
8483
8630
  if (value == null) return undefined;
8484
8631
  if (typeof value === 'string') return value;
8485
- if (typeof value === 'object' && 'chain' in value && typeof value.chain === 'string') {
8486
- return value.chain;
8632
+ try {
8633
+ if (typeof value === 'object' && 'chain' in value) {
8634
+ const chain = value.chain;
8635
+ if (typeof chain === 'string') return chain;
8636
+ }
8637
+ } catch {
8638
+ return undefined;
8487
8639
  }
8488
8640
  return undefined;
8489
8641
  }
@@ -9191,6 +9343,7 @@ const swapTokenEnumSchema = z.enum([
9191
9343
  * - Retries on rate limiting (429)
9192
9344
  * - Does not retry on client errors (4xx, except 429)
9193
9345
  * - Does not retry on validation failures
9346
+ * - Does not retry when `config.isTerminalError` marks the error terminal
9194
9347
  *
9195
9348
  * Each HTTP request is given a configurable timeout before it is aborted.
9196
9349
  * Between retry attempts the wait depends on the `backoff` strategy. The
@@ -9270,7 +9423,10 @@ const swapTokenEnumSchema = z.enum([
9270
9423
  return await makeApiRequest(url, method, isValidType, effectiveConfig, body);
9271
9424
  } catch (err) {
9272
9425
  const error = err instanceof Error ? err : new Error(String(err));
9273
- if (!isRetryableError(error)) {
9426
+ // A caller-supplied predicate can mark an error terminal (e.g. a
9427
+ // deterministic 404) so it is surfaced immediately instead of burning
9428
+ // the retry budget on a non-transient answer.
9429
+ if (effectiveConfig.isTerminalError?.(error) === true || !isRetryableError(error)) {
9274
9430
  throw error;
9275
9431
  }
9276
9432
  lastError = error;
@@ -9354,7 +9510,24 @@ const swapTokenEnumSchema = z.enum([
9354
9510
  * // After this call, TypeScript knows params is of type BridgeParams
9355
9511
  * ```
9356
9512
  */ function validate(value, schema, context) {
9357
- const result = schema.safeParse(value);
9513
+ let result;
9514
+ try {
9515
+ result = schema.safeParse(value);
9516
+ } catch (error) {
9517
+ throw new KitError({
9518
+ ...InputError.VALIDATION_FAILED,
9519
+ recoverability: 'FATAL',
9520
+ message: `Invalid ${context}: reading a property threw`,
9521
+ cause: {
9522
+ trace: {
9523
+ validationErrors: [
9524
+ 'Reading a property of the value threw'
9525
+ ],
9526
+ originalError: error
9527
+ }
9528
+ }
9529
+ });
9530
+ }
9358
9531
  if (!result.success) {
9359
9532
  throw createValidationErrorFromZod(result.error, context);
9360
9533
  }
@@ -12055,11 +12228,11 @@ function resolveOptions(options) {
12055
12228
  void emitAnalyticsLog(buildPayload(config, stepEntry?.[1] ?? fallbackEventType, errorDetails, context));
12056
12229
  }
12057
12230
 
12058
- var name$2 = "@circle-fin/bridge-kit";
12059
- var version$3 = "1.15.1";
12060
- var pkg$3 = {
12061
- name: name$2,
12062
- version: version$3};
12231
+ var name$3 = "@circle-fin/bridge-kit";
12232
+ var version$4 = "1.15.2";
12233
+ var pkg$4 = {
12234
+ name: name$3,
12235
+ version: version$4};
12063
12236
 
12064
12237
  const assertCustomFeePolicySymbol = Symbol('assertCustomFeePolicy');
12065
12238
  /**
@@ -12628,6 +12801,12 @@ const READ_ACTION_KEY_SET = new Set(READ_ACTION_KEYS);
12628
12801
  /** EIP-2612 standard permit */ PermitType[PermitType["EIP2612"] = 1] = "EIP2612";
12629
12802
  })(PermitType || (PermitType = {}));
12630
12803
 
12804
+ var BorrowPermitType;
12805
+ (function(BorrowPermitType) {
12806
+ /** Tokens must be approved separately. */ BorrowPermitType[BorrowPermitType["NONE"] = 0] = "NONE";
12807
+ /** EIP-2612 permit calldata accompanies the token input. */ BorrowPermitType[BorrowPermitType["EIP2612"] = 1] = "EIP2612";
12808
+ })(BorrowPermitType || (BorrowPermitType = {}));
12809
+
12631
12810
  /**
12632
12811
  * Abstract base class for bridging providers that implement cross-chain bridging protocols.
12633
12812
  *
@@ -19751,7 +19930,7 @@ const defaultSleep = async (ms)=>new Promise((resolve)=>setTimeout(resolve, ms))
19751
19930
  * Must always contain both adapter and chain explicitly.
19752
19931
  *
19753
19932
  * Optionally includes address for developer-controlled adapters.
19754
- */ const adapterContextSchema$3 = z.object({
19933
+ */ const adapterContextSchema$4 = z.object({
19755
19934
  adapter: adapterSchema,
19756
19935
  chain: bridgeChainIdentifierSchema,
19757
19936
  address: z.string().optional()
@@ -19760,14 +19939,14 @@ const defaultSleep = async (ms)=>new Promise((resolve)=>setTimeout(resolve, ms))
19760
19939
  * Schema for validating BridgeDestinationWithAddress objects.
19761
19940
  * Contains an explicit recipientAddress along with adapter and chain.
19762
19941
  * The address format is validated based on the chain type (EVM or Solana).
19763
- */ const bridgeDestinationWithAddressSchema = adapterContextSchema$3.extend({
19942
+ */ const bridgeDestinationWithAddressSchema = adapterContextSchema$4.extend({
19764
19943
  recipientAddress: z.string().min(1, 'Recipient address is required'),
19765
19944
  useForwarder: z.boolean().optional()
19766
19945
  }).superRefine(createRecipientAddressValidator());
19767
19946
  /**
19768
19947
  * Schema for validating AdapterContext with optional useForwarder.
19769
19948
  * Extends adapterContextSchema with the useForwarder flag.
19770
- */ const adapterContextWithForwarderSchema = adapterContextSchema$3.extend({
19949
+ */ const adapterContextWithForwarderSchema = adapterContextSchema$4.extend({
19771
19950
  useForwarder: z.boolean().optional()
19772
19951
  });
19773
19952
  /**
@@ -19842,7 +20021,7 @@ const defaultSleep = async (ms)=>new Promise((resolve)=>setTimeout(resolve, ms))
19842
20021
  * }
19843
20022
  * ```
19844
20023
  */ const bridgeParamsWithChainIdentifierSchema = z.object({
19845
- from: adapterContextSchema$3.strict(),
20024
+ from: adapterContextSchema$4.strict(),
19846
20025
  to: bridgeDestinationSchema,
19847
20026
  amount: z.string().min(1, 'Required').pipe(createDecimalStringValidator({
19848
20027
  allowZero: false,
@@ -20002,7 +20181,7 @@ const defaultSleep = async (ms)=>new Promise((resolve)=>setTimeout(resolve, ms))
20002
20181
  const bridgeKitCaller = {
20003
20182
  type: 'kit',
20004
20183
  name: 'BridgeKit',
20005
- version: pkg$3.version
20184
+ version: pkg$4.version
20006
20185
  };
20007
20186
  // Create default runtime and tokens for invocation context resolution
20008
20187
  const defaults = {
@@ -23221,16 +23400,16 @@ const mockAttestationMessage = {
23221
23400
  return step;
23222
23401
  }
23223
23402
 
23224
- var version$2 = "1.14.0";
23225
- var pkg$2 = {
23226
- version: version$2};
23403
+ var version$3 = "1.14.1";
23404
+ var pkg$3 = {
23405
+ version: version$3};
23227
23406
 
23228
23407
  /**
23229
23408
  * Provider caller component for bridge operations.
23230
23409
  */ const BRIDGE_CALLER = {
23231
23410
  type: 'provider',
23232
23411
  name: 'CCTPV2BridgingProvider.bridge',
23233
- version: pkg$2.version
23412
+ version: pkg$3.version
23234
23413
  };
23235
23414
  /**
23236
23415
  * Resolve invocation context for bridge operations.
@@ -23603,7 +23782,7 @@ var pkg$2 = {
23603
23782
  */ const RETRY_CALLER = {
23604
23783
  type: 'provider',
23605
23784
  name: 'CCTPV2BridgingProvider.retry',
23606
- version: pkg$2.version
23785
+ version: pkg$3.version
23607
23786
  };
23608
23787
  /**
23609
23788
  * Resolve invocation context for retry operations.
@@ -25530,7 +25709,7 @@ function assertCCTPV2Config(config) {
25530
25709
  * Decimal string in token minor units, constrained to be strictly positive.
25531
25710
  *
25532
25711
  * @internal
25533
- */ const positiveAmountSchema = z.string().regex(/^\d+$/, 'must be a non-negative integer string')// Re-check the digit shape here: zod still runs this refinement when the
25712
+ */ const positiveAmountSchema$1 = z.string().regex(/^\d+$/, 'must be a non-negative integer string')// Re-check the digit shape here: zod still runs this refinement when the
25534
25713
  // regex check above fails ("dirty"), so guard BigInt() against throwing on a
25535
25714
  // non-numeric value before comparing.
25536
25715
  .refine((value)=>/^\d+$/.test(value) && BigInt(value) > 0n, 'must be greater than zero');
@@ -25610,7 +25789,7 @@ const preFinalityRequestSchema = z.object({
25610
25789
  */ const fetchFeeQuoteInputSchema = z.object({
25611
25790
  sourceDomain: z.number().int().nonnegative(),
25612
25791
  destinationDomain: z.number().int().nonnegative(),
25613
- amount: positiveAmountSchema,
25792
+ amount: positiveAmountSchema$1,
25614
25793
  feeToken: evmAddressSchema.optional(),
25615
25794
  requests: feeQuoteRequestsSchema,
25616
25795
  isTestnet: z.boolean(),
@@ -26487,7 +26666,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
26487
26666
  * The ERC-20 `decimals` field is a `uint8`, so a provider reporting more than
26488
26667
  * this is returning something that cannot describe a real token.
26489
26668
  */ const MAX_TOKEN_DECIMALS = 255;
26490
- /** SDK name used in telemetry payloads. */ const SDK_NAME = resolveKitSdkName(pkg$3.name);
26669
+ /** SDK name used in telemetry payloads. */ const SDK_NAME = resolveKitSdkName(pkg$4.name);
26491
26670
  /**
26492
26671
  * Pick the most-relevant `txHash` to attach to an error telemetry payload.
26493
26672
  *
@@ -26528,7 +26707,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
26528
26707
  */ const BRIDGE_KIT_CALLER = {
26529
26708
  type: 'kit',
26530
26709
  name: 'BridgeKit',
26531
- version: pkg$3.version
26710
+ version: pkg$4.version
26532
26711
  };
26533
26712
  /**
26534
26713
  * Merge BridgeKit's caller into the invocation metadata for retry operations.
@@ -26676,7 +26855,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
26676
26855
  this.disableErrorReporting = config.disableErrorReporting === true;
26677
26856
  this.telemetryConfig = {
26678
26857
  sdkName: SDK_NAME,
26679
- sdkVersion: pkg$3.version,
26858
+ sdkVersion: pkg$4.version,
26680
26859
  disabled: this.disableErrorReporting
26681
26860
  };
26682
26861
  for (const provider of this.providers){
@@ -27400,7 +27579,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
27400
27579
  }
27401
27580
 
27402
27581
  // Auto-register this kit for user agent tracking
27403
- registerKit(`${pkg$3.name}/${pkg$3.version}`);
27582
+ registerKit(`${pkg$4.name}/${pkg$4.version}`);
27404
27583
 
27405
27584
  /**
27406
27585
  * Create a BridgeKit instance with optional developer fee configuration.
@@ -27471,11 +27650,11 @@ registerKit(`${pkg$3.name}/${pkg$3.version}`);
27471
27650
  return kit;
27472
27651
  };
27473
27652
 
27474
- var name$1 = "@circle-fin/swap-kit";
27475
- var version$1 = "1.7.0";
27476
- var pkg$1 = {
27477
- name: name$1,
27478
- version: version$1};
27653
+ var name$2 = "@circle-fin/swap-kit";
27654
+ var version$2 = "1.7.1";
27655
+ var pkg$2 = {
27656
+ name: name$2,
27657
+ version: version$2};
27479
27658
 
27480
27659
  const chainIdentifierField = z.custom((value)=>chainIdentifierSchema.safeParse(value).success, {
27481
27660
  message: 'chain must be a valid chain identifier'
@@ -27556,7 +27735,7 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
27556
27735
  *
27557
27736
  * @remarks
27558
27737
  * Optionally includes address for developer-controlled adapters.
27559
- */ const adapterContextSchema$2 = z.object({
27738
+ */ const adapterContextSchema$3 = z.object({
27560
27739
  adapter: adapterSchema,
27561
27740
  chain: chainIdentifierField,
27562
27741
  address: z.string().optional()
@@ -27577,7 +27756,7 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
27577
27756
  * }
27578
27757
  * ```
27579
27758
  */ z.object({
27580
- from: adapterContextSchema$2,
27759
+ from: adapterContextSchema$3,
27581
27760
  tokenIn: z.string({
27582
27761
  required_error: 'tokenIn is required',
27583
27762
  invalid_type_error: 'tokenIn must be a string'
@@ -28305,36 +28484,176 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
28305
28484
  return normalize(source.apiKey) ?? normalize(source.kitKey);
28306
28485
  };
28307
28486
 
28487
+ function isBigIntLike$1(value) {
28488
+ try {
28489
+ BigInt(value);
28490
+ return true;
28491
+ } catch {
28492
+ return false;
28493
+ }
28494
+ }
28495
+ function isNonNegativeBigIntLike$3(value) {
28496
+ try {
28497
+ return BigInt(value) >= 0n;
28498
+ } catch {
28499
+ return false;
28500
+ }
28501
+ }
28308
28502
  /**
28309
- * Zod schema for validating EVM adapter capabilities.
28503
+ * A `0x`-prefixed, even-length hex byte string (`'0x'` for empty calldata).
28310
28504
  *
28311
- * This schema ensures that EVM adapter capabilities meet the requirements for the
28312
- * OperationContext pattern by validating the addressContext property and ensuring
28313
- * the supportedChains property contains only EVM-compatible chains.
28505
+ * @internal
28506
+ */ const hexBytesSchema$3 = z.union([
28507
+ hexStringSchema,
28508
+ z.literal('0x')
28509
+ ]).refine((value)=>value.length % 2 === 0, {
28510
+ message: 'value must be a 0x-prefixed even-length hex string'
28511
+ });
28512
+ /**
28513
+ * A non-negative uint256, accepted as a decimal string or a `bigint`.
28314
28514
  *
28315
- * @remarks
28316
- * This schema enforces that all supported chains are EVM type, making it specific
28317
- * to EVM adapters (Ethers, Viem, etc.). For non-EVM adapters, a different validation
28318
- * schema should be used.
28515
+ * @internal
28516
+ */ const uint256LikeSchema$3 = z.union([
28517
+ z.string(),
28518
+ z.bigint()
28519
+ ]).refine(isNonNegativeBigIntLike$3, {
28520
+ message: 'value must be a non-negative bigint-compatible string or bigint'
28521
+ });
28522
+ /**
28523
+ * A typed base-unit amount object as emitted by the API.
28319
28524
  *
28320
- * When used with the validate() function from @core/utils, this throws KitError
28321
- * with INPUT_VALIDATION_FAILED code if validation fails, with details about which
28322
- * properties failed.
28525
+ * @internal
28526
+ */ const amountJsonSchema$2 = z.object({
28527
+ raw: z.string().refine(isBigIntLike$1, {
28528
+ message: 'raw must be a bigint-compatible string'
28529
+ }),
28530
+ decimals: z.number().int().nonnegative()
28531
+ });
28532
+ /**
28533
+ * One instruction in a signed claim-rewards execution payload.
28323
28534
  *
28324
- * @example
28325
- * ```typescript
28326
- * import { AdapterCapabilitiesSchema } from '@core/adapter-evm/validation'
28327
- * import { Ethereum, Base } from '@core/chains'
28535
+ * `.passthrough()` so a backend that adds a field does not fail validation.
28328
28536
  *
28329
- * // Valid user-controlled capabilities
28330
- * const userCapabilities = {
28331
- * addressContext: 'user-controlled',
28332
- * supportedChains: [Ethereum, Base]
28333
- * }
28537
+ * @internal
28538
+ */ const claimRewardsInstructionSchema = z.object({
28539
+ target: evmAddressSchema$1,
28540
+ data: hexBytesSchema$3,
28541
+ value: uint256LikeSchema$3,
28542
+ tokenIn: evmAddressSchema$1,
28543
+ amountToApprove: uint256LikeSchema$3,
28544
+ tokenOut: evmAddressSchema$1,
28545
+ minTokenOut: uint256LikeSchema$3
28546
+ }).passthrough();
28547
+ const claimRewardsTokenSchema = z.object({
28548
+ token: evmAddressSchema$1,
28549
+ beneficiary: evmAddressSchema$1
28550
+ }).passthrough();
28551
+ /**
28552
+ * The signed execution payload the `earn.claimRewards` Adapter action takes.
28334
28553
  *
28335
- * // Valid developer-controlled capabilities
28336
- * const devCapabilities = {
28337
- * addressContext: 'developer-controlled',
28554
+ * @internal
28555
+ */ const claimRewardsExecutionParamsSchema = z.object({
28556
+ instructions: z.tuple([
28557
+ claimRewardsInstructionSchema
28558
+ ]).rest(claimRewardsInstructionSchema),
28559
+ tokens: z.tuple([
28560
+ claimRewardsTokenSchema
28561
+ ]).rest(claimRewardsTokenSchema),
28562
+ execId: uint256LikeSchema$3,
28563
+ deadline: uint256LikeSchema$3,
28564
+ metadata: hexBytesSchema$3
28565
+ }).passthrough();
28566
+ /**
28567
+ * A single claimable reward entry in a claim-rewards response.
28568
+ *
28569
+ * @internal
28570
+ */ const claimedAmountSchema = z.object({
28571
+ token: evmAddressSchema$1,
28572
+ symbol: z.string(),
28573
+ amount: amountJsonSchema$2
28574
+ });
28575
+ /**
28576
+ * The `data` envelope of a claim-rewards response.
28577
+ *
28578
+ * `executionParams` and `signature` are present exactly when rewards are
28579
+ * claimable — never one without the other, and never either when `rewards`
28580
+ * is empty.
28581
+ *
28582
+ * @internal
28583
+ */ const claimRewardsPayloadSchema = z.object({
28584
+ rewards: z.array(claimedAmountSchema),
28585
+ executionParams: claimRewardsExecutionParamsSchema.optional(),
28586
+ signature: evmSignatureSchema.optional()
28587
+ }).refine((data)=>{
28588
+ const signedFieldCount = (data.executionParams === undefined ? 0 : 1) + (data.signature === undefined ? 0 : 1);
28589
+ if (data.rewards.length > 0) {
28590
+ return signedFieldCount === 2;
28591
+ }
28592
+ return signedFieldCount === 0;
28593
+ }, {
28594
+ message: 'claim rewards response must include executionParams and signature only when rewards are claimable'
28595
+ });
28596
+ /**
28597
+ * Zod schema for a claim-rewards API response.
28598
+ *
28599
+ * @internal
28600
+ */ z.object({
28601
+ data: claimRewardsPayloadSchema
28602
+ });
28603
+ /**
28604
+ * A single claimable reward entry in a claim-rewards quote response.
28605
+ *
28606
+ * @internal
28607
+ */ const claimRewardsQuoteRewardSchema = z.object({
28608
+ token: z.string(),
28609
+ symbol: z.string(),
28610
+ amount: amountJsonSchema$2
28611
+ });
28612
+ /**
28613
+ * The `data` envelope of a claim-rewards quote response.
28614
+ *
28615
+ * @internal
28616
+ */ const claimRewardsQuotePayloadSchema = z.object({
28617
+ rewards: z.array(claimRewardsQuoteRewardSchema)
28618
+ });
28619
+ /**
28620
+ * Zod schema for a claim-rewards quote API response.
28621
+ *
28622
+ * @internal
28623
+ */ z.object({
28624
+ data: claimRewardsQuotePayloadSchema
28625
+ });
28626
+
28627
+ /**
28628
+ * Zod schema for validating EVM adapter capabilities.
28629
+ *
28630
+ * This schema ensures that EVM adapter capabilities meet the requirements for the
28631
+ * OperationContext pattern by validating the addressContext property and ensuring
28632
+ * the supportedChains property contains only EVM-compatible chains.
28633
+ *
28634
+ * @remarks
28635
+ * This schema enforces that all supported chains are EVM type, making it specific
28636
+ * to EVM adapters (Ethers, Viem, etc.). For non-EVM adapters, a different validation
28637
+ * schema should be used.
28638
+ *
28639
+ * When used with the validate() function from @core/utils, this throws KitError
28640
+ * with INPUT_VALIDATION_FAILED code if validation fails, with details about which
28641
+ * properties failed.
28642
+ *
28643
+ * @example
28644
+ * ```typescript
28645
+ * import { AdapterCapabilitiesSchema } from '@core/adapter-evm/validation'
28646
+ * import { Ethereum, Base } from '@core/chains'
28647
+ *
28648
+ * // Valid user-controlled capabilities
28649
+ * const userCapabilities = {
28650
+ * addressContext: 'user-controlled',
28651
+ * supportedChains: [Ethereum, Base]
28652
+ * }
28653
+ *
28654
+ * // Valid developer-controlled capabilities
28655
+ * const devCapabilities = {
28656
+ * addressContext: 'developer-controlled',
28338
28657
  * supportedChains: [Ethereum]
28339
28658
  * }
28340
28659
  *
@@ -28732,7 +29051,7 @@ const abiParameterSchema = z.object({
28732
29051
  * const result = evmPreparedChainRequestParamsSchema.safeParse(params)
28733
29052
  * ```
28734
29053
  */ z.object({
28735
- type: z.literal('evm'),
29054
+ type: z.literal('evm').optional(),
28736
29055
  abi: abiSchema,
28737
29056
  address: evmAddressSchema$1,
28738
29057
  functionName: z.string({
@@ -28849,7 +29168,7 @@ const abiParameterSchema = z.object({
28849
29168
  message: 'Private key must be a valid 64-character hex string. Please provide a valid private key with or without "0x" prefix.'
28850
29169
  }));
28851
29170
 
28852
- const hexBytesSchema$1 = z.string().regex(/^0x([0-9a-fA-F]{2})*$/, {
29171
+ const hexBytesSchema$2 = z.string().regex(/^0x([0-9a-fA-F]{2})*$/, {
28853
29172
  message: 'value must be a 0x-prefixed even-length hex string'
28854
29173
  }).transform((value)=>value);
28855
29174
  z.object({
@@ -28861,6 +29180,53 @@ z.object({
28861
29180
  amount: z.bigint().refine((value)=>value >= 0n, {
28862
29181
  message: 'amount must be a non-negative bigint'
28863
29182
  }),
29183
+ permitCalldata: hexBytesSchema$2
29184
+ }))
29185
+ }).passthrough();
29186
+
29187
+ const hexBytesSchema$1 = z.string().regex(/^0x([0-9a-fA-F]{2})*$/, {
29188
+ message: 'value must be a 0x-prefixed even-length hex string'
29189
+ }).transform((value)=>value);
29190
+ function isNonNegativeBigIntLike$2(value) {
29191
+ try {
29192
+ return BigInt(value) >= 0n;
29193
+ } catch {
29194
+ return false;
29195
+ }
29196
+ }
29197
+ const uint256LikeSchema$2 = z.union([
29198
+ z.string(),
29199
+ z.bigint()
29200
+ ]).refine(isNonNegativeBigIntLike$2, {
29201
+ message: 'value must be a non-negative bigint-compatible string or bigint'
29202
+ });
29203
+ const borrowExecutionParamsSchema$1 = z.object({
29204
+ instructions: z.array(z.object({
29205
+ target: evmAddressSchema$1,
29206
+ data: hexBytesSchema$1,
29207
+ value: uint256LikeSchema$2,
29208
+ tokenIn: evmAddressSchema$1,
29209
+ amountToApprove: uint256LikeSchema$2,
29210
+ tokenOut: evmAddressSchema$1,
29211
+ minTokenOut: uint256LikeSchema$2
29212
+ }).passthrough()).min(1),
29213
+ tokens: z.array(z.object({
29214
+ token: evmAddressSchema$1,
29215
+ beneficiary: evmAddressSchema$1
29216
+ }).passthrough()),
29217
+ execId: uint256LikeSchema$2,
29218
+ deadline: uint256LikeSchema$2,
29219
+ metadata: hexBytesSchema$1
29220
+ }).passthrough();
29221
+ z.object({
29222
+ executeParams: borrowExecutionParamsSchema$1,
29223
+ signature: evmSignatureSchema,
29224
+ tokenInputs: z.array(z.object({
29225
+ permitType: z.nativeEnum(BorrowPermitType),
29226
+ token: evmAddressSchema$1,
29227
+ amount: z.bigint().refine((value)=>value >= 0n, {
29228
+ message: 'amount must be a non-negative bigint'
29229
+ }),
28864
29230
  permitCalldata: hexBytesSchema$1
28865
29231
  }))
28866
29232
  }).passthrough();
@@ -29253,7 +29619,7 @@ const optionalSwapChainIdentifierField = swapChainIdentifierField.optional();
29253
29619
  * Schema for validating AdapterContext.
29254
29620
  * Must always contain both adapter and chain explicitly.
29255
29621
  * Optionally includes address for developer-controlled adapters.
29256
- */ const adapterContextSchema$1 = z.object({
29622
+ */ const adapterContextSchema$2 = z.object({
29257
29623
  adapter: adapterSchema,
29258
29624
  chain: swapChainIdentifierField,
29259
29625
  address: z.string().optional()
@@ -29314,7 +29680,7 @@ const swapDestinationSchema = z.object({
29314
29680
  message: 'recipientAddress must be a valid blockchain address: EVM (0x + 40 hex chars) or Solana (base58, 32-44 chars)'
29315
29681
  }).optional()
29316
29682
  }).strict();
29317
- const EVM_ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/;
29683
+ const EVM_ADDRESS_REGEX$1 = /^0x[a-fA-F0-9]{40}$/;
29318
29684
  const SOLANA_ADDRESS_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
29319
29685
  const BASE58_CHARS_REGEX = /^[1-9A-HJ-NP-Za-km-z]+$/;
29320
29686
  /**
@@ -29357,7 +29723,7 @@ const MAX_DISPLAY_LENGTH = 30;
29357
29723
  */ let _symbolResult;
29358
29724
  const swapTokenSchema = z.string().superRefine((value, ctx)=>{
29359
29725
  if (value.startsWith('0x')) {
29360
- if (!EVM_ADDRESS_REGEX.test(value)) {
29726
+ if (!EVM_ADDRESS_REGEX$1.test(value)) {
29361
29727
  ctx.addIssue({
29362
29728
  code: z.ZodIssueCode.custom,
29363
29729
  message: `Invalid EVM token address format. Expected '0x' followed by 40 hexadecimal characters, but received: '${truncate(value)}'`
@@ -29452,7 +29818,7 @@ const amountInSchema = z.string().min(1, 'Required').pipe(createDecimalStringVal
29452
29818
  * }
29453
29819
  * ```
29454
29820
  */ z.object({
29455
- from: adapterContextSchema$1,
29821
+ from: adapterContextSchema$2,
29456
29822
  tokenIn: swapTokenSchema,
29457
29823
  tokenOut: swapTokenSchema,
29458
29824
  amountIn: amountInSchema,
@@ -29493,16 +29859,16 @@ new Set(Object.values(Blockchain));
29493
29859
 
29494
29860
  new Set(Object.values(Blockchain));
29495
29861
 
29496
- /** SDK name used in telemetry payloads. */ resolveKitSdkName(pkg$1.name);
29862
+ /** SDK name used in telemetry payloads. */ resolveKitSdkName(pkg$2.name);
29497
29863
 
29498
29864
  // Auto-register this kit for user agent tracking
29499
- registerKit(`${pkg$1.name}/${pkg$1.version}`);
29865
+ registerKit(`${pkg$2.name}/${pkg$2.version}`);
29500
29866
 
29501
- var name = "@circle-fin/earn-kit";
29502
- var version = "1.7.0";
29503
- var pkg = {
29504
- name: name,
29505
- version: version};
29867
+ var name$1 = "@circle-fin/earn-kit";
29868
+ var version$1 = "1.8.1";
29869
+ var pkg$1 = {
29870
+ name: name$1,
29871
+ version: version$1};
29506
29872
 
29507
29873
  /**
29508
29874
  * Map SDK chain identifiers to bridge API chain strings.
@@ -29574,7 +29940,7 @@ function isBigIntLike(value) {
29574
29940
  return false;
29575
29941
  }
29576
29942
  }
29577
- function isNonNegativeBigIntLike(value) {
29943
+ function isNonNegativeBigIntLike$1(value) {
29578
29944
  try {
29579
29945
  return BigInt(value) >= 0n;
29580
29946
  } catch {
@@ -29594,28 +29960,22 @@ const bridgeFeeTokenSchema = hexAddressSchema;
29594
29960
  * unchanged so signed execution params can be forwarded verbatim.
29595
29961
  *
29596
29962
  * @internal
29597
- */ const uint256LikeSchema = z.union([
29963
+ */ const uint256LikeSchema$1 = z.union([
29598
29964
  z.string(),
29599
29965
  z.bigint()
29600
- ]).refine(isNonNegativeBigIntLike, {
29966
+ ]).refine(isNonNegativeBigIntLike$1, {
29601
29967
  message: 'value must be a non-negative bigint-compatible string or bigint'
29602
29968
  });
29603
29969
  /**
29604
29970
  * Zod schema for typed amount objects emitted by the API.
29605
29971
  *
29606
29972
  * @internal
29607
- */ const amountJsonSchema = z.object({
29973
+ */ const amountJsonSchema$1 = z.object({
29608
29974
  raw: z.string().refine(isBigIntLike, {
29609
29975
  message: 'raw must be a bigint-compatible string'
29610
29976
  }),
29611
29977
  decimals: z.number().int().nonnegative()
29612
29978
  });
29613
- /** @internal */ const hexBytesSchema = z.union([
29614
- hexStringSchema,
29615
- z.literal('0x')
29616
- ]).refine((value)=>value.length % 2 === 0, {
29617
- message: 'value must be a 0x-prefixed even-length hex string'
29618
- });
29619
29979
  /** @internal */ const bytes32HexSchema = hexStringSchema.refine((value)=>value.length === BYTES32_HEX_LENGTH, {
29620
29980
  message: 'value must be a 0x-prefixed 32-byte hex string'
29621
29981
  });
@@ -29641,10 +30001,8 @@ const bridgeFeeTokenSchema = hexAddressSchema;
29641
30001
  assetAddress: z.string(),
29642
30002
  lltv: z.number(),
29643
30003
  supplyUsd: z.number(),
29644
- // Optional during the expand/contract window (a backend that predates the
29645
- // field omits the key), mirroring the `.optional()` facets on the base
29646
- // schema; `null` when the product exposes no per-market allocation (V2).
29647
- allocationPct: z.number().nullable().optional()
30004
+ // `null` when the product exposes no per-market allocation (V2).
30005
+ allocationPct: z.number().nullable()
29648
30006
  });
29649
30007
  /**
29650
30008
  * Zod schema for a Morpho vault warning in the API response.
@@ -29701,9 +30059,9 @@ const bridgeFeeTokenSchema = hexAddressSchema;
29701
30059
  *
29702
30060
  * @internal
29703
30061
  */ const liquidityProfileSchema = z.object({
29704
- totalDeposits: amountJsonSchema,
29705
- available: amountJsonSchema,
29706
- totalSupply: amountJsonSchema,
30062
+ totalDeposits: amountJsonSchema$1,
30063
+ available: amountJsonSchema$1,
30064
+ totalSupply: amountJsonSchema$1,
29707
30065
  status: z.enum([
29708
30066
  'active',
29709
30067
  'low_liquidity'
@@ -29740,8 +30098,8 @@ const bridgeFeeTokenSchema = hexAddressSchema;
29740
30098
  vaultFee: z.number(),
29741
30099
  rewards: z.array(vaultRewardSchema),
29742
30100
  collateral: z.array(collateralSchema),
29743
- totalDeposits: amountJsonSchema,
29744
- liquidity: amountJsonSchema,
30101
+ totalDeposits: amountJsonSchema$1,
30102
+ liquidity: amountJsonSchema$1,
29745
30103
  status: z.enum([
29746
30104
  'active',
29747
30105
  'low_liquidity'
@@ -29751,19 +30109,20 @@ const bridgeFeeTokenSchema = hexAddressSchema;
29751
30109
  earnKitWarnings: z.array(z.string()).optional()
29752
30110
  });
29753
30111
  /**
29754
- * Shared base schema: existing flat fields (kept) plus the new nested
29755
- * facets and neutral identity. Facets are `.optional()` during the
29756
- * transition; flip to required once the backend is confirmed emitting.
30112
+ * Shared base schema: existing flat fields (kept as deprecated aliases) plus
30113
+ * the nested facets. Zenith emits all facets on every response; required here
30114
+ * so a partial emission is caught at parse time rather than surfacing as a
30115
+ * runtime `undefined` access.
29757
30116
  *
29758
30117
  * @internal
29759
30118
  */ const earnBaseSchema = vaultInfoResponseSchema.extend({
29760
- address: z.string().optional(),
29761
- asOf: z.string().optional(),
29762
- manager: managerSchema.nullable().optional(),
29763
- apyProfile: apyProfileSchema.optional(),
29764
- fee: feeInfoSchema.optional(),
29765
- liquidityProfile: liquidityProfileSchema.optional(),
29766
- riskSignals: riskSignalsSchema.optional()
30119
+ address: z.string(),
30120
+ asOf: z.string(),
30121
+ manager: managerSchema.nullable(),
30122
+ apyProfile: apyProfileSchema,
30123
+ fee: feeInfoSchema,
30124
+ liquidityProfile: liquidityProfileSchema,
30125
+ riskSignals: riskSignalsSchema
29767
30126
  });
29768
30127
  /**
29769
30128
  * Zod schema for the `vault` opportunity variant.
@@ -29850,13 +30209,13 @@ const bridgeFeeTokenSchema = hexAddressSchema;
29850
30209
  */ const accruedRewardSchema = z.object({
29851
30210
  token: z.string(),
29852
30211
  symbol: z.string(),
29853
- amount: amountJsonSchema
30212
+ amount: amountJsonSchema$1
29854
30213
  });
29855
30214
  const positionPnlSchema = z.discriminatedUnion('status', [
29856
30215
  z.object({
29857
30216
  status: z.literal('available'),
29858
- principalDeposited: amountJsonSchema,
29859
- totalYieldEarned: amountJsonSchema
30217
+ principalDeposited: amountJsonSchema$1,
30218
+ totalYieldEarned: amountJsonSchema$1
29860
30219
  }),
29861
30220
  z.object({
29862
30221
  status: z.literal('pending')
@@ -29876,9 +30235,9 @@ const positionPnlSchema = z.discriminatedUnion('status', [
29876
30235
  vaultAddress: z.string(),
29877
30236
  vaultName: z.string(),
29878
30237
  asset: z.string(),
29879
- currentBalance: amountJsonSchema,
30238
+ currentBalance: amountJsonSchema$1,
29880
30239
  currentApy: z.number(),
29881
- shares: amountJsonSchema,
30240
+ shares: amountJsonSchema$1,
29882
30241
  pnl: positionPnlSchema,
29883
30242
  accruedRewards: z.array(accruedRewardSchema).optional(),
29884
30243
  rewardsUnavailableReason: z.string().optional()
@@ -29906,7 +30265,7 @@ const positionPnlSchema = z.discriminatedUnion('status', [
29906
30265
  * @internal
29907
30266
  */ const earnInstructionSchema = z.object({
29908
30267
  tokenIn: hexAddressSchema,
29909
- amountToApprove: uint256LikeSchema
30268
+ amountToApprove: uint256LikeSchema$1
29910
30269
  }).passthrough();
29911
30270
  /**
29912
30271
  * Zod schema for earn execution params returned by the earn service.
@@ -29920,50 +30279,10 @@ const positionPnlSchema = z.discriminatedUnion('status', [
29920
30279
  instructions: z.tuple([
29921
30280
  earnInstructionSchema
29922
30281
  ]).rest(earnInstructionSchema),
29923
- deadline: uint256LikeSchema
30282
+ deadline: uint256LikeSchema$1
29924
30283
  }).passthrough();
29925
30284
  /** @internal */ const depositExecutionParamsSchema = earnExecutionParamsSchema;
29926
30285
  /** @internal */ const withdrawExecutionParamsSchema = earnExecutionParamsSchema;
29927
- /**
29928
- * Zod schema for the claim rewards instruction fields that must be safe to
29929
- * ABI-encode.
29930
- *
29931
- * Claim rewards has no approval preflight, so this validates the forwarded
29932
- * signed payload at the provider boundary. Additional instruction fields are
29933
- * accepted and preserved.
29934
- *
29935
- * @internal
29936
- */ const claimRewardsInstructionSchema = z.object({
29937
- target: hexAddressSchema,
29938
- data: hexBytesSchema,
29939
- value: uint256LikeSchema,
29940
- tokenIn: hexAddressSchema,
29941
- amountToApprove: uint256LikeSchema,
29942
- tokenOut: hexAddressSchema,
29943
- minTokenOut: uint256LikeSchema
29944
- }).passthrough();
29945
- /** @internal */ const claimRewardsTokenSchema = z.object({
29946
- token: hexAddressSchema,
29947
- beneficiary: hexAddressSchema
29948
- }).passthrough();
29949
- /**
29950
- * Zod schema for signed claim rewards execution params.
29951
- *
29952
- * This enforces the required envelope and preserves additive fields so the
29953
- * adapter receives the signed params verbatim.
29954
- *
29955
- * @internal
29956
- */ const claimRewardsExecutionParamsSchema = z.object({
29957
- instructions: z.tuple([
29958
- claimRewardsInstructionSchema
29959
- ]).rest(claimRewardsInstructionSchema),
29960
- tokens: z.tuple([
29961
- claimRewardsTokenSchema
29962
- ]).rest(claimRewardsTokenSchema),
29963
- execId: uint256LikeSchema,
29964
- deadline: uint256LikeSchema,
29965
- metadata: hexBytesSchema
29966
- }).passthrough();
29967
30286
  /**
29968
30287
  * Zod schema for the deposit payload inside the API `data` envelope.
29969
30288
  *
@@ -30022,9 +30341,9 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
30022
30341
  message: z.object({
30023
30342
  from: hexAddressSchema,
30024
30343
  to: hexAddressSchema,
30025
- value: uint256LikeSchema,
30026
- validAfter: uint256LikeSchema,
30027
- validBefore: uint256LikeSchema,
30344
+ value: uint256LikeSchema$1,
30345
+ validAfter: uint256LikeSchema$1,
30346
+ validBefore: uint256LikeSchema$1,
30028
30347
  nonce: bytes32HexSchema
30029
30348
  }).passthrough()
30030
30349
  }).passthrough();
@@ -30042,7 +30361,7 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
30042
30361
  feeToken: bridgeFeeTokenSchema,
30043
30362
  items: z.array(z.object({
30044
30363
  type: z.string(),
30045
- amount: uint256LikeSchema
30364
+ amount: uint256LikeSchema$1
30046
30365
  }).passthrough())
30047
30366
  }).passthrough();
30048
30367
  /**
@@ -30058,7 +30377,7 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
30058
30377
  const bridgeDepositPrepareReviewSchema = z.object({
30059
30378
  sourceChain: z.string(),
30060
30379
  destinationChain: z.string(),
30061
- amount: amountJsonSchema,
30380
+ amount: amountJsonSchema$1,
30062
30381
  vaultAddress: hexAddressSchema
30063
30382
  }).passthrough();
30064
30383
  /** @internal */ const bridgeQuoteExpirySchema = z.discriminatedUnion('mode', [
@@ -30193,44 +30512,6 @@ const bridgeDepositPrepareReviewSchema = z.object({
30193
30512
  // ---------------------------------------------------------------------------
30194
30513
  // Claim rewards response schema
30195
30514
  // ---------------------------------------------------------------------------
30196
- /**
30197
- * Zod schema for a claimed reward amount in the API response.
30198
- *
30199
- * @internal
30200
- */ const claimedAmountSchema = z.object({
30201
- token: hexAddressSchema,
30202
- symbol: z.string(),
30203
- amount: amountJsonSchema
30204
- });
30205
- /**
30206
- * Zod schema for the claim rewards payload inside the API `data` envelope.
30207
- *
30208
- * Enforce that `executionParams` and `signature` are either both
30209
- * present (claimable rewards) or both absent (nothing to claim).
30210
- *
30211
- * @internal
30212
- */ const claimRewardsPayloadSchema = z.object({
30213
- rewards: z.array(claimedAmountSchema),
30214
- executionParams: claimRewardsExecutionParamsSchema.optional(),
30215
- signature: hexSignatureSchema.optional()
30216
- }).refine((data)=>{
30217
- const signedFieldCount = (data.executionParams === undefined ? 0 : 1) + (data.signature === undefined ? 0 : 1);
30218
- if (data.rewards.length > 0) {
30219
- return signedFieldCount === 2;
30220
- }
30221
- return signedFieldCount === 0;
30222
- }, {
30223
- message: 'claim rewards response must include executionParams and signature only when rewards are claimable'
30224
- });
30225
- /**
30226
- * Zod schema for the `POST /v1/earnKit/claimRewards` API response.
30227
- *
30228
- * The Earn Service API wraps the claim rewards payload in a `data` envelope.
30229
- *
30230
- * @internal
30231
- */ z.object({
30232
- data: claimRewardsPayloadSchema
30233
- });
30234
30515
  // ---------------------------------------------------------------------------
30235
30516
  // Deposit quote response schema
30236
30517
  // ---------------------------------------------------------------------------
@@ -30249,7 +30530,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
30249
30530
  type: z.string().optional(),
30250
30531
  status: z.string().optional(),
30251
30532
  token: z.string(),
30252
- amount: amountJsonSchema
30533
+ amount: amountJsonSchema$1
30253
30534
  });
30254
30535
  /**
30255
30536
  * Zod schema for a native gas-fee entry in an EarnKit quote response.
@@ -30286,8 +30567,8 @@ const bridgeDepositPrepareReviewSchema = z.object({
30286
30567
  vaultAddress: z.string(),
30287
30568
  vaultName: z.string(),
30288
30569
  asset: z.string(),
30289
- depositAmount: amountJsonSchema,
30290
- expectedShares: amountJsonSchema,
30570
+ depositAmount: amountJsonSchema$1,
30571
+ expectedShares: amountJsonSchema$1,
30291
30572
  sharePrice: z.string(),
30292
30573
  currentApy: z.number(),
30293
30574
  fees: z.array(feeSchema).optional(),
@@ -30313,10 +30594,10 @@ const bridgeDepositPrepareReviewSchema = z.object({
30313
30594
  vaultAddress: z.string(),
30314
30595
  vaultName: z.string(),
30315
30596
  asset: z.string(),
30316
- withdrawAmount: amountJsonSchema,
30317
- sharesToRedeem: amountJsonSchema,
30597
+ withdrawAmount: amountJsonSchema$1,
30598
+ sharesToRedeem: amountJsonSchema$1,
30318
30599
  sharePrice: z.string(),
30319
- maxWithdrawable: amountJsonSchema,
30600
+ maxWithdrawable: amountJsonSchema$1,
30320
30601
  fees: z.array(feeSchema),
30321
30602
  gasFees: z.array(quoteGasFeeSchema).optional(),
30322
30603
  warnings: z.array(z.string()).optional()
@@ -30333,31 +30614,6 @@ const bridgeDepositPrepareReviewSchema = z.object({
30333
30614
  // ---------------------------------------------------------------------------
30334
30615
  // Claim rewards quote response schema
30335
30616
  // ---------------------------------------------------------------------------
30336
- /**
30337
- * Zod schema for a reward in the claim rewards quote response.
30338
- *
30339
- * @internal
30340
- */ const claimRewardsQuoteRewardSchema = z.object({
30341
- token: z.string(),
30342
- symbol: z.string(),
30343
- amount: amountJsonSchema
30344
- });
30345
- /**
30346
- * Zod schema for the inner claim rewards quote payload.
30347
- *
30348
- * @internal
30349
- */ const claimRewardsQuotePayloadSchema = z.object({
30350
- rewards: z.array(claimRewardsQuoteRewardSchema)
30351
- });
30352
- /**
30353
- * Zod schema for the `POST /v1/earnKit/claimRewards/quote` API response.
30354
- *
30355
- * The API wraps the payload in a `data` envelope.
30356
- *
30357
- * @internal
30358
- */ z.object({
30359
- data: claimRewardsQuotePayloadSchema
30360
- });
30361
30617
  // ---------------------------------------------------------------------------
30362
30618
  // Batch vault response schema
30363
30619
  // ---------------------------------------------------------------------------
@@ -30497,7 +30753,7 @@ createTokenRegistry();
30497
30753
  * fast instead of being silently stripped.
30498
30754
  *
30499
30755
  * @internal
30500
- */ const adapterContextSchema = z.object({
30756
+ */ const adapterContextSchema$1 = z.object({
30501
30757
  adapter: adapterSchema,
30502
30758
  // AdapterContext accepts a wider chain field, but runtime validation must
30503
30759
  // stay constrained to EarnChain identifiers.
@@ -30729,10 +30985,53 @@ const sourceAdapterContextSchema = z.object({
30729
30985
  * })
30730
30986
  * ```
30731
30987
  */ z.object({
30732
- from: adapterContextSchema,
30988
+ from: adapterContextSchema$1,
30733
30989
  vaultAddress: vaultAddressSchema,
30734
30990
  config: earnConfigSchema.optional()
30735
30991
  });
30992
+ /**
30993
+ * Schema for a successful gas fee entry (fees is non-null).
30994
+ *
30995
+ * Validates the kit shape — {@link EarnEstimatedGas} uses decimal strings for
30996
+ * `gas`, `gasPrice`, and `fee`. Only digits are accepted so that the deposit
30997
+ * operation can safely convert them to `bigint` before passing them to the
30998
+ * provider's `computeGasReserve`.
30999
+ *
31000
+ * @internal
31001
+ */ const earnGasFeeEstimateSuccessSchema = z.object({
31002
+ name: z.string(),
31003
+ token: z.string(),
31004
+ blockchain: z.string(),
31005
+ fees: z.object({
31006
+ gas: z.string().regex(/^\d+$/, 'gas must be a non-negative integer string'),
31007
+ gasPrice: z.string().regex(/^\d+$/, 'gasPrice must be a non-negative integer string'),
31008
+ fee: z.string().regex(/^\d+$/, 'fee must be a non-negative integer string')
31009
+ }),
31010
+ error: z.undefined().optional()
31011
+ }).strict();
31012
+ /**
31013
+ * Schema for a failed gas fee entry (fees is null, error is a string).
31014
+ *
31015
+ * @internal
31016
+ */ const earnGasFeeEstimateFailureSchema = z.object({
31017
+ name: z.string(),
31018
+ token: z.string(),
31019
+ blockchain: z.string(),
31020
+ fees: z.null(),
31021
+ error: z.string()
31022
+ }).strict();
31023
+ /**
31024
+ * Schema for a single kit-level gas fee estimate entry.
31025
+ *
31026
+ * Rejects arbitrary inputs (null, numbers, empty objects, non-numeric fee
31027
+ * strings) so callers receive a descriptive validation error instead of a
31028
+ * raw `BigInt` conversion error inside `computeGasReserve`.
31029
+ *
31030
+ * @internal
31031
+ */ const earnGasFeeEstimateSchema = z.union([
31032
+ earnGasFeeEstimateSuccessSchema,
31033
+ earnGasFeeEstimateFailureSchema
31034
+ ]);
30736
31035
  /**
30737
31036
  * Validation schema for the same-chain variant of DepositParams.
30738
31037
  *
@@ -30741,10 +31040,11 @@ const sourceAdapterContextSchema = z.object({
30741
31040
  *
30742
31041
  * @internal Exported for branch-targeted validation in the deposit operation.
30743
31042
  */ const sameChainDepositParamsSchema = z.object({
30744
- from: adapterContextSchema,
31043
+ from: adapterContextSchema$1,
30745
31044
  to: z.undefined().optional(),
30746
31045
  vaultAddress: vaultAddressSchema,
30747
31046
  amount: amountSchema,
31047
+ gasFees: z.array(earnGasFeeEstimateSchema).optional(),
30748
31048
  config: earnConfigSchema.optional()
30749
31049
  }).strict();
30750
31050
  const crossChainDepositDestinationSchema = z.object({
@@ -30811,7 +31111,7 @@ const crossChainDepositDestinationSchema = z.object({
30811
31111
  * })
30812
31112
  * ```
30813
31113
  */ z.object({
30814
- from: adapterContextSchema,
31114
+ from: adapterContextSchema$1,
30815
31115
  vaultAddress: vaultAddressSchema,
30816
31116
  amount: amountSchema,
30817
31117
  config: earnConfigSchema.optional()
@@ -30865,7 +31165,7 @@ const crossChainDepositDestinationSchema = z.object({
30865
31165
  * })
30866
31166
  * ```
30867
31167
  */ z.object({
30868
- from: adapterContextSchema,
31168
+ from: adapterContextSchema$1,
30869
31169
  vaultAddress: vaultAddressSchema,
30870
31170
  amount: amountSchema,
30871
31171
  config: earnConfigSchema.optional()
@@ -30885,12 +31185,12 @@ const crossChainDepositDestinationSchema = z.object({
30885
31185
  *
30886
31186
  * @internal
30887
31187
  */ z.object({
30888
- from: adapterContextSchema,
31188
+ from: adapterContextSchema$1,
30889
31189
  vaultAddress: vaultAddressSchema,
30890
31190
  config: earnConfigSchema.optional()
30891
31191
  });
30892
31192
  const sameChainGetDepositQuoteParamsSchema = z.object({
30893
- from: adapterContextSchema,
31193
+ from: adapterContextSchema$1,
30894
31194
  vaultAddress: vaultAddressSchema,
30895
31195
  amount: amountSchema,
30896
31196
  config: earnConfigSchema.optional()
@@ -30974,7 +31274,7 @@ function hasCrossChainDepositQuoteShape(params) {
30974
31274
  * })
30975
31275
  * ```
30976
31276
  */ z.object({
30977
- from: adapterContextSchema,
31277
+ from: adapterContextSchema$1,
30978
31278
  vaultAddress: vaultAddressSchema,
30979
31279
  amount: amountSchema,
30980
31280
  config: earnConfigSchema.optional()
@@ -30994,11 +31294,1363 @@ function hasCrossChainDepositQuoteShape(params) {
30994
31294
  *
30995
31295
  * @internal
30996
31296
  */ z.object({
30997
- from: adapterContextSchema,
31297
+ from: adapterContextSchema$1,
30998
31298
  vaultAddress: vaultAddressSchema,
30999
31299
  config: earnConfigSchema.optional()
31000
31300
  });
31001
31301
 
31302
+ /** SDK name used in telemetry payloads. */ resolveKitSdkName(pkg$1.name);
31303
+
31304
+ // Auto-register this kit for user agent tracking
31305
+ registerKit(`${pkg$1.name}/${pkg$1.version}`);
31306
+
31307
+ var name = "@circle-fin/borrow-kit";
31308
+ var version = "1.0.0";
31309
+ var pkg = {
31310
+ name: name,
31311
+ version: version};
31312
+
31313
+ const HUMAN_READABLE_AMOUNT_REGEX$1 = /^(?:0|[1-9]\d*)(?:\.\d+)?$/;
31314
+ const EVM_ADDRESS_REGEX = /^0x[0-9a-fA-F]{40}$/;
31315
+ const POSITIVE_USDC_AMOUNT_REGEX = /^(?:0|[1-9]\d*)(?:\.\d{1,6})?$/;
31316
+ /**
31317
+ * True when `value` parses as a URL whose scheme is exactly `https:`.
31318
+ *
31319
+ * Uses the WHATWG `URL` parser rather than `startsWith('https://')` so the
31320
+ * check is scheme-normalized (case-insensitive, e.g. `HTTPS://...` still
31321
+ * passes) instead of a literal prefix match. `value` has already passed
31322
+ * `z.string().url()` by the time this runs, but a caller could still supply
31323
+ * a string that `URL` itself rejects, so the parse is guarded.
31324
+ */ function isHttpsUrl$1(value) {
31325
+ try {
31326
+ return new URL(value).protocol === 'https:';
31327
+ } catch {
31328
+ return false;
31329
+ }
31330
+ }
31331
+ const borrowServiceConfigSchema$1 = z.object({
31332
+ apiKey: z.string().optional(),
31333
+ baseUrl: z.string().url().optional()
31334
+ }).strict();
31335
+ /** Loan asset amounts are USDC, so they carry at most 6 decimal places. */ function positiveLoanAssetAmountSchema(field) {
31336
+ return z.string().regex(POSITIVE_USDC_AMOUNT_REGEX, `${field} must be a canonical decimal with at most 6 decimal places`).refine((value)=>/[1-9]/.test(value), {
31337
+ message: `${field} must be greater than zero`
31338
+ });
31339
+ }
31340
+ /**
31341
+ * Collateral amounts denominate an arbitrary token, so the decimal count is the
31342
+ * token's rather than USDC's — a satoshi-precision collateral is valid.
31343
+ */ function positiveCollateralAmountSchema(field) {
31344
+ return z.string().regex(HUMAN_READABLE_AMOUNT_REGEX$1, `${field} must be a canonical decimal`).refine((value)=>/[1-9]/.test(value), {
31345
+ message: `${field} must be greater than zero`
31346
+ });
31347
+ }
31348
+ /** @internal */ z.object({
31349
+ chain: chainIdentifierSchema,
31350
+ marketId: z.string().min(1),
31351
+ config: borrowServiceConfigSchema$1.optional()
31352
+ }).strict();
31353
+ /** @internal */ z.object({
31354
+ walletAddress: z.string().regex(EVM_ADDRESS_REGEX),
31355
+ chain: chainIdentifierSchema,
31356
+ pageSize: z.number().int().positive().optional(),
31357
+ pageAfter: z.string().min(1).optional(),
31358
+ config: borrowServiceConfigSchema$1.optional()
31359
+ }).strict();
31360
+ /** @internal */ const marketSortBySchema$1 = z.enum([
31361
+ 'lltv',
31362
+ 'borrowApy'
31363
+ ]);
31364
+ /** @internal */ const decimalFilterSchema$1 = z.string().regex(/^\d+(\.\d+)?$/, 'filter thresholds must be non-negative decimal strings');
31365
+ /**
31366
+ * Provider-level runtime schema for {@link ExploreMarketsServiceParams}.
31367
+ *
31368
+ * Mirrors the kit's `exploreMarketsParamsSchema` at the provider boundary so a
31369
+ * plain-JS caller invoking `BorrowServiceProvider.exploreMarkets` directly is
31370
+ * still validated before any filter reaches `url.searchParams` — including the
31371
+ * kit's `minLltv <= maxLltv` / `minBorrow <= maxBorrow` range check, which
31372
+ * otherwise lets an inverted range serialize into the request and return a
31373
+ * silently empty page.
31374
+ *
31375
+ * @internal
31376
+ */ z.object({
31377
+ chain: chainIdentifierSchema,
31378
+ minLltv: decimalFilterSchema$1.optional(),
31379
+ maxLltv: decimalFilterSchema$1.optional(),
31380
+ minBorrow: decimalFilterSchema$1.optional(),
31381
+ maxBorrow: decimalFilterSchema$1.optional(),
31382
+ sortBy: marketSortBySchema$1.optional(),
31383
+ pageSize: z.number().int().min(1).max(1000).optional(),
31384
+ pageAfter: z.string().min(1).optional(),
31385
+ config: borrowServiceConfigSchema$1.optional()
31386
+ }).strict().superRefine((value, ctx)=>{
31387
+ if (value.minLltv !== undefined && value.maxLltv !== undefined && Number(value.minLltv) > Number(value.maxLltv)) {
31388
+ ctx.addIssue({
31389
+ code: z.ZodIssueCode.custom,
31390
+ path: [
31391
+ 'maxLltv'
31392
+ ],
31393
+ message: 'maxLltv must be greater than or equal to minLltv'
31394
+ });
31395
+ }
31396
+ if (value.minBorrow !== undefined && value.maxBorrow !== undefined && Number(value.minBorrow) > Number(value.maxBorrow)) {
31397
+ ctx.addIssue({
31398
+ code: z.ZodIssueCode.custom,
31399
+ path: [
31400
+ 'maxBorrow'
31401
+ ],
31402
+ message: 'maxBorrow must be greater than or equal to minBorrow'
31403
+ });
31404
+ }
31405
+ });
31406
+ /** @internal */ const repayQuoteServiceParamsSchema = z.object({
31407
+ loanId: z.string().uuid(),
31408
+ chain: chainIdentifierSchema,
31409
+ repayAmount: positiveLoanAssetAmountSchema('repayAmount'),
31410
+ config: borrowServiceConfigSchema$1.optional()
31411
+ }).strict();
31412
+ /** @internal */ repayQuoteServiceParamsSchema.omit({
31413
+ chain: true
31414
+ }).extend({
31415
+ idempotencyKey: z.string().uuid().optional()
31416
+ });
31417
+ /** @internal */ const closeLoanQuoteServiceParamsSchema = z.object({
31418
+ loanId: z.string().uuid(),
31419
+ chain: chainIdentifierSchema,
31420
+ slippageBps: z.number().int().min(0).max(10_000).optional(),
31421
+ config: borrowServiceConfigSchema$1.optional()
31422
+ }).strict();
31423
+ /** Fields a borrow carries whichever way it names its position. @internal */ const borrowServiceParamsBaseShape = {
31424
+ loanAssetAmount: positiveLoanAssetAmountSchema('loanAssetAmount'),
31425
+ slippageBps: z.number().int().min(0).max(10_000).optional(),
31426
+ idempotencyKey: z.string().uuid().optional(),
31427
+ config: borrowServiceConfigSchema$1.optional()
31428
+ };
31429
+ /** A first-open: owner, chain and market are required together. @internal */ const openLoanServiceParamsSchema = z.object({
31430
+ ...borrowServiceParamsBaseShape,
31431
+ walletAddress: z.string().regex(EVM_ADDRESS_REGEX),
31432
+ chain: chainIdentifierSchema,
31433
+ marketId: z.string().min(1)
31434
+ }).strict();
31435
+ /** A borrow-more: the loan is the only addressing field. @internal */ const borrowMoreServiceParamsSchema = z.object({
31436
+ ...borrowServiceParamsBaseShape,
31437
+ loanId: z.string().uuid()
31438
+ }).strict();
31439
+ /**
31440
+ * The two ways a borrow names its position.
31441
+ *
31442
+ * A union of strict objects rather than one object with a refinement:
31443
+ * `.strict()` is what rejects a mixed body, and the service refuses `loanId`
31444
+ * next to any open-tuple field as well as an incomplete open tuple.
31445
+ *
31446
+ * @internal
31447
+ */ z.union([
31448
+ openLoanServiceParamsSchema,
31449
+ borrowMoreServiceParamsSchema
31450
+ ]);
31451
+ /** A first-open quote carries the complete owner/chain/market tuple. @internal */ const openLoanQuoteServiceParamsSchema = z.object({
31452
+ walletAddress: z.string().regex(EVM_ADDRESS_REGEX),
31453
+ chain: chainIdentifierSchema,
31454
+ marketId: z.string().min(1),
31455
+ loanAssetAmount: positiveLoanAssetAmountSchema('loanAssetAmount'),
31456
+ slippageBps: z.number().int().min(0).max(10_000).optional(),
31457
+ config: borrowServiceConfigSchema$1.optional()
31458
+ }).strict();
31459
+ /** A borrow-more quote needs only the existing loan ID. @internal */ const borrowMoreQuoteServiceParamsSchema = z.object({
31460
+ loanId: z.string().uuid(),
31461
+ loanAssetAmount: positiveLoanAssetAmountSchema('loanAssetAmount'),
31462
+ slippageBps: z.number().int().min(0).max(10_000).optional(),
31463
+ config: borrowServiceConfigSchema$1.optional()
31464
+ }).strict();
31465
+ /** @internal */ z.union([
31466
+ openLoanQuoteServiceParamsSchema,
31467
+ borrowMoreQuoteServiceParamsSchema
31468
+ ]);
31469
+ /** @internal */ z.object({
31470
+ chain: chainIdentifierSchema,
31471
+ marketId: z.string().min(1),
31472
+ loanAssetAmount: positiveLoanAssetAmountSchema('loanAssetAmount'),
31473
+ // `.finite()` is load-bearing, not decoration: the value is encoded as a
31474
+ // decimal string on the wire, and there is no decimal string for Infinity.
31475
+ targetHealthFactor: z.number().positive().finite(),
31476
+ config: borrowServiceConfigSchema$1.optional()
31477
+ }).strict();
31478
+ /** @internal */ z.object({
31479
+ chain: chainIdentifierSchema,
31480
+ marketId: z.string().min(1),
31481
+ collateralAmount: positiveCollateralAmountSchema('collateralAmount'),
31482
+ config: borrowServiceConfigSchema$1.optional()
31483
+ }).strict();
31484
+ /** @internal */ closeLoanQuoteServiceParamsSchema.omit({
31485
+ chain: true
31486
+ }).extend({
31487
+ idempotencyKey: z.string().uuid().optional()
31488
+ });
31489
+ /**
31490
+ * Provider-level runtime schema for the non-adapter portion of
31491
+ * {@link ClaimRewardsServiceParams} / {@link GetRewardsServiceParams}.
31492
+ *
31493
+ * `from` (the adapter context) is intentionally excluded — like
31494
+ * `repay`/`closeLoan`, it is validated structurally by TypeScript and resolved
31495
+ * via `resolveAdapterContext` rather than by a Zod schema, since it carries a
31496
+ * live adapter instance rather than plain data. `config` is the only field
31497
+ * that reaches the wire, so it is what gets validated here, matching every
31498
+ * other provider method's independent `parseOrThrow` call.
31499
+ *
31500
+ * @internal
31501
+ */ z.object({
31502
+ config: borrowServiceConfigSchema$1.optional()
31503
+ }).strict();
31504
+ /**
31505
+ * Provider-level runtime schema for {@link GetPositionServiceParams}.
31506
+ *
31507
+ * @internal
31508
+ */ z.object({
31509
+ loanId: z.string().uuid(),
31510
+ config: borrowServiceConfigSchema$1.optional()
31511
+ }).strict();
31512
+ /** @internal */ const withdrawCollateralQuoteServiceParamsSchema = z.object({
31513
+ loanId: z.string().uuid(),
31514
+ chain: chainIdentifierSchema,
31515
+ // Carries no decimal-place cap: the repayment is USDC, but the collateral
31516
+ // is the market's own token and may hold more precision than USDC's six.
31517
+ collateralAmount: positiveCollateralAmountSchema('collateralAmount'),
31518
+ slippageBps: z.number().int().min(0).max(10_000).optional(),
31519
+ config: borrowServiceConfigSchema$1.optional()
31520
+ }).strict();
31521
+ /** @internal */ withdrawCollateralQuoteServiceParamsSchema.omit({
31522
+ chain: true
31523
+ }).extend({
31524
+ idempotencyKey: z.string().uuid().optional()
31525
+ });
31526
+ /**
31527
+ * Adding collateral sizes no second leg, so there is no slippage bound.
31528
+ *
31529
+ * @internal
31530
+ */ const addCollateralQuoteServiceParamsSchema = z.object({
31531
+ loanId: z.string().uuid(),
31532
+ chain: chainIdentifierSchema,
31533
+ collateralAmount: positiveCollateralAmountSchema('collateralAmount'),
31534
+ config: borrowServiceConfigSchema$1.optional()
31535
+ }).strict();
31536
+ /** @internal */ addCollateralQuoteServiceParamsSchema.omit({
31537
+ chain: true
31538
+ }).extend({
31539
+ idempotencyKey: z.string().uuid().optional()
31540
+ });
31541
+ /** @internal */ const borrowAssetAmountSchema = z.object({
31542
+ token: z.string().min(1),
31543
+ tokenAddress: z.string().regex(EVM_ADDRESS_REGEX),
31544
+ decimals: z.number().int().min(0).max(255),
31545
+ amount: z.string().regex(HUMAN_READABLE_AMOUNT_REGEX$1)
31546
+ });
31547
+ /** @internal */ const healthFactorBandSchema = z.enum([
31548
+ 'SAFE',
31549
+ 'WARN',
31550
+ 'URGENT',
31551
+ 'IMMINENT',
31552
+ 'LIQUIDATABLE'
31553
+ ]);
31554
+ /**
31555
+ * Whether a loan's economic projection has converged.
31556
+ *
31557
+ * `PENDING` means the loan's identity and lifecycle are known but its
31558
+ * economics are not yet materialized — every economic field is `null` until
31559
+ * the service's repair queue fills them in. See {@link loanSchema}.
31560
+ *
31561
+ * @internal
31562
+ */ const loanDataStatusSchema = z.enum([
31563
+ 'READY',
31564
+ 'PENDING'
31565
+ ]);
31566
+ /**
31567
+ * Lifecycle status of a loan: still open (`active`) or fully wound down
31568
+ * (`closed`). Unlike {@link loanDataStatusSchema} this is not about whether
31569
+ * economics have converged — a `closed` loan is `READY` with every economic
31570
+ * field legitimately zeroed, not `null`. Shared by {@link loanSchema} and
31571
+ * {@link loanPayloadSchema}, which return the same field for the same entity.
31572
+ *
31573
+ * @internal
31574
+ */ const loanStatusSchema = z.enum([
31575
+ 'active',
31576
+ 'closed'
31577
+ ]);
31578
+ /**
31579
+ * Zod schema for one loan in the `GET /v1/borrowKit/loans` page.
31580
+ *
31581
+ * @remarks Every economic field is nullable because the service returns a
31582
+ * `PENDING` loan — identity and lifecycle fields set, all economics `null` —
31583
+ * while materialization, principal, debt, or market APY is still converging.
31584
+ * That is the documented representation of a freshly-created loan, so
31585
+ * declaring these non-nullable made the first read after a `borrow()` fail
31586
+ * validation. `dataStatus` tells callers which of the two shapes they hold.
31587
+ *
31588
+ * `status` distinguishes a fully wound-down loan — `READY` with legitimately
31589
+ * zeroed economics — from a live one. Without it a caller cannot tell the two
31590
+ * apart, which is what left a closed loan sitting in `getLoans` output looking
31591
+ * open. It is declared **required here and on {@link loanPayloadSchema}**: a
31592
+ * live `GET /v1/borrowKit/loans` page reports it on every loan, including a
31593
+ * closed one.
31594
+ *
31595
+ * @internal
31596
+ */ const loanSchema = z.object({
31597
+ loanId: z.string().uuid(),
31598
+ chain: z.string().min(1),
31599
+ marketId: z.string().min(1),
31600
+ walletAddress: z.string().regex(EVM_ADDRESS_REGEX),
31601
+ dataStatus: loanDataStatusSchema,
31602
+ collateral: borrowAssetAmountSchema.nullable(),
31603
+ borrowed: borrowAssetAmountSchema.nullable(),
31604
+ principalBorrowed: borrowAssetAmountSchema.nullable(),
31605
+ accruedInterest: borrowAssetAmountSchema.nullable(),
31606
+ borrowApy: z.number().nullable(),
31607
+ ltv: z.number().nullable(),
31608
+ healthFactor: z.number().nullable(),
31609
+ healthFactorBand: healthFactorBandSchema.nullable(),
31610
+ liquidationPrice: borrowAssetAmountSchema.nullable(),
31611
+ status: loanStatusSchema
31612
+ });
31613
+ /**
31614
+ * Zod schema for the `GET /v1/borrowKit/loans` API response. The Borrow
31615
+ * Service wraps every response in a `data` envelope.
31616
+ *
31617
+ * @internal
31618
+ */ z.object({
31619
+ data: z.object({
31620
+ loans: z.array(loanSchema),
31621
+ pagination: z.object({
31622
+ pageAfter: z.string().optional()
31623
+ })
31624
+ })
31625
+ });
31626
+ /** @internal */ const borrowFeeSchema = z.object({
31627
+ type: z.string(),
31628
+ token: z.string(),
31629
+ amount: borrowAssetAmountSchema
31630
+ });
31631
+ /** @internal */ const borrowQuoteGasFeeSchema = z.object({
31632
+ name: z.string(),
31633
+ fees: z.object({
31634
+ gas: z.string(),
31635
+ gasPrice: borrowAssetAmountSchema,
31636
+ fee: borrowAssetAmountSchema
31637
+ })
31638
+ });
31639
+ /** @internal */ const hexBytesSchema = z.string().regex(/^0x(?:[0-9a-fA-F]{2})*$/).transform((value)=>value);
31640
+ function isNonNegativeBigIntLike(value) {
31641
+ try {
31642
+ return BigInt(value) >= 0n;
31643
+ } catch {
31644
+ return false;
31645
+ }
31646
+ }
31647
+ /** @internal */ const uint256LikeSchema = z.union([
31648
+ z.string(),
31649
+ z.bigint()
31650
+ ]).refine(isNonNegativeBigIntLike, {
31651
+ message: 'value must be a non-negative bigint-compatible string or bigint'
31652
+ });
31653
+ /**
31654
+ * A quoted decimal that has to parse finite, for the response fields the
31655
+ * service marshals from a Go `decimal.Decimal`.
31656
+ *
31657
+ * Deliberately not `z.coerce.number()`: coercion maps `''` and whitespace to
31658
+ * `0`, so a service that stopped sending a value would read as a real `0.0` —
31659
+ * a health factor of zero is a liquidated position, so that failure mode
31660
+ * silently reports the opposite of the truth. Refusing anything unparseable
31661
+ * here also makes the `decimalToNumber` mapper total, with no fallback value to
31662
+ * invent downstream.
31663
+ */ const decimalNumericString = z.string().min(1).refine((value)=>value.trim() !== '' && Number.isFinite(Number(value)), {
31664
+ message: 'value must be a decimal string that parses to a finite number'
31665
+ });
31666
+ /** @internal */ const borrowExecutionParamsSchema = z.object({
31667
+ instructions: z.array(z.object({
31668
+ target: evmAddressSchema$1,
31669
+ data: hexBytesSchema,
31670
+ value: uint256LikeSchema,
31671
+ tokenIn: evmAddressSchema$1,
31672
+ amountToApprove: uint256LikeSchema,
31673
+ tokenOut: evmAddressSchema$1,
31674
+ minTokenOut: uint256LikeSchema
31675
+ }).passthrough()).min(1),
31676
+ tokens: z.array(z.object({
31677
+ token: evmAddressSchema$1,
31678
+ beneficiary: evmAddressSchema$1
31679
+ }).passthrough()),
31680
+ execId: uint256LikeSchema,
31681
+ deadline: uint256LikeSchema,
31682
+ metadata: hexBytesSchema
31683
+ }).passthrough();
31684
+ /**
31685
+ * Inner payload for a Borrow Service execution response, shared by every
31686
+ * write endpoint (`borrow`, `repay`, `addCollateral`, `closeLoan`,
31687
+ * `withdrawCollateral`). Kept separate from {@link loanExecutionSchema} so
31688
+ * {@link withdrawCollateralExecutionSchema} — the one execution response that
31689
+ * omits `chain` — can build on it without re-declaring every field.
31690
+ *
31691
+ * @internal
31692
+ */ const loanExecutionPayloadSchema = z.object({
31693
+ loanId: z.string().uuid(),
31694
+ chain: z.string().min(1),
31695
+ execId: z.string().min(1),
31696
+ signature: evmSignatureSchema,
31697
+ executionParams: borrowExecutionParamsSchema
31698
+ });
31699
+ /**
31700
+ * Zod schema for a Borrow Service execution API response. The Borrow Service
31701
+ * wraps every response in a `data` envelope.
31702
+ *
31703
+ * @internal
31704
+ */ z.object({
31705
+ data: loanExecutionPayloadSchema
31706
+ });
31707
+ /**
31708
+ * Zod schema for the `POST /v1/borrowKit/loans/borrow` execution API
31709
+ * response. Extends {@link loanExecutionPayloadSchema} with `fees`, the fee
31710
+ * legs the signed bundle charges at origination (empty when nothing is
31711
+ * charged) — a field only this endpoint's response carries.
31712
+ *
31713
+ * `fees` is optional here, and only here. The API spec documents it as always
31714
+ * present and `[]` when nothing is charged, but the deployed service omits the
31715
+ * key entirely; requiring it fails validation on a healthy `200` and turns
31716
+ * every borrow into a FATAL error. It is optional rather than defaulted
31717
+ * because the guard consuming this schema reports `safeParse().success` and
31718
+ * discards the parsed value, so a default would never reach a reader.
31719
+ *
31720
+ * The absence is preserved to the caller rather than normalised to `[]`:
31721
+ * `fetchBorrow` returns `response.data` unchanged and `BorrowResponse.fees` is
31722
+ * optional, so "the service named no legs" stays distinguishable from "nothing
31723
+ * was charged". `executeBorrow` is what resolves it, by reporting the fee
31724
+ * transfers the receipt paid out under `type: 'unknown'`.
31725
+ *
31726
+ * @internal
31727
+ */ z.object({
31728
+ data: loanExecutionPayloadSchema.extend({
31729
+ fees: z.array(borrowFeeSchema).optional()
31730
+ })
31731
+ });
31732
+ /** @internal */ const resultingHealthSchema = {
31733
+ resultingHealthFactor: z.number().nullable(),
31734
+ resultingLtv: z.number().nullable(),
31735
+ resultingBand: healthFactorBandSchema,
31736
+ liquidationPrice: borrowAssetAmountSchema.nullable()
31737
+ };
31738
+ /**
31739
+ * Zod schema for the `POST /v1/borrowKit/loans/:loan_id/repay/quote` API
31740
+ * response. The Borrow Service wraps every response in a `data` envelope.
31741
+ *
31742
+ * @internal
31743
+ */ z.object({
31744
+ data: z.object({
31745
+ chain: z.string().min(1),
31746
+ repayAmount: borrowAssetAmountSchema,
31747
+ fees: z.array(borrowFeeSchema),
31748
+ gasFees: z.array(borrowQuoteGasFeeSchema),
31749
+ ...resultingHealthSchema
31750
+ })
31751
+ });
31752
+ // ---------------------------------------------------------------------------
31753
+ // Loan position response schema (SE-6383: getPosition)
31754
+ // ---------------------------------------------------------------------------
31755
+ /**
31756
+ * Zod schema for the inner loan position payload.
31757
+ *
31758
+ * @remarks Matches the real `GET /v1/borrowKit/loans/:loan_id` wire shape
31759
+ * (Zenith's `borrowkit.LoanResponse`). Two fields in the original placeholder
31760
+ * did not exist on that contract and made every lookup of a real loan fail
31761
+ * validation: the owner address is sent as `walletAddress`, not `wallet`, and
31762
+ * the service sends no liquidation threshold at all — liquidation LTV is a
31763
+ * market property, served by `GET /v1/borrowKit/markets/:chain/:market_id` as
31764
+ * `lltv`, not a per-loan one.
31765
+ *
31766
+ * `collateral` and `borrowed` are nullable for the same reason they are on
31767
+ * {@link loanSchema}: this route returns the same `PENDING` representation —
31768
+ * null economics — for a loan whose on-chain create has not been observed
31769
+ * yet, which is exactly the state a `borrow()` leaves behind. `dataStatus`
31770
+ * distinguishes that from a `READY` loan whose economics happen to be zero.
31771
+ *
31772
+ * Declares the same economic field set as {@link loanSchema}, because Zenith
31773
+ * serves both routes from one struct (`borrowkit.LoanResponse`): a loan read
31774
+ * one at a time reports exactly what the same loan reports inside a page, so a
31775
+ * caller never has to list a wallet to recover a field. Both declare `status`
31776
+ * as required: a live `GET /v1/borrowKit/loans` page reports it on every loan,
31777
+ * including a closed one.
31778
+ *
31779
+ * `registeredAt` is the sole field on the wire that neither schema declares.
31780
+ *
31781
+ * @internal
31782
+ */ const loanPayloadSchema = z.object({
31783
+ loanId: z.string(),
31784
+ walletAddress: z.string(),
31785
+ chain: z.string(),
31786
+ marketId: z.string().min(1),
31787
+ dataStatus: loanDataStatusSchema,
31788
+ collateral: borrowAssetAmountSchema.nullable(),
31789
+ borrowed: borrowAssetAmountSchema.nullable(),
31790
+ principalBorrowed: borrowAssetAmountSchema.nullable(),
31791
+ accruedInterest: borrowAssetAmountSchema.nullable(),
31792
+ borrowApy: z.number().nullable(),
31793
+ ltv: z.number().nullable(),
31794
+ healthFactor: z.number().nullable(),
31795
+ healthFactorBand: healthFactorBandSchema.nullable(),
31796
+ liquidationPrice: borrowAssetAmountSchema.nullable(),
31797
+ status: loanStatusSchema
31798
+ });
31799
+ /**
31800
+ * Zod schema for the `GET /v1/borrowKit/loans/:loan_id` API response.
31801
+ *
31802
+ * @internal
31803
+ */ z.object({
31804
+ data: loanPayloadSchema
31805
+ });
31806
+ // ---------------------------------------------------------------------------
31807
+ // Inferred types
31808
+ // ---------------------------------------------------------------------------
31809
+ /**
31810
+ * Zod schema for the `POST /v1/borrowKit/loans/borrow/quote` API response.
31811
+ * The Borrow Service wraps every response in a `data` envelope.
31812
+ *
31813
+ * @internal
31814
+ */ z.object({
31815
+ data: z.object({
31816
+ chain: z.string().min(1),
31817
+ collateralAmount: borrowAssetAmountSchema,
31818
+ loanAssetAmount: borrowAssetAmountSchema,
31819
+ // Nullable: the service reports null when the curated market row has no
31820
+ // cached rate yet, rather than a misleading 0%. The loans and markets
31821
+ // schemas already allow it; this one did not, so an unpriced market failed
31822
+ // validation and surfaced the whole quote as SERVICE_UNKNOWN_ERROR.
31823
+ borrowApy: z.number().nullable(),
31824
+ fees: z.array(borrowFeeSchema),
31825
+ gasFees: z.array(borrowQuoteGasFeeSchema),
31826
+ ...resultingHealthSchema
31827
+ })
31828
+ });
31829
+ /**
31830
+ * Zod schema for the `POST /v1/borrowKit/loans/:loan_id/addCollateral/quote`
31831
+ * API response. The Borrow Service wraps every response in a `data` envelope.
31832
+ *
31833
+ * @internal
31834
+ */ z.object({
31835
+ data: z.object({
31836
+ chain: z.string().min(1),
31837
+ collateralAmount: borrowAssetAmountSchema,
31838
+ fees: z.array(borrowFeeSchema),
31839
+ gasFees: z.array(borrowQuoteGasFeeSchema),
31840
+ ...resultingHealthSchema
31841
+ })
31842
+ });
31843
+ /**
31844
+ * Zod schema for the `POST /v1/borrowKit/loans/:loan_id/closeLoan/quote` API
31845
+ * response. The Borrow Service wraps every response in a `data` envelope.
31846
+ *
31847
+ * @internal
31848
+ */ z.object({
31849
+ data: z.object({
31850
+ chain: z.string().min(1),
31851
+ repayAmount: borrowAssetAmountSchema,
31852
+ collateralAmount: borrowAssetAmountSchema,
31853
+ fees: z.array(borrowFeeSchema),
31854
+ gasFees: z.array(borrowQuoteGasFeeSchema),
31855
+ ...resultingHealthSchema
31856
+ })
31857
+ });
31858
+ /**
31859
+ * The collateral-withdrawal execution response is the one Borrow Service
31860
+ * execution body that omits `chain`, so it cannot reuse
31861
+ * {@link loanExecutionSchema} unchanged. Built on
31862
+ * {@link loanExecutionPayloadSchema} so the `data` envelope only needs to be
31863
+ * applied once.
31864
+ *
31865
+ * @internal
31866
+ */ z.object({
31867
+ data: loanExecutionPayloadSchema.omit({
31868
+ chain: true
31869
+ })
31870
+ });
31871
+ /**
31872
+ * Zod schema for the
31873
+ * `POST /v1/borrowKit/loans/:loan_id/withdrawCollateral/quote` API response.
31874
+ * The Borrow Service wraps every response in a `data` envelope.
31875
+ *
31876
+ * @internal
31877
+ */ z.object({
31878
+ data: z.object({
31879
+ chain: z.string().min(1),
31880
+ repayAmount: borrowAssetAmountSchema,
31881
+ collateralAmount: borrowAssetAmountSchema,
31882
+ fees: z.array(borrowFeeSchema),
31883
+ gasFees: z.array(borrowQuoteGasFeeSchema),
31884
+ ...resultingHealthSchema
31885
+ })
31886
+ });
31887
+ /**
31888
+ * Zod schema for the `POST /v1/borrowKit/loans/requiredCollateral/quote` API
31889
+ * response. The Borrow Service wraps every response in a `data` envelope.
31890
+ *
31891
+ * @remarks Deliberately not {@link resultingHealthSchema}. The two
31892
+ * market-scoped sizing quotes send four fields, not seven — no `resultingLtv`
31893
+ * and no `resultingBand` — so requiring the loan-scoped health block rejected
31894
+ * every well-formed response with `MALFORMED_RESPONSE`.
31895
+ *
31896
+ * `resultingHealthFactor` arrives as a decimal *string* on this route alone
31897
+ * (Zenith types it `decimal.Decimal`, which marshals quoted, where every other
31898
+ * route types it `*float64`). It is accepted as either encoding here and
31899
+ * narrowed to a `number` by the mapper — deliberately not via a Zod
31900
+ * `.transform`, because these schemas are consumed through boolean type guards
31901
+ * (`isRequiredCollateralQuote`), which discard a transform's output and would
31902
+ * leave the raw string flowing on while typed as a number.
31903
+ *
31904
+ * @internal
31905
+ */ z.object({
31906
+ data: z.object({
31907
+ chain: z.string().min(1),
31908
+ requiredCollateral: borrowAssetAmountSchema,
31909
+ resultingHealthFactor: z.union([
31910
+ z.number(),
31911
+ decimalNumericString
31912
+ ]).nullable(),
31913
+ liquidationPrice: borrowAssetAmountSchema.nullable()
31914
+ })
31915
+ });
31916
+ /**
31917
+ * Zod schema for the `POST /v1/borrowKit/loans/maxBorrow/quote` API response.
31918
+ * The Borrow Service wraps every response in a `data` envelope.
31919
+ *
31920
+ * @remarks Four fields, not seven — see
31921
+ * {@link requiredCollateralQuoteSchema}. `resultingHealthFactor` is a plain
31922
+ * JSON number here (Zenith types it `*float64` on this route), so unlike its
31923
+ * inverse it needs no string coercion.
31924
+ *
31925
+ * @internal
31926
+ */ z.object({
31927
+ data: z.object({
31928
+ chain: z.string().min(1),
31929
+ maxBorrowAmount: borrowAssetAmountSchema,
31930
+ resultingHealthFactor: z.number().nullable(),
31931
+ liquidationPrice: borrowAssetAmountSchema.nullable()
31932
+ })
31933
+ });
31934
+ /**
31935
+ * Zod schema for the `GET`/`POST /v1/borrowKit/integrators/config` API
31936
+ * response. The Borrow Service wraps every response in a `data` envelope.
31937
+ *
31938
+ * @internal
31939
+ */ z.object({
31940
+ data: z.object({
31941
+ integratorId: z.string().min(1),
31942
+ integratorFeeBps: z.number().int().min(0),
31943
+ integratorFeeAddress: z.string().regex(EVM_ADDRESS_REGEX).nullable(),
31944
+ createdAt: z.string().datetime({
31945
+ offset: true
31946
+ }),
31947
+ updatedAt: z.string().datetime({
31948
+ offset: true
31949
+ })
31950
+ })
31951
+ });
31952
+ /** @internal */ z.object({
31953
+ config: borrowServiceConfigSchema$1.optional()
31954
+ }).strict();
31955
+ /**
31956
+ * Both fee fields are always required, so neither half is accepted alone.
31957
+ *
31958
+ * `integratorFeeAddress` may be `null` only when `integratorFeeBps` is 0, which
31959
+ * is how an integrator turns a fee off and clears the recipient. The reverse is
31960
+ * still allowed: a 0 rate can keep an address, which pauses the fee without
31961
+ * forgetting where it used to go. A rate above 0 with no recipient is unusable.
31962
+ *
31963
+ * The rule spans two fields, so it cannot live on either one and cannot be
31964
+ * expressed in the type. `{ integratorFeeBps: 25, integratorFeeAddress: null }`
31965
+ * type-checks and fails here.
31966
+ *
31967
+ * @internal
31968
+ */ z.object({
31969
+ integratorFeeBps: z.number().int().min(0).max(10_000),
31970
+ integratorFeeAddress: z.string().regex(EVM_ADDRESS_REGEX).nullable(),
31971
+ config: borrowServiceConfigSchema$1.optional()
31972
+ }).strict().refine((params)=>params.integratorFeeAddress !== null || params.integratorFeeBps === 0, {
31973
+ message: 'integratorFeeAddress can only be null when integratorFeeBps is 0',
31974
+ path: [
31975
+ 'integratorFeeAddress'
31976
+ ]
31977
+ });
31978
+ /**
31979
+ * Zod schema for the webhook registration payload inside the API `data`
31980
+ * envelope, returned by
31981
+ * `POST /v1/borrowKit/loans/:loan_id/webhookRegistration`.
31982
+ *
31983
+ * @internal
31984
+ */ const webhookRegistrationPayloadSchema = z.object({
31985
+ loanId: z.string().uuid(),
31986
+ webhookUrl: z.string().nullish()
31987
+ });
31988
+ /**
31989
+ * Zod schema validating the caller-supplied `loanId` and `webhookUrl` inputs
31990
+ * to `BorrowServiceProvider.registerWebhook` before they're signed and
31991
+ * submitted.
31992
+ *
31993
+ * `loanId` must be a UUID, consistent with every other loan-scoped schema in
31994
+ * this package (`repayQuoteServiceParamsSchema`, `loanSchema`,
31995
+ * `loanExecutionSchema`). `webhookUrl` must be `null` (an explicit "unset"
31996
+ * intent) or a syntactically valid **https** URL string — an empty string is
31997
+ * neither, so it's rejected here rather than silently reaching the `?? ''`
31998
+ * coercion that `buildWebhookRegistrationTypedData` applies to a genuine
31999
+ * `null`. The scheme is restricted to `https:` because this URL is where
32000
+ * loan-lifecycle callbacks get delivered and is cryptographically signed by
32001
+ * the loan owner: allowing `http:` would let a signed registration point at
32002
+ * a plaintext endpoint (or a link-local/loopback address reachable only from
32003
+ * the callback sender's own network), and the SDK is the natural place to
32004
+ * refuse that before it's ever signed or transmitted.
32005
+ *
32006
+ * @internal
32007
+ */ z.object({
32008
+ loanId: z.string().uuid(),
32009
+ webhookUrl: z.string().url().refine((value)=>isHttpsUrl$1(value), 'webhookUrl must use the https scheme').nullable()
32010
+ }).strict();
32011
+ /**
32012
+ * Zod schema for the `POST /v1/borrowKit/loans/:loan_id/webhookRegistration`
32013
+ * API response.
32014
+ *
32015
+ * The Borrow Service API wraps the webhook registration payload in a `data`
32016
+ * envelope.
32017
+ *
32018
+ * @internal
32019
+ */ z.object({
32020
+ data: webhookRegistrationPayloadSchema
32021
+ });
32022
+ /** @internal */ const marketAssetSchema = z.object({
32023
+ symbol: z.string().min(1),
32024
+ address: z.string().regex(EVM_ADDRESS_REGEX),
32025
+ decimals: z.number().int().nonnegative()
32026
+ });
32027
+ /**
32028
+ * Wire shape for a typed token amount: raw atoms as an integer string plus the
32029
+ * token's decimals, matching `@core/amounts` {@link AmountJSON}.
32030
+ *
32031
+ * @internal
32032
+ */ const amountJsonSchema = z.object({
32033
+ raw: z.string().refine(isNonNegativeBigIntLike, {
32034
+ message: 'raw must be a non-negative bigint-compatible string'
32035
+ }),
32036
+ decimals: z.number().int().nonnegative()
32037
+ });
32038
+ /**
32039
+ * Wire shape for a single borrow market returned by
32040
+ * `GET /v1/borrowKit/markets/:chain/:market_id`. `chain` is the Borrow Service
32041
+ * API chain code (mapped back to the SDK chain by `toMarketInfo`); display
32042
+ * ratios arrive as numbers, token amounts as `{ raw, decimals }` objects.
32043
+ *
32044
+ * @remarks `lltv`, `borrowAssets`, `liquidity`, `borrowApy`, `utilization`,
32045
+ * and `refreshedAt` are all nullable because the service's economics are
32046
+ * cached projections, not live reads: a market that has been discovered but
32047
+ * not yet backfilled by the cache reports every economic field as `null`
32048
+ * rather than a placeholder value. An idle market keeps its last-known values
32049
+ * and old `refreshedAt` rather than reporting zeros, so `null` unambiguously
32050
+ * means "never backfilled." `borrowCap` is always `null` (Morpho Blue has no
32051
+ * per-market cap) but carried anyway so the field does not have to be added
32052
+ * later as a breaking change; it is also optional since the service may omit
32053
+ * it entirely.
32054
+ *
32055
+ * @internal
32056
+ */ const marketResponseSchema = z.object({
32057
+ marketId: z.string().min(1),
32058
+ protocol: z.enum([
32059
+ 'morpho'
32060
+ ]),
32061
+ chain: z.string().min(1),
32062
+ loanAsset: marketAssetSchema,
32063
+ collateralAsset: marketAssetSchema,
32064
+ lltv: z.number().nonnegative().nullable(),
32065
+ borrowCap: amountJsonSchema.nullable().optional(),
32066
+ borrowAssets: amountJsonSchema.nullable(),
32067
+ liquidity: amountJsonSchema.nullable(),
32068
+ borrowApy: z.number().nonnegative().nullable(),
32069
+ utilization: z.number().nonnegative().nullable(),
32070
+ refreshedAt: z.string().datetime({
32071
+ offset: true
32072
+ }).nullable()
32073
+ });
32074
+ /**
32075
+ * Zod schema for the `GET /v1/borrowKit/markets/:chain/:market_id` API
32076
+ * response. The Borrow Service wraps every response in a `data` envelope;
32077
+ * {@link marketResponseSchema} itself stays unwrapped since it is also reused
32078
+ * per-entry inside {@link listMarketsResponseSchema}.
32079
+ *
32080
+ * @internal
32081
+ */ z.object({
32082
+ data: marketResponseSchema
32083
+ });
32084
+ /**
32085
+ * Wire shape for a page of borrow markets returned by
32086
+ * `GET /v1/borrowKit/markets`. Reuses {@link marketResponseSchema} per entry so
32087
+ * the per-market wire format stays defined in one place, and adds the
32088
+ * pagination envelope: an opaque `pageAfter` cursor absent on the last page.
32089
+ * The Borrow Service wraps every response in a `data` envelope.
32090
+ *
32091
+ * @internal
32092
+ */ z.object({
32093
+ data: z.object({
32094
+ markets: z.array(marketResponseSchema),
32095
+ pagination: z.object({
32096
+ pageAfter: z.string().optional()
32097
+ })
32098
+ })
32099
+ });
32100
+
32101
+ /** @internal */ const BORROW_CHAIN_TO_API = {
32102
+ [Blockchain.Arc]: 'ARC',
32103
+ [Blockchain.Arc_Testnet]: 'ARC-TESTNET'
32104
+ };
32105
+
32106
+ Object.fromEntries(Object.entries(BORROW_CHAIN_TO_API).map(([sdkChain, apiChain])=>[
32107
+ apiChain,
32108
+ sdkChain
32109
+ ]));
32110
+
32111
+ /**
32112
+ * Schema for the Borrow Service configuration options.
32113
+ *
32114
+ * `apiKey` carries a Circle API key (`<ENV>_API_KEY:<keyId>:<keySecret>`) or a
32115
+ * legacy `KIT_KEY:<keyId>:<keySecret>` value. It is shape-checked only — as
32116
+ * with every other field here, the credential's format is the provider's call,
32117
+ * and `buildConfig` rejects a malformed one via `isValidApiKey`. The empty
32118
+ * string is allowed on purpose: `process.env.CIRCLE_API_KEY ?? ''` yields one
32119
+ * when the variable is unset, and the provider reads that as "no credential"
32120
+ * rather than as a malformed one.
32121
+ *
32122
+ * This schema is `.strict()`, so a field missing here is not merely unvalidated
32123
+ * — it is rejected outright, which is what made an `apiKey` config unusable
32124
+ * before it was listed.
32125
+ *
32126
+ * @internal
32127
+ */ const borrowServiceConfigSchema = z.object({
32128
+ apiKey: z.string().optional(),
32129
+ baseUrl: z.string().url('baseUrl must be a valid URL').optional()
32130
+ }).strict();
32131
+ /**
32132
+ * Runtime schema for {@link GetLoansParams}.
32133
+ *
32134
+ * @example
32135
+ * ```typescript
32136
+ * import { getLoansParamsSchema } from '@circle-fin/borrow-kit'
32137
+ *
32138
+ * const result = getLoansParamsSchema.safeParse({
32139
+ * walletAddress: '0x1111111111111111111111111111111111111111',
32140
+ * chain: 'Arc_Testnet',
32141
+ * })
32142
+ * ```
32143
+ */ z.object({
32144
+ walletAddress: evmAddressSchema$1,
32145
+ chain: chainIdentifierSchema,
32146
+ pageSize: z.number().int().positive().optional(),
32147
+ pageAfter: z.string().min(1).optional(),
32148
+ config: borrowServiceConfigSchema.optional()
32149
+ }).strict();
32150
+ /**
32151
+ * Runtime schema for {@link GetIntegratorConfigParams}.
32152
+ *
32153
+ * @example
32154
+ * ```typescript
32155
+ * import { getIntegratorConfigParamsSchema } from '@circle-fin/borrow-kit'
32156
+ *
32157
+ * const result = getIntegratorConfigParamsSchema.safeParse({
32158
+ * config: { apiKey: 'TEST_API_KEY:key-id:key-secret' },
32159
+ * })
32160
+ * ```
32161
+ */ z.object({
32162
+ config: borrowServiceConfigSchema.optional()
32163
+ }).strict();
32164
+ /**
32165
+ * Runtime schema for {@link GetMarketParams}.
32166
+ *
32167
+ * @example
32168
+ * ```typescript
32169
+ * import { getMarketParamsSchema } from '@circle-fin/borrow-kit'
32170
+ *
32171
+ * const result = getMarketParamsSchema.safeParse({
32172
+ * chain: 'Arc_Testnet',
32173
+ * marketId: '0xabc...',
32174
+ * })
32175
+ * ```
32176
+ */ z.object({
32177
+ chain: chainIdentifierSchema,
32178
+ marketId: z.string().min(1),
32179
+ config: borrowServiceConfigSchema.optional()
32180
+ }).strict();
32181
+ /**
32182
+ * Runtime schema for {@link SetIntegratorConfigParams}.
32183
+ *
32184
+ * Both fee fields are required, so neither half is accepted alone.
32185
+ * `integratorFeeAddress` may be `null` only when `integratorFeeBps` is 0, which
32186
+ * turns the fee off and clears the recipient. A rate above 0 with no recipient
32187
+ * is unusable and is rejected.
32188
+ *
32189
+ * @example
32190
+ * ```typescript
32191
+ * import { setIntegratorConfigParamsSchema } from '@circle-fin/borrow-kit'
32192
+ *
32193
+ * const result = setIntegratorConfigParamsSchema.safeParse({
32194
+ * integratorFeeBps: 25,
32195
+ * integratorFeeAddress: '0x1111111111111111111111111111111111111111',
32196
+ * })
32197
+ *
32198
+ * // Turning the fee off and clearing the recipient.
32199
+ * const cleared = setIntegratorConfigParamsSchema.safeParse({
32200
+ * integratorFeeBps: 0,
32201
+ * integratorFeeAddress: null,
32202
+ * })
32203
+ * ```
32204
+ */ z.object({
32205
+ integratorFeeBps: z.number().int().min(0).max(10_000),
32206
+ integratorFeeAddress: evmAddressSchema$1.nullable(),
32207
+ config: borrowServiceConfigSchema.optional()
32208
+ }).strict().refine((params)=>params.integratorFeeAddress !== null || params.integratorFeeBps === 0, {
32209
+ message: 'integratorFeeAddress can only be null when integratorFeeBps is 0',
32210
+ path: [
32211
+ 'integratorFeeAddress'
32212
+ ]
32213
+ });
32214
+ /** @internal */ const HUMAN_READABLE_AMOUNT_REGEX = /^(?:0|[1-9]\d*)(?:\.\d+)?$/;
32215
+ /**
32216
+ * @param maxDecimals - Decimal places the amount may carry, or `null` for no
32217
+ * cap. USDC amounts take the default six; an amount denominated in a market's
32218
+ * own collateral token may be finer, so those pass `null`.
32219
+ * @internal
32220
+ */ function createPositiveAmountSchema(field, maxDecimals = 6) {
32221
+ const positive = z.string().regex(HUMAN_READABLE_AMOUNT_REGEX, `${field} must be a human-readable decimal string`).refine((value)=>/[1-9]/.test(value), `${field} must be greater than zero`);
32222
+ if (maxDecimals === null) {
32223
+ return positive;
32224
+ }
32225
+ return positive.refine((value)=>(value.split('.')[1]?.length ?? 0) <= maxDecimals, `${field} must have at most ${maxDecimals.toString()} decimal places`);
32226
+ }
32227
+ /** @internal */ const positiveAmountSchema = createPositiveAmountSchema('repayAmount');
32228
+ const NIL_UUID = '00000000-0000-0000-0000-000000000000';
32229
+ const idempotencyKeySchema = z.string().uuid().refine((value)=>value !== NIL_UUID, {
32230
+ message: 'idempotencyKey must not be the nil UUID; generate a fresh one per write'
32231
+ });
32232
+ /** @internal */ const adapterContextSchema = z.object({
32233
+ // prepareAction is declared in the shape (rather than checked only via
32234
+ // .passthrough()) so its value is read off the input by property access:
32235
+ // .passthrough() only copies an input's own enumerable keys into its
32236
+ // output, which drops prototype methods like a class's prepareAction.
32237
+ adapter: adapterSchema.extend({
32238
+ prepareAction: z.unknown()
32239
+ }).passthrough().refine((adapter)=>typeof adapter.prepareAction === 'function', 'adapter must expose prepareAction'),
32240
+ chain: chainIdentifierSchema,
32241
+ address: evmAddressSchema$1.optional()
32242
+ }).strict();
32243
+ /**
32244
+ * Shared `superRefine` enforcing the address/adapter-capability contract: a
32245
+ * developer-controlled adapter must supply `address` (the kit cannot resolve
32246
+ * it), and a user-controlled adapter must not (the adapter itself resolves
32247
+ * it — a caller-supplied value would silently take precedence, letting the
32248
+ * two disagree). Applied to every schema whose `from` shape carries an
32249
+ * adapter with a declared `addressContext` capability, so every Borrow Kit
32250
+ * write rejects a mismatched `from` the same way.
32251
+ *
32252
+ * @internal
32253
+ */ function refineAddressContext(from, context) {
32254
+ const addressContext = from.adapter.capabilities?.addressContext;
32255
+ if (addressContext === 'developer-controlled' && from.address === undefined) {
32256
+ context.addIssue({
32257
+ code: z.ZodIssueCode.custom,
32258
+ message: 'address is required for developer-controlled adapters',
32259
+ path: [
32260
+ 'address'
32261
+ ]
32262
+ });
32263
+ }
32264
+ if (addressContext === 'user-controlled' && from.address !== undefined) {
32265
+ context.addIssue({
32266
+ code: z.ZodIssueCode.custom,
32267
+ message: 'address must be resolved by user-controlled adapters',
32268
+ path: [
32269
+ 'address'
32270
+ ]
32271
+ });
32272
+ }
32273
+ }
32274
+ /** @internal */ const borrowExecutionFromSchema = z.object({
32275
+ // prepareAction/validateChainSupport/capabilities are declared in the
32276
+ // shape (rather than checked only via .passthrough()) so their values are
32277
+ // read off the input by property access: .passthrough() only copies an
32278
+ // input's own enumerable keys into its output, which drops a prototype
32279
+ // method or getter like a class's prepareAction/validateChainSupport/
32280
+ // capabilities. capabilities is read below and by refineAddressContext.
32281
+ adapter: adapterSchema.extend({
32282
+ prepareAction: z.unknown(),
32283
+ validateChainSupport: z.unknown(),
32284
+ capabilities: z.unknown()
32285
+ }).passthrough().refine((adapter)=>typeof adapter.prepareAction === 'function', 'adapter must expose prepareAction').refine((adapter)=>typeof adapter.validateChainSupport === 'function', 'adapter must expose validateChainSupport').refine((adapter)=>adapter.capabilities?.addressContext === 'user-controlled' || adapter.capabilities?.addressContext === 'developer-controlled', 'adapter must declare its addressContext capability'),
32286
+ chain: chainIdentifierSchema,
32287
+ address: evmAddressSchema$1.optional()
32288
+ }).strict().superRefine(refineAddressContext);
32289
+ /**
32290
+ * Runtime schema for {@link RepayQuoteParams}.
32291
+ */ const repayQuoteParamsSchema = z.object({
32292
+ loanId: z.string().uuid(),
32293
+ chain: chainIdentifierSchema,
32294
+ repayAmount: positiveAmountSchema,
32295
+ config: borrowServiceConfigSchema.optional()
32296
+ }).strict();
32297
+ /** Runtime schema for {@link RepayParams}. */ repayQuoteParamsSchema.omit({
32298
+ chain: true
32299
+ }).extend({
32300
+ idempotencyKey: idempotencyKeySchema.optional(),
32301
+ from: borrowExecutionFromSchema
32302
+ });
32303
+ /** Runtime schema for requesting a full-close quote. */ const closeLoanQuoteParamsSchema = z.object({
32304
+ loanId: z.string().uuid(),
32305
+ chain: chainIdentifierSchema,
32306
+ slippageBps: z.number().int().min(0).max(10_000).optional(),
32307
+ config: borrowServiceConfigSchema.optional()
32308
+ }).strict();
32309
+ /** Runtime schema for atomically closing a loan. */ closeLoanQuoteParamsSchema.omit({
32310
+ chain: true
32311
+ }).extend({
32312
+ idempotencyKey: idempotencyKeySchema.optional(),
32313
+ from: borrowExecutionFromSchema
32314
+ });
32315
+ /**
32316
+ * Runtime schema for {@link GetPositionParams}.
32317
+ *
32318
+ * @example
32319
+ * ```typescript
32320
+ * import { getPositionParamsSchema } from '@circle-fin/borrow-kit'
32321
+ *
32322
+ * const result = getPositionParamsSchema.safeParse({
32323
+ * loanId: '11111111-1111-4111-8111-111111111111',
32324
+ * })
32325
+ * ```
32326
+ */ z.object({
32327
+ loanId: z.string().uuid(),
32328
+ config: borrowServiceConfigSchema.optional()
32329
+ }).strict();
32330
+ /**
32331
+ * Schema for the adapter context within Borrow operations.
32332
+ *
32333
+ * `.strict()` so a typo nested inside `from` fails fast instead of being
32334
+ * silently stripped. The address field is optional (resolved from the
32335
+ * adapter at runtime).
32336
+ *
32337
+ * @internal
32338
+ */ const borrowAdapterContextSchema = z.object({
32339
+ // signTypedData/capabilities are declared in the shape (rather than
32340
+ // checked only via .passthrough()) so their values are read off the input
32341
+ // by property access: .passthrough() only copies an input's own
32342
+ // enumerable keys into its output, which drops a prototype method or
32343
+ // getter like a class's signTypedData/capabilities. capabilities is read
32344
+ // by refineAddressContext below.
32345
+ adapter: adapterSchema.extend({
32346
+ signTypedData: z.unknown(),
32347
+ capabilities: z.unknown()
32348
+ }).passthrough().refine(// supportsSignTypedData is optional on SignTypedDataAdapter (see
32349
+ // @core/adapter-evm's hasSignTypedData/canSignTypedData): only
32350
+ // signTypedData itself is required here.
32351
+ (adapter)=>typeof adapter.signTypedData === 'function', 'adapter must support signTypedData'),
32352
+ // BorrowAdapterContext accepts a wider chain field, but runtime
32353
+ // validation must stay constrained to chains where loans exist. No cast
32354
+ // needed here: inferring straight from borrowChainIdentifierSchema keeps
32355
+ // this schema's exported type accurate (only the Borrow chain set),
32356
+ // unlike the previous `as unknown as typeof chainIdentifierSchema` cast,
32357
+ // which over-widened it to the full ChainIdentifier union.
32358
+ chain: borrowChainIdentifierSchema,
32359
+ address: z.string().min(1, 'address must not be empty').optional()
32360
+ }).strict()// Same address/adapter-capability contract every other Borrow Kit write
32361
+ // enforces via borrowExecutionFromSchema: a developer-controlled adapter
32362
+ // without `address` fails fast with a named message instead of falling
32363
+ // through to adapter.getAddress(); a user-controlled adapter with `address`
32364
+ // set is rejected instead of silently taking precedence.
32365
+ .superRefine(refineAddressContext);
32366
+ /** @internal */ const borrowParamsBaseSchema = z.object({
32367
+ from: adapterContextSchema,
32368
+ borrowAmount: createPositiveAmountSchema('borrowAmount'),
32369
+ slippageBps: z.number().int().min(0).max(10_000).optional(),
32370
+ idempotencyKey: idempotencyKeySchema.optional(),
32371
+ config: borrowServiceConfigSchema.optional()
32372
+ });
32373
+ /**
32374
+ * Runtime schema for {@link BorrowParams}.
32375
+ *
32376
+ * One strict object with a refinement, rather than a union of a market branch
32377
+ * and a loan branch: a union that fails every branch reports one `invalid_union`
32378
+ * issue, which costs the caller the field that actually failed. The refinement
32379
+ * states the rule it enforces, and every other field keeps naming itself.
32380
+ */ borrowParamsBaseSchema.extend({
32381
+ marketId: z.string().min(1).optional(),
32382
+ loanId: z.string().uuid().optional()
32383
+ }).strict().refine((params)=>params.marketId === undefined !== (params.loanId === undefined), {
32384
+ message: 'Provide exactly one of marketId or loanId'
32385
+ });
32386
+ /**
32387
+ * Schema for the adapter context within reward-claiming operations.
32388
+ *
32389
+ * Validate that a properly-shaped adapter instance and a valid chain
32390
+ * identifier are provided. The address field is optional at the schema
32391
+ * level (resolved from the adapter at runtime for user-controlled
32392
+ * adapters, required for developer-controlled ones — that distinction is
32393
+ * enforced by {@link BorrowAdapterContext}'s conditional `AddressField`,
32394
+ * not by this runtime schema). `.strict()` so a typo nested inside `from`
32395
+ * fails fast instead of being silently stripped.
32396
+ *
32397
+ * Reward claiming is restricted to the Borrow chain identifiers (Arc and
32398
+ * Arc Testnet), which is narrower than the general
32399
+ * {@link chainIdentifierSchema} `repay`/`borrow` accept.
32400
+ *
32401
+ * @internal
32402
+ */ const claimRewardsAdapterContextSchema = z.object({
32403
+ adapter: adapterSchema,
32404
+ chain: borrowChainIdentifierSchema,
32405
+ address: evmAddressSchema$1.optional()
32406
+ }).strict()// Same address/adapter-capability contract every other Borrow Kit write
32407
+ // enforces via borrowExecutionFromSchema: a developer-controlled adapter
32408
+ // without `address` fails fast with a named message instead of falling
32409
+ // through to adapter.getAddress(); a user-controlled adapter with `address`
32410
+ // set is rejected instead of silently taking precedence.
32411
+ .superRefine(refineAddressContext);
32412
+ /** @internal */ const borrowPreviewParamsBaseSchema = z.object({
32413
+ chain: chainIdentifierSchema,
32414
+ marketId: z.string().min(1),
32415
+ config: borrowServiceConfigSchema.optional()
32416
+ });
32417
+ /** Runtime schema for a first-open borrow quote. @internal */ const openLoanQuoteParamsSchema = borrowPreviewParamsBaseSchema.extend({
32418
+ walletAddress: evmAddressSchema$1,
32419
+ borrowAmount: createPositiveAmountSchema('borrowAmount'),
32420
+ slippageBps: z.number().int().min(0).max(10_000).optional()
32421
+ }).strict();
32422
+ /** Runtime schema for an existing-loan borrow quote. @internal */ const borrowMoreQuoteParamsSchema = z.object({
32423
+ loanId: z.string().uuid(),
32424
+ borrowAmount: createPositiveAmountSchema('borrowAmount'),
32425
+ slippageBps: z.number().int().min(0).max(10_000).optional(),
32426
+ config: borrowServiceConfigSchema.optional()
32427
+ }).strict();
32428
+ /** Runtime schema for {@link BorrowQuoteParams}. */ z.union([
32429
+ openLoanQuoteParamsSchema,
32430
+ borrowMoreQuoteParamsSchema
32431
+ ]);
32432
+ /** Runtime schema for {@link RequiredCollateralParams}. */ borrowPreviewParamsBaseSchema.extend({
32433
+ borrowAmount: createPositiveAmountSchema('borrowAmount'),
32434
+ targetHealthFactor: z.number().positive().finite()
32435
+ }).strict();
32436
+ // Uncapped: repayments are USDC, but collateral is the market's own token and
32437
+ // may hold more precision than USDC's six places.
32438
+ /** @internal */ const collateralAmountSchema = createPositiveAmountSchema('collateralAmount', null);
32439
+ /**
32440
+ * Validation schema for ClaimRewardsParams.
32441
+ *
32442
+ * @example
32443
+ * ```typescript
32444
+ * import { claimRewardsParamsSchema } from '@circle-fin/borrow-kit'
32445
+ *
32446
+ * const result = claimRewardsParamsSchema.safeParse({
32447
+ * from: { adapter, chain: 'Arc_Testnet' },
32448
+ * })
32449
+ * ```
32450
+ */ z.object({
32451
+ from: claimRewardsAdapterContextSchema,
32452
+ config: borrowServiceConfigSchema.optional()
32453
+ }).strict();
32454
+ /**
32455
+ * Validation schema for GetClaimRewardsQuoteParams.
32456
+ *
32457
+ * @example
32458
+ * ```typescript
32459
+ * import { getClaimRewardsQuoteParamsSchema } from '@circle-fin/borrow-kit'
32460
+ *
32461
+ * const result = getClaimRewardsQuoteParamsSchema.safeParse({
32462
+ * from: { adapter, chain: 'Arc_Testnet' },
32463
+ * })
32464
+ * ```
32465
+ */ z.object({
32466
+ from: claimRewardsAdapterContextSchema,
32467
+ config: borrowServiceConfigSchema.optional()
32468
+ }).strict();
32469
+ /** @internal */ const marketSortBySchema = z.enum([
32470
+ 'lltv',
32471
+ 'borrowApy'
32472
+ ]);
32473
+ /**
32474
+ * Build a schema for an optional non-negative decimal filter string.
32475
+ *
32476
+ * Accepts values like `'0'`, `'100'`, `'0.86'`; rejects negatives, leading
32477
+ * dots, and non-numeric input so a malformed filter fails fast.
32478
+ *
32479
+ * @param field - The filter field name, used in the rejection message.
32480
+ * @returns A Zod string schema constrained to a non-negative decimal form.
32481
+ * @internal
32482
+ */ function decimalFilterSchema(field) {
32483
+ return z.string().regex(/^\d+(\.\d+)?$/, `${field} must be a non-negative decimal string`);
32484
+ }
32485
+ const exploreMarketsParamsBase = z.object({
32486
+ chain: chainIdentifierSchema,
32487
+ minLltv: decimalFilterSchema('minLltv').optional(),
32488
+ maxLltv: decimalFilterSchema('maxLltv').optional(),
32489
+ minBorrow: decimalFilterSchema('minBorrow').optional(),
32490
+ maxBorrow: decimalFilterSchema('maxBorrow').optional(),
32491
+ sortBy: marketSortBySchema.optional(),
32492
+ // Provisional bounds: the backend has not published a pageSize range, so
32493
+ // reject only implausible values rather than plausible ones.
32494
+ pageSize: z.number().int('pageSize must be an integer').min(1, 'pageSize must be at least 1').max(1000, 'pageSize must be at most 1000').optional(),
32495
+ pageAfter: z.string().min(1, 'pageAfter must not be empty').optional(),
32496
+ config: borrowServiceConfigSchema.optional()
32497
+ }).strict();
32498
+ /**
32499
+ * Runtime schema for {@link MaxBorrowParams}.
32500
+ *
32501
+ * The collateral amount is not held to the loan asset's six decimal places: it
32502
+ * denominates the market's collateral token, whose precision may be finer.
32503
+ */ borrowPreviewParamsBaseSchema.extend({
32504
+ collateralAmount: collateralAmountSchema
32505
+ }).strict();
32506
+ /** Runtime schema for {@link WithdrawCollateralQuoteParams}. */ const withdrawCollateralQuoteParamsSchema = z.object({
32507
+ loanId: z.string().uuid(),
32508
+ chain: chainIdentifierSchema,
32509
+ collateralAmount: collateralAmountSchema,
32510
+ slippageBps: z.number().int().min(0).max(10_000).optional(),
32511
+ config: borrowServiceConfigSchema.optional()
32512
+ }).strict();
32513
+ /**
32514
+ * Maximum accepted signature deadline: 300 seconds from now, matching the
32515
+ * Borrow Service's own hard limit on `WebhookRegistration` deadlines. A wider
32516
+ * SDK-side window would let a caller sign a deadline the service always
32517
+ * rejects.
32518
+ *
32519
+ * @internal
32520
+ */ const MAX_DEADLINE_SKEW_SECONDS = 300;
32521
+ /**
32522
+ * True when `value` parses as a URL whose scheme is exactly `https:`.
32523
+ *
32524
+ * Uses the WHATWG `URL` parser rather than `startsWith('https://')` so the
32525
+ * check is scheme-normalized (case-insensitive, e.g. `HTTPS://...` still
32526
+ * passes) instead of a literal prefix match. `value` has already passed
32527
+ * `z.string().url()` by the time this runs, but a caller could still supply
32528
+ * a string that `URL` itself rejects, so the parse is guarded.
32529
+ *
32530
+ * @internal
32531
+ */ function isHttpsUrl(value) {
32532
+ try {
32533
+ return new URL(value).protocol === 'https:';
32534
+ } catch {
32535
+ return false;
32536
+ }
32537
+ }
32538
+ /**
32539
+ * Validation schema for RegisterWebhookParams.
32540
+ *
32541
+ * @example
32542
+ * ```typescript
32543
+ * import { registerWebhookParamsSchema } from '@circle-fin/borrow-kit'
32544
+ *
32545
+ * const result = registerWebhookParamsSchema.safeParse({
32546
+ * from: { adapter, chain: 'Arc_Testnet' },
32547
+ * loanId: '11111111-1111-4111-8111-111111111111',
32548
+ * webhookUrl: 'https://example.com/webhook',
32549
+ * })
32550
+ * ```
32551
+ */ z.object({
32552
+ from: borrowAdapterContextSchema,
32553
+ // loanId must be a UUID, consistent with every other loan-scoped schema
32554
+ // in this package (repayQuoteParamsSchema, closeLoanQuoteParamsSchema,
32555
+ // borrowParamsSchema) and with the provider-level
32556
+ // registerWebhookInputSchema, which already enforces this.
32557
+ loanId: z.string().uuid(),
32558
+ // Restricted to https: for the same reason as the provider-level
32559
+ // registerWebhookInputSchema — this URL receives a cryptographically
32560
+ // signed, owner-authorized registration, and http:// would let that
32561
+ // signed intent point at a plaintext or link-local/loopback endpoint.
32562
+ webhookUrl: z.string().url('webhookUrl must be a valid URL').refine((value)=>isHttpsUrl(value), 'webhookUrl must use the https scheme').nullable().optional(),
32563
+ deadline: z.number().int('deadline must be an integer unix-seconds timestamp').refine((deadline)=>deadline > Math.floor(Date.now() / 1000), 'deadline must be in the future — a past deadline would sign a message the Borrow Service always rejects').refine((deadline)=>deadline <= Math.floor(Date.now() / 1000) + MAX_DEADLINE_SKEW_SECONDS, `deadline must be at most ${String(MAX_DEADLINE_SKEW_SECONDS)} seconds from now`).optional(),
32564
+ config: borrowServiceConfigSchema.optional()
32565
+ }).strict();
32566
+ /**
32567
+ * Reject a filter range whose lower bound exceeds its upper bound.
32568
+ *
32569
+ * Each bound is validated independently, so `{ minLltv: '0.9', maxLltv: '0.1' }`
32570
+ * would otherwise pass and return a silently empty page; comparing the bounds
32571
+ * numerically turns that contradiction into a clear validation error. Shared by
32572
+ * the single-page and iterator schemas so the two cannot drift.
32573
+ *
32574
+ * @param value - The parsed explore filters.
32575
+ * @param ctx - The Zod refinement context that collects any range issues.
32576
+ * @internal
32577
+ */ function refineFilterRanges(value, ctx) {
32578
+ if (value.minLltv !== undefined && value.maxLltv !== undefined && Number(value.minLltv) > Number(value.maxLltv)) {
32579
+ ctx.addIssue({
32580
+ code: z.ZodIssueCode.custom,
32581
+ path: [
32582
+ 'maxLltv'
32583
+ ],
32584
+ message: 'maxLltv must be greater than or equal to minLltv'
32585
+ });
32586
+ }
32587
+ if (value.minBorrow !== undefined && value.maxBorrow !== undefined && Number(value.minBorrow) > Number(value.maxBorrow)) {
32588
+ ctx.addIssue({
32589
+ code: z.ZodIssueCode.custom,
32590
+ path: [
32591
+ 'maxBorrow'
32592
+ ],
32593
+ message: 'maxBorrow must be greater than or equal to minBorrow'
32594
+ });
32595
+ }
32596
+ }
32597
+ /**
32598
+ * Runtime schema for {@link ExploreMarketsParams}.
32599
+ *
32600
+ * `chain` is required; every filter is optional. `pageAfter` is an opaque
32601
+ * non-empty cursor and `pageSize` a positive integer (provisional upper bound
32602
+ * 1000, pending backend confirmation). Unknown keys are rejected, and a range
32603
+ * whose minimum exceeds its maximum is rejected rather than returning a
32604
+ * silently empty page.
32605
+ *
32606
+ * @example
32607
+ * ```typescript
32608
+ * import { exploreMarketsParamsSchema } from '@circle-fin/borrow-kit'
32609
+ *
32610
+ * const result = exploreMarketsParamsSchema.safeParse({
32611
+ * chain: 'Arc_Testnet',
32612
+ * minLltv: '0.8',
32613
+ * sortBy: 'borrowApy',
32614
+ * })
32615
+ * ```
32616
+ */ exploreMarketsParamsBase.superRefine(refineFilterRanges);
32617
+ /**
32618
+ * Runtime schema for {@link ExploreMarketsIteratorParams}.
32619
+ *
32620
+ * Identical to {@link exploreMarketsParamsSchema} minus `pageAfter`: the
32621
+ * iterator owns the cursor and advances through pages itself.
32622
+ *
32623
+ * @example
32624
+ * ```typescript
32625
+ * import { exploreMarketsIteratorParamsSchema } from '@circle-fin/borrow-kit'
32626
+ *
32627
+ * const result = exploreMarketsIteratorParamsSchema.safeParse({
32628
+ * chain: 'Arc_Testnet',
32629
+ * sortBy: 'borrowApy',
32630
+ * })
32631
+ * ```
32632
+ */ exploreMarketsParamsBase.omit({
32633
+ pageAfter: true
32634
+ }).superRefine(refineFilterRanges);
32635
+ /** Runtime schema for {@link WithdrawCollateralParams}. */ withdrawCollateralQuoteParamsSchema.omit({
32636
+ chain: true
32637
+ }).extend({
32638
+ idempotencyKey: idempotencyKeySchema.optional(),
32639
+ from: borrowExecutionFromSchema
32640
+ });
32641
+ /** Runtime schema for {@link AddCollateralQuoteParams}. */ const addCollateralQuoteParamsSchema = z.object({
32642
+ loanId: z.string().uuid(),
32643
+ chain: chainIdentifierSchema,
32644
+ collateralAmount: collateralAmountSchema,
32645
+ config: borrowServiceConfigSchema.optional()
32646
+ }).strict();
32647
+ /** Runtime schema for {@link AddCollateralParams}. */ addCollateralQuoteParamsSchema.omit({
32648
+ chain: true
32649
+ }).extend({
32650
+ idempotencyKey: idempotencyKeySchema.optional(),
32651
+ from: borrowExecutionFromSchema
32652
+ });
32653
+
31002
32654
  /** SDK name used in telemetry payloads. */ resolveKitSdkName(pkg.name);
31003
32655
 
31004
32656
  // Auto-register this kit for user agent tracking