@avalabs/fusion-sdk 0.21.0 → 0.23.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 (101) hide show
  1. package/dist/constants.cjs +1 -1
  2. package/dist/constants.cjs.map +1 -1
  3. package/dist/constants.d.cts +9 -1
  4. package/dist/constants.d.ts +9 -1
  5. package/dist/constants.js +1 -1
  6. package/dist/constants.js.map +1 -1
  7. package/dist/mod.cjs +1 -1
  8. package/dist/mod.d.cts +5 -1
  9. package/dist/mod.d.ts +5 -1
  10. package/dist/mod.js +1 -1
  11. package/dist/transfer-manager.cjs +1 -1
  12. package/dist/transfer-manager.cjs.map +1 -1
  13. package/dist/transfer-manager.js +1 -1
  14. package/dist/transfer-manager.js.map +1 -1
  15. package/dist/transfer-service/_evm-approval.cjs +2 -0
  16. package/dist/transfer-service/_evm-approval.cjs.map +1 -0
  17. package/dist/transfer-service/_evm-approval.d.cts +23 -0
  18. package/dist/transfer-service/_evm-approval.d.ts +23 -0
  19. package/dist/transfer-service/_evm-approval.js +2 -0
  20. package/dist/transfer-service/_evm-approval.js.map +1 -0
  21. package/dist/transfer-service/_utils.cjs +1 -1
  22. package/dist/transfer-service/_utils.cjs.map +1 -1
  23. package/dist/transfer-service/_utils.d.ts +1 -0
  24. package/dist/transfer-service/_utils.js +1 -1
  25. package/dist/transfer-service/_utils.js.map +1 -1
  26. package/dist/transfer-service/avalanche-cct/_handlers/estimate-native-fee.cjs +1 -1
  27. package/dist/transfer-service/avalanche-cct/_handlers/estimate-native-fee.js +1 -1
  28. package/dist/transfer-service/avalanche-cct/_handlers/track-transfer.cjs +1 -1
  29. package/dist/transfer-service/avalanche-cct/_handlers/track-transfer.js +1 -1
  30. package/dist/transfer-service/avalanche-cct/_handlers/transfer-asset.cjs +1 -1
  31. package/dist/transfer-service/avalanche-cct/_handlers/transfer-asset.js +1 -1
  32. package/dist/transfer-service/avalanche-cct/_utils/fees.cjs +1 -1
  33. package/dist/transfer-service/avalanche-cct/_utils/fees.js +1 -1
  34. package/dist/transfer-service/avalanche-cct/_utils/polling.cjs +1 -1
  35. package/dist/transfer-service/avalanche-cct/_utils/polling.js +1 -1
  36. package/dist/transfer-service/avalanche-evm/_handlers/estimate-native-fee.cjs +1 -1
  37. package/dist/transfer-service/avalanche-evm/_handlers/estimate-native-fee.js +1 -1
  38. package/dist/transfer-service/markr/_api.cjs +1 -1
  39. package/dist/transfer-service/markr/_api.cjs.map +1 -1
  40. package/dist/transfer-service/markr/_api.js +1 -1
  41. package/dist/transfer-service/markr/_api.js.map +1 -1
  42. package/dist/transfer-service/markr/_handlers/estimate-native-fee.cjs +1 -1
  43. package/dist/transfer-service/markr/_handlers/estimate-native-fee.js +1 -1
  44. package/dist/transfer-service/markr/_handlers/transfer-asset.cjs +1 -1
  45. package/dist/transfer-service/markr/_handlers/transfer-asset.cjs.map +1 -1
  46. package/dist/transfer-service/markr/_handlers/transfer-asset.js +1 -1
  47. package/dist/transfer-service/markr/_handlers/transfer-asset.js.map +1 -1
  48. package/dist/transfer-service/markr/_schema.cjs +1 -1
  49. package/dist/transfer-service/markr/_schema.cjs.map +1 -1
  50. package/dist/transfer-service/markr/_schema.js +1 -1
  51. package/dist/transfer-service/markr/_schema.js.map +1 -1
  52. package/dist/transfer-service/markr/_utils.cjs +1 -1
  53. package/dist/transfer-service/markr/_utils.cjs.map +1 -1
  54. package/dist/transfer-service/markr/_utils.js +1 -1
  55. package/dist/transfer-service/markr/_utils.js.map +1 -1
  56. package/dist/transfer-service/markr/markr-service.cjs +1 -1
  57. package/dist/transfer-service/markr/markr-service.cjs.map +1 -1
  58. package/dist/transfer-service/markr/markr-service.d.cts +26 -0
  59. package/dist/transfer-service/markr/markr-service.d.ts +26 -0
  60. package/dist/transfer-service/markr/markr-service.js +1 -1
  61. package/dist/transfer-service/markr/markr-service.js.map +1 -1
  62. package/dist/transfer-service/markr/recurring/_api.cjs +2 -0
  63. package/dist/transfer-service/markr/recurring/_api.cjs.map +1 -0
  64. package/dist/transfer-service/markr/recurring/_api.js +2 -0
  65. package/dist/transfer-service/markr/recurring/_api.js.map +1 -0
  66. package/dist/transfer-service/markr/recurring/_chain-info.cjs +2 -0
  67. package/dist/transfer-service/markr/recurring/_chain-info.cjs.map +1 -0
  68. package/dist/transfer-service/markr/recurring/_chain-info.js +2 -0
  69. package/dist/transfer-service/markr/recurring/_chain-info.js.map +1 -0
  70. package/dist/transfer-service/markr/recurring/_eligibility.cjs +2 -0
  71. package/dist/transfer-service/markr/recurring/_eligibility.cjs.map +1 -0
  72. package/dist/transfer-service/markr/recurring/_eligibility.js +2 -0
  73. package/dist/transfer-service/markr/recurring/_eligibility.js.map +1 -0
  74. package/dist/transfer-service/markr/recurring/_frequency.cjs +2 -0
  75. package/dist/transfer-service/markr/recurring/_frequency.cjs.map +1 -0
  76. package/dist/transfer-service/markr/recurring/_frequency.d.cts +17 -0
  77. package/dist/transfer-service/markr/recurring/_frequency.d.ts +17 -0
  78. package/dist/transfer-service/markr/recurring/_frequency.js +2 -0
  79. package/dist/transfer-service/markr/recurring/_frequency.js.map +1 -0
  80. package/dist/transfer-service/markr/recurring/_namespace.cjs +2 -0
  81. package/dist/transfer-service/markr/recurring/_namespace.cjs.map +1 -0
  82. package/dist/transfer-service/markr/recurring/_namespace.js +2 -0
  83. package/dist/transfer-service/markr/recurring/_namespace.js.map +1 -0
  84. package/dist/transfer-service/markr/recurring/_schema.cjs +2 -0
  85. package/dist/transfer-service/markr/recurring/_schema.cjs.map +1 -0
  86. package/dist/transfer-service/markr/recurring/_schema.js +2 -0
  87. package/dist/transfer-service/markr/recurring/_schema.js.map +1 -0
  88. package/dist/transfer-service/markr/recurring/index.d.ts +2 -0
  89. package/dist/transfer-service/markr/recurring/types.cjs +2 -0
  90. package/dist/transfer-service/markr/recurring/types.cjs.map +1 -0
  91. package/dist/transfer-service/markr/recurring/types.d.cts +455 -0
  92. package/dist/transfer-service/markr/recurring/types.d.ts +455 -0
  93. package/dist/transfer-service/markr/recurring/types.js +2 -0
  94. package/dist/transfer-service/markr/recurring/types.js.map +1 -0
  95. package/dist/transfer-service/wrap-unwrap/_handlers/transfer-asset.cjs +1 -1
  96. package/dist/transfer-service/wrap-unwrap/_handlers/transfer-asset.js +1 -1
  97. package/dist/types/transfer-manager.d.cts +16 -0
  98. package/dist/types/transfer-manager.d.ts +16 -0
  99. package/dist/types/transfer.d.cts +8 -0
  100. package/dist/types/transfer.d.ts +8 -0
  101. package/package.json +3 -3
