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