@circle-fin/app-kit 1.15.3 → 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 (57) hide show
  1. package/CHANGELOG.md +53 -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 +1885 -276
  11. package/bridge.d.cts +86 -12
  12. package/bridge.d.mts +86 -12
  13. package/bridge.d.ts +86 -12
  14. package/bridge.mjs +1885 -276
  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 +86 -12
  22. package/context.d.mts +86 -12
  23. package/context.d.ts +86 -12
  24. package/context.mjs +1 -0
  25. package/earn.cjs +4981 -3314
  26. package/earn.d.cts +1117 -981
  27. package/earn.d.mts +1117 -981
  28. package/earn.d.ts +1117 -981
  29. package/earn.mjs +4981 -3314
  30. package/estimateBridge.cjs +1883 -274
  31. package/estimateBridge.d.cts +86 -12
  32. package/estimateBridge.d.mts +86 -12
  33. package/estimateBridge.d.ts +86 -12
  34. package/estimateBridge.mjs +1883 -274
  35. package/estimateSwap.cjs +8554 -6931
  36. package/estimateSwap.d.cts +86 -12
  37. package/estimateSwap.d.mts +86 -12
  38. package/estimateSwap.d.ts +86 -12
  39. package/estimateSwap.mjs +8503 -6880
  40. package/index.cjs +30943 -18928
  41. package/index.d.cts +23051 -2742
  42. package/index.d.mts +23051 -2742
  43. package/index.d.ts +23051 -2742
  44. package/index.mjs +30884 -18922
  45. package/package.json +17 -7
  46. package/server.cjs +101 -6
  47. package/server.mjs +101 -6
  48. package/swap.cjs +8554 -6931
  49. package/swap.d.cts +86 -12
  50. package/swap.d.mts +86 -12
  51. package/swap.d.ts +86 -12
  52. package/swap.mjs +8503 -6880
  53. package/unifiedBalance.cjs +457 -128
  54. package/unifiedBalance.d.cts +108 -11
  55. package/unifiedBalance.d.mts +108 -11
  56. package/unifiedBalance.d.ts +108 -11
  57. package/unifiedBalance.mjs +457 -128
package/bridge.cjs CHANGED
@@ -1367,6 +1367,34 @@ let activeRedactor = defaultMessageRedactor;
1367
1367
  return redactErrorMessage(String(error));
1368
1368
  }
1369
1369
 
1370
+ /**
1371
+ * Render an object value for an error message without letting the rendering
1372
+ * itself throw.
1373
+ *
1374
+ * `JSON.stringify` rejects `BigInt` and circular structures, and a rejected
1375
+ * value is exactly the kind of thing a validation error is built from: an
1376
+ * on-chain read or a receipt log carries `bigint` fields, so serializing one
1377
+ * naively replaces the intended error with a `TypeError`.
1378
+ *
1379
+ * @param value - The value to render.
1380
+ * @returns A JSON string with `bigint` fields stringified, or
1381
+ * `'[unserializable object]'` if serialization still fails.
1382
+ * @throws Never; serialization failures are caught and rendered as a fallback string.
1383
+ * @example
1384
+ * ```typescript
1385
+ * import { describeObjectValue } from '@core/errors'
1386
+ *
1387
+ * describeObjectValue({ amount: 1n })
1388
+ * // '{"amount":"1"}'
1389
+ * ```
1390
+ */ function describeObjectValue(value) {
1391
+ try {
1392
+ return JSON.stringify(value, (_key, entry)=>typeof entry === 'bigint' ? entry.toString() : entry);
1393
+ } catch {
1394
+ return '[unserializable object]';
1395
+ }
1396
+ }
1397
+
1370
1398
  /**
1371
1399
  * Creates error for network type mismatch between source and destination.
1372
1400
  *
@@ -1629,7 +1657,7 @@ let activeRedactor = defaultMessageRedactor;
1629
1657
  * // Message: "Validation failed for 'chainId': 999 - Unsupported chain ID"
1630
1658
  *
1631
1659
  * throw createValidationFailedError('config', { invalid: true }, 'Missing required properties')
1632
- * // Message: "Validation failed for 'config': [object Object] - Missing required properties"
1660
+ * // Message: "Validation failed for 'config': {"invalid":true} - Missing required properties"
1633
1661
  * ```
1634
1662
  */ function createValidationFailedError$1(field, value, reason) {
1635
1663
  // Convert value to string for display, handling different types appropriately
@@ -1637,7 +1665,7 @@ let activeRedactor = defaultMessageRedactor;
1637
1665
  if (typeof value === 'string') {
1638
1666
  valueString = `'${value}'`;
1639
1667
  } else if (typeof value === 'object' && value !== null) {
1640
- valueString = JSON.stringify(value);
1668
+ valueString = describeObjectValue(value);
1641
1669
  } else {
1642
1670
  valueString = String(value);
1643
1671
  }
@@ -3135,6 +3163,105 @@ let activeRedactor = defaultMessageRedactor;
3135
3163
  return chain;
3136
3164
  }
3137
3165
 
3166
+ /**
3167
+ * Extracts the HTTP status code from an error message.
3168
+ *
3169
+ * Attempts to parse HTTP status codes from common error message formats,
3170
+ * such as "HTTP 404" or "Status: 500".
3171
+ *
3172
+ * Shared by `parseApiError` and the backend-error-code parsers that route on
3173
+ * status when no backend code is available, so all of them recognise the same
3174
+ * message shapes.
3175
+ *
3176
+ * @param msg - The error message to extract from
3177
+ * @returns The extracted HTTP status code, or null if not found
3178
+ *
3179
+ * @example
3180
+ * ```typescript
3181
+ * const code = extractHttpStatusCode('HTTP 404')
3182
+ * // Returns: 404
3183
+ * ```
3184
+ *
3185
+ * @example
3186
+ * ```typescript
3187
+ * const code = extractHttpStatusCode('Status: 500 Internal Server Error')
3188
+ * // Returns: 500
3189
+ * ```
3190
+ *
3191
+ * @internal
3192
+ */ function extractHttpStatusCode(msg) {
3193
+ // Pattern: "HTTP 404" or "HTTP 404 - some message" or "Status: 404"
3194
+ const patterns = [
3195
+ /HTTP (\d{3})/i,
3196
+ /Status:\s*(\d{3})/i,
3197
+ /^(\d{3}) -/
3198
+ ];
3199
+ for (const pattern of patterns){
3200
+ const match = pattern.exec(msg);
3201
+ const codeStr = match?.at(1);
3202
+ if (codeStr !== undefined) {
3203
+ const code = Number.parseInt(codeStr, 10);
3204
+ // Validate it's a valid HTTP status code
3205
+ if (code >= 100 && code < 600) {
3206
+ return code;
3207
+ }
3208
+ }
3209
+ }
3210
+ return null;
3211
+ }
3212
+
3213
+ /**
3214
+ * Type guard that narrows an unknown error to one carrying a non-null
3215
+ * object `responseBody` property (attached by `makeApiRequest`).
3216
+ *
3217
+ * Shared by backend-error-code parsers (`parseEarnApiError`,
3218
+ * `parseBorrowApiError`) so the narrowing logic lives in one place.
3219
+ *
3220
+ * @param error - The raw error from the HTTP layer
3221
+ * @returns `true` when `error.responseBody` is a non-null object
3222
+ * @internal
3223
+ */ function hasResponseBody(error) {
3224
+ return typeof error === 'object' && error !== null && 'responseBody' in error && typeof error['responseBody'] === 'object' && error['responseBody'] !== null;
3225
+ }
3226
+ /**
3227
+ * Narrow an unknown value to a non-null object.
3228
+ *
3229
+ * @param value - The value to check
3230
+ * @returns `true` when `value` is a non-null object
3231
+ * @internal
3232
+ */ function isRecord(value) {
3233
+ return typeof value === 'object' && value !== null;
3234
+ }
3235
+ /**
3236
+ * Read the machine-readable error fields (`code`, `message`,
3237
+ * `externalMessage`) that a Circle service attaches to an HTTP error body.
3238
+ *
3239
+ * `platform-common-go` serializes app-thrown errors under a nested envelope —
3240
+ * `{ response: { status: { code, message, externalMessage } } }` — for every
3241
+ * HTTP status, so this returns that inner `response.status` object when
3242
+ * present. It otherwise falls back to the top-level body so a flattened shape
3243
+ * (e.g. the stablecoin-kits-proxy) is still read. Callers read
3244
+ * `code` / `message` / `externalMessage` off the returned object uniformly.
3245
+ *
3246
+ * @param error - The raw error from the HTTP layer
3247
+ * @returns The error-status fields, or `undefined` when the error carries no
3248
+ * response body
3249
+ * @internal
3250
+ */ function extractResponseBody$1(error) {
3251
+ if (!hasResponseBody(error)) {
3252
+ return undefined;
3253
+ }
3254
+ const body = error.responseBody;
3255
+ const response = body['response'];
3256
+ if (isRecord(response)) {
3257
+ const status = response['status'];
3258
+ if (isRecord(status)) {
3259
+ return status;
3260
+ }
3261
+ }
3262
+ return body;
3263
+ }
3264
+
3138
3265
  /**
3139
3266
  * Proxy-specific structured error codes carried in `responseBody.code`.
3140
3267
  *
@@ -3435,29 +3562,22 @@ let activeRedactor = defaultMessageRedactor;
3435
3562
  });
3436
3563
  }
3437
3564
  /**
3438
- * Type guard that narrows an unknown error to one carrying a non-null
3439
- * object `responseBody` property (attached by `makeApiRequest`).
3565
+ * Extract the machine-readable error fields that `makeApiRequest` attaches to
3566
+ * HTTP error instances.
3440
3567
  *
3441
- * @param error - The raw error from the HTTP layer
3442
- * @returns `true` when `error.responseBody` is a non-null object
3443
- * @internal
3444
- */ function hasResponseBody(error) {
3445
- return typeof error === 'object' && error !== null && 'responseBody' in error && typeof error['responseBody'] === 'object' && error['responseBody'] !== null;
3446
- }
3447
- /**
3448
- * Extract the `responseBody` property that `makeApiRequest` attaches to
3449
- * HTTP error instances when the server returns a JSON body.
3568
+ * Delegates to the shared extractor so this fall-through path reads the same
3569
+ * shape as the backend-code parsers: it unwraps the nested
3570
+ * `{ response: { status } }` envelope when present, otherwise returns the
3571
+ * top-level body. Routing both halves through one extractor keeps an
3572
+ * unmapped-code error from losing the server's `externalMessage`.
3450
3573
  *
3451
3574
  * @param error - The raw error from the HTTP layer
3452
- * @returns The parsed body cast to {@link ApiErrorResponseBody}, or undefined
3575
+ * @returns The parsed body as {@link ApiErrorResponseBody}, or undefined
3453
3576
  * @throws Never. Returns `undefined` when the error does not carry a valid
3454
3577
  * `responseBody`.
3455
3578
  * @internal
3456
3579
  */ function extractResponseBody(error) {
3457
- if (!hasResponseBody(error)) {
3458
- return undefined;
3459
- }
3460
- return error.responseBody;
3580
+ return extractResponseBody$1(error);
3461
3581
  }
3462
3582
  /**
3463
3583
  * Extract a field name from an {@link ApiFieldError}.
@@ -3566,46 +3686,6 @@ let activeRedactor = defaultMessageRedactor;
3566
3686
  }
3567
3687
  return topMessage ?? fieldDetail;
3568
3688
  }
3569
- /**
3570
- * Extracts the HTTP status code from an error message.
3571
- *
3572
- * Attempts to parse HTTP status codes from common error message formats,
3573
- * such as "HTTP 404" or "Status: 500".
3574
- *
3575
- * @param msg - The error message to extract from
3576
- * @returns The extracted HTTP status code, or null if not found
3577
- *
3578
- * @example
3579
- * ```typescript
3580
- * const code = extractHttpStatusCode('HTTP 404')
3581
- * // Returns: 404
3582
- * ```
3583
- *
3584
- * @example
3585
- * ```typescript
3586
- * const code = extractHttpStatusCode('Status: 500 Internal Server Error')
3587
- * // Returns: 500
3588
- * ```
3589
- */ function extractHttpStatusCode(msg) {
3590
- // Pattern: "HTTP 404" or "HTTP 404 - some message" or "Status: 404"
3591
- const patterns = [
3592
- /HTTP (\d{3})/i,
3593
- /Status:\s*(\d{3})/i,
3594
- /^(\d{3}) -/
3595
- ];
3596
- for (const pattern of patterns){
3597
- const match = pattern.exec(msg);
3598
- const codeStr = match?.at(1);
3599
- if (codeStr !== undefined) {
3600
- const code = Number.parseInt(codeStr, 10);
3601
- // Validate it's a valid HTTP status code
3602
- if (code >= 100 && code < 600) {
3603
- return code;
3604
- }
3605
- }
3606
- }
3607
- return null;
3608
- }
3609
3689
 
3610
3690
  /**
3611
3691
  * @packageDocumentation
@@ -3861,6 +3941,11 @@ var EarnChain;
3861
3941
  "Arc",
3862
3942
  "Arc_Testnet"
3863
3943
  ];
3944
+ var BorrowChain;
3945
+ (function(BorrowChain) {
3946
+ BorrowChain["Arc"] = "Arc";
3947
+ BorrowChain["Arc_Testnet"] = "Arc_Testnet";
3948
+ })(BorrowChain || (BorrowChain = {}));
3864
3949
 
3865
3950
  /**
3866
3951
  * Helper function to define a chain with proper TypeScript typing.
@@ -4203,6 +4288,29 @@ var EarnChain;
4203
4288
  * on EVM-compatible testnet chains. Use this address for testnet adapter
4204
4289
  * integrations (e.g., Arc Testnet).
4205
4290
  */ const ADAPTER_CONTRACT_EVM_TESTNET = '0xBBD70b01a1CAbc96d5b7b129Ae1AAabdf50dd40b';
4291
+ /**
4292
+ * The sender-preserving batching contract on Arc (`Multicall3From`).
4293
+ *
4294
+ * This predeploy batches calls like the ubiquitous Multicall3, but routes each
4295
+ * subcall through Arc's `CallFrom` precompile
4296
+ * (`0x1800000000000000000000000000000000000003`), which executes on behalf of
4297
+ * the transaction's original sender. Every target therefore sees the calling
4298
+ * EOA as `msg.sender`, which is what makes a plain, un-upgraded EOA capable of
4299
+ * an atomic batch on Arc.
4300
+ *
4301
+ * Deployed at the same address on Arc Testnet and Arc Mainnet.
4302
+ *
4303
+ * @see https://docs.arc.io/arc/concepts/batched-transactions
4304
+ */ const BATCHER_CONTRACT_ARC_TESTNET = '0x522fAf9A91c41c443c66765030741e4AaCe147D0';
4305
+ /**
4306
+ * The sender-preserving batching contract on Arc Mainnet (`Multicall3From`).
4307
+ *
4308
+ * See {@link BATCHER_CONTRACT_ARC_TESTNET} for how this contract works.
4309
+ * Requires Arc's Zero7 hardfork, which activates the `CallFrom` precompile
4310
+ * this contract depends on.
4311
+ *
4312
+ * @see https://docs.arc.io/arc/concepts/batched-transactions
4313
+ */ const BATCHER_CONTRACT_ARC_MAINNET = '0x522fAf9A91c41c443c66765030741e4AaCe147D0';
4206
4314
  /**
4207
4315
  * The GatewayWallet contract address for EVM mainnet networks.
4208
4316
  *
@@ -4342,7 +4450,10 @@ var EarnChain;
4342
4450
  },
4343
4451
  kitContracts: {
4344
4452
  bridge: BRIDGE_CONTRACT_EVM_MAINNET,
4345
- adapter: ADAPTER_CONTRACT_EVM_MAINNET
4453
+ adapter: ADAPTER_CONTRACT_EVM_MAINNET,
4454
+ // Arc is the only chain with a sender-preserving batcher, because it
4455
+ // takes a precompile rather than an ordinary contract to build one.
4456
+ senderPreservingBatcher: BATCHER_CONTRACT_ARC_MAINNET
4346
4457
  },
4347
4458
  gateway: {
4348
4459
  domain: 26,
@@ -4413,7 +4524,10 @@ var EarnChain;
4413
4524
  },
4414
4525
  kitContracts: {
4415
4526
  bridge: BRIDGE_CONTRACT_EVM_TESTNET,
4416
- adapter: ADAPTER_CONTRACT_EVM_TESTNET
4527
+ adapter: ADAPTER_CONTRACT_EVM_TESTNET,
4528
+ // Arc is the only chain with a sender-preserving batcher, because it
4529
+ // takes a precompile rather than an ordinary contract to build one.
4530
+ senderPreservingBatcher: BATCHER_CONTRACT_ARC_TESTNET
4417
4531
  },
4418
4532
  gateway: {
4419
4533
  domain: 26,
@@ -8083,7 +8197,8 @@ var Chains = {
8083
8197
  cctpx: zod.z.any().optional(),
8084
8198
  kitContracts: zod.z.object({
8085
8199
  bridge: zod.z.string().optional(),
8086
- adapter: zod.z.string().optional()
8200
+ adapter: zod.z.string().optional(),
8201
+ senderPreservingBatcher: zod.z.string().optional()
8087
8202
  }).optional(),
8088
8203
  gateway: gatewayConfigSchema.optional()
8089
8204
  });
@@ -8279,6 +8394,38 @@ var Chains = {
8279
8394
  message: `"${chain.chain}" is not a supported earn chain. ` + `Supported chains: ${Object.values(EarnChain).join(', ')}`
8280
8395
  }))
8281
8396
  ]);
8397
+ /**
8398
+ * Zod schema for validating Borrow-specific chain identifiers.
8399
+ *
8400
+ * Validate that the provided chain is supported for Borrow Kit's loan
8401
+ * operations. Unlike {@link earnChainIdentifierSchema}, this includes Arc
8402
+ * mainnet as well as Arc Testnet.
8403
+ *
8404
+ * Accept a BorrowChain enum value, a matching string literal, or a
8405
+ * ChainDefinition for a supported chain.
8406
+ *
8407
+ * @example
8408
+ * ```typescript
8409
+ * import { borrowChainIdentifierSchema } from '@core/chains'
8410
+ * import { Arc, BorrowChain } from '@core/chains'
8411
+ *
8412
+ * // Valid
8413
+ * borrowChainIdentifierSchema.parse(BorrowChain.Arc)
8414
+ * borrowChainIdentifierSchema.parse('Arc')
8415
+ * borrowChainIdentifierSchema.parse(Arc)
8416
+ *
8417
+ * // Invalid (throws ZodError)
8418
+ * borrowChainIdentifierSchema.parse('Solana')
8419
+ * ```
8420
+ */ const borrowChainIdentifierSchema = zod.z.union([
8421
+ zod.z.string().refine((val)=>val in BorrowChain, (val)=>({
8422
+ message: `"${val}" is not a supported borrow chain. ` + `Supported chains: ${Object.values(BorrowChain).join(', ')}`
8423
+ })),
8424
+ zod.z.nativeEnum(BorrowChain),
8425
+ chainDefinitionSchema$2.refine((chain)=>chain.chain in BorrowChain, (chain)=>({
8426
+ message: `"${chain.chain}" is not a supported borrow chain. ` + `Supported chains: ${Object.values(BorrowChain).join(', ')}`
8427
+ }))
8428
+ ]);
8282
8429
  // Widened views so `.includes()` accepts arbitrary strings under strict TS.
