@avalabs/fusion-sdk 0.24.0 → 0.25.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 (41) hide show
  1. package/dist/errors.cjs +1 -1
  2. package/dist/errors.cjs.map +1 -1
  3. package/dist/errors.d.cts +18 -1
  4. package/dist/errors.d.ts +18 -1
  5. package/dist/errors.js +1 -1
  6. package/dist/errors.js.map +1 -1
  7. package/dist/transfer-service/markr/_schema.cjs +1 -1
  8. package/dist/transfer-service/markr/_schema.cjs.map +1 -1
  9. package/dist/transfer-service/markr/_schema.js +1 -1
  10. package/dist/transfer-service/markr/_schema.js.map +1 -1
  11. package/dist/transfer-service/markr/_utils.cjs +1 -1
  12. package/dist/transfer-service/markr/_utils.cjs.map +1 -1
  13. package/dist/transfer-service/markr/_utils.js +1 -1
  14. package/dist/transfer-service/markr/_utils.js.map +1 -1
  15. package/dist/transfer-service/markr/recurring/_api.cjs +1 -1
  16. package/dist/transfer-service/markr/recurring/_api.cjs.map +1 -1
  17. package/dist/transfer-service/markr/recurring/_api.js +1 -1
  18. package/dist/transfer-service/markr/recurring/_api.js.map +1 -1
  19. package/dist/transfer-service/markr/recurring/_chain-info.cjs +1 -1
  20. package/dist/transfer-service/markr/recurring/_chain-info.cjs.map +1 -1
  21. package/dist/transfer-service/markr/recurring/_chain-info.js +1 -1
  22. package/dist/transfer-service/markr/recurring/_chain-info.js.map +1 -1
  23. package/dist/transfer-service/markr/recurring/_eligibility.cjs +1 -1
  24. package/dist/transfer-service/markr/recurring/_eligibility.cjs.map +1 -1
  25. package/dist/transfer-service/markr/recurring/_eligibility.js +1 -1
  26. package/dist/transfer-service/markr/recurring/_eligibility.js.map +1 -1
  27. package/dist/transfer-service/markr/recurring/_namespace.cjs +1 -1
  28. package/dist/transfer-service/markr/recurring/_namespace.cjs.map +1 -1
  29. package/dist/transfer-service/markr/recurring/_namespace.js +1 -1
  30. package/dist/transfer-service/markr/recurring/_namespace.js.map +1 -1
  31. package/dist/transfer-service/markr/recurring/_schema.cjs +1 -1
  32. package/dist/transfer-service/markr/recurring/_schema.cjs.map +1 -1
  33. package/dist/transfer-service/markr/recurring/_schema.js +1 -1
  34. package/dist/transfer-service/markr/recurring/_schema.js.map +1 -1
  35. package/dist/transfer-service/markr/recurring/types.cjs +1 -1
  36. package/dist/transfer-service/markr/recurring/types.cjs.map +1 -1
  37. package/dist/transfer-service/markr/recurring/types.d.cts +32 -23
  38. package/dist/transfer-service/markr/recurring/types.d.ts +32 -23
  39. package/dist/transfer-service/markr/recurring/types.js +1 -1
  40. package/dist/transfer-service/markr/recurring/types.js.map +1 -1
  41. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"_api.js","names":[],"sources":["../../../../src/transfer-service/markr/recurring/_api.ts"],"sourcesContent":["import { AbortedError, InvalidParamsError, ResponseValidationError } from '../../../errors';\nimport { combineUrlPathnames, fetchJson } from '../../fetch-utilities';\nimport { WrappedSwapTransactionResponseSchema, type WrappedSwapTransactionResponse } from '../_schema';\nimport { getAuthHeaders, type ApiOptions } from '../_api';\nimport { ListRecurringOrdersResponseSchema, RecurringQuoteResponseSchema } from './_schema';\nimport {\n RECURRING_UNLIMITED_ORDERS_SENTINEL,\n type ListRecurringOrdersParams,\n type ListRecurringOrdersResponse,\n type RecurringOrderActionApiParams,\n type RecurringQuoteParams,\n type RecurringQuoteResponse,\n type RecurringSwapParams,\n} from './types';\n\n/** bytes32 hex — same regex as `RecurringOrderSchema.orderId`. */\nconst ORDER_ID_REGEX = /^0x[0-9a-fA-F]{64}$/;\n\n/**\n * Retry policy for `/recurring/swap` and the order-action endpoints\n * (`/recurring/orders/{}/cancel`, `/recurring/orders/{}/pause`,\n * `/recurring/orders/{}/unpause`) — Markr documents all of them as\n * idempotent on the same params, so transient network / 5xx failures are\n * safe to replay. Mirrors the `markrGetCrossChainStatus` pattern but admits\n * POST (whereas the GET variant only whitelists safe verbs) and does NOT\n * retry 404 (for these endpoints, 404 means the resource genuinely doesn't\n * exist).\n */\nconst IDEMPOTENT_POST_RETRY_COUNT = 3;\n\nfunction retryIdempotentPost(ctx: { error?: unknown; response?: Response }): boolean {\n if (ctx.error) {\n if (ctx.error instanceof AbortedError) return false;\n return true;\n }\n const status = ctx.response?.status ?? 0;\n return status === 408 || status === 425 || status === 429 || (status >= 500 && status <= 599);\n}\n\n/**\n * Translate the SDK-public `numberOfOrders` value into Markr's wire shape:\n * - `Infinity` or `-1` → wire sentinel `-1` (unlimited).\n * - Integer in `[2, 365]` → passthrough (matches Markr's documented bounds).\n * - Anything else (`NaN`, `0`, `1`, negatives other than `-1`, non-integers,\n * values > 365, `-Infinity`) → `InvalidParamsError` at the SDK boundary.\n *\n * @see https://orchestrator-docs.markr.io/#/paths/~1recurring~1quote/post — Markr's\n * `numberOfOrders` spec: `-1` for infinite, or integer 2-365 inclusive.\n */\nfunction translateNumberOfOrders(input: number): number {\n if (input === Infinity || input === RECURRING_UNLIMITED_ORDERS_SENTINEL) {\n return RECURRING_UNLIMITED_ORDERS_SENTINEL;\n }\n\n if (!Number.isInteger(input) || input < 2 || input > 365) {\n throw new InvalidParamsError(\n 'Invalid numberOfOrders',\n `Expected an integer in [2, 365], Infinity, or -1 (unlimited). Got: ${String(input)}`,\n );\n }\n\n return input;\n}\n\nexport async function markrRecurringQuote(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: RecurringQuoteParams,\n): Promise<RecurringQuoteResponse> {\n const endpoint = '/recurring/quote';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const body = {\n appId: params.appId,\n chainId: params.chainId,\n tokenIn: params.tokenIn,\n tokenInDecimals: params.tokenInDecimals,\n tokenOut: params.tokenOut,\n tokenOutDecimals: params.tokenOutDecimals,\n // Inline `.toString()` — `JSON.stringify` cannot serialize bigint, so the\n // wire shape stays a decimal string.\n amount: params.amount.toString(),\n numberOfOrders: translateNumberOfOrders(params.numberOfOrders),\n frequency: params.frequency,\n slippage: params.slippage,\n };\n\n const rawJson = await fetchJson(url, {\n body: JSON.stringify(body),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n method: 'POST',\n });\n\n const parsed = RecurringQuoteResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(\n `Invalid response from Markr \"${endpoint}\" endpoint.`,\n parsed.error.issues,\n rawJson,\n );\n }\n\n return parsed.data;\n}\n\n/**\n * Fetches the first-fill swap calldata for a previously quoted recurring swap.\n *\n * Allowance must already cover `totalAmountIn` from the quote. The returned\n * `WrappedSwapTransactionResponse` is signed and broadcast by the caller (the\n * SDK does not sign on the recurring path).\n *\n * Idempotent on the same `uuid` per the Markr docs — retried on transient\n * network / 5xx failures via `retryIdempotentPost`.\n */\nexport async function markrRecurringSwap(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: RecurringSwapParams,\n): Promise<WrappedSwapTransactionResponse> {\n const endpoint = '/recurring/swap';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, {\n body: JSON.stringify(params),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n method: 'POST',\n retries: IDEMPOTENT_POST_RETRY_COUNT,\n retryOn: retryIdempotentPost,\n });\n\n const parsed = WrappedSwapTransactionResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(\n `Invalid response from Markr \"${endpoint}\" endpoint.`,\n parsed.error.issues,\n rawJson,\n );\n }\n\n return parsed.data;\n}\n\nexport async function markrListRecurringOrders(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: ListRecurringOrdersParams,\n): Promise<ListRecurringOrdersResponse> {\n // `URLSearchParams` URL-encodes each value — defense-in-depth against a\n // caller reaching from JS (no TS brand check) and passing an `address` like\n // `0x…&adminKey=x` that would otherwise inject extra query params.\n const searchParams = new URLSearchParams({ address: params.address });\n if (params.chainId !== undefined) searchParams.set('chainId', String(params.chainId));\n if (params.status !== undefined) searchParams.set('status', params.status);\n\n const endpoint = `/recurring/orders?${searchParams.toString()}`;\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = ListRecurringOrdersResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(\n `Invalid response from Markr \"/recurring/orders\" endpoint.`,\n parsed.error.issues,\n rawJson,\n );\n }\n\n return parsed.data;\n}\n\n/**\n * Shared implementation for the three calldata-returning order-action\n * endpoints (`cancel`, `pause`, `unpause`). All three share:\n * - identical body shape `{ address, chainId }`\n * - identical response shape (`WrappedSwapTransactionResponse`)\n * - identical bytes32 `orderId` validation (path-traversal defense before\n * URL interpolation — catches stale UUIDs / malformed values as a clear\n * `InvalidParamsError` at the SDK boundary rather than an opaque 404\n * from the orchestrator)\n * - identical idempotent-POST retry policy\n *\n * Kept private so all three exported helpers go through the same wire\n * contract — adding a new field (or tightening a check) is a one-place\n * change here.\n */\nasync function postRecurringOrderAction(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n action: 'cancel' | 'pause' | 'unpause',\n params: { orderId: `0x${string}`; address: string; chainId: number },\n): Promise<WrappedSwapTransactionResponse> {\n if (!ORDER_ID_REGEX.test(params.orderId)) {\n throw new InvalidParamsError(\n 'Invalid recurring orderId',\n `Expected 0x-prefixed bytes32 hex (66 chars). Got: ${JSON.stringify(params.orderId)}`,\n );\n }\n\n const endpoint = `/recurring/orders/${encodeURIComponent(params.orderId)}/${action}`;\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, {\n body: JSON.stringify({ address: params.address, chainId: params.chainId }),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n method: 'POST',\n retries: IDEMPOTENT_POST_RETRY_COUNT,\n retryOn: retryIdempotentPost,\n });\n\n const parsed = WrappedSwapTransactionResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(\n `Invalid response from Markr \"${endpoint}\" endpoint.`,\n parsed.error.issues,\n rawJson,\n );\n }\n\n return parsed.data;\n}\n\n/**\n * Fetches the calldata to cancel the recurring schedule identified by\n * `orderId`. The returned `WrappedSwapTransactionResponse` is signed and\n * broadcast on-chain by the caller — cancellation only takes effect after\n * the TX confirms, at which point Markr transitions the order's `status`\n * to `'cancelled'`.\n *\n * Only `'active'` and `'paused'` orders can be cancelled per the docs; an\n * attempt to cancel a `'completed'` (or otherwise non-cancellable) order\n * surfaces as `HttpError(400)` from the orchestrator.\n *\n * Idempotent on the same `(orderId, address, chainId)` triple per the Markr\n * docs — retried on transient network / 5xx failures via `retryIdempotentPost`.\n *\n * @see https://orchestrator-docs.markr.io/#/paths/~1recurring~1orders~1{orderId}~1cancel/post\n */\nexport function markrPrepareCancellation(\n apiOptions: ApiOptions,\n params: RecurringOrderActionApiParams,\n): Promise<WrappedSwapTransactionResponse> {\n return postRecurringOrderAction(apiOptions, 'cancel', params);\n}\n\n/**\n * Fetches the calldata to pause the recurring schedule identified by\n * `orderId`. The returned `WrappedSwapTransactionResponse` is signed and\n * broadcast on-chain by the caller — the schedule only transitions to\n * `status: 'paused'` once the TX confirms and Markr observes the on-chain\n * event.\n *\n * Only `'active'` orders can be paused per the docs; an attempt to pause a\n * non-`'active'` order surfaces as `HttpError(400)` from the orchestrator.\n *\n * Pausing preserves the existing ERC-20 allowance — when the user later\n * unpauses, no re-approval is required and no new native schedule fee is\n * charged. This is the key UX benefit of pause over cancel-and-recreate.\n *\n * Idempotent on the same `(orderId, address, chainId)` triple — retried\n * on transient network / 5xx failures via `retryIdempotentPost`.\n *\n * @see https://orchestrator-docs.markr.io/#tag/Recurring-Swaps/paths/~1recurring~1orders~1{orderId}~1pause/post\n */\nexport function markrPreparePause(\n apiOptions: ApiOptions,\n params: RecurringOrderActionApiParams,\n): Promise<WrappedSwapTransactionResponse> {\n return postRecurringOrderAction(apiOptions, 'pause', params);\n}\n\n/**\n * Fetches the calldata to unpause (resume) the recurring schedule\n * identified by `orderId`. The returned `WrappedSwapTransactionResponse` is\n * signed and broadcast on-chain by the caller — the schedule only\n * transitions back to `status: 'active'` once the TX confirms and Markr\n * observes the on-chain event.\n *\n * Only `'paused'` orders can be unpaused per the docs; an attempt to\n * unpause a non-`'paused'` order surfaces as `HttpError(400)` from the\n * orchestrator.\n *\n * Resumes execution from where the schedule left off — remaining fills\n * continue on the original `frequency` cadence and the orchestrator\n * recomputes `nextExecutionAt` after the TX confirms.\n *\n * Idempotent on the same `(orderId, address, chainId)` triple — retried\n * on transient network / 5xx failures via `retryIdempotentPost`.\n *\n * @see https://orchestrator-docs.markr.io/#tag/Recurring-Swaps/paths/~1recurring~1orders~1{orderId}~1unpause/post\n */\nexport function markrPrepareUnpause(\n apiOptions: ApiOptions,\n params: RecurringOrderActionApiParams,\n): Promise<WrappedSwapTransactionResponse> {\n return postRecurringOrderAction(apiOptions, 'unpause', params);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"_api.js","names":[],"sources":["../../../../src/transfer-service/markr/recurring/_api.ts"],"sourcesContent":["import { AbortedError, InvalidParamsError, ResponseValidationError } from '../../../errors';\nimport { combineUrlPathnames, fetchJson } from '../../fetch-utilities';\nimport { WrappedSwapTransactionResponseSchema, type WrappedSwapTransactionResponse } from '../_schema';\nimport { getAuthHeaders, type ApiOptions } from '../_api';\nimport {\n ListRecurringOrdersResponseSchema,\n RecurringQuoteResponseSchema,\n RecurringSwapResponseSchema,\n} from './_schema';\nimport {\n RECURRING_UNLIMITED_ORDERS_SENTINEL,\n type ListRecurringOrdersParams,\n type ListRecurringOrdersResponse,\n type RecurringOrderActionApiParams,\n type RecurringQuoteParams,\n type RecurringQuoteResponse,\n type RecurringSwapParams,\n type RecurringSwapResponse,\n} from './types';\n\n/** bytes32 hex — same regex as `RecurringOrderSchema.orderId`. */\nconst ORDER_ID_REGEX = /^0x[0-9a-fA-F]{64}$/;\n\n/**\n * Retry policy for `/recurring/swap` and the order-action endpoints\n * (`/recurring/orders/{}/cancel`, `/recurring/orders/{}/pause`,\n * `/recurring/orders/{}/unpause`) — Markr documents all of them as\n * idempotent on the same params, so transient network / 5xx failures are\n * safe to replay. Mirrors the `markrGetCrossChainStatus` pattern but admits\n * POST (whereas the GET variant only whitelists safe verbs) and does NOT\n * retry 404 (for these endpoints, 404 means the resource genuinely doesn't\n * exist).\n */\nconst IDEMPOTENT_POST_RETRY_COUNT = 3;\n\nfunction retryIdempotentPost(ctx: { error?: unknown; response?: Response }): boolean {\n if (ctx.error) {\n if (ctx.error instanceof AbortedError) return false;\n return true;\n }\n const status = ctx.response?.status ?? 0;\n return status === 408 || status === 425 || status === 429 || (status >= 500 && status <= 599);\n}\n\n/**\n * Translate the SDK-public `numberOfOrders` value into Markr's wire shape:\n * - `Infinity` or `-1` → wire sentinel `-1` (unlimited).\n * - Integer in `[2, 365]` → passthrough (matches Markr's documented bounds).\n * - Anything else (`NaN`, `0`, `1`, negatives other than `-1`, non-integers,\n * values > 365, `-Infinity`) → `InvalidParamsError` at the SDK boundary.\n *\n * @see https://orchestrator-docs.markr.io/#/paths/~1recurring~1quote/post — Markr's\n * `numberOfOrders` spec: `-1` for infinite, or integer 2-365 inclusive.\n */\nfunction translateNumberOfOrders(input: number): number {\n if (input === Infinity || input === RECURRING_UNLIMITED_ORDERS_SENTINEL) {\n return RECURRING_UNLIMITED_ORDERS_SENTINEL;\n }\n\n if (!Number.isInteger(input) || input < 2 || input > 365) {\n throw new InvalidParamsError(\n 'Invalid numberOfOrders',\n `Expected an integer in [2, 365], Infinity, or -1 (unlimited). Got: ${String(input)}`,\n );\n }\n\n return input;\n}\n\nexport async function markrRecurringQuote(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: RecurringQuoteParams,\n): Promise<RecurringQuoteResponse> {\n const endpoint = '/recurring/quote';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const body = {\n appId: params.appId,\n chainId: params.chainId,\n tokenIn: params.tokenIn,\n tokenInDecimals: params.tokenInDecimals,\n tokenOut: params.tokenOut,\n tokenOutDecimals: params.tokenOutDecimals,\n // Inline `.toString()` — `JSON.stringify` cannot serialize bigint, so the\n // wire shape stays a decimal string.\n amount: params.amount.toString(),\n numberOfOrders: translateNumberOfOrders(params.numberOfOrders),\n frequency: params.frequency,\n slippage: params.slippage,\n };\n\n const rawJson = await fetchJson(url, {\n body: JSON.stringify(body),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n method: 'POST',\n });\n\n const parsed = RecurringQuoteResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(\n `Invalid response from Markr \"${endpoint}\" endpoint.`,\n parsed.error.issues,\n rawJson,\n );\n }\n\n return parsed.data;\n}\n\n/**\n * Fetches the first-fill swap calldata for a previously quoted recurring swap.\n *\n * Returns an **ordered array** of `RecurringSwapTransaction` steps per the\n * Markr `/recurring/swap` doc:\n * - ERC-20 `tokenIn`: `[createOrder]` (1 element). Caller must have already\n * approved `totalAmountIn` of the ERC-20 to the RecurringSwaps router.\n * - Native `tokenIn` (`0x0…`): `[wrap, createOrder]` (2 elements). Caller\n * must approve the wrapped-native ERC-20 to RecurringSwaps **between**\n * the wrap and createOrder signatures (the SDK inserts that step itself —\n * Markr does not return an approval entry).\n *\n * The SDK signs and broadcasts each entry in array order; relay-driven\n * fills follow `createOrder` on Markr's schedule cadence.\n *\n * Idempotent on the same `uuid` per the Markr docs — retried on transient\n * network / 5xx failures via `retryIdempotentPost`.\n */\nexport async function markrRecurringSwap(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: RecurringSwapParams,\n): Promise<RecurringSwapResponse> {\n const endpoint = '/recurring/swap';\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, {\n body: JSON.stringify(params),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n method: 'POST',\n retries: IDEMPOTENT_POST_RETRY_COUNT,\n retryOn: retryIdempotentPost,\n });\n\n const parsed = RecurringSwapResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(\n `Invalid response from Markr \"${endpoint}\" endpoint.`,\n parsed.error.issues,\n rawJson,\n );\n }\n\n return parsed.data;\n}\n\nexport async function markrListRecurringOrders(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n params: ListRecurringOrdersParams,\n): Promise<ListRecurringOrdersResponse> {\n // `URLSearchParams` URL-encodes each value — defense-in-depth against a\n // caller reaching from JS (no TS brand check) and passing an `address` like\n // `0x…&adminKey=x` that would otherwise inject extra query params.\n const searchParams = new URLSearchParams({ address: params.address });\n if (params.chainId !== undefined) searchParams.set('chainId', String(params.chainId));\n if (params.status !== undefined) searchParams.set('status', params.status);\n\n const endpoint = `/recurring/orders?${searchParams.toString()}`;\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, { headers: getAuthHeaders(apiToken), fetch: customFetch });\n\n const parsed = ListRecurringOrdersResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(\n `Invalid response from Markr \"/recurring/orders\" endpoint.`,\n parsed.error.issues,\n rawJson,\n );\n }\n\n return parsed.data;\n}\n\n/**\n * Shared implementation for the three calldata-returning order-action\n * endpoints (`cancel`, `pause`, `unpause`). All three share:\n * - identical body shape `{ address, chainId }`\n * - identical response shape (`WrappedSwapTransactionResponse`)\n * - identical bytes32 `orderId` validation (path-traversal defense before\n * URL interpolation — catches stale UUIDs / malformed values as a clear\n * `InvalidParamsError` at the SDK boundary rather than an opaque 404\n * from the orchestrator)\n * - identical idempotent-POST retry policy\n *\n * Kept private so all three exported helpers go through the same wire\n * contract — adding a new field (or tightening a check) is a one-place\n * change here.\n */\nasync function postRecurringOrderAction(\n { apiBaseUrl, apiToken, fetch: customFetch }: ApiOptions,\n action: 'cancel' | 'pause' | 'unpause',\n params: { orderId: `0x${string}`; address: string; chainId: number },\n): Promise<WrappedSwapTransactionResponse> {\n if (!ORDER_ID_REGEX.test(params.orderId)) {\n throw new InvalidParamsError(\n 'Invalid recurring orderId',\n `Expected 0x-prefixed bytes32 hex (66 chars). Got: ${JSON.stringify(params.orderId)}`,\n );\n }\n\n const endpoint = `/recurring/orders/${encodeURIComponent(params.orderId)}/${action}`;\n const url = combineUrlPathnames(apiBaseUrl, endpoint);\n\n const rawJson = await fetchJson(url, {\n body: JSON.stringify({ address: params.address, chainId: params.chainId }),\n fetch: customFetch,\n headers: getAuthHeaders(apiToken),\n method: 'POST',\n retries: IDEMPOTENT_POST_RETRY_COUNT,\n retryOn: retryIdempotentPost,\n });\n\n const parsed = WrappedSwapTransactionResponseSchema.safeParse(rawJson);\n\n if (!parsed.success) {\n throw new ResponseValidationError(\n `Invalid response from Markr \"${endpoint}\" endpoint.`,\n parsed.error.issues,\n rawJson,\n );\n }\n\n return parsed.data;\n}\n\n/**\n * Fetches the calldata to cancel the recurring schedule identified by\n * `orderId`. The returned `WrappedSwapTransactionResponse` is signed and\n * broadcast on-chain by the caller — cancellation only takes effect after\n * the TX confirms, at which point Markr transitions the order's `status`\n * to `'cancelled'`.\n *\n * Only `'active'` and `'paused'` orders can be cancelled per the docs; an\n * attempt to cancel a `'completed'` (or otherwise non-cancellable) order\n * surfaces as `HttpError(400)` from the orchestrator.\n *\n * Idempotent on the same `(orderId, address, chainId)` triple per the Markr\n * docs — retried on transient network / 5xx failures via `retryIdempotentPost`.\n *\n * @see https://orchestrator-docs.markr.io/#/paths/~1recurring~1orders~1{orderId}~1cancel/post\n */\nexport function markrPrepareCancellation(\n apiOptions: ApiOptions,\n params: RecurringOrderActionApiParams,\n): Promise<WrappedSwapTransactionResponse> {\n return postRecurringOrderAction(apiOptions, 'cancel', params);\n}\n\n/**\n * Fetches the calldata to pause the recurring schedule identified by\n * `orderId`. The returned `WrappedSwapTransactionResponse` is signed and\n * broadcast on-chain by the caller — the schedule only transitions to\n * `status: 'paused'` once the TX confirms and Markr observes the on-chain\n * event.\n *\n * Only `'active'` orders can be paused per the docs; an attempt to pause a\n * non-`'active'` order surfaces as `HttpError(400)` from the orchestrator.\n *\n * Pausing preserves the existing ERC-20 allowance — when the user later\n * unpauses, no re-approval is required and no new native schedule fee is\n * charged. This is the key UX benefit of pause over cancel-and-recreate.\n *\n * Idempotent on the same `(orderId, address, chainId)` triple — retried\n * on transient network / 5xx failures via `retryIdempotentPost`.\n *\n * @see https://orchestrator-docs.markr.io/#tag/Recurring-Swaps/paths/~1recurring~1orders~1{orderId}~1pause/post\n */\nexport function markrPreparePause(\n apiOptions: ApiOptions,\n params: RecurringOrderActionApiParams,\n): Promise<WrappedSwapTransactionResponse> {\n return postRecurringOrderAction(apiOptions, 'pause', params);\n}\n\n/**\n * Fetches the calldata to unpause (resume) the recurring schedule\n * identified by `orderId`. The returned `WrappedSwapTransactionResponse` is\n * signed and broadcast on-chain by the caller — the schedule only\n * transitions back to `status: 'active'` once the TX confirms and Markr\n * observes the on-chain event.\n *\n * Only `'paused'` orders can be unpaused per the docs; an attempt to\n * unpause a non-`'paused'` order surfaces as `HttpError(400)` from the\n * orchestrator.\n *\n * Resumes execution from where the schedule left off — remaining fills\n * continue on the original `frequency` cadence and the orchestrator\n * recomputes `nextExecutionAt` after the TX confirms.\n *\n * Idempotent on the same `(orderId, address, chainId)` triple — retried\n * on transient network / 5xx failures via `retryIdempotentPost`.\n *\n * @see https://orchestrator-docs.markr.io/#tag/Recurring-Swaps/paths/~1recurring~1orders~1{orderId}~1unpause/post\n */\nexport function markrPrepareUnpause(\n apiOptions: ApiOptions,\n params: RecurringOrderActionApiParams,\n): Promise<WrappedSwapTransactionResponse> {\n return postRecurringOrderAction(apiOptions, 'unpause', params);\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- function e(e){let t=new Map;for(let n of e.values())typeof n.chainId!=`number`||!n.recurring||t.set(n.chainId,{minFrequencySeconds:n.recurring.minFrequencySeconds,supportedTokens:n.recurring.supportedTokens});return t}exports.deriveRecurringChainInfo=e;
1
+ function e(e){let t=new Map;for(let n of e.values())typeof n.chainId!=`number`||!n.recurring||t.set(n.chainId,{minFrequencySeconds:n.recurring.minFrequencySeconds,...n.wrappedNativeAddress?{wrappedNativeAddress:n.wrappedNativeAddress}:{}});return t}exports.deriveRecurringChainInfo=e;
2
2
  //# sourceMappingURL=_chain-info.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"_chain-info.cjs","names":[],"sources":["../../../../src/transfer-service/markr/recurring/_chain-info.ts"],"sourcesContent":["import type { SupportedChainsMap } from '../_utils';\nimport type { RecurringChainInfoEntry, RecurringChainInfoMap } from './types';\n\n/**\n * Derives a `RecurringChainInfoMap` (chainId → recurring metadata) from a\n * `SupportedChainsMap` already populated by `getSupportedChains`. Skips chains\n * that do not carry a `recurring` block in the `/info/chains` response.\n *\n * Pure function — no fetch. The original `/info/chains` response is the single\n * source for both maps (no second `/info/chains` call).\n */\nexport function deriveRecurringChainInfo(supportedChains: SupportedChainsMap): RecurringChainInfoMap {\n const recurringChainInfo: Map<number, RecurringChainInfoEntry> = new Map();\n\n for (const entry of supportedChains.values()) {\n if (typeof entry.chainId !== 'number' || !entry.recurring) {\n continue;\n }\n\n recurringChainInfo.set(entry.chainId, {\n minFrequencySeconds: entry.recurring.minFrequencySeconds,\n supportedTokens: entry.recurring.supportedTokens,\n });\n }\n\n return recurringChainInfo;\n}\n"],"mappings":"AAWA,SAAgB,EAAyB,EAA4D,CACnG,IAAM,EAA2D,IAAI,IAErE,IAAK,IAAM,KAAS,EAAgB,QAAQ,CACtC,OAAO,EAAM,SAAY,UAAY,CAAC,EAAM,WAIhD,EAAmB,IAAI,EAAM,QAAS,CACpC,oBAAqB,EAAM,UAAU,oBACrC,gBAAiB,EAAM,UAAU,gBAClC,CAAC,CAGJ,OAAO"}
1
+ {"version":3,"file":"_chain-info.cjs","names":[],"sources":["../../../../src/transfer-service/markr/recurring/_chain-info.ts"],"sourcesContent":["import type { SupportedChainsMap } from '../_utils';\nimport type { RecurringChainInfoEntry, RecurringChainInfoMap } from './types';\n\n/**\n * Derives a `RecurringChainInfoMap` (chainId → recurring metadata) from a\n * `SupportedChainsMap` already populated by `getSupportedChains`. Skips chains\n * that do not carry a `recurring` block in the `/info/chains` response.\n *\n * Pure function — no fetch. The original `/info/chains` response is the single\n * source for both maps (no second `/info/chains` call).\n */\nexport function deriveRecurringChainInfo(supportedChains: SupportedChainsMap): RecurringChainInfoMap {\n const recurringChainInfo: Map<number, RecurringChainInfoEntry> = new Map();\n\n for (const entry of supportedChains.values()) {\n if (typeof entry.chainId !== 'number' || !entry.recurring) {\n continue;\n }\n\n recurringChainInfo.set(entry.chainId, {\n minFrequencySeconds: entry.recurring.minFrequencySeconds,\n // `wrapped_token` may be absent on a chain that lists recurring (rare —\n // Markr publishes it for all EVM chains it serves). When undefined,\n // eligibility + the quote boundary fail closed on native input.\n ...(entry.wrappedNativeAddress ? { wrappedNativeAddress: entry.wrappedNativeAddress } : {}),\n });\n }\n\n return recurringChainInfo;\n}\n"],"mappings":"AAWA,SAAgB,EAAyB,EAA4D,CACnG,IAAM,EAA2D,IAAI,IAErE,IAAK,IAAM,KAAS,EAAgB,QAAQ,CACtC,OAAO,EAAM,SAAY,UAAY,CAAC,EAAM,WAIhD,EAAmB,IAAI,EAAM,QAAS,CACpC,oBAAqB,EAAM,UAAU,oBAIrC,GAAI,EAAM,qBAAuB,CAAE,qBAAsB,EAAM,qBAAsB,CAAG,EAAE,CAC3F,CAAC,CAGJ,OAAO"}
@@ -1,2 +1,2 @@
1
- function e(e){let t=new Map;for(let n of e.values())typeof n.chainId!=`number`||!n.recurring||t.set(n.chainId,{minFrequencySeconds:n.recurring.minFrequencySeconds,supportedTokens:n.recurring.supportedTokens});return t}export{e as deriveRecurringChainInfo};
1
+ function e(e){let t=new Map;for(let n of e.values())typeof n.chainId!=`number`||!n.recurring||t.set(n.chainId,{minFrequencySeconds:n.recurring.minFrequencySeconds,...n.wrappedNativeAddress?{wrappedNativeAddress:n.wrappedNativeAddress}:{}});return t}export{e as deriveRecurringChainInfo};
2
2
  //# sourceMappingURL=_chain-info.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_chain-info.js","names":[],"sources":["../../../../src/transfer-service/markr/recurring/_chain-info.ts"],"sourcesContent":["import type { SupportedChainsMap } from '../_utils';\nimport type { RecurringChainInfoEntry, RecurringChainInfoMap } from './types';\n\n/**\n * Derives a `RecurringChainInfoMap` (chainId → recurring metadata) from a\n * `SupportedChainsMap` already populated by `getSupportedChains`. Skips chains\n * that do not carry a `recurring` block in the `/info/chains` response.\n *\n * Pure function — no fetch. The original `/info/chains` response is the single\n * source for both maps (no second `/info/chains` call).\n */\nexport function deriveRecurringChainInfo(supportedChains: SupportedChainsMap): RecurringChainInfoMap {\n const recurringChainInfo: Map<number, RecurringChainInfoEntry> = new Map();\n\n for (const entry of supportedChains.values()) {\n if (typeof entry.chainId !== 'number' || !entry.recurring) {\n continue;\n }\n\n recurringChainInfo.set(entry.chainId, {\n minFrequencySeconds: entry.recurring.minFrequencySeconds,\n supportedTokens: entry.recurring.supportedTokens,\n });\n }\n\n return recurringChainInfo;\n}\n"],"mappings":"AAWA,SAAgB,EAAyB,EAA4D,CACnG,IAAM,EAA2D,IAAI,IAErE,IAAK,IAAM,KAAS,EAAgB,QAAQ,CACtC,OAAO,EAAM,SAAY,UAAY,CAAC,EAAM,WAIhD,EAAmB,IAAI,EAAM,QAAS,CACpC,oBAAqB,EAAM,UAAU,oBACrC,gBAAiB,EAAM,UAAU,gBAClC,CAAC,CAGJ,OAAO"}
1
+ {"version":3,"file":"_chain-info.js","names":[],"sources":["../../../../src/transfer-service/markr/recurring/_chain-info.ts"],"sourcesContent":["import type { SupportedChainsMap } from '../_utils';\nimport type { RecurringChainInfoEntry, RecurringChainInfoMap } from './types';\n\n/**\n * Derives a `RecurringChainInfoMap` (chainId → recurring metadata) from a\n * `SupportedChainsMap` already populated by `getSupportedChains`. Skips chains\n * that do not carry a `recurring` block in the `/info/chains` response.\n *\n * Pure function — no fetch. The original `/info/chains` response is the single\n * source for both maps (no second `/info/chains` call).\n */\nexport function deriveRecurringChainInfo(supportedChains: SupportedChainsMap): RecurringChainInfoMap {\n const recurringChainInfo: Map<number, RecurringChainInfoEntry> = new Map();\n\n for (const entry of supportedChains.values()) {\n if (typeof entry.chainId !== 'number' || !entry.recurring) {\n continue;\n }\n\n recurringChainInfo.set(entry.chainId, {\n minFrequencySeconds: entry.recurring.minFrequencySeconds,\n // `wrapped_token` may be absent on a chain that lists recurring (rare —\n // Markr publishes it for all EVM chains it serves). When undefined,\n // eligibility + the quote boundary fail closed on native input.\n ...(entry.wrappedNativeAddress ? { wrappedNativeAddress: entry.wrappedNativeAddress } : {}),\n });\n }\n\n return recurringChainInfo;\n}\n"],"mappings":"AAWA,SAAgB,EAAyB,EAA4D,CACnG,IAAM,EAA2D,IAAI,IAErE,IAAK,IAAM,KAAS,EAAgB,QAAQ,CACtC,OAAO,EAAM,SAAY,UAAY,CAAC,EAAM,WAIhD,EAAmB,IAAI,EAAM,QAAS,CACpC,oBAAqB,EAAM,UAAU,oBAIrC,GAAI,EAAM,qBAAuB,CAAE,qBAAsB,EAAM,qBAAsB,CAAG,EAAE,CAC3F,CAAC,CAGJ,OAAO"}
@@ -1,2 +1,2 @@
1
- require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`./types.cjs`);let t=require(`viem`);function n(n){let{recurringChainInfo:r,fromTokenAddress:i,toTokenAddress:a,sourceChainId:o,targetChainId:s,ownerAddress:c,amount:l}=n;if(!c)return{eligible:!1,reason:e.RecurringEligibilityReason.NoEvmAddress};if(o!==s)return{eligible:!1,reason:e.RecurringEligibilityReason.CrossChain};let u=r.get(o);if(!u||u.supportedTokens.length===0)return{eligible:!1,reason:e.RecurringEligibilityReason.UnsupportedSourceChain};let d=u.supportedTokens.find(e=>(0,t.isAddressEqual)(e.address,i));return!d||(0,t.isAddressEqual)(a,i)?{eligible:!1,reason:e.RecurringEligibilityReason.UnsupportedToken}:l!==void 0&&l<BigInt(d.minimumAmount)?{eligible:!1,reason:e.RecurringEligibilityReason.AmountBelowMinimum,minimumAmount:d.minimumAmount}:{eligible:!0,minimumAmount:d.minimumAmount,minIntervalSeconds:u.minFrequencySeconds}}exports.checkRecurringEligibility=n;
1
+ require(`../../../_virtual/_rolldown/runtime.cjs`),require(`../../../constants.cjs`);const e=require(`./types.cjs`);let t=require(`viem`);function n(n){let{recurringChainInfo:r,fromTokenAddress:i,toTokenAddress:a,sourceChainId:o,targetChainId:s,ownerAddress:c}=n;if(!c)return{eligible:!1,reason:e.RecurringEligibilityReason.NoEvmAddress};if(o!==s)return{eligible:!1,reason:e.RecurringEligibilityReason.CrossChain};let l=r.get(o);if(!l)return{eligible:!1,reason:e.RecurringEligibilityReason.UnsupportedSourceChain};if((0,t.isAddressEqual)(i,`0x0000000000000000000000000000000000000000`)){if(!l.wrappedNativeAddress)return{eligible:!1,reason:e.RecurringEligibilityReason.UnsupportedToken};if((0,t.isAddressEqual)(a,l.wrappedNativeAddress))return{eligible:!1,reason:e.RecurringEligibilityReason.NativeToWrappedNative}}return(0,t.isAddressEqual)(a,i)?{eligible:!1,reason:e.RecurringEligibilityReason.UnsupportedToken}:{eligible:!0,minIntervalSeconds:l.minFrequencySeconds}}exports.checkRecurringEligibility=n;
2
2
  //# sourceMappingURL=_eligibility.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"_eligibility.cjs","names":["RecurringEligibilityReason"],"sources":["../../../../src/transfer-service/markr/recurring/_eligibility.ts"],"sourcesContent":["import { isAddressEqual } from 'viem';\nimport { RecurringEligibilityReason } from './types';\nimport type { CheckRecurringEligibilityParams, RecurringChainInfoEntry, RecurringEligibility } from './types';\n\n/**\n * Pure check that a `(fromToken, toToken, ownerAddress)` triple is supported\n * for recurring swaps against a cached `/info/chains` response.\n *\n * Mirrors the branch order of the mobile `useRecurringEligibility` hook so the\n * `reason` codes returned here can drive UI strings unchanged.\n *\n * ## What this checks (static, no I/O)\n *\n * - Owner has an EVM address → `NoEvmAddress`\n * - Source and target chains match (same-chain only) → `CrossChain`\n * - Chain is in the cached recurring chain-info map → `UnsupportedSourceChain`\n * - `fromTokenAddress` is in the chain's supported list → `UnsupportedToken`\n * - `toTokenAddress` differs from `fromTokenAddress` → `UnsupportedToken`\n * - When `amount` is provided, `amount >= minimumAmount` `AmountBelowMinimum`\n * (the failure variant carries `minimumAmount` so error UIs can say\n * \"Min is X\" without a second `getRecurringChainInfo()` lookup)\n *\n * ## What this does NOT check\n *\n * - **Wallet balance.** This helper has no wallet/RPC context — it cannot\n * compare `amount × numberOfOrders` against the user's `tokenIn` balance,\n * their native-gas balance for the first-fill TX, or any other on-chain\n * state. Balance checks are the **consumer's** responsibility, same as the\n * one-shot swap flow.\n * - **Post-fill failures** (e.g. a scheduled fill reverts because the user\n * later moved funds). These surface server-side via\n * `RecurringOrder.failures[].reasons: ReadonlyArray<string>` — open-ended\n * strings, NOT this enum. Markr emits literals like `\"Insufficient balance\"`\n * or `\"Slippage tolerance exceeded\"`; consumers substring-match per the\n * AC4 auto-cancel plan and call {@link RecurringNamespace.prepareCancellation}\n * when applicable. Kept as `string` (with `(string & NonNullable<unknown>)`\n * widening) so a new server-side reason doesn't brick already-shipped clients.\n * - **Server-side quote rejection** (slippage, target-token unsupported,\n * liquidity, etc.) — Markr decides at `/recurring/quote` time. Surface\n * those as `HttpError(400)` / `HttpError(422)` from\n * {@link RecurringNamespace.quote}.\n *\n * Net: this helper covers the \"can the user *attempt* a recurring swap with\n * this token pair at this size\" question. Anything that requires a wallet,\n * RPC, or live orchestrator round-trip lives elsewhere.\n */\nexport function checkRecurringEligibility(params: CheckRecurringEligibilityParams): RecurringEligibility {\n const { recurringChainInfo, fromTokenAddress, toTokenAddress, sourceChainId, targetChainId, ownerAddress, amount } =\n params;\n\n if (!ownerAddress) {\n return { eligible: false, reason: RecurringEligibilityReason.NoEvmAddress };\n }\n\n if (sourceChainId !== targetChainId) {\n return { eligible: false, reason: RecurringEligibilityReason.CrossChain };\n }\n\n const chain: RecurringChainInfoEntry | undefined = recurringChainInfo.get(sourceChainId);\n\n if (!chain || chain.supportedTokens.length === 0) {\n return { eligible: false, reason: RecurringEligibilityReason.UnsupportedSourceChain };\n }\n\n // `isAddressEqual` does a case-insensitive compare without per-call string\n // allocations (matches the established pattern in `markr/_utils.ts`). The\n // `EvmAddress` brand type guarantees the inputs are well-formed; if a JS\n // consumer reaches in with a malformed value, the resulting throw is the\n // right failure mode (loud > silently \"unsupported-token\").\n const supportedToken = chain.supportedTokens.find((token) => isAddressEqual(token.address, fromTokenAddress));\n\n if (!supportedToken) {\n return { eligible: false, reason: RecurringEligibilityReason.UnsupportedToken };\n }\n\n // The target token only needs to exist on the same chain; recurring swaps\n // are one-way (tokenIn → tokenOut) and Markr decides target eligibility\n // server-side at /recurring/quote time. Reject the obvious nonsense\n // (`toTokenAddress` matching `fromTokenAddress`) up front to fail fast.\n if (isAddressEqual(toTokenAddress, fromTokenAddress)) {\n return { eligible: false, reason: RecurringEligibilityReason.UnsupportedToken };\n }\n\n if (amount !== undefined && amount < BigInt(supportedToken.minimumAmount)) {\n return {\n eligible: false,\n reason: RecurringEligibilityReason.AmountBelowMinimum,\n minimumAmount: supportedToken.minimumAmount,\n };\n }\n\n return {\n eligible: true,\n minimumAmount: supportedToken.minimumAmount,\n minIntervalSeconds: chain.minFrequencySeconds,\n };\n}\n"],"mappings":"wGA8CA,SAAgB,EAA0B,EAA+D,CACvG,GAAM,CAAE,qBAAoB,mBAAkB,iBAAgB,gBAAe,gBAAe,eAAc,UACxG,EAEF,GAAI,CAAC,EACH,MAAO,CAAE,SAAU,GAAO,OAAQA,EAAAA,2BAA2B,aAAc,CAG7E,GAAI,IAAkB,EACpB,MAAO,CAAE,SAAU,GAAO,OAAQA,EAAAA,2BAA2B,WAAY,CAG3E,IAAM,EAA6C,EAAmB,IAAI,EAAc,CAExF,GAAI,CAAC,GAAS,EAAM,gBAAgB,SAAW,EAC7C,MAAO,CAAE,SAAU,GAAO,OAAQA,EAAAA,2BAA2B,uBAAwB,CAQvF,IAAM,EAAiB,EAAM,gBAAgB,KAAM,IAAA,EAAA,EAAA,gBAAyB,EAAM,QAAS,EAAiB,CAAC,CAsB7G,MApBI,CAAC,IAQL,EAAA,EAAA,gBAAmB,EAAgB,EAAiB,CAC3C,CAAE,SAAU,GAAO,OAAQA,EAAAA,2BAA2B,iBAAkB,CAG7E,IAAW,IAAA,IAAa,EAAS,OAAO,EAAe,cAAc,CAChE,CACL,SAAU,GACV,OAAQA,EAAAA,2BAA2B,mBACnC,cAAe,EAAe,cAC/B,CAGI,CACL,SAAU,GACV,cAAe,EAAe,cAC9B,mBAAoB,EAAM,oBAC3B"}
1
+ {"version":3,"file":"_eligibility.cjs","names":["RecurringEligibilityReason"],"sources":["../../../../src/transfer-service/markr/recurring/_eligibility.ts"],"sourcesContent":["import { isAddressEqual } from 'viem';\nimport { ERC_ZERO_ADDRESS } from '../../../constants';\nimport { RecurringEligibilityReason } from './types';\nimport type { CheckRecurringEligibilityParams, RecurringChainInfoEntry, RecurringEligibility } from './types';\n\n/**\n * Pure check that a `(fromToken, toToken, ownerAddress)` triple is supported\n * for recurring swaps against a cached `/info/chains` response.\n *\n * Mirrors the branch order of the mobile `useRecurringEligibility` hook so the\n * `reason` codes returned here can drive UI strings unchanged.\n *\n * ## What this checks (static, no I/O)\n *\n * - Owner has an EVM address → `NoEvmAddress`\n * - Source and target chains match (same-chain only) → `CrossChain`\n * - Chain has recurring enabled in the chain-info map → `UnsupportedSourceChain`\n * - Native input chain has a wrapped-native published → `UnsupportedToken`\n * - Native input → target is not the wrapped-native → `NativeToWrappedNative`\n * - `toTokenAddress` differs from `fromTokenAddress` → `UnsupportedToken`\n *\n * Markr no longer publishes a per-chain supported-token list (the old\n * `/info/chains[].recurring.supportedTokens`), so every ERC-20 — and the\n * chain's native asset is treated as recurring-eligible here. Token-level\n * support (and any per-order minimum) is decided server-side at\n * `/recurring/quote` time.\n *\n * ## What this does NOT check\n *\n * - **Wallet balance.** This helper has no wallet/RPC context — it cannot\n * compare `amount × numberOfOrders` against the user's `tokenIn` balance,\n * their native-gas balance for the first-fill TX, or any other on-chain\n * state. Balance checks are the **consumer's** responsibility, same as the\n * one-shot swap flow.\n * - **Post-fill failures** (e.g. a scheduled fill reverts because the user\n * later moved funds). These surface server-side via\n * `RecurringOrder.failures[].reasons: ReadonlyArray<string>` — open-ended\n * strings, NOT this enum. Markr emits literals like `\"Insufficient balance\"`\n * or `\"Slippage tolerance exceeded\"`; consumers substring-match per the\n * AC4 auto-cancel plan and call {@link RecurringNamespace.prepareCancellation}\n * when applicable. Kept as `string` (with `(string & NonNullable<unknown>)`\n * widening) so a new server-side reason doesn't brick already-shipped clients.\n * - **Server-side quote rejection** (slippage, target-token unsupported,\n * liquidity, etc.) — Markr decides at `/recurring/quote` time. Surface\n * those as `HttpError(400)` / `HttpError(422)` from\n * {@link RecurringNamespace.quote}.\n *\n * Net: this helper covers the \"can the user *attempt* a recurring swap with\n * this token pair\" question. Anything that requires a wallet, RPC, or live\n * orchestrator round-trip lives elsewhere.\n */\nexport function checkRecurringEligibility(params: CheckRecurringEligibilityParams): RecurringEligibility {\n const { recurringChainInfo, fromTokenAddress, toTokenAddress, sourceChainId, targetChainId, ownerAddress } = params;\n\n if (!ownerAddress) {\n return { eligible: false, reason: RecurringEligibilityReason.NoEvmAddress };\n }\n\n if (sourceChainId !== targetChainId) {\n return { eligible: false, reason: RecurringEligibilityReason.CrossChain };\n }\n\n // Presence in the chain-info map is the recurring-enabled signal — the map\n // is built only for chains that carried a `recurring` block in\n // `/info/chains`. Markr no longer publishes a per-chain supported-token\n // list, so there is nothing token-level to assert here.\n const chain: RecurringChainInfoEntry | undefined = recurringChainInfo.get(sourceChainId);\n\n if (!chain) {\n return { eligible: false, reason: RecurringEligibilityReason.UnsupportedSourceChain };\n }\n\n // Native input is passed through to Markr verbatim (the recurring API\n // accepts the zero address as `tokenIn`); the SDK only uses the chain's\n // wrapped-native address for the on-chain wrap leg + WAVAX allowance in\n // `executeFirstFill`. The wrapped-native is read off the chain entry\n // (sourced from `/info/chains[].wrapped_token`) — no SDK-side static map.\n //\n // Two native-specific checks live here:\n // 1. Fail closed when Markr didn't publish a wrapped-native for the\n // chain we couldn't execute the schedule even if it's eligible.\n // 2. Reject native → wrapped-native (e.g. AVAX → WAVAX) with a dedicated\n // reason economically just a scheduled wrap, not a swap. Consumer\n // UI should steer the user to a one-shot wrap instead of failing with\n // a generic \"unsupported token\" message.\n const isNativeInput = isAddressEqual(fromTokenAddress, ERC_ZERO_ADDRESS);\n if (isNativeInput) {\n if (!chain.wrappedNativeAddress) {\n return { eligible: false, reason: RecurringEligibilityReason.UnsupportedToken };\n }\n if (isAddressEqual(toTokenAddress, chain.wrappedNativeAddress)) {\n return { eligible: false, reason: RecurringEligibilityReason.NativeToWrappedNative };\n }\n }\n\n // Recurring swaps are one-way (tokenIn → tokenOut) and Markr decides\n // token-level eligibility server-side at /recurring/quote time. Reject the\n // obvious nonsense (`toTokenAddress` matching `fromTokenAddress`) up front\n // to fail fast. `isAddressEqual` does a case-insensitive compare without\n // per-call string allocations (matches the pattern in `markr/_utils.ts`).\n if (isAddressEqual(toTokenAddress, fromTokenAddress)) {\n return { eligible: false, reason: RecurringEligibilityReason.UnsupportedToken };\n }\n\n return {\n eligible: true,\n minIntervalSeconds: chain.minFrequencySeconds,\n };\n}\n"],"mappings":"0IAmDA,SAAgB,EAA0B,EAA+D,CACvG,GAAM,CAAE,qBAAoB,mBAAkB,iBAAgB,gBAAe,gBAAe,gBAAiB,EAE7G,GAAI,CAAC,EACH,MAAO,CAAE,SAAU,GAAO,OAAQA,EAAAA,2BAA2B,aAAc,CAG7E,GAAI,IAAkB,EACpB,MAAO,CAAE,SAAU,GAAO,OAAQA,EAAAA,2BAA2B,WAAY,CAO3E,IAAM,EAA6C,EAAmB,IAAI,EAAc,CAExF,GAAI,CAAC,EACH,MAAO,CAAE,SAAU,GAAO,OAAQA,EAAAA,2BAA2B,uBAAwB,CAiBvF,IAAA,EAAA,EAAA,gBADqC,EAAA,6CAAmC,CACrD,CACjB,GAAI,CAAC,EAAM,qBACT,MAAO,CAAE,SAAU,GAAO,OAAQA,EAAAA,2BAA2B,iBAAkB,CAEjF,IAAA,EAAA,EAAA,gBAAmB,EAAgB,EAAM,qBAAqB,CAC5D,MAAO,CAAE,SAAU,GAAO,OAAQA,EAAAA,2BAA2B,sBAAuB,CAaxF,OAJA,EAAA,EAAA,gBAAmB,EAAgB,EAAiB,CAC3C,CAAE,SAAU,GAAO,OAAQA,EAAAA,2BAA2B,iBAAkB,CAG1E,CACL,SAAU,GACV,mBAAoB,EAAM,oBAC3B"}
@@ -1,2 +1,2 @@
1
- import{RecurringEligibilityReason as e}from"./types.js";import{isAddressEqual as t}from"viem";function n(n){let{recurringChainInfo:r,fromTokenAddress:i,toTokenAddress:a,sourceChainId:o,targetChainId:s,ownerAddress:c,amount:l}=n;if(!c)return{eligible:!1,reason:e.NoEvmAddress};if(o!==s)return{eligible:!1,reason:e.CrossChain};let u=r.get(o);if(!u||u.supportedTokens.length===0)return{eligible:!1,reason:e.UnsupportedSourceChain};let d=u.supportedTokens.find(e=>t(e.address,i));return!d||t(a,i)?{eligible:!1,reason:e.UnsupportedToken}:l!==void 0&&l<BigInt(d.minimumAmount)?{eligible:!1,reason:e.AmountBelowMinimum,minimumAmount:d.minimumAmount}:{eligible:!0,minimumAmount:d.minimumAmount,minIntervalSeconds:u.minFrequencySeconds}}export{n as checkRecurringEligibility};
1
+ import"../../../constants.js";import{RecurringEligibilityReason as e}from"./types.js";import{isAddressEqual as t}from"viem";function n(n){let{recurringChainInfo:r,fromTokenAddress:i,toTokenAddress:a,sourceChainId:o,targetChainId:s,ownerAddress:c}=n;if(!c)return{eligible:!1,reason:e.NoEvmAddress};if(o!==s)return{eligible:!1,reason:e.CrossChain};let l=r.get(o);if(!l)return{eligible:!1,reason:e.UnsupportedSourceChain};if(t(i,`0x0000000000000000000000000000000000000000`)){if(!l.wrappedNativeAddress)return{eligible:!1,reason:e.UnsupportedToken};if(t(a,l.wrappedNativeAddress))return{eligible:!1,reason:e.NativeToWrappedNative}}return t(a,i)?{eligible:!1,reason:e.UnsupportedToken}:{eligible:!0,minIntervalSeconds:l.minFrequencySeconds}}export{n as checkRecurringEligibility};
2
2
  //# sourceMappingURL=_eligibility.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_eligibility.js","names":[],"sources":["../../../../src/transfer-service/markr/recurring/_eligibility.ts"],"sourcesContent":["import { isAddressEqual } from 'viem';\nimport { RecurringEligibilityReason } from './types';\nimport type { CheckRecurringEligibilityParams, RecurringChainInfoEntry, RecurringEligibility } from './types';\n\n/**\n * Pure check that a `(fromToken, toToken, ownerAddress)` triple is supported\n * for recurring swaps against a cached `/info/chains` response.\n *\n * Mirrors the branch order of the mobile `useRecurringEligibility` hook so the\n * `reason` codes returned here can drive UI strings unchanged.\n *\n * ## What this checks (static, no I/O)\n *\n * - Owner has an EVM address → `NoEvmAddress`\n * - Source and target chains match (same-chain only) → `CrossChain`\n * - Chain is in the cached recurring chain-info map → `UnsupportedSourceChain`\n * - `fromTokenAddress` is in the chain's supported list → `UnsupportedToken`\n * - `toTokenAddress` differs from `fromTokenAddress` → `UnsupportedToken`\n * - When `amount` is provided, `amount >= minimumAmount` `AmountBelowMinimum`\n * (the failure variant carries `minimumAmount` so error UIs can say\n * \"Min is X\" without a second `getRecurringChainInfo()` lookup)\n *\n * ## What this does NOT check\n *\n * - **Wallet balance.** This helper has no wallet/RPC context — it cannot\n * compare `amount × numberOfOrders` against the user's `tokenIn` balance,\n * their native-gas balance for the first-fill TX, or any other on-chain\n * state. Balance checks are the **consumer's** responsibility, same as the\n * one-shot swap flow.\n * - **Post-fill failures** (e.g. a scheduled fill reverts because the user\n * later moved funds). These surface server-side via\n * `RecurringOrder.failures[].reasons: ReadonlyArray<string>` — open-ended\n * strings, NOT this enum. Markr emits literals like `\"Insufficient balance\"`\n * or `\"Slippage tolerance exceeded\"`; consumers substring-match per the\n * AC4 auto-cancel plan and call {@link RecurringNamespace.prepareCancellation}\n * when applicable. Kept as `string` (with `(string & NonNullable<unknown>)`\n * widening) so a new server-side reason doesn't brick already-shipped clients.\n * - **Server-side quote rejection** (slippage, target-token unsupported,\n * liquidity, etc.) — Markr decides at `/recurring/quote` time. Surface\n * those as `HttpError(400)` / `HttpError(422)` from\n * {@link RecurringNamespace.quote}.\n *\n * Net: this helper covers the \"can the user *attempt* a recurring swap with\n * this token pair at this size\" question. Anything that requires a wallet,\n * RPC, or live orchestrator round-trip lives elsewhere.\n */\nexport function checkRecurringEligibility(params: CheckRecurringEligibilityParams): RecurringEligibility {\n const { recurringChainInfo, fromTokenAddress, toTokenAddress, sourceChainId, targetChainId, ownerAddress, amount } =\n params;\n\n if (!ownerAddress) {\n return { eligible: false, reason: RecurringEligibilityReason.NoEvmAddress };\n }\n\n if (sourceChainId !== targetChainId) {\n return { eligible: false, reason: RecurringEligibilityReason.CrossChain };\n }\n\n const chain: RecurringChainInfoEntry | undefined = recurringChainInfo.get(sourceChainId);\n\n if (!chain || chain.supportedTokens.length === 0) {\n return { eligible: false, reason: RecurringEligibilityReason.UnsupportedSourceChain };\n }\n\n // `isAddressEqual` does a case-insensitive compare without per-call string\n // allocations (matches the established pattern in `markr/_utils.ts`). The\n // `EvmAddress` brand type guarantees the inputs are well-formed; if a JS\n // consumer reaches in with a malformed value, the resulting throw is the\n // right failure mode (loud > silently \"unsupported-token\").\n const supportedToken = chain.supportedTokens.find((token) => isAddressEqual(token.address, fromTokenAddress));\n\n if (!supportedToken) {\n return { eligible: false, reason: RecurringEligibilityReason.UnsupportedToken };\n }\n\n // The target token only needs to exist on the same chain; recurring swaps\n // are one-way (tokenIn → tokenOut) and Markr decides target eligibility\n // server-side at /recurring/quote time. Reject the obvious nonsense\n // (`toTokenAddress` matching `fromTokenAddress`) up front to fail fast.\n if (isAddressEqual(toTokenAddress, fromTokenAddress)) {\n return { eligible: false, reason: RecurringEligibilityReason.UnsupportedToken };\n }\n\n if (amount !== undefined && amount < BigInt(supportedToken.minimumAmount)) {\n return {\n eligible: false,\n reason: RecurringEligibilityReason.AmountBelowMinimum,\n minimumAmount: supportedToken.minimumAmount,\n };\n }\n\n return {\n eligible: true,\n minimumAmount: supportedToken.minimumAmount,\n minIntervalSeconds: chain.minFrequencySeconds,\n };\n}\n"],"mappings":"8FA8CA,SAAgB,EAA0B,EAA+D,CACvG,GAAM,CAAE,qBAAoB,mBAAkB,iBAAgB,gBAAe,gBAAe,eAAc,UACxG,EAEF,GAAI,CAAC,EACH,MAAO,CAAE,SAAU,GAAO,OAAQ,EAA2B,aAAc,CAG7E,GAAI,IAAkB,EACpB,MAAO,CAAE,SAAU,GAAO,OAAQ,EAA2B,WAAY,CAG3E,IAAM,EAA6C,EAAmB,IAAI,EAAc,CAExF,GAAI,CAAC,GAAS,EAAM,gBAAgB,SAAW,EAC7C,MAAO,CAAE,SAAU,GAAO,OAAQ,EAA2B,uBAAwB,CAQvF,IAAM,EAAiB,EAAM,gBAAgB,KAAM,GAAU,EAAe,EAAM,QAAS,EAAiB,CAAC,CAsB7G,MApBI,CAAC,GAQD,EAAe,EAAgB,EAAiB,CAC3C,CAAE,SAAU,GAAO,OAAQ,EAA2B,iBAAkB,CAG7E,IAAW,IAAA,IAAa,EAAS,OAAO,EAAe,cAAc,CAChE,CACL,SAAU,GACV,OAAQ,EAA2B,mBACnC,cAAe,EAAe,cAC/B,CAGI,CACL,SAAU,GACV,cAAe,EAAe,cAC9B,mBAAoB,EAAM,oBAC3B"}
1
+ {"version":3,"file":"_eligibility.js","names":[],"sources":["../../../../src/transfer-service/markr/recurring/_eligibility.ts"],"sourcesContent":["import { isAddressEqual } from 'viem';\nimport { ERC_ZERO_ADDRESS } from '../../../constants';\nimport { RecurringEligibilityReason } from './types';\nimport type { CheckRecurringEligibilityParams, RecurringChainInfoEntry, RecurringEligibility } from './types';\n\n/**\n * Pure check that a `(fromToken, toToken, ownerAddress)` triple is supported\n * for recurring swaps against a cached `/info/chains` response.\n *\n * Mirrors the branch order of the mobile `useRecurringEligibility` hook so the\n * `reason` codes returned here can drive UI strings unchanged.\n *\n * ## What this checks (static, no I/O)\n *\n * - Owner has an EVM address → `NoEvmAddress`\n * - Source and target chains match (same-chain only) → `CrossChain`\n * - Chain has recurring enabled in the chain-info map → `UnsupportedSourceChain`\n * - Native input chain has a wrapped-native published → `UnsupportedToken`\n * - Native input → target is not the wrapped-native → `NativeToWrappedNative`\n * - `toTokenAddress` differs from `fromTokenAddress` → `UnsupportedToken`\n *\n * Markr no longer publishes a per-chain supported-token list (the old\n * `/info/chains[].recurring.supportedTokens`), so every ERC-20 — and the\n * chain's native asset is treated as recurring-eligible here. Token-level\n * support (and any per-order minimum) is decided server-side at\n * `/recurring/quote` time.\n *\n * ## What this does NOT check\n *\n * - **Wallet balance.** This helper has no wallet/RPC context — it cannot\n * compare `amount × numberOfOrders` against the user's `tokenIn` balance,\n * their native-gas balance for the first-fill TX, or any other on-chain\n * state. Balance checks are the **consumer's** responsibility, same as the\n * one-shot swap flow.\n * - **Post-fill failures** (e.g. a scheduled fill reverts because the user\n * later moved funds). These surface server-side via\n * `RecurringOrder.failures[].reasons: ReadonlyArray<string>` — open-ended\n * strings, NOT this enum. Markr emits literals like `\"Insufficient balance\"`\n * or `\"Slippage tolerance exceeded\"`; consumers substring-match per the\n * AC4 auto-cancel plan and call {@link RecurringNamespace.prepareCancellation}\n * when applicable. Kept as `string` (with `(string & NonNullable<unknown>)`\n * widening) so a new server-side reason doesn't brick already-shipped clients.\n * - **Server-side quote rejection** (slippage, target-token unsupported,\n * liquidity, etc.) — Markr decides at `/recurring/quote` time. Surface\n * those as `HttpError(400)` / `HttpError(422)` from\n * {@link RecurringNamespace.quote}.\n *\n * Net: this helper covers the \"can the user *attempt* a recurring swap with\n * this token pair\" question. Anything that requires a wallet, RPC, or live\n * orchestrator round-trip lives elsewhere.\n */\nexport function checkRecurringEligibility(params: CheckRecurringEligibilityParams): RecurringEligibility {\n const { recurringChainInfo, fromTokenAddress, toTokenAddress, sourceChainId, targetChainId, ownerAddress } = params;\n\n if (!ownerAddress) {\n return { eligible: false, reason: RecurringEligibilityReason.NoEvmAddress };\n }\n\n if (sourceChainId !== targetChainId) {\n return { eligible: false, reason: RecurringEligibilityReason.CrossChain };\n }\n\n // Presence in the chain-info map is the recurring-enabled signal — the map\n // is built only for chains that carried a `recurring` block in\n // `/info/chains`. Markr no longer publishes a per-chain supported-token\n // list, so there is nothing token-level to assert here.\n const chain: RecurringChainInfoEntry | undefined = recurringChainInfo.get(sourceChainId);\n\n if (!chain) {\n return { eligible: false, reason: RecurringEligibilityReason.UnsupportedSourceChain };\n }\n\n // Native input is passed through to Markr verbatim (the recurring API\n // accepts the zero address as `tokenIn`); the SDK only uses the chain's\n // wrapped-native address for the on-chain wrap leg + WAVAX allowance in\n // `executeFirstFill`. The wrapped-native is read off the chain entry\n // (sourced from `/info/chains[].wrapped_token`) — no SDK-side static map.\n //\n // Two native-specific checks live here:\n // 1. Fail closed when Markr didn't publish a wrapped-native for the\n // chain we couldn't execute the schedule even if it's eligible.\n // 2. Reject native → wrapped-native (e.g. AVAX → WAVAX) with a dedicated\n // reason economically just a scheduled wrap, not a swap. Consumer\n // UI should steer the user to a one-shot wrap instead of failing with\n // a generic \"unsupported token\" message.\n const isNativeInput = isAddressEqual(fromTokenAddress, ERC_ZERO_ADDRESS);\n if (isNativeInput) {\n if (!chain.wrappedNativeAddress) {\n return { eligible: false, reason: RecurringEligibilityReason.UnsupportedToken };\n }\n if (isAddressEqual(toTokenAddress, chain.wrappedNativeAddress)) {\n return { eligible: false, reason: RecurringEligibilityReason.NativeToWrappedNative };\n }\n }\n\n // Recurring swaps are one-way (tokenIn → tokenOut) and Markr decides\n // token-level eligibility server-side at /recurring/quote time. Reject the\n // obvious nonsense (`toTokenAddress` matching `fromTokenAddress`) up front\n // to fail fast. `isAddressEqual` does a case-insensitive compare without\n // per-call string allocations (matches the pattern in `markr/_utils.ts`).\n if (isAddressEqual(toTokenAddress, fromTokenAddress)) {\n return { eligible: false, reason: RecurringEligibilityReason.UnsupportedToken };\n }\n\n return {\n eligible: true,\n minIntervalSeconds: chain.minFrequencySeconds,\n };\n}\n"],"mappings":"4HAmDA,SAAgB,EAA0B,EAA+D,CACvG,GAAM,CAAE,qBAAoB,mBAAkB,iBAAgB,gBAAe,gBAAe,gBAAiB,EAE7G,GAAI,CAAC,EACH,MAAO,CAAE,SAAU,GAAO,OAAQ,EAA2B,aAAc,CAG7E,GAAI,IAAkB,EACpB,MAAO,CAAE,SAAU,GAAO,OAAQ,EAA2B,WAAY,CAO3E,IAAM,EAA6C,EAAmB,IAAI,EAAc,CAExF,GAAI,CAAC,EACH,MAAO,CAAE,SAAU,GAAO,OAAQ,EAA2B,uBAAwB,CAiBvF,GADsB,EAAe,EAAA,6CAAmC,CACrD,CACjB,GAAI,CAAC,EAAM,qBACT,MAAO,CAAE,SAAU,GAAO,OAAQ,EAA2B,iBAAkB,CAEjF,GAAI,EAAe,EAAgB,EAAM,qBAAqB,CAC5D,MAAO,CAAE,SAAU,GAAO,OAAQ,EAA2B,sBAAuB,CAaxF,OAJI,EAAe,EAAgB,EAAiB,CAC3C,CAAE,SAAU,GAAO,OAAQ,EAA2B,iBAAkB,CAG1E,CACL,SAAU,GACV,mBAAoB,EAAM,oBAC3B"}
@@ -1,2 +1,2 @@
1
- require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../constants.cjs`),t=require(`../../../errors.cjs`),n=require(`../../../utils/caip.cjs`),r=require(`../../_utils.cjs`),i=require(`../../_evm-errors.cjs`),a=require(`../../_evm-approval.cjs`),o=require(`../_api.cjs`),s=require(`../_utils.cjs`),c=require(`./_api.cjs`),l=require(`./_eligibility.cjs`);let u=require(`viem`);function d({apiOptions:t,appId:n,evmSigner:r,recurringChainInfo:i}){return{quote:e=>c.markrRecurringQuote(t,{...e,appId:n}),executeFirstFill:e=>f({...e,apiOptions:t,appId:n,evmSigner:r}),listOrders:e=>c.markrListRecurringOrders(t,e),executeCancellation:n=>m({...n,signatureReason:e.TransferSignatureReason.CancelRecurringSwap,apiOptions:t,evmSigner:r,fetchCalldata:c.markrPrepareCancellation}),executePause:n=>m({...n,signatureReason:e.TransferSignatureReason.PauseRecurringSwap,apiOptions:t,evmSigner:r,fetchCalldata:c.markrPreparePause}),executeUnpause:n=>m({...n,signatureReason:e.TransferSignatureReason.ResumeRecurringSwap,apiOptions:t,evmSigner:r,fetchCalldata:c.markrPrepareUnpause}),checkEligibility:e=>l.checkRecurringEligibility({...e,recurringChainInfo:i}),getRecurringChainInfo:()=>i}}async function f({apiOptions:l,appId:u,evmSigner:d,fallbackToDefaultOnBatchFailure:f,fromAddress:p,gasSettings:m,quote:g,signerContext:_,sourceChain:v}){let y=Math.floor(Date.now()/1e3);if(g.expiredAt<=y){let e=y-g.expiredAt;throw new t.InvalidParamsError(t.ErrorReason.QUOTE_EXPIRED,`Recurring quote expired ${e} seconds ago.`)}let b=n.caip2ToEip155ChainId(v.chainId);if(b!==g.chainId)throw new t.InvalidParamsError(`sourceChain does not match quote.chainId`,`sourceChain.chainId=${v.chainId} resolves to ${b}, but quote.chainId=${g.chainId}.`);let x=r.getEvmClientForChain({chain:v}),S=n.caip2ToEip155HexChainId(v.chainId),{address:C}=await o.markrGetSpenderAddress(l,{chainId:g.chainId,crossChainSwap:!1,quoteId:g.uuid});if(!C)throw new t.SdkError(t.ErrorReason.CHAIN_NOT_SUPPORTED,t.ErrorCode.INVALID_PARAMS,{details:`Missing Markr spender address for source chain ${v.chainId}.`});let w=await a.buildErc20ApprovalRequest({chainIdHex:S,client:x,gasSettings:m,owner:p,requiredAllowance:g.totalAmountIn,spender:C,token:g.tokenIn}),T=h({fromAddress:p,quote:g,sourceChain:v}),E=await c.markrRecurringSwap(l,{uuid:g.uuid,appId:u});if(w!==void 0&&typeof d.signBatch==`function`){let n={currentSignature:1,currentSignatureReason:e.TransferSignatureReason.ScheduleRecurringSwap,quote:T,requiredSignatures:1,signerContext:_},i={chainId:S,data:E.data,from:p,gas:void 0,to:E.to,value:E.value,...r.maybe1559(m)};try{let e=(await d.signBatch([w,i],e=>x.sendRawTransaction({serializedTransaction:e}),n)).at(-1);if(!e)throw new t.SdkError(`One-click batch signing returned no transaction hashes.`,t.ErrorCode.SIGNING_FAILED);return{txHash:e}}catch(e){if(!f)throw e}}w&&await a.signApprovalAndAssertConfirmed({client:x,evmSigner:d,request:w,step:{currentSignature:1,currentSignatureReason:e.TransferSignatureReason.AllowanceApproval,quote:T,requiredSignatures:2,signerContext:_}});let D=await s.getMarkrSwapWrapperAbi(!1),O=await i.estimateGasWithRevert(x,{account:p,to:E.to,data:E.data,value:E.value},D,`Failed to estimate gas for recurring first-fill swap transaction.`),k={chainId:S,data:E.data,from:p,gas:r.applyFeeUnitsBpsMargin(O,m?.estimateGasMarginBps),to:E.to,value:E.value,...r.maybe1559(m)},A={currentSignature:w?2:1,currentSignatureReason:e.TransferSignatureReason.ScheduleRecurringSwap,quote:T,requiredSignatures:w?2:1,signerContext:_};return{txHash:await d.sign(k,e=>x.sendRawTransaction({serializedTransaction:e}),A)}}const p={[e.TransferSignatureReason.PauseRecurringSwap]:`pause`,[e.TransferSignatureReason.ResumeRecurringSwap]:`resume`,[e.TransferSignatureReason.CancelRecurringSwap]:`cancel`};async function m({signatureReason:e,address:t,apiOptions:a,evmSigner:o,fetchCalldata:s,gasSettings:c,orderId:l,signerContext:d,sourceChain:f}){let m=r.getEvmClientForChain({chain:f}),h=n.caip2ToEip155ChainId(f.chainId),_=n.caip2ToEip155HexChainId(f.chainId),v=await s(a,{orderId:l,address:t,chainId:h}),y=await i.estimateGasWithRevert(m,{account:t,to:v.to,data:v.data,value:v.value},u.erc20Abi,`Failed to estimate gas for recurring ${p[e]} transaction.`),b={chainId:_,data:v.data,from:t,gas:r.applyFeeUnitsBpsMargin(y,c?.estimateGasMarginBps),to:v.to,value:v.value,...r.maybe1559(c)},x={currentSignature:1,currentSignatureReason:e,quote:g({address:t,signatureReason:e,orderId:l,sourceChain:f}),requiredSignatures:1,signerContext:d};return{txHash:await o.sign(b,e=>m.sendRawTransaction({serializedTransaction:e}),x)}}function h({fromAddress:t,quote:n,sourceChain:r}){return{aggregator:{id:`markr-recurring`,name:`Markr recurring`},amountIn:n.amount,amountOut:n.amountOut,assetIn:{type:e.TokenType.ERC20,address:n.tokenIn,name:``,symbol:``,decimals:0},assetOut:{type:e.TokenType.ERC20,address:n.tokenOut,name:``,symbol:``,decimals:0},expiresAt:n.expiredAt,fees:[],fromAddress:t,id:n.uuid,partnerFeeBps:null,serviceType:e.ServiceType.MARKR,slippageBps:n.recommendedSlippage,sourceChain:r,targetChain:r,toAddress:t}}function g({signatureReason:t,address:n,orderId:r,sourceChain:i}){let a=p[t];return{aggregator:{id:`markr-recurring-${a}`,name:`Markr recurring (${a})`},amountIn:0n,amountOut:0n,assetIn:_(),assetOut:_(),expiresAt:0,fees:[],fromAddress:n,id:r,partnerFeeBps:null,serviceType:e.ServiceType.MARKR,slippageBps:0,sourceChain:i,targetChain:i,toAddress:n}}function _(){return{type:e.TokenType.NATIVE,name:``,symbol:``,decimals:0}}exports.createRecurringNamespace=d;
1
+ require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../constants.cjs`),t=require(`../../../errors.cjs`),n=require(`../../../utils/caip.cjs`),r=require(`../../_utils.cjs`),i=require(`../../_evm-errors.cjs`),a=require(`../../_evm-approval.cjs`),o=require(`../_api.cjs`),s=require(`../_utils.cjs`),c=require(`./_api.cjs`),l=require(`./_eligibility.cjs`);let u=require(`viem`);function d({apiOptions:t,appId:n,evmSigner:r,recurringChainInfo:i}){return{quote:e=>f({...e,apiOptions:t,appId:n,recurringChainInfo:i}),executeFirstFill:e=>p({...e,apiOptions:t,appId:n,evmSigner:r,recurringChainInfo:i}),listOrders:e=>c.markrListRecurringOrders(t,e),executeCancellation:n=>g({...n,signatureReason:e.TransferSignatureReason.CancelRecurringSwap,apiOptions:t,evmSigner:r,fetchCalldata:c.markrPrepareCancellation}),executePause:n=>g({...n,signatureReason:e.TransferSignatureReason.PauseRecurringSwap,apiOptions:t,evmSigner:r,fetchCalldata:c.markrPreparePause}),executeUnpause:n=>g({...n,signatureReason:e.TransferSignatureReason.ResumeRecurringSwap,apiOptions:t,evmSigner:r,fetchCalldata:c.markrPrepareUnpause}),checkEligibility:e=>l.checkRecurringEligibility({...e,recurringChainInfo:i}),getRecurringChainInfo:()=>i}}async function f({apiOptions:e,appId:n,recurringChainInfo:r,...i}){if((0,u.isAddressEqual)(i.tokenIn,`0x0000000000000000000000000000000000000000`)&&!r.get(i.chainId)?.wrappedNativeAddress)throw new t.InvalidParamsError(t.ErrorReason.CHAIN_NOT_SUPPORTED,`No wrapped-native ERC-20 address known for EVM chainId ${i.chainId}. Native-input recurring swaps require Markr to publish \`wrapped_token\` for the chain in \`/info/chains\`.`);return c.markrRecurringQuote(e,{...i,appId:n})}async function p({apiOptions:l,appId:d,evmSigner:f,fallbackToDefaultOnBatchFailure:p,fromAddress:h,gasSettings:g,quote:v,recurringChainInfo:y,signerContext:b,sourceChain:x}){let S=Math.floor(Date.now()/1e3);if(v.expiredAt<=S){let e=S-v.expiredAt;throw new t.InvalidParamsError(t.ErrorReason.QUOTE_EXPIRED,`Recurring quote expired ${e} seconds ago.`)}let C=n.caip2ToEip155ChainId(x.chainId);if(C!==v.chainId)throw new t.InvalidParamsError(`sourceChain does not match quote.chainId`,`sourceChain.chainId=${x.chainId} resolves to ${C}, but quote.chainId=${v.chainId}.`);let w=r.getEvmClientForChain({chain:x}),T=n.caip2ToEip155HexChainId(x.chainId),E=(0,u.isAddressEqual)(v.tokenIn,e.ERC_ZERO_ADDRESS),{address:D}=await o.markrGetSpenderAddress(l,{chainId:v.chainId,crossChainSwap:!1,quoteId:v.uuid});if(!D)throw new t.SdkError(t.ErrorReason.CHAIN_NOT_SUPPORTED,t.ErrorCode.INVALID_PARAMS,{details:`Missing Markr spender address for source chain ${x.chainId}.`});let O=await c.markrRecurringSwap(l,{uuid:v.uuid,appId:d}),k=O.find(e=>e.type===`wrap`),A=O.find(e=>e.type===`createOrder`);if(!A)throw new t.SdkError(t.ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT,t.ErrorCode.INVALID_PARAMS,{details:`Missing createOrder step (quote uuid: ${v.uuid}).`});if(E&&!k)throw new t.SdkError(t.ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT,t.ErrorCode.INVALID_PARAMS,{details:`Native-input quote returned no wrap step (quote uuid: ${v.uuid}).`});if(!E&&k)throw new t.SdkError(t.ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT,t.ErrorCode.INVALID_PARAMS,{details:`ERC-20 input quote returned a wrap step (quote uuid: ${v.uuid}, tokenIn: ${v.tokenIn}).`});if(k){if(k.value!==v.totalAmountIn)throw new t.SdkError(t.ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT,t.ErrorCode.INVALID_PARAMS,{details:`Wrap step value ${k.value} does not match quote.totalAmountIn ${v.totalAmountIn} (quote uuid: ${v.uuid}).`});let e=y.get(v.chainId)?.wrappedNativeAddress;if(e&&!(0,u.isAddressEqual)(k.to,e))throw new t.SdkError(t.ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT,t.ErrorCode.INVALID_PARAMS,{details:`Wrap step target ${k.to} does not match the published wrapped-native ${e} for chainId ${v.chainId} (quote uuid: ${v.uuid}).`})}let j=k?.to??v.tokenIn,M=await a.buildErc20ApprovalRequest({chainIdHex:T,client:w,gasSettings:g,owner:h,requiredAllowance:v.totalAmountIn,spender:D,token:j}),N=k?{chainId:T,data:k.data,from:h,gas:void 0,to:k.to,value:k.value,...r.maybe1559(g)}:void 0,P=_({fromAddress:h,quote:v,sourceChain:x}),F=[];if(N&&F.push(N),M&&F.push(M),F.length>0&&typeof f.signBatch==`function`){let n={currentSignature:1,currentSignatureReason:e.TransferSignatureReason.ScheduleRecurringSwap,quote:P,requiredSignatures:1,signerContext:b},i={chainId:T,data:A.data,from:h,gas:void 0,to:A.to,value:A.value,...r.maybe1559(g)};try{let e=(await f.signBatch([...F,i],e=>w.sendRawTransaction({serializedTransaction:e}),n)).at(-1);if(!e)throw new t.SdkError(`One-click batch signing returned no transaction hashes.`,t.ErrorCode.SIGNING_FAILED);return{txHash:e}}catch(e){if(!p)throw e}}let I=1+F.length,L=0;if(N&&k){let t=await i.estimateGasWithRevert(w,{account:h,to:k.to,data:k.data,value:k.value},[],`Failed to estimate gas for recurring first-fill wrap transaction.`),n={...N,gas:r.applyFeeUnitsBpsMargin(t,g?.estimateGasMarginBps)};L+=1,await m({client:w,evmSigner:f,request:n,step:{currentSignature:L,currentSignatureReason:e.TransferSignatureReason.WrapToken,quote:P,requiredSignatures:I,signerContext:b}})}M&&(L+=1,await a.signApprovalAndAssertConfirmed({client:w,evmSigner:f,request:M,step:{currentSignature:L,currentSignatureReason:e.TransferSignatureReason.AllowanceApproval,quote:P,requiredSignatures:I,signerContext:b}}));let R=await s.getMarkrSwapWrapperAbi(!1),z=await i.estimateGasWithRevert(w,{account:h,to:A.to,data:A.data,value:A.value},R,`Failed to estimate gas for recurring first-fill swap transaction.`),B={chainId:T,data:A.data,from:h,gas:r.applyFeeUnitsBpsMargin(z,g?.estimateGasMarginBps),to:A.to,value:A.value,...r.maybe1559(g)};L+=1;let V={currentSignature:L,currentSignatureReason:e.TransferSignatureReason.ScheduleRecurringSwap,quote:P,requiredSignatures:I,signerContext:b};return{txHash:await f.sign(B,e=>w.sendRawTransaction({serializedTransaction:e}),V)}}async function m({client:e,evmSigner:n,request:r,step:i}){let a=await n.sign(r,t=>e.sendRawTransaction({serializedTransaction:t}),i);if((await e.waitForTransactionReceipt({hash:a})).status===`reverted`)throw new t.SdkError(t.ErrorReason.NATIVE_WRAP_REVERTED,t.ErrorCode.TRANSACTION_REVERTED,{details:`Wrap tx reverted on-chain (tx hash: ${a}).`});return a}const h={[e.TransferSignatureReason.PauseRecurringSwap]:`pause`,[e.TransferSignatureReason.ResumeRecurringSwap]:`resume`,[e.TransferSignatureReason.CancelRecurringSwap]:`cancel`};async function g({signatureReason:e,address:t,apiOptions:a,evmSigner:o,fetchCalldata:s,gasSettings:c,orderId:l,signerContext:d,sourceChain:f}){let p=r.getEvmClientForChain({chain:f}),m=n.caip2ToEip155ChainId(f.chainId),g=n.caip2ToEip155HexChainId(f.chainId),_=await s(a,{orderId:l,address:t,chainId:m}),y=await i.estimateGasWithRevert(p,{account:t,to:_.to,data:_.data,value:_.value},u.erc20Abi,`Failed to estimate gas for recurring ${h[e]} transaction.`),b={chainId:g,data:_.data,from:t,gas:r.applyFeeUnitsBpsMargin(y,c?.estimateGasMarginBps),to:_.to,value:_.value,...r.maybe1559(c)},x={currentSignature:1,currentSignatureReason:e,quote:v({address:t,signatureReason:e,orderId:l,sourceChain:f}),requiredSignatures:1,signerContext:d};return{txHash:await o.sign(b,e=>p.sendRawTransaction({serializedTransaction:e}),x)}}function _({fromAddress:t,quote:n,sourceChain:r}){return{aggregator:{id:`markr-recurring`,name:`Markr recurring`},amountIn:n.amount,amountOut:n.amountOut,assetIn:{type:e.TokenType.ERC20,address:n.tokenIn,name:``,symbol:``,decimals:0},assetOut:{type:e.TokenType.ERC20,address:n.tokenOut,name:``,symbol:``,decimals:0},expiresAt:n.expiredAt,fees:[],fromAddress:t,id:n.uuid,partnerFeeBps:null,serviceType:e.ServiceType.MARKR,slippageBps:n.recommendedSlippage,sourceChain:r,targetChain:r,toAddress:t}}function v({signatureReason:t,address:n,orderId:r,sourceChain:i}){let a=h[t];return{aggregator:{id:`markr-recurring-${a}`,name:`Markr recurring (${a})`},amountIn:0n,amountOut:0n,assetIn:y(),assetOut:y(),expiresAt:0,fees:[],fromAddress:n,id:r,partnerFeeBps:null,serviceType:e.ServiceType.MARKR,slippageBps:0,sourceChain:i,targetChain:i,toAddress:n}}function y(){return{type:e.TokenType.NATIVE,name:``,symbol:``,decimals:0}}exports.createRecurringNamespace=d;
2
2
  //# sourceMappingURL=_namespace.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"_namespace.cjs","names":["markrRecurringQuote","markrListRecurringOrders","TransferSignatureReason","markrPrepareCancellation","markrPreparePause","markrPrepareUnpause","checkRecurringEligibility","InvalidParamsError","ErrorReason","caip2ToEip155ChainId","getEvmClientForChain","caip2ToEip155HexChainId","markrGetSpenderAddress","SdkError","ErrorCode","buildErc20ApprovalRequest","markrRecurringSwap","maybe1559","signApprovalAndAssertConfirmed","getMarkrSwapWrapperAbi","estimateGasWithRevert","applyFeeUnitsBpsMargin","erc20Abi","TokenType","ServiceType"],"sources":["../../../../src/transfer-service/markr/recurring/_namespace.ts"],"sourcesContent":["import { erc20Abi } from 'viem';\nimport { ServiceType, TokenType, TransferSignatureReason } from '../../../constants';\nimport { ErrorCode, ErrorReason, InvalidParamsError, SdkError } from '../../../errors';\nimport type { Chain } from '../../../types/chain';\nimport type { Quote } from '../../../types/quote';\nimport type { EvmSigner, EvmTransactionRequest } from '../../../types/signer';\nimport type { TransferStepDetails } from '../../../types/transfer';\nimport { caip2ToEip155ChainId, caip2ToEip155HexChainId } from '../../../utils/caip';\nimport { applyFeeUnitsBpsMargin, getEvmClientForChain, maybe1559 } from '../../_utils';\nimport { buildErc20ApprovalRequest, signApprovalAndAssertConfirmed } from '../../_evm-approval';\nimport { estimateGasWithRevert } from '../../_evm-errors';\nimport type { WrappedSwapTransactionResponse } from '../_schema';\nimport { markrGetSpenderAddress, type ApiOptions } from '../_api';\nimport { getMarkrSwapWrapperAbi } from '../_utils';\nimport {\n markrListRecurringOrders,\n markrPrepareCancellation,\n markrPreparePause,\n markrPrepareUnpause,\n markrRecurringQuote,\n markrRecurringSwap,\n} from './_api';\nimport { checkRecurringEligibility } from './_eligibility';\nimport type {\n RecurringChainInfoMap,\n RecurringExecuteFirstFillParams,\n RecurringExecuteOrderActionParams,\n RecurringExecuteResult,\n RecurringNamespace,\n RecurringQuoteResponse,\n} from './types';\n\nexport interface CreateRecurringNamespaceOptions {\n apiOptions: ApiOptions;\n appId: string;\n evmSigner: EvmSigner;\n /**\n * The cached `/info/chains` recurring metadata. Captured by value at\n * namespace construction time — matches how `partnerFeeBps`,\n * `supportedChains`, and `supportedTokens` are also frozen at\n * `createMarkrService` init. If staleness ever becomes a real consumer\n * concern, the fix is a top-level `manager.refresh()` (not a per-namespace\n * lazy-read pattern).\n */\n recurringChainInfo: RecurringChainInfoMap;\n}\n\nexport function createRecurringNamespace({\n apiOptions,\n appId,\n evmSigner,\n recurringChainInfo,\n}: CreateRecurringNamespaceOptions): RecurringNamespace {\n return {\n quote: (props) => markrRecurringQuote(apiOptions, { ...props, appId }),\n\n executeFirstFill: (props) => executeFirstFillImpl({ ...props, apiOptions, appId, evmSigner }),\n\n listOrders: (props) => markrListRecurringOrders(apiOptions, props),\n\n executeCancellation: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.CancelRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPrepareCancellation,\n }),\n\n executePause: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.PauseRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPreparePause,\n }),\n\n executeUnpause: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.ResumeRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPrepareUnpause,\n }),\n\n checkEligibility: (props) => checkRecurringEligibility({ ...props, recurringChainInfo }),\n\n getRecurringChainInfo: () => recurringChainInfo,\n };\n}\n\n// ---------------------------------------------------------------------------\n// First-fill execution (allowance check + approve-if-needed + first-fill swap)\n// ---------------------------------------------------------------------------\n\ninterface ExecuteFirstFillImplParams extends RecurringExecuteFirstFillParams {\n apiOptions: ApiOptions;\n appId: string;\n evmSigner: EvmSigner;\n}\n\nasync function executeFirstFillImpl({\n apiOptions,\n appId,\n evmSigner,\n fallbackToDefaultOnBatchFailure,\n fromAddress,\n gasSettings,\n quote,\n signerContext,\n sourceChain,\n}: ExecuteFirstFillImplParams): Promise<RecurringExecuteResult> {\n // Mirror the one-shot guard at `TransferManager.estimateNativeFee` — fail at\n // the SDK boundary with `QUOTE_EXPIRED` instead of an opaque `HttpError`\n // from `/recurring/swap` for a slow-to-approve user.\n const now = Math.floor(Date.now() / 1_000);\n if (quote.expiredAt <= now) {\n const expiredSecondsAgo = now - quote.expiredAt;\n throw new InvalidParamsError(\n ErrorReason.QUOTE_EXPIRED,\n `Recurring quote expired ${expiredSecondsAgo} seconds ago.`,\n );\n }\n\n // Wiring-mistake guard: the passed `sourceChain.chainId` (CAIP-2) must agree\n // with the `chainId` (numeric) the quote was issued against. Otherwise the\n // allowance / gas reads hit the wrong chain.\n const sourceChainIdNumeric = caip2ToEip155ChainId(sourceChain.chainId);\n if (sourceChainIdNumeric !== quote.chainId) {\n throw new InvalidParamsError(\n 'sourceChain does not match quote.chainId',\n `sourceChain.chainId=${sourceChain.chainId} resolves to ${sourceChainIdNumeric}, but quote.chainId=${quote.chainId}.`,\n );\n }\n\n const sourceClient = getEvmClientForChain({ chain: sourceChain });\n const chainIdHex = caip2ToEip155HexChainId(sourceChain.chainId);\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: quote.chainId,\n crossChainSwap: false,\n quoteId: quote.uuid,\n });\n\n if (!spenderAddress) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Missing Markr spender address for source chain ${sourceChain.chainId}.`,\n });\n }\n\n const approvalRequest = await buildErc20ApprovalRequest({\n chainIdHex,\n client: sourceClient,\n gasSettings,\n owner: fromAddress,\n requiredAllowance: quote.totalAmountIn,\n spender: spenderAddress,\n token: quote.tokenIn,\n });\n\n const syntheticQuote = buildSyntheticQuoteForFirstFill({ fromAddress, quote, sourceChain });\n\n const swap = await markrRecurringSwap(apiOptions, { uuid: quote.uuid, appId });\n\n // One-click batch path: same-chain DCA, approval required, signer exposes\n // `signBatch`. Matches `_executeEvmTransfer`'s eligibility check (recurring\n // is always same-chain so the cross-chain check there collapses to true).\n if (approvalRequest !== undefined && typeof evmSigner.signBatch === 'function') {\n const batchStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.ScheduleRecurringSwap,\n quote: syntheticQuote,\n requiredSignatures: 1,\n signerContext,\n };\n\n // Gas is left undefined on the swap leg — the wallet handles batched gas\n // estimation since the approval hasn't executed yet.\n const swapRequest: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: swap.data,\n from: fromAddress,\n gas: undefined,\n to: swap.to,\n value: swap.value,\n ...maybe1559(gasSettings),\n };\n\n try {\n const txHashes = await evmSigner.signBatch(\n [approvalRequest, swapRequest],\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n batchStep,\n );\n const swapTxHash = txHashes.at(-1);\n if (!swapTxHash) {\n throw new SdkError('One-click batch signing returned no transaction hashes.', ErrorCode.SIGNING_FAILED);\n }\n return { txHash: swapTxHash };\n } catch (error) {\n if (!fallbackToDefaultOnBatchFailure) {\n throw error;\n }\n // Fall through to the two-signature path below.\n }\n }\n\n if (approvalRequest) {\n await signApprovalAndAssertConfirmed({\n client: sourceClient,\n evmSigner,\n request: approvalRequest,\n step: {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.AllowanceApproval,\n quote: syntheticQuote,\n requiredSignatures: 2,\n signerContext,\n },\n });\n }\n\n // Use the Markr same-chain swap wrapper ABI for best-effort revert decoding\n // — matches `_estimateGasFromSwapResponse` in `estimate-native-fee.ts`.\n // Recurring is always same-chain, so `crossChain: false`. Built-in\n // `Error(string)` / `Panic(uint256)` are decoded regardless of ABI.\n const markrAbi = await getMarkrSwapWrapperAbi(false);\n const swapGasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: fromAddress, to: swap.to, data: swap.data, value: swap.value },\n markrAbi,\n 'Failed to estimate gas for recurring first-fill swap transaction.',\n );\n\n const swapRequest: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: swap.data,\n from: fromAddress,\n gas: applyFeeUnitsBpsMargin(swapGasEstimate, gasSettings?.estimateGasMarginBps),\n to: swap.to,\n value: swap.value,\n ...maybe1559(gasSettings),\n };\n\n const swapStep: TransferStepDetails = {\n currentSignature: approvalRequest ? 2 : 1,\n currentSignatureReason: TransferSignatureReason.ScheduleRecurringSwap,\n quote: syntheticQuote,\n requiredSignatures: approvalRequest ? 2 : 1,\n signerContext,\n };\n\n const txHash = await evmSigner.sign(\n swapRequest,\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n swapStep,\n );\n\n return { txHash };\n}\n\n// ---------------------------------------------------------------------------\n// Order-action execution (cancel / pause / unpause — single-tx state change)\n// ---------------------------------------------------------------------------\n\ninterface ExecuteOrderActionImplParams extends RecurringExecuteOrderActionParams {\n signatureReason:\n | TransferSignatureReason.PauseRecurringSwap\n | TransferSignatureReason.ResumeRecurringSwap\n | TransferSignatureReason.CancelRecurringSwap;\n apiOptions: ApiOptions;\n evmSigner: EvmSigner;\n fetchCalldata: (\n apiOptions: ApiOptions,\n params: { orderId: `0x${string}`; address: `0x${string}`; chainId: number },\n ) => Promise<WrappedSwapTransactionResponse>;\n}\n\n// Short verbs for error-message interpolation — avoids the doubled-\"recurring\"\n// + kebab-case-in-prose readout you'd get from interpolating the raw enum\n// wire value (e.g. `recurring pause-recurring-swap transaction`).\nconst ORDER_ACTION_LABEL: Record<ExecuteOrderActionImplParams['signatureReason'], string> = {\n [TransferSignatureReason.PauseRecurringSwap]: 'pause',\n [TransferSignatureReason.ResumeRecurringSwap]: 'resume',\n [TransferSignatureReason.CancelRecurringSwap]: 'cancel',\n};\n\nasync function executeOrderActionImpl({\n signatureReason,\n address,\n apiOptions,\n evmSigner,\n fetchCalldata,\n gasSettings,\n orderId,\n signerContext,\n sourceChain,\n}: ExecuteOrderActionImplParams): Promise<RecurringExecuteResult> {\n const sourceClient = getEvmClientForChain({ chain: sourceChain });\n const chainIdNumeric = caip2ToEip155ChainId(sourceChain.chainId);\n const chainIdHex = caip2ToEip155HexChainId(sourceChain.chainId);\n\n const calldata = await fetchCalldata(apiOptions, { orderId, address, chainId: chainIdNumeric });\n\n const gasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: address, to: calldata.to, data: calldata.data, value: calldata.value },\n erc20Abi,\n `Failed to estimate gas for recurring ${ORDER_ACTION_LABEL[signatureReason]} transaction.`,\n );\n\n const request: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: calldata.data,\n from: address,\n gas: applyFeeUnitsBpsMargin(gasEstimate, gasSettings?.estimateGasMarginBps),\n to: calldata.to,\n value: calldata.value,\n ...maybe1559(gasSettings),\n };\n\n const step: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: signatureReason,\n quote: buildSyntheticQuoteForOrderAction({ address, signatureReason, orderId, sourceChain }),\n requiredSignatures: 1,\n signerContext,\n };\n\n const txHash = await evmSigner.sign(\n request,\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n return { txHash };\n}\n\n// ---------------------------------------------------------------------------\n// Internal: synthetic Quote objects for `TransferStepDetails.quote`\n// ---------------------------------------------------------------------------\n\n/**\n * Builds a minimum-viable {@link Quote} for the signer step so consumer\n * `EvmSigner` impls can render meaningful wallet prompts for a recurring\n * action (which has no real `Quote` in the swap-quoter sense). The synthetic\n * value carries enough recurring context (uuid, chain, amounts, tokens) for\n * a wallet UI to label the popup; the `aggregator.id` (`'markr-recurring'`)\n * lets advanced signers detect the recurring path explicitly.\n *\n * Asset fields use placeholder `name`/`symbol`/`decimals` because the\n * recurring quote doesn't echo those — consumers needing rich asset display\n * should resolve token metadata against their own asset map keyed by\n * `quote.tokenIn`/`tokenOut`.\n */\nfunction buildSyntheticQuoteForFirstFill({\n fromAddress,\n quote,\n sourceChain,\n}: {\n fromAddress: `0x${string}`;\n quote: RecurringQuoteResponse;\n sourceChain: Chain;\n}): Quote {\n return {\n // Keep the stable `'markr-recurring'` marker (shipped in #240) — consumer\n // signers may detect the recurring path via `quote.aggregator.id`. The\n // typed `TransferStepDetails.currentSignatureReason` is now the preferred\n // discriminant for new integrations, but this id stays for back-compat.\n aggregator: { id: 'markr-recurring', name: 'Markr recurring' },\n amountIn: quote.amount,\n amountOut: quote.amountOut,\n assetIn: { type: TokenType.ERC20, address: quote.tokenIn, name: '', symbol: '', decimals: 0 },\n assetOut: { type: TokenType.ERC20, address: quote.tokenOut, name: '', symbol: '', decimals: 0 },\n expiresAt: quote.expiredAt,\n fees: [],\n fromAddress,\n id: quote.uuid,\n partnerFeeBps: null,\n serviceType: ServiceType.MARKR,\n slippageBps: quote.recommendedSlippage,\n // Pass the caller-provided `Chain` straight through — recurring is always\n // same-chain, so source === target. Avoids stripping `chainName` /\n // `networkToken` / `rpcUrl` that consumer signers may use for display.\n sourceChain,\n targetChain: sourceChain,\n toAddress: fromAddress,\n };\n}\n\nfunction buildSyntheticQuoteForOrderAction({\n signatureReason,\n address,\n orderId,\n sourceChain,\n}: {\n signatureReason:\n | TransferSignatureReason.PauseRecurringSwap\n | TransferSignatureReason.ResumeRecurringSwap\n | TransferSignatureReason.CancelRecurringSwap;\n address: `0x${string}`;\n orderId: `0x${string}`;\n sourceChain: Chain;\n}): Quote {\n const action = ORDER_ACTION_LABEL[signatureReason];\n return {\n // Same back-compat rationale as `buildSyntheticQuoteForFirstFill` — preserve\n // the original lowercase `markr-recurring-${action}` id shape (shipped in\n // #240) so consumers keying off `quote.aggregator.id` keep working.\n aggregator: {\n id: `markr-recurring-${action}`,\n name: `Markr recurring (${action})`,\n },\n amountIn: 0n,\n amountOut: 0n,\n assetIn: emptyNativeAsset(),\n assetOut: emptyNativeAsset(),\n expiresAt: 0,\n fees: [],\n fromAddress: address,\n id: orderId,\n partnerFeeBps: null,\n serviceType: ServiceType.MARKR,\n slippageBps: 0,\n // See `buildSyntheticQuoteForFirstFill` — pass the real `Chain` through.\n sourceChain,\n targetChain: sourceChain,\n toAddress: address,\n };\n}\n\nfunction emptyNativeAsset() {\n return { type: TokenType.NATIVE, name: '', symbol: '', decimals: 0 } as const;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"_namespace.cjs","names":["markrListRecurringOrders","TransferSignatureReason","markrPrepareCancellation","markrPreparePause","markrPrepareUnpause","checkRecurringEligibility","InvalidParamsError","ErrorReason","markrRecurringQuote","caip2ToEip155ChainId","getEvmClientForChain","caip2ToEip155HexChainId","ERC_ZERO_ADDRESS","markrGetSpenderAddress","SdkError","ErrorCode","markrRecurringSwap","buildErc20ApprovalRequest","maybe1559","estimateGasWithRevert","applyFeeUnitsBpsMargin","signApprovalAndAssertConfirmed","getMarkrSwapWrapperAbi","erc20Abi","TokenType","ServiceType"],"sources":["../../../../src/transfer-service/markr/recurring/_namespace.ts"],"sourcesContent":["import { erc20Abi, isAddressEqual } from 'viem';\nimport { ERC_ZERO_ADDRESS, ServiceType, TokenType, TransferSignatureReason } from '../../../constants';\nimport { ErrorCode, ErrorReason, InvalidParamsError, SdkError } from '../../../errors';\nimport type { Chain } from '../../../types/chain';\nimport type { Quote } from '../../../types/quote';\nimport type { EvmSigner, EvmTransactionRequest, Hex } from '../../../types/signer';\nimport type { TransferStepDetails } from '../../../types/transfer';\nimport { caip2ToEip155ChainId, caip2ToEip155HexChainId } from '../../../utils/caip';\nimport { applyFeeUnitsBpsMargin, getEvmClientForChain, maybe1559 } from '../../_utils';\nimport type { EvmSourceClient } from '../../_utils';\nimport { buildErc20ApprovalRequest, signApprovalAndAssertConfirmed } from '../../_evm-approval';\nimport { estimateGasWithRevert } from '../../_evm-errors';\nimport type { WrappedSwapTransactionResponse } from '../_schema';\nimport { markrGetSpenderAddress, type ApiOptions } from '../_api';\nimport { getMarkrSwapWrapperAbi } from '../_utils';\nimport {\n markrListRecurringOrders,\n markrPrepareCancellation,\n markrPreparePause,\n markrPrepareUnpause,\n markrRecurringQuote,\n markrRecurringSwap,\n} from './_api';\nimport { checkRecurringEligibility } from './_eligibility';\nimport type {\n RecurringChainInfoMap,\n RecurringExecuteFirstFillParams,\n RecurringExecuteOrderActionParams,\n RecurringExecuteResult,\n RecurringNamespace,\n RecurringNamespaceQuoteParams,\n RecurringQuoteResponse,\n} from './types';\n\nexport interface CreateRecurringNamespaceOptions {\n apiOptions: ApiOptions;\n appId: string;\n evmSigner: EvmSigner;\n /**\n * The cached `/info/chains` recurring metadata. Captured by value at\n * namespace construction time — matches how `partnerFeeBps`,\n * `supportedChains`, and `supportedTokens` are also frozen at\n * `createMarkrService` init. If staleness ever becomes a real consumer\n * concern, the fix is a top-level `manager.refresh()` (not a per-namespace\n * lazy-read pattern).\n */\n recurringChainInfo: RecurringChainInfoMap;\n}\n\nexport function createRecurringNamespace({\n apiOptions,\n appId,\n evmSigner,\n recurringChainInfo,\n}: CreateRecurringNamespaceOptions): RecurringNamespace {\n return {\n quote: (props) => quoteImpl({ ...props, apiOptions, appId, recurringChainInfo }),\n\n executeFirstFill: (props) => executeFirstFillImpl({ ...props, apiOptions, appId, evmSigner, recurringChainInfo }),\n\n listOrders: (props) => markrListRecurringOrders(apiOptions, props),\n\n executeCancellation: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.CancelRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPrepareCancellation,\n }),\n\n executePause: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.PauseRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPreparePause,\n }),\n\n executeUnpause: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.ResumeRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPrepareUnpause,\n }),\n\n checkEligibility: (props) => checkRecurringEligibility({ ...props, recurringChainInfo }),\n\n getRecurringChainInfo: () => recurringChainInfo,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Quote — native input (`tokenIn === 0x0…`) is passed through to Markr\n// verbatim (the recurring API accepts the zero address as `tokenIn`). The\n// chain's wrapped-native address is read off the cached chain info (sourced\n// from `/info/chains[].wrapped_token`); the SDK only fails fast at this\n// boundary when Markr hasn't published one for the chain — we'd be issuing\n// a quote we couldn't honor.\n// ---------------------------------------------------------------------------\n\ninterface QuoteImplParams extends RecurringNamespaceQuoteParams {\n apiOptions: ApiOptions;\n appId: string;\n recurringChainInfo: RecurringChainInfoMap;\n}\n\nasync function quoteImpl({\n apiOptions,\n appId,\n recurringChainInfo,\n ...quoteParams\n}: QuoteImplParams): Promise<RecurringQuoteResponse> {\n const isNativeInput = isAddressEqual(quoteParams.tokenIn, ERC_ZERO_ADDRESS);\n\n if (isNativeInput && !recurringChainInfo.get(quoteParams.chainId)?.wrappedNativeAddress) {\n throw new InvalidParamsError(\n ErrorReason.CHAIN_NOT_SUPPORTED,\n `No wrapped-native ERC-20 address known for EVM chainId ${quoteParams.chainId}. ` +\n 'Native-input recurring swaps require Markr to publish `wrapped_token` for the chain in `/info/chains`.',\n );\n }\n\n return markrRecurringQuote(apiOptions, { ...quoteParams, appId });\n}\n\n// ---------------------------------------------------------------------------\n// First-fill execution (allowance check + approve-if-needed + first-fill swap)\n// ---------------------------------------------------------------------------\n\ninterface ExecuteFirstFillImplParams extends RecurringExecuteFirstFillParams {\n apiOptions: ApiOptions;\n appId: string;\n evmSigner: EvmSigner;\n recurringChainInfo: RecurringChainInfoMap;\n}\n\nasync function executeFirstFillImpl({\n apiOptions,\n appId,\n evmSigner,\n fallbackToDefaultOnBatchFailure,\n fromAddress,\n gasSettings,\n quote,\n recurringChainInfo,\n signerContext,\n sourceChain,\n}: ExecuteFirstFillImplParams): Promise<RecurringExecuteResult> {\n // Mirror the one-shot guard at `TransferManager.estimateNativeFee` — fail at\n // the SDK boundary with `QUOTE_EXPIRED` instead of an opaque `HttpError`\n // from `/recurring/swap` for a slow-to-approve user.\n const now = Math.floor(Date.now() / 1_000);\n if (quote.expiredAt <= now) {\n const expiredSecondsAgo = now - quote.expiredAt;\n throw new InvalidParamsError(\n ErrorReason.QUOTE_EXPIRED,\n `Recurring quote expired ${expiredSecondsAgo} seconds ago.`,\n );\n }\n\n // Wiring-mistake guard: the passed `sourceChain.chainId` (CAIP-2) must agree\n // with the `chainId` (numeric) the quote was issued against. Otherwise the\n // allowance / gas reads hit the wrong chain.\n const sourceChainIdNumeric = caip2ToEip155ChainId(sourceChain.chainId);\n if (sourceChainIdNumeric !== quote.chainId) {\n throw new InvalidParamsError(\n 'sourceChain does not match quote.chainId',\n `sourceChain.chainId=${sourceChain.chainId} resolves to ${sourceChainIdNumeric}, but quote.chainId=${quote.chainId}.`,\n );\n }\n\n const sourceClient = getEvmClientForChain({ chain: sourceChain });\n const chainIdHex = caip2ToEip155HexChainId(sourceChain.chainId);\n\n const isNativeInput = isAddressEqual(quote.tokenIn, ERC_ZERO_ADDRESS);\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: quote.chainId,\n crossChainSwap: false,\n quoteId: quote.uuid,\n });\n\n if (!spenderAddress) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Missing Markr spender address for source chain ${sourceChain.chainId}.`,\n });\n }\n\n // Fetch the ordered transaction array from Markr's `/recurring/swap`:\n // - ERC-20 `tokenIn`: `[createOrder]` (1 element).\n // - Native `tokenIn` (`0x0…`): `[wrap, createOrder]` (2 elements).\n // The wrap's `to` is the wrapped-native ERC-20 we'll then approve against\n // (Markr does not return an approval entry — the SDK inserts that step).\n const recurringSwapTxs = await markrRecurringSwap(apiOptions, { uuid: quote.uuid, appId });\n\n const wrapTx = recurringSwapTxs.find((tx) => tx.type === 'wrap');\n const createOrderTx = recurringSwapTxs.find((tx) => tx.type === 'createOrder');\n\n if (!createOrderTx) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `Missing createOrder step (quote uuid: ${quote.uuid}).`,\n });\n }\n\n // Cross-check: native input must come back with a wrap leg, and an ERC-20\n // input must not. If Markr disagrees with the cached quote's `tokenIn`,\n // bail rather than silently signing a mismatched flow (e.g. broadcasting\n // a wrap when the user thought they were spending ERC-20, or skipping a\n // wrap when the user expected to fund the schedule with native).\n if (isNativeInput && !wrapTx) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `Native-input quote returned no wrap step (quote uuid: ${quote.uuid}).`,\n });\n }\n if (!isNativeInput && wrapTx) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `ERC-20 input quote returned a wrap step (quote uuid: ${quote.uuid}, tokenIn: ${quote.tokenIn}).`,\n });\n }\n\n // Defense-in-depth on the wrap leg before we hand it to the wallet:\n // - `wrap.value` must equal `quote.totalAmountIn` — that's what funds the\n // full schedule; a smaller value would under-fund subsequent fills, a\n // larger one would silently overcharge the user.\n // - `wrap.to` must match the chain's published wrapped-native (from\n // `/info/chains[].wrapped_token`) when one is known. Cross-check guards\n // against a misrouted approval — we're about to grant `totalAmountIn`\n // allowance to whatever `wrap.to` points at. When the chain entry has\n // no published wrapped-native, defer to Markr (`wrap.to` is server-\n // authoritative); the quote boundary already failed-closed in that\n // case anyway, so this is purely belt-and-suspenders.\n if (wrapTx) {\n if (wrapTx.value !== quote.totalAmountIn) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `Wrap step value ${wrapTx.value} does not match quote.totalAmountIn ${quote.totalAmountIn} (quote uuid: ${quote.uuid}).`,\n });\n }\n const expectedWrappedNative = recurringChainInfo.get(quote.chainId)?.wrappedNativeAddress;\n if (expectedWrappedNative && !isAddressEqual(wrapTx.to, expectedWrappedNative)) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `Wrap step target ${wrapTx.to} does not match the published wrapped-native ${expectedWrappedNative} for chainId ${quote.chainId} (quote uuid: ${quote.uuid}).`,\n });\n }\n }\n\n // Approval target: for native input, the wrapped-native ERC-20 returned\n // by Markr in `wrap.to` (cross-checked above). For ERC-20 input, the\n // quote's `tokenIn`. Either way the spender is the RecurringSwaps router.\n const approvalTokenAddress = wrapTx?.to ?? quote.tokenIn;\n\n const approvalRequest = await buildErc20ApprovalRequest({\n chainIdHex,\n client: sourceClient,\n gasSettings,\n owner: fromAddress,\n requiredAllowance: quote.totalAmountIn,\n spender: spenderAddress,\n token: approvalTokenAddress,\n });\n\n // Wrap leg comes straight from Markr — `wrap.to` is the chain wrapped-native\n // contract, `data` is `deposit()`, `value` is `totalAmountIn`. Gas is left\n // undefined: when batched the wallet handles atomic estimation; sequentially\n // the wrap is the first call so the wallet's own estimation fires the prompt.\n const wrapRequest: EvmTransactionRequest | undefined = wrapTx\n ? {\n chainId: chainIdHex,\n data: wrapTx.data,\n from: fromAddress,\n gas: undefined,\n to: wrapTx.to,\n value: wrapTx.value,\n ...maybe1559(gasSettings),\n }\n : undefined;\n\n const syntheticQuote = buildSyntheticQuoteForFirstFill({ fromAddress, quote, sourceChain });\n\n // One-click batch path: same-chain DCA, signer exposes `signBatch`, and at\n // least one leg precedes the swap (otherwise there's nothing to batch — we\n // sign the swap solo). The batch shape adapts to the recurring setup:\n // - native + needs approval: [wrap, approve, swap] (3 elements)\n // - native + allowance covers: [wrap, swap] (2 elements)\n // - ERC-20 + needs approval: [approve, swap] (2 elements)\n // - ERC-20 + allowance covers: swap solo (no batch)\n const batchPreSwap: EvmTransactionRequest[] = [];\n if (wrapRequest) batchPreSwap.push(wrapRequest);\n if (approvalRequest) batchPreSwap.push(approvalRequest);\n\n if (batchPreSwap.length > 0 && typeof evmSigner.signBatch === 'function') {\n const batchStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.ScheduleRecurringSwap,\n quote: syntheticQuote,\n requiredSignatures: 1,\n signerContext,\n };\n\n // Gas is left undefined on the swap leg — the wallet handles batched gas\n // estimation since the preceding leg(s) haven't executed yet.\n const swapRequest: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: createOrderTx.data,\n from: fromAddress,\n gas: undefined,\n to: createOrderTx.to,\n value: createOrderTx.value,\n ...maybe1559(gasSettings),\n };\n\n try {\n const txHashes = await evmSigner.signBatch(\n [...batchPreSwap, swapRequest],\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n batchStep,\n );\n const swapTxHash = txHashes.at(-1);\n if (!swapTxHash) {\n throw new SdkError('One-click batch signing returned no transaction hashes.', ErrorCode.SIGNING_FAILED);\n }\n return { txHash: swapTxHash };\n } catch (error) {\n if (!fallbackToDefaultOnBatchFailure) {\n throw error;\n }\n // Fall through to the sequential path below.\n }\n }\n\n // Sequential path — sign each preceding leg, await its receipt, then sign\n // the swap. Signature counters reflect the actual prompt count the user\n // will see (1 + wrap? + approval?).\n const requiredSignatures = 1 + batchPreSwap.length;\n let signatureCursor = 0;\n\n if (wrapRequest && wrapTx) {\n // Estimate gas for the wrap leg on the sequential path. On the batch\n // path we leave gas undefined and let the wallet do atomic estimation;\n // sequentially the wrap is a real first-tx prompt so it gets the same\n // treatment as the approval and swap legs (estimate + bps margin) for\n // wallets that don't auto-estimate. Read `to`/`data` off `wrapTx` (the\n // narrow `RecurringSwapTransaction` shape) rather than the wider\n // `EvmTransactionRequest` so the args are non-nullable.\n const wrapGasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: fromAddress, to: wrapTx.to, data: wrapTx.data, value: wrapTx.value },\n // No router ABI to decode against — wrap is a plain\n // `WAVAX.deposit{value}()`; built-in `Error(string)` / `Panic(uint256)`\n // are still decoded regardless of the ABI argument.\n [],\n 'Failed to estimate gas for recurring first-fill wrap transaction.',\n );\n const wrapRequestWithGas: EvmTransactionRequest = {\n ...wrapRequest,\n gas: applyFeeUnitsBpsMargin(wrapGasEstimate, gasSettings?.estimateGasMarginBps),\n };\n\n signatureCursor += 1;\n await signWrapAndAssertConfirmed({\n client: sourceClient,\n evmSigner,\n request: wrapRequestWithGas,\n step: {\n currentSignature: signatureCursor,\n currentSignatureReason: TransferSignatureReason.WrapToken,\n quote: syntheticQuote,\n requiredSignatures,\n signerContext,\n },\n });\n }\n\n if (approvalRequest) {\n signatureCursor += 1;\n await signApprovalAndAssertConfirmed({\n client: sourceClient,\n evmSigner,\n request: approvalRequest,\n step: {\n currentSignature: signatureCursor,\n currentSignatureReason: TransferSignatureReason.AllowanceApproval,\n quote: syntheticQuote,\n requiredSignatures,\n signerContext,\n },\n });\n }\n\n // Use the Markr same-chain swap wrapper ABI for best-effort revert decoding\n // — matches `_estimateGasFromSwapResponse` in `estimate-native-fee.ts`.\n // Recurring is always same-chain, so `crossChain: false`. Built-in\n // `Error(string)` / `Panic(uint256)` are decoded regardless of ABI.\n const markrAbi = await getMarkrSwapWrapperAbi(false);\n const swapGasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: fromAddress, to: createOrderTx.to, data: createOrderTx.data, value: createOrderTx.value },\n markrAbi,\n 'Failed to estimate gas for recurring first-fill swap transaction.',\n );\n\n const swapRequest: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: createOrderTx.data,\n from: fromAddress,\n gas: applyFeeUnitsBpsMargin(swapGasEstimate, gasSettings?.estimateGasMarginBps),\n to: createOrderTx.to,\n value: createOrderTx.value,\n ...maybe1559(gasSettings),\n };\n\n signatureCursor += 1;\n const swapStep: TransferStepDetails = {\n currentSignature: signatureCursor,\n currentSignatureReason: TransferSignatureReason.ScheduleRecurringSwap,\n quote: syntheticQuote,\n requiredSignatures,\n signerContext,\n };\n\n const txHash = await evmSigner.sign(\n swapRequest,\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n swapStep,\n );\n\n return { txHash };\n}\n\n/**\n * Signs a `WAVAX.deposit{value}()` wrap request, dispatches it, and waits for\n * the receipt. Mirrors {@link signApprovalAndAssertConfirmed} so the\n * sequential native path fails loudly if the wrap reverts on-chain (without\n * which the downstream approve would silently fail for \"insufficient WAVAX\").\n */\nasync function signWrapAndAssertConfirmed({\n client,\n evmSigner,\n request,\n step,\n}: {\n client: EvmSourceClient;\n evmSigner: EvmSigner;\n request: EvmTransactionRequest;\n step: TransferStepDetails;\n}): Promise<Hex> {\n const wrapTxHash = await evmSigner.sign(\n request,\n (signedTxHash) => client.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n const receipt = await client.waitForTransactionReceipt({ hash: wrapTxHash });\n\n if (receipt.status === 'reverted') {\n throw new SdkError(ErrorReason.NATIVE_WRAP_REVERTED, ErrorCode.TRANSACTION_REVERTED, {\n details: `Wrap tx reverted on-chain (tx hash: ${wrapTxHash}).`,\n });\n }\n\n return wrapTxHash;\n}\n\n// ---------------------------------------------------------------------------\n// Order-action execution (cancel / pause / unpause — single-tx state change)\n// ---------------------------------------------------------------------------\n\ninterface ExecuteOrderActionImplParams extends RecurringExecuteOrderActionParams {\n signatureReason:\n | TransferSignatureReason.PauseRecurringSwap\n | TransferSignatureReason.ResumeRecurringSwap\n | TransferSignatureReason.CancelRecurringSwap;\n apiOptions: ApiOptions;\n evmSigner: EvmSigner;\n fetchCalldata: (\n apiOptions: ApiOptions,\n params: { orderId: `0x${string}`; address: `0x${string}`; chainId: number },\n ) => Promise<WrappedSwapTransactionResponse>;\n}\n\n// Short verbs for error-message interpolation — avoids the doubled-\"recurring\"\n// + kebab-case-in-prose readout you'd get from interpolating the raw enum\n// wire value (e.g. `recurring pause-recurring-swap transaction`).\nconst ORDER_ACTION_LABEL: Record<ExecuteOrderActionImplParams['signatureReason'], string> = {\n [TransferSignatureReason.PauseRecurringSwap]: 'pause',\n [TransferSignatureReason.ResumeRecurringSwap]: 'resume',\n [TransferSignatureReason.CancelRecurringSwap]: 'cancel',\n};\n\nasync function executeOrderActionImpl({\n signatureReason,\n address,\n apiOptions,\n evmSigner,\n fetchCalldata,\n gasSettings,\n orderId,\n signerContext,\n sourceChain,\n}: ExecuteOrderActionImplParams): Promise<RecurringExecuteResult> {\n const sourceClient = getEvmClientForChain({ chain: sourceChain });\n const chainIdNumeric = caip2ToEip155ChainId(sourceChain.chainId);\n const chainIdHex = caip2ToEip155HexChainId(sourceChain.chainId);\n\n const calldata = await fetchCalldata(apiOptions, { orderId, address, chainId: chainIdNumeric });\n\n const gasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: address, to: calldata.to, data: calldata.data, value: calldata.value },\n erc20Abi,\n `Failed to estimate gas for recurring ${ORDER_ACTION_LABEL[signatureReason]} transaction.`,\n );\n\n const request: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: calldata.data,\n from: address,\n gas: applyFeeUnitsBpsMargin(gasEstimate, gasSettings?.estimateGasMarginBps),\n to: calldata.to,\n value: calldata.value,\n ...maybe1559(gasSettings),\n };\n\n const step: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: signatureReason,\n quote: buildSyntheticQuoteForOrderAction({ address, signatureReason, orderId, sourceChain }),\n requiredSignatures: 1,\n signerContext,\n };\n\n const txHash = await evmSigner.sign(\n request,\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n return { txHash };\n}\n\n// ---------------------------------------------------------------------------\n// Internal: synthetic Quote objects for `TransferStepDetails.quote`\n// ---------------------------------------------------------------------------\n\n/**\n * Builds a minimum-viable {@link Quote} for the signer step so consumer\n * `EvmSigner` impls can render meaningful wallet prompts for a recurring\n * action (which has no real `Quote` in the swap-quoter sense). The synthetic\n * value carries enough recurring context (uuid, chain, amounts, tokens) for\n * a wallet UI to label the popup; the `aggregator.id` (`'markr-recurring'`)\n * lets advanced signers detect the recurring path explicitly.\n *\n * Asset fields use placeholder `name`/`symbol`/`decimals` because the\n * recurring quote doesn't echo those — consumers needing rich asset display\n * should resolve token metadata against their own asset map keyed by\n * `quote.tokenIn`/`tokenOut`.\n */\nfunction buildSyntheticQuoteForFirstFill({\n fromAddress,\n quote,\n sourceChain,\n}: {\n fromAddress: `0x${string}`;\n quote: RecurringQuoteResponse;\n sourceChain: Chain;\n}): Quote {\n return {\n // Keep the stable `'markr-recurring'` marker (shipped in #240) — consumer\n // signers may detect the recurring path via `quote.aggregator.id`. The\n // typed `TransferStepDetails.currentSignatureReason` is now the preferred\n // discriminant for new integrations, but this id stays for back-compat.\n aggregator: { id: 'markr-recurring', name: 'Markr recurring' },\n amountIn: quote.amount,\n amountOut: quote.amountOut,\n assetIn: { type: TokenType.ERC20, address: quote.tokenIn, name: '', symbol: '', decimals: 0 },\n assetOut: { type: TokenType.ERC20, address: quote.tokenOut, name: '', symbol: '', decimals: 0 },\n expiresAt: quote.expiredAt,\n fees: [],\n fromAddress,\n id: quote.uuid,\n partnerFeeBps: null,\n serviceType: ServiceType.MARKR,\n slippageBps: quote.recommendedSlippage,\n // Pass the caller-provided `Chain` straight through — recurring is always\n // same-chain, so source === target. Avoids stripping `chainName` /\n // `networkToken` / `rpcUrl` that consumer signers may use for display.\n sourceChain,\n targetChain: sourceChain,\n toAddress: fromAddress,\n };\n}\n\nfunction buildSyntheticQuoteForOrderAction({\n signatureReason,\n address,\n orderId,\n sourceChain,\n}: {\n signatureReason:\n | TransferSignatureReason.PauseRecurringSwap\n | TransferSignatureReason.ResumeRecurringSwap\n | TransferSignatureReason.CancelRecurringSwap;\n address: `0x${string}`;\n orderId: `0x${string}`;\n sourceChain: Chain;\n}): Quote {\n const action = ORDER_ACTION_LABEL[signatureReason];\n return {\n // Same back-compat rationale as `buildSyntheticQuoteForFirstFill` — preserve\n // the original lowercase `markr-recurring-${action}` id shape (shipped in\n // #240) so consumers keying off `quote.aggregator.id` keep working.\n aggregator: {\n id: `markr-recurring-${action}`,\n name: `Markr recurring (${action})`,\n },\n amountIn: 0n,\n amountOut: 0n,\n assetIn: emptyNativeAsset(),\n assetOut: emptyNativeAsset(),\n expiresAt: 0,\n fees: [],\n fromAddress: address,\n id: orderId,\n partnerFeeBps: null,\n serviceType: ServiceType.MARKR,\n slippageBps: 0,\n // See `buildSyntheticQuoteForFirstFill` — pass the real `Chain` through.\n sourceChain,\n targetChain: sourceChain,\n toAddress: address,\n };\n}\n\nfunction emptyNativeAsset() {\n return { type: TokenType.NATIVE, name: '', symbol: '', decimals: 0 } as const;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{ServiceType as e,TokenType as t,TransferSignatureReason as n}from"../../../constants.js";import{ErrorCode as r,ErrorReason as i,InvalidParamsError as a,SdkError as o}from"../../../errors.js";import{caip2ToEip155ChainId as s,caip2ToEip155HexChainId as c}from"../../../utils/caip.js";import{applyFeeUnitsBpsMargin as l,getEvmClientForChain as u,maybe1559 as d}from"../../_utils.js";import{estimateGasWithRevert as f}from"../../_evm-errors.js";import{buildErc20ApprovalRequest as p,signApprovalAndAssertConfirmed as m}from"../../_evm-approval.js";import{markrGetSpenderAddress as h}from"../_api.js";import{getMarkrSwapWrapperAbi as g}from"../_utils.js";import{markrListRecurringOrders as _,markrPrepareCancellation as v,markrPreparePause as y,markrPrepareUnpause as b,markrRecurringQuote as x,markrRecurringSwap as S}from"./_api.js";import{checkRecurringEligibility as C}from"./_eligibility.js";import{erc20Abi as w}from"viem";function T({apiOptions:e,appId:t,evmSigner:r,recurringChainInfo:i}){return{quote:n=>x(e,{...n,appId:t}),executeFirstFill:n=>E({...n,apiOptions:e,appId:t,evmSigner:r}),listOrders:t=>_(e,t),executeCancellation:t=>O({...t,signatureReason:n.CancelRecurringSwap,apiOptions:e,evmSigner:r,fetchCalldata:v}),executePause:t=>O({...t,signatureReason:n.PauseRecurringSwap,apiOptions:e,evmSigner:r,fetchCalldata:y}),executeUnpause:t=>O({...t,signatureReason:n.ResumeRecurringSwap,apiOptions:e,evmSigner:r,fetchCalldata:b}),checkEligibility:e=>C({...e,recurringChainInfo:i}),getRecurringChainInfo:()=>i}}async function E({apiOptions:e,appId:t,evmSigner:_,fallbackToDefaultOnBatchFailure:v,fromAddress:y,gasSettings:b,quote:x,signerContext:C,sourceChain:w}){let T=Math.floor(Date.now()/1e3);if(x.expiredAt<=T){let e=T-x.expiredAt;throw new a(i.QUOTE_EXPIRED,`Recurring quote expired ${e} seconds ago.`)}let E=s(w.chainId);if(E!==x.chainId)throw new a(`sourceChain does not match quote.chainId`,`sourceChain.chainId=${w.chainId} resolves to ${E}, but quote.chainId=${x.chainId}.`);let D=u({chain:w}),O=c(w.chainId),{address:A}=await h(e,{chainId:x.chainId,crossChainSwap:!1,quoteId:x.uuid});if(!A)throw new o(i.CHAIN_NOT_SUPPORTED,r.INVALID_PARAMS,{details:`Missing Markr spender address for source chain ${w.chainId}.`});let j=await p({chainIdHex:O,client:D,gasSettings:b,owner:y,requiredAllowance:x.totalAmountIn,spender:A,token:x.tokenIn}),M=k({fromAddress:y,quote:x,sourceChain:w}),N=await S(e,{uuid:x.uuid,appId:t});if(j!==void 0&&typeof _.signBatch==`function`){let e={currentSignature:1,currentSignatureReason:n.ScheduleRecurringSwap,quote:M,requiredSignatures:1,signerContext:C},t={chainId:O,data:N.data,from:y,gas:void 0,to:N.to,value:N.value,...d(b)};try{let n=(await _.signBatch([j,t],e=>D.sendRawTransaction({serializedTransaction:e}),e)).at(-1);if(!n)throw new o(`One-click batch signing returned no transaction hashes.`,r.SIGNING_FAILED);return{txHash:n}}catch(e){if(!v)throw e}}j&&await m({client:D,evmSigner:_,request:j,step:{currentSignature:1,currentSignatureReason:n.AllowanceApproval,quote:M,requiredSignatures:2,signerContext:C}});let P=await g(!1),F=await f(D,{account:y,to:N.to,data:N.data,value:N.value},P,`Failed to estimate gas for recurring first-fill swap transaction.`),I={chainId:O,data:N.data,from:y,gas:l(F,b?.estimateGasMarginBps),to:N.to,value:N.value,...d(b)},L={currentSignature:j?2:1,currentSignatureReason:n.ScheduleRecurringSwap,quote:M,requiredSignatures:j?2:1,signerContext:C};return{txHash:await _.sign(I,e=>D.sendRawTransaction({serializedTransaction:e}),L)}}const D={[n.PauseRecurringSwap]:`pause`,[n.ResumeRecurringSwap]:`resume`,[n.CancelRecurringSwap]:`cancel`};async function O({signatureReason:e,address:t,apiOptions:n,evmSigner:r,fetchCalldata:i,gasSettings:a,orderId:o,signerContext:p,sourceChain:m}){let h=u({chain:m}),g=s(m.chainId),_=c(m.chainId),v=await i(n,{orderId:o,address:t,chainId:g}),y=await f(h,{account:t,to:v.to,data:v.data,value:v.value},w,`Failed to estimate gas for recurring ${D[e]} transaction.`),b={chainId:_,data:v.data,from:t,gas:l(y,a?.estimateGasMarginBps),to:v.to,value:v.value,...d(a)},x={currentSignature:1,currentSignatureReason:e,quote:A({address:t,signatureReason:e,orderId:o,sourceChain:m}),requiredSignatures:1,signerContext:p};return{txHash:await r.sign(b,e=>h.sendRawTransaction({serializedTransaction:e}),x)}}function k({fromAddress:n,quote:r,sourceChain:i}){return{aggregator:{id:`markr-recurring`,name:`Markr recurring`},amountIn:r.amount,amountOut:r.amountOut,assetIn:{type:t.ERC20,address:r.tokenIn,name:``,symbol:``,decimals:0},assetOut:{type:t.ERC20,address:r.tokenOut,name:``,symbol:``,decimals:0},expiresAt:r.expiredAt,fees:[],fromAddress:n,id:r.uuid,partnerFeeBps:null,serviceType:e.MARKR,slippageBps:r.recommendedSlippage,sourceChain:i,targetChain:i,toAddress:n}}function A({signatureReason:t,address:n,orderId:r,sourceChain:i}){let a=D[t];return{aggregator:{id:`markr-recurring-${a}`,name:`Markr recurring (${a})`},amountIn:0n,amountOut:0n,assetIn:j(),assetOut:j(),expiresAt:0,fees:[],fromAddress:n,id:r,partnerFeeBps:null,serviceType:e.MARKR,slippageBps:0,sourceChain:i,targetChain:i,toAddress:n}}function j(){return{type:t.NATIVE,name:``,symbol:``,decimals:0}}export{T as createRecurringNamespace};
1
+ import{ERC_ZERO_ADDRESS as e,ServiceType as t,TokenType as n,TransferSignatureReason as r}from"../../../constants.js";import{ErrorCode as i,ErrorReason as a,InvalidParamsError as o,SdkError as s}from"../../../errors.js";import{caip2ToEip155ChainId as c,caip2ToEip155HexChainId as l}from"../../../utils/caip.js";import{applyFeeUnitsBpsMargin as u,getEvmClientForChain as d,maybe1559 as f}from"../../_utils.js";import{estimateGasWithRevert as p}from"../../_evm-errors.js";import{buildErc20ApprovalRequest as m,signApprovalAndAssertConfirmed as h}from"../../_evm-approval.js";import{markrGetSpenderAddress as g}from"../_api.js";import{getMarkrSwapWrapperAbi as _}from"../_utils.js";import{markrListRecurringOrders as v,markrPrepareCancellation as y,markrPreparePause as b,markrPrepareUnpause as x,markrRecurringQuote as S,markrRecurringSwap as C}from"./_api.js";import{checkRecurringEligibility as w}from"./_eligibility.js";import{erc20Abi as T,isAddressEqual as E}from"viem";function D({apiOptions:e,appId:t,evmSigner:n,recurringChainInfo:i}){return{quote:n=>O({...n,apiOptions:e,appId:t,recurringChainInfo:i}),executeFirstFill:r=>k({...r,apiOptions:e,appId:t,evmSigner:n,recurringChainInfo:i}),listOrders:t=>v(e,t),executeCancellation:t=>M({...t,signatureReason:r.CancelRecurringSwap,apiOptions:e,evmSigner:n,fetchCalldata:y}),executePause:t=>M({...t,signatureReason:r.PauseRecurringSwap,apiOptions:e,evmSigner:n,fetchCalldata:b}),executeUnpause:t=>M({...t,signatureReason:r.ResumeRecurringSwap,apiOptions:e,evmSigner:n,fetchCalldata:x}),checkEligibility:e=>w({...e,recurringChainInfo:i}),getRecurringChainInfo:()=>i}}async function O({apiOptions:e,appId:t,recurringChainInfo:n,...r}){if(E(r.tokenIn,`0x0000000000000000000000000000000000000000`)&&!n.get(r.chainId)?.wrappedNativeAddress)throw new o(a.CHAIN_NOT_SUPPORTED,`No wrapped-native ERC-20 address known for EVM chainId ${r.chainId}. Native-input recurring swaps require Markr to publish \`wrapped_token\` for the chain in \`/info/chains\`.`);return S(e,{...r,appId:t})}async function k({apiOptions:t,appId:n,evmSigner:v,fallbackToDefaultOnBatchFailure:y,fromAddress:b,gasSettings:x,quote:S,recurringChainInfo:w,signerContext:T,sourceChain:D}){let O=Math.floor(Date.now()/1e3);if(S.expiredAt<=O){let e=O-S.expiredAt;throw new o(a.QUOTE_EXPIRED,`Recurring quote expired ${e} seconds ago.`)}let k=c(D.chainId);if(k!==S.chainId)throw new o(`sourceChain does not match quote.chainId`,`sourceChain.chainId=${D.chainId} resolves to ${k}, but quote.chainId=${S.chainId}.`);let j=d({chain:D}),M=l(D.chainId),P=E(S.tokenIn,e),{address:F}=await g(t,{chainId:S.chainId,crossChainSwap:!1,quoteId:S.uuid});if(!F)throw new s(a.CHAIN_NOT_SUPPORTED,i.INVALID_PARAMS,{details:`Missing Markr spender address for source chain ${D.chainId}.`});let I=await C(t,{uuid:S.uuid,appId:n}),L=I.find(e=>e.type===`wrap`),R=I.find(e=>e.type===`createOrder`);if(!R)throw new s(a.RECURRING_SWAP_RESPONSE_INCONSISTENT,i.INVALID_PARAMS,{details:`Missing createOrder step (quote uuid: ${S.uuid}).`});if(P&&!L)throw new s(a.RECURRING_SWAP_RESPONSE_INCONSISTENT,i.INVALID_PARAMS,{details:`Native-input quote returned no wrap step (quote uuid: ${S.uuid}).`});if(!P&&L)throw new s(a.RECURRING_SWAP_RESPONSE_INCONSISTENT,i.INVALID_PARAMS,{details:`ERC-20 input quote returned a wrap step (quote uuid: ${S.uuid}, tokenIn: ${S.tokenIn}).`});if(L){if(L.value!==S.totalAmountIn)throw new s(a.RECURRING_SWAP_RESPONSE_INCONSISTENT,i.INVALID_PARAMS,{details:`Wrap step value ${L.value} does not match quote.totalAmountIn ${S.totalAmountIn} (quote uuid: ${S.uuid}).`});let e=w.get(S.chainId)?.wrappedNativeAddress;if(e&&!E(L.to,e))throw new s(a.RECURRING_SWAP_RESPONSE_INCONSISTENT,i.INVALID_PARAMS,{details:`Wrap step target ${L.to} does not match the published wrapped-native ${e} for chainId ${S.chainId} (quote uuid: ${S.uuid}).`})}let z=L?.to??S.tokenIn,B=await m({chainIdHex:M,client:j,gasSettings:x,owner:b,requiredAllowance:S.totalAmountIn,spender:F,token:z}),V=L?{chainId:M,data:L.data,from:b,gas:void 0,to:L.to,value:L.value,...f(x)}:void 0,H=N({fromAddress:b,quote:S,sourceChain:D}),U=[];if(V&&U.push(V),B&&U.push(B),U.length>0&&typeof v.signBatch==`function`){let e={currentSignature:1,currentSignatureReason:r.ScheduleRecurringSwap,quote:H,requiredSignatures:1,signerContext:T},t={chainId:M,data:R.data,from:b,gas:void 0,to:R.to,value:R.value,...f(x)};try{let n=(await v.signBatch([...U,t],e=>j.sendRawTransaction({serializedTransaction:e}),e)).at(-1);if(!n)throw new s(`One-click batch signing returned no transaction hashes.`,i.SIGNING_FAILED);return{txHash:n}}catch(e){if(!y)throw e}}let W=1+U.length,G=0;if(V&&L){let e=await p(j,{account:b,to:L.to,data:L.data,value:L.value},[],`Failed to estimate gas for recurring first-fill wrap transaction.`),t={...V,gas:u(e,x?.estimateGasMarginBps)};G+=1,await A({client:j,evmSigner:v,request:t,step:{currentSignature:G,currentSignatureReason:r.WrapToken,quote:H,requiredSignatures:W,signerContext:T}})}B&&(G+=1,await h({client:j,evmSigner:v,request:B,step:{currentSignature:G,currentSignatureReason:r.AllowanceApproval,quote:H,requiredSignatures:W,signerContext:T}}));let K=await _(!1),q=await p(j,{account:b,to:R.to,data:R.data,value:R.value},K,`Failed to estimate gas for recurring first-fill swap transaction.`),J={chainId:M,data:R.data,from:b,gas:u(q,x?.estimateGasMarginBps),to:R.to,value:R.value,...f(x)};G+=1;let Y={currentSignature:G,currentSignatureReason:r.ScheduleRecurringSwap,quote:H,requiredSignatures:W,signerContext:T};return{txHash:await v.sign(J,e=>j.sendRawTransaction({serializedTransaction:e}),Y)}}async function A({client:e,evmSigner:t,request:n,step:r}){let o=await t.sign(n,t=>e.sendRawTransaction({serializedTransaction:t}),r);if((await e.waitForTransactionReceipt({hash:o})).status===`reverted`)throw new s(a.NATIVE_WRAP_REVERTED,i.TRANSACTION_REVERTED,{details:`Wrap tx reverted on-chain (tx hash: ${o}).`});return o}const j={[r.PauseRecurringSwap]:`pause`,[r.ResumeRecurringSwap]:`resume`,[r.CancelRecurringSwap]:`cancel`};async function M({signatureReason:e,address:t,apiOptions:n,evmSigner:r,fetchCalldata:i,gasSettings:a,orderId:o,signerContext:s,sourceChain:m}){let h=d({chain:m}),g=c(m.chainId),_=l(m.chainId),v=await i(n,{orderId:o,address:t,chainId:g}),y=await p(h,{account:t,to:v.to,data:v.data,value:v.value},T,`Failed to estimate gas for recurring ${j[e]} transaction.`),b={chainId:_,data:v.data,from:t,gas:u(y,a?.estimateGasMarginBps),to:v.to,value:v.value,...f(a)},x={currentSignature:1,currentSignatureReason:e,quote:P({address:t,signatureReason:e,orderId:o,sourceChain:m}),requiredSignatures:1,signerContext:s};return{txHash:await r.sign(b,e=>h.sendRawTransaction({serializedTransaction:e}),x)}}function N({fromAddress:e,quote:r,sourceChain:i}){return{aggregator:{id:`markr-recurring`,name:`Markr recurring`},amountIn:r.amount,amountOut:r.amountOut,assetIn:{type:n.ERC20,address:r.tokenIn,name:``,symbol:``,decimals:0},assetOut:{type:n.ERC20,address:r.tokenOut,name:``,symbol:``,decimals:0},expiresAt:r.expiredAt,fees:[],fromAddress:e,id:r.uuid,partnerFeeBps:null,serviceType:t.MARKR,slippageBps:r.recommendedSlippage,sourceChain:i,targetChain:i,toAddress:e}}function P({signatureReason:e,address:n,orderId:r,sourceChain:i}){let a=j[e];return{aggregator:{id:`markr-recurring-${a}`,name:`Markr recurring (${a})`},amountIn:0n,amountOut:0n,assetIn:F(),assetOut:F(),expiresAt:0,fees:[],fromAddress:n,id:r,partnerFeeBps:null,serviceType:t.MARKR,slippageBps:0,sourceChain:i,targetChain:i,toAddress:n}}function F(){return{type:n.NATIVE,name:``,symbol:``,decimals:0}}export{D as createRecurringNamespace};
2
2
  //# sourceMappingURL=_namespace.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_namespace.js","names":[],"sources":["../../../../src/transfer-service/markr/recurring/_namespace.ts"],"sourcesContent":["import { erc20Abi } from 'viem';\nimport { ServiceType, TokenType, TransferSignatureReason } from '../../../constants';\nimport { ErrorCode, ErrorReason, InvalidParamsError, SdkError } from '../../../errors';\nimport type { Chain } from '../../../types/chain';\nimport type { Quote } from '../../../types/quote';\nimport type { EvmSigner, EvmTransactionRequest } from '../../../types/signer';\nimport type { TransferStepDetails } from '../../../types/transfer';\nimport { caip2ToEip155ChainId, caip2ToEip155HexChainId } from '../../../utils/caip';\nimport { applyFeeUnitsBpsMargin, getEvmClientForChain, maybe1559 } from '../../_utils';\nimport { buildErc20ApprovalRequest, signApprovalAndAssertConfirmed } from '../../_evm-approval';\nimport { estimateGasWithRevert } from '../../_evm-errors';\nimport type { WrappedSwapTransactionResponse } from '../_schema';\nimport { markrGetSpenderAddress, type ApiOptions } from '../_api';\nimport { getMarkrSwapWrapperAbi } from '../_utils';\nimport {\n markrListRecurringOrders,\n markrPrepareCancellation,\n markrPreparePause,\n markrPrepareUnpause,\n markrRecurringQuote,\n markrRecurringSwap,\n} from './_api';\nimport { checkRecurringEligibility } from './_eligibility';\nimport type {\n RecurringChainInfoMap,\n RecurringExecuteFirstFillParams,\n RecurringExecuteOrderActionParams,\n RecurringExecuteResult,\n RecurringNamespace,\n RecurringQuoteResponse,\n} from './types';\n\nexport interface CreateRecurringNamespaceOptions {\n apiOptions: ApiOptions;\n appId: string;\n evmSigner: EvmSigner;\n /**\n * The cached `/info/chains` recurring metadata. Captured by value at\n * namespace construction time — matches how `partnerFeeBps`,\n * `supportedChains`, and `supportedTokens` are also frozen at\n * `createMarkrService` init. If staleness ever becomes a real consumer\n * concern, the fix is a top-level `manager.refresh()` (not a per-namespace\n * lazy-read pattern).\n */\n recurringChainInfo: RecurringChainInfoMap;\n}\n\nexport function createRecurringNamespace({\n apiOptions,\n appId,\n evmSigner,\n recurringChainInfo,\n}: CreateRecurringNamespaceOptions): RecurringNamespace {\n return {\n quote: (props) => markrRecurringQuote(apiOptions, { ...props, appId }),\n\n executeFirstFill: (props) => executeFirstFillImpl({ ...props, apiOptions, appId, evmSigner }),\n\n listOrders: (props) => markrListRecurringOrders(apiOptions, props),\n\n executeCancellation: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.CancelRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPrepareCancellation,\n }),\n\n executePause: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.PauseRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPreparePause,\n }),\n\n executeUnpause: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.ResumeRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPrepareUnpause,\n }),\n\n checkEligibility: (props) => checkRecurringEligibility({ ...props, recurringChainInfo }),\n\n getRecurringChainInfo: () => recurringChainInfo,\n };\n}\n\n// ---------------------------------------------------------------------------\n// First-fill execution (allowance check + approve-if-needed + first-fill swap)\n// ---------------------------------------------------------------------------\n\ninterface ExecuteFirstFillImplParams extends RecurringExecuteFirstFillParams {\n apiOptions: ApiOptions;\n appId: string;\n evmSigner: EvmSigner;\n}\n\nasync function executeFirstFillImpl({\n apiOptions,\n appId,\n evmSigner,\n fallbackToDefaultOnBatchFailure,\n fromAddress,\n gasSettings,\n quote,\n signerContext,\n sourceChain,\n}: ExecuteFirstFillImplParams): Promise<RecurringExecuteResult> {\n // Mirror the one-shot guard at `TransferManager.estimateNativeFee` — fail at\n // the SDK boundary with `QUOTE_EXPIRED` instead of an opaque `HttpError`\n // from `/recurring/swap` for a slow-to-approve user.\n const now = Math.floor(Date.now() / 1_000);\n if (quote.expiredAt <= now) {\n const expiredSecondsAgo = now - quote.expiredAt;\n throw new InvalidParamsError(\n ErrorReason.QUOTE_EXPIRED,\n `Recurring quote expired ${expiredSecondsAgo} seconds ago.`,\n );\n }\n\n // Wiring-mistake guard: the passed `sourceChain.chainId` (CAIP-2) must agree\n // with the `chainId` (numeric) the quote was issued against. Otherwise the\n // allowance / gas reads hit the wrong chain.\n const sourceChainIdNumeric = caip2ToEip155ChainId(sourceChain.chainId);\n if (sourceChainIdNumeric !== quote.chainId) {\n throw new InvalidParamsError(\n 'sourceChain does not match quote.chainId',\n `sourceChain.chainId=${sourceChain.chainId} resolves to ${sourceChainIdNumeric}, but quote.chainId=${quote.chainId}.`,\n );\n }\n\n const sourceClient = getEvmClientForChain({ chain: sourceChain });\n const chainIdHex = caip2ToEip155HexChainId(sourceChain.chainId);\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: quote.chainId,\n crossChainSwap: false,\n quoteId: quote.uuid,\n });\n\n if (!spenderAddress) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Missing Markr spender address for source chain ${sourceChain.chainId}.`,\n });\n }\n\n const approvalRequest = await buildErc20ApprovalRequest({\n chainIdHex,\n client: sourceClient,\n gasSettings,\n owner: fromAddress,\n requiredAllowance: quote.totalAmountIn,\n spender: spenderAddress,\n token: quote.tokenIn,\n });\n\n const syntheticQuote = buildSyntheticQuoteForFirstFill({ fromAddress, quote, sourceChain });\n\n const swap = await markrRecurringSwap(apiOptions, { uuid: quote.uuid, appId });\n\n // One-click batch path: same-chain DCA, approval required, signer exposes\n // `signBatch`. Matches `_executeEvmTransfer`'s eligibility check (recurring\n // is always same-chain so the cross-chain check there collapses to true).\n if (approvalRequest !== undefined && typeof evmSigner.signBatch === 'function') {\n const batchStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.ScheduleRecurringSwap,\n quote: syntheticQuote,\n requiredSignatures: 1,\n signerContext,\n };\n\n // Gas is left undefined on the swap leg — the wallet handles batched gas\n // estimation since the approval hasn't executed yet.\n const swapRequest: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: swap.data,\n from: fromAddress,\n gas: undefined,\n to: swap.to,\n value: swap.value,\n ...maybe1559(gasSettings),\n };\n\n try {\n const txHashes = await evmSigner.signBatch(\n [approvalRequest, swapRequest],\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n batchStep,\n );\n const swapTxHash = txHashes.at(-1);\n if (!swapTxHash) {\n throw new SdkError('One-click batch signing returned no transaction hashes.', ErrorCode.SIGNING_FAILED);\n }\n return { txHash: swapTxHash };\n } catch (error) {\n if (!fallbackToDefaultOnBatchFailure) {\n throw error;\n }\n // Fall through to the two-signature path below.\n }\n }\n\n if (approvalRequest) {\n await signApprovalAndAssertConfirmed({\n client: sourceClient,\n evmSigner,\n request: approvalRequest,\n step: {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.AllowanceApproval,\n quote: syntheticQuote,\n requiredSignatures: 2,\n signerContext,\n },\n });\n }\n\n // Use the Markr same-chain swap wrapper ABI for best-effort revert decoding\n // — matches `_estimateGasFromSwapResponse` in `estimate-native-fee.ts`.\n // Recurring is always same-chain, so `crossChain: false`. Built-in\n // `Error(string)` / `Panic(uint256)` are decoded regardless of ABI.\n const markrAbi = await getMarkrSwapWrapperAbi(false);\n const swapGasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: fromAddress, to: swap.to, data: swap.data, value: swap.value },\n markrAbi,\n 'Failed to estimate gas for recurring first-fill swap transaction.',\n );\n\n const swapRequest: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: swap.data,\n from: fromAddress,\n gas: applyFeeUnitsBpsMargin(swapGasEstimate, gasSettings?.estimateGasMarginBps),\n to: swap.to,\n value: swap.value,\n ...maybe1559(gasSettings),\n };\n\n const swapStep: TransferStepDetails = {\n currentSignature: approvalRequest ? 2 : 1,\n currentSignatureReason: TransferSignatureReason.ScheduleRecurringSwap,\n quote: syntheticQuote,\n requiredSignatures: approvalRequest ? 2 : 1,\n signerContext,\n };\n\n const txHash = await evmSigner.sign(\n swapRequest,\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n swapStep,\n );\n\n return { txHash };\n}\n\n// ---------------------------------------------------------------------------\n// Order-action execution (cancel / pause / unpause — single-tx state change)\n// ---------------------------------------------------------------------------\n\ninterface ExecuteOrderActionImplParams extends RecurringExecuteOrderActionParams {\n signatureReason:\n | TransferSignatureReason.PauseRecurringSwap\n | TransferSignatureReason.ResumeRecurringSwap\n | TransferSignatureReason.CancelRecurringSwap;\n apiOptions: ApiOptions;\n evmSigner: EvmSigner;\n fetchCalldata: (\n apiOptions: ApiOptions,\n params: { orderId: `0x${string}`; address: `0x${string}`; chainId: number },\n ) => Promise<WrappedSwapTransactionResponse>;\n}\n\n// Short verbs for error-message interpolation — avoids the doubled-\"recurring\"\n// + kebab-case-in-prose readout you'd get from interpolating the raw enum\n// wire value (e.g. `recurring pause-recurring-swap transaction`).\nconst ORDER_ACTION_LABEL: Record<ExecuteOrderActionImplParams['signatureReason'], string> = {\n [TransferSignatureReason.PauseRecurringSwap]: 'pause',\n [TransferSignatureReason.ResumeRecurringSwap]: 'resume',\n [TransferSignatureReason.CancelRecurringSwap]: 'cancel',\n};\n\nasync function executeOrderActionImpl({\n signatureReason,\n address,\n apiOptions,\n evmSigner,\n fetchCalldata,\n gasSettings,\n orderId,\n signerContext,\n sourceChain,\n}: ExecuteOrderActionImplParams): Promise<RecurringExecuteResult> {\n const sourceClient = getEvmClientForChain({ chain: sourceChain });\n const chainIdNumeric = caip2ToEip155ChainId(sourceChain.chainId);\n const chainIdHex = caip2ToEip155HexChainId(sourceChain.chainId);\n\n const calldata = await fetchCalldata(apiOptions, { orderId, address, chainId: chainIdNumeric });\n\n const gasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: address, to: calldata.to, data: calldata.data, value: calldata.value },\n erc20Abi,\n `Failed to estimate gas for recurring ${ORDER_ACTION_LABEL[signatureReason]} transaction.`,\n );\n\n const request: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: calldata.data,\n from: address,\n gas: applyFeeUnitsBpsMargin(gasEstimate, gasSettings?.estimateGasMarginBps),\n to: calldata.to,\n value: calldata.value,\n ...maybe1559(gasSettings),\n };\n\n const step: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: signatureReason,\n quote: buildSyntheticQuoteForOrderAction({ address, signatureReason, orderId, sourceChain }),\n requiredSignatures: 1,\n signerContext,\n };\n\n const txHash = await evmSigner.sign(\n request,\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n return { txHash };\n}\n\n// ---------------------------------------------------------------------------\n// Internal: synthetic Quote objects for `TransferStepDetails.quote`\n// ---------------------------------------------------------------------------\n\n/**\n * Builds a minimum-viable {@link Quote} for the signer step so consumer\n * `EvmSigner` impls can render meaningful wallet prompts for a recurring\n * action (which has no real `Quote` in the swap-quoter sense). The synthetic\n * value carries enough recurring context (uuid, chain, amounts, tokens) for\n * a wallet UI to label the popup; the `aggregator.id` (`'markr-recurring'`)\n * lets advanced signers detect the recurring path explicitly.\n *\n * Asset fields use placeholder `name`/`symbol`/`decimals` because the\n * recurring quote doesn't echo those — consumers needing rich asset display\n * should resolve token metadata against their own asset map keyed by\n * `quote.tokenIn`/`tokenOut`.\n */\nfunction buildSyntheticQuoteForFirstFill({\n fromAddress,\n quote,\n sourceChain,\n}: {\n fromAddress: `0x${string}`;\n quote: RecurringQuoteResponse;\n sourceChain: Chain;\n}): Quote {\n return {\n // Keep the stable `'markr-recurring'` marker (shipped in #240) — consumer\n // signers may detect the recurring path via `quote.aggregator.id`. The\n // typed `TransferStepDetails.currentSignatureReason` is now the preferred\n // discriminant for new integrations, but this id stays for back-compat.\n aggregator: { id: 'markr-recurring', name: 'Markr recurring' },\n amountIn: quote.amount,\n amountOut: quote.amountOut,\n assetIn: { type: TokenType.ERC20, address: quote.tokenIn, name: '', symbol: '', decimals: 0 },\n assetOut: { type: TokenType.ERC20, address: quote.tokenOut, name: '', symbol: '', decimals: 0 },\n expiresAt: quote.expiredAt,\n fees: [],\n fromAddress,\n id: quote.uuid,\n partnerFeeBps: null,\n serviceType: ServiceType.MARKR,\n slippageBps: quote.recommendedSlippage,\n // Pass the caller-provided `Chain` straight through — recurring is always\n // same-chain, so source === target. Avoids stripping `chainName` /\n // `networkToken` / `rpcUrl` that consumer signers may use for display.\n sourceChain,\n targetChain: sourceChain,\n toAddress: fromAddress,\n };\n}\n\nfunction buildSyntheticQuoteForOrderAction({\n signatureReason,\n address,\n orderId,\n sourceChain,\n}: {\n signatureReason:\n | TransferSignatureReason.PauseRecurringSwap\n | TransferSignatureReason.ResumeRecurringSwap\n | TransferSignatureReason.CancelRecurringSwap;\n address: `0x${string}`;\n orderId: `0x${string}`;\n sourceChain: Chain;\n}): Quote {\n const action = ORDER_ACTION_LABEL[signatureReason];\n return {\n // Same back-compat rationale as `buildSyntheticQuoteForFirstFill` — preserve\n // the original lowercase `markr-recurring-${action}` id shape (shipped in\n // #240) so consumers keying off `quote.aggregator.id` keep working.\n aggregator: {\n id: `markr-recurring-${action}`,\n name: `Markr recurring (${action})`,\n },\n amountIn: 0n,\n amountOut: 0n,\n assetIn: emptyNativeAsset(),\n assetOut: emptyNativeAsset(),\n expiresAt: 0,\n fees: [],\n fromAddress: address,\n id: orderId,\n partnerFeeBps: null,\n serviceType: ServiceType.MARKR,\n slippageBps: 0,\n // See `buildSyntheticQuoteForFirstFill` — pass the real `Chain` through.\n sourceChain,\n targetChain: sourceChain,\n toAddress: address,\n };\n}\n\nfunction emptyNativeAsset() {\n return { type: TokenType.NATIVE, name: '', symbol: '', decimals: 0 } as const;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"_namespace.js","names":[],"sources":["../../../../src/transfer-service/markr/recurring/_namespace.ts"],"sourcesContent":["import { erc20Abi, isAddressEqual } from 'viem';\nimport { ERC_ZERO_ADDRESS, ServiceType, TokenType, TransferSignatureReason } from '../../../constants';\nimport { ErrorCode, ErrorReason, InvalidParamsError, SdkError } from '../../../errors';\nimport type { Chain } from '../../../types/chain';\nimport type { Quote } from '../../../types/quote';\nimport type { EvmSigner, EvmTransactionRequest, Hex } from '../../../types/signer';\nimport type { TransferStepDetails } from '../../../types/transfer';\nimport { caip2ToEip155ChainId, caip2ToEip155HexChainId } from '../../../utils/caip';\nimport { applyFeeUnitsBpsMargin, getEvmClientForChain, maybe1559 } from '../../_utils';\nimport type { EvmSourceClient } from '../../_utils';\nimport { buildErc20ApprovalRequest, signApprovalAndAssertConfirmed } from '../../_evm-approval';\nimport { estimateGasWithRevert } from '../../_evm-errors';\nimport type { WrappedSwapTransactionResponse } from '../_schema';\nimport { markrGetSpenderAddress, type ApiOptions } from '../_api';\nimport { getMarkrSwapWrapperAbi } from '../_utils';\nimport {\n markrListRecurringOrders,\n markrPrepareCancellation,\n markrPreparePause,\n markrPrepareUnpause,\n markrRecurringQuote,\n markrRecurringSwap,\n} from './_api';\nimport { checkRecurringEligibility } from './_eligibility';\nimport type {\n RecurringChainInfoMap,\n RecurringExecuteFirstFillParams,\n RecurringExecuteOrderActionParams,\n RecurringExecuteResult,\n RecurringNamespace,\n RecurringNamespaceQuoteParams,\n RecurringQuoteResponse,\n} from './types';\n\nexport interface CreateRecurringNamespaceOptions {\n apiOptions: ApiOptions;\n appId: string;\n evmSigner: EvmSigner;\n /**\n * The cached `/info/chains` recurring metadata. Captured by value at\n * namespace construction time — matches how `partnerFeeBps`,\n * `supportedChains`, and `supportedTokens` are also frozen at\n * `createMarkrService` init. If staleness ever becomes a real consumer\n * concern, the fix is a top-level `manager.refresh()` (not a per-namespace\n * lazy-read pattern).\n */\n recurringChainInfo: RecurringChainInfoMap;\n}\n\nexport function createRecurringNamespace({\n apiOptions,\n appId,\n evmSigner,\n recurringChainInfo,\n}: CreateRecurringNamespaceOptions): RecurringNamespace {\n return {\n quote: (props) => quoteImpl({ ...props, apiOptions, appId, recurringChainInfo }),\n\n executeFirstFill: (props) => executeFirstFillImpl({ ...props, apiOptions, appId, evmSigner, recurringChainInfo }),\n\n listOrders: (props) => markrListRecurringOrders(apiOptions, props),\n\n executeCancellation: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.CancelRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPrepareCancellation,\n }),\n\n executePause: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.PauseRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPreparePause,\n }),\n\n executeUnpause: (props) =>\n executeOrderActionImpl({\n ...props,\n signatureReason: TransferSignatureReason.ResumeRecurringSwap,\n apiOptions,\n evmSigner,\n fetchCalldata: markrPrepareUnpause,\n }),\n\n checkEligibility: (props) => checkRecurringEligibility({ ...props, recurringChainInfo }),\n\n getRecurringChainInfo: () => recurringChainInfo,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Quote — native input (`tokenIn === 0x0…`) is passed through to Markr\n// verbatim (the recurring API accepts the zero address as `tokenIn`). The\n// chain's wrapped-native address is read off the cached chain info (sourced\n// from `/info/chains[].wrapped_token`); the SDK only fails fast at this\n// boundary when Markr hasn't published one for the chain — we'd be issuing\n// a quote we couldn't honor.\n// ---------------------------------------------------------------------------\n\ninterface QuoteImplParams extends RecurringNamespaceQuoteParams {\n apiOptions: ApiOptions;\n appId: string;\n recurringChainInfo: RecurringChainInfoMap;\n}\n\nasync function quoteImpl({\n apiOptions,\n appId,\n recurringChainInfo,\n ...quoteParams\n}: QuoteImplParams): Promise<RecurringQuoteResponse> {\n const isNativeInput = isAddressEqual(quoteParams.tokenIn, ERC_ZERO_ADDRESS);\n\n if (isNativeInput && !recurringChainInfo.get(quoteParams.chainId)?.wrappedNativeAddress) {\n throw new InvalidParamsError(\n ErrorReason.CHAIN_NOT_SUPPORTED,\n `No wrapped-native ERC-20 address known for EVM chainId ${quoteParams.chainId}. ` +\n 'Native-input recurring swaps require Markr to publish `wrapped_token` for the chain in `/info/chains`.',\n );\n }\n\n return markrRecurringQuote(apiOptions, { ...quoteParams, appId });\n}\n\n// ---------------------------------------------------------------------------\n// First-fill execution (allowance check + approve-if-needed + first-fill swap)\n// ---------------------------------------------------------------------------\n\ninterface ExecuteFirstFillImplParams extends RecurringExecuteFirstFillParams {\n apiOptions: ApiOptions;\n appId: string;\n evmSigner: EvmSigner;\n recurringChainInfo: RecurringChainInfoMap;\n}\n\nasync function executeFirstFillImpl({\n apiOptions,\n appId,\n evmSigner,\n fallbackToDefaultOnBatchFailure,\n fromAddress,\n gasSettings,\n quote,\n recurringChainInfo,\n signerContext,\n sourceChain,\n}: ExecuteFirstFillImplParams): Promise<RecurringExecuteResult> {\n // Mirror the one-shot guard at `TransferManager.estimateNativeFee` — fail at\n // the SDK boundary with `QUOTE_EXPIRED` instead of an opaque `HttpError`\n // from `/recurring/swap` for a slow-to-approve user.\n const now = Math.floor(Date.now() / 1_000);\n if (quote.expiredAt <= now) {\n const expiredSecondsAgo = now - quote.expiredAt;\n throw new InvalidParamsError(\n ErrorReason.QUOTE_EXPIRED,\n `Recurring quote expired ${expiredSecondsAgo} seconds ago.`,\n );\n }\n\n // Wiring-mistake guard: the passed `sourceChain.chainId` (CAIP-2) must agree\n // with the `chainId` (numeric) the quote was issued against. Otherwise the\n // allowance / gas reads hit the wrong chain.\n const sourceChainIdNumeric = caip2ToEip155ChainId(sourceChain.chainId);\n if (sourceChainIdNumeric !== quote.chainId) {\n throw new InvalidParamsError(\n 'sourceChain does not match quote.chainId',\n `sourceChain.chainId=${sourceChain.chainId} resolves to ${sourceChainIdNumeric}, but quote.chainId=${quote.chainId}.`,\n );\n }\n\n const sourceClient = getEvmClientForChain({ chain: sourceChain });\n const chainIdHex = caip2ToEip155HexChainId(sourceChain.chainId);\n\n const isNativeInput = isAddressEqual(quote.tokenIn, ERC_ZERO_ADDRESS);\n\n const { address: spenderAddress } = await markrGetSpenderAddress(apiOptions, {\n chainId: quote.chainId,\n crossChainSwap: false,\n quoteId: quote.uuid,\n });\n\n if (!spenderAddress) {\n throw new SdkError(ErrorReason.CHAIN_NOT_SUPPORTED, ErrorCode.INVALID_PARAMS, {\n details: `Missing Markr spender address for source chain ${sourceChain.chainId}.`,\n });\n }\n\n // Fetch the ordered transaction array from Markr's `/recurring/swap`:\n // - ERC-20 `tokenIn`: `[createOrder]` (1 element).\n // - Native `tokenIn` (`0x0…`): `[wrap, createOrder]` (2 elements).\n // The wrap's `to` is the wrapped-native ERC-20 we'll then approve against\n // (Markr does not return an approval entry — the SDK inserts that step).\n const recurringSwapTxs = await markrRecurringSwap(apiOptions, { uuid: quote.uuid, appId });\n\n const wrapTx = recurringSwapTxs.find((tx) => tx.type === 'wrap');\n const createOrderTx = recurringSwapTxs.find((tx) => tx.type === 'createOrder');\n\n if (!createOrderTx) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `Missing createOrder step (quote uuid: ${quote.uuid}).`,\n });\n }\n\n // Cross-check: native input must come back with a wrap leg, and an ERC-20\n // input must not. If Markr disagrees with the cached quote's `tokenIn`,\n // bail rather than silently signing a mismatched flow (e.g. broadcasting\n // a wrap when the user thought they were spending ERC-20, or skipping a\n // wrap when the user expected to fund the schedule with native).\n if (isNativeInput && !wrapTx) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `Native-input quote returned no wrap step (quote uuid: ${quote.uuid}).`,\n });\n }\n if (!isNativeInput && wrapTx) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `ERC-20 input quote returned a wrap step (quote uuid: ${quote.uuid}, tokenIn: ${quote.tokenIn}).`,\n });\n }\n\n // Defense-in-depth on the wrap leg before we hand it to the wallet:\n // - `wrap.value` must equal `quote.totalAmountIn` — that's what funds the\n // full schedule; a smaller value would under-fund subsequent fills, a\n // larger one would silently overcharge the user.\n // - `wrap.to` must match the chain's published wrapped-native (from\n // `/info/chains[].wrapped_token`) when one is known. Cross-check guards\n // against a misrouted approval — we're about to grant `totalAmountIn`\n // allowance to whatever `wrap.to` points at. When the chain entry has\n // no published wrapped-native, defer to Markr (`wrap.to` is server-\n // authoritative); the quote boundary already failed-closed in that\n // case anyway, so this is purely belt-and-suspenders.\n if (wrapTx) {\n if (wrapTx.value !== quote.totalAmountIn) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `Wrap step value ${wrapTx.value} does not match quote.totalAmountIn ${quote.totalAmountIn} (quote uuid: ${quote.uuid}).`,\n });\n }\n const expectedWrappedNative = recurringChainInfo.get(quote.chainId)?.wrappedNativeAddress;\n if (expectedWrappedNative && !isAddressEqual(wrapTx.to, expectedWrappedNative)) {\n throw new SdkError(ErrorReason.RECURRING_SWAP_RESPONSE_INCONSISTENT, ErrorCode.INVALID_PARAMS, {\n details: `Wrap step target ${wrapTx.to} does not match the published wrapped-native ${expectedWrappedNative} for chainId ${quote.chainId} (quote uuid: ${quote.uuid}).`,\n });\n }\n }\n\n // Approval target: for native input, the wrapped-native ERC-20 returned\n // by Markr in `wrap.to` (cross-checked above). For ERC-20 input, the\n // quote's `tokenIn`. Either way the spender is the RecurringSwaps router.\n const approvalTokenAddress = wrapTx?.to ?? quote.tokenIn;\n\n const approvalRequest = await buildErc20ApprovalRequest({\n chainIdHex,\n client: sourceClient,\n gasSettings,\n owner: fromAddress,\n requiredAllowance: quote.totalAmountIn,\n spender: spenderAddress,\n token: approvalTokenAddress,\n });\n\n // Wrap leg comes straight from Markr — `wrap.to` is the chain wrapped-native\n // contract, `data` is `deposit()`, `value` is `totalAmountIn`. Gas is left\n // undefined: when batched the wallet handles atomic estimation; sequentially\n // the wrap is the first call so the wallet's own estimation fires the prompt.\n const wrapRequest: EvmTransactionRequest | undefined = wrapTx\n ? {\n chainId: chainIdHex,\n data: wrapTx.data,\n from: fromAddress,\n gas: undefined,\n to: wrapTx.to,\n value: wrapTx.value,\n ...maybe1559(gasSettings),\n }\n : undefined;\n\n const syntheticQuote = buildSyntheticQuoteForFirstFill({ fromAddress, quote, sourceChain });\n\n // One-click batch path: same-chain DCA, signer exposes `signBatch`, and at\n // least one leg precedes the swap (otherwise there's nothing to batch — we\n // sign the swap solo). The batch shape adapts to the recurring setup:\n // - native + needs approval: [wrap, approve, swap] (3 elements)\n // - native + allowance covers: [wrap, swap] (2 elements)\n // - ERC-20 + needs approval: [approve, swap] (2 elements)\n // - ERC-20 + allowance covers: swap solo (no batch)\n const batchPreSwap: EvmTransactionRequest[] = [];\n if (wrapRequest) batchPreSwap.push(wrapRequest);\n if (approvalRequest) batchPreSwap.push(approvalRequest);\n\n if (batchPreSwap.length > 0 && typeof evmSigner.signBatch === 'function') {\n const batchStep: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: TransferSignatureReason.ScheduleRecurringSwap,\n quote: syntheticQuote,\n requiredSignatures: 1,\n signerContext,\n };\n\n // Gas is left undefined on the swap leg — the wallet handles batched gas\n // estimation since the preceding leg(s) haven't executed yet.\n const swapRequest: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: createOrderTx.data,\n from: fromAddress,\n gas: undefined,\n to: createOrderTx.to,\n value: createOrderTx.value,\n ...maybe1559(gasSettings),\n };\n\n try {\n const txHashes = await evmSigner.signBatch(\n [...batchPreSwap, swapRequest],\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n batchStep,\n );\n const swapTxHash = txHashes.at(-1);\n if (!swapTxHash) {\n throw new SdkError('One-click batch signing returned no transaction hashes.', ErrorCode.SIGNING_FAILED);\n }\n return { txHash: swapTxHash };\n } catch (error) {\n if (!fallbackToDefaultOnBatchFailure) {\n throw error;\n }\n // Fall through to the sequential path below.\n }\n }\n\n // Sequential path — sign each preceding leg, await its receipt, then sign\n // the swap. Signature counters reflect the actual prompt count the user\n // will see (1 + wrap? + approval?).\n const requiredSignatures = 1 + batchPreSwap.length;\n let signatureCursor = 0;\n\n if (wrapRequest && wrapTx) {\n // Estimate gas for the wrap leg on the sequential path. On the batch\n // path we leave gas undefined and let the wallet do atomic estimation;\n // sequentially the wrap is a real first-tx prompt so it gets the same\n // treatment as the approval and swap legs (estimate + bps margin) for\n // wallets that don't auto-estimate. Read `to`/`data` off `wrapTx` (the\n // narrow `RecurringSwapTransaction` shape) rather than the wider\n // `EvmTransactionRequest` so the args are non-nullable.\n const wrapGasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: fromAddress, to: wrapTx.to, data: wrapTx.data, value: wrapTx.value },\n // No router ABI to decode against — wrap is a plain\n // `WAVAX.deposit{value}()`; built-in `Error(string)` / `Panic(uint256)`\n // are still decoded regardless of the ABI argument.\n [],\n 'Failed to estimate gas for recurring first-fill wrap transaction.',\n );\n const wrapRequestWithGas: EvmTransactionRequest = {\n ...wrapRequest,\n gas: applyFeeUnitsBpsMargin(wrapGasEstimate, gasSettings?.estimateGasMarginBps),\n };\n\n signatureCursor += 1;\n await signWrapAndAssertConfirmed({\n client: sourceClient,\n evmSigner,\n request: wrapRequestWithGas,\n step: {\n currentSignature: signatureCursor,\n currentSignatureReason: TransferSignatureReason.WrapToken,\n quote: syntheticQuote,\n requiredSignatures,\n signerContext,\n },\n });\n }\n\n if (approvalRequest) {\n signatureCursor += 1;\n await signApprovalAndAssertConfirmed({\n client: sourceClient,\n evmSigner,\n request: approvalRequest,\n step: {\n currentSignature: signatureCursor,\n currentSignatureReason: TransferSignatureReason.AllowanceApproval,\n quote: syntheticQuote,\n requiredSignatures,\n signerContext,\n },\n });\n }\n\n // Use the Markr same-chain swap wrapper ABI for best-effort revert decoding\n // — matches `_estimateGasFromSwapResponse` in `estimate-native-fee.ts`.\n // Recurring is always same-chain, so `crossChain: false`. Built-in\n // `Error(string)` / `Panic(uint256)` are decoded regardless of ABI.\n const markrAbi = await getMarkrSwapWrapperAbi(false);\n const swapGasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: fromAddress, to: createOrderTx.to, data: createOrderTx.data, value: createOrderTx.value },\n markrAbi,\n 'Failed to estimate gas for recurring first-fill swap transaction.',\n );\n\n const swapRequest: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: createOrderTx.data,\n from: fromAddress,\n gas: applyFeeUnitsBpsMargin(swapGasEstimate, gasSettings?.estimateGasMarginBps),\n to: createOrderTx.to,\n value: createOrderTx.value,\n ...maybe1559(gasSettings),\n };\n\n signatureCursor += 1;\n const swapStep: TransferStepDetails = {\n currentSignature: signatureCursor,\n currentSignatureReason: TransferSignatureReason.ScheduleRecurringSwap,\n quote: syntheticQuote,\n requiredSignatures,\n signerContext,\n };\n\n const txHash = await evmSigner.sign(\n swapRequest,\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n swapStep,\n );\n\n return { txHash };\n}\n\n/**\n * Signs a `WAVAX.deposit{value}()` wrap request, dispatches it, and waits for\n * the receipt. Mirrors {@link signApprovalAndAssertConfirmed} so the\n * sequential native path fails loudly if the wrap reverts on-chain (without\n * which the downstream approve would silently fail for \"insufficient WAVAX\").\n */\nasync function signWrapAndAssertConfirmed({\n client,\n evmSigner,\n request,\n step,\n}: {\n client: EvmSourceClient;\n evmSigner: EvmSigner;\n request: EvmTransactionRequest;\n step: TransferStepDetails;\n}): Promise<Hex> {\n const wrapTxHash = await evmSigner.sign(\n request,\n (signedTxHash) => client.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n const receipt = await client.waitForTransactionReceipt({ hash: wrapTxHash });\n\n if (receipt.status === 'reverted') {\n throw new SdkError(ErrorReason.NATIVE_WRAP_REVERTED, ErrorCode.TRANSACTION_REVERTED, {\n details: `Wrap tx reverted on-chain (tx hash: ${wrapTxHash}).`,\n });\n }\n\n return wrapTxHash;\n}\n\n// ---------------------------------------------------------------------------\n// Order-action execution (cancel / pause / unpause — single-tx state change)\n// ---------------------------------------------------------------------------\n\ninterface ExecuteOrderActionImplParams extends RecurringExecuteOrderActionParams {\n signatureReason:\n | TransferSignatureReason.PauseRecurringSwap\n | TransferSignatureReason.ResumeRecurringSwap\n | TransferSignatureReason.CancelRecurringSwap;\n apiOptions: ApiOptions;\n evmSigner: EvmSigner;\n fetchCalldata: (\n apiOptions: ApiOptions,\n params: { orderId: `0x${string}`; address: `0x${string}`; chainId: number },\n ) => Promise<WrappedSwapTransactionResponse>;\n}\n\n// Short verbs for error-message interpolation — avoids the doubled-\"recurring\"\n// + kebab-case-in-prose readout you'd get from interpolating the raw enum\n// wire value (e.g. `recurring pause-recurring-swap transaction`).\nconst ORDER_ACTION_LABEL: Record<ExecuteOrderActionImplParams['signatureReason'], string> = {\n [TransferSignatureReason.PauseRecurringSwap]: 'pause',\n [TransferSignatureReason.ResumeRecurringSwap]: 'resume',\n [TransferSignatureReason.CancelRecurringSwap]: 'cancel',\n};\n\nasync function executeOrderActionImpl({\n signatureReason,\n address,\n apiOptions,\n evmSigner,\n fetchCalldata,\n gasSettings,\n orderId,\n signerContext,\n sourceChain,\n}: ExecuteOrderActionImplParams): Promise<RecurringExecuteResult> {\n const sourceClient = getEvmClientForChain({ chain: sourceChain });\n const chainIdNumeric = caip2ToEip155ChainId(sourceChain.chainId);\n const chainIdHex = caip2ToEip155HexChainId(sourceChain.chainId);\n\n const calldata = await fetchCalldata(apiOptions, { orderId, address, chainId: chainIdNumeric });\n\n const gasEstimate = await estimateGasWithRevert(\n sourceClient,\n { account: address, to: calldata.to, data: calldata.data, value: calldata.value },\n erc20Abi,\n `Failed to estimate gas for recurring ${ORDER_ACTION_LABEL[signatureReason]} transaction.`,\n );\n\n const request: EvmTransactionRequest = {\n chainId: chainIdHex,\n data: calldata.data,\n from: address,\n gas: applyFeeUnitsBpsMargin(gasEstimate, gasSettings?.estimateGasMarginBps),\n to: calldata.to,\n value: calldata.value,\n ...maybe1559(gasSettings),\n };\n\n const step: TransferStepDetails = {\n currentSignature: 1,\n currentSignatureReason: signatureReason,\n quote: buildSyntheticQuoteForOrderAction({ address, signatureReason, orderId, sourceChain }),\n requiredSignatures: 1,\n signerContext,\n };\n\n const txHash = await evmSigner.sign(\n request,\n (signedTxHash) => sourceClient.sendRawTransaction({ serializedTransaction: signedTxHash }),\n step,\n );\n\n return { txHash };\n}\n\n// ---------------------------------------------------------------------------\n// Internal: synthetic Quote objects for `TransferStepDetails.quote`\n// ---------------------------------------------------------------------------\n\n/**\n * Builds a minimum-viable {@link Quote} for the signer step so consumer\n * `EvmSigner` impls can render meaningful wallet prompts for a recurring\n * action (which has no real `Quote` in the swap-quoter sense). The synthetic\n * value carries enough recurring context (uuid, chain, amounts, tokens) for\n * a wallet UI to label the popup; the `aggregator.id` (`'markr-recurring'`)\n * lets advanced signers detect the recurring path explicitly.\n *\n * Asset fields use placeholder `name`/`symbol`/`decimals` because the\n * recurring quote doesn't echo those — consumers needing rich asset display\n * should resolve token metadata against their own asset map keyed by\n * `quote.tokenIn`/`tokenOut`.\n */\nfunction buildSyntheticQuoteForFirstFill({\n fromAddress,\n quote,\n sourceChain,\n}: {\n fromAddress: `0x${string}`;\n quote: RecurringQuoteResponse;\n sourceChain: Chain;\n}): Quote {\n return {\n // Keep the stable `'markr-recurring'` marker (shipped in #240) — consumer\n // signers may detect the recurring path via `quote.aggregator.id`. The\n // typed `TransferStepDetails.currentSignatureReason` is now the preferred\n // discriminant for new integrations, but this id stays for back-compat.\n aggregator: { id: 'markr-recurring', name: 'Markr recurring' },\n amountIn: quote.amount,\n amountOut: quote.amountOut,\n assetIn: { type: TokenType.ERC20, address: quote.tokenIn, name: '', symbol: '', decimals: 0 },\n assetOut: { type: TokenType.ERC20, address: quote.tokenOut, name: '', symbol: '', decimals: 0 },\n expiresAt: quote.expiredAt,\n fees: [],\n fromAddress,\n id: quote.uuid,\n partnerFeeBps: null,\n serviceType: ServiceType.MARKR,\n slippageBps: quote.recommendedSlippage,\n // Pass the caller-provided `Chain` straight through — recurring is always\n // same-chain, so source === target. Avoids stripping `chainName` /\n // `networkToken` / `rpcUrl` that consumer signers may use for display.\n sourceChain,\n targetChain: sourceChain,\n toAddress: fromAddress,\n };\n}\n\nfunction buildSyntheticQuoteForOrderAction({\n signatureReason,\n address,\n orderId,\n sourceChain,\n}: {\n signatureReason:\n | TransferSignatureReason.PauseRecurringSwap\n | TransferSignatureReason.ResumeRecurringSwap\n | TransferSignatureReason.CancelRecurringSwap;\n address: `0x${string}`;\n orderId: `0x${string}`;\n sourceChain: Chain;\n}): Quote {\n const action = ORDER_ACTION_LABEL[signatureReason];\n return {\n // Same back-compat rationale as `buildSyntheticQuoteForFirstFill` — preserve\n // the original lowercase `markr-recurring-${action}` id shape (shipped in\n // #240) so consumers keying off `quote.aggregator.id` keep working.\n aggregator: {\n id: `markr-recurring-${action}`,\n name: `Markr recurring (${action})`,\n },\n amountIn: 0n,\n amountOut: 0n,\n assetIn: emptyNativeAsset(),\n assetOut: emptyNativeAsset(),\n expiresAt: 0,\n fees: [],\n fromAddress: address,\n id: orderId,\n partnerFeeBps: null,\n serviceType: ServiceType.MARKR,\n slippageBps: 0,\n // See `buildSyntheticQuoteForFirstFill` — pass the real `Chain` through.\n sourceChain,\n targetChain: sourceChain,\n toAddress: address,\n };\n}\n\nfunction emptyNativeAsset() {\n return { type: TokenType.NATIVE, name: '', symbol: '', decimals: 0 } as const;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`./types.cjs`),t=require(`../../service-schemas.cjs`);let n=require(`zod`);const r=/^0x[0-9a-fA-F]{64}$/,i=n.z.enum(e.RECURRING_FREQUENCY_UNITS),a=n.z.object({unit:i,value:n.z.number().int().min(1)}),o=n.z.enum(Object.values(e.RecurringOrderStatus)),s=n.z.object({executionIndex:n.z.number().int().nonnegative(),reasons:n.z.array(n.z.string()),tryCount:n.z.number().int().nonnegative(),failedAt:n.z.number().int().nonnegative()}),c=n.z.string().regex(r,`Invalid recurring order id (expected 0x-prefixed bytes32)`).transform(e=>e),l=n.z.object({orderId:c,owner:t.EvmAddressSchema,chainId:n.z.coerce.number().int().nonnegative(),tokenIn:t.EvmAddressSchema,tokenOut:t.EvmAddressSchema,amount:n.z.coerce.bigint().nonnegative(),numberOfOrders:n.z.number().int(),executedOrders:n.z.number().int().nonnegative(),remainingOrders:n.z.number().int().nonnegative().nullish().transform(e=>e??null),frequency:a,totalAmountIn:n.z.coerce.bigint().nonnegative(),tryCount:n.z.number().int().nonnegative(),failures:n.z.array(s),status:o,createdAt:n.z.number().int().nonnegative(),nextExecutionAt:n.z.number().int().nonnegative().nullish().transform(e=>e??null),cancelledAt:n.z.number().int().nonnegative().nullish().transform(e=>e??null)}),u=n.z.object({type:n.z.enum([`gas`,`recurring`,`protocol`,`bridge`,`slippage`,`swap`,`other`]).or(n.z.string()),name:n.z.string(),amount:n.z.coerce.bigint().nonnegative(),token:n.z.object({chainId:n.z.coerce.number().int().nonnegative(),address:t.EvmAddressSchema}),extra:n.z.union([n.z.boolean(),n.z.record(n.z.string(),n.z.unknown())]).optional()}),d=n.z.object({uuid:n.z.uuid(),chainId:n.z.coerce.number().int().nonnegative(),tokenIn:t.EvmAddressSchema,tokenOut:t.EvmAddressSchema,amount:n.z.coerce.bigint().nonnegative(),numberOfOrders:n.z.number().int(),frequency:a,intervalSeconds:n.z.number().int().nonnegative(),totalAmountIn:n.z.coerce.bigint().nonnegative(),amountOut:n.z.coerce.bigint().nonnegative(),minAmountOut:n.z.coerce.bigint().nonnegative(),fees:n.z.array(u),recommendedSlippage:n.z.number().int().nonnegative(),expiredAt:n.z.number().int().nonnegative()}),f=n.z.object({address:t.EvmAddressSchema,count:n.z.number().int().nonnegative(),orders:n.z.array(l)});exports.ListRecurringOrdersResponseSchema=f,exports.RecurringQuoteResponseSchema=d;
1
+ require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`./types.cjs`),t=require(`../../service-schemas.cjs`);let n=require(`zod`);const r=/^0x[0-9a-fA-F]{64}$/,i=n.z.enum(e.RECURRING_FREQUENCY_UNITS),a=n.z.object({unit:i,value:n.z.number().int().min(1)}),o=n.z.enum(Object.values(e.RecurringOrderStatus)),s=n.z.object({executionIndex:n.z.number().int().nonnegative(),reasons:n.z.array(n.z.string()),tryCount:n.z.number().int().nonnegative(),failedAt:n.z.number().int().nonnegative()}),c=n.z.object({type:n.z.enum([`wrap`,`createOrder`]),to:t.EvmAddressSchema,data:t.HexSchema,value:n.z.coerce.bigint().nonnegative()}),l=n.z.array(c),u=n.z.string().regex(r,`Invalid recurring order id (expected 0x-prefixed bytes32)`).transform(e=>e),d=n.z.object({orderId:u,owner:t.EvmAddressSchema,chainId:n.z.coerce.number().int().nonnegative(),tokenIn:t.EvmAddressSchema,tokenOut:t.EvmAddressSchema,amount:n.z.coerce.bigint().nonnegative(),numberOfOrders:n.z.number().int(),executedOrders:n.z.number().int().nonnegative(),remainingOrders:n.z.number().int().nonnegative().nullish().transform(e=>e??null),frequency:a,totalAmountIn:n.z.coerce.bigint().nonnegative(),tryCount:n.z.number().int().nonnegative(),failures:n.z.array(s),status:o,createdAt:n.z.number().int().nonnegative(),nextExecutionAt:n.z.number().int().nonnegative().nullish().transform(e=>e??null),cancelledAt:n.z.number().int().nonnegative().nullish().transform(e=>e??null)}),f=n.z.object({type:n.z.enum([`gas`,`recurring`,`protocol`,`bridge`,`slippage`,`swap`,`other`]).or(n.z.string()),name:n.z.string(),amount:n.z.coerce.bigint().nonnegative(),token:n.z.object({chainId:n.z.coerce.number().int().nonnegative(),address:t.EvmAddressSchema}),extra:n.z.union([n.z.boolean(),n.z.record(n.z.string(),n.z.unknown())]).optional()}),p=n.z.object({uuid:n.z.uuid(),chainId:n.z.coerce.number().int().nonnegative(),tokenIn:t.EvmAddressSchema,tokenOut:t.EvmAddressSchema,amount:n.z.coerce.bigint().nonnegative(),numberOfOrders:n.z.number().int(),frequency:a,intervalSeconds:n.z.number().int().nonnegative(),totalAmountIn:n.z.coerce.bigint().nonnegative(),amountOut:n.z.coerce.bigint().nonnegative(),minAmountOut:n.z.coerce.bigint().nonnegative(),fees:n.z.array(f),recommendedSlippage:n.z.number().int().nonnegative(),expiredAt:n.z.number().int().nonnegative()}),m=n.z.object({address:t.EvmAddressSchema,count:n.z.number().int().nonnegative(),orders:n.z.array(d)});exports.ListRecurringOrdersResponseSchema=m,exports.RecurringQuoteResponseSchema=p,exports.RecurringSwapResponseSchema=l;
2
2
  //# sourceMappingURL=_schema.cjs.map