@@ -0,0 +1,455 @@
1
+ import { Chain } from "../../../types/chain.js";
2
+ import { Hex } from "../../../types/signer.js";
3
+ import { GasSettings } from "../../../types/service.js";
4
+ import { Address } from "viem";
5
+
6
+ //#region src/transfer-service/markr/recurring/types.d.ts
7
+ /**
8
+ * Frequency units accepted by Markr's `/recurring/quote` and `/recurring/orders` endpoints.
9
+ *
10
+ * @see https://orchestrator-docs.markr.io/#/paths/~1recurring~1quote/post
11
+ */
12
+ declare const RECURRING_FREQUENCY_UNITS: readonly ["minute", "hour", "day", "week", "month"];
13
+ type RecurringFrequencyUnit = (typeof RECURRING_FREQUENCY_UNITS)[number];
14
+ interface RecurringFrequency {
15
+ unit: RecurringFrequencyUnit;
16
+ /**
17
+ * Integer in `[1, 365]` (server-enforced upper bound). `validateFrequency`
18
+ * surfaces violations as `{ ok: false, reason: 'invalid-value' }`.
19
+ */
20
+ value: number;
21
+ }
22
+ /**
23
+ * Markr's "unlimited orders" sentinel. Sent to the server as `-1`, which the
24
+ * router expands to `uint256` max on-chain. Callers can also pass `Infinity`
25
+ * to {@link RecurringQuoteParams.numberOfOrders} for the same effect; the API
26
+ * helpers translate to `-1` at the wire boundary.
27
+ */
28
+ declare const RECURRING_UNLIMITED_ORDERS_SENTINEL = -1;
29
+ /**
30
+ * Status values emitted by Markr for a recurring schedule. Treated as a
31
+ * closed set — if Markr ever adds a new value server-side, the schema
32
+ * will reject it loudly so the SDK update gates rendering changes
33
+ * (instead of silently passing an unhandled state through to the UI).
34
+ *
35
+ * Mirrors the existing `TransferSignatureReason` enum pattern in
36
+ * `constants.ts`: PascalCase members with kebab/lowercase wire values.
37
+ */
38
+ declare enum RecurringOrderStatus {
39
+ Active = "active",
40
+ Completed = "completed",
41
+ Cancelled = "cancelled",
42
+ Paused = "paused"
43
+ }
44
+ interface RecurringOrderFailure {
45
+ /** 1-based index of the failed scheduled swap. */
46
+ executionIndex: number;
47
+ /** Reason strings supplied by the orchestrator (e.g. `"Slippage tolerance exceeded"`). */
48
+ reasons: ReadonlyArray<string>;
49
+ /** On-chain attempts before the execution was marked failed. */
50
+ tryCount: number;
51
+ /** Unix seconds. */
52
+ failedAt: number;
53
+ }
54
+ /**
55
+ * Server-side recurring-swap order returned by `GET /recurring/orders` and
56
+ * `POST /recurring/orders/{orderId}/cancel`.
57
+ *
58
+ * @see https://orchestrator-docs.markr.io/#/Recurring%20Swaps
59
+ */
60
+ interface RecurringOrder {
61
+ /**
62
+ * bytes32 hex (`0x` + 64 hex chars). Used as the path param for cancellation.
63
+ * Typed as a template-literal `0x`-prefixed string to catch the obvious
64
+ * "I forgot the `0x`" mistake at compile time; the wire-level regex check
65
+ * (in `markrCancelRecurringOrder`) enforces the full bytes32 shape.
66
+ */
67
+ orderId: `0x${string}`;
68
+ /** EVM wallet that created the schedule. */
69
+ owner: Address;
70
+ chainId: number;
71
+ tokenIn: Address;
72
+ tokenOut: Address;
73
+ /** Per-order input amount, in `tokenIn`'s smallest unit. */
74
+ amount: bigint;
75
+ /** -1 when unlimited; otherwise a positive integer (server-clamped to ≤ 365). */
76
+ numberOfOrders: number;
77
+ executedOrders: number;
78
+ /**
79
+ * `numberOfOrders - executedOrders` on finite schedules. `null` on
80
+ * unlimited schedules (`numberOfOrders === -1`) — they have no finite
81
+ * remainder to report. Per the Markr OpenAPI spec the field is
82
+ * nullable; the schema also normalizes `undefined` to `null` so a
83
+ * `=== null` check is sufficient.
84
+ */
85
+ remainingOrders: number | null;
86
+ frequency: RecurringFrequency;
87
+ /** `amount × numberOfOrders` — the ERC-20 allowance granted at setup. */
88
+ totalAmountIn: bigint;
89
+ /** Retry count for the *next* pending execution. `0` when none is pending. */
90
+ tryCount: number;
91
+ /** History of failed `executionIndex` values, newest last. */
92
+ failures: ReadonlyArray<RecurringOrderFailure>;
93
+ status: RecurringOrderStatus;
94
+ /** Unix seconds. */
95
+ createdAt: number;
96
+ /**
97
+ * Unix seconds. `null` once the schedule is completed / cancelled /
98
+ * inactive. Per the Markr OpenAPI spec this field is optional + nullable;
99
+ * the schema normalizes an omitted-field response to `null` so consumers
100
+ * can branch on a single `=== null` check.
101
+ */
102
+ nextExecutionAt: number | null;
103
+ /**
104
+ * Unix seconds when the order was cancelled; `null` otherwise. Populated
105
+ * with a number when `status === 'cancelled'`. Per the Markr OpenAPI spec
106
+ * this field is optional + nullable; the schema normalizes both wire
107
+ * shapes (`null` and omitted) to `null` for consumer ergonomics.
108
+ */
109
+ cancelledAt: number | null;
110
+ }
111
+ /**
112
+ * Known fee types emitted by Markr today. Open at runtime — the schema
113
+ * tolerates unknown values so a new fee category from the orchestrator doesn't
114
+ * fail quote parsing. See {@link RecurringOrderStatus} for the widening
115
+ * pattern.
116
+ */
117
+ type RecurringQuoteFeeType = "gas" | "recurring" | "protocol" | "bridge" | "slippage" | "swap" | "other" | (string & Record<never, never>);
118
+ interface RecurringQuoteFee {
119
+ type: RecurringQuoteFeeType;
120
+ name: string;
121
+ amount: bigint;
122
+ token: {
123
+ chainId: number;
124
+ address: Address;
125
+ };
126
+ /**
127
+ * Docs document `extra` as `boolean or object`. The boolean form is the
128
+ * legacy "additive one-time charge" flag (e.g. the one-time native
129
+ * schedule fee with `type: 'recurring'`); the object form is reserved
130
+ * for future structured metadata. Consumers should treat any truthy
131
+ * value as "additive — balance-check separately."
132
+ */
133
+ extra?: boolean | Record<string, unknown>;
134
+ }
135
+ interface RecurringQuoteResponse {
136
+ uuid: string;
137
+ chainId: number;
138
+ tokenIn: Address;
139
+ tokenOut: Address;
140
+ /** Per-order input. */
141
+ amount: bigint;
142
+ /** Server-side clamped value (may be 365 if the request was unlimited). */
143
+ numberOfOrders: number;
144
+ frequency: RecurringFrequency;
145
+ /** Server-derived from `frequency`. */
146
+ intervalSeconds: number;
147
+ /** `amount × numberOfOrders` — the ERC-20 allowance the caller must grant. */
148
+ totalAmountIn: bigint;
149
+ /** First-fill output estimate. */
150
+ amountOut: bigint;
151
+ /** First-fill `minAmountOut` (slippage applied). */
152
+ minAmountOut: bigint;
153
+ fees: ReadonlyArray<RecurringQuoteFee>;
154
+ /** Basis points. */
155
+ recommendedSlippage: number;
156
+ /** Unix seconds. */
157
+ expiredAt: number;
158
+ }
159
+ interface RecurringQuoteParams {
160
+ appId: string;
161
+ chainId: number;
162
+ tokenIn: Address;
163
+ tokenInDecimals: number;
164
+ tokenOut: Address;
165
+ tokenOutDecimals: number;
166
+ /**
167
+ * Per-order input in smallest unit. `bigint` only — matches the rest of the
168
+ * SDK's internal amount types (response amounts, `Quote.amountIn`, etc.).
169
+ * Callers holding a decimal string should coerce with `BigInt(s)` at the
170
+ * call site.
171
+ */
172
+ amount: bigint;
173
+ /**
174
+ * Number of orders. Accepts:
175
+ * - `Infinity` or `-1` — translated to the unlimited sentinel (`-1`) on the wire.
176
+ * - Integer in `[2, 365]` — Markr's documented finite bound.
177
+ *
178
+ * Anything else (`NaN`, `0`, `1`, negatives other than `-1`, non-integers,
179
+ * values > 365) throws `InvalidParamsError` at the SDK boundary so a
180
+ * misbehaving form parse (`parseInt('')` → `NaN`, or a stale "minimum is 1"
181
+ * assumption) can't silently become an unlimited schedule or a guaranteed
182
+ * server-side rejection.
183
+ */
184
+ numberOfOrders: number;
185
+ frequency: RecurringFrequency;
186
+ /** Basis points (matches `/quote` semantics). */
187
+ slippage?: number;
188
+ }
189
+ interface RecurringSwapParams {
190
+ uuid: string;
191
+ appId: string;
192
+ }
193
+ interface ListRecurringOrdersParams {
194
+ address: Address;
195
+ chainId?: number;
196
+ status?: RecurringOrderStatus;
197
+ }
198
+ interface ListRecurringOrdersResponse {
199
+ address: Address;
200
+ count: number;
201
+ orders: ReadonlyArray<RecurringOrder>;
202
+ }
203
+ /**
204
+ * Shared params for the three order-action execute methods
205
+ * ({@link RecurringNamespace.executeCancellation},
206
+ * {@link RecurringNamespace.executePause},
207
+ * {@link RecurringNamespace.executeUnpause}). The SDK derives the wire-level
208
+ * `chainId` from `sourceChain`, estimates gas via the chain's RPC, then signs
209
+ * and broadcasts via the configured `evmSigner`.
210
+ */
211
+ interface RecurringExecuteOrderActionParams {
212
+ /** See {@link RecurringOrder.orderId} for the shape. */
213
+ orderId: `0x${string}`;
214
+ /** Owner address of the schedule — must match the order's `owner`. */
215
+ address: Address;
216
+ /**
217
+ * Source chain the schedule lives on — pass the same `Chain` that backs
218
+ * `sourceChain` on the recurring order (the SDK reads `rpcUrl` + multicall
219
+ * for the on-chain gas estimate and uses `chainId` for the wire request).
220
+ */
221
+ sourceChain: Chain;
222
+ /** Optional fee-margin + 1559 overrides forwarded to the signed TX. */
223
+ gasSettings?: GasSettings;
224
+ /**
225
+ * Opaque payload forwarded unchanged onto the `step.signerContext` field
226
+ * seen by the configured `EvmSigner`. Lets consumers correlate the wallet
227
+ * prompt back to the specific cancel / pause / unpause request that
228
+ * produced it (e.g. UI slot id, display label) without relying on an
229
+ * action-type-keyed lookup map that two concurrent same-type actions
230
+ * could clobber.
231
+ */
232
+ signerContext?: unknown;
233
+ }
234
+ /**
235
+ * Params for {@link RecurringNamespace.executeFirstFill}. Replaces the
236
+ * pre-signer `prepareFirstFill` shape; the SDK now reads the on-chain
237
+ * allowance against `totalAmountIn`, signs an `approve` if needed (batched
238
+ * one-click when `evmSigner.signBatch` is available and the swap is
239
+ * same-chain), then signs and broadcasts the first-fill swap.
240
+ */
241
+ interface RecurringExecuteFirstFillParams {
242
+ /** Full recurring quote — carries `uuid`, `totalAmountIn`, `expiredAt`. */
243
+ quote: RecurringQuoteResponse;
244
+ /** EVM address creating the schedule (and signing the first fill). */
245
+ fromAddress: Address;
246
+ /**
247
+ * Source chain — same `Chain` used to obtain the recurring quote. The SDK
248
+ * reads `rpcUrl` for allowance + gas calls; `chainId` is cross-checked
249
+ * against `quote.chainId` to catch obvious wiring mistakes.
250
+ */
251
+ sourceChain: Chain;
252
+ /** Optional fee-margin + 1559 overrides. */
253
+ gasSettings?: GasSettings;
254
+ /**
255
+ * Mirrors the same flag on `TransferService.transferAsset`: when the
256
+ * one-click batch (approval + first-fill) is attempted and the consumer's
257
+ * wallet rejects the batch, fall back to two sequential signatures
258
+ * (`approve`, then `swap`) instead of bubbling the batch error up.
259
+ */
260
+ fallbackToDefaultOnBatchFailure?: boolean;
261
+ /**
262
+ * Opaque payload forwarded unchanged onto the `step.signerContext` field
263
+ * seen by the configured `EvmSigner` for both the optional approval step
264
+ * and the first-fill swap step. See
265
+ * {@link RecurringExecuteOrderActionParams.signerContext}.
266
+ */
267
+ signerContext?: unknown;
268
+ }
269
+ /** Result of any `recurring.execute*` method — broadcast TX hash. */
270
+ interface RecurringExecuteResult {
271
+ txHash: Hex;
272
+ }
273
+ interface RecurringChainInfoEntry {
274
+ /** Server-published lower bound for `intervalSeconds` (today: 300s on enabled chains). */
275
+ minFrequencySeconds: number;
276
+ supportedTokens: ReadonlyArray<{
277
+ address: Address;
278
+ /**
279
+ * Smallest-unit decimal string — must be `BigInt()`-parseable (i.e.
280
+ * matches `/^\d+$/`). The Zod schema enforces this on the wire, but the
281
+ * TS type alone is plain `string`; consumers constructing this map by
282
+ * hand (caching, tests) should pass a digits-only decimal string or
283
+ * `BigInt(minimumAmount)` will throw downstream in `checkEligibility`.
284
+ */
285
+ minimumAmount: string;
286
+ }>;
287
+ }
288
+ /**
289
+ * Cached `/info/chains` recurring metadata keyed by EVM chainId. SVM chains
290
+ * are omitted — Markr supports recurring on same-chain EVM only.
291
+ */
292
+ type RecurringChainInfoMap = ReadonlyMap<number, RecurringChainInfoEntry>;
293
+ /**
294
+ * Reasons surfaced when {@link checkRecurringEligibility} returns
295
+ * `{ eligible: false, … }`. Mirrors the existing `TransferSignatureReason`
296
+ * enum pattern (PascalCase member, kebab-case wire value) so external
297
+ * consumers comparing the raw string still match.
298
+ */
299
+ declare enum RecurringEligibilityReason {
300
+ CrossChain = "cross-chain",
301
+ UnsupportedSourceChain = "unsupported-source-chain",
302
+ UnsupportedToken = "unsupported-token",
303
+ NoEvmAddress = "no-evm-address",
304
+ AmountBelowMinimum = "amount-below-minimum"
305
+ }
306
+ type RecurringEligibility = {
307
+ eligible: true;
308
+ minimumAmount: string;
309
+ minIntervalSeconds: number;
310
+ } | {
311
+ eligible: false;
312
+ reason: RecurringEligibilityReason.AmountBelowMinimum;
313
+ minimumAmount: string;
314
+ } | {
315
+ eligible: false;
316
+ reason: Exclude<RecurringEligibilityReason, RecurringEligibilityReason.AmountBelowMinimum>;
317
+ };
318
+ interface CheckRecurringEligibilityParams {
319
+ recurringChainInfo: RecurringChainInfoMap;
320
+ fromTokenAddress: Address;
321
+ toTokenAddress: Address;
322
+ sourceChainId: number;
323
+ targetChainId: number;
324
+ ownerAddress?: Address;
325
+ /** Per-order amount; when present, enables the `amount-below-minimum` check. */
326
+ amount?: bigint;
327
+ }
328
+ /**
329
+ * Params passed to `RecurringNamespace.checkEligibility`. Same as
330
+ * `CheckRecurringEligibilityParams` minus the chain-info map, which the
331
+ * namespace closure injects.
332
+ */
333
+ type RecurringNamespaceCheckEligibilityParams = Omit<CheckRecurringEligibilityParams, "recurringChainInfo">;
334
+ /**
335
+ * Params passed to `RecurringNamespace.quote`. Same as `RecurringQuoteParams`
336
+ * minus `appId`, which the namespace closure injects.
337
+ */
338
+ type RecurringNamespaceQuoteParams = Omit<RecurringQuoteParams, "appId">;
339
+ /**
340
+ * High-level wrapper exposed as `MarkrService.recurring`. Methods curry
341
+ * `apiOptions`, `appId`, and the cached `recurringChainInfo` so callers only
342
+ * pass per-call inputs.
343
+ */
344
+ interface RecurringNamespace {
345
+ /** POST `/recurring/quote` — full quote with `totalAmountIn`, fees, expiry, uuid. */
346
+ quote(props: RecurringNamespaceQuoteParams): Promise<RecurringQuoteResponse>;
347
+ /**
348
+ * Creates the schedule on-chain by signing and broadcasting the first
349
+ * `/recurring/swap` fill via the configured `evmSigner`. Mirrors
350
+ * `TransferService.transferAsset`:
351
+ *
352
+ * 1. Reads on-chain `allowance(tokenIn → router)` against `quote.totalAmountIn`.
353
+ * 2. If allowance is short, builds an `approve(router, totalAmountIn)` TX.
354
+ * When the consumer's signer exposes `signBatch`, the SDK attempts a
355
+ * one-click batch (approve + swap) — set
356
+ * {@link RecurringExecuteFirstFillParams.fallbackToDefaultOnBatchFailure}
357
+ * to fall back to two sequential signatures if the wallet rejects the
358
+ * batch.
359
+ * 3. Estimates gas (with `gasSettings.estimateGasMarginBps` margin) for
360
+ * each TX before signing, and dispatches the signed serialized TX via
361
+ * the chain's RPC.
362
+ *
363
+ * Quote-expiry guard mirrors the previous `prepareFirstFill` behavior —
364
+ * `quote.expiredAt <= now` throws `InvalidParamsError(QUOTE_EXPIRED)` at
365
+ * the SDK boundary before any HTTP / on-chain call.
366
+ *
367
+ * Returns the broadcast first-fill TX hash; the schedule transitions to
368
+ * `'active'` once Markr observes the on-chain event (poll `listOrders`).
369
+ */
370
+ executeFirstFill(props: RecurringExecuteFirstFillParams): Promise<RecurringExecuteResult>;
371
+ /**
372
+ * GET `/recurring/orders?address=…&chainId?=…&status?=…` — returns the
373
+ * full response (`{ address, count, orders }`) so callers can render the
374
+ * server-echoed `address` (e.g. confirming the queried wallet matches the
375
+ * current EVM signer) and `count` (pagination / "you have N schedules"
376
+ * affordances) without an extra lookup. Consumers that only care about the
377
+ * orders array can destructure: `const { orders } = await listOrders(…)`.
378
+ */
379
+ listOrders(props: ListRecurringOrdersParams): Promise<ListRecurringOrdersResponse>;
380
+ /**
381
+ * Cancels the recurring schedule identified by `orderId`: fetches the
382
+ * `/recurring/orders/{orderId}/cancel` calldata, estimates gas, then signs
383
+ * and broadcasts via the configured `evmSigner`. The schedule transitions
384
+ * to `status: 'cancelled'` only once the TX confirms and Markr observes
385
+ * the on-chain event.
386
+ *
387
+ * Eligibility: only `'active'` and `'paused'` orders can be cancelled per
388
+ * Markr's docs. An attempt to cancel a `'completed'` order surfaces as
389
+ * `HttpError(400)` from the orchestrator before signing.
390
+ */
391
+ executeCancellation(props: RecurringExecuteOrderActionParams): Promise<RecurringExecuteResult>;
392
+ /**
393
+ * Pauses the recurring schedule identified by `orderId`: fetches the
394
+ * `/recurring/orders/{orderId}/pause` calldata, estimates gas, then signs
395
+ * and broadcasts via the configured `evmSigner`. The schedule transitions
396
+ * to `status: 'paused'` only once the TX confirms and Markr observes the
397
+ * on-chain event.
398
+ *
399
+ * Eligibility: only `'active'` orders can be paused per Markr's docs.
400
+ * Attempting to pause a non-`active` order surfaces as `HttpError(400)`.
401
+ *
402
+ * Pausing preserves the schedule's existing ERC-20 allowance — when the
403
+ * user later unpauses, no re-approval and no new native schedule fee are
404
+ * required (this is the key UX benefit of pause over cancel-and-recreate).
405
+ *
406
+ * @see https://orchestrator-docs.markr.io/#tag/Recurring-Swaps/paths/~1recurring~1orders~1{orderId}~1pause/post
407
+ */
408
+ executePause(props: RecurringExecuteOrderActionParams): Promise<RecurringExecuteResult>;
409
+ /**
410
+ * Unpauses (resumes) the recurring schedule identified by `orderId`:
411
+ * fetches the `/recurring/orders/{orderId}/unpause` calldata, estimates
412
+ * gas, then signs and broadcasts via the configured `evmSigner`. The
413
+ * schedule transitions back to `status: 'active'` only once the TX
414
+ * confirms and Markr observes the on-chain event.
415
+ *
416
+ * Eligibility: only `'paused'` orders can be unpaused per Markr's docs.
417
+ * Attempting to unpause a non-`paused` order surfaces as `HttpError(400)`.
418
+ *
419
+ * Resumes execution from where the schedule left off — remaining fills
420
+ * continue on the original `frequency` cadence. The orchestrator recomputes
421
+ * `nextExecutionAt` after the TX confirms.
422
+ *
423
+ * @see https://orchestrator-docs.markr.io/#tag/Recurring-Swaps/paths/~1recurring~1orders~1{orderId}~1unpause/post
424
+ */
425
+ executeUnpause(props: RecurringExecuteOrderActionParams): Promise<RecurringExecuteResult>;
426
+ /**
427
+ * Pure (no fetch) — uses the cached `/info/chains` recurring metadata.
428
+ *
429
+ * **Covers:** chain support, token support, EVM-address presence, same-chain
430
+ * (cross-chain rejected), and per-order minimum (when `amount` is passed —
431
+ * failure carries `minimumAmount`).
432
+ *
433
+ * **Does NOT cover wallet balance.** This helper has no wallet/RPC context.
434
+ * Checking that the user holds `amount × numberOfOrders` of `tokenIn` (plus
435
+ * native gas for the first fill) is the consumer's responsibility, same as
436
+ * the one-shot swap flow. There is no `InsufficientBalance` reason on
437
+ * {@link RecurringEligibilityReason} by design.
438
+ *
439
+ * **Does NOT cover post-fill failures.** Once a schedule is live, on-chain
440
+ * reverts (slippage, runtime insufficient balance, etc.) surface server-side
441
+ * as open-ended strings on `RecurringOrder.failures[].reasons` — substring-
442
+ * match those for client-driven auto-cancel (AC4 pattern) and call
443
+ * {@link RecurringNamespace.prepareCancellation} when applicable.
444
+ *
445
+ * **Does NOT cover server-side quote rejection.** Slippage, target-token
446
+ * unsupported, liquidity, etc. are decided at `/recurring/quote` time and
447
+ * surface as `HttpError` from {@link RecurringNamespace.quote}.
448
+ */
449
+ checkEligibility(props: RecurringNamespaceCheckEligibilityParams): RecurringEligibility;
450
+ /** Returns the cached `/info/chains` recurring metadata. */
451
+ getRecurringChainInfo(): RecurringChainInfoMap;
452
+ }
453
+ //#endregion
454
+ export { CheckRecurringEligibilityParams, ListRecurringOrdersParams, ListRecurringOrdersResponse, RECURRING_FREQUENCY_UNITS, RECURRING_UNLIMITED_ORDERS_SENTINEL, RecurringChainInfoEntry, RecurringChainInfoMap, RecurringEligibility, RecurringEligibilityReason, RecurringExecuteFirstFillParams, RecurringExecuteOrderActionParams, RecurringExecuteResult, RecurringFrequency, RecurringFrequencyUnit, RecurringNamespace, RecurringNamespaceCheckEligibilityParams, RecurringNamespaceQuoteParams, RecurringOrder, RecurringOrderFailure, RecurringOrderStatus, RecurringQuoteFee, RecurringQuoteFeeType, RecurringQuoteParams, RecurringQuoteResponse, RecurringSwapParams };
455
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,2 @@
1
+ const e=[`minute`,`hour`,`day`,`week`,`month`],t=-1;let n=function(e){return e.Active=`active`,e.Completed=`completed`,e.Cancelled=`cancelled`,e.Paused=`paused`,e}({}),r=function(e){return e.CrossChain=`cross-chain`,e.UnsupportedSourceChain=`unsupported-source-chain`,e.UnsupportedToken=`unsupported-token`,e.NoEvmAddress=`no-evm-address`,e.AmountBelowMinimum=`amount-below-minimum`,e}({});export{e as RECURRING_FREQUENCY_UNITS,t as RECURRING_UNLIMITED_ORDERS_SENTINEL,r as RecurringEligibilityReason,n as RecurringOrderStatus};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../../src/transfer-service/markr/recurring/types.ts"],"sourcesContent":["import type { Address as EvmAddress } from 'viem';\nimport type { Chain } from '../../../types/chain';\nimport type { GasSettings } from '../../../types/service';\nimport type { Hex } from '../../../types/signer';\n\n/**\n * Frequency units accepted by Markr's `/recurring/quote` and `/recurring/orders` endpoints.\n *\n * @see https://orchestrator-docs.markr.io/#/paths/~1recurring~1quote/post\n */\nexport const RECURRING_FREQUENCY_UNITS = ['minute', 'hour', 'day', 'week', 'month'] as const;\n\nexport type RecurringFrequencyUnit = (typeof RECURRING_FREQUENCY_UNITS)[number];\n\nexport interface RecurringFrequency {\n unit: RecurringFrequencyUnit;\n /**\n * Integer in `[1, 365]` (server-enforced upper bound). `validateFrequency`\n * surfaces violations as `{ ok: false, reason: 'invalid-value' }`.\n */\n value: number;\n}\n\n/**\n * Markr's \"unlimited orders\" sentinel. Sent to the server as `-1`, which the\n * router expands to `uint256` max on-chain. Callers can also pass `Infinity`\n * to {@link RecurringQuoteParams.numberOfOrders} for the same effect; the API\n * helpers translate to `-1` at the wire boundary.\n */\nexport const RECURRING_UNLIMITED_ORDERS_SENTINEL = -1;\n\n/**\n * Status values emitted by Markr for a recurring schedule. Treated as a\n * closed set — if Markr ever adds a new value server-side, the schema\n * will reject it loudly so the SDK update gates rendering changes\n * (instead of silently passing an unhandled state through to the UI).\n *\n * Mirrors the existing `TransferSignatureReason` enum pattern in\n * `constants.ts`: PascalCase members with kebab/lowercase wire values.\n */\nexport enum RecurringOrderStatus {\n Active = 'active',\n Completed = 'completed',\n Cancelled = 'cancelled',\n Paused = 'paused',\n}\n\nexport interface RecurringOrderFailure {\n /** 1-based index of the failed scheduled swap. */\n executionIndex: number;\n /** Reason strings supplied by the orchestrator (e.g. `\"Slippage tolerance exceeded\"`). */\n reasons: ReadonlyArray<string>;\n /** On-chain attempts before the execution was marked failed. */\n tryCount: number;\n /** Unix seconds. */\n failedAt: number;\n}\n\n/**\n * Server-side recurring-swap order returned by `GET /recurring/orders` and\n * `POST /recurring/orders/{orderId}/cancel`.\n *\n * @see https://orchestrator-docs.markr.io/#/Recurring%20Swaps\n */\nexport interface RecurringOrder {\n /**\n * bytes32 hex (`0x` + 64 hex chars). Used as the path param for cancellation.\n * Typed as a template-literal `0x`-prefixed string to catch the obvious\n * \"I forgot the `0x`\" mistake at compile time; the wire-level regex check\n * (in `markrCancelRecurringOrder`) enforces the full bytes32 shape.\n */\n orderId: `0x${string}`;\n /** EVM wallet that created the schedule. */\n owner: EvmAddress;\n chainId: number;\n tokenIn: EvmAddress;\n tokenOut: EvmAddress;\n /** Per-order input amount, in `tokenIn`'s smallest unit. */\n amount: bigint;\n /** -1 when unlimited; otherwise a positive integer (server-clamped to ≤ 365). */\n numberOfOrders: number;\n executedOrders: number;\n /**\n * `numberOfOrders - executedOrders` on finite schedules. `null` on\n * unlimited schedules (`numberOfOrders === -1`) — they have no finite\n * remainder to report. Per the Markr OpenAPI spec the field is\n * nullable; the schema also normalizes `undefined` to `null` so a\n * `=== null` check is sufficient.\n */\n remainingOrders: number | null;\n frequency: RecurringFrequency;\n /** `amount × numberOfOrders` — the ERC-20 allowance granted at setup. */\n totalAmountIn: bigint;\n /** Retry count for the *next* pending execution. `0` when none is pending. */\n tryCount: number;\n /** History of failed `executionIndex` values, newest last. */\n failures: ReadonlyArray<RecurringOrderFailure>;\n status: RecurringOrderStatus;\n /** Unix seconds. */\n createdAt: number;\n /**\n * Unix seconds. `null` once the schedule is completed / cancelled /\n * inactive. Per the Markr OpenAPI spec this field is optional + nullable;\n * the schema normalizes an omitted-field response to `null` so consumers\n * can branch on a single `=== null` check.\n */\n nextExecutionAt: number | null;\n /**\n * Unix seconds when the order was cancelled; `null` otherwise. Populated\n * with a number when `status === 'cancelled'`. Per the Markr OpenAPI spec\n * this field is optional + nullable; the schema normalizes both wire\n * shapes (`null` and omitted) to `null` for consumer ergonomics.\n */\n cancelledAt: number | null;\n}\n\n/**\n * Known fee types emitted by Markr today. Open at runtime — the schema\n * tolerates unknown values so a new fee category from the orchestrator doesn't\n * fail quote parsing. See {@link RecurringOrderStatus} for the widening\n * pattern.\n */\nexport type RecurringQuoteFeeType =\n | 'gas'\n | 'recurring'\n | 'protocol'\n | 'bridge'\n | 'slippage'\n | 'swap'\n | 'other'\n // See `RecurringOrderStatus` for why `Record<never, never>` replaces `{}`.\n | (string & Record<never, never>);\n\nexport interface RecurringQuoteFee {\n type: RecurringQuoteFeeType;\n name: string;\n amount: bigint;\n token: { chainId: number; address: EvmAddress };\n /**\n * Docs document `extra` as `boolean or object`. The boolean form is the\n * legacy \"additive one-time charge\" flag (e.g. the one-time native\n * schedule fee with `type: 'recurring'`); the object form is reserved\n * for future structured metadata. Consumers should treat any truthy\n * value as \"additive — balance-check separately.\"\n */\n extra?: boolean | Record<string, unknown>;\n}\n\nexport interface RecurringQuoteResponse {\n uuid: string;\n chainId: number;\n tokenIn: EvmAddress;\n tokenOut: EvmAddress;\n /** Per-order input. */\n amount: bigint;\n /** Server-side clamped value (may be 365 if the request was unlimited). */\n numberOfOrders: number;\n frequency: RecurringFrequency;\n /** Server-derived from `frequency`. */\n intervalSeconds: number;\n /** `amount × numberOfOrders` — the ERC-20 allowance the caller must grant. */\n totalAmountIn: bigint;\n /** First-fill output estimate. */\n amountOut: bigint;\n /** First-fill `minAmountOut` (slippage applied). */\n minAmountOut: bigint;\n fees: ReadonlyArray<RecurringQuoteFee>;\n /** Basis points. */\n recommendedSlippage: number;\n /** Unix seconds. */\n expiredAt: number;\n}\n\nexport interface RecurringQuoteParams {\n appId: string;\n chainId: number;\n tokenIn: EvmAddress;\n tokenInDecimals: number;\n tokenOut: EvmAddress;\n tokenOutDecimals: number;\n /**\n * Per-order input in smallest unit. `bigint` only — matches the rest of the\n * SDK's internal amount types (response amounts, `Quote.amountIn`, etc.).\n * Callers holding a decimal string should coerce with `BigInt(s)` at the\n * call site.\n */\n amount: bigint;\n /**\n * Number of orders. Accepts:\n * - `Infinity` or `-1` — translated to the unlimited sentinel (`-1`) on the wire.\n * - Integer in `[2, 365]` — Markr's documented finite bound.\n *\n * Anything else (`NaN`, `0`, `1`, negatives other than `-1`, non-integers,\n * values > 365) throws `InvalidParamsError` at the SDK boundary so a\n * misbehaving form parse (`parseInt('')` → `NaN`, or a stale \"minimum is 1\"\n * assumption) can't silently become an unlimited schedule or a guaranteed\n * server-side rejection.\n */\n numberOfOrders: number;\n frequency: RecurringFrequency;\n /** Basis points (matches `/quote` semantics). */\n slippage?: number;\n}\n\nexport interface RecurringSwapParams {\n uuid: string;\n appId: string;\n}\n\nexport interface ListRecurringOrdersParams {\n address: EvmAddress;\n chainId?: number;\n status?: RecurringOrderStatus;\n}\n\nexport interface ListRecurringOrdersResponse {\n address: EvmAddress;\n count: number;\n orders: ReadonlyArray<RecurringOrder>;\n}\n\n/**\n * Wire-level params for the internal `_api.ts` cancel/pause/unpause helpers\n * (`markrPrepareCancellation` etc.). Public consumers reach the same endpoints\n * via {@link RecurringNamespace.executeCancellation}/`executePause`/\n * `executeUnpause`, which take {@link RecurringExecuteOrderActionParams}\n * instead and derive `chainId` from the passed `sourceChain`.\n */\nexport interface RecurringOrderActionApiParams {\n /** See {@link RecurringOrder.orderId} for the shape. */\n orderId: `0x${string}`;\n address: EvmAddress;\n /**\n * Chain the schedule lives on — required by Markr's\n * `POST /recurring/orders/{orderId}/{action}` endpoints (the orchestrator\n * scopes orderIds per chain, so the same bytes32 could in principle exist\n * on multiple chains).\n */\n chainId: number;\n}\n\n/**\n * Shared params for the three order-action execute methods\n * ({@link RecurringNamespace.executeCancellation},\n * {@link RecurringNamespace.executePause},\n * {@link RecurringNamespace.executeUnpause}). The SDK derives the wire-level\n * `chainId` from `sourceChain`, estimates gas via the chain's RPC, then signs\n * and broadcasts via the configured `evmSigner`.\n */\nexport interface RecurringExecuteOrderActionParams {\n /** See {@link RecurringOrder.orderId} for the shape. */\n orderId: `0x${string}`;\n /** Owner address of the schedule — must match the order's `owner`. */\n address: EvmAddress;\n /**\n * Source chain the schedule lives on — pass the same `Chain` that backs\n * `sourceChain` on the recurring order (the SDK reads `rpcUrl` + multicall\n * for the on-chain gas estimate and uses `chainId` for the wire request).\n */\n sourceChain: Chain;\n /** Optional fee-margin + 1559 overrides forwarded to the signed TX. */\n gasSettings?: GasSettings;\n /**\n * Opaque payload forwarded unchanged onto the `step.signerContext` field\n * seen by the configured `EvmSigner`. Lets consumers correlate the wallet\n * prompt back to the specific cancel / pause / unpause request that\n * produced it (e.g. UI slot id, display label) without relying on an\n * action-type-keyed lookup map that two concurrent same-type actions\n * could clobber.\n */\n signerContext?: unknown;\n}\n\n/**\n * Params for {@link RecurringNamespace.executeFirstFill}. Replaces the\n * pre-signer `prepareFirstFill` shape; the SDK now reads the on-chain\n * allowance against `totalAmountIn`, signs an `approve` if needed (batched\n * one-click when `evmSigner.signBatch` is available and the swap is\n * same-chain), then signs and broadcasts the first-fill swap.\n */\nexport interface RecurringExecuteFirstFillParams {\n /** Full recurring quote — carries `uuid`, `totalAmountIn`, `expiredAt`. */\n quote: RecurringQuoteResponse;\n /** EVM address creating the schedule (and signing the first fill). */\n fromAddress: EvmAddress;\n /**\n * Source chain — same `Chain` used to obtain the recurring quote. The SDK\n * reads `rpcUrl` for allowance + gas calls; `chainId` is cross-checked\n * against `quote.chainId` to catch obvious wiring mistakes.\n */\n sourceChain: Chain;\n /** Optional fee-margin + 1559 overrides. */\n gasSettings?: GasSettings;\n /**\n * Mirrors the same flag on `TransferService.transferAsset`: when the\n * one-click batch (approval + first-fill) is attempted and the consumer's\n * wallet rejects the batch, fall back to two sequential signatures\n * (`approve`, then `swap`) instead of bubbling the batch error up.\n */\n fallbackToDefaultOnBatchFailure?: boolean;\n /**\n * Opaque payload forwarded unchanged onto the `step.signerContext` field\n * seen by the configured `EvmSigner` for both the optional approval step\n * and the first-fill swap step. See\n * {@link RecurringExecuteOrderActionParams.signerContext}.\n */\n signerContext?: unknown;\n}\n\n/** Result of any `recurring.execute*` method — broadcast TX hash. */\nexport interface RecurringExecuteResult {\n txHash: Hex;\n}\n\nexport interface RecurringChainInfoEntry {\n /** Server-published lower bound for `intervalSeconds` (today: 300s on enabled chains). */\n minFrequencySeconds: number;\n supportedTokens: ReadonlyArray<{\n address: EvmAddress;\n /**\n * Smallest-unit decimal string — must be `BigInt()`-parseable (i.e.\n * matches `/^\\d+$/`). The Zod schema enforces this on the wire, but the\n * TS type alone is plain `string`; consumers constructing this map by\n * hand (caching, tests) should pass a digits-only decimal string or\n * `BigInt(minimumAmount)` will throw downstream in `checkEligibility`.\n */\n minimumAmount: string;\n }>;\n}\n\n/**\n * Cached `/info/chains` recurring metadata keyed by EVM chainId. SVM chains\n * are omitted — Markr supports recurring on same-chain EVM only.\n */\nexport type RecurringChainInfoMap = ReadonlyMap<number, RecurringChainInfoEntry>;\n\n/**\n * Reasons surfaced when {@link checkRecurringEligibility} returns\n * `{ eligible: false, … }`. Mirrors the existing `TransferSignatureReason`\n * enum pattern (PascalCase member, kebab-case wire value) so external\n * consumers comparing the raw string still match.\n */\nexport enum RecurringEligibilityReason {\n CrossChain = 'cross-chain',\n UnsupportedSourceChain = 'unsupported-source-chain',\n UnsupportedToken = 'unsupported-token',\n NoEvmAddress = 'no-evm-address',\n AmountBelowMinimum = 'amount-below-minimum',\n}\n\nexport type RecurringEligibility =\n | { eligible: true; minimumAmount: string; minIntervalSeconds: number }\n // `AmountBelowMinimum` carries the floor so error UIs can say \"Min is X\"\n // without a second `getRecurringChainInfo()` lookup. The value is the same\n // smallest-unit decimal string as the success branch's `minimumAmount`.\n | { eligible: false; reason: RecurringEligibilityReason.AmountBelowMinimum; minimumAmount: string }\n | { eligible: false; reason: Exclude<RecurringEligibilityReason, RecurringEligibilityReason.AmountBelowMinimum> };\n\nexport interface CheckRecurringEligibilityParams {\n recurringChainInfo: RecurringChainInfoMap;\n fromTokenAddress: EvmAddress;\n toTokenAddress: EvmAddress;\n sourceChainId: number;\n targetChainId: number;\n ownerAddress?: EvmAddress;\n /** Per-order amount; when present, enables the `amount-below-minimum` check. */\n amount?: bigint;\n}\n\n/**\n * Params passed to `RecurringNamespace.checkEligibility`. Same as\n * `CheckRecurringEligibilityParams` minus the chain-info map, which the\n * namespace closure injects.\n */\nexport type RecurringNamespaceCheckEligibilityParams = Omit<CheckRecurringEligibilityParams, 'recurringChainInfo'>;\n\n/**\n * Params passed to `RecurringNamespace.quote`. Same as `RecurringQuoteParams`\n * minus `appId`, which the namespace closure injects.\n */\nexport type RecurringNamespaceQuoteParams = Omit<RecurringQuoteParams, 'appId'>;\n\n/**\n * High-level wrapper exposed as `MarkrService.recurring`. Methods curry\n * `apiOptions`, `appId`, and the cached `recurringChainInfo` so callers only\n * pass per-call inputs.\n */\nexport interface RecurringNamespace {\n /** POST `/recurring/quote` — full quote with `totalAmountIn`, fees, expiry, uuid. */\n quote(props: RecurringNamespaceQuoteParams): Promise<RecurringQuoteResponse>;\n\n /**\n * Creates the schedule on-chain by signing and broadcasting the first\n * `/recurring/swap` fill via the configured `evmSigner`. Mirrors\n * `TransferService.transferAsset`:\n *\n * 1. Reads on-chain `allowance(tokenIn → router)` against `quote.totalAmountIn`.\n * 2. If allowance is short, builds an `approve(router, totalAmountIn)` TX.\n * When the consumer's signer exposes `signBatch`, the SDK attempts a\n * one-click batch (approve + swap) — set\n * {@link RecurringExecuteFirstFillParams.fallbackToDefaultOnBatchFailure}\n * to fall back to two sequential signatures if the wallet rejects the\n * batch.\n * 3. Estimates gas (with `gasSettings.estimateGasMarginBps` margin) for\n * each TX before signing, and dispatches the signed serialized TX via\n * the chain's RPC.\n *\n * Quote-expiry guard mirrors the previous `prepareFirstFill` behavior —\n * `quote.expiredAt <= now` throws `InvalidParamsError(QUOTE_EXPIRED)` at\n * the SDK boundary before any HTTP / on-chain call.\n *\n * Returns the broadcast first-fill TX hash; the schedule transitions to\n * `'active'` once Markr observes the on-chain event (poll `listOrders`).\n */\n executeFirstFill(props: RecurringExecuteFirstFillParams): Promise<RecurringExecuteResult>;\n\n /**\n * GET `/recurring/orders?address=…&chainId?=…&status?=…` — returns the\n * full response (`{ address, count, orders }`) so callers can render the\n * server-echoed `address` (e.g. confirming the queried wallet matches the\n * current EVM signer) and `count` (pagination / \"you have N schedules\"\n * affordances) without an extra lookup. Consumers that only care about the\n * orders array can destructure: `const { orders } = await listOrders(…)`.\n */\n listOrders(props: ListRecurringOrdersParams): Promise<ListRecurringOrdersResponse>;\n\n /**\n * Cancels the recurring schedule identified by `orderId`: fetches the\n * `/recurring/orders/{orderId}/cancel` calldata, estimates gas, then signs\n * and broadcasts via the configured `evmSigner`. The schedule transitions\n * to `status: 'cancelled'` only once the TX confirms and Markr observes\n * the on-chain event.\n *\n * Eligibility: only `'active'` and `'paused'` orders can be cancelled per\n * Markr's docs. An attempt to cancel a `'completed'` order surfaces as\n * `HttpError(400)` from the orchestrator before signing.\n */\n executeCancellation(props: RecurringExecuteOrderActionParams): Promise<RecurringExecuteResult>;\n\n /**\n * Pauses the recurring schedule identified by `orderId`: fetches the\n * `/recurring/orders/{orderId}/pause` calldata, estimates gas, then signs\n * and broadcasts via the configured `evmSigner`. The schedule transitions\n * to `status: 'paused'` only once the TX confirms and Markr observes the\n * on-chain event.\n *\n * Eligibility: only `'active'` orders can be paused per Markr's docs.\n * Attempting to pause a non-`active` order surfaces as `HttpError(400)`.\n *\n * Pausing preserves the schedule's existing ERC-20 allowance — when the\n * user later unpauses, no re-approval and no new native schedule fee are\n * required (this is the key UX benefit of pause over cancel-and-recreate).\n *\n * @see https://orchestrator-docs.markr.io/#tag/Recurring-Swaps/paths/~1recurring~1orders~1{orderId}~1pause/post\n */\n executePause(props: RecurringExecuteOrderActionParams): Promise<RecurringExecuteResult>;\n\n /**\n * Unpauses (resumes) the recurring schedule identified by `orderId`:\n * fetches the `/recurring/orders/{orderId}/unpause` calldata, estimates\n * gas, then signs and broadcasts via the configured `evmSigner`. The\n * schedule transitions back to `status: 'active'` only once the TX\n * confirms and Markr observes the on-chain event.\n *\n * Eligibility: only `'paused'` orders can be unpaused per Markr's docs.\n * Attempting to unpause a non-`paused` order surfaces as `HttpError(400)`.\n *\n * Resumes execution from where the schedule left off — remaining fills\n * continue on the original `frequency` cadence. The orchestrator recomputes\n * `nextExecutionAt` after the TX confirms.\n *\n * @see https://orchestrator-docs.markr.io/#tag/Recurring-Swaps/paths/~1recurring~1orders~1{orderId}~1unpause/post\n */\n executeUnpause(props: RecurringExecuteOrderActionParams): Promise<RecurringExecuteResult>;\n\n /**\n * Pure (no fetch) — uses the cached `/info/chains` recurring metadata.\n *\n * **Covers:** chain support, token support, EVM-address presence, same-chain\n * (cross-chain rejected), and per-order minimum (when `amount` is passed —\n * failure carries `minimumAmount`).\n *\n * **Does NOT cover wallet balance.** This helper has no wallet/RPC context.\n * Checking that the user holds `amount × numberOfOrders` of `tokenIn` (plus\n * native gas for the first fill) is the consumer's responsibility, same as\n * the one-shot swap flow. There is no `InsufficientBalance` reason on\n * {@link RecurringEligibilityReason} by design.\n *\n * **Does NOT cover post-fill failures.** Once a schedule is live, on-chain\n * reverts (slippage, runtime insufficient balance, etc.) surface server-side\n * as open-ended strings on `RecurringOrder.failures[].reasons` — substring-\n * match those for client-driven auto-cancel (AC4 pattern) and call\n * {@link RecurringNamespace.prepareCancellation} when applicable.\n *\n * **Does NOT cover server-side quote rejection.** Slippage, target-token\n * unsupported, liquidity, etc. are decided at `/recurring/quote` time and\n * surface as `HttpError` from {@link RecurringNamespace.quote}.\n */\n checkEligibility(props: RecurringNamespaceCheckEligibilityParams): RecurringEligibility;\n\n /** Returns the cached `/info/chains` recurring metadata. */\n getRecurringChainInfo(): RecurringChainInfoMap;\n}\n"],"mappings":"AAUA,MAAa,EAA4B,CAAC,SAAU,OAAQ,MAAO,OAAQ,QAAQ,CAmBtE,EAAsC,GAWnD,IAAY,EAAL,SAAA,EAAA,OACL,GAAA,OAAA,SACA,EAAA,UAAA,YACA,EAAA,UAAA,YACA,EAAA,OAAA,eACD,CAySW,EAAL,SAAA,EAAA,OACL,GAAA,WAAA,cACA,EAAA,uBAAA,2BACA,EAAA,iBAAA,oBACA,EAAA,aAAA,iBACA,EAAA,mBAAA,6BACD"}
@@ -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(`../../_transfer-utilities.cjs`),i=require(`../../_utils.cjs`),a=require(`../_utils.cjs`);let o=require(`viem`);function s({chainConfigs:s,environment:c,evmSigner:l}){return async({quote:u,gasSettings:d,onStepChange:f})=>{if(u.serviceType!==e.ServiceType.WRAP_UNWRAP)throw new t.SdkError(t.ErrorReason.INCORRECT_PROVIDER_PROVIDED,t.ErrorCode.INVALID_PARAMS);let p=Math.floor(Date.now()/1e3);if(u.expiresAt<=p)throw new t.SdkError(t.ErrorReason.QUOTE_EXPIRED,t.ErrorCode.INVALID_PARAMS);let m=u.fromAddress;if(!(0,o.isAddress)(m))throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`fromAddress is not a valid EVM address.`});let h=u.sourceChain.chainId,g=a.getWrapDirection(u.assetIn,u.assetOut,h,s);if(!g)throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`Quote does not represent a valid wrap/unwrap pair.`});let _=a.getWrapperContractAddress(h,s),v=g===`wrap`,y=a.encodeWrapUnwrapData(g,u.amountIn),b=i.getEvmClientForChain({chain:u.sourceChain}),x=await a.estimateWrapUnwrapGas({direction:g,amountIn:u.amountIn,contractAddress:_,fromAddress:m,client:b,estimateGasMarginBps:d?.estimateGasMarginBps}),S={chainId:n.caip2ToEip155HexChainId(u.sourceChain.chainId),data:y,from:m,gas:x,to:_,value:v?u.amountIn:0n,...d?.maxFeePerGas===void 0?null:{maxFeePerGas:d.maxFeePerGas,maxPriorityFeePerGas:d.maxPriorityFeePerGas}},C={currentSignature:1,currentSignatureReason:e.TransferSignatureReason.WrapToken,quote:u,requiredSignatures:1};f?.(C);let w=Date.now();return r.sourcePendingTransferFromQuote(u,{environment:c,txHash:await l.sign(S,async e=>b.sendRawTransaction({serializedTransaction:e}),C),startedAtMs:w,requiredConfirmationCount:1})}}exports.transferAssetFactory=s;
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(`../../_transfer-utilities.cjs`),a=require(`../_utils.cjs`);let o=require(`viem`);function s({chainConfigs:s,environment:c,evmSigner:l}){return async({quote:u,gasSettings:d,onStepChange:f})=>{if(u.serviceType!==e.ServiceType.WRAP_UNWRAP)throw new t.SdkError(t.ErrorReason.INCORRECT_PROVIDER_PROVIDED,t.ErrorCode.INVALID_PARAMS);let p=Math.floor(Date.now()/1e3);if(u.expiresAt<=p)throw new t.SdkError(t.ErrorReason.QUOTE_EXPIRED,t.ErrorCode.INVALID_PARAMS);let m=u.fromAddress;if(!(0,o.isAddress)(m))throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`fromAddress is not a valid EVM address.`});let h=u.sourceChain.chainId,g=a.getWrapDirection(u.assetIn,u.assetOut,h,s);if(!g)throw new t.SdkError(t.ErrorReason.INVALID_PARAMS,t.ErrorCode.INVALID_PARAMS,{details:`Quote does not represent a valid wrap/unwrap pair.`});let _=a.getWrapperContractAddress(h,s),v=g===`wrap`,y=a.encodeWrapUnwrapData(g,u.amountIn),b=r.getEvmClientForChain({chain:u.sourceChain}),x=await a.estimateWrapUnwrapGas({direction:g,amountIn:u.amountIn,contractAddress:_,fromAddress:m,client:b,estimateGasMarginBps:d?.estimateGasMarginBps}),S={chainId:n.caip2ToEip155HexChainId(u.sourceChain.chainId),data:y,from:m,gas:x,to:_,value:v?u.amountIn:0n,...d?.maxFeePerGas===void 0?null:{maxFeePerGas:d.maxFeePerGas,maxPriorityFeePerGas:d.maxPriorityFeePerGas}},C={currentSignature:1,currentSignatureReason:e.TransferSignatureReason.WrapToken,quote:u,requiredSignatures:1};f?.(C);let w=Date.now();return i.sourcePendingTransferFromQuote(u,{environment:c,txHash:await l.sign(S,async e=>b.sendRawTransaction({serializedTransaction:e}),C),startedAtMs:w,requiredConfirmationCount:1})}}exports.transferAssetFactory=s;
2
2
  //# sourceMappingURL=transfer-asset.cjs.map