8283
8430
  const EARN_BRIDGE_SOURCE_CHAIN_VALUES = EARN_BRIDGE_SOURCE_BLOCKCHAINS;
8284
8431
  const EARN_BRIDGE_DESTINATION_CHAIN_VALUES = EARN_BRIDGE_DESTINATION_BLOCKCHAINS;
@@ -8489,8 +8636,13 @@ const swapTokenEnumSchema = zod.z.enum([
8489
8636
  */ function resolveChainName(value) {
8490
8637
  if (value == null) return undefined;
8491
8638
  if (typeof value === 'string') return value;
8492
- if (typeof value === 'object' && 'chain' in value && typeof value.chain === 'string') {
8493
- return value.chain;
8639
+ try {
8640
+ if (typeof value === 'object' && 'chain' in value) {
8641
+ const chain = value.chain;
8642
+ if (typeof chain === 'string') return chain;
8643
+ }
8644
+ } catch {
8645
+ return undefined;
8494
8646
  }
8495
8647
  return undefined;
8496
8648
  }
@@ -9198,6 +9350,7 @@ const swapTokenEnumSchema = zod.z.enum([
9198
9350
  * - Retries on rate limiting (429)
9199
9351
  * - Does not retry on client errors (4xx, except 429)
9200
9352
  * - Does not retry on validation failures
9353
+ * - Does not retry when `config.isTerminalError` marks the error terminal
9201
9354
  *
9202
9355
  * Each HTTP request is given a configurable timeout before it is aborted.
9203
9356
  * Between retry attempts the wait depends on the `backoff` strategy. The
@@ -9277,7 +9430,10 @@ const swapTokenEnumSchema = zod.z.enum([
9277
9430
  return await makeApiRequest(url, method, isValidType, effectiveConfig, body);
9278
9431
  } catch (err) {
9279
9432
  const error = err instanceof Error ? err : new Error(String(err));
9280
- if (!isRetryableError(error)) {
9433
+ // A caller-supplied predicate can mark an error terminal (e.g. a
9434
+ // deterministic 404) so it is surfaced immediately instead of burning
9435
+ // the retry budget on a non-transient answer.
9436
+ if (effectiveConfig.isTerminalError?.(error) === true || !isRetryableError(error)) {
9281
9437
  throw error;
9282
9438
  }
9283
9439
  lastError = error;
@@ -9361,7 +9517,24 @@ const swapTokenEnumSchema = zod.z.enum([
9361
9517
  * // After this call, TypeScript knows params is of type BridgeParams
9362
9518
  * ```
9363
9519
  */ function validate(value, schema, context) {
9364
- const result = schema.safeParse(value);
9520
+ let result;
9521
+ try {
9522
+ result = schema.safeParse(value);
9523
+ } catch (error) {
9524
+ throw new KitError({
9525
+ ...InputError.VALIDATION_FAILED,
9526
+ recoverability: 'FATAL',
9527
+ message: `Invalid ${context}: reading a property threw`,
9528
+ cause: {
9529
+ trace: {
9530
+ validationErrors: [
9531
+ 'Reading a property of the value threw'
9532
+ ],
9533
+ originalError: error
9534
+ }
9535
+ }
9536
+ });
9537
+ }
9365
9538
  if (!result.success) {
9366
9539
  throw createValidationErrorFromZod(result.error, context);
9367
9540
  }
@@ -12062,11 +12235,11 @@ function resolveOptions(options) {
12062
12235
  void emitAnalyticsLog(buildPayload(config, stepEntry?.[1] ?? fallbackEventType, errorDetails, context));
12063
12236
  }
12064
12237
 
12065
- var name$2 = "@circle-fin/bridge-kit";
12066
- var version$3 = "1.15.1";
12067
- var pkg$3 = {
12068
- name: name$2,
12069
- version: version$3};
12238
+ var name$3 = "@circle-fin/bridge-kit";
12239
+ var version$4 = "1.15.2";
12240
+ var pkg$4 = {
12241
+ name: name$3,
12242
+ version: version$4};
12070
12243
 
12071
12244
  const assertCustomFeePolicySymbol = Symbol('assertCustomFeePolicy');
12072
12245
  /**
@@ -12635,6 +12808,12 @@ const READ_ACTION_KEY_SET = new Set(READ_ACTION_KEYS);
12635
12808
  /** EIP-2612 standard permit */ PermitType[PermitType["EIP2612"] = 1] = "EIP2612";
12636
12809
  })(PermitType || (PermitType = {}));
12637
12810
 
12811
+ var BorrowPermitType;
12812
+ (function(BorrowPermitType) {
12813
+ /** Tokens must be approved separately. */ BorrowPermitType[BorrowPermitType["NONE"] = 0] = "NONE";
12814
+ /** EIP-2612 permit calldata accompanies the token input. */ BorrowPermitType[BorrowPermitType["EIP2612"] = 1] = "EIP2612";
12815
+ })(BorrowPermitType || (BorrowPermitType = {}));
12816
+
12638
12817
  /**
12639
12818
  * Abstract base class for bridging providers that implement cross-chain bridging protocols.
12640
12819
  *
@@ -19758,7 +19937,7 @@ const defaultSleep = async (ms)=>new Promise((resolve)=>setTimeout(resolve, ms))
19758
19937
  * Must always contain both adapter and chain explicitly.
19759
19938
  *
19760
19939
  * Optionally includes address for developer-controlled adapters.
19761
- */ const adapterContextSchema$3 = zod.z.object({
19940
+ */ const adapterContextSchema$4 = zod.z.object({
19762
19941
  adapter: adapterSchema,
19763
19942
  chain: bridgeChainIdentifierSchema,
19764
19943
  address: zod.z.string().optional()
@@ -19767,14 +19946,14 @@ const defaultSleep = async (ms)=>new Promise((resolve)=>setTimeout(resolve, ms))
19767
19946
  * Schema for validating BridgeDestinationWithAddress objects.
19768
19947
  * Contains an explicit recipientAddress along with adapter and chain.
19769
19948
  * The address format is validated based on the chain type (EVM or Solana).
19770
- */ const bridgeDestinationWithAddressSchema = adapterContextSchema$3.extend({
19949
+ */ const bridgeDestinationWithAddressSchema = adapterContextSchema$4.extend({
19771
19950
  recipientAddress: zod.z.string().min(1, 'Recipient address is required'),
19772
19951
  useForwarder: zod.z.boolean().optional()
19773
19952
  }).superRefine(createRecipientAddressValidator());
19774
19953
  /**
19775
19954
  * Schema for validating AdapterContext with optional useForwarder.
19776
19955
  * Extends adapterContextSchema with the useForwarder flag.
19777
- */ const adapterContextWithForwarderSchema = adapterContextSchema$3.extend({
19956
+ */ const adapterContextWithForwarderSchema = adapterContextSchema$4.extend({
19778
19957
  useForwarder: zod.z.boolean().optional()
19779
19958
  });
19780
19959
  /**
@@ -19849,7 +20028,7 @@ const defaultSleep = async (ms)=>new Promise((resolve)=>setTimeout(resolve, ms))
19849
20028
  * }
19850
20029
  * ```
19851
20030
  */ const bridgeParamsWithChainIdentifierSchema = zod.z.object({
19852
- from: adapterContextSchema$3.strict(),
20031
+ from: adapterContextSchema$4.strict(),
19853
20032
  to: bridgeDestinationSchema,
19854
20033
  amount: zod.z.string().min(1, 'Required').pipe(createDecimalStringValidator({
19855
20034
  allowZero: false,
@@ -20009,7 +20188,7 @@ const defaultSleep = async (ms)=>new Promise((resolve)=>setTimeout(resolve, ms))
20009
20188
  const bridgeKitCaller = {
20010
20189
  type: 'kit',
20011
20190
  name: 'BridgeKit',
20012
- version: pkg$3.version
20191
+ version: pkg$4.version
20013
20192
  };
20014
20193
  // Create default runtime and tokens for invocation context resolution
20015
20194
  const defaults = {
@@ -23228,16 +23407,16 @@ const mockAttestationMessage = {
23228
23407
  return step;
23229
23408
  }
23230
23409
 
23231
- var version$2 = "1.14.0";
23232
- var pkg$2 = {
23233
- version: version$2};
23410
+ var version$3 = "1.14.1";
23411
+ var pkg$3 = {
23412
+ version: version$3};
23234
23413
 
23235
23414
  /**
23236
23415
  * Provider caller component for bridge operations.
23237
23416
  */ const BRIDGE_CALLER = {
23238
23417
  type: 'provider',
23239
23418
  name: 'CCTPV2BridgingProvider.bridge',
23240
- version: pkg$2.version
23419
+ version: pkg$3.version
23241
23420
  };
23242
23421
  /**
23243
23422
  * Resolve invocation context for bridge operations.
@@ -23610,7 +23789,7 @@ var pkg$2 = {
23610
23789
  */ const RETRY_CALLER = {
23611
23790
  type: 'provider',
23612
23791
  name: 'CCTPV2BridgingProvider.retry',
23613
- version: pkg$2.version
23792
+ version: pkg$3.version
23614
23793
  };
23615
23794
  /**
23616
23795
  * Resolve invocation context for retry operations.
@@ -25537,7 +25716,7 @@ function assertCCTPV2Config(config) {
25537
25716
  * Decimal string in token minor units, constrained to be strictly positive.
25538
25717
  *
25539
25718
  * @internal
25540
- */ const positiveAmountSchema = zod.z.string().regex(/^\d+$/, 'must be a non-negative integer string')// Re-check the digit shape here: zod still runs this refinement when the
25719
+ */ const positiveAmountSchema$1 = zod.z.string().regex(/^\d+$/, 'must be a non-negative integer string')// Re-check the digit shape here: zod still runs this refinement when the
25541
25720
  // regex check above fails ("dirty"), so guard BigInt() against throwing on a
25542
25721
  // non-numeric value before comparing.
25543
25722
  .refine((value)=>/^\d+$/.test(value) && BigInt(value) > 0n, 'must be greater than zero');
@@ -25617,7 +25796,7 @@ const preFinalityRequestSchema = zod.z.object({
25617
25796
  */ const fetchFeeQuoteInputSchema = zod.z.object({
25618
25797
  sourceDomain: zod.z.number().int().nonnegative(),
25619
25798
  destinationDomain: zod.z.number().int().nonnegative(),
25620
- amount: positiveAmountSchema,
25799
+ amount: positiveAmountSchema$1,
25621
25800
  feeToken: evmAddressSchema.optional(),
25622
25801
  requests: feeQuoteRequestsSchema,
25623
25802
  isTestnet: zod.z.boolean(),
@@ -26494,7 +26673,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
26494
26673
  * The ERC-20 `decimals` field is a `uint8`, so a provider reporting more than
26495
26674
  * this is returning something that cannot describe a real token.
26496
26675
  */ const MAX_TOKEN_DECIMALS = 255;
26497
- /** SDK name used in telemetry payloads. */ const SDK_NAME = resolveKitSdkName(pkg$3.name);
26676
+ /** SDK name used in telemetry payloads. */ const SDK_NAME = resolveKitSdkName(pkg$4.name);
26498
26677
  /**
26499
26678
  * Pick the most-relevant `txHash` to attach to an error telemetry payload.
26500
26679
  *
@@ -26535,7 +26714,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
26535
26714
  */ const BRIDGE_KIT_CALLER = {
26536
26715
  type: 'kit',
26537
26716
  name: 'BridgeKit',
26538
- version: pkg$3.version
26717
+ version: pkg$4.version
26539
26718
  };
26540
26719
  /**
26541
26720
  * Merge BridgeKit's caller into the invocation metadata for retry operations.
@@ -26683,7 +26862,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
26683
26862
  this.disableErrorReporting = config.disableErrorReporting === true;
26684
26863
  this.telemetryConfig = {
26685
26864
  sdkName: SDK_NAME,
26686
- sdkVersion: pkg$3.version,
26865
+ sdkVersion: pkg$4.version,
26687
26866
  disabled: this.disableErrorReporting
26688
26867
  };
26689
26868
  for (const provider of this.providers){
@@ -27407,7 +27586,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
27407
27586
  }
27408
27587
 
27409
27588
  // Auto-register this kit for user agent tracking
27410
- registerKit(`${pkg$3.name}/${pkg$3.version}`);
27589
+ registerKit(`${pkg$4.name}/${pkg$4.version}`);
27411
27590
 
27412
27591
  /**
27413
27592
  * Create a BridgeKit instance with optional developer fee configuration.
@@ -27478,11 +27657,11 @@ registerKit(`${pkg$3.name}/${pkg$3.version}`);
27478
27657
  return kit;
27479
27658
  };
27480
27659
 
27481
- var name$1 = "@circle-fin/swap-kit";
27482
- var version$1 = "1.7.0";
27483
- var pkg$1 = {
27484
- name: name$1,
27485
- version: version$1};
27660
+ var name$2 = "@circle-fin/swap-kit";
27661
+ var version$2 = "1.7.1";
27662
+ var pkg$2 = {
27663
+ name: name$2,
27664
+ version: version$2};
27486
27665
 
27487
27666
  const chainIdentifierField = zod.z.custom((value)=>chainIdentifierSchema.safeParse(value).success, {
27488
27667
  message: 'chain must be a valid chain identifier'
@@ -27563,7 +27742,7 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
27563
27742
  *
27564
27743
  * @remarks
27565
27744
  * Optionally includes address for developer-controlled adapters.
27566
- */ const adapterContextSchema$2 = zod.z.object({
27745
+ */ const adapterContextSchema$3 = zod.z.object({
27567
27746
  adapter: adapterSchema,
27568
27747
  chain: chainIdentifierField,
27569
27748
  address: zod.z.string().optional()
@@ -27584,7 +27763,7 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
27584
27763
  * }
27585
27764
  * ```
27586
27765
  */ zod.z.object({
27587
- from: adapterContextSchema$2,
27766
+ from: adapterContextSchema$3,
27588
27767
  tokenIn: zod.z.string({
27589
27768
  required_error: 'tokenIn is required',
27590
27769
  invalid_type_error: 'tokenIn must be a string'
@@ -28312,36 +28491,176 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
28312
28491
  return normalize(source.apiKey) ?? normalize(source.kitKey);
28313
28492
  };
28314
28493
 
28494
+ function isBigIntLike$1(value) {
28495
+ try {
28496
+ BigInt(value);
28497
+ return true;
28498
+ } catch {
28499
+ return false;
28500
+ }
28501
+ }
28502
+ function isNonNegativeBigIntLike$3(value) {
28503
+ try {
28504
+ return BigInt(value) >= 0n;
28505
+ } catch {
28506
+ return false;
28507
+ }
28508
+ }
28315
28509
  /**
28316
- * Zod schema for validating EVM adapter capabilities.
28510
+ * A `0x`-prefixed, even-length hex byte string (`'0x'` for empty calldata).
28317
28511
  *
28318
- * This schema ensures that EVM adapter capabilities meet the requirements for the
28319
- * OperationContext pattern by validating the addressContext property and ensuring
28320
- * the supportedChains property contains only EVM-compatible chains.
28512
+ * @internal
28513
+ */ const hexBytesSchema$3 = zod.z.union([
28514
+ hexStringSchema,
28515
+ zod.z.literal('0x')
28516
+ ]).refine((value)=>value.length % 2 === 0, {
28517
+ message: 'value must be a 0x-prefixed even-length hex string'
28518
+ });
28519
+ /**
28520
+ * A non-negative uint256, accepted as a decimal string or a `bigint`.
28321
28521
  *
28322
- * @remarks
28323
- * This schema enforces that all supported chains are EVM type, making it specific
28324
- * to EVM adapters (Ethers, Viem, etc.). For non-EVM adapters, a different validation
28325
- * schema should be used.
28522
+ * @internal
28523
+ */ const uint256LikeSchema$3 = zod.z.union([
28524
+ zod.z.string(),
28525
+ zod.z.bigint()
28526
+ ]).refine(isNonNegativeBigIntLike$3, {
28527
+ message: 'value must be a non-negative bigint-compatible string or bigint'
28528
+ });
28529
+ /**
28530
+ * A typed base-unit amount object as emitted by the API.
28326
28531
  *
28327
- * When used with the validate() function from @core/utils, this throws KitError
28328
- * with INPUT_VALIDATION_FAILED code if validation fails, with details about which
28329
- * properties failed.
28532
+ * @internal
28533
+ */ const amountJsonSchema$2 = zod.z.object({
28534
+ raw: zod.z.string().refine(isBigIntLike$1, {
28535
+ message: 'raw must be a bigint-compatible string'
28536
+ }),
28537
+ decimals: zod.z.number().int().nonnegative()
28538
+ });
28539
+ /**
28540
+ * One instruction in a signed claim-rewards execution payload.
28330
28541
  *
28331
- * @example
28332
- * ```typescript
28333
- * import { AdapterCapabilitiesSchema } from '@core/adapter-evm/validation'
28334
- * import { Ethereum, Base } from '@core/chains'
28542
+ * `.passthrough()` so a backend that adds a field does not fail validation.
28335
28543
  *
28336
- * // Valid user-controlled capabilities
28337
- * const userCapabilities = {
28338
- * addressContext: 'user-controlled',
28339
- * supportedChains: [Ethereum, Base]
28340
- * }
28544
+ * @internal
28545
+ */ const claimRewardsInstructionSchema = zod.z.object({
28546
+ target: evmAddressSchema$1,
28547
+ data: hexBytesSchema$3,
28548
+ value: uint256LikeSchema$3,
28549
+ tokenIn: evmAddressSchema$1,
28550
+ amountToApprove: uint256LikeSchema$3,
28551
+ tokenOut: evmAddressSchema$1,
28552
+ minTokenOut: uint256LikeSchema$3
28553
+ }).passthrough();
28554
+ const claimRewardsTokenSchema = zod.z.object({
28555
+ token: evmAddressSchema$1,
28556
+ beneficiary: evmAddressSchema$1
28557
+ }).passthrough();
28558
+ /**
28559
+ * The signed execution payload the `earn.claimRewards` Adapter action takes.
28341
28560
  *
28342
- * // Valid developer-controlled capabilities
28343
- * const devCapabilities = {
28344
- * addressContext: 'developer-controlled',
28561
+ * @internal
28562
+ */ const claimRewardsExecutionParamsSchema = zod.z.object({
28563
+ instructions: zod.z.tuple([
28564
+ claimRewardsInstructionSchema
28565
+ ]).rest(claimRewardsInstructionSchema),
28566
+ tokens: zod.z.tuple([
28567
+ claimRewardsTokenSchema
28568
+ ]).rest(claimRewardsTokenSchema),
28569
+ execId: uint256LikeSchema$3,
28570
+ deadline: uint256LikeSchema$3,
28571
+ metadata: hexBytesSchema$3
28572
+ }).passthrough();
28573
+ /**
28574
+ * A single claimable reward entry in a claim-rewards response.
28575
+ *
28576
+ * @internal
28577
+ */ const claimedAmountSchema = zod.z.object({
28578
+ token: evmAddressSchema$1,
28579
+ symbol: zod.z.string(),
28580
+ amount: amountJsonSchema$2
28581
+ });
28582
+ /**
28583
+ * The `data` envelope of a claim-rewards response.
28584
+ *
28585
+ * `executionParams` and `signature` are present exactly when rewards are
28586
+ * claimable — never one without the other, and never either when `rewards`
28587
+ * is empty.
28588
+ *
28589
+ * @internal
28590
+ */ const claimRewardsPayloadSchema = zod.z.object({
28591
+ rewards: zod.z.array(claimedAmountSchema),
28592
+ executionParams: claimRewardsExecutionParamsSchema.optional(),
28593
+ signature: evmSignatureSchema.optional()
28594
+ }).refine((data)=>{
28595
+ const signedFieldCount = (data.executionParams === undefined ? 0 : 1) + (data.signature === undefined ? 0 : 1);
28596
+ if (data.rewards.length > 0) {
28597
+ return signedFieldCount === 2;
28598
+ }
28599
+ return signedFieldCount === 0;
28600
+ }, {
28601
+ message: 'claim rewards response must include executionParams and signature only when rewards are claimable'
28602
+ });
28603
+ /**
28604
+ * Zod schema for a claim-rewards API response.
28605
+ *
28606
+ * @internal
28607
+ */ zod.z.object({
28608
+ data: claimRewardsPayloadSchema
28609
+ });
28610
+ /**
28611
+ * A single claimable reward entry in a claim-rewards quote response.
28612
+ *
28613
+ * @internal
28614
+ */ const claimRewardsQuoteRewardSchema = zod.z.object({
28615
+ token: zod.z.string(),
28616
+ symbol: zod.z.string(),
28617
+ amount: amountJsonSchema$2
28618
+ });
28619
+ /**
28620
+ * The `data` envelope of a claim-rewards quote response.
28621
+ *
28622
+ * @internal
28623
+ */ const claimRewardsQuotePayloadSchema = zod.z.object({
28624
+ rewards: zod.z.array(claimRewardsQuoteRewardSchema)
28625
+ });
28626
+ /**
28627
+ * Zod schema for a claim-rewards quote API response.
28628
+ *
28629
+ * @internal
28630
+ */ zod.z.object({
28631
+ data: claimRewardsQuotePayloadSchema
28632
+ });
28633
+
28634
+ /**
28635
+ * Zod schema for validating EVM adapter capabilities.
28636
+ *
28637
+ * This schema ensures that EVM adapter capabilities meet the requirements for the
28638
+ * OperationContext pattern by validating the addressContext property and ensuring
28639
+ * the supportedChains property contains only EVM-compatible chains.
28640
+ *
28641
+ * @remarks
28642
+ * This schema enforces that all supported chains are EVM type, making it specific
28643
+ * to EVM adapters (Ethers, Viem, etc.). For non-EVM adapters, a different validation
28644
+ * schema should be used.
28645
+ *
28646
+ * When used with the validate() function from @core/utils, this throws KitError
28647
+ * with INPUT_VALIDATION_FAILED code if validation fails, with details about which
28648
+ * properties failed.
28649
+ *
28650
+ * @example
28651
+ * ```typescript
28652
+ * import { AdapterCapabilitiesSchema } from '@core/adapter-evm/validation'
28653
+ * import { Ethereum, Base } from '@core/chains'
28654
+ *
28655
+ * // Valid user-controlled capabilities
28656
+ * const userCapabilities = {
28657
+ * addressContext: 'user-controlled',
28658
+ * supportedChains: [Ethereum, Base]
28659
+ * }
28660
+ *
28661
+ * // Valid developer-controlled capabilities
28662
+ * const devCapabilities = {
28663
+ * addressContext: 'developer-controlled',
28345
28664
  * supportedChains: [Ethereum]
28346
28665
  * }
28347
28666
  *
@@ -28739,7 +29058,7 @@ const abiParameterSchema = zod.z.object({
28739
29058
  * const result = evmPreparedChainRequestParamsSchema.safeParse(params)
28740
29059
  * ```
28741
29060
  */ zod.z.object({
28742
- type: zod.z.literal('evm'),
29061
+ type: zod.z.literal('evm').optional(),
28743
29062
  abi: abiSchema,
28744
29063
  address: evmAddressSchema$1,
28745
29064
  functionName: zod.z.string({
@@ -28856,7 +29175,7 @@ const abiParameterSchema = zod.z.object({
28856
29175
  message: 'Private key must be a valid 64-character hex string. Please provide a valid private key with or without "0x" prefix.'
28857
29176
  }));
28858
29177
 
28859
- const hexBytesSchema$1 = zod.z.string().regex(/^0x([0-9a-fA-F]{2})*$/, {
29178
+ const hexBytesSchema$2 = zod.z.string().regex(/^0x([0-9a-fA-F]{2})*$/, {
28860
29179
  message: 'value must be a 0x-prefixed even-length hex string'
28861
29180
  }).transform((value)=>value);
28862
29181
  zod.z.object({
@@ -28868,6 +29187,53 @@ zod.z.object({
28868
29187
  amount: zod.z.bigint().refine((value)=>value >= 0n, {
28869
29188
  message: 'amount must be a non-negative bigint'
28870
29189
  }),
29190
+ permitCalldata: hexBytesSchema$2
29191
+ }))
29192
+ }).passthrough();
29193
+
29194
+ const hexBytesSchema$1 = zod.z.string().regex(/^0x([0-9a-fA-F]{2})*$/, {
29195
+ message: 'value must be a 0x-prefixed even-length hex string'
29196
+ }).transform((value)=>value);
29197
+ function isNonNegativeBigIntLike$2(value) {
29198
+ try {
29199
+ return BigInt(value) >= 0n;
29200
+ } catch {
29201
+ return false;
29202
+ }
29203
+ }
29204
+ const uint256LikeSchema$2 = zod.z.union([
29205
+ zod.z.string(),
29206
+ zod.z.bigint()
29207
+ ]).refine(isNonNegativeBigIntLike$2, {
29208
+ message: 'value must be a non-negative bigint-compatible string or bigint'
29209
+ });
29210
+ const borrowExecutionParamsSchema$1 = zod.z.object({
29211
+ instructions: zod.z.array(zod.z.object({
29212
+ target: evmAddressSchema$1,
29213
+ data: hexBytesSchema$1,
29214
+ value: uint256LikeSchema$2,
29215
+ tokenIn: evmAddressSchema$1,
29216
+ amountToApprove: uint256LikeSchema$2,
29217
+ tokenOut: evmAddressSchema$1,
29218
+ minTokenOut: uint256LikeSchema$2
29219
+ }).passthrough()).min(1),
29220
+ tokens: zod.z.array(zod.z.object({
29221
+ token: evmAddressSchema$1,
29222
+ beneficiary: evmAddressSchema$1
29223
+ }).passthrough()),
29224
+ execId: uint256LikeSchema$2,
29225
+ deadline: uint256LikeSchema$2,
29226
+ metadata: hexBytesSchema$1
29227
+ }).passthrough();
29228
+ zod.z.object({
29229
+ executeParams: borrowExecutionParamsSchema$1,
29230
+ signature: evmSignatureSchema,
29231
+ tokenInputs: zod.z.array(zod.z.object({
29232
+ permitType: zod.z.nativeEnum(BorrowPermitType),
29233
+ token: evmAddressSchema$1,
29234
+ amount: zod.z.bigint().refine((value)=>value >= 0n, {
29235
+ message: 'amount must be a non-negative bigint'
29236
+ }),
28871
29237
  permitCalldata: hexBytesSchema$1
28872
29238
  }))
28873
29239
  }).passthrough();
@@ -29260,7 +29626,7 @@ const optionalSwapChainIdentifierField = swapChainIdentifierField.optional();
29260
29626
  * Schema for validating AdapterContext.
29261
29627
  * Must always contain both adapter and chain explicitly.
29262
29628
  * Optionally includes address for developer-controlled adapters.
29263
- */ const adapterContextSchema$1 = zod.z.object({
29629
+ */ const adapterContextSchema$2 = zod.z.object({
29264
29630
  adapter: adapterSchema,
29265
29631
  chain: swapChainIdentifierField,
29266
29632
  address: zod.z.string().optional()
@@ -29321,7 +29687,7 @@ const swapDestinationSchema = zod.z.object({
29321
29687
  message: 'recipientAddress must be a valid blockchain address: EVM (0x + 40 hex chars) or Solana (base58, 32-44 chars)'
29322
29688
  }).optional()
29323
29689
  }).strict();
29324
- const EVM_ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/;
29690
+ const EVM_ADDRESS_REGEX$1 = /^0x[a-fA-F0-9]{40}$/;
29325
29691
  const SOLANA_ADDRESS_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
29326
29692
  const BASE58_CHARS_REGEX = /^[1-9A-HJ-NP-Za-km-z]+$/;
29327
29693
  /**
@@ -29364,7 +29730,7 @@ const MAX_DISPLAY_LENGTH = 30;
29364
29730
  */ let _symbolResult;
29365
29731
  const swapTokenSchema = zod.z.string().superRefine((value, ctx)=>{
29366
29732
  if (value.startsWith('0x')) {
29367
- if (!EVM_ADDRESS_REGEX.test(value)) {
29733
+ if (!EVM_ADDRESS_REGEX$1.test(value)) {
29368
29734
  ctx.addIssue({
29369
29735
  code: zod.z.ZodIssueCode.custom,
29370
29736
  message: `Invalid EVM token address format. Expected '0x' followed by 40 hexadecimal characters, but received: '${truncate(value)}'`
@@ -29459,7 +29825,7 @@ const amountInSchema = zod.z.string().min(1, 'Required').pipe(createDecimalStrin
29459
29825
  * }
29460
29826
  * ```
29461
29827
  */ zod.z.object({
29462
- from: adapterContextSchema$1,
29828
+ from: adapterContextSchema$2,
29463
29829
  tokenIn: swapTokenSchema,
29464
29830
  tokenOut: swapTokenSchema,
29465
29831
  amountIn: amountInSchema,
@@ -29500,16 +29866,16 @@ new Set(Object.values(Blockchain));
29500
29866
 
29501
29867
  new Set(Object.values(Blockchain));
29502
29868
 
29503
- /** SDK name used in telemetry payloads. */ resolveKitSdkName(pkg$1.name);
29869
+ /** SDK name used in telemetry payloads. */ resolveKitSdkName(pkg$2.name);
29504
29870
 
29505
29871
  // Auto-register this kit for user agent tracking
29506
- registerKit(`${pkg$1.name}/${pkg$1.version}`);
29872
+ registerKit(`${pkg$2.name}/${pkg$2.version}`);
29507
29873
 
29508
- var name = "@circle-fin/earn-kit";
29509
- var version = "1.8.0";
29510
- var pkg = {
29511
- name: name,
29512
- version: version};
29874
+ var name$1 = "@circle-fin/earn-kit";
29875
+ var version$1 = "1.8.1";
29876
+ var pkg$1 = {
29877
+ name: name$1,
29878
+ version: version$1};
29513
29879
 
29514
29880
  /**
29515
29881
  * Map SDK chain identifiers to bridge API chain strings.
@@ -29581,7 +29947,7 @@ function isBigIntLike(value) {
29581
29947
  return false;
29582
29948
  }
29583
29949
  }
29584
- function isNonNegativeBigIntLike(value) {
29950
+ function isNonNegativeBigIntLike$1(value) {
29585
29951
  try {
29586
29952
  return BigInt(value) >= 0n;
29587
29953
  } catch {
@@ -29601,28 +29967,22 @@ const bridgeFeeTokenSchema = hexAddressSchema;
29601
29967
  * unchanged so signed execution params can be forwarded verbatim.
29602
29968
  *
29603
29969
  * @internal
29604
- */ const uint256LikeSchema = zod.z.union([
29970
+ */ const uint256LikeSchema$1 = zod.z.union([
29605
29971
  zod.z.string(),
29606
29972
  zod.z.bigint()
29607
- ]).refine(isNonNegativeBigIntLike, {
29973
+ ]).refine(isNonNegativeBigIntLike$1, {
29608
29974
  message: 'value must be a non-negative bigint-compatible string or bigint'
29609
29975
  });
29610
29976
  /**
29611
29977
  * Zod schema for typed amount objects emitted by the API.
29612
29978
  *
29613
29979
  * @internal
29614
- */ const amountJsonSchema = zod.z.object({
29980
+ */ const amountJsonSchema$1 = zod.z.object({
29615
29981
  raw: zod.z.string().refine(isBigIntLike, {
29616
29982
  message: 'raw must be a bigint-compatible string'
29617
29983
  }),
29618
29984
  decimals: zod.z.number().int().nonnegative()
29619
29985
  });
29620
- /** @internal */ const hexBytesSchema = zod.z.union([
29621
- hexStringSchema,
29622
- zod.z.literal('0x')
29623
- ]).refine((value)=>value.length % 2 === 0, {
29624
- message: 'value must be a 0x-prefixed even-length hex string'
29625
- });
29626
29986
  /** @internal */ const bytes32HexSchema = hexStringSchema.refine((value)=>value.length === BYTES32_HEX_LENGTH, {
29627
29987
  message: 'value must be a 0x-prefixed 32-byte hex string'
29628
29988
  });
@@ -29706,9 +30066,9 @@ const bridgeFeeTokenSchema = hexAddressSchema;
29706
30066
  *
29707
30067
  * @internal
29708
30068
  */ const liquidityProfileSchema = zod.z.object({
29709
- totalDeposits: amountJsonSchema,
29710
- available: amountJsonSchema,
29711
- totalSupply: amountJsonSchema,
30069
+ totalDeposits: amountJsonSchema$1,
30070
+ available: amountJsonSchema$1,
30071
+ totalSupply: amountJsonSchema$1,
29712
30072
  status: zod.z.enum([
29713
30073
  'active',
29714
30074
  'low_liquidity'
@@ -29745,8 +30105,8 @@ const bridgeFeeTokenSchema = hexAddressSchema;
29745
30105
  vaultFee: zod.z.number(),
29746
30106
  rewards: zod.z.array(vaultRewardSchema),
29747
30107
  collateral: zod.z.array(collateralSchema),
29748
- totalDeposits: amountJsonSchema,
29749
- liquidity: amountJsonSchema,
30108
+ totalDeposits: amountJsonSchema$1,
30109
+ liquidity: amountJsonSchema$1,
29750
30110
  status: zod.z.enum([
29751
30111
  'active',
29752
30112
  'low_liquidity'
@@ -29856,13 +30216,13 @@ const bridgeFeeTokenSchema = hexAddressSchema;
29856
30216
  */ const accruedRewardSchema = zod.z.object({
29857
30217
  token: zod.z.string(),
29858
30218
  symbol: zod.z.string(),
29859
- amount: amountJsonSchema
30219
+ amount: amountJsonSchema$1
29860
30220
  });
29861
30221
  const positionPnlSchema = zod.z.discriminatedUnion('status', [
29862
30222
  zod.z.object({
29863
30223
  status: zod.z.literal('available'),
29864
- principalDeposited: amountJsonSchema,
29865
- totalYieldEarned: amountJsonSchema
30224
+ principalDeposited: amountJsonSchema$1,
30225
+ totalYieldEarned: amountJsonSchema$1
29866
30226
  }),
29867
30227
  zod.z.object({
29868
30228
  status: zod.z.literal('pending')
@@ -29882,9 +30242,9 @@ const positionPnlSchema = zod.z.discriminatedUnion('status', [
29882
30242
  vaultAddress: zod.z.string(),
29883
30243
  vaultName: zod.z.string(),
29884
30244
  asset: zod.z.string(),
29885
- currentBalance: amountJsonSchema,
30245
+ currentBalance: amountJsonSchema$1,
29886
30246
  currentApy: zod.z.number(),
29887
- shares: amountJsonSchema,
30247
+ shares: amountJsonSchema$1,
29888
30248
  pnl: positionPnlSchema,
29889
30249
  accruedRewards: zod.z.array(accruedRewardSchema).optional(),
29890
30250
  rewardsUnavailableReason: zod.z.string().optional()
@@ -29912,7 +30272,7 @@ const positionPnlSchema = zod.z.discriminatedUnion('status', [
29912
30272
  * @internal
29913
30273
  */ const earnInstructionSchema = zod.z.object({
29914
30274
  tokenIn: hexAddressSchema,
29915
- amountToApprove: uint256LikeSchema
30275
+ amountToApprove: uint256LikeSchema$1
29916
30276
  }).passthrough();
29917
30277
  /**
29918
30278
  * Zod schema for earn execution params returned by the earn service.
@@ -29926,50 +30286,10 @@ const positionPnlSchema = zod.z.discriminatedUnion('status', [
29926
30286
  instructions: zod.z.tuple([
29927
30287
  earnInstructionSchema
29928
30288
  ]).rest(earnInstructionSchema),
29929
- deadline: uint256LikeSchema
30289
+ deadline: uint256LikeSchema$1
29930
30290
  }).passthrough();
29931
30291
  /** @internal */ const depositExecutionParamsSchema = earnExecutionParamsSchema;
29932
30292
  /** @internal */ const withdrawExecutionParamsSchema = earnExecutionParamsSchema;
29933
- /**
29934
- * Zod schema for the claim rewards instruction fields that must be safe to
29935
- * ABI-encode.
29936
- *
29937
- * Claim rewards has no approval preflight, so this validates the forwarded
29938
- * signed payload at the provider boundary. Additional instruction fields are
29939
- * accepted and preserved.
29940
- *
29941
- * @internal
29942
- */ const claimRewardsInstructionSchema = zod.z.object({
29943
- target: hexAddressSchema,
29944
- data: hexBytesSchema,
29945
- value: uint256LikeSchema,
29946
- tokenIn: hexAddressSchema,
29947
- amountToApprove: uint256LikeSchema,
29948
- tokenOut: hexAddressSchema,
29949
- minTokenOut: uint256LikeSchema
29950
- }).passthrough();
29951
- /** @internal */ const claimRewardsTokenSchema = zod.z.object({
29952
- token: hexAddressSchema,
29953
- beneficiary: hexAddressSchema
29954
- }).passthrough();
29955
- /**
29956
- * Zod schema for signed claim rewards execution params.
29957
- *
29958
- * This enforces the required envelope and preserves additive fields so the
29959
- * adapter receives the signed params verbatim.
29960
- *
29961
- * @internal
29962
- */ const claimRewardsExecutionParamsSchema = zod.z.object({
29963
- instructions: zod.z.tuple([
29964
- claimRewardsInstructionSchema
29965
- ]).rest(claimRewardsInstructionSchema),
29966
- tokens: zod.z.tuple([
29967
- claimRewardsTokenSchema
29968
- ]).rest(claimRewardsTokenSchema),
29969
- execId: uint256LikeSchema,
29970
- deadline: uint256LikeSchema,
29971
- metadata: hexBytesSchema
29972
- }).passthrough();
29973
30293
  /**
29974
30294
  * Zod schema for the deposit payload inside the API `data` envelope.
29975
30295
  *
@@ -30028,9 +30348,9 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
30028
30348
  message: zod.z.object({
30029
30349
  from: hexAddressSchema,
30030
30350
  to: hexAddressSchema,
30031
- value: uint256LikeSchema,
30032
- validAfter: uint256LikeSchema,
30033
- validBefore: uint256LikeSchema,
30351
+ value: uint256LikeSchema$1,
30352
+ validAfter: uint256LikeSchema$1,
30353
+ validBefore: uint256LikeSchema$1,
30034
30354
  nonce: bytes32HexSchema
30035
30355
  }).passthrough()
30036
30356
  }).passthrough();
@@ -30048,7 +30368,7 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
30048
30368
  feeToken: bridgeFeeTokenSchema,
30049
30369
  items: zod.z.array(zod.z.object({
30050
30370
  type: zod.z.string(),
30051
- amount: uint256LikeSchema
30371
+ amount: uint256LikeSchema$1
30052
30372
  }).passthrough())
30053
30373
  }).passthrough();
30054
30374
  /**
@@ -30064,7 +30384,7 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
30064
30384
  const bridgeDepositPrepareReviewSchema = zod.z.object({
30065
30385
  sourceChain: zod.z.string(),
30066
30386
  destinationChain: zod.z.string(),
30067
- amount: amountJsonSchema,
30387
+ amount: amountJsonSchema$1,
30068
30388
  vaultAddress: hexAddressSchema
30069
30389
  }).passthrough();
30070
30390
  /** @internal */ const bridgeQuoteExpirySchema = zod.z.discriminatedUnion('mode', [
@@ -30199,44 +30519,6 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
30199
30519
  // ---------------------------------------------------------------------------
30200
30520
  // Claim rewards response schema
30201
30521
  // ---------------------------------------------------------------------------
30202
- /**
30203
- * Zod schema for a claimed reward amount in the API response.
30204
- *
30205
- * @internal
30206
- */ const claimedAmountSchema = zod.z.object({
30207
- token: hexAddressSchema,
30208
- symbol: zod.z.string(),
30209
- amount: amountJsonSchema
30210
- });
30211
- /**
30212
- * Zod schema for the claim rewards payload inside the API `data` envelope.
30213
- *
30214
- * Enforce that `executionParams` and `signature` are either both
30215
- * present (claimable rewards) or both absent (nothing to claim).
30216
- *
30217
- * @internal
30218
- */ const claimRewardsPayloadSchema = zod.z.object({
30219
- rewards: zod.z.array(claimedAmountSchema),
30220
- executionParams: claimRewardsExecutionParamsSchema.optional(),
30221
- signature: hexSignatureSchema.optional()
30222
- }).refine((data)=>{
30223
- const signedFieldCount = (data.executionParams === undefined ? 0 : 1) + (data.signature === undefined ? 0 : 1);
30224
- if (data.rewards.length > 0) {
30225
- return signedFieldCount === 2;
30226
- }
30227
- return signedFieldCount === 0;
30228
- }, {
30229
- message: 'claim rewards response must include executionParams and signature only when rewards are claimable'
30230
- });
30231
- /**
30232
- * Zod schema for the `POST /v1/earnKit/claimRewards` API response.
30233
- *
30234
- * The Earn Service API wraps the claim rewards payload in a `data` envelope.
30235
- *
30236
- * @internal
30237
- */ zod.z.object({
30238
- data: claimRewardsPayloadSchema
30239
- });
30240
30522
  // ---------------------------------------------------------------------------
30241
30523
  // Deposit quote response schema
30242
30524
  // ---------------------------------------------------------------------------
@@ -30255,7 +30537,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
30255
30537
  type: zod.z.string().optional(),
30256
30538
  status: zod.z.string().optional(),
30257
30539
  token: zod.z.string(),
30258
- amount: amountJsonSchema
30540
+ amount: amountJsonSchema$1
30259
30541
  });
30260
30542
  /**
30261
30543
  * Zod schema for a native gas-fee entry in an EarnKit quote response.
@@ -30292,8 +30574,8 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
30292
30574
  vaultAddress: zod.z.string(),
30293
30575
  vaultName: zod.z.string(),
30294
30576
  asset: zod.z.string(),
30295
- depositAmount: amountJsonSchema,
30296
- expectedShares: amountJsonSchema,
30577
+ depositAmount: amountJsonSchema$1,
30578
+ expectedShares: amountJsonSchema$1,
30297
30579
  sharePrice: zod.z.string(),
30298
30580
  currentApy: zod.z.number(),
30299
30581
  fees: zod.z.array(feeSchema).optional(),
@@ -30319,10 +30601,10 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
30319
30601
  vaultAddress: zod.z.string(),
30320
30602
  vaultName: zod.z.string(),
30321
30603
  asset: zod.z.string(),
30322
- withdrawAmount: amountJsonSchema,
30323
- sharesToRedeem: amountJsonSchema,
30604
+ withdrawAmount: amountJsonSchema$1,
30605
+ sharesToRedeem: amountJsonSchema$1,
30324
30606
  sharePrice: zod.z.string(),
30325
- maxWithdrawable: amountJsonSchema,
30607
+ maxWithdrawable: amountJsonSchema$1,
30326
30608
  fees: zod.z.array(feeSchema),
30327
30609
  gasFees: zod.z.array(quoteGasFeeSchema).optional(),
30328
30610
  warnings: zod.z.array(zod.z.string()).optional()
@@ -30339,31 +30621,6 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
30339
30621
  // ---------------------------------------------------------------------------
30340
30622
  // Claim rewards quote response schema
30341
30623
  // ---------------------------------------------------------------------------
30342
- /**
30343
- * Zod schema for a reward in the claim rewards quote response.
30344
- *
30345
- * @internal
30346
- */ const claimRewardsQuoteRewardSchema = zod.z.object({
30347
- token: zod.z.string(),
30348
- symbol: zod.z.string(),
30349
- amount: amountJsonSchema
30350
- });
30351
- /**
30352
- * Zod schema for the inner claim rewards quote payload.
30353
- *
30354
- * @internal
30355
- */ const claimRewardsQuotePayloadSchema = zod.z.object({
30356
- rewards: zod.z.array(claimRewardsQuoteRewardSchema)
30357
- });
30358
- /**
30359
- * Zod schema for the `POST /v1/earnKit/claimRewards/quote` API response.
30360
- *
30361
- * The API wraps the payload in a `data` envelope.
30362
- *
30363
- * @internal
30364
- */ zod.z.object({
30365
- data: claimRewardsQuotePayloadSchema
30366
- });
30367
30624
  // ---------------------------------------------------------------------------
30368
30625
  // Batch vault response schema
30369
30626
  // ---------------------------------------------------------------------------
@@ -30503,7 +30760,7 @@ createTokenRegistry();
30503
30760
  * fast instead of being silently stripped.
30504
30761
  *
30505
30762
  * @internal
30506
- */ const adapterContextSchema = zod.z.object({
30763
+ */ const adapterContextSchema$1 = zod.z.object({
30507
30764
  adapter: adapterSchema,
30508
30765
  // AdapterContext accepts a wider chain field, but runtime validation must
30509
30766
  // stay constrained to EarnChain identifiers.
@@ -30735,7 +30992,7 @@ const sourceAdapterContextSchema = zod.z.object({
30735
30992
  * })
30736
30993
  * ```
30737
30994
  */ zod.z.object({
30738
- from: adapterContextSchema,
30995
+ from: adapterContextSchema$1,
30739
30996
  vaultAddress: vaultAddressSchema,
30740
30997
  config: earnConfigSchema.optional()
30741
30998
  });
@@ -30790,7 +31047,7 @@ const sourceAdapterContextSchema = zod.z.object({
30790
31047
  *
30791
31048
  * @internal Exported for branch-targeted validation in the deposit operation.
30792
31049
  */ const sameChainDepositParamsSchema = zod.z.object({
30793
- from: adapterContextSchema,
31050
+ from: adapterContextSchema$1,
30794
31051
  to: zod.z.undefined().optional(),
30795
31052
  vaultAddress: vaultAddressSchema,
30796
31053
  amount: amountSchema,
@@ -30861,7 +31118,7 @@ const crossChainDepositDestinationSchema = zod.z.object({
30861
31118
  * })
30862
31119
  * ```
30863
31120
  */ zod.z.object({
30864
- from: adapterContextSchema,
31121
+ from: adapterContextSchema$1,
30865
31122
  vaultAddress: vaultAddressSchema,
30866
31123
  amount: amountSchema,
30867
31124
  config: earnConfigSchema.optional()
@@ -30915,7 +31172,7 @@ const crossChainDepositDestinationSchema = zod.z.object({
30915
31172
  * })
30916
31173
  * ```
30917
31174
  */ zod.z.object({
30918
- from: adapterContextSchema,
31175
+ from: adapterContextSchema$1,
30919
31176
  vaultAddress: vaultAddressSchema,
30920
31177
  amount: amountSchema,
30921
31178
  config: earnConfigSchema.optional()
@@ -30935,12 +31192,12 @@ const crossChainDepositDestinationSchema = zod.z.object({
30935
31192
  *
30936
31193
  * @internal
30937
31194
  */ zod.z.object({
30938
- from: adapterContextSchema,
31195
+ from: adapterContextSchema$1,
30939
31196
  vaultAddress: vaultAddressSchema,
30940
31197
  config: earnConfigSchema.optional()
30941
31198
  });
30942
31199
  const sameChainGetDepositQuoteParamsSchema = zod.z.object({
30943
- from: adapterContextSchema,
31200
+ from: adapterContextSchema$1,
30944
31201
  vaultAddress: vaultAddressSchema,
30945
31202
  amount: amountSchema,
30946
31203
  config: earnConfigSchema.optional()
@@ -31024,7 +31281,7 @@ function hasCrossChainDepositQuoteShape(params) {
31024
31281
  * })
31025
31282
  * ```
31026
31283
  */ zod.z.object({
31027
- from: adapterContextSchema,
31284
+ from: adapterContextSchema$1,
31028
31285
  vaultAddress: vaultAddressSchema,
31029
31286
  amount: amountSchema,
31030
31287
  config: earnConfigSchema.optional()
@@ -31044,15 +31301,15 @@ function hasCrossChainDepositQuoteShape(params) {
31044
31301
  *
31045
31302
  * @internal
31046
31303
  */ zod.z.object({
31047
- from: adapterContextSchema,
31304
+ from: adapterContextSchema$1,
31048
31305
  vaultAddress: vaultAddressSchema,
31049
31306
  config: earnConfigSchema.optional()
31050
31307
  });
31051
31308
 
31052
- /** SDK name used in telemetry payloads. */ resolveKitSdkName(pkg.name);
31309
+ /** SDK name used in telemetry payloads. */ resolveKitSdkName(pkg$1.name);
31053
31310
 
31054
31311
  // Auto-register this kit for user agent tracking
31055
- registerKit(`${pkg.name}/${pkg.version}`);
31312
+ registerKit(`${pkg$1.name}/${pkg$1.version}`);
31056
31313
 
31057
31314
  /**
31058
31315
  * Register event handlers from a context actions map to a kit instance.
@@ -31118,6 +31375,1358 @@ registerKit(`${pkg.name}/${pkg.version}`);
31118
31375
  }
31119
31376
  };
31120
31377
 
31378
+ var name = "@circle-fin/borrow-kit";
31379
+ var version = "1.0.0";
31380
+ var pkg = {
31381
+ name: name,
31382
+ version: version};
31383
+
31384
+ const HUMAN_READABLE_AMOUNT_REGEX$1 = /^(?:0|[1-9]\d*)(?:\.\d+)?$/;
31385
+ const EVM_ADDRESS_REGEX = /^0x[0-9a-fA-F]{40}$/;
31386
+ const POSITIVE_USDC_AMOUNT_REGEX = /^(?:0|[1-9]\d*)(?:\.\d{1,6})?$/;
31387
+ /**
31388
+ * True when `value` parses as a URL whose scheme is exactly `https:`.
31389
+ *
31390
+ * Uses the WHATWG `URL` parser rather than `startsWith('https://')` so the
31391
+ * check is scheme-normalized (case-insensitive, e.g. `HTTPS://...` still
31392
+ * passes) instead of a literal prefix match. `value` has already passed
31393
+ * `z.string().url()` by the time this runs, but a caller could still supply
31394
+ * a string that `URL` itself rejects, so the parse is guarded.
31395
+ */ function isHttpsUrl$1(value) {
31396
+ try {
31397
+ return new URL(value).protocol === 'https:';
31398
+ } catch {
31399
+ return false;
31400
+ }
31401
+ }
31402
+ const borrowServiceConfigSchema$1 = zod.z.object({
31403
+ apiKey: zod.z.string().optional(),
31404
+ baseUrl: zod.z.string().url().optional()
31405
+ }).strict();
31406
+ /** Loan asset amounts are USDC, so they carry at most 6 decimal places. */ function positiveLoanAssetAmountSchema(field) {
31407
+ return zod.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), {
31408
+ message: `${field} must be greater than zero`
31409
+ });
31410
+ }
31411
+ /**
31412
+ * Collateral amounts denominate an arbitrary token, so the decimal count is the
31413
+ * token's rather than USDC's — a satoshi-precision collateral is valid.
31414
+ */ function positiveCollateralAmountSchema(field) {
31415
+ return zod.z.string().regex(HUMAN_READABLE_AMOUNT_REGEX$1, `${field} must be a canonical decimal`).refine((value)=>/[1-9]/.test(value), {
31416
+ message: `${field} must be greater than zero`
31417
+ });
31418
+ }
31419
+ /** @internal */ zod.z.object({
31420
+ chain: chainIdentifierSchema,
31421
+ marketId: zod.z.string().min(1),
31422
+ config: borrowServiceConfigSchema$1.optional()
31423
+ }).strict();
31424
+ /** @internal */ zod.z.object({
31425
+ walletAddress: zod.z.string().regex(EVM_ADDRESS_REGEX),
31426
+ chain: chainIdentifierSchema,
31427
+ pageSize: zod.z.number().int().positive().optional(),
31428
+ pageAfter: zod.z.string().min(1).optional(),
31429
+ config: borrowServiceConfigSchema$1.optional()
31430
+ }).strict();
31431
+ /** @internal */ const marketSortBySchema$1 = zod.z.enum([
31432
+ 'lltv',
31433
+ 'borrowApy'
31434
+ ]);
31435
+ /** @internal */ const decimalFilterSchema$1 = zod.z.string().regex(/^\d+(\.\d+)?$/, 'filter thresholds must be non-negative decimal strings');
31436
+ /**
31437
+ * Provider-level runtime schema for {@link ExploreMarketsServiceParams}.
31438
+ *
31439
+ * Mirrors the kit's `exploreMarketsParamsSchema` at the provider boundary so a
31440
+ * plain-JS caller invoking `BorrowServiceProvider.exploreMarkets` directly is
31441
+ * still validated before any filter reaches `url.searchParams` — including the
31442
+ * kit's `minLltv <= maxLltv` / `minBorrow <= maxBorrow` range check, which
31443
+ * otherwise lets an inverted range serialize into the request and return a
31444
+ * silently empty page.
31445
+ *
31446
+ * @internal
31447
+ */ zod.z.object({
31448
+ chain: chainIdentifierSchema,
31449
+ minLltv: decimalFilterSchema$1.optional(),
31450
+ maxLltv: decimalFilterSchema$1.optional(),
31451
+ minBorrow: decimalFilterSchema$1.optional(),
31452
+ maxBorrow: decimalFilterSchema$1.optional(),
31453
+ sortBy: marketSortBySchema$1.optional(),
31454
+ pageSize: zod.z.number().int().min(1).max(1000).optional(),
31455
+ pageAfter: zod.z.string().min(1).optional(),
31456
+ config: borrowServiceConfigSchema$1.optional()
31457
+ }).strict().superRefine((value, ctx)=>{
31458
+ if (value.minLltv !== undefined && value.maxLltv !== undefined && Number(value.minLltv) > Number(value.maxLltv)) {
31459
+ ctx.addIssue({
31460
+ code: zod.z.ZodIssueCode.custom,
31461
+ path: [
31462
+ 'maxLltv'
31463
+ ],
31464
+ message: 'maxLltv must be greater than or equal to minLltv'
31465
+ });
31466
+ }
31467
+ if (value.minBorrow !== undefined && value.maxBorrow !== undefined && Number(value.minBorrow) > Number(value.maxBorrow)) {
31468
+ ctx.addIssue({
31469
+ code: zod.z.ZodIssueCode.custom,
31470
+ path: [
31471
+ 'maxBorrow'
31472
+ ],
31473
+ message: 'maxBorrow must be greater than or equal to minBorrow'
31474
+ });
31475
+ }
31476
+ });
31477
+ /** @internal */ const repayQuoteServiceParamsSchema = zod.z.object({
31478
+ loanId: zod.z.string().uuid(),
31479
+ chain: chainIdentifierSchema,
31480
+ repayAmount: positiveLoanAssetAmountSchema('repayAmount'),
31481
+ config: borrowServiceConfigSchema$1.optional()
31482
+ }).strict();
31483
+ /** @internal */ repayQuoteServiceParamsSchema.omit({
31484
+ chain: true
31485
+ }).extend({
31486
+ idempotencyKey: zod.z.string().uuid().optional()
31487
+ });
31488
+ /** @internal */ const closeLoanQuoteServiceParamsSchema = zod.z.object({
31489
+ loanId: zod.z.string().uuid(),
31490
+ chain: chainIdentifierSchema,
31491
+ slippageBps: zod.z.number().int().min(0).max(10_000).optional(),
31492
+ config: borrowServiceConfigSchema$1.optional()
31493
+ }).strict();
31494
+ /** Fields a borrow carries whichever way it names its position. @internal */ const borrowServiceParamsBaseShape = {
31495
+ loanAssetAmount: positiveLoanAssetAmountSchema('loanAssetAmount'),
31496
+ slippageBps: zod.z.number().int().min(0).max(10_000).optional(),
31497
+ idempotencyKey: zod.z.string().uuid().optional(),
31498
+ config: borrowServiceConfigSchema$1.optional()
31499
+ };
31500
+ /** A first-open: owner, chain and market are required together. @internal */ const openLoanServiceParamsSchema = zod.z.object({
31501
+ ...borrowServiceParamsBaseShape,
31502
+ walletAddress: zod.z.string().regex(EVM_ADDRESS_REGEX),
31503
+ chain: chainIdentifierSchema,
31504
+ marketId: zod.z.string().min(1)
31505
+ }).strict();
31506
+ /** A borrow-more: the loan is the only addressing field. @internal */ const borrowMoreServiceParamsSchema = zod.z.object({
31507
+ ...borrowServiceParamsBaseShape,
31508
+ loanId: zod.z.string().uuid()
31509
+ }).strict();
31510
+ /**
31511
+ * The two ways a borrow names its position.
31512
+ *
31513
+ * A union of strict objects rather than one object with a refinement:
31514
+ * `.strict()` is what rejects a mixed body, and the service refuses `loanId`
31515
+ * next to any open-tuple field as well as an incomplete open tuple.
31516
+ *
31517
+ * @internal
31518
+ */ zod.z.union([
31519
+ openLoanServiceParamsSchema,
31520
+ borrowMoreServiceParamsSchema
31521
+ ]);
31522
+ /** A first-open quote carries the complete owner/chain/market tuple. @internal */ const openLoanQuoteServiceParamsSchema = zod.z.object({
31523
+ walletAddress: zod.z.string().regex(EVM_ADDRESS_REGEX),
31524
+ chain: chainIdentifierSchema,
31525
+ marketId: zod.z.string().min(1),
31526
+ loanAssetAmount: positiveLoanAssetAmountSchema('loanAssetAmount'),
31527
+ slippageBps: zod.z.number().int().min(0).max(10_000).optional(),
31528
+ config: borrowServiceConfigSchema$1.optional()
31529
+ }).strict();
31530
+ /** A borrow-more quote needs only the existing loan ID. @internal */ const borrowMoreQuoteServiceParamsSchema = zod.z.object({
31531
+ loanId: zod.z.string().uuid(),
31532
+ loanAssetAmount: positiveLoanAssetAmountSchema('loanAssetAmount'),
31533
+ slippageBps: zod.z.number().int().min(0).max(10_000).optional(),
31534
+ config: borrowServiceConfigSchema$1.optional()
31535
+ }).strict();
31536
+ /** @internal */ zod.z.union([
31537
+ openLoanQuoteServiceParamsSchema,
31538
+ borrowMoreQuoteServiceParamsSchema
31539
+ ]);
31540
+ /** @internal */ zod.z.object({
31541
+ chain: chainIdentifierSchema,
31542
+ marketId: zod.z.string().min(1),
31543
+ loanAssetAmount: positiveLoanAssetAmountSchema('loanAssetAmount'),
31544
+ // `.finite()` is load-bearing, not decoration: the value is encoded as a
31545
+ // decimal string on the wire, and there is no decimal string for Infinity.
31546
+ targetHealthFactor: zod.z.number().positive().finite(),
31547
+ config: borrowServiceConfigSchema$1.optional()
31548
+ }).strict();
31549
+ /** @internal */ zod.z.object({
31550
+ chain: chainIdentifierSchema,
31551
+ marketId: zod.z.string().min(1),
31552
+ collateralAmount: positiveCollateralAmountSchema('collateralAmount'),
31553
+ config: borrowServiceConfigSchema$1.optional()
31554
+ }).strict();
31555
+ /** @internal */ closeLoanQuoteServiceParamsSchema.omit({
31556
+ chain: true
31557
+ }).extend({
31558
+ idempotencyKey: zod.z.string().uuid().optional()
31559
+ });
31560
+ /**
31561
+ * Provider-level runtime schema for the non-adapter portion of
31562
+ * {@link ClaimRewardsServiceParams} / {@link GetRewardsServiceParams}.
31563
+ *
31564
+ * `from` (the adapter context) is intentionally excluded — like
31565
+ * `repay`/`closeLoan`, it is validated structurally by TypeScript and resolved
31566
+ * via `resolveAdapterContext` rather than by a Zod schema, since it carries a
31567
+ * live adapter instance rather than plain data. `config` is the only field
31568
+ * that reaches the wire, so it is what gets validated here, matching every
31569
+ * other provider method's independent `parseOrThrow` call.
31570
+ *
31571
+ * @internal
31572
+ */ zod.z.object({
31573
+ config: borrowServiceConfigSchema$1.optional()
31574
+ }).strict();
31575
+ /**
31576
+ * Provider-level runtime schema for {@link GetPositionServiceParams}.
31577
+ *
31578
+ * @internal
31579
+ */ zod.z.object({
31580
+ loanId: zod.z.string().uuid(),
31581
+ config: borrowServiceConfigSchema$1.optional()
31582
+ }).strict();
31583
+ /** @internal */ const withdrawCollateralQuoteServiceParamsSchema = zod.z.object({
31584
+ loanId: zod.z.string().uuid(),
31585
+ chain: chainIdentifierSchema,
31586
+ // Carries no decimal-place cap: the repayment is USDC, but the collateral
31587
+ // is the market's own token and may hold more precision than USDC's six.
31588
+ collateralAmount: positiveCollateralAmountSchema('collateralAmount'),
31589
+ slippageBps: zod.z.number().int().min(0).max(10_000).optional(),
31590
+ config: borrowServiceConfigSchema$1.optional()
31591
+ }).strict();
31592
+ /** @internal */ withdrawCollateralQuoteServiceParamsSchema.omit({
31593
+ chain: true
31594
+ }).extend({
31595
+ idempotencyKey: zod.z.string().uuid().optional()
31596
+ });
31597
+ /**
31598
+ * Adding collateral sizes no second leg, so there is no slippage bound.
31599
+ *
31600
+ * @internal
31601
+ */ const addCollateralQuoteServiceParamsSchema = zod.z.object({
31602
+ loanId: zod.z.string().uuid(),
31603
+ chain: chainIdentifierSchema,
31604
+ collateralAmount: positiveCollateralAmountSchema('collateralAmount'),
31605
+ config: borrowServiceConfigSchema$1.optional()
31606
+ }).strict();
31607
+ /** @internal */ addCollateralQuoteServiceParamsSchema.omit({
31608
+ chain: true
31609
+ }).extend({
31610
+ idempotencyKey: zod.z.string().uuid().optional()
31611
+ });
31612
+ /** @internal */ const borrowAssetAmountSchema = zod.z.object({
31613
+ token: zod.z.string().min(1),
31614
+ tokenAddress: zod.z.string().regex(EVM_ADDRESS_REGEX),
31615
+ decimals: zod.z.number().int().min(0).max(255),
31616
+ amount: zod.z.string().regex(HUMAN_READABLE_AMOUNT_REGEX$1)
31617
+ });
31618
+ /** @internal */ const healthFactorBandSchema = zod.z.enum([
31619
+ 'SAFE',
31620
+ 'WARN',
31621
+ 'URGENT',
31622
+ 'IMMINENT',
31623
+ 'LIQUIDATABLE'
31624
+ ]);
31625
+ /**
31626
+ * Whether a loan's economic projection has converged.
31627
+ *
31628
+ * `PENDING` means the loan's identity and lifecycle are known but its
31629
+ * economics are not yet materialized — every economic field is `null` until
31630
+ * the service's repair queue fills them in. See {@link loanSchema}.
31631
+ *
31632
+ * @internal
31633
+ */ const loanDataStatusSchema = zod.z.enum([
31634
+ 'READY',
31635
+ 'PENDING'
31636
+ ]);
31637
+ /**
31638
+ * Lifecycle status of a loan: still open (`active`) or fully wound down
31639
+ * (`closed`). Unlike {@link loanDataStatusSchema} this is not about whether
31640
+ * economics have converged — a `closed` loan is `READY` with every economic
31641
+ * field legitimately zeroed, not `null`. Shared by {@link loanSchema} and
31642
+ * {@link loanPayloadSchema}, which return the same field for the same entity.
31643
+ *
31644
+ * @internal
31645
+ */ const loanStatusSchema = zod.z.enum([
31646
+ 'active',
31647
+ 'closed'
31648
+ ]);
31649
+ /**
31650
+ * Zod schema for one loan in the `GET /v1/borrowKit/loans` page.
31651
+ *
31652
+ * @remarks Every economic field is nullable because the service returns a
31653
+ * `PENDING` loan — identity and lifecycle fields set, all economics `null` —
31654
+ * while materialization, principal, debt, or market APY is still converging.
31655
+ * That is the documented representation of a freshly-created loan, so
31656
+ * declaring these non-nullable made the first read after a `borrow()` fail
31657
+ * validation. `dataStatus` tells callers which of the two shapes they hold.
31658
+ *
31659
+ * `status` distinguishes a fully wound-down loan — `READY` with legitimately
31660
+ * zeroed economics — from a live one. Without it a caller cannot tell the two
31661
+ * apart, which is what left a closed loan sitting in `getLoans` output looking
31662
+ * open. It is declared **required here and on {@link loanPayloadSchema}**: a
31663
+ * live `GET /v1/borrowKit/loans` page reports it on every loan, including a
31664
+ * closed one.
31665
+ *
31666
+ * @internal
31667
+ */ const loanSchema = zod.z.object({
31668
+ loanId: zod.z.string().uuid(),
31669
+ chain: zod.z.string().min(1),
31670
+ marketId: zod.z.string().min(1),
31671
+ walletAddress: zod.z.string().regex(EVM_ADDRESS_REGEX),
31672
+ dataStatus: loanDataStatusSchema,
31673
+ collateral: borrowAssetAmountSchema.nullable(),
31674
+ borrowed: borrowAssetAmountSchema.nullable(),
31675
+ principalBorrowed: borrowAssetAmountSchema.nullable(),
31676
+ accruedInterest: borrowAssetAmountSchema.nullable(),
31677
+ borrowApy: zod.z.number().nullable(),
31678
+ ltv: zod.z.number().nullable(),
31679
+ healthFactor: zod.z.number().nullable(),
31680
+ healthFactorBand: healthFactorBandSchema.nullable(),
31681
+ liquidationPrice: borrowAssetAmountSchema.nullable(),
31682
+ status: loanStatusSchema
31683
+ });
31684
+ /**
31685
+ * Zod schema for the `GET /v1/borrowKit/loans` API response. The Borrow
31686
+ * Service wraps every response in a `data` envelope.
31687
+ *
31688
+ * @internal
31689
+ */ zod.z.object({
31690
+ data: zod.z.object({
31691
+ loans: zod.z.array(loanSchema),
31692
+ pagination: zod.z.object({
31693
+ pageAfter: zod.z.string().optional()
31694
+ })
31695
+ })
31696
+ });
31697
+ /** @internal */ const borrowFeeSchema = zod.z.object({
31698
+ type: zod.z.string(),
31699
+ token: zod.z.string(),
31700
+ amount: borrowAssetAmountSchema
31701
+ });
31702
+ /** @internal */ const borrowQuoteGasFeeSchema = zod.z.object({
31703
+ name: zod.z.string(),
31704
+ fees: zod.z.object({
31705
+ gas: zod.z.string(),
31706
+ gasPrice: borrowAssetAmountSchema,
31707
+ fee: borrowAssetAmountSchema
31708
+ })
31709
+ });
31710
+ /** @internal */ const hexBytesSchema = zod.z.string().regex(/^0x(?:[0-9a-fA-F]{2})*$/).transform((value)=>value);
31711
+ function isNonNegativeBigIntLike(value) {
31712
+ try {
31713
+ return BigInt(value) >= 0n;
31714
+ } catch {
31715
+ return false;
31716
+ }
31717
+ }
31718
+ /** @internal */ const uint256LikeSchema = zod.z.union([
31719
+ zod.z.string(),
31720
+ zod.z.bigint()
31721
+ ]).refine(isNonNegativeBigIntLike, {
31722
+ message: 'value must be a non-negative bigint-compatible string or bigint'
31723
+ });
31724
+ /**
31725
+ * A quoted decimal that has to parse finite, for the response fields the
31726
+ * service marshals from a Go `decimal.Decimal`.
31727
+ *
31728
+ * Deliberately not `z.coerce.number()`: coercion maps `''` and whitespace to
31729
+ * `0`, so a service that stopped sending a value would read as a real `0.0` —
31730
+ * a health factor of zero is a liquidated position, so that failure mode
31731
+ * silently reports the opposite of the truth. Refusing anything unparseable
31732
+ * here also makes the `decimalToNumber` mapper total, with no fallback value to
31733
+ * invent downstream.
31734
+ */ const decimalNumericString = zod.z.string().min(1).refine((value)=>value.trim() !== '' && Number.isFinite(Number(value)), {
31735
+ message: 'value must be a decimal string that parses to a finite number'
31736
+ });
31737
+ /** @internal */ const borrowExecutionParamsSchema = zod.z.object({
31738
+ instructions: zod.z.array(zod.z.object({
31739
+ target: evmAddressSchema$1,
31740
+ data: hexBytesSchema,
31741
+ value: uint256LikeSchema,
31742
+ tokenIn: evmAddressSchema$1,
31743
+ amountToApprove: uint256LikeSchema,
31744
+ tokenOut: evmAddressSchema$1,
31745
+ minTokenOut: uint256LikeSchema
31746
+ }).passthrough()).min(1),
31747
+ tokens: zod.z.array(zod.z.object({
31748
+ token: evmAddressSchema$1,
31749
+ beneficiary: evmAddressSchema$1
31750
+ }).passthrough()),
31751
+ execId: uint256LikeSchema,
31752
+ deadline: uint256LikeSchema,
31753
+ metadata: hexBytesSchema
31754
+ }).passthrough();
31755
+ /**
31756
+ * Inner payload for a Borrow Service execution response, shared by every
31757
+ * write endpoint (`borrow`, `repay`, `addCollateral`, `closeLoan`,
31758
+ * `withdrawCollateral`). Kept separate from {@link loanExecutionSchema} so
31759
+ * {@link withdrawCollateralExecutionSchema} — the one execution response that
31760
+ * omits `chain` — can build on it without re-declaring every field.
31761
+ *
31762
+ * @internal
31763
+ */ const loanExecutionPayloadSchema = zod.z.object({
31764
+ loanId: zod.z.string().uuid(),
31765
+ chain: zod.z.string().min(1),
31766
+ execId: zod.z.string().min(1),
31767
+ signature: evmSignatureSchema,
31768
+ executionParams: borrowExecutionParamsSchema
31769
+ });
31770
+ /**
31771
+ * Zod schema for a Borrow Service execution API response. The Borrow Service
31772
+ * wraps every response in a `data` envelope.
31773
+ *
31774
+ * @internal
31775
+ */ zod.z.object({
31776
+ data: loanExecutionPayloadSchema
31777
+ });
31778
+ /**
31779
+ * Zod schema for the `POST /v1/borrowKit/loans/borrow` execution API
31780
+ * response. Extends {@link loanExecutionPayloadSchema} with `fees`, the fee
31781
+ * legs the signed bundle charges at origination (empty when nothing is
31782
+ * charged) — a field only this endpoint's response carries.
31783
+ *
31784
+ * `fees` is optional here, and only here. The API spec documents it as always
31785
+ * present and `[]` when nothing is charged, but the deployed service omits the
31786
+ * key entirely; requiring it fails validation on a healthy `200` and turns
31787
+ * every borrow into a FATAL error. It is optional rather than defaulted
31788
+ * because the guard consuming this schema reports `safeParse().success` and
31789
+ * discards the parsed value, so a default would never reach a reader.
31790
+ *
31791
+ * The absence is preserved to the caller rather than normalised to `[]`:
31792
+ * `fetchBorrow` returns `response.data` unchanged and `BorrowResponse.fees` is
31793
+ * optional, so "the service named no legs" stays distinguishable from "nothing
31794
+ * was charged". `executeBorrow` is what resolves it, by reporting the fee
31795
+ * transfers the receipt paid out under `type: 'unknown'`.
31796
+ *
31797
+ * @internal
31798
+ */ zod.z.object({
31799
+ data: loanExecutionPayloadSchema.extend({
31800
+ fees: zod.z.array(borrowFeeSchema).optional()
31801
+ })
31802
+ });
31803
+ /** @internal */ const resultingHealthSchema = {
31804
+ resultingHealthFactor: zod.z.number().nullable(),
31805
+ resultingLtv: zod.z.number().nullable(),
31806
+ resultingBand: healthFactorBandSchema,
31807
+ liquidationPrice: borrowAssetAmountSchema.nullable()
31808
+ };
31809
+ /**
31810
+ * Zod schema for the `POST /v1/borrowKit/loans/:loan_id/repay/quote` API
31811
+ * response. The Borrow Service wraps every response in a `data` envelope.
31812
+ *
31813
+ * @internal
31814
+ */ zod.z.object({
31815
+ data: zod.z.object({
31816
+ chain: zod.z.string().min(1),
31817
+ repayAmount: borrowAssetAmountSchema,
31818
+ fees: zod.z.array(borrowFeeSchema),
31819
+ gasFees: zod.z.array(borrowQuoteGasFeeSchema),
31820
+ ...resultingHealthSchema
31821
+ })
31822
+ });
31823
+ // ---------------------------------------------------------------------------
31824
+ // Loan position response schema (SE-6383: getPosition)
31825
+ // ---------------------------------------------------------------------------
31826
+ /**
31827
+ * Zod schema for the inner loan position payload.
31828
+ *
31829
+ * @remarks Matches the real `GET /v1/borrowKit/loans/:loan_id` wire shape
31830
+ * (Zenith's `borrowkit.LoanResponse`). Two fields in the original placeholder
31831
+ * did not exist on that contract and made every lookup of a real loan fail
31832
+ * validation: the owner address is sent as `walletAddress`, not `wallet`, and
31833
+ * the service sends no liquidation threshold at all — liquidation LTV is a
31834
+ * market property, served by `GET /v1/borrowKit/markets/:chain/:market_id` as
31835
+ * `lltv`, not a per-loan one.
31836
+ *
31837
+ * `collateral` and `borrowed` are nullable for the same reason they are on
31838
+ * {@link loanSchema}: this route returns the same `PENDING` representation —
31839
+ * null economics — for a loan whose on-chain create has not been observed
31840
+ * yet, which is exactly the state a `borrow()` leaves behind. `dataStatus`
31841
+ * distinguishes that from a `READY` loan whose economics happen to be zero.
31842
+ *
31843
+ * Declares the same economic field set as {@link loanSchema}, because Zenith
31844
+ * serves both routes from one struct (`borrowkit.LoanResponse`): a loan read
31845
+ * one at a time reports exactly what the same loan reports inside a page, so a
31846
+ * caller never has to list a wallet to recover a field. Both declare `status`
31847
+ * as required: a live `GET /v1/borrowKit/loans` page reports it on every loan,
31848
+ * including a closed one.
31849
+ *
31850
+ * `registeredAt` is the sole field on the wire that neither schema declares.
31851
+ *
31852
+ * @internal
31853
+ */ const loanPayloadSchema = zod.z.object({
31854
+ loanId: zod.z.string(),
31855
+ walletAddress: zod.z.string(),
31856
+ chain: zod.z.string(),
31857
+ marketId: zod.z.string().min(1),
31858
+ dataStatus: loanDataStatusSchema,
31859
+ collateral: borrowAssetAmountSchema.nullable(),
31860
+ borrowed: borrowAssetAmountSchema.nullable(),
31861
+ principalBorrowed: borrowAssetAmountSchema.nullable(),
31862
+ accruedInterest: borrowAssetAmountSchema.nullable(),
31863
+ borrowApy: zod.z.number().nullable(),
31864
+ ltv: zod.z.number().nullable(),
31865
+ healthFactor: zod.z.number().nullable(),
31866
+ healthFactorBand: healthFactorBandSchema.nullable(),
31867
+ liquidationPrice: borrowAssetAmountSchema.nullable(),
31868
+ status: loanStatusSchema
31869
+ });
31870
+ /**
31871
+ * Zod schema for the `GET /v1/borrowKit/loans/:loan_id` API response.
31872
+ *
31873
+ * @internal
31874
+ */ zod.z.object({
31875
+ data: loanPayloadSchema
31876
+ });
31877
+ // ---------------------------------------------------------------------------
31878
+ // Inferred types
31879
+ // ---------------------------------------------------------------------------
31880
+ /**
31881
+ * Zod schema for the `POST /v1/borrowKit/loans/borrow/quote` API response.
31882
+ * The Borrow Service wraps every response in a `data` envelope.
31883
+ *
31884
+ * @internal
31885
+ */ zod.z.object({
31886
+ data: zod.z.object({
31887
+ chain: zod.z.string().min(1),
31888
+ collateralAmount: borrowAssetAmountSchema,
31889
+ loanAssetAmount: borrowAssetAmountSchema,
31890
+ // Nullable: the service reports null when the curated market row has no
31891
+ // cached rate yet, rather than a misleading 0%. The loans and markets
31892
+ // schemas already allow it; this one did not, so an unpriced market failed
31893
+ // validation and surfaced the whole quote as SERVICE_UNKNOWN_ERROR.
31894
+ borrowApy: zod.z.number().nullable(),
31895
+ fees: zod.z.array(borrowFeeSchema),
31896
+ gasFees: zod.z.array(borrowQuoteGasFeeSchema),
31897
+ ...resultingHealthSchema
31898
+ })
31899
+ });
31900
+ /**
31901
+ * Zod schema for the `POST /v1/borrowKit/loans/:loan_id/addCollateral/quote`
31902
+ * API response. The Borrow Service wraps every response in a `data` envelope.
31903
+ *
31904
+ * @internal
31905
+ */ zod.z.object({
31906
+ data: zod.z.object({
31907
+ chain: zod.z.string().min(1),
31908
+ collateralAmount: borrowAssetAmountSchema,
31909
+ fees: zod.z.array(borrowFeeSchema),
31910
+ gasFees: zod.z.array(borrowQuoteGasFeeSchema),
31911
+ ...resultingHealthSchema
31912
+ })
31913
+ });
31914
+ /**
31915
+ * Zod schema for the `POST /v1/borrowKit/loans/:loan_id/closeLoan/quote` API
31916
+ * response. The Borrow Service wraps every response in a `data` envelope.
31917
+ *
31918
+ * @internal
31919
+ */ zod.z.object({
31920
+ data: zod.z.object({
31921
+ chain: zod.z.string().min(1),
31922
+ repayAmount: borrowAssetAmountSchema,
31923
+ collateralAmount: borrowAssetAmountSchema,
31924
+ fees: zod.z.array(borrowFeeSchema),
31925
+ gasFees: zod.z.array(borrowQuoteGasFeeSchema),
31926
+ ...resultingHealthSchema
31927
+ })
31928
+ });
31929
+ /**
31930
+ * The collateral-withdrawal execution response is the one Borrow Service
31931
+ * execution body that omits `chain`, so it cannot reuse
31932
+ * {@link loanExecutionSchema} unchanged. Built on
31933
+ * {@link loanExecutionPayloadSchema} so the `data` envelope only needs to be
31934
+ * applied once.
31935
+ *
31936
+ * @internal
31937
+ */ zod.z.object({
31938
+ data: loanExecutionPayloadSchema.omit({
31939
+ chain: true
31940
+ })
31941
+ });
31942
+ /**
31943
+ * Zod schema for the
31944
+ * `POST /v1/borrowKit/loans/:loan_id/withdrawCollateral/quote` API response.
31945
+ * The Borrow Service wraps every response in a `data` envelope.
31946
+ *
31947
+ * @internal
31948
+ */ zod.z.object({
31949
+ data: zod.z.object({
31950
+ chain: zod.z.string().min(1),
31951
+ repayAmount: borrowAssetAmountSchema,
31952
+ collateralAmount: borrowAssetAmountSchema,
31953
+ fees: zod.z.array(borrowFeeSchema),
31954
+ gasFees: zod.z.array(borrowQuoteGasFeeSchema),
31955
+ ...resultingHealthSchema
31956
+ })
31957
+ });
31958
+ /**
31959
+ * Zod schema for the `POST /v1/borrowKit/loans/requiredCollateral/quote` API
31960
+ * response. The Borrow Service wraps every response in a `data` envelope.
31961
+ *
31962
+ * @remarks Deliberately not {@link resultingHealthSchema}. The two
31963
+ * market-scoped sizing quotes send four fields, not seven — no `resultingLtv`
31964
+ * and no `resultingBand` — so requiring the loan-scoped health block rejected
31965
+ * every well-formed response with `MALFORMED_RESPONSE`.
31966
+ *
31967
+ * `resultingHealthFactor` arrives as a decimal *string* on this route alone
31968
+ * (Zenith types it `decimal.Decimal`, which marshals quoted, where every other
31969
+ * route types it `*float64`). It is accepted as either encoding here and
31970
+ * narrowed to a `number` by the mapper — deliberately not via a Zod
31971
+ * `.transform`, because these schemas are consumed through boolean type guards
31972
+ * (`isRequiredCollateralQuote`), which discard a transform's output and would
31973
+ * leave the raw string flowing on while typed as a number.
31974
+ *
31975
+ * @internal
31976
+ */ zod.z.object({
31977
+ data: zod.z.object({
31978
+ chain: zod.z.string().min(1),
31979
+ requiredCollateral: borrowAssetAmountSchema,
31980
+ resultingHealthFactor: zod.z.union([
31981
+ zod.z.number(),
31982
+ decimalNumericString
31983
+ ]).nullable(),
31984
+ liquidationPrice: borrowAssetAmountSchema.nullable()
31985
+ })
31986
+ });
31987
+ /**
31988
+ * Zod schema for the `POST /v1/borrowKit/loans/maxBorrow/quote` API response.
31989
+ * The Borrow Service wraps every response in a `data` envelope.
31990
+ *
31991
+ * @remarks Four fields, not seven — see
31992
+ * {@link requiredCollateralQuoteSchema}. `resultingHealthFactor` is a plain
31993
+ * JSON number here (Zenith types it `*float64` on this route), so unlike its
31994
+ * inverse it needs no string coercion.
31995
+ *
31996
+ * @internal
31997
+ */ zod.z.object({
31998
+ data: zod.z.object({
31999
+ chain: zod.z.string().min(1),
32000
+ maxBorrowAmount: borrowAssetAmountSchema,
32001
+ resultingHealthFactor: zod.z.number().nullable(),
32002
+ liquidationPrice: borrowAssetAmountSchema.nullable()
32003
+ })
32004
+ });
32005
+ /**
32006
+ * Zod schema for the `GET`/`POST /v1/borrowKit/integrators/config` API
32007
+ * response. The Borrow Service wraps every response in a `data` envelope.
32008
+ *
32009
+ * @internal
32010
+ */ zod.z.object({
32011
+ data: zod.z.object({
32012
+ integratorId: zod.z.string().min(1),
32013
+ integratorFeeBps: zod.z.number().int().min(0),
32014
+ integratorFeeAddress: zod.z.string().regex(EVM_ADDRESS_REGEX).nullable(),
32015
+ createdAt: zod.z.string().datetime({
32016
+ offset: true
32017
+ }),
32018
+ updatedAt: zod.z.string().datetime({
32019
+ offset: true
32020
+ })
32021
+ })
32022
+ });
32023
+ /** @internal */ zod.z.object({
32024
+ config: borrowServiceConfigSchema$1.optional()
32025
+ }).strict();
32026
+ /**
32027
+ * Both fee fields are always required, so neither half is accepted alone.
32028
+ *
32029
+ * `integratorFeeAddress` may be `null` only when `integratorFeeBps` is 0, which
32030
+ * is how an integrator turns a fee off and clears the recipient. The reverse is
32031
+ * still allowed: a 0 rate can keep an address, which pauses the fee without
32032
+ * forgetting where it used to go. A rate above 0 with no recipient is unusable.
32033
+ *
32034
+ * The rule spans two fields, so it cannot live on either one and cannot be
32035
+ * expressed in the type. `{ integratorFeeBps: 25, integratorFeeAddress: null }`
32036
+ * type-checks and fails here.
32037
+ *
32038
+ * @internal
32039
+ */ zod.z.object({
32040
+ integratorFeeBps: zod.z.number().int().min(0).max(10_000),
32041
+ integratorFeeAddress: zod.z.string().regex(EVM_ADDRESS_REGEX).nullable(),
32042
+ config: borrowServiceConfigSchema$1.optional()
32043
+ }).strict().refine((params)=>params.integratorFeeAddress !== null || params.integratorFeeBps === 0, {
32044
+ message: 'integratorFeeAddress can only be null when integratorFeeBps is 0',
32045
+ path: [
32046
+ 'integratorFeeAddress'
32047
+ ]
32048
+ });
32049
+ /**
32050
+ * Zod schema for the webhook registration payload inside the API `data`
32051
+ * envelope, returned by
32052
+ * `POST /v1/borrowKit/loans/:loan_id/webhookRegistration`.
32053
+ *
32054
+ * @internal
32055
+ */ const webhookRegistrationPayloadSchema = zod.z.object({
32056
+ loanId: zod.z.string().uuid(),
32057
+ webhookUrl: zod.z.string().nullish()
32058
+ });
32059
+ /**
32060
+ * Zod schema validating the caller-supplied `loanId` and `webhookUrl` inputs
32061
+ * to `BorrowServiceProvider.registerWebhook` before they're signed and
32062
+ * submitted.
32063
+ *
32064
+ * `loanId` must be a UUID, consistent with every other loan-scoped schema in
32065
+ * this package (`repayQuoteServiceParamsSchema`, `loanSchema`,
32066
+ * `loanExecutionSchema`). `webhookUrl` must be `null` (an explicit "unset"
32067
+ * intent) or a syntactically valid **https** URL string — an empty string is
32068
+ * neither, so it's rejected here rather than silently reaching the `?? ''`
32069
+ * coercion that `buildWebhookRegistrationTypedData` applies to a genuine
32070
+ * `null`. The scheme is restricted to `https:` because this URL is where
32071
+ * loan-lifecycle callbacks get delivered and is cryptographically signed by
32072
+ * the loan owner: allowing `http:` would let a signed registration point at
32073
+ * a plaintext endpoint (or a link-local/loopback address reachable only from
32074
+ * the callback sender's own network), and the SDK is the natural place to
32075
+ * refuse that before it's ever signed or transmitted.
32076
+ *
32077
+ * @internal
32078
+ */ zod.z.object({
32079
+ loanId: zod.z.string().uuid(),
32080
+ webhookUrl: zod.z.string().url().refine((value)=>isHttpsUrl$1(value), 'webhookUrl must use the https scheme').nullable()
32081
+ }).strict();
32082
+ /**
32083
+ * Zod schema for the `POST /v1/borrowKit/loans/:loan_id/webhookRegistration`
32084
+ * API response.
32085
+ *
32086
+ * The Borrow Service API wraps the webhook registration payload in a `data`
32087
+ * envelope.
32088
+ *
32089
+ * @internal
32090
+ */ zod.z.object({
32091
+ data: webhookRegistrationPayloadSchema
32092
+ });
32093
+ /** @internal */ const marketAssetSchema = zod.z.object({
32094
+ symbol: zod.z.string().min(1),
32095
+ address: zod.z.string().regex(EVM_ADDRESS_REGEX),
32096
+ decimals: zod.z.number().int().nonnegative()
32097
+ });
32098
+ /**
32099
+ * Wire shape for a typed token amount: raw atoms as an integer string plus the
32100
+ * token's decimals, matching `@core/amounts` {@link AmountJSON}.
32101
+ *
32102
+ * @internal
32103
+ */ const amountJsonSchema = zod.z.object({
32104
+ raw: zod.z.string().refine(isNonNegativeBigIntLike, {
32105
+ message: 'raw must be a non-negative bigint-compatible string'
32106
+ }),
32107
+ decimals: zod.z.number().int().nonnegative()
32108
+ });
32109
+ /**
32110
+ * Wire shape for a single borrow market returned by
32111
+ * `GET /v1/borrowKit/markets/:chain/:market_id`. `chain` is the Borrow Service
32112
+ * API chain code (mapped back to the SDK chain by `toMarketInfo`); display
32113
+ * ratios arrive as numbers, token amounts as `{ raw, decimals }` objects.
32114
+ *
32115
+ * @remarks `lltv`, `borrowAssets`, `liquidity`, `borrowApy`, `utilization`,
32116
+ * and `refreshedAt` are all nullable because the service's economics are
32117
+ * cached projections, not live reads: a market that has been discovered but
32118
+ * not yet backfilled by the cache reports every economic field as `null`
32119
+ * rather than a placeholder value. An idle market keeps its last-known values
32120
+ * and old `refreshedAt` rather than reporting zeros, so `null` unambiguously
32121
+ * means "never backfilled." `borrowCap` is always `null` (Morpho Blue has no
32122
+ * per-market cap) but carried anyway so the field does not have to be added
32123
+ * later as a breaking change; it is also optional since the service may omit
32124
+ * it entirely.
32125
+ *
32126
+ * @internal
32127
+ */ const marketResponseSchema = zod.z.object({
32128
+ marketId: zod.z.string().min(1),
32129
+ protocol: zod.z.enum([
32130
+ 'morpho'
32131
+ ]),
32132
+ chain: zod.z.string().min(1),
32133
+ loanAsset: marketAssetSchema,
32134
+ collateralAsset: marketAssetSchema,
32135
+ lltv: zod.z.number().nonnegative().nullable(),
32136
+ borrowCap: amountJsonSchema.nullable().optional(),
32137
+ borrowAssets: amountJsonSchema.nullable(),
32138
+ liquidity: amountJsonSchema.nullable(),
32139
+ borrowApy: zod.z.number().nonnegative().nullable(),
32140
+ utilization: zod.z.number().nonnegative().nullable(),
32141
+ refreshedAt: zod.z.string().datetime({
32142
+ offset: true
32143
+ }).nullable()
32144
+ });
32145
+ /**
32146
+ * Zod schema for the `GET /v1/borrowKit/markets/:chain/:market_id` API
32147
+ * response. The Borrow Service wraps every response in a `data` envelope;
32148
+ * {@link marketResponseSchema} itself stays unwrapped since it is also reused
32149
+ * per-entry inside {@link listMarketsResponseSchema}.
32150
+ *
32151
+ * @internal
32152
+ */ zod.z.object({
32153
+ data: marketResponseSchema
32154
+ });
32155
+ /**
32156
+ * Wire shape for a page of borrow markets returned by
32157
+ * `GET /v1/borrowKit/markets`. Reuses {@link marketResponseSchema} per entry so
32158
+ * the per-market wire format stays defined in one place, and adds the
32159
+ * pagination envelope: an opaque `pageAfter` cursor absent on the last page.
32160
+ * The Borrow Service wraps every response in a `data` envelope.
32161
+ *
32162
+ * @internal
32163
+ */ zod.z.object({
32164
+ data: zod.z.object({
32165
+ markets: zod.z.array(marketResponseSchema),
32166
+ pagination: zod.z.object({
32167
+ pageAfter: zod.z.string().optional()
32168
+ })
32169
+ })
32170
+ });
32171
+
32172
+ /** @internal */ const BORROW_CHAIN_TO_API = {
32173
+ [Blockchain.Arc]: 'ARC',
32174
+ [Blockchain.Arc_Testnet]: 'ARC-TESTNET'
32175
+ };
32176
+
32177
+ Object.fromEntries(Object.entries(BORROW_CHAIN_TO_API).map(([sdkChain, apiChain])=>[
32178
+ apiChain,
32179
+ sdkChain
32180
+ ]));
32181
+
32182
+ /**
32183
+ * Schema for the Borrow Service configuration options.
32184
+ *
32185
+ * `apiKey` carries a Circle API key (`<ENV>_API_KEY:<keyId>:<keySecret>`) or a
32186
+ * legacy `KIT_KEY:<keyId>:<keySecret>` value. It is shape-checked only — as
32187
+ * with every other field here, the credential's format is the provider's call,
32188
+ * and `buildConfig` rejects a malformed one via `isValidApiKey`. The empty
32189
+ * string is allowed on purpose: `process.env.CIRCLE_API_KEY ?? ''` yields one
32190
+ * when the variable is unset, and the provider reads that as "no credential"
32191
+ * rather than as a malformed one.
32192
+ *
32193
+ * This schema is `.strict()`, so a field missing here is not merely unvalidated
32194
+ * — it is rejected outright, which is what made an `apiKey` config unusable
32195
+ * before it was listed.
32196
+ *
32197
+ * @internal
32198
+ */ const borrowServiceConfigSchema = zod.z.object({
32199
+ apiKey: zod.z.string().optional(),
32200
+ baseUrl: zod.z.string().url('baseUrl must be a valid URL').optional()
32201
+ }).strict();
32202
+ /**
32203
+ * Runtime schema for {@link GetLoansParams}.
32204
+ *
32205
+ * @example
32206
+ * ```typescript
32207
+ * import { getLoansParamsSchema } from '@circle-fin/borrow-kit'
32208
+ *
32209
+ * const result = getLoansParamsSchema.safeParse({
32210
+ * walletAddress: '0x1111111111111111111111111111111111111111',
32211
+ * chain: 'Arc_Testnet',
32212
+ * })
32213
+ * ```
32214
+ */ zod.z.object({
32215
+ walletAddress: evmAddressSchema$1,
32216
+ chain: chainIdentifierSchema,
32217
+ pageSize: zod.z.number().int().positive().optional(),
32218
+ pageAfter: zod.z.string().min(1).optional(),
32219
+ config: borrowServiceConfigSchema.optional()
32220
+ }).strict();
32221
+ /**
32222
+ * Runtime schema for {@link GetIntegratorConfigParams}.
32223
+ *
32224
+ * @example
32225
+ * ```typescript
32226
+ * import { getIntegratorConfigParamsSchema } from '@circle-fin/borrow-kit'
32227
+ *
32228
+ * const result = getIntegratorConfigParamsSchema.safeParse({
32229
+ * config: { apiKey: 'TEST_API_KEY:key-id:key-secret' },
32230
+ * })
32231
+ * ```
32232
+ */ zod.z.object({
32233
+ config: borrowServiceConfigSchema.optional()
32234
+ }).strict();
32235
+ /**
32236
+ * Runtime schema for {@link GetMarketParams}.
32237
+ *
32238
+ * @example
32239
+ * ```typescript
32240
+ * import { getMarketParamsSchema } from '@circle-fin/borrow-kit'
32241
+ *
32242
+ * const result = getMarketParamsSchema.safeParse({
32243
+ * chain: 'Arc_Testnet',
32244
+ * marketId: '0xabc...',
32245
+ * })
32246
+ * ```
32247
+ */ zod.z.object({
32248
+ chain: chainIdentifierSchema,
32249
+ marketId: zod.z.string().min(1),
32250
+ config: borrowServiceConfigSchema.optional()
32251
+ }).strict();
32252
+ /**
32253
+ * Runtime schema for {@link SetIntegratorConfigParams}.
32254
+ *
32255
+ * Both fee fields are required, so neither half is accepted alone.
32256
+ * `integratorFeeAddress` may be `null` only when `integratorFeeBps` is 0, which
32257
+ * turns the fee off and clears the recipient. A rate above 0 with no recipient
32258
+ * is unusable and is rejected.
32259
+ *
32260
+ * @example
32261
+ * ```typescript
32262
+ * import { setIntegratorConfigParamsSchema } from '@circle-fin/borrow-kit'
32263
+ *
32264
+ * const result = setIntegratorConfigParamsSchema.safeParse({
32265
+ * integratorFeeBps: 25,
32266
+ * integratorFeeAddress: '0x1111111111111111111111111111111111111111',
32267
+ * })
32268
+ *
32269
+ * // Turning the fee off and clearing the recipient.
32270
+ * const cleared = setIntegratorConfigParamsSchema.safeParse({
32271
+ * integratorFeeBps: 0,
32272
+ * integratorFeeAddress: null,
32273
+ * })
32274
+ * ```
32275
+ */ zod.z.object({
32276
+ integratorFeeBps: zod.z.number().int().min(0).max(10_000),
32277
+ integratorFeeAddress: evmAddressSchema$1.nullable(),
32278
+ config: borrowServiceConfigSchema.optional()
32279
+ }).strict().refine((params)=>params.integratorFeeAddress !== null || params.integratorFeeBps === 0, {
32280
+ message: 'integratorFeeAddress can only be null when integratorFeeBps is 0',
32281
+ path: [
32282
+ 'integratorFeeAddress'
32283
+ ]
32284
+ });
32285
+ /** @internal */ const HUMAN_READABLE_AMOUNT_REGEX = /^(?:0|[1-9]\d*)(?:\.\d+)?$/;
32286
+ /**
32287
+ * @param maxDecimals - Decimal places the amount may carry, or `null` for no
32288
+ * cap. USDC amounts take the default six; an amount denominated in a market's
32289
+ * own collateral token may be finer, so those pass `null`.
32290
+ * @internal
32291
+ */ function createPositiveAmountSchema(field, maxDecimals = 6) {
32292
+ const positive = zod.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`);
32293
+ if (maxDecimals === null) {
32294
+ return positive;
32295
+ }
32296
+ return positive.refine((value)=>(value.split('.')[1]?.length ?? 0) <= maxDecimals, `${field} must have at most ${maxDecimals.toString()} decimal places`);
32297
+ }
32298
+ /** @internal */ const positiveAmountSchema = createPositiveAmountSchema('repayAmount');
32299
+ const NIL_UUID = '00000000-0000-0000-0000-000000000000';
32300
+ const idempotencyKeySchema = zod.z.string().uuid().refine((value)=>value !== NIL_UUID, {
32301
+ message: 'idempotencyKey must not be the nil UUID; generate a fresh one per write'
32302
+ });
32303
+ /** @internal */ const adapterContextSchema = zod.z.object({
32304
+ // prepareAction is declared in the shape (rather than checked only via
32305
+ // .passthrough()) so its value is read off the input by property access:
32306
+ // .passthrough() only copies an input's own enumerable keys into its
32307
+ // output, which drops prototype methods like a class's prepareAction.
32308
+ adapter: adapterSchema.extend({
32309
+ prepareAction: zod.z.unknown()
32310
+ }).passthrough().refine((adapter)=>typeof adapter.prepareAction === 'function', 'adapter must expose prepareAction'),
32311
+ chain: chainIdentifierSchema,
32312
+ address: evmAddressSchema$1.optional()
32313
+ }).strict();
32314
+ /**
32315
+ * Shared `superRefine` enforcing the address/adapter-capability contract: a
32316
+ * developer-controlled adapter must supply `address` (the kit cannot resolve
32317
+ * it), and a user-controlled adapter must not (the adapter itself resolves
32318
+ * it — a caller-supplied value would silently take precedence, letting the
32319
+ * two disagree). Applied to every schema whose `from` shape carries an
32320
+ * adapter with a declared `addressContext` capability, so every Borrow Kit
32321
+ * write rejects a mismatched `from` the same way.
32322
+ *
32323
+ * @internal
32324
+ */ function refineAddressContext(from, context) {
32325
+ const addressContext = from.adapter.capabilities?.addressContext;
32326
+ if (addressContext === 'developer-controlled' && from.address === undefined) {
32327
+ context.addIssue({
32328
+ code: zod.z.ZodIssueCode.custom,
32329
+ message: 'address is required for developer-controlled adapters',
32330
+ path: [
32331
+ 'address'
32332
+ ]
32333
+ });
32334
+ }
32335
+ if (addressContext === 'user-controlled' && from.address !== undefined) {
32336
+ context.addIssue({
32337
+ code: zod.z.ZodIssueCode.custom,
32338
+ message: 'address must be resolved by user-controlled adapters',
32339
+ path: [
32340
+ 'address'
32341
+ ]
32342
+ });
32343
+ }
32344
+ }
32345
+ /** @internal */ const borrowExecutionFromSchema = zod.z.object({
32346
+ // prepareAction/validateChainSupport/capabilities are declared in the
32347
+ // shape (rather than checked only via .passthrough()) so their values are
32348
+ // read off the input by property access: .passthrough() only copies an
32349
+ // input's own enumerable keys into its output, which drops a prototype
32350
+ // method or getter like a class's prepareAction/validateChainSupport/
32351
+ // capabilities. capabilities is read below and by refineAddressContext.
32352
+ adapter: adapterSchema.extend({
32353
+ prepareAction: zod.z.unknown(),
32354
+ validateChainSupport: zod.z.unknown(),
32355
+ capabilities: zod.z.unknown()
32356
+ }).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'),
32357
+ chain: chainIdentifierSchema,
32358
+ address: evmAddressSchema$1.optional()
32359
+ }).strict().superRefine(refineAddressContext);
32360
+ /**
32361
+ * Runtime schema for {@link RepayQuoteParams}.
32362
+ */ const repayQuoteParamsSchema = zod.z.object({
32363
+ loanId: zod.z.string().uuid(),
32364
+ chain: chainIdentifierSchema,
32365
+ repayAmount: positiveAmountSchema,
32366
+ config: borrowServiceConfigSchema.optional()
32367
+ }).strict();
32368
+ /** Runtime schema for {@link RepayParams}. */ repayQuoteParamsSchema.omit({
32369
+ chain: true
32370
+ }).extend({
32371
+ idempotencyKey: idempotencyKeySchema.optional(),
32372
+ from: borrowExecutionFromSchema
32373
+ });
32374
+ /** Runtime schema for requesting a full-close quote. */ const closeLoanQuoteParamsSchema = zod.z.object({
32375
+ loanId: zod.z.string().uuid(),
32376
+ chain: chainIdentifierSchema,
32377
+ slippageBps: zod.z.number().int().min(0).max(10_000).optional(),
32378
+ config: borrowServiceConfigSchema.optional()
32379
+ }).strict();
32380
+ /** Runtime schema for atomically closing a loan. */ closeLoanQuoteParamsSchema.omit({
32381
+ chain: true
32382
+ }).extend({
32383
+ idempotencyKey: idempotencyKeySchema.optional(),
32384
+ from: borrowExecutionFromSchema
32385
+ });
32386
+ /**
32387
+ * Runtime schema for {@link GetPositionParams}.
32388
+ *
32389
+ * @example
32390
+ * ```typescript
32391
+ * import { getPositionParamsSchema } from '@circle-fin/borrow-kit'
32392
+ *
32393
+ * const result = getPositionParamsSchema.safeParse({
32394
+ * loanId: '11111111-1111-4111-8111-111111111111',
32395
+ * })
32396
+ * ```
32397
+ */ zod.z.object({
32398
+ loanId: zod.z.string().uuid(),
32399
+ config: borrowServiceConfigSchema.optional()
32400
+ }).strict();
32401
+ /**
32402
+ * Schema for the adapter context within Borrow operations.
32403
+ *
32404
+ * `.strict()` so a typo nested inside `from` fails fast instead of being
32405
+ * silently stripped. The address field is optional (resolved from the
32406
+ * adapter at runtime).
32407
+ *
32408
+ * @internal
32409
+ */ const borrowAdapterContextSchema = zod.z.object({
32410
+ // signTypedData/capabilities are declared in the shape (rather than
32411
+ // checked only via .passthrough()) so their values are read off the input
32412
+ // by property access: .passthrough() only copies an input's own
32413
+ // enumerable keys into its output, which drops a prototype method or
32414
+ // getter like a class's signTypedData/capabilities. capabilities is read
32415
+ // by refineAddressContext below.
32416
+ adapter: adapterSchema.extend({
32417
+ signTypedData: zod.z.unknown(),
32418
+ capabilities: zod.z.unknown()
32419
+ }).passthrough().refine(// supportsSignTypedData is optional on SignTypedDataAdapter (see
32420
+ // @core/adapter-evm's hasSignTypedData/canSignTypedData): only
32421
+ // signTypedData itself is required here.
32422
+ (adapter)=>typeof adapter.signTypedData === 'function', 'adapter must support signTypedData'),
32423
+ // BorrowAdapterContext accepts a wider chain field, but runtime
32424
+ // validation must stay constrained to chains where loans exist. No cast
32425
+ // needed here: inferring straight from borrowChainIdentifierSchema keeps
32426
+ // this schema's exported type accurate (only the Borrow chain set),
32427
+ // unlike the previous `as unknown as typeof chainIdentifierSchema` cast,
32428
+ // which over-widened it to the full ChainIdentifier union.
32429
+ chain: borrowChainIdentifierSchema,
32430
+ address: zod.z.string().min(1, 'address must not be empty').optional()
32431
+ }).strict()// Same address/adapter-capability contract every other Borrow Kit write
32432
+ // enforces via borrowExecutionFromSchema: a developer-controlled adapter
32433
+ // without `address` fails fast with a named message instead of falling
32434
+ // through to adapter.getAddress(); a user-controlled adapter with `address`
32435
+ // set is rejected instead of silently taking precedence.
32436
+ .superRefine(refineAddressContext);
32437
+ /** @internal */ const borrowParamsBaseSchema = zod.z.object({
32438
+ from: adapterContextSchema,
32439
+ borrowAmount: createPositiveAmountSchema('borrowAmount'),
32440
+ slippageBps: zod.z.number().int().min(0).max(10_000).optional(),
32441
+ idempotencyKey: idempotencyKeySchema.optional(),
32442
+ config: borrowServiceConfigSchema.optional()
32443
+ });
32444
+ /**
32445
+ * Runtime schema for {@link BorrowParams}.
32446
+ *
32447
+ * One strict object with a refinement, rather than a union of a market branch
32448
+ * and a loan branch: a union that fails every branch reports one `invalid_union`
32449
+ * issue, which costs the caller the field that actually failed. The refinement
32450
+ * states the rule it enforces, and every other field keeps naming itself.
32451
+ */ borrowParamsBaseSchema.extend({
32452
+ marketId: zod.z.string().min(1).optional(),
32453
+ loanId: zod.z.string().uuid().optional()
32454
+ }).strict().refine((params)=>params.marketId === undefined !== (params.loanId === undefined), {
32455
+ message: 'Provide exactly one of marketId or loanId'
32456
+ });
32457
+ /**
32458
+ * Schema for the adapter context within reward-claiming operations.
32459
+ *
32460
+ * Validate that a properly-shaped adapter instance and a valid chain
32461
+ * identifier are provided. The address field is optional at the schema
32462
+ * level (resolved from the adapter at runtime for user-controlled
32463
+ * adapters, required for developer-controlled ones — that distinction is
32464
+ * enforced by {@link BorrowAdapterContext}'s conditional `AddressField`,
32465
+ * not by this runtime schema). `.strict()` so a typo nested inside `from`
32466
+ * fails fast instead of being silently stripped.
32467
+ *
32468
+ * Reward claiming is restricted to the Borrow chain identifiers (Arc and
32469
+ * Arc Testnet), which is narrower than the general
32470
+ * {@link chainIdentifierSchema} `repay`/`borrow` accept.
32471
+ *
32472
+ * @internal
32473
+ */ const claimRewardsAdapterContextSchema = zod.z.object({
32474
+ adapter: adapterSchema,
32475
+ chain: borrowChainIdentifierSchema,
32476
+ address: evmAddressSchema$1.optional()
32477
+ }).strict()// Same address/adapter-capability contract every other Borrow Kit write
32478
+ // enforces via borrowExecutionFromSchema: a developer-controlled adapter
32479
+ // without `address` fails fast with a named message instead of falling
32480
+ // through to adapter.getAddress(); a user-controlled adapter with `address`
32481
+ // set is rejected instead of silently taking precedence.
32482
+ .superRefine(refineAddressContext);
32483
+ /** @internal */ const borrowPreviewParamsBaseSchema = zod.z.object({
32484
+ chain: chainIdentifierSchema,
32485
+ marketId: zod.z.string().min(1),
32486
+ config: borrowServiceConfigSchema.optional()
32487
+ });
32488
+ /** Runtime schema for a first-open borrow quote. @internal */ const openLoanQuoteParamsSchema = borrowPreviewParamsBaseSchema.extend({
32489
+ walletAddress: evmAddressSchema$1,
32490
+ borrowAmount: createPositiveAmountSchema('borrowAmount'),
32491
+ slippageBps: zod.z.number().int().min(0).max(10_000).optional()
32492
+ }).strict();
32493
+ /** Runtime schema for an existing-loan borrow quote. @internal */ const borrowMoreQuoteParamsSchema = zod.z.object({
32494
+ loanId: zod.z.string().uuid(),
32495
+ borrowAmount: createPositiveAmountSchema('borrowAmount'),
32496
+ slippageBps: zod.z.number().int().min(0).max(10_000).optional(),
32497
+ config: borrowServiceConfigSchema.optional()
32498
+ }).strict();
32499
+ /** Runtime schema for {@link BorrowQuoteParams}. */ zod.z.union([
32500
+ openLoanQuoteParamsSchema,
32501
+ borrowMoreQuoteParamsSchema
32502
+ ]);
32503
+ /** Runtime schema for {@link RequiredCollateralParams}. */ borrowPreviewParamsBaseSchema.extend({
32504
+ borrowAmount: createPositiveAmountSchema('borrowAmount'),
32505
+ targetHealthFactor: zod.z.number().positive().finite()
32506
+ }).strict();
32507
+ // Uncapped: repayments are USDC, but collateral is the market's own token and
32508
+ // may hold more precision than USDC's six places.
32509
+ /** @internal */ const collateralAmountSchema = createPositiveAmountSchema('collateralAmount', null);
32510
+ /**
32511
+ * Validation schema for ClaimRewardsParams.
32512
+ *
32513
+ * @example
32514
+ * ```typescript
32515
+ * import { claimRewardsParamsSchema } from '@circle-fin/borrow-kit'
32516
+ *
32517
+ * const result = claimRewardsParamsSchema.safeParse({
32518
+ * from: { adapter, chain: 'Arc_Testnet' },
32519
+ * })
32520
+ * ```
32521
+ */ zod.z.object({
32522
+ from: claimRewardsAdapterContextSchema,
32523
+ config: borrowServiceConfigSchema.optional()
32524
+ }).strict();
32525
+ /**
32526
+ * Validation schema for GetClaimRewardsQuoteParams.
32527
+ *
32528
+ * @example
32529
+ * ```typescript
32530
+ * import { getClaimRewardsQuoteParamsSchema } from '@circle-fin/borrow-kit'
32531
+ *
32532
+ * const result = getClaimRewardsQuoteParamsSchema.safeParse({
32533
+ * from: { adapter, chain: 'Arc_Testnet' },
32534
+ * })
32535
+ * ```
32536
+ */ zod.z.object({
32537
+ from: claimRewardsAdapterContextSchema,
32538
+ config: borrowServiceConfigSchema.optional()
32539
+ }).strict();
32540
+ /** @internal */ const marketSortBySchema = zod.z.enum([
32541
+ 'lltv',
32542
+ 'borrowApy'
32543
+ ]);
32544
+ /**
32545
+ * Build a schema for an optional non-negative decimal filter string.
32546
+ *
32547
+ * Accepts values like `'0'`, `'100'`, `'0.86'`; rejects negatives, leading
32548
+ * dots, and non-numeric input so a malformed filter fails fast.
32549
+ *
32550
+ * @param field - The filter field name, used in the rejection message.
32551
+ * @returns A Zod string schema constrained to a non-negative decimal form.
32552
+ * @internal
32553
+ */ function decimalFilterSchema(field) {
32554
+ return zod.z.string().regex(/^\d+(\.\d+)?$/, `${field} must be a non-negative decimal string`);
32555
+ }
32556
+ const exploreMarketsParamsBase = zod.z.object({
32557
+ chain: chainIdentifierSchema,
32558
+ minLltv: decimalFilterSchema('minLltv').optional(),
32559
+ maxLltv: decimalFilterSchema('maxLltv').optional(),
32560
+ minBorrow: decimalFilterSchema('minBorrow').optional(),
32561
+ maxBorrow: decimalFilterSchema('maxBorrow').optional(),
32562
+ sortBy: marketSortBySchema.optional(),
32563
+ // Provisional bounds: the backend has not published a pageSize range, so
32564
+ // reject only implausible values rather than plausible ones.
32565
+ pageSize: zod.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(),
32566
+ pageAfter: zod.z.string().min(1, 'pageAfter must not be empty').optional(),
32567
+ config: borrowServiceConfigSchema.optional()
32568
+ }).strict();
32569
+ /**
32570
+ * Runtime schema for {@link MaxBorrowParams}.
32571
+ *
32572
+ * The collateral amount is not held to the loan asset's six decimal places: it
32573
+ * denominates the market's collateral token, whose precision may be finer.
32574
+ */ borrowPreviewParamsBaseSchema.extend({
32575
+ collateralAmount: collateralAmountSchema
32576
+ }).strict();
32577
+ /** Runtime schema for {@link WithdrawCollateralQuoteParams}. */ const withdrawCollateralQuoteParamsSchema = zod.z.object({
32578
+ loanId: zod.z.string().uuid(),
32579
+ chain: chainIdentifierSchema,
32580
+ collateralAmount: collateralAmountSchema,
32581
+ slippageBps: zod.z.number().int().min(0).max(10_000).optional(),
32582
+ config: borrowServiceConfigSchema.optional()
32583
+ }).strict();
32584
+ /**
32585
+ * Maximum accepted signature deadline: 300 seconds from now, matching the
32586
+ * Borrow Service's own hard limit on `WebhookRegistration` deadlines. A wider
32587
+ * SDK-side window would let a caller sign a deadline the service always
32588
+ * rejects.
32589
+ *
32590
+ * @internal
32591
+ */ const MAX_DEADLINE_SKEW_SECONDS = 300;
32592
+ /**
32593
+ * True when `value` parses as a URL whose scheme is exactly `https:`.
32594
+ *
32595
+ * Uses the WHATWG `URL` parser rather than `startsWith('https://')` so the
32596
+ * check is scheme-normalized (case-insensitive, e.g. `HTTPS://...` still
32597
+ * passes) instead of a literal prefix match. `value` has already passed
32598
+ * `z.string().url()` by the time this runs, but a caller could still supply
32599
+ * a string that `URL` itself rejects, so the parse is guarded.
32600
+ *
32601
+ * @internal
32602
+ */ function isHttpsUrl(value) {
32603
+ try {
32604
+ return new URL(value).protocol === 'https:';
32605
+ } catch {
32606
+ return false;
32607
+ }
32608
+ }
32609
+ /**
32610
+ * Validation schema for RegisterWebhookParams.
32611
+ *
32612
+ * @example
32613
+ * ```typescript
32614
+ * import { registerWebhookParamsSchema } from '@circle-fin/borrow-kit'
32615
+ *
32616
+ * const result = registerWebhookParamsSchema.safeParse({
32617
+ * from: { adapter, chain: 'Arc_Testnet' },
32618
+ * loanId: '11111111-1111-4111-8111-111111111111',
32619
+ * webhookUrl: 'https://example.com/webhook',
32620
+ * })
32621
+ * ```
32622
+ */ zod.z.object({
32623
+ from: borrowAdapterContextSchema,
32624
+ // loanId must be a UUID, consistent with every other loan-scoped schema
32625
+ // in this package (repayQuoteParamsSchema, closeLoanQuoteParamsSchema,
32626
+ // borrowParamsSchema) and with the provider-level
32627
+ // registerWebhookInputSchema, which already enforces this.
32628
+ loanId: zod.z.string().uuid(),
32629
+ // Restricted to https: for the same reason as the provider-level
32630
+ // registerWebhookInputSchema — this URL receives a cryptographically
32631
+ // signed, owner-authorized registration, and http:// would let that
32632
+ // signed intent point at a plaintext or link-local/loopback endpoint.
32633
+ webhookUrl: zod.z.string().url('webhookUrl must be a valid URL').refine((value)=>isHttpsUrl(value), 'webhookUrl must use the https scheme').nullable().optional(),
32634
+ deadline: zod.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(),
32635
+ config: borrowServiceConfigSchema.optional()
32636
+ }).strict();
32637
+ /**
32638
+ * Reject a filter range whose lower bound exceeds its upper bound.
32639
+ *
32640
+ * Each bound is validated independently, so `{ minLltv: '0.9', maxLltv: '0.1' }`
32641
+ * would otherwise pass and return a silently empty page; comparing the bounds
32642
+ * numerically turns that contradiction into a clear validation error. Shared by
32643
+ * the single-page and iterator schemas so the two cannot drift.
32644
+ *
32645
+ * @param value - The parsed explore filters.
32646
+ * @param ctx - The Zod refinement context that collects any range issues.
32647
+ * @internal
32648
+ */ function refineFilterRanges(value, ctx) {
32649
+ if (value.minLltv !== undefined && value.maxLltv !== undefined && Number(value.minLltv) > Number(value.maxLltv)) {
32650
+ ctx.addIssue({
32651
+ code: zod.z.ZodIssueCode.custom,
32652
+ path: [
32653
+ 'maxLltv'
32654
+ ],
32655
+ message: 'maxLltv must be greater than or equal to minLltv'
32656
+ });
32657
+ }
32658
+ if (value.minBorrow !== undefined && value.maxBorrow !== undefined && Number(value.minBorrow) > Number(value.maxBorrow)) {
32659
+ ctx.addIssue({
32660
+ code: zod.z.ZodIssueCode.custom,
32661
+ path: [
32662
+ 'maxBorrow'
32663
+ ],
32664
+ message: 'maxBorrow must be greater than or equal to minBorrow'
32665
+ });
32666
+ }
32667
+ }
32668
+ /**
32669
+ * Runtime schema for {@link ExploreMarketsParams}.
32670
+ *
32671
+ * `chain` is required; every filter is optional. `pageAfter` is an opaque
32672
+ * non-empty cursor and `pageSize` a positive integer (provisional upper bound
32673
+ * 1000, pending backend confirmation). Unknown keys are rejected, and a range
32674
+ * whose minimum exceeds its maximum is rejected rather than returning a
32675
+ * silently empty page.
32676
+ *
32677
+ * @example
32678
+ * ```typescript
32679
+ * import { exploreMarketsParamsSchema } from '@circle-fin/borrow-kit'
32680
+ *
32681
+ * const result = exploreMarketsParamsSchema.safeParse({
32682
+ * chain: 'Arc_Testnet',
32683
+ * minLltv: '0.8',
32684
+ * sortBy: 'borrowApy',
32685
+ * })
32686
+ * ```
32687
+ */ exploreMarketsParamsBase.superRefine(refineFilterRanges);
32688
+ /**
32689
+ * Runtime schema for {@link ExploreMarketsIteratorParams}.
32690
+ *
32691
+ * Identical to {@link exploreMarketsParamsSchema} minus `pageAfter`: the
32692
+ * iterator owns the cursor and advances through pages itself.
32693
+ *
32694
+ * @example
32695
+ * ```typescript
32696
+ * import { exploreMarketsIteratorParamsSchema } from '@circle-fin/borrow-kit'
32697
+ *
32698
+ * const result = exploreMarketsIteratorParamsSchema.safeParse({
32699
+ * chain: 'Arc_Testnet',
32700
+ * sortBy: 'borrowApy',
32701
+ * })
32702
+ * ```
32703
+ */ exploreMarketsParamsBase.omit({
32704
+ pageAfter: true
32705
+ }).superRefine(refineFilterRanges);
32706
+ /** Runtime schema for {@link WithdrawCollateralParams}. */ withdrawCollateralQuoteParamsSchema.omit({
32707
+ chain: true
32708
+ }).extend({
32709
+ idempotencyKey: idempotencyKeySchema.optional(),
32710
+ from: borrowExecutionFromSchema
32711
+ });
32712
+ /** Runtime schema for {@link AddCollateralQuoteParams}. */ const addCollateralQuoteParamsSchema = zod.z.object({
32713
+ loanId: zod.z.string().uuid(),
32714
+ chain: chainIdentifierSchema,
32715
+ collateralAmount: collateralAmountSchema,
32716
+ config: borrowServiceConfigSchema.optional()
32717
+ }).strict();
32718
+ /** Runtime schema for {@link AddCollateralParams}. */ addCollateralQuoteParamsSchema.omit({
32719
+ chain: true
32720
+ }).extend({
32721
+ idempotencyKey: idempotencyKeySchema.optional(),
32722
+ from: borrowExecutionFromSchema
32723
+ });
32724
+
32725
+ /** SDK name used in telemetry payloads. */ resolveKitSdkName(pkg.name);
32726
+
32727
+ // Auto-register this kit for user agent tracking
32728
+ registerKit(`${pkg.name}/${pkg.version}`);
32729
+
31121
32730
  async function bridge(context, params) {
31122
32731
  const kit = createBridgeKit(context);
31123
32732
  registerActionHandlers(kit, context.actions.bridge, 'bridge');