@dimes-dot-fi/sdk 1.0.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.
@@ -0,0 +1,283 @@
1
+ import {
2
+ DimesApiError,
3
+ DimesError
4
+ } from "./chunk-LQ5LLBR6.mjs";
5
+
6
+ // src/quote/build-quote-params.ts
7
+ var DEFAULT_LEVERAGE_STEP_BPS = 2500;
8
+ function buildQuoteParams(params, stepBps = DEFAULT_LEVERAGE_STEP_BPS) {
9
+ const leverageBps = Math.round(params.leverageBps / stepBps) * stepBps;
10
+ const notionalUsdPips = Math.round(params.collateralUsd * leverageBps);
11
+ return {
12
+ marketTicker: params.marketTicker,
13
+ effectiveSide: params.side,
14
+ leverageBps,
15
+ notionalAmountUsdPips: notionalUsdPips.toString(),
16
+ slippageBps: params.slippageBps
17
+ };
18
+ }
19
+
20
+ // src/quote/quote-error-hints.ts
21
+ var pipsPerUsd = 1e4;
22
+ var bpsPerUnit = 1e4;
23
+ var bpsPerPct = 100;
24
+ var centsFactor = 100;
25
+ var decimalPlaces = 2;
26
+ var marketMovedCodes = /* @__PURE__ */ new Set([
27
+ "quote_slippage_too_high",
28
+ "quote_insufficient_liquidity",
29
+ "quote_entry_price_out_of_range",
30
+ "quote_entry_bid_depth_too_low",
31
+ "quote_entry_depth_too_low",
32
+ "quote_entry_spread_too_wide"
33
+ ]);
34
+ function num(params, key) {
35
+ if (!params) {
36
+ return null;
37
+ }
38
+ const raw = params[key];
39
+ if (raw === null || raw === void 0) {
40
+ return null;
41
+ }
42
+ const n = typeof raw === "string" ? Number(raw) : typeof raw === "number" ? raw : NaN;
43
+ return Number.isFinite(n) ? n : null;
44
+ }
45
+ function pipsToUsd(pips) {
46
+ return pips / pipsPerUsd;
47
+ }
48
+ function notionalPipsToCollateralUsd(notionalPips, leverageBps) {
49
+ if (!Number.isFinite(leverageBps) || leverageBps <= 0) {
50
+ return null;
51
+ }
52
+ return notionalPips * bpsPerUnit / leverageBps / pipsPerUsd;
53
+ }
54
+ function resolveMaxCollateralHint(params, context, capacityKey) {
55
+ const serverMaxCollateralPips = num(params, "maxSupportedCollateralUsdPips");
56
+ const capacityPips = num(params, capacityKey);
57
+ const minNotionalPips = num(params, "minNotionalUsdPips");
58
+ const fromServer = serverMaxCollateralPips !== null ? pipsToUsd(serverMaxCollateralPips) : null;
59
+ const fromCapacity = capacityPips !== null ? notionalPipsToCollateralUsd(capacityPips, context.leverageBps) : null;
60
+ const maxCollateralUsd = fromServer !== null && fromCapacity !== null ? Math.min(fromServer, fromCapacity) : fromServer ?? fromCapacity;
61
+ const minCollateralUsd = minNotionalPips !== null ? notionalPipsToCollateralUsd(minNotionalPips, context.leverageBps) : null;
62
+ if (maxCollateralUsd === null || minCollateralUsd === null) {
63
+ return null;
64
+ }
65
+ if (maxCollateralUsd < minCollateralUsd) {
66
+ return { kind: "market-full" };
67
+ }
68
+ return { kind: "use-max-collateral", maxCollateralUsd, minCollateralUsd };
69
+ }
70
+ function quoteErrorHint(code, params, context) {
71
+ if (!code) {
72
+ return null;
73
+ }
74
+ switch (code) {
75
+ case "quote_side_capacity_exceeded":
76
+ case "quote_user_position_limit_exceeded":
77
+ case "quote_market_position_limit_exceeded":
78
+ case "quote_side_position_limit_exceeded":
79
+ case "quote_global_position_limit_exceeded":
80
+ case "quote_partner_position_limit_exceeded":
81
+ return resolveMaxCollateralHint(params, context, "availableCapacityUsdPips");
82
+ case "quote_insufficient_liquidity":
83
+ case "notional_selector_insufficient_liquidity":
84
+ return resolveMaxCollateralHint(params, context, "slippageMaxUsdPips");
85
+ case "quote_leverage_exceeds_maximum":
86
+ case "quote_leverage_exceeds_model_max": {
87
+ const maxLeverageBps = num(params, "maxLeverageBps");
88
+ if (maxLeverageBps === null) {
89
+ return null;
90
+ }
91
+ return { kind: "clamp-leverage", maxLeverageBps };
92
+ }
93
+ case "quote_leverage_too_high_for_price": {
94
+ const maxLeverageBps = num(params, "maxAcceptableLeverageBps");
95
+ if (maxLeverageBps === null) {
96
+ return null;
97
+ }
98
+ return { kind: "clamp-leverage", maxLeverageBps };
99
+ }
100
+ case "quote_leverage_below_minimum": {
101
+ const minLeverageBps = num(params, "minLeverageBps");
102
+ if (minLeverageBps === null) {
103
+ return null;
104
+ }
105
+ return { kind: "raise-leverage", minLeverageBps };
106
+ }
107
+ case "quote_slippage_too_high": {
108
+ const currentSlippageBps = num(params, "currentSlippageBps");
109
+ const maxSlippageBps = num(params, "maxSlippageBps");
110
+ if (currentSlippageBps === null || maxSlippageBps === null) {
111
+ return null;
112
+ }
113
+ return { kind: "raise-slippage", currentSlippageBps, maxSlippageBps };
114
+ }
115
+ default:
116
+ return null;
117
+ }
118
+ }
119
+ function formatUsd(value) {
120
+ return new Intl.NumberFormat("en-US", {
121
+ style: "currency",
122
+ currency: "USD",
123
+ minimumFractionDigits: 2,
124
+ maximumFractionDigits: 2
125
+ }).format(value);
126
+ }
127
+ function bpsToMultiplier(bps) {
128
+ return `${(bps / bpsPerUnit).toFixed(1).replace(/\.0$/, "")}x`;
129
+ }
130
+ function hintAdjustment(hint, current) {
131
+ if (!hint) {
132
+ return null;
133
+ }
134
+ switch (hint.kind) {
135
+ case "use-max-collateral": {
136
+ const to = Math.max(0, Math.floor(hint.maxCollateralUsd * centsFactor) / centsFactor);
137
+ if (to <= 0) {
138
+ return null;
139
+ }
140
+ return {
141
+ field: "collateral",
142
+ fromValue: current.collateralUsd,
143
+ toValue: to,
144
+ toLabel: formatUsd(to),
145
+ reason: "max-collateral"
146
+ };
147
+ }
148
+ case "clamp-leverage": {
149
+ if (hint.maxLeverageBps === void 0) {
150
+ return null;
151
+ }
152
+ return {
153
+ field: "leverage",
154
+ fromValue: current.leverageBps,
155
+ toValue: hint.maxLeverageBps,
156
+ toLabel: bpsToMultiplier(hint.maxLeverageBps),
157
+ reason: "clamp-max"
158
+ };
159
+ }
160
+ case "raise-leverage":
161
+ return {
162
+ field: "leverage",
163
+ fromValue: current.leverageBps,
164
+ toValue: hint.minLeverageBps,
165
+ toLabel: bpsToMultiplier(hint.minLeverageBps),
166
+ reason: "raise-min"
167
+ };
168
+ case "raise-slippage":
169
+ return {
170
+ field: "slippage",
171
+ fromValue: hint.currentSlippageBps,
172
+ toValue: hint.maxSlippageBps,
173
+ toLabel: `${(hint.maxSlippageBps / bpsPerPct).toFixed(decimalPlaces).replace(/\.?0+$/, "")}%`,
174
+ reason: "raise-slippage"
175
+ };
176
+ case "market-full":
177
+ return null;
178
+ default:
179
+ return null;
180
+ }
181
+ }
182
+
183
+ // src/quote/quote.ts
184
+ var DEFAULT_MAX_RETRIES = 3;
185
+ function isMarketMovedError(err) {
186
+ return err instanceof DimesApiError && marketMovedCodes.has(err.code);
187
+ }
188
+ function applyAdjustment(params, adj, currentParams) {
189
+ switch (adj.field) {
190
+ case "collateral": {
191
+ const notionalUsdPips = Math.round(adj.toValue * params.leverageBps);
192
+ return { ...params, notionalAmountUsdPips: notionalUsdPips.toString() };
193
+ }
194
+ case "leverage": {
195
+ const notionalUsdPips = Math.round(currentParams.collateralUsd * adj.toValue);
196
+ return {
197
+ ...params,
198
+ leverageBps: adj.toValue,
199
+ notionalAmountUsdPips: notionalUsdPips.toString()
200
+ };
201
+ }
202
+ case "slippage":
203
+ return { ...params, slippageBps: adj.toValue };
204
+ default:
205
+ return params;
206
+ }
207
+ }
208
+ function handleMarketMoved(err, attempt, maxRetries) {
209
+ return isMarketMovedError(err) && attempt < maxRetries;
210
+ }
211
+ function handleCorrection(err, currentParams) {
212
+ if (!(err instanceof DimesApiError)) {
213
+ return null;
214
+ }
215
+ const hint = quoteErrorHint(err.code, err.params, {
216
+ leverageBps: currentParams.leverageBps
217
+ });
218
+ const adj = hintAdjustment(hint, {
219
+ collateralUsd: currentParams.collateralUsd,
220
+ leverageBps: currentParams.leverageBps,
221
+ slippageBps: currentParams.slippageBps
222
+ });
223
+ if (!adj) {
224
+ return null;
225
+ }
226
+ return { adj };
227
+ }
228
+ async function executeQuote(client, params, options) {
229
+ const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;
230
+ const autoCorrect = options?.autoCorrect ?? true;
231
+ const corrections = [];
232
+ let retries = 0;
233
+ let offerParams = buildQuoteParams(params);
234
+ const currentParams = { ...params };
235
+ const draft = await client.createDraftQuote(offerParams);
236
+ options?.onDraftReady?.(draft);
237
+ let currentDraft = draft;
238
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
239
+ try {
240
+ const promotedOffer = await client.promoteDraftQuote(currentDraft.id);
241
+ return { offer: promotedOffer, corrections, retries };
242
+ } catch (err) {
243
+ if (handleMarketMoved(err, attempt, maxRetries)) {
244
+ const newDraft = await client.createDraftQuote(offerParams);
245
+ retries++;
246
+ const callbackResult = options?.onMarketMoved?.({
247
+ originalDraft: currentDraft,
248
+ newDraft,
249
+ retryCount: retries
250
+ });
251
+ if (callbackResult === false) {
252
+ throw err;
253
+ }
254
+ currentDraft = newDraft;
255
+ continue;
256
+ }
257
+ if (autoCorrect) {
258
+ const correction = handleCorrection(err, currentParams);
259
+ if (correction) {
260
+ const callbackResult = options?.onCorrection?.(correction.adj);
261
+ if (callbackResult === false) {
262
+ throw err;
263
+ }
264
+ offerParams = applyAdjustment(offerParams, correction.adj, currentParams);
265
+ corrections.push(correction.adj);
266
+ const correctedOffer = await client.createQuote(offerParams);
267
+ return { offer: correctedOffer, corrections, retries };
268
+ }
269
+ }
270
+ throw err;
271
+ }
272
+ }
273
+ throw new DimesError("market_moved_retries_exhausted", "Exhausted market-moved retries");
274
+ }
275
+
276
+ export {
277
+ buildQuoteParams,
278
+ marketMovedCodes,
279
+ quoteErrorHint,
280
+ hintAdjustment,
281
+ executeQuote
282
+ };
283
+ //# sourceMappingURL=chunk-BRANC7OH.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/quote/build-quote-params.ts","../src/quote/quote-error-hints.ts","../src/quote/quote.ts"],"sourcesContent":["import type { CreateOfferParams } from \"../types\";\nimport type { QuoteParams } from \"../types/quote\";\n\nconst DEFAULT_LEVERAGE_STEP_BPS = 2500;\n\nexport function buildQuoteParams(params: QuoteParams, stepBps: number = DEFAULT_LEVERAGE_STEP_BPS): CreateOfferParams {\n const leverageBps = Math.round(params.leverageBps / stepBps) * stepBps;\n const notionalUsdPips = Math.round(params.collateralUsd * leverageBps);\n\n return {\n marketTicker: params.marketTicker,\n effectiveSide: params.side,\n leverageBps,\n notionalAmountUsdPips: notionalUsdPips.toString(),\n slippageBps: params.slippageBps,\n };\n}\n","const pipsPerUsd = 10_000;\nconst bpsPerUnit = 10_000;\nconst bpsPerPct = 100;\nconst centsFactor = 100;\nconst decimalPlaces = 2;\n\nexport const marketMovedCodes = new Set([\n \"quote_slippage_too_high\",\n \"quote_insufficient_liquidity\",\n \"quote_entry_price_out_of_range\",\n \"quote_entry_bid_depth_too_low\",\n \"quote_entry_depth_too_low\",\n \"quote_entry_spread_too_wide\",\n]);\n\nexport type QuoteHint =\n | { kind: \"use-max-collateral\"; maxCollateralUsd: number; minCollateralUsd: number }\n | { kind: \"clamp-leverage\"; maxLeverageBps?: number }\n | { kind: \"raise-leverage\"; minLeverageBps: number }\n | { kind: \"raise-slippage\"; currentSlippageBps: number; maxSlippageBps: number }\n | { kind: \"market-full\" }\n | null;\n\ntype Params = Record<string, unknown> | null | undefined;\n\nfunction num(params: Params, key: string): number | null {\n if (!params) {\n return null;\n }\n const raw = params[key];\n if (raw === null || raw === undefined) {\n return null;\n }\n // eslint-disable-next-line no-restricted-syntax\n const n = typeof raw === \"string\" ? Number(raw) : typeof raw === \"number\" ? raw : NaN;\n return Number.isFinite(n) ? n : null;\n}\n\nfunction pipsToUsd(pips: number): number {\n return pips / pipsPerUsd;\n}\n\nfunction notionalPipsToCollateralUsd(notionalPips: number, leverageBps: number): number | null {\n if (!Number.isFinite(leverageBps) || leverageBps <= 0) {\n return null;\n }\n return (notionalPips * bpsPerUnit) / leverageBps / pipsPerUsd;\n}\n\nfunction resolveMaxCollateralHint(params: Params, context: { leverageBps: number }, capacityKey: string): QuoteHint {\n const serverMaxCollateralPips = num(params, \"maxSupportedCollateralUsdPips\");\n const capacityPips = num(params, capacityKey);\n const minNotionalPips = num(params, \"minNotionalUsdPips\");\n\n const fromServer = serverMaxCollateralPips !== null ? pipsToUsd(serverMaxCollateralPips) : null;\n const fromCapacity = capacityPips !== null ? notionalPipsToCollateralUsd(capacityPips, context.leverageBps) : null;\n const maxCollateralUsd =\n fromServer !== null && fromCapacity !== null ? Math.min(fromServer, fromCapacity) : (fromServer ?? fromCapacity);\n\n const minCollateralUsd =\n minNotionalPips !== null ? notionalPipsToCollateralUsd(minNotionalPips, context.leverageBps) : null;\n\n if (maxCollateralUsd === null || minCollateralUsd === null) {\n return null;\n }\n if (maxCollateralUsd < minCollateralUsd) {\n return { kind: \"market-full\" };\n }\n return { kind: \"use-max-collateral\", maxCollateralUsd, minCollateralUsd };\n}\n\n// eslint-disable-next-line complexity\nexport function quoteErrorHint(code: string | null, params: Params, context: { leverageBps: number }): QuoteHint {\n if (!code) {\n return null;\n }\n\n switch (code) {\n case \"quote_side_capacity_exceeded\":\n case \"quote_user_position_limit_exceeded\":\n case \"quote_market_position_limit_exceeded\":\n case \"quote_side_position_limit_exceeded\":\n case \"quote_global_position_limit_exceeded\":\n case \"quote_partner_position_limit_exceeded\":\n return resolveMaxCollateralHint(params, context, \"availableCapacityUsdPips\");\n\n case \"quote_insufficient_liquidity\":\n case \"notional_selector_insufficient_liquidity\":\n return resolveMaxCollateralHint(params, context, \"slippageMaxUsdPips\");\n\n case \"quote_leverage_exceeds_maximum\":\n case \"quote_leverage_exceeds_model_max\": {\n const maxLeverageBps = num(params, \"maxLeverageBps\");\n if (maxLeverageBps === null) {\n return null;\n }\n return { kind: \"clamp-leverage\", maxLeverageBps };\n }\n\n case \"quote_leverage_too_high_for_price\": {\n const maxLeverageBps = num(params, \"maxAcceptableLeverageBps\");\n if (maxLeverageBps === null) {\n return null;\n }\n return { kind: \"clamp-leverage\", maxLeverageBps };\n }\n\n case \"quote_leverage_below_minimum\": {\n const minLeverageBps = num(params, \"minLeverageBps\");\n if (minLeverageBps === null) {\n return null;\n }\n return { kind: \"raise-leverage\", minLeverageBps };\n }\n\n case \"quote_slippage_too_high\": {\n const currentSlippageBps = num(params, \"currentSlippageBps\");\n const maxSlippageBps = num(params, \"maxSlippageBps\");\n if (currentSlippageBps === null || maxSlippageBps === null) {\n return null;\n }\n return { kind: \"raise-slippage\", currentSlippageBps, maxSlippageBps };\n }\n\n default:\n return null;\n }\n}\n\nexport type CorrectedField = \"collateral\" | \"leverage\" | \"slippage\";\n\nexport type HintAdjustment =\n | {\n field: \"collateral\";\n fromValue: number;\n toValue: number;\n toLabel: string;\n reason: \"max-collateral\";\n }\n | {\n field: \"leverage\";\n fromValue: number;\n toValue: number;\n toLabel: string;\n reason: \"clamp-max\" | \"raise-min\";\n }\n | {\n field: \"slippage\";\n fromValue: number;\n toValue: number;\n toLabel: string;\n reason: \"raise-slippage\";\n }\n | null;\n\nfunction formatUsd(value: number): string {\n return new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: \"USD\",\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }).format(value);\n}\n\nfunction bpsToMultiplier(bps: number): string {\n return `${(bps / bpsPerUnit).toFixed(1).replace(/\\.0$/, \"\")}x`;\n}\n\nexport function hintAdjustment(\n hint: QuoteHint,\n current: { collateralUsd: number; leverageBps: number; slippageBps: number },\n): HintAdjustment {\n if (!hint) {\n return null;\n }\n\n switch (hint.kind) {\n case \"use-max-collateral\": {\n const to = Math.max(0, Math.floor(hint.maxCollateralUsd * centsFactor) / centsFactor);\n if (to <= 0) {\n return null;\n }\n return {\n field: \"collateral\",\n fromValue: current.collateralUsd,\n toValue: to,\n toLabel: formatUsd(to),\n reason: \"max-collateral\",\n };\n }\n case \"clamp-leverage\": {\n if (hint.maxLeverageBps === undefined) {\n return null;\n }\n return {\n field: \"leverage\",\n fromValue: current.leverageBps,\n toValue: hint.maxLeverageBps,\n toLabel: bpsToMultiplier(hint.maxLeverageBps),\n reason: \"clamp-max\",\n };\n }\n case \"raise-leverage\":\n return {\n field: \"leverage\",\n fromValue: current.leverageBps,\n toValue: hint.minLeverageBps,\n toLabel: bpsToMultiplier(hint.minLeverageBps),\n reason: \"raise-min\",\n };\n case \"raise-slippage\":\n return {\n field: \"slippage\",\n fromValue: hint.currentSlippageBps,\n toValue: hint.maxSlippageBps,\n toLabel: `${(hint.maxSlippageBps / bpsPerPct).toFixed(decimalPlaces).replace(/\\.?0+$/, \"\")}%`,\n reason: \"raise-slippage\",\n };\n case \"market-full\":\n return null;\n default:\n return null;\n }\n}\n","import { DimesApiError, DimesError } from \"../errors/dimes-error\";\nimport type { CreateOfferParams, Offer } from \"../types\";\nimport type { QuoteOptions, QuoteParams, QuoteResult } from \"../types/quote\";\nimport { buildQuoteParams } from \"./build-quote-params\";\nimport { type HintAdjustment, hintAdjustment, marketMovedCodes, quoteErrorHint } from \"./quote-error-hints\";\n\nexport interface QuoteClient {\n createDraftQuote(params: CreateOfferParams): Promise<Offer>;\n promoteDraftQuote(draftId: string): Promise<Offer>;\n createQuote(params: CreateOfferParams): Promise<Offer>;\n}\n\nconst DEFAULT_MAX_RETRIES = 3;\n\nfunction isMarketMovedError(err: unknown): boolean {\n return err instanceof DimesApiError && marketMovedCodes.has(err.code);\n}\n\nfunction applyAdjustment(\n params: CreateOfferParams,\n adj: NonNullable<HintAdjustment>,\n currentParams: QuoteParams,\n): CreateOfferParams {\n switch (adj.field) {\n case \"collateral\": {\n const notionalUsdPips = Math.round(adj.toValue * params.leverageBps);\n return { ...params, notionalAmountUsdPips: notionalUsdPips.toString() };\n }\n case \"leverage\": {\n const notionalUsdPips = Math.round(currentParams.collateralUsd * adj.toValue);\n return {\n ...params,\n leverageBps: adj.toValue,\n notionalAmountUsdPips: notionalUsdPips.toString(),\n };\n }\n case \"slippage\":\n return { ...params, slippageBps: adj.toValue };\n default:\n return params;\n }\n}\n\nfunction handleMarketMoved(err: unknown, attempt: number, maxRetries: number): boolean {\n return isMarketMovedError(err) && attempt < maxRetries;\n}\n\nfunction handleCorrection(err: unknown, currentParams: QuoteParams): { adj: NonNullable<HintAdjustment> } | null {\n if (!(err instanceof DimesApiError)) {\n return null;\n }\n\n const hint = quoteErrorHint(err.code, err.params, {\n leverageBps: currentParams.leverageBps,\n });\n\n const adj = hintAdjustment(hint, {\n collateralUsd: currentParams.collateralUsd,\n leverageBps: currentParams.leverageBps,\n slippageBps: currentParams.slippageBps,\n });\n\n if (!adj) {\n return null;\n }\n\n return { adj };\n}\n\n// eslint-disable-next-line complexity\nexport async function executeQuote(\n client: QuoteClient,\n params: QuoteParams,\n options?: QuoteOptions,\n): Promise<QuoteResult> {\n const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;\n const autoCorrect = options?.autoCorrect ?? true;\n const corrections: NonNullable<HintAdjustment>[] = [];\n let retries = 0;\n\n let offerParams = buildQuoteParams(params);\n const currentParams = { ...params };\n\n const draft = await client.createDraftQuote(offerParams);\n options?.onDraftReady?.(draft);\n\n let currentDraft: Offer = draft;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const promotedOffer = await client.promoteDraftQuote(currentDraft.id);\n return { offer: promotedOffer, corrections, retries };\n } catch (err) {\n if (handleMarketMoved(err, attempt, maxRetries)) {\n const newDraft = await client.createDraftQuote(offerParams);\n retries++;\n\n const callbackResult = options?.onMarketMoved?.({\n originalDraft: currentDraft,\n newDraft,\n retryCount: retries,\n });\n\n if (callbackResult === false) {\n throw err;\n }\n\n currentDraft = newDraft;\n continue;\n }\n\n if (autoCorrect) {\n const correction = handleCorrection(err, currentParams);\n\n if (correction) {\n const callbackResult = options?.onCorrection?.(correction.adj);\n if (callbackResult === false) {\n throw err;\n }\n\n offerParams = applyAdjustment(offerParams, correction.adj, currentParams);\n corrections.push(correction.adj);\n\n const correctedOffer = await client.createQuote(offerParams);\n return { offer: correctedOffer, corrections, retries };\n }\n }\n\n throw err;\n }\n }\n\n throw new DimesError(\"market_moved_retries_exhausted\", \"Exhausted market-moved retries\");\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,283 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+ var _chunkXXTTXLCTcjs = require('./chunk-XXTTXLCT.cjs');
5
+
6
+ // src/quote/build-quote-params.ts
7
+ var DEFAULT_LEVERAGE_STEP_BPS = 2500;
8
+ function buildQuoteParams(params, stepBps = DEFAULT_LEVERAGE_STEP_BPS) {
9
+ const leverageBps = Math.round(params.leverageBps / stepBps) * stepBps;
10
+ const notionalUsdPips = Math.round(params.collateralUsd * leverageBps);
11
+ return {
12
+ marketTicker: params.marketTicker,
13
+ effectiveSide: params.side,
14
+ leverageBps,
15
+ notionalAmountUsdPips: notionalUsdPips.toString(),
16
+ slippageBps: params.slippageBps
17
+ };
18
+ }
19
+
20
+ // src/quote/quote-error-hints.ts
21
+ var pipsPerUsd = 1e4;
22
+ var bpsPerUnit = 1e4;
23
+ var bpsPerPct = 100;
24
+ var centsFactor = 100;
25
+ var decimalPlaces = 2;
26
+ var marketMovedCodes = /* @__PURE__ */ new Set([
27
+ "quote_slippage_too_high",
28
+ "quote_insufficient_liquidity",
29
+ "quote_entry_price_out_of_range",
30
+ "quote_entry_bid_depth_too_low",
31
+ "quote_entry_depth_too_low",
32
+ "quote_entry_spread_too_wide"
33
+ ]);
34
+ function num(params, key) {
35
+ if (!params) {
36
+ return null;
37
+ }
38
+ const raw = params[key];
39
+ if (raw === null || raw === void 0) {
40
+ return null;
41
+ }
42
+ const n = typeof raw === "string" ? Number(raw) : typeof raw === "number" ? raw : NaN;
43
+ return Number.isFinite(n) ? n : null;
44
+ }
45
+ function pipsToUsd(pips) {
46
+ return pips / pipsPerUsd;
47
+ }
48
+ function notionalPipsToCollateralUsd(notionalPips, leverageBps) {
49
+ if (!Number.isFinite(leverageBps) || leverageBps <= 0) {
50
+ return null;
51
+ }
52
+ return notionalPips * bpsPerUnit / leverageBps / pipsPerUsd;
53
+ }
54
+ function resolveMaxCollateralHint(params, context, capacityKey) {
55
+ const serverMaxCollateralPips = num(params, "maxSupportedCollateralUsdPips");
56
+ const capacityPips = num(params, capacityKey);
57
+ const minNotionalPips = num(params, "minNotionalUsdPips");
58
+ const fromServer = serverMaxCollateralPips !== null ? pipsToUsd(serverMaxCollateralPips) : null;
59
+ const fromCapacity = capacityPips !== null ? notionalPipsToCollateralUsd(capacityPips, context.leverageBps) : null;
60
+ const maxCollateralUsd = fromServer !== null && fromCapacity !== null ? Math.min(fromServer, fromCapacity) : _nullishCoalesce(fromServer, () => ( fromCapacity));
61
+ const minCollateralUsd = minNotionalPips !== null ? notionalPipsToCollateralUsd(minNotionalPips, context.leverageBps) : null;
62
+ if (maxCollateralUsd === null || minCollateralUsd === null) {
63
+ return null;
64
+ }
65
+ if (maxCollateralUsd < minCollateralUsd) {
66
+ return { kind: "market-full" };
67
+ }
68
+ return { kind: "use-max-collateral", maxCollateralUsd, minCollateralUsd };
69
+ }
70
+ function quoteErrorHint(code, params, context) {
71
+ if (!code) {
72
+ return null;
73
+ }
74
+ switch (code) {
75
+ case "quote_side_capacity_exceeded":
76
+ case "quote_user_position_limit_exceeded":
77
+ case "quote_market_position_limit_exceeded":
78
+ case "quote_side_position_limit_exceeded":
79
+ case "quote_global_position_limit_exceeded":
80
+ case "quote_partner_position_limit_exceeded":
81
+ return resolveMaxCollateralHint(params, context, "availableCapacityUsdPips");
82
+ case "quote_insufficient_liquidity":
83
+ case "notional_selector_insufficient_liquidity":
84
+ return resolveMaxCollateralHint(params, context, "slippageMaxUsdPips");
85
+ case "quote_leverage_exceeds_maximum":
86
+ case "quote_leverage_exceeds_model_max": {
87
+ const maxLeverageBps = num(params, "maxLeverageBps");
88
+ if (maxLeverageBps === null) {
89
+ return null;
90
+ }
91
+ return { kind: "clamp-leverage", maxLeverageBps };
92
+ }
93
+ case "quote_leverage_too_high_for_price": {
94
+ const maxLeverageBps = num(params, "maxAcceptableLeverageBps");
95
+ if (maxLeverageBps === null) {
96
+ return null;
97
+ }
98
+ return { kind: "clamp-leverage", maxLeverageBps };
99
+ }
100
+ case "quote_leverage_below_minimum": {
101
+ const minLeverageBps = num(params, "minLeverageBps");
102
+ if (minLeverageBps === null) {
103
+ return null;
104
+ }
105
+ return { kind: "raise-leverage", minLeverageBps };
106
+ }
107
+ case "quote_slippage_too_high": {
108
+ const currentSlippageBps = num(params, "currentSlippageBps");
109
+ const maxSlippageBps = num(params, "maxSlippageBps");
110
+ if (currentSlippageBps === null || maxSlippageBps === null) {
111
+ return null;
112
+ }
113
+ return { kind: "raise-slippage", currentSlippageBps, maxSlippageBps };
114
+ }
115
+ default:
116
+ return null;
117
+ }
118
+ }
119
+ function formatUsd(value) {
120
+ return new Intl.NumberFormat("en-US", {
121
+ style: "currency",
122
+ currency: "USD",
123
+ minimumFractionDigits: 2,
124
+ maximumFractionDigits: 2
125
+ }).format(value);
126
+ }
127
+ function bpsToMultiplier(bps) {
128
+ return `${(bps / bpsPerUnit).toFixed(1).replace(/\.0$/, "")}x`;
129
+ }
130
+ function hintAdjustment(hint, current) {
131
+ if (!hint) {
132
+ return null;
133
+ }
134
+ switch (hint.kind) {
135
+ case "use-max-collateral": {
136
+ const to = Math.max(0, Math.floor(hint.maxCollateralUsd * centsFactor) / centsFactor);
137
+ if (to <= 0) {
138
+ return null;
139
+ }
140
+ return {
141
+ field: "collateral",
142
+ fromValue: current.collateralUsd,
143
+ toValue: to,
144
+ toLabel: formatUsd(to),
145
+ reason: "max-collateral"
146
+ };
147
+ }
148
+ case "clamp-leverage": {
149
+ if (hint.maxLeverageBps === void 0) {
150
+ return null;
151
+ }
152
+ return {
153
+ field: "leverage",
154
+ fromValue: current.leverageBps,
155
+ toValue: hint.maxLeverageBps,
156
+ toLabel: bpsToMultiplier(hint.maxLeverageBps),
157
+ reason: "clamp-max"
158
+ };
159
+ }
160
+ case "raise-leverage":
161
+ return {
162
+ field: "leverage",
163
+ fromValue: current.leverageBps,
164
+ toValue: hint.minLeverageBps,
165
+ toLabel: bpsToMultiplier(hint.minLeverageBps),
166
+ reason: "raise-min"
167
+ };
168
+ case "raise-slippage":
169
+ return {
170
+ field: "slippage",
171
+ fromValue: hint.currentSlippageBps,
172
+ toValue: hint.maxSlippageBps,
173
+ toLabel: `${(hint.maxSlippageBps / bpsPerPct).toFixed(decimalPlaces).replace(/\.?0+$/, "")}%`,
174
+ reason: "raise-slippage"
175
+ };
176
+ case "market-full":
177
+ return null;
178
+ default:
179
+ return null;
180
+ }
181
+ }
182
+
183
+ // src/quote/quote.ts
184
+ var DEFAULT_MAX_RETRIES = 3;
185
+ function isMarketMovedError(err) {
186
+ return err instanceof _chunkXXTTXLCTcjs.DimesApiError && marketMovedCodes.has(err.code);
187
+ }
188
+ function applyAdjustment(params, adj, currentParams) {
189
+ switch (adj.field) {
190
+ case "collateral": {
191
+ const notionalUsdPips = Math.round(adj.toValue * params.leverageBps);
192
+ return { ...params, notionalAmountUsdPips: notionalUsdPips.toString() };
193
+ }
194
+ case "leverage": {
195
+ const notionalUsdPips = Math.round(currentParams.collateralUsd * adj.toValue);
196
+ return {
197
+ ...params,
198
+ leverageBps: adj.toValue,
199
+ notionalAmountUsdPips: notionalUsdPips.toString()
200
+ };
201
+ }
202
+ case "slippage":
203
+ return { ...params, slippageBps: adj.toValue };
204
+ default:
205
+ return params;
206
+ }
207
+ }
208
+ function handleMarketMoved(err, attempt, maxRetries) {
209
+ return isMarketMovedError(err) && attempt < maxRetries;
210
+ }
211
+ function handleCorrection(err, currentParams) {
212
+ if (!(err instanceof _chunkXXTTXLCTcjs.DimesApiError)) {
213
+ return null;
214
+ }
215
+ const hint = quoteErrorHint(err.code, err.params, {
216
+ leverageBps: currentParams.leverageBps
217
+ });
218
+ const adj = hintAdjustment(hint, {
219
+ collateralUsd: currentParams.collateralUsd,
220
+ leverageBps: currentParams.leverageBps,
221
+ slippageBps: currentParams.slippageBps
222
+ });
223
+ if (!adj) {
224
+ return null;
225
+ }
226
+ return { adj };
227
+ }
228
+ async function executeQuote(client, params, options) {
229
+ const maxRetries = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _ => _.maxRetries]), () => ( DEFAULT_MAX_RETRIES));
230
+ const autoCorrect = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _2 => _2.autoCorrect]), () => ( true));
231
+ const corrections = [];
232
+ let retries = 0;
233
+ let offerParams = buildQuoteParams(params);
234
+ const currentParams = { ...params };
235
+ const draft = await client.createDraftQuote(offerParams);
236
+ _optionalChain([options, 'optionalAccess', _3 => _3.onDraftReady, 'optionalCall', _4 => _4(draft)]);
237
+ let currentDraft = draft;
238
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
239
+ try {
240
+ const promotedOffer = await client.promoteDraftQuote(currentDraft.id);
241
+ return { offer: promotedOffer, corrections, retries };
242
+ } catch (err) {
243
+ if (handleMarketMoved(err, attempt, maxRetries)) {
244
+ const newDraft = await client.createDraftQuote(offerParams);
245
+ retries++;
246
+ const callbackResult = _optionalChain([options, 'optionalAccess', _5 => _5.onMarketMoved, 'optionalCall', _6 => _6({
247
+ originalDraft: currentDraft,
248
+ newDraft,
249
+ retryCount: retries
250
+ })]);
251
+ if (callbackResult === false) {
252
+ throw err;
253
+ }
254
+ currentDraft = newDraft;
255
+ continue;
256
+ }
257
+ if (autoCorrect) {
258
+ const correction = handleCorrection(err, currentParams);
259
+ if (correction) {
260
+ const callbackResult = _optionalChain([options, 'optionalAccess', _7 => _7.onCorrection, 'optionalCall', _8 => _8(correction.adj)]);
261
+ if (callbackResult === false) {
262
+ throw err;
263
+ }
264
+ offerParams = applyAdjustment(offerParams, correction.adj, currentParams);
265
+ corrections.push(correction.adj);
266
+ const correctedOffer = await client.createQuote(offerParams);
267
+ return { offer: correctedOffer, corrections, retries };
268
+ }
269
+ }
270
+ throw err;
271
+ }
272
+ }
273
+ throw new (0, _chunkXXTTXLCTcjs.DimesError)("market_moved_retries_exhausted", "Exhausted market-moved retries");
274
+ }
275
+
276
+
277
+
278
+
279
+
280
+
281
+
282
+ exports.buildQuoteParams = buildQuoteParams; exports.marketMovedCodes = marketMovedCodes; exports.quoteErrorHint = quoteErrorHint; exports.hintAdjustment = hintAdjustment; exports.executeQuote = executeQuote;
283
+ //# sourceMappingURL=chunk-JGK55KDX.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/alexemery/bl/dimes-sdk/dist/chunk-JGK55KDX.cjs","../src/quote/build-quote-params.ts","../src/quote/quote-error-hints.ts","../src/quote/quote.ts"],"names":[],"mappings":"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","file":"/Users/alexemery/bl/dimes-sdk/dist/chunk-JGK55KDX.cjs","sourcesContent":[null,"import type { CreateOfferParams } from \"../types\";\nimport type { QuoteParams } from \"../types/quote\";\n\nconst DEFAULT_LEVERAGE_STEP_BPS = 2500;\n\nexport function buildQuoteParams(params: QuoteParams, stepBps: number = DEFAULT_LEVERAGE_STEP_BPS): CreateOfferParams {\n const leverageBps = Math.round(params.leverageBps / stepBps) * stepBps;\n const notionalUsdPips = Math.round(params.collateralUsd * leverageBps);\n\n return {\n marketTicker: params.marketTicker,\n effectiveSide: params.side,\n leverageBps,\n notionalAmountUsdPips: notionalUsdPips.toString(),\n slippageBps: params.slippageBps,\n };\n}\n","const pipsPerUsd = 10_000;\nconst bpsPerUnit = 10_000;\nconst bpsPerPct = 100;\nconst centsFactor = 100;\nconst decimalPlaces = 2;\n\nexport const marketMovedCodes = new Set([\n \"quote_slippage_too_high\",\n \"quote_insufficient_liquidity\",\n \"quote_entry_price_out_of_range\",\n \"quote_entry_bid_depth_too_low\",\n \"quote_entry_depth_too_low\",\n \"quote_entry_spread_too_wide\",\n]);\n\nexport type QuoteHint =\n | { kind: \"use-max-collateral\"; maxCollateralUsd: number; minCollateralUsd: number }\n | { kind: \"clamp-leverage\"; maxLeverageBps?: number }\n | { kind: \"raise-leverage\"; minLeverageBps: number }\n | { kind: \"raise-slippage\"; currentSlippageBps: number; maxSlippageBps: number }\n | { kind: \"market-full\" }\n | null;\n\ntype Params = Record<string, unknown> | null | undefined;\n\nfunction num(params: Params, key: string): number | null {\n if (!params) {\n return null;\n }\n const raw = params[key];\n if (raw === null || raw === undefined) {\n return null;\n }\n // eslint-disable-next-line no-restricted-syntax\n const n = typeof raw === \"string\" ? Number(raw) : typeof raw === \"number\" ? raw : NaN;\n return Number.isFinite(n) ? n : null;\n}\n\nfunction pipsToUsd(pips: number): number {\n return pips / pipsPerUsd;\n}\n\nfunction notionalPipsToCollateralUsd(notionalPips: number, leverageBps: number): number | null {\n if (!Number.isFinite(leverageBps) || leverageBps <= 0) {\n return null;\n }\n return (notionalPips * bpsPerUnit) / leverageBps / pipsPerUsd;\n}\n\nfunction resolveMaxCollateralHint(params: Params, context: { leverageBps: number }, capacityKey: string): QuoteHint {\n const serverMaxCollateralPips = num(params, \"maxSupportedCollateralUsdPips\");\n const capacityPips = num(params, capacityKey);\n const minNotionalPips = num(params, \"minNotionalUsdPips\");\n\n const fromServer = serverMaxCollateralPips !== null ? pipsToUsd(serverMaxCollateralPips) : null;\n const fromCapacity = capacityPips !== null ? notionalPipsToCollateralUsd(capacityPips, context.leverageBps) : null;\n const maxCollateralUsd =\n fromServer !== null && fromCapacity !== null ? Math.min(fromServer, fromCapacity) : (fromServer ?? fromCapacity);\n\n const minCollateralUsd =\n minNotionalPips !== null ? notionalPipsToCollateralUsd(minNotionalPips, context.leverageBps) : null;\n\n if (maxCollateralUsd === null || minCollateralUsd === null) {\n return null;\n }\n if (maxCollateralUsd < minCollateralUsd) {\n return { kind: \"market-full\" };\n }\n return { kind: \"use-max-collateral\", maxCollateralUsd, minCollateralUsd };\n}\n\n// eslint-disable-next-line complexity\nexport function quoteErrorHint(code: string | null, params: Params, context: { leverageBps: number }): QuoteHint {\n if (!code) {\n return null;\n }\n\n switch (code) {\n case \"quote_side_capacity_exceeded\":\n case \"quote_user_position_limit_exceeded\":\n case \"quote_market_position_limit_exceeded\":\n case \"quote_side_position_limit_exceeded\":\n case \"quote_global_position_limit_exceeded\":\n case \"quote_partner_position_limit_exceeded\":\n return resolveMaxCollateralHint(params, context, \"availableCapacityUsdPips\");\n\n case \"quote_insufficient_liquidity\":\n case \"notional_selector_insufficient_liquidity\":\n return resolveMaxCollateralHint(params, context, \"slippageMaxUsdPips\");\n\n case \"quote_leverage_exceeds_maximum\":\n case \"quote_leverage_exceeds_model_max\": {\n const maxLeverageBps = num(params, \"maxLeverageBps\");\n if (maxLeverageBps === null) {\n return null;\n }\n return { kind: \"clamp-leverage\", maxLeverageBps };\n }\n\n case \"quote_leverage_too_high_for_price\": {\n const maxLeverageBps = num(params, \"maxAcceptableLeverageBps\");\n if (maxLeverageBps === null) {\n return null;\n }\n return { kind: \"clamp-leverage\", maxLeverageBps };\n }\n\n case \"quote_leverage_below_minimum\": {\n const minLeverageBps = num(params, \"minLeverageBps\");\n if (minLeverageBps === null) {\n return null;\n }\n return { kind: \"raise-leverage\", minLeverageBps };\n }\n\n case \"quote_slippage_too_high\": {\n const currentSlippageBps = num(params, \"currentSlippageBps\");\n const maxSlippageBps = num(params, \"maxSlippageBps\");\n if (currentSlippageBps === null || maxSlippageBps === null) {\n return null;\n }\n return { kind: \"raise-slippage\", currentSlippageBps, maxSlippageBps };\n }\n\n default:\n return null;\n }\n}\n\nexport type CorrectedField = \"collateral\" | \"leverage\" | \"slippage\";\n\nexport type HintAdjustment =\n | {\n field: \"collateral\";\n fromValue: number;\n toValue: number;\n toLabel: string;\n reason: \"max-collateral\";\n }\n | {\n field: \"leverage\";\n fromValue: number;\n toValue: number;\n toLabel: string;\n reason: \"clamp-max\" | \"raise-min\";\n }\n | {\n field: \"slippage\";\n fromValue: number;\n toValue: number;\n toLabel: string;\n reason: \"raise-slippage\";\n }\n | null;\n\nfunction formatUsd(value: number): string {\n return new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: \"USD\",\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }).format(value);\n}\n\nfunction bpsToMultiplier(bps: number): string {\n return `${(bps / bpsPerUnit).toFixed(1).replace(/\\.0$/, \"\")}x`;\n}\n\nexport function hintAdjustment(\n hint: QuoteHint,\n current: { collateralUsd: number; leverageBps: number; slippageBps: number },\n): HintAdjustment {\n if (!hint) {\n return null;\n }\n\n switch (hint.kind) {\n case \"use-max-collateral\": {\n const to = Math.max(0, Math.floor(hint.maxCollateralUsd * centsFactor) / centsFactor);\n if (to <= 0) {\n return null;\n }\n return {\n field: \"collateral\",\n fromValue: current.collateralUsd,\n toValue: to,\n toLabel: formatUsd(to),\n reason: \"max-collateral\",\n };\n }\n case \"clamp-leverage\": {\n if (hint.maxLeverageBps === undefined) {\n return null;\n }\n return {\n field: \"leverage\",\n fromValue: current.leverageBps,\n toValue: hint.maxLeverageBps,\n toLabel: bpsToMultiplier(hint.maxLeverageBps),\n reason: \"clamp-max\",\n };\n }\n case \"raise-leverage\":\n return {\n field: \"leverage\",\n fromValue: current.leverageBps,\n toValue: hint.minLeverageBps,\n toLabel: bpsToMultiplier(hint.minLeverageBps),\n reason: \"raise-min\",\n };\n case \"raise-slippage\":\n return {\n field: \"slippage\",\n fromValue: hint.currentSlippageBps,\n toValue: hint.maxSlippageBps,\n toLabel: `${(hint.maxSlippageBps / bpsPerPct).toFixed(decimalPlaces).replace(/\\.?0+$/, \"\")}%`,\n reason: \"raise-slippage\",\n };\n case \"market-full\":\n return null;\n default:\n return null;\n }\n}\n","import { DimesApiError, DimesError } from \"../errors/dimes-error\";\nimport type { CreateOfferParams, Offer } from \"../types\";\nimport type { QuoteOptions, QuoteParams, QuoteResult } from \"../types/quote\";\nimport { buildQuoteParams } from \"./build-quote-params\";\nimport { type HintAdjustment, hintAdjustment, marketMovedCodes, quoteErrorHint } from \"./quote-error-hints\";\n\nexport interface QuoteClient {\n createDraftQuote(params: CreateOfferParams): Promise<Offer>;\n promoteDraftQuote(draftId: string): Promise<Offer>;\n createQuote(params: CreateOfferParams): Promise<Offer>;\n}\n\nconst DEFAULT_MAX_RETRIES = 3;\n\nfunction isMarketMovedError(err: unknown): boolean {\n return err instanceof DimesApiError && marketMovedCodes.has(err.code);\n}\n\nfunction applyAdjustment(\n params: CreateOfferParams,\n adj: NonNullable<HintAdjustment>,\n currentParams: QuoteParams,\n): CreateOfferParams {\n switch (adj.field) {\n case \"collateral\": {\n const notionalUsdPips = Math.round(adj.toValue * params.leverageBps);\n return { ...params, notionalAmountUsdPips: notionalUsdPips.toString() };\n }\n case \"leverage\": {\n const notionalUsdPips = Math.round(currentParams.collateralUsd * adj.toValue);\n return {\n ...params,\n leverageBps: adj.toValue,\n notionalAmountUsdPips: notionalUsdPips.toString(),\n };\n }\n case \"slippage\":\n return { ...params, slippageBps: adj.toValue };\n default:\n return params;\n }\n}\n\nfunction handleMarketMoved(err: unknown, attempt: number, maxRetries: number): boolean {\n return isMarketMovedError(err) && attempt < maxRetries;\n}\n\nfunction handleCorrection(err: unknown, currentParams: QuoteParams): { adj: NonNullable<HintAdjustment> } | null {\n if (!(err instanceof DimesApiError)) {\n return null;\n }\n\n const hint = quoteErrorHint(err.code, err.params, {\n leverageBps: currentParams.leverageBps,\n });\n\n const adj = hintAdjustment(hint, {\n collateralUsd: currentParams.collateralUsd,\n leverageBps: currentParams.leverageBps,\n slippageBps: currentParams.slippageBps,\n });\n\n if (!adj) {\n return null;\n }\n\n return { adj };\n}\n\n// eslint-disable-next-line complexity\nexport async function executeQuote(\n client: QuoteClient,\n params: QuoteParams,\n options?: QuoteOptions,\n): Promise<QuoteResult> {\n const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;\n const autoCorrect = options?.autoCorrect ?? true;\n const corrections: NonNullable<HintAdjustment>[] = [];\n let retries = 0;\n\n let offerParams = buildQuoteParams(params);\n const currentParams = { ...params };\n\n const draft = await client.createDraftQuote(offerParams);\n options?.onDraftReady?.(draft);\n\n let currentDraft: Offer = draft;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const promotedOffer = await client.promoteDraftQuote(currentDraft.id);\n return { offer: promotedOffer, corrections, retries };\n } catch (err) {\n if (handleMarketMoved(err, attempt, maxRetries)) {\n const newDraft = await client.createDraftQuote(offerParams);\n retries++;\n\n const callbackResult = options?.onMarketMoved?.({\n originalDraft: currentDraft,\n newDraft,\n retryCount: retries,\n });\n\n if (callbackResult === false) {\n throw err;\n }\n\n currentDraft = newDraft;\n continue;\n }\n\n if (autoCorrect) {\n const correction = handleCorrection(err, currentParams);\n\n if (correction) {\n const callbackResult = options?.onCorrection?.(correction.adj);\n if (callbackResult === false) {\n throw err;\n }\n\n offerParams = applyAdjustment(offerParams, correction.adj, currentParams);\n corrections.push(correction.adj);\n\n const correctedOffer = await client.createQuote(offerParams);\n return { offer: correctedOffer, corrections, retries };\n }\n }\n\n throw err;\n }\n }\n\n throw new DimesError(\"market_moved_retries_exhausted\", \"Exhausted market-moved retries\");\n}\n"]}