@@ -1,2 +1,2 @@
1
- import{ServiceType as e,TransferSignatureReason as t}from"../../../constants.js";import{ErrorCode as n,ErrorReason as r,SdkError as i}from"../../../errors.js";import{caip2ToEip155HexChainId as a}from"../../../utils/caip.js";import{sourcePendingTransferFromQuote as o}from"../../_transfer-utilities.js";import{getEvmClientForChain as s}from"../../_utils.js";import{encodeWrapUnwrapData as c,estimateWrapUnwrapGas as l,getWrapDirection as u,getWrapperContractAddress as d}from"../_utils.js";import{isAddress as f}from"viem";function p({chainConfigs:p,environment:m,evmSigner:h}){return async({quote:g,gasSettings:_,onStepChange:v})=>{if(g.serviceType!==e.WRAP_UNWRAP)throw new i(r.INCORRECT_PROVIDER_PROVIDED,n.INVALID_PARAMS);let y=Math.floor(Date.now()/1e3);if(g.expiresAt<=y)throw new i(r.QUOTE_EXPIRED,n.INVALID_PARAMS);let b=g.fromAddress;if(!f(b))throw new i(r.INVALID_PARAMS,n.INVALID_PARAMS,{details:`fromAddress is not a valid EVM address.`});let x=g.sourceChain.chainId,S=u(g.assetIn,g.assetOut,x,p);if(!S)throw new i(r.INVALID_PARAMS,n.INVALID_PARAMS,{details:`Quote does not represent a valid wrap/unwrap pair.`});let C=d(x,p),w=S===`wrap`,T=c(S,g.amountIn),E=s({chain:g.sourceChain}),D=await l({direction:S,amountIn:g.amountIn,contractAddress:C,fromAddress:b,client:E,estimateGasMarginBps:_?.estimateGasMarginBps}),O={chainId:a(g.sourceChain.chainId),data:T,from:b,gas:D,to:C,value:w?g.amountIn:0n,..._?.maxFeePerGas===void 0?null:{maxFeePerGas:_.maxFeePerGas,maxPriorityFeePerGas:_.maxPriorityFeePerGas}},k={currentSignature:1,currentSignatureReason:t.WrapToken,quote:g,requiredSignatures:1};v?.(k);let A=Date.now();return o(g,{environment:m,txHash:await h.sign(O,async e=>E.sendRawTransaction({serializedTransaction:e}),k),startedAtMs:A,requiredConfirmationCount:1})}}export{p as transferAssetFactory};
1
+ import{ServiceType as e,TransferSignatureReason as t}from"../../../constants.js";import{ErrorCode as n,ErrorReason as r,SdkError as i}from"../../../errors.js";import{caip2ToEip155HexChainId as a}from"../../../utils/caip.js";import{getEvmClientForChain as o}from"../../_utils.js";import{sourcePendingTransferFromQuote as s}from"../../_transfer-utilities.js";import{encodeWrapUnwrapData as c,estimateWrapUnwrapGas as l,getWrapDirection as u,getWrapperContractAddress as d}from"../_utils.js";import{isAddress as f}from"viem";function p({chainConfigs:p,environment:m,evmSigner:h}){return async({quote:g,gasSettings:_,onStepChange:v})=>{if(g.serviceType!==e.WRAP_UNWRAP)throw new i(r.INCORRECT_PROVIDER_PROVIDED,n.INVALID_PARAMS);let y=Math.floor(Date.now()/1e3);if(g.expiresAt<=y)throw new i(r.QUOTE_EXPIRED,n.INVALID_PARAMS);let b=g.fromAddress;if(!f(b))throw new i(r.INVALID_PARAMS,n.INVALID_PARAMS,{details:`fromAddress is not a valid EVM address.`});let x=g.sourceChain.chainId,S=u(g.assetIn,g.assetOut,x,p);if(!S)throw new i(r.INVALID_PARAMS,n.INVALID_PARAMS,{details:`Quote does not represent a valid wrap/unwrap pair.`});let C=d(x,p),w=S===`wrap`,T=c(S,g.amountIn),E=o({chain:g.sourceChain}),D=await l({direction:S,amountIn:g.amountIn,contractAddress:C,fromAddress:b,client:E,estimateGasMarginBps:_?.estimateGasMarginBps}),O={chainId:a(g.sourceChain.chainId),data:T,from:b,gas:D,to:C,value:w?g.amountIn:0n,..._?.maxFeePerGas===void 0?null:{maxFeePerGas:_.maxFeePerGas,maxPriorityFeePerGas:_.maxPriorityFeePerGas}},k={currentSignature:1,currentSignatureReason:t.WrapToken,quote:g,requiredSignatures:1};v?.(k);let A=Date.now();return s(g,{environment:m,txHash:await h.sign(O,async e=>E.sendRawTransaction({serializedTransaction:e}),k),startedAtMs:A,requiredConfirmationCount:1})}}export{p as transferAssetFactory};
2
2
  //# sourceMappingURL=transfer-asset.js.map
@@ -7,6 +7,7 @@ import { SdkError } from "../errors.cjs";
7
7
  import { Transfer } from "./transfer.cjs";
8
8
  import { EstimateNativeFeeOptions, GetBridgeableAssetsProps, GetMinimumTransferAmountProps, GetSupportedChainsResult, NativeFeeEstimate, ServiceInitializer, TrackTransferProps, TransferAssetProps } from "./service.cjs";
9
9
  import { QuoterOptions } from "../quoter/quoter.cjs";
10
+ import { RecurringNamespace } from "../transfer-service/markr/recurring/types.cjs";
10
11
 
11
12
  //#region src/types/transfer-manager.d.ts
12
13
  interface AssetBridgeMap {
@@ -93,6 +94,21 @@ interface TransferManager {
93
94
  getSupportedChains(): Promise<GetSupportedChainsResult>;
94
95
  /** Create a quote aggregator for the specified intent. */
95
96
  getQuoter(props: QuoterProps, options?: QuoterOptions): QuoterInterface;
97
+ /**
98
+ * Recurring-swap (DCA) capability surface, aggregated at the manager layer
99
+ * to match the style of `getBridgeableAssets` / `getMinimumTransferAmount`.
100
+ *
101
+ * The manager delegates each call internally to whichever underlying
102
+ * service implements recurring (today: Markr). Each method throws
103
+ * `ServiceUnavailableError` if no initialized service backs the call —
104
+ * same failure shape as `transferAsset` / `estimateNativeFee` /
105
+ * `trackTransfer` when the relevant service wasn't in the initializer
106
+ * list.
107
+ *
108
+ * @example
109
+ * const quote = await manager.recurring.quote({ ... });
110
+ */
111
+ readonly recurring: RecurringNamespace;
96
112
  /** Returns the current status of the transfer manager. */
97
113
  status(): TransferManagerStatus;
98
114
  /** Track a transfer’s lifecycle. */
@@ -7,6 +7,7 @@ import { SdkError } from "../errors.js";
7
7
  import { Transfer } from "./transfer.js";
8
8
  import { EstimateNativeFeeOptions, GetBridgeableAssetsProps, GetMinimumTransferAmountProps, GetSupportedChainsResult, NativeFeeEstimate, ServiceInitializer, TrackTransferProps, TransferAssetProps } from "./service.js";
9
9
  import { QuoterOptions } from "../quoter/quoter.js";
10
+ import { RecurringNamespace } from "../transfer-service/markr/recurring/types.js";
10
11
 
11
12
  //#region src/types/transfer-manager.d.ts
12
13
  interface AssetBridgeMap {
@@ -93,6 +94,21 @@ interface TransferManager {
93
94
  getSupportedChains(): Promise<GetSupportedChainsResult>;
94
95
  /** Create a quote aggregator for the specified intent. */
95
96
  getQuoter(props: QuoterProps, options?: QuoterOptions): QuoterInterface;
97
+ /**
98
+ * Recurring-swap (DCA) capability surface, aggregated at the manager layer
99
+ * to match the style of `getBridgeableAssets` / `getMinimumTransferAmount`.
100
+ *
101
+ * The manager delegates each call internally to whichever underlying
102
+ * service implements recurring (today: Markr). Each method throws
103
+ * `ServiceUnavailableError` if no initialized service backs the call —
104
+ * same failure shape as `transferAsset` / `estimateNativeFee` /
105
+ * `trackTransfer` when the relevant service wasn't in the initializer
106
+ * list.
107
+ *
108
+ * @example
109
+ * const quote = await manager.recurring.quote({ ... });
110
+ */
111
+ readonly recurring: RecurringNamespace;
96
112
  /** Returns the current status of the transfer manager. */
97
113
  status(): TransferManagerStatus;
98
114
  /** Track a transfer’s lifecycle. */
@@ -16,6 +16,14 @@ interface TransferStepDetails {
16
16
  readonly requiredSignatures: number;
17
17
  /** The original quote */
18
18
  readonly quote: Quote;
19
+ /**
20
+ * Opaque per-request payload supplied by the caller on the originating
21
+ * execute call; the SDK forwards it unchanged. Lets consumers correlate
22
+ * a signer prompt back to the specific request that produced it without
23
+ * relying on out-of-band state keyed by action type (which can collide
24
+ * when two same-type actions are in flight).
25
+ */
26
+ readonly signerContext?: unknown;
19
27
  }
20
28
  /**
21
29
  * Unified transfer lifecycle states (bridge and swap).
@@ -16,6 +16,14 @@ interface TransferStepDetails {
16
16
  readonly requiredSignatures: number;
17
17
  /** The original quote */
18
18
  readonly quote: Quote;
19
+ /**
20
+ * Opaque per-request payload supplied by the caller on the originating
21
+ * execute call; the SDK forwards it unchanged. Lets consumers correlate
22
+ * a signer prompt back to the specific request that produced it without
23
+ * relying on out-of-band state keyed by action type (which can collide
24
+ * when two same-type actions are in flight).
25
+ */
26
+ readonly signerContext?: unknown;
19
27
  }
20
28
  /**
21
29
  * Unified transfer lifecycle states (bridge and swap).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@avalabs/fusion-sdk",
3
3
  "license": "Limited Ecosystem License",
4
- "version": "0.21.0",
4
+ "version": "0.23.0",
5
5
  "type": "module",
6
6
  "main": "./dist/mod.cjs",
7
7
  "module": "./dist/mod.js",
@@ -49,8 +49,8 @@
49
49
  "vitest": "4.0.6",
50
50
  "tsdown": "0.21.4",
51
51
  "zod": "4.1.12",
52
- "@internal/tsdown-config": "0.0.1",
53
- "eslint-config-custom": "0.1.0"
52
+ "eslint-config-custom": "0.1.0",
53
+ "@internal/tsdown-config": "0.0.1"
54
54
  },
55
55
  "sideEffects": false,
56
56
  "scripts": {