@dimes-dot-fi/sdk 2.1.0 → 2.3.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 (52) hide show
  1. package/dist/{aliases-BJyM8ydu.d.cts → aliases-Dne14KBa.d.cts} +125 -11
  2. package/dist/{aliases-BJyM8ydu.d.ts → aliases-Dne14KBa.d.ts} +125 -11
  3. package/dist/{chunk-PZCBUVPD.mjs → chunk-4OKYU5D7.mjs} +5 -2
  4. package/dist/{chunk-PZCBUVPD.mjs.map → chunk-4OKYU5D7.mjs.map} +1 -1
  5. package/dist/{chunk-5VHDXPRV.mjs → chunk-7SGBJTUW.mjs} +2 -2
  6. package/dist/{chunk-72LTVPD2.cjs → chunk-E6YJDY4F.cjs} +5 -2
  7. package/dist/chunk-E6YJDY4F.cjs.map +1 -0
  8. package/dist/{chunk-7SAMK7CS.cjs → chunk-GY6L2QGR.cjs} +5 -5
  9. package/dist/{chunk-7SAMK7CS.cjs.map → chunk-GY6L2QGR.cjs.map} +1 -1
  10. package/dist/{chunk-T67Z74J3.mjs → chunk-IJO5E22G.mjs} +2 -2
  11. package/dist/{chunk-PK2PRTQW.mjs → chunk-TYR33WJW.mjs} +9 -4
  12. package/dist/chunk-TYR33WJW.mjs.map +1 -0
  13. package/dist/{chunk-FAW2C5AM.cjs → chunk-UPNJRN65.cjs} +4 -4
  14. package/dist/{chunk-FAW2C5AM.cjs.map → chunk-UPNJRN65.cjs.map} +1 -1
  15. package/dist/{chunk-53U53KZ2.cjs → chunk-UYDXDYEP.cjs} +9 -4
  16. package/dist/chunk-UYDXDYEP.cjs.map +1 -0
  17. package/dist/contract/index.cjs +21 -14
  18. package/dist/contract/index.cjs.map +1 -1
  19. package/dist/contract/index.d.cts +3 -3
  20. package/dist/contract/index.d.ts +3 -3
  21. package/dist/contract/index.mjs +9 -2
  22. package/dist/contract/index.mjs.map +1 -1
  23. package/dist/{dimes-client-ntybPwHK.d.cts → dimes-client-D9tohawC.d.cts} +2 -1
  24. package/dist/{dimes-client-DLbPP30g.d.ts → dimes-client-DJ1d_p31.d.ts} +2 -1
  25. package/dist/{dimes-error-BhKtCgba.d.cts → dimes-error-E9yPAZb-.d.cts} +1 -1
  26. package/dist/{dimes-error-DjxvjzCZ.d.ts → dimes-error-hSoOierP.d.ts} +1 -1
  27. package/dist/index.cjs +14 -9
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +7 -7
  30. package/dist/index.d.ts +7 -7
  31. package/dist/index.mjs +10 -5
  32. package/dist/index.mjs.map +1 -1
  33. package/dist/{quote-BoTWtznc.d.ts → quote-D4QunMtN.d.ts} +2 -2
  34. package/dist/{quote-Bc9H5-2H.d.cts → quote-sWguOcoJ.d.cts} +2 -2
  35. package/dist/react/index.cjs +30 -12
  36. package/dist/react/index.cjs.map +1 -1
  37. package/dist/react/index.d.cts +7 -5
  38. package/dist/react/index.d.ts +7 -5
  39. package/dist/react/index.mjs +25 -7
  40. package/dist/react/index.mjs.map +1 -1
  41. package/dist/{types-ClHQbIcY.d.ts → types-BHU4Qq7e.d.ts} +6 -3
  42. package/dist/{types-Co-2bQSi.d.cts → types-Bvj_WDbX.d.cts} +6 -3
  43. package/dist/ws/index.cjs +3 -3
  44. package/dist/ws/index.d.cts +3 -3
  45. package/dist/ws/index.d.ts +3 -3
  46. package/dist/ws/index.mjs +2 -2
  47. package/package.json +1 -1
  48. package/dist/chunk-53U53KZ2.cjs.map +0 -1
  49. package/dist/chunk-72LTVPD2.cjs.map +0 -1
  50. package/dist/chunk-PK2PRTQW.mjs.map +0 -1
  51. /package/dist/{chunk-5VHDXPRV.mjs.map → chunk-7SGBJTUW.mjs.map} +0 -0
  52. /package/dist/{chunk-T67Z74J3.mjs.map → chunk-IJO5E22G.mjs.map} +0 -0
@@ -1,4 +1,4 @@
1
- import { M as Market, C as CreateQuoteParams, Q as Quote, P as Position, c as PositionTransactions, d as ContractInfo, e as CustomerLimit, F as FeeRates, f as FeeReportParams, g as FeeReport } from './aliases-BJyM8ydu.cjs';
1
+ import { M as Market, C as CreateQuoteParams, Q as Quote, P as Position, c as PositionTransactions, d as PositionPartialCloseList, e as ContractInfo, f as CustomerLimit, F as FeeRates, g as FeeReportParams, h as FeeReport } from './aliases-Dne14KBa.cjs';
2
2
 
3
3
  declare const marketMovedCodes: Set<string>;
4
4
  type QuoteHint = {
@@ -175,6 +175,7 @@ declare class DimesClient {
175
175
  createQuote(params: CreateQuoteParams): Promise<Quote>;
176
176
  getPositions(params?: GetPositionsParams): Promise<Position[]>;
177
177
  getPositionTransactions(positionId: string): Promise<PositionTransactions>;
178
+ getPositionPartialCloses(positionId: string): Promise<PositionPartialCloseList>;
178
179
  cancelPosition(positionId: string): Promise<void>;
179
180
  getContractInfo(): Promise<ContractInfo>;
180
181
  getUserLimits(): Promise<CustomerLimit>;
@@ -1,4 +1,4 @@
1
- import { M as Market, C as CreateQuoteParams, Q as Quote, P as Position, c as PositionTransactions, d as ContractInfo, e as CustomerLimit, F as FeeRates, f as FeeReportParams, g as FeeReport } from './aliases-BJyM8ydu.js';
1
+ import { M as Market, C as CreateQuoteParams, Q as Quote, P as Position, c as PositionTransactions, d as PositionPartialCloseList, e as ContractInfo, f as CustomerLimit, F as FeeRates, g as FeeReportParams, h as FeeReport } from './aliases-Dne14KBa.js';
2
2
 
3
3
  declare const marketMovedCodes: Set<string>;
4
4
  type QuoteHint = {
@@ -175,6 +175,7 @@ declare class DimesClient {
175
175
  createQuote(params: CreateQuoteParams): Promise<Quote>;
176
176
  getPositions(params?: GetPositionsParams): Promise<Position[]>;
177
177
  getPositionTransactions(positionId: string): Promise<PositionTransactions>;
178
+ getPositionPartialCloses(positionId: string): Promise<PositionPartialCloseList>;
178
179
  cancelPosition(positionId: string): Promise<void>;
179
180
  getContractInfo(): Promise<ContractInfo>;
180
181
  getUserLimits(): Promise<CustomerLimit>;
@@ -1,4 +1,4 @@
1
- import { Q as QuoteHint } from './dimes-client-ntybPwHK.cjs';
1
+ import { Q as QuoteHint } from './dimes-client-D9tohawC.cjs';
2
2
 
3
3
  declare class DimesError extends Error {
4
4
  readonly code: string;
@@ -1,4 +1,4 @@
1
- import { Q as QuoteHint } from './dimes-client-DLbPP30g.js';
1
+ import { Q as QuoteHint } from './dimes-client-DJ1d_p31.js';
2
2
 
3
3
  declare class DimesError extends Error {
4
4
  readonly code: string;
package/dist/index.cjs CHANGED
@@ -5,17 +5,17 @@
5
5
 
6
6
 
7
7
 
8
- var _chunk7SAMK7CScjs = require('./chunk-7SAMK7CS.cjs');
8
+ var _chunkGY6L2QGRcjs = require('./chunk-GY6L2QGR.cjs');
9
9
 
10
10
 
11
11
 
12
12
 
13
13
 
14
14
 
15
- var _chunk72LTVPD2cjs = require('./chunk-72LTVPD2.cjs');
15
+ var _chunkE6YJDY4Fcjs = require('./chunk-E6YJDY4F.cjs');
16
16
 
17
17
 
18
- var _chunk53U53KZ2cjs = require('./chunk-53U53KZ2.cjs');
18
+ var _chunkUYDXDYEPcjs = require('./chunk-UYDXDYEP.cjs');
19
19
 
20
20
  // src/client/dimes-client.ts
21
21
  var _humps = require('humps');
@@ -60,7 +60,7 @@ async function throwFromResponse(response) {
60
60
  const message = _nullishCoalesce(_optionalChain([parsed, 'optionalAccess', _5 => _5.error, 'optionalAccess', _6 => _6.message]), () => ( `API error ${response.status}`));
61
61
  const rawParams = _optionalChain([parsed, 'optionalAccess', _7 => _7.error, 'optionalAccess', _8 => _8.params]);
62
62
  const params = rawParams ? _humps.camelizeKeys.call(void 0, rawParams) : null;
63
- throw new (0, _chunk72LTVPD2cjs.DimesApiError)({ status: response.status, code, type, message, params });
63
+ throw new (0, _chunkE6YJDY4Fcjs.DimesApiError)({ status: response.status, code, type, message, params });
64
64
  }
65
65
  var HttpClient = class {
66
66
 
@@ -193,6 +193,11 @@ var DimesClient = class {
193
193
  `/v1/prediction-markets/positions/${encodeURIComponent(positionId)}/transactions`
194
194
  );
195
195
  }
196
+ async getPositionPartialCloses(positionId) {
197
+ return this.http.request(
198
+ `/v1/prediction-markets/positions/${encodeURIComponent(positionId)}/partial-closes`
199
+ );
200
+ }
196
201
  async cancelPosition(positionId) {
197
202
  await this.http.request(`/v1/prediction-markets/positions/${encodeURIComponent(positionId)}`, {
198
203
  method: "DELETE"
@@ -275,7 +280,7 @@ var ApiKeyAuth = (_class = class {
275
280
  });
276
281
  if (!response.ok) {
277
282
  const text = await response.text();
278
- throw new (0, _chunk72LTVPD2cjs.DimesError)("auth_token_failed", `Failed to obtain auth token (${response.status}): ${text}`);
283
+ throw new (0, _chunkE6YJDY4Fcjs.DimesError)("auth_token_failed", `Failed to obtain auth token (${response.status}): ${text}`);
279
284
  }
280
285
  const data = await response.json();
281
286
  this.jwt = data.token;
@@ -318,7 +323,7 @@ var JwtAuth = (_class2 = class {
318
323
  const response = await this.fetchFn(this.tokenUrl);
319
324
  if (!response.ok) {
320
325
  const text = await response.text();
321
- throw new (0, _chunk72LTVPD2cjs.DimesError)(
326
+ throw new (0, _chunkE6YJDY4Fcjs.DimesError)(
322
327
  "auth_token_failed",
323
328
  `Failed to fetch token from ${this.tokenUrl} (${response.status}): ${text}`
324
329
  );
@@ -377,14 +382,14 @@ function rejectionReasonText(code) {
377
382
  if (!code) {
378
383
  return "Not eligible for new positions";
379
384
  }
380
- const stripped = code.replace(/^quote_/i, "").replaceAll("_", " ").toLowerCase();
385
+ const stripped = code.replace(/^quote_/i, "").replace(/^notional_selector_/i, "").replaceAll("_", " ").toLowerCase();
381
386
  return stripped.charAt(0).toUpperCase() + stripped.slice(1);
382
387
  }
383
388
  function rejectionReasonShort(code) {
384
389
  if (!code) {
385
390
  return "unavailable";
386
391
  }
387
- const stripped = code.replace(/^quote_/i, "").replace(/_exceeded$/i, "").replace(/_too_(low|high)$/i, "").replaceAll("_", " ").toLowerCase();
392
+ const stripped = code.replace(/^quote_/i, "").replace(/^notional_selector_/i, "").replace(/_exceeded$/i, "").replace(/_too_(low|high)$/i, "").replaceAll("_", " ").toLowerCase();
388
393
  return stripped;
389
394
  }
390
395
 
@@ -625,5 +630,5 @@ function clampCloseTokenUnits(value, min, max) {
625
630
 
626
631
 
627
632
 
628
- exports.ApiKeyAuth = ApiKeyAuth; exports.DimesApiError = _chunk72LTVPD2cjs.DimesApiError; exports.DimesClient = DimesClient; exports.DimesContractError = _chunk72LTVPD2cjs.DimesContractError; exports.DimesError = _chunk72LTVPD2cjs.DimesError; exports.JwtAuth = JwtAuth; exports.buildQuoteParams = _chunk7SAMK7CScjs.buildQuoteParams; exports.clampCloseTokenUnits = clampCloseTokenUnits; exports.closeTokenUnitsForPct = closeTokenUnitsForPct; exports.computeMaxGain = computeMaxGain; exports.computeOriginationFeeUsdcUnits = computeOriginationFeeUsdcUnits; exports.computePolymarketTradingFee = computePolymarketTradingFee; exports.defaultSide = defaultSide; exports.estimateLiquidationPrice = estimateLiquidationPrice; exports.executeQuote = _chunk7SAMK7CScjs.executeQuote; exports.expectedPositionTokenUnits = expectedPositionTokenUnits; exports.fallbackMinPartialCloseTokenUnits = fallbackMinPartialCloseTokenUnits; exports.formatErrorMessage = _chunk72LTVPD2cjs.formatErrorMessage; exports.getOriginationFeeBreakdown = getOriginationFeeBreakdown; exports.getSidedEligibility = getSidedEligibility; exports.hintAdjustment = _chunk7SAMK7CScjs.hintAdjustment; exports.isClosedPosition = isClosedPosition; exports.isFullyClosed = isFullyClosed; exports.isFullyOpen = isFullyOpen; exports.isMarketMovedError = _chunk7SAMK7CScjs.isMarketMovedError; exports.isOpenPosition = isOpenPosition; exports.leverageMaxBps = leverageMaxBps; exports.marketMovedCodes = _chunk7SAMK7CScjs.marketMovedCodes; exports.maxLeverageBpsAtNotional = maxLeverageBpsAtNotional; exports.maxViableLeverageBpsForCollateral = maxViableLeverageBpsForCollateral; exports.partialCloseMinFractionBps = partialCloseMinFractionBps; exports.partialCloseMinTokens = partialCloseMinTokens; exports.pctBpsForCloseTokenUnits = pctBpsForCloseTokenUnits; exports.positionEventTypes = _chunk53U53KZ2cjs.positionEventTypes; exports.quoteErrorHint = _chunk7SAMK7CScjs.quoteErrorHint; exports.rejectionReasonShort = rejectionReasonShort; exports.rejectionReasonText = rejectionReasonText; exports.resolveFriendlyMessage = _chunk72LTVPD2cjs.resolveFriendlyMessage; exports.resolveOriginationFeeBps = resolveOriginationFeeBps; exports.resolveProtocolOriginationFeeBps = resolveProtocolOriginationFeeBps; exports.tokenUnitsPerToken = tokenUnitsPerToken;
633
+ exports.ApiKeyAuth = ApiKeyAuth; exports.DimesApiError = _chunkE6YJDY4Fcjs.DimesApiError; exports.DimesClient = DimesClient; exports.DimesContractError = _chunkE6YJDY4Fcjs.DimesContractError; exports.DimesError = _chunkE6YJDY4Fcjs.DimesError; exports.JwtAuth = JwtAuth; exports.buildQuoteParams = _chunkGY6L2QGRcjs.buildQuoteParams; exports.clampCloseTokenUnits = clampCloseTokenUnits; exports.closeTokenUnitsForPct = closeTokenUnitsForPct; exports.computeMaxGain = computeMaxGain; exports.computeOriginationFeeUsdcUnits = computeOriginationFeeUsdcUnits; exports.computePolymarketTradingFee = computePolymarketTradingFee; exports.defaultSide = defaultSide; exports.estimateLiquidationPrice = estimateLiquidationPrice; exports.executeQuote = _chunkGY6L2QGRcjs.executeQuote; exports.expectedPositionTokenUnits = expectedPositionTokenUnits; exports.fallbackMinPartialCloseTokenUnits = fallbackMinPartialCloseTokenUnits; exports.formatErrorMessage = _chunkE6YJDY4Fcjs.formatErrorMessage; exports.getOriginationFeeBreakdown = getOriginationFeeBreakdown; exports.getSidedEligibility = getSidedEligibility; exports.hintAdjustment = _chunkGY6L2QGRcjs.hintAdjustment; exports.isClosedPosition = isClosedPosition; exports.isFullyClosed = isFullyClosed; exports.isFullyOpen = isFullyOpen; exports.isMarketMovedError = _chunkGY6L2QGRcjs.isMarketMovedError; exports.isOpenPosition = isOpenPosition; exports.leverageMaxBps = leverageMaxBps; exports.marketMovedCodes = _chunkGY6L2QGRcjs.marketMovedCodes; exports.maxLeverageBpsAtNotional = maxLeverageBpsAtNotional; exports.maxViableLeverageBpsForCollateral = maxViableLeverageBpsForCollateral; exports.partialCloseMinFractionBps = partialCloseMinFractionBps; exports.partialCloseMinTokens = partialCloseMinTokens; exports.pctBpsForCloseTokenUnits = pctBpsForCloseTokenUnits; exports.positionEventTypes = _chunkUYDXDYEPcjs.positionEventTypes; exports.quoteErrorHint = _chunkGY6L2QGRcjs.quoteErrorHint; exports.rejectionReasonShort = rejectionReasonShort; exports.rejectionReasonText = rejectionReasonText; exports.resolveFriendlyMessage = _chunkE6YJDY4Fcjs.resolveFriendlyMessage; exports.resolveOriginationFeeBps = resolveOriginationFeeBps; exports.resolveProtocolOriginationFeeBps = resolveProtocolOriginationFeeBps; exports.tokenUnitsPerToken = tokenUnitsPerToken;
629
634
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/alexemery/bl/dimes-sdk/dist/index.cjs","../src/client/dimes-client.ts","../src/client/http.ts","../src/client/auth.ts","../src/types/aliases.ts","../src/utils/eligibility.ts","../src/utils/leverage.ts","../src/utils/fees.ts","../src/utils/max-gain.ts","../src/utils/partial-close.ts"],"names":["BPS_DIVISOR"],"mappings":"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EAAA;AACiB,EAAA;AAEqB,EAAA;AACD,EAAA;AAEV,EAAA;AAC7D;AAW6F;AACnE,EAAA;AACf,IAAA;AACT,EAAA;AACwC,EAAA;AACX,EAAA;AACwBA,EAAAA;AACY,EAAA;AACnE;AAqBE;AAE+BA,EAAAA;AACZ,EAAA;AACV,IAAA;AACT,EAAA;AACuD,EAAA;AACRA,EAAAA;AACjD;AAyCmE;AAC3B,EAAA;AACwB,EAAA;AAE9B,EAAA;AAEzB,EAAA;AACL,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACF;ARkZyE;AACA;AS3iBrD;AACI;AAEU;AAEG;AAEK;AAE+C;AACtB,EAAA;AAEvB,EAAA;AAC5C;AAEqG;AACtE,EAAA;AACpB,IAAA;AACT,EAAA;AAEqE,EAAA;AACvE;AAEsF;AACxC,EAAA;AACA,EAAA;AAES,EAAA;AACvD;AAEsF;AACnE,EAAA;AACR,IAAA;AACT,EAAA;AAEiB,EAAA;AACR,IAAA;AACT,EAAA;AAEO,EAAA;AACT;ATiiByE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/Users/alexemery/bl/dimes-sdk/dist/index.cjs","sourcesContent":[null,"import { decamelizeKeys } from \"humps\";\nimport type {\n ContractInfo,\n CreateQuoteParams,\n CustomerLimit,\n FeeRates,\n FeeReport,\n FeeReportParams,\n Market,\n Paginated,\n Position,\n PositionTransactions,\n Quote,\n} from \"../types\";\nimport type { AuthProvider } from \"./auth\";\nimport { HttpClient } from \"./http\";\n\nexport interface DimesClientOptions {\n baseUrl?: string;\n auth: AuthProvider;\n fetch?: typeof globalThis.fetch;\n maxRetries?: number;\n maxRetryDelayMs?: number;\n}\n\nexport type MarketSort = \"ticker_asc\" | \"depth_desc\" | \"discovered_at_desc\";\n\nexport type MarketExpand = \"total_count\" | \"prices\";\n\nexport type PositionStatus = \"open\" | \"unwinding\" | \"pending\" | \"closing\" | \"closed\" | \"settled\" | \"liquidated\";\n\nexport interface GetMarketsParams {\n limit?: number;\n startingAfter?: string;\n endingBefore?: string;\n expand?: MarketExpand[];\n sort?: MarketSort;\n acceptingNewPositions?: boolean;\n category?: string;\n status?: string;\n provider?: \"polymarket\" | \"kalshi\";\n /** Free-text search across market tickers and titles. */\n query?: string;\n}\n\n/** @deprecated Use {@link GetMarketsParams} with `query` and {@link DimesClient.getMarkets}. */\nexport interface SearchMarketsParams extends GetMarketsParams {\n query: string;\n}\n\nexport interface GetPositionsParams {\n limit?: number;\n startingAfter?: string;\n endingBefore?: string;\n expand?: string[];\n sortBy?: \"created_at\" | \"closed_at\";\n sortDirection?: \"asc\" | \"desc\";\n status?: PositionStatus;\n state?: \"active\" | \"inactive\";\n}\n\nexport interface GetFeeRatesParams {\n ticker?: string;\n}\n\nfunction buildQueryFromEntries(entries: [string, unknown][]): string {\n const filtered = entries.filter(([, v]) => v !== undefined && v !== null);\n if (filtered.length === 0) {\n return \"\";\n }\n\n const search = new URLSearchParams();\n for (const [key, value] of filtered) {\n search.set(\n key.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`),\n String(value),\n );\n }\n\n return `?${search.toString()}`;\n}\n\nexport class DimesClient {\n /** The resolved API base URL. Useful for constructing WebSocket clients against the same host. */\n public readonly baseUrl: string;\n\n private readonly http: HttpClient;\n\n private readonly auth: AuthProvider;\n\n constructor(options: DimesClientOptions) {\n this.baseUrl = options.baseUrl ?? \"https://api.dimes.fi\";\n this.auth = options.auth;\n this.http = new HttpClient({\n baseUrl: this.baseUrl,\n auth: options.auth,\n fetch: options.fetch,\n maxRetries: options.maxRetries,\n maxRetryDelayMs: options.maxRetryDelayMs,\n });\n }\n\n /** Synchronously return the current cached JWT, or null. Returns null if the auth provider does not expose one. */\n public getToken(): string | null {\n return this.auth.getToken?.() ?? null;\n }\n\n public async getMarkets(params?: GetMarketsParams): Promise<Paginated<Market>> {\n const query = params ? buildQueryFromEntries(Object.entries(params)) : \"\";\n return this.http.request<Paginated<Market>>(`/v1/prediction-markets/markets${query}`);\n }\n\n public async getMarket(ticker: string): Promise<Market> {\n return this.http.request<Market>(`/v1/prediction-markets/markets/${encodeURIComponent(ticker)}`);\n }\n\n /**\n * @deprecated The `/markets/search` path is deprecated. Use {@link getMarkets} with a `query` param:\n * `getMarkets({ query: \"bitcoin\" })`.\n */\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- this IS the deprecated method\n public async searchMarkets(params: SearchMarketsParams): Promise<Paginated<Market>> {\n return this.getMarkets(params);\n }\n\n public async createDraftQuote(params: CreateQuoteParams): Promise<Quote> {\n return this.http.request<Quote>(\"/v1/prediction-markets/draft-quotes\", {\n method: \"POST\",\n body: JSON.stringify(decamelizeKeys(params)),\n });\n }\n\n public async promoteDraftQuote(draftId: string): Promise<Quote> {\n return this.http.request<Quote>(`/v1/prediction-markets/promoted-quotes/${encodeURIComponent(draftId)}`, {\n method: \"POST\",\n });\n }\n\n public async createQuote(params: CreateQuoteParams): Promise<Quote> {\n return this.http.request<Quote>(\"/v1/prediction-markets/quotes\", {\n method: \"POST\",\n body: JSON.stringify(decamelizeKeys(params)),\n });\n }\n\n public async getPositions(params?: GetPositionsParams): Promise<Position[]> {\n const query = params ? buildQueryFromEntries(Object.entries(params)) : \"\";\n return this.http.requestList<Position>(`/v1/prediction-markets/positions${query}`);\n }\n\n public async getPositionTransactions(positionId: string): Promise<PositionTransactions> {\n return this.http.request<PositionTransactions>(\n `/v1/prediction-markets/positions/${encodeURIComponent(positionId)}/transactions`,\n );\n }\n\n public async cancelPosition(positionId: string): Promise<void> {\n await this.http.request<unknown>(`/v1/prediction-markets/positions/${encodeURIComponent(positionId)}`, {\n method: \"DELETE\",\n });\n }\n\n public async getContractInfo(): Promise<ContractInfo> {\n return this.http.request<ContractInfo>(\"/v1/prediction-markets/contract-info\");\n }\n\n public async getUserLimits(): Promise<CustomerLimit> {\n return this.http.request<CustomerLimit>(\"/v1/prediction-markets/user-limits\");\n }\n\n public async getPartnerLimits(): Promise<CustomerLimit> {\n return this.http.request<CustomerLimit>(\"/v1/prediction-markets/partner-limits\");\n }\n\n /**\n * @deprecated The `/limits` path was never served by the API. Use {@link getUserLimits}\n * (JWT/user context) or {@link getPartnerLimits} (API-key/partner context). This alias\n * forwards to `getUserLimits` and will be removed in a future major.\n */\n public async getLimits(): Promise<CustomerLimit> {\n return this.getUserLimits();\n }\n\n public async getFeeRates(params?: GetFeeRatesParams): Promise<FeeRates> {\n const query = params ? buildQueryFromEntries(Object.entries(params)) : \"\";\n return this.http.request<FeeRates>(`/v1/prediction-markets/fee-rates${query}`);\n }\n\n public async getFeeReport(params: FeeReportParams): Promise<FeeReport> {\n return this.http.request<FeeReport>(\"/v1/prediction-markets/fee-reports\", {\n method: \"POST\",\n body: JSON.stringify(decamelizeKeys(params)),\n });\n }\n}\n","import { camelizeKeys, type Camelized } from \"humps\";\nimport { DimesApiError } from \"../errors/dimes-error\";\nimport type { AuthProvider } from \"./auth\";\n\nexport type { Camelized };\n\ninterface ApiErrorBody {\n error?: {\n type?: string;\n code?: string;\n message: string;\n params?: Record<string, unknown>;\n };\n}\n\nconst HTTP_UNAUTHORIZED = 401;\nconst HTTP_TOO_MANY_REQUESTS = 429;\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_MAX_RETRY_DELAY_MS = 60_000;\nconst DEFAULT_RETRY_DELAY_MS = 1000;\nconst BACKOFF_FACTOR = 2;\nconst MS_PER_SECOND = 1000;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction parseRetryAfterMs(header: string | null, attempt: number): number {\n const fallbackMs = DEFAULT_RETRY_DELAY_MS * BACKOFF_FACTOR ** attempt;\n if (!header) {\n return fallbackMs;\n }\n\n const seconds = Number(header);\n if (!Number.isNaN(seconds) && seconds >= 0) {\n return seconds * MS_PER_SECOND;\n }\n\n const dateMs = Date.parse(header);\n if (!Number.isNaN(dateMs)) {\n return Math.max(0, dateMs - Date.now());\n }\n\n return fallbackMs;\n}\n\n// eslint-disable-next-line complexity\nasync function throwFromResponse(response: Response): Promise<never> {\n const rawBody = await response.text();\n let parsed: ApiErrorBody | null;\n try {\n parsed = rawBody ? (JSON.parse(rawBody) as ApiErrorBody) : null;\n } catch {\n parsed = null;\n }\n\n const code = parsed?.error?.code ?? \"unknown_error\";\n const type = parsed?.error?.type ?? null;\n const message = parsed?.error?.message ?? `API error ${response.status}`;\n const rawParams = parsed?.error?.params;\n const params = rawParams ? (camelizeKeys(rawParams) as Record<string, unknown>) : null;\n\n throw new DimesApiError({ status: response.status, code, type, message, params });\n}\n\nexport interface HttpClientOptions {\n baseUrl: string;\n auth: AuthProvider;\n fetch?: typeof globalThis.fetch;\n maxRetries?: number;\n maxRetryDelayMs?: number;\n}\n\nexport class HttpClient {\n private readonly baseUrl: string;\n\n private readonly auth: AuthProvider;\n\n private readonly fetchFn: typeof globalThis.fetch;\n\n private readonly maxRetries: number;\n\n private readonly maxRetryDelayMs: number;\n\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl;\n this.auth = options.auth;\n this.fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);\n this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;\n this.maxRetryDelayMs = options.maxRetryDelayMs ?? DEFAULT_MAX_RETRY_DELAY_MS;\n }\n\n public async request<T>(path: string, options?: RequestInit): Promise<T> {\n const authHeaders = await this.auth.getHeaders();\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...authHeaders,\n ...(options?.headers as Record<string, string> | undefined),\n };\n\n let response = await this.fetchFn(`${this.baseUrl}${path}`, {\n ...options,\n headers,\n });\n\n if (response.status === HTTP_UNAUTHORIZED && this.auth.refresh) {\n await this.auth.refresh();\n const retryHeaders = await this.auth.getHeaders();\n response = await this.fetchFn(`${this.baseUrl}${path}`, {\n ...options,\n headers: { ...headers, ...retryHeaders },\n });\n }\n\n for (let attempt = 0; response.status === HTTP_TOO_MANY_REQUESTS && attempt < this.maxRetries; attempt++) {\n const delayMs = parseRetryAfterMs(response.headers.get(\"retry-after\"), attempt);\n if (delayMs > this.maxRetryDelayMs) {\n break;\n }\n await sleep(delayMs);\n const freshAuth = await this.auth.getHeaders();\n response = await this.fetchFn(`${this.baseUrl}${path}`, {\n ...options,\n headers: { ...headers, ...freshAuth },\n });\n }\n\n if (!response.ok) {\n await throwFromResponse(response);\n }\n\n return camelizeKeys(await response.json()) as T;\n }\n\n public async requestList<T>(path: string, options?: RequestInit): Promise<T[]> {\n const result = await this.request<{ data: T[] }>(path, options);\n return result.data;\n }\n}\n","import { DimesError } from \"../errors/dimes-error\";\n\nexport interface AuthProvider {\n getHeaders(): Promise<Record<string, string>>;\n refresh?(): Promise<void>;\n /** Synchronously return the current cached JWT, or null if not yet obtained. Used by the WebSocket clients. */\n getToken?(): string | null;\n}\n\ninterface TokenResponse {\n token: string;\n expires_at: string;\n}\n\nexport interface ApiKeyAuthOptions {\n apiKey: string;\n walletAddress: string;\n baseUrl?: string;\n fetch?: typeof globalThis.fetch;\n}\n\nexport class ApiKeyAuth implements AuthProvider {\n private jwt: string | null = null;\n\n private expiresAt = 0;\n\n private refreshPromise: Promise<void> | null = null;\n\n private readonly apiKey: string;\n\n private readonly walletAddress: string;\n\n private readonly baseUrl: string;\n\n private readonly fetchFn: typeof globalThis.fetch;\n\n constructor(options: ApiKeyAuthOptions) {\n this.apiKey = options.apiKey;\n this.walletAddress = options.walletAddress;\n this.baseUrl = options.baseUrl ?? \"https://api.dimes.fi\";\n this.fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n public async getHeaders(): Promise<Record<string, string>> {\n const TOKEN_EXPIRY_BUFFER_MS = 30_000;\n if (!this.jwt || Date.now() >= this.expiresAt - TOKEN_EXPIRY_BUFFER_MS) {\n await this.refresh();\n }\n return { Authorization: `Bearer ${this.jwt}` };\n }\n\n public getToken(): string | null {\n return this.jwt;\n }\n\n public async refresh(): Promise<void> {\n if (this.refreshPromise) {\n await this.refreshPromise;\n return;\n }\n\n this.refreshPromise = this.fetchToken();\n try {\n await this.refreshPromise;\n } finally {\n this.refreshPromise = null;\n }\n }\n\n private async fetchToken(): Promise<void> {\n const response = await this.fetchFn(`${this.baseUrl}/v1/prediction-markets/tokens`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Api-Key ${this.apiKey}`,\n },\n body: JSON.stringify({ wallet_address: this.walletAddress }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new DimesError(\"auth_token_failed\", `Failed to obtain auth token (${response.status}): ${text}`);\n }\n\n const data = (await response.json()) as TokenResponse;\n this.jwt = data.token;\n this.expiresAt = new Date(data.expires_at).getTime();\n }\n}\n\nexport interface JwtAuthOptions {\n tokenUrl: string;\n fetch?: typeof globalThis.fetch;\n}\n\nexport class JwtAuth implements AuthProvider {\n private readonly fetchFn: typeof globalThis.fetch;\n\n private readonly tokenUrl: string;\n\n private jwt: string | null = null;\n\n private expiresAt = 0;\n\n private refreshPromise: Promise<void> | null = null;\n\n constructor(options: JwtAuthOptions) {\n this.tokenUrl = options.tokenUrl;\n this.fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n public async getHeaders(): Promise<Record<string, string>> {\n const TOKEN_EXPIRY_BUFFER_MS = 30_000;\n if (!this.jwt || Date.now() >= this.expiresAt - TOKEN_EXPIRY_BUFFER_MS) {\n await this.refresh();\n }\n return { Authorization: `Bearer ${this.jwt}` };\n }\n\n public getToken(): string | null {\n return this.jwt;\n }\n\n public async refresh(): Promise<void> {\n if (this.refreshPromise) {\n await this.refreshPromise;\n return;\n }\n\n this.refreshPromise = this.fetchToken();\n try {\n await this.refreshPromise;\n } finally {\n this.refreshPromise = null;\n }\n }\n\n private async fetchToken(): Promise<void> {\n const response = await this.fetchFn(this.tokenUrl);\n\n if (!response.ok) {\n const text = await response.text();\n throw new DimesError(\n \"auth_token_failed\",\n `Failed to fetch token from ${this.tokenUrl} (${response.status}): ${text}`,\n );\n }\n\n const data = (await response.json()) as TokenResponse;\n this.jwt = data.token;\n this.expiresAt = new Date(data.expires_at).getTime();\n }\n}\n","import type { CamelizeKeys } from \"./camelize\";\nimport type { components } from \"./generated\";\n\ntype Raw = components[\"schemas\"];\n\nexport type Market = CamelizeKeys<Raw[\"CustomerMarket\"]>;\n\nexport type MarketLeverage = CamelizeKeys<Raw[\"CustomerLeverage\"]>;\n\nexport type MarketMaxLeveragePerNotional = CamelizeKeys<Raw[\"CustomerMaxMarketLeveragePerNotional\"]>;\n\nexport type MarketSidedMaxLeveragePerNotional = CamelizeKeys<Raw[\"CustomerSidedMaxMarketLeveragePerNotional\"]>;\n\nexport type MarketSidedEligibility = CamelizeKeys<Raw[\"CustomerSidedEligibility\"]>;\n\nexport type MarketFees = CamelizeKeys<Raw[\"CustomerFees\"]>;\n\nexport type MarketPrices = CamelizeKeys<Raw[\"CustomerMarketPrices\"]>;\n\nexport interface MarketPolymarket {\n conditionId: string | null;\n noTokenId: string;\n slug: string;\n yesTokenId: string;\n}\n\nexport type OriginationTier = CamelizeKeys<Raw[\"CustomerOriginationTier\"]>;\n\nexport type Quote = CamelizeKeys<Raw[\"CustomerOffer\"]>;\n\n/** @deprecated Use {@link Quote}. Back-compat alias; removed in a future major. */\n// eslint-disable-next-line no-restricted-syntax -- intentional deprecated alias\nexport type Offer = Quote;\n\nexport type OpenPosition = CamelizeKeys<Raw[\"CustomerOpenPosition\"]>;\n\nexport type ClosedPosition = CamelizeKeys<Raw[\"CustomerClosedPosition\"]>;\n\nexport type Position = OpenPosition | ClosedPosition;\n\nexport type PositionEntry = CamelizeKeys<Raw[\"CustomerPositionEntry\"]>;\n\nexport type PositionCurrent = CamelizeKeys<Raw[\"CustomerPositionCurrent\"]>;\n\nexport type PositionRisk = CamelizeKeys<Raw[\"CustomerPositionRisk\"]>;\n\nexport type PositionOpenFees = CamelizeKeys<Raw[\"CustomerPositionOpenFees\"]>;\n\nexport type PositionClosedFees = CamelizeKeys<Raw[\"CustomerPositionClosedFees\"]>;\n\nexport type PositionResult = CamelizeKeys<Raw[\"CustomerPositionResult\"]>;\n\nexport type PositionTiming = CamelizeKeys<Raw[\"CustomerPositionTiming\"]>;\n\nexport type PositionFailure = CamelizeKeys<Raw[\"CustomerPositionFailure\"]>;\n\nexport type CloseAttempt = CamelizeKeys<Raw[\"CustomerCloseAttempt\"]>;\n\nexport type PendingOperation = CamelizeKeys<Raw[\"CustomerPendingOperation\"]>;\n\nexport type PositionUnwind = CamelizeKeys<Raw[\"CustomerPositionUnwind\"]>;\n\nexport type PositionUnwindList = CamelizeKeys<Raw[\"CustomerPositionUnwindList\"]>;\n\nexport type PositionTransactionEntry = CamelizeKeys<Raw[\"PositionTransactionEntry\"]>;\n\nexport type PositionTransactionGroup = CamelizeKeys<Raw[\"PositionTransactionGroup\"]>;\n\nexport type PositionTransactions = CamelizeKeys<Raw[\"PositionTransactions\"]>;\n\nexport type ContractInfo = CamelizeKeys<Raw[\"CustomerContractInfo\"]>;\n\nexport type CustomerLimit = CamelizeKeys<Raw[\"CustomerLimit\"]>;\n\nexport type CreateTokenResult = CamelizeKeys<Raw[\"CreateTokenResult\"]>;\n\nexport type FeeRatesOriginationTier = CamelizeKeys<Raw[\"CustomerOriginationFeeTier\"]>;\n\nexport type FeeRatesMarket = CamelizeKeys<Raw[\"CustomerFeeRatesMarket\"]>;\n\nexport type FeeRates = CamelizeKeys<Raw[\"CustomerFeeRates\"]>;\n\nexport type FeeReport = CamelizeKeys<Raw[\"CustomerFeeReport\"]>;\n\nexport interface CreateQuoteParams {\n marketTicker: string;\n effectiveSide: \"yes\" | \"no\";\n leverageBps: number;\n notionalAmountUsdPips: string;\n slippageBps: number;\n pmProvider?: \"polymarket\" | \"kalshi\";\n allowPartialFill?: boolean;\n minFillBps?: number;\n}\n\n/** @deprecated Renamed to {@link CreateQuoteParams}. Kept as an alias for backward compatibility. */\n// eslint-disable-next-line no-restricted-syntax -- intentional deprecated alias\nexport type CreateOfferParams = CreateQuoteParams;\n\nexport interface FeeReportParams {\n marketTicker: string;\n effectiveSide: \"yes\" | \"no\";\n leverageBps: number;\n notionalAmountUsdPips: string;\n entryPriceUsdPips?: string;\n}\n\nexport function isOpenPosition(p: Position): p is OpenPosition {\n return \"current\" in p;\n}\n\nexport function isClosedPosition(p: Position): p is ClosedPosition {\n return \"result\" in p;\n}\n\nexport function leverageMaxBps(lev: MarketLeverage, side: \"yes\" | \"no\"): number {\n const perSide = side === \"yes\" ? lev.maxYesBps : lev.maxNoBps;\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n return perSide ?? lev.maxBps ?? lev.minBps;\n}\n","import type { Market } from \"../types/aliases\";\n\nexport type Side = \"yes\" | \"no\";\n\nexport interface SideEligibility {\n open: boolean;\n reasonCode: string | null;\n}\n\nexport interface SidedEligibility {\n yes: SideEligibility;\n no: SideEligibility;\n}\n\nexport function getSidedEligibility(market: Market): SidedEligibility {\n const sided = market.sidedEligibility;\n return {\n yes: {\n open: sided.yes.acceptingNewPositions,\n reasonCode: sided.yes.rejectionReasonCode ?? null,\n },\n no: {\n open: sided.no.acceptingNewPositions,\n reasonCode: sided.no.rejectionReasonCode ?? null,\n },\n };\n}\n\nexport function defaultSide(eligibility: SidedEligibility): Side | null {\n if (eligibility.yes.open && eligibility.no.open) {\n return \"yes\";\n }\n if (eligibility.yes.open) {\n return \"yes\";\n }\n if (eligibility.no.open) {\n return \"no\";\n }\n return null;\n}\n\nexport function isFullyOpen(eligibility: SidedEligibility): boolean {\n return eligibility.yes.open && eligibility.no.open;\n}\n\nexport function isFullyClosed(eligibility: SidedEligibility): boolean {\n return !eligibility.yes.open && !eligibility.no.open;\n}\n\nexport function rejectionReasonText(code: string | null | undefined): string {\n if (!code) {\n return \"Not eligible for new positions\";\n }\n const stripped = code\n .replace(/^quote_/i, \"\")\n .replaceAll(\"_\", \" \")\n .toLowerCase();\n return stripped.charAt(0).toUpperCase() + stripped.slice(1);\n}\n\nexport function rejectionReasonShort(code: string | null | undefined): string {\n if (!code) {\n return \"unavailable\";\n }\n const stripped = code\n .replace(/^quote_/i, \"\")\n .replace(/_exceeded$/i, \"\")\n .replace(/_too_(low|high)$/i, \"\")\n .replaceAll(\"_\", \" \")\n .toLowerCase();\n return stripped;\n}\n","import { type Market, type MarketMaxLeveragePerNotional, leverageMaxBps } from \"../types/aliases\";\nimport type { Side } from \"./eligibility\";\n\nconst USD_100 = 100;\nconst USD_500 = 500;\nconst USD_1K = 1_000;\nconst USD_10K = 10_000;\nconst BPS_PER_UNIT = 10_000;\n\nconst ANCHORS_USD = [USD_100, USD_500, USD_1K, USD_10K] as const;\n\ntype Anchor = readonly [usd: number, bps: number];\n\nfunction anchorsForSide(market: Market, side: Side): readonly Anchor[] {\n const sided = market.leverage.maxMarketLeveragePerNotional;\n const per: MarketMaxLeveragePerNotional = side === \"yes\" ? sided.yes : sided.no;\n return [\n [ANCHORS_USD[0], per.at100UsdBps],\n [ANCHORS_USD[1], per.at500UsdBps],\n [ANCHORS_USD[2], per.at1000UsdBps],\n [ANCHORS_USD[3], per.at10000UsdBps],\n ];\n}\n\nfunction snapDownToStep(bps: number, stepBps: number, minBps: number): number {\n if (stepBps <= 0) {\n return Math.max(minBps, bps);\n }\n const k = Math.floor((bps - minBps) / stepBps);\n return Math.max(minBps, minBps + Math.max(0, k) * stepBps);\n}\n\nfunction interpolateRawBps(anchors: readonly Anchor[], notionalUsd: number): number {\n const first = anchors[0];\n const last = anchors[anchors.length - 1];\n if (!first || !last) {\n return 0;\n }\n if (notionalUsd <= first[0]) {\n return first[1];\n }\n if (notionalUsd >= last[0]) {\n return last[1];\n }\n for (let i = 1; i < anchors.length; i++) {\n const hi = anchors[i];\n const lo = anchors[i - 1];\n if (!hi || !lo) {\n continue;\n }\n if (notionalUsd <= hi[0]) {\n const t = (notionalUsd - lo[0]) / (hi[0] - lo[0]);\n return lo[1] + (hi[1] - lo[1]) * t;\n }\n }\n return last[1];\n}\n\n/**\n * Maximum leverage in basis points the API will allow at a given notional, per side.\n * Piecewise-linear interpolation across the four anchor points ($100/$500/$1k/$10k).\n * Below $100 uses the $100 cap; above $10k uses the $10k cap. Result is clamped to\n * the absolute side max and rounded down to `stepBps`.\n */\nexport function maxLeverageBpsAtNotional(market: Market, side: Side, notionalUsd: number): number {\n const sideAbsMax = leverageMaxBps(market.leverage, side);\n if (!Number.isFinite(notionalUsd) || notionalUsd <= 0) {\n return sideAbsMax;\n }\n const anchors = anchorsForSide(market, side);\n const raw = interpolateRawBps(anchors, notionalUsd);\n const clamped = Math.min(sideAbsMax, raw);\n return snapDownToStep(clamped, market.leverage.stepBps, market.leverage.minBps);\n}\n\n/**\n * Largest leverage (bps) the user can pick for a given collateral such that the\n * resulting notional still satisfies the per-notional cap.\n *\n * Walks down from the absolute side max in `stepBps` increments and returns the\n * first leverage `lev` where `lev <= maxLeverageBpsAtNotional(collateral * lev / 1)`.\n */\nexport function maxViableLeverageBpsForCollateral(market: Market, side: Side, collateralUsd: number): number {\n const sideAbsMax = leverageMaxBps(market.leverage, side);\n if (!Number.isFinite(collateralUsd) || collateralUsd <= 0) {\n return sideAbsMax;\n }\n\n const step = Math.max(market.leverage.stepBps, 1);\n const minBps = market.leverage.minBps;\n const maxSteps = Math.max(0, Math.floor((sideAbsMax - minBps) / step));\n\n for (let i = maxSteps; i >= 0; i--) {\n const lev = minBps + i * step;\n const notionalUsd = collateralUsd * (lev / BPS_PER_UNIT);\n if (lev <= maxLeverageBpsAtNotional(market, side, notionalUsd)) {\n return lev;\n }\n }\n return minBps;\n}\n","import type { Position, PositionEntry } from \"../types/aliases\";\n\nconst BPS_DIVISOR = 10_000;\n\n/**\n * One leverage-tiered origination-fee rate. `maxLeverageBps` is the inclusive\n * upper bound (in basis points) of leverage covered by this tier; `feeBps` is\n * the protocol origination fee charged for any leverage at or below that bound.\n * Tiers must be supplied in ascending `maxLeverageBps` order; the final tier\n * acts as the catch-all for the highest leverages.\n */\nexport interface OriginationFeeTier {\n maxLeverageBps: number;\n feeBps: number;\n}\n\n/**\n * Resolve the protocol origination fee rate (bps) for a given leverage from an\n * ordered list of leverage tiers. Returns the `feeBps` of the first tier whose\n * `maxLeverageBps >= leverageBps`. If no tier matches (leverage exceeds every\n * bound) the last tier is used as the catch-all. The caller fetches the tiers\n * from the `fee-rates` API; the math is pure.\n *\n * Note: this returns the PROTOCOL rate only — add `partnerOriginationFeeBps`\n * separately (see {@link resolveOriginationFeeBps}).\n */\nexport function resolveProtocolOriginationFeeBps(tiers: readonly OriginationFeeTier[], leverageBps: number): number {\n const lastTier = tiers[tiers.length - 1];\n if (!lastTier) {\n return 0;\n }\n for (const tier of tiers) {\n if (leverageBps <= tier.maxLeverageBps) {\n return tier.feeBps;\n }\n }\n return lastTier.feeBps;\n}\n\n/**\n * Combined origination fee rate (bps) = protocol tier rate + partner add-on.\n * Mirrors the server: the protocol rate is leverage-tiered, the partner rate is\n * a flat add-on supplied by the partner's `fee-rates` config.\n */\nexport function resolveOriginationFeeBps(\n tiers: readonly OriginationFeeTier[],\n leverageBps: number,\n partnerOriginationFeeBps: number,\n): number {\n return resolveProtocolOriginationFeeBps(tiers, leverageBps) + partnerOriginationFeeBps;\n}\n\n/**\n * Origination fee in USDC units (1_000_000 = $1), floored, matching the server:\n * `floor(notionalUsdcUnits * combinedOriginationFeeBps / 10_000)`.\n */\nexport function computeOriginationFeeUsdcUnits(notionalUsdcUnits: number, combinedOriginationFeeBps: number): number {\n return Math.floor((notionalUsdcUnits * combinedOriginationFeeBps) / BPS_DIVISOR);\n}\n\nexport interface OriginationFeeBreakdown {\n totalBps: number;\n totalUsd: number;\n protocolBps: number;\n protocolUsd: number;\n partnerBps: number;\n partnerUsd: number;\n}\n\nfunction getEntry(position: Position): PositionEntry {\n return position.entry;\n}\n\nexport function getOriginationFeeBreakdown(position: Position): OriginationFeeBreakdown {\n const entry = getEntry(position);\n const totalBps = entry.originationFeeBps;\n const totalUsd = Number(entry.originationFeeUsd) || 0;\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const protocolBps = entry.protocolOriginationFeeBps ?? totalBps;\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const partnerBps = entry.partnerOriginationFeeBps ?? 0;\n\n const share = totalBps > 0 ? protocolBps / totalBps : 1;\n const protocolUsd = totalUsd * share;\n const partnerUsd = totalUsd - protocolUsd;\n\n return {\n totalBps,\n totalUsd,\n protocolBps,\n protocolUsd,\n partnerBps,\n partnerUsd,\n };\n}\n","const BPS_DIVISOR = 10_000;\nconst USDC_UNITS_PER_USD = 1_000_000;\nconst TOKEN_UNITS_PER_TOKEN = 1_000_000;\n\n/**\n * Inputs to the Polymarket trading-fee curve. All rates are basis points; the\n * caller fetches `feeRateBps`, `feeExponent`, and `builderTakerFeeRateBps` from\n * the `fee-rates` API (snapshotted server-side as `Quote.polymarketFeeRateBps`\n * / `polymarketFeeExponent` / `polymarketBuilderFeeRateBps`).\n */\nexport interface PolymarketTradingFeeInput {\n notionalUsdcUnits: number;\n priceUsd: number;\n feeRateBps: number;\n feeExponent?: number;\n builderTakerFeeRateBps?: number;\n}\n\n/**\n * Polymarket open/close trading fee in USDC units (1_000_000 = $1).\n *\n * Matches the canonical formula (docs: position-math/09-exchange-trading-fees):\n *\n * ```\n * protocol = feeRateBps / 10_000 * C * (p * (1 - p)) ^ feeExponent * 1e6\n * builder = builderTakerFeeRateBps / 10_000 * notionalUsdc\n * fee = ceil(protocol + builder)\n * ```\n *\n * where `C` = contracts = notionalUsd / p, `p` = price in dollars (0..1). The\n * curvature term peaks at p = 0.5 and is symmetric; the flat builder term does\n * not shrink at price extremes. `feeExponent` defaults to 1 (standard quadratic\n * curvature); some markets use 0 (flat `feeRate * C`). `builderTakerFeeRateBps`\n * defaults to 0 (Bloom's own operator builder code is always 0-fee).\n */\nexport function computePolymarketTradingFee(input: PolymarketTradingFeeInput): number {\n const { notionalUsdcUnits, priceUsd, feeRateBps } = input;\n const feeExponent = input.feeExponent ?? 1;\n const builderTakerFeeRateBps = input.builderTakerFeeRateBps ?? 0;\n\n if (priceUsd <= 0) {\n return 0;\n }\n\n const notionalUsd = notionalUsdcUnits / USDC_UNITS_PER_USD;\n const contracts = notionalUsd / priceUsd;\n const curvature = (priceUsd * (1 - priceUsd)) ** feeExponent;\n\n const protocolFeeUsdcUnits = (feeRateBps / BPS_DIVISOR) * contracts * curvature * USDC_UNITS_PER_USD;\n const builderFeeUsdcUnits = (builderTakerFeeRateBps / BPS_DIVISOR) * notionalUsdcUnits;\n\n return Math.ceil(protocolFeeUsdcUnits + builderFeeUsdcUnits);\n}\n\n/**\n * Expected position size in token units (1_000_000 = 1 whole token) for a given\n * notional and entry price, optionally discounted by slippage. A token redeems\n * at $1 on a win, so token units are numerically equal to USDC units.\n *\n * `tokens = notionalUsd / entryPrice`, then scaled down by `slippageBps`.\n * Floored to whole token units. This is an at-quote estimate of the quote's\n * `minExpectedPositionTokenUnits`; the server is authoritative.\n */\nexport function expectedPositionTokenUnits(notionalUsdcUnits: number, entryPriceUsd: number, slippageBps = 0): number {\n if (entryPriceUsd <= 0) {\n return 0;\n }\n const notionalUsd = notionalUsdcUnits / USDC_UNITS_PER_USD;\n const tokens = notionalUsd / entryPriceUsd;\n const slippageFactor = (BPS_DIVISOR - slippageBps) / BPS_DIVISOR;\n return Math.floor(tokens * slippageFactor * TOKEN_UNITS_PER_TOKEN);\n}\n\n/**\n * Estimated base liquidation price (deterministic, at-entry closed form).\n *\n * **This is an estimate, not the server's TWAP solver result.** It computes the\n * at-entry base liquidation price (F = 0, no safety margin) per the docs\n * (position-math/04-liquidation):\n *\n * ```\n * P_liq_base = entryPrice * (L - 1) / L * (1 + liquidationFeeBps / 10_000)\n * ```\n *\n * where `L = leverageBps / 10_000`. At 1x leverage the borrowed capital is zero\n * so the liquidation price is zero. `entryPriceUsd` is in dollars; the result is\n * in the same units. The live server liquidation price drifts above this as the\n * lifetime fee `F` accrues and includes a safety margin.\n */\nexport function estimateLiquidationPrice(\n entryPriceUsd: number,\n leverageBps: number,\n liquidationFeeBps: number,\n): number {\n const leverage = leverageBps / BPS_DIVISOR;\n if (leverage <= 1) {\n return 0;\n }\n const loanPerToken = entryPriceUsd * ((leverage - 1) / leverage);\n return loanPerToken * (1 + liquidationFeeBps / BPS_DIVISOR);\n}\n\n/**\n * Inputs for {@link computeMaxGain}. All amounts are in USDC units\n * (1_000_000 = $1) except `positionTokenUnits` (token units, 1_000_000 = 1\n * token) which is numerically equal to its settlement USDC value.\n */\nexport interface MaxGainInput {\n positionTokenUnits: number;\n notionalUsdcUnits: number;\n expectedOpenTradingFeeUsdcUnits: number;\n originationFeeUsdcUnits: number;\n}\n\n/**\n * Result of {@link computeMaxGain}. All amounts in USDC units (1_000_000 = $1).\n * Gains are profit OVER principal (notional = loan + collateral) and may be\n * negative — they are signed and never clamped.\n */\nexport interface MaxGainResult {\n fullValueOnWinUsdcUnits: number;\n grossMaxGainUsdcUnits: number;\n netMaxGainUsdcUnits: number;\n}\n\n/**\n * Maximum gain (gross and net) for a winning settlement exit — profit over\n * principal. On a win each position token redeems at $1 (CTF settlement), so\n * the full value equals `positionTokenUnits` and there is NO exit trading fee.\n *\n * ```\n * fullValueOnWin = positionTokenUnits\n * grossMaxGain = fullValueOnWin - notionalUsdcUnits\n * netMaxGain = grossMaxGain - expectedOpenTradingFee - originationFee\n * ```\n *\n * Lifetime fees are excluded, so net max gain is an upper bound (a position held\n * to settlement accrues lifetime fees that reduce realized profit). Gains are\n * signed — a position whose principal exceeds its winning redemption value\n * yields a negative max gain.\n */\nexport function computeMaxGain(input: MaxGainInput): MaxGainResult {\n const fullValueOnWinUsdcUnits = input.positionTokenUnits;\n const grossMaxGainUsdcUnits = fullValueOnWinUsdcUnits - input.notionalUsdcUnits;\n const netMaxGainUsdcUnits =\n grossMaxGainUsdcUnits - input.expectedOpenTradingFeeUsdcUnits - input.originationFeeUsdcUnits;\n\n return {\n fullValueOnWinUsdcUnits,\n grossMaxGainUsdcUnits,\n netMaxGainUsdcUnits,\n };\n}\n","const BPS_DIVISOR = 10_000;\nconst BPS_DIVISOR_BIG = 10_000n;\n\nexport const tokenUnitsPerToken = 1_000_000n;\n\nexport const partialCloseMinTokens = 5n;\n\nexport const partialCloseMinFractionBps = 2_000n;\n\nexport function closeTokenUnitsForPct(currentTokenUnits: bigint, pctBps: number): bigint {\n const clampedBps = BigInt(Math.max(0, Math.min(BPS_DIVISOR, Math.round(pctBps))));\n\n return (currentTokenUnits * clampedBps) / BPS_DIVISOR_BIG;\n}\n\nexport function pctBpsForCloseTokenUnits(currentTokenUnits: bigint, closeTokenUnits: bigint): number {\n if (currentTokenUnits <= 0n) {\n return 0;\n }\n\n return Number((closeTokenUnits * BPS_DIVISOR_BIG) / currentTokenUnits);\n}\n\nexport function fallbackMinPartialCloseTokenUnits(originalTokenUnits: bigint): bigint {\n const floorTokens = partialCloseMinTokens * tokenUnitsPerToken;\n const floorFraction = (originalTokenUnits * partialCloseMinFractionBps) / BPS_DIVISOR_BIG;\n\n return floorFraction > floorTokens ? floorFraction : floorTokens;\n}\n\nexport function clampCloseTokenUnits(value: bigint, min: bigint, max: bigint): bigint {\n if (value < min) {\n return min;\n }\n\n if (value > max) {\n return max;\n }\n\n return value;\n}\n"]}
1
+ {"version":3,"sources":["/Users/alexemery/bl/dimes-sdk/dist/index.cjs","../src/client/dimes-client.ts","../src/client/http.ts","../src/client/auth.ts","../src/types/aliases.ts","../src/utils/eligibility.ts","../src/utils/leverage.ts","../src/utils/fees.ts","../src/utils/max-gain.ts","../src/utils/partial-close.ts"],"names":["BPS_DIVISOR"],"mappings":"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,EAAA;AAE5C,EAAA;AACV,IAAA;AACT,EAAA;AAEwC,EAAA;AACR,EAAA;AACiB,EAAA;AAEqB,EAAA;AACD,EAAA;AAEV,EAAA;AAC7D;AAW6F;AACnE,EAAA;AACf,IAAA;AACT,EAAA;AACwC,EAAA;AACX,EAAA;AACwBA,EAAAA;AACY,EAAA;AACnE;AAqBE;AAE+BA,EAAAA;AACZ,EAAA;AACV,IAAA;AACT,EAAA;AACuD,EAAA;AACRA,EAAAA;AACjD;AAyCmE;AAC3B,EAAA;AACwB,EAAA;AAE9B,EAAA;AAEzB,EAAA;AACL,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACF;ARuZyE;AACA;AShjBrD;AACI;AAEU;AAEG;AAEK;AAE+C;AACtB,EAAA;AAEvB,EAAA;AAC5C;AAEqG;AACtE,EAAA;AACpB,IAAA;AACT,EAAA;AAEqE,EAAA;AACvE;AAEsF;AACxC,EAAA;AACA,EAAA;AAES,EAAA;AACvD;AAEsF;AACnE,EAAA;AACR,IAAA;AACT,EAAA;AAEiB,EAAA;AACR,IAAA;AACT,EAAA;AAEO,EAAA;AACT;ATsiByE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/Users/alexemery/bl/dimes-sdk/dist/index.cjs","sourcesContent":[null,"import { decamelizeKeys } from \"humps\";\nimport type {\n ContractInfo,\n CreateQuoteParams,\n CustomerLimit,\n FeeRates,\n FeeReport,\n FeeReportParams,\n Market,\n Paginated,\n Position,\n PositionPartialCloseList,\n PositionTransactions,\n Quote,\n} from \"../types\";\nimport type { AuthProvider } from \"./auth\";\nimport { HttpClient } from \"./http\";\n\nexport interface DimesClientOptions {\n baseUrl?: string;\n auth: AuthProvider;\n fetch?: typeof globalThis.fetch;\n maxRetries?: number;\n maxRetryDelayMs?: number;\n}\n\nexport type MarketSort = \"ticker_asc\" | \"depth_desc\" | \"discovered_at_desc\";\n\nexport type MarketExpand = \"total_count\" | \"prices\";\n\nexport type PositionStatus = \"open\" | \"unwinding\" | \"pending\" | \"closing\" | \"closed\" | \"settled\" | \"liquidated\";\n\nexport interface GetMarketsParams {\n limit?: number;\n startingAfter?: string;\n endingBefore?: string;\n expand?: MarketExpand[];\n sort?: MarketSort;\n acceptingNewPositions?: boolean;\n category?: string;\n status?: string;\n provider?: \"polymarket\" | \"kalshi\";\n /** Free-text search across market tickers and titles. */\n query?: string;\n}\n\n/** @deprecated Use {@link GetMarketsParams} with `query` and {@link DimesClient.getMarkets}. */\nexport interface SearchMarketsParams extends GetMarketsParams {\n query: string;\n}\n\nexport interface GetPositionsParams {\n limit?: number;\n startingAfter?: string;\n endingBefore?: string;\n expand?: string[];\n sortBy?: \"created_at\" | \"closed_at\";\n sortDirection?: \"asc\" | \"desc\";\n status?: PositionStatus;\n state?: \"active\" | \"inactive\";\n}\n\nexport interface GetFeeRatesParams {\n ticker?: string;\n}\n\nfunction buildQueryFromEntries(entries: [string, unknown][]): string {\n const filtered = entries.filter(([, v]) => v !== undefined && v !== null);\n if (filtered.length === 0) {\n return \"\";\n }\n\n const search = new URLSearchParams();\n for (const [key, value] of filtered) {\n search.set(\n key.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`),\n String(value),\n );\n }\n\n return `?${search.toString()}`;\n}\n\nexport class DimesClient {\n /** The resolved API base URL. Useful for constructing WebSocket clients against the same host. */\n public readonly baseUrl: string;\n\n private readonly http: HttpClient;\n\n private readonly auth: AuthProvider;\n\n constructor(options: DimesClientOptions) {\n this.baseUrl = options.baseUrl ?? \"https://api.dimes.fi\";\n this.auth = options.auth;\n this.http = new HttpClient({\n baseUrl: this.baseUrl,\n auth: options.auth,\n fetch: options.fetch,\n maxRetries: options.maxRetries,\n maxRetryDelayMs: options.maxRetryDelayMs,\n });\n }\n\n /** Synchronously return the current cached JWT, or null. Returns null if the auth provider does not expose one. */\n public getToken(): string | null {\n return this.auth.getToken?.() ?? null;\n }\n\n public async getMarkets(params?: GetMarketsParams): Promise<Paginated<Market>> {\n const query = params ? buildQueryFromEntries(Object.entries(params)) : \"\";\n return this.http.request<Paginated<Market>>(`/v1/prediction-markets/markets${query}`);\n }\n\n public async getMarket(ticker: string): Promise<Market> {\n return this.http.request<Market>(`/v1/prediction-markets/markets/${encodeURIComponent(ticker)}`);\n }\n\n /**\n * @deprecated The `/markets/search` path is deprecated. Use {@link getMarkets} with a `query` param:\n * `getMarkets({ query: \"bitcoin\" })`.\n */\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- this IS the deprecated method\n public async searchMarkets(params: SearchMarketsParams): Promise<Paginated<Market>> {\n return this.getMarkets(params);\n }\n\n public async createDraftQuote(params: CreateQuoteParams): Promise<Quote> {\n return this.http.request<Quote>(\"/v1/prediction-markets/draft-quotes\", {\n method: \"POST\",\n body: JSON.stringify(decamelizeKeys(params)),\n });\n }\n\n public async promoteDraftQuote(draftId: string): Promise<Quote> {\n return this.http.request<Quote>(`/v1/prediction-markets/promoted-quotes/${encodeURIComponent(draftId)}`, {\n method: \"POST\",\n });\n }\n\n public async createQuote(params: CreateQuoteParams): Promise<Quote> {\n return this.http.request<Quote>(\"/v1/prediction-markets/quotes\", {\n method: \"POST\",\n body: JSON.stringify(decamelizeKeys(params)),\n });\n }\n\n public async getPositions(params?: GetPositionsParams): Promise<Position[]> {\n const query = params ? buildQueryFromEntries(Object.entries(params)) : \"\";\n return this.http.requestList<Position>(`/v1/prediction-markets/positions${query}`);\n }\n\n public async getPositionTransactions(positionId: string): Promise<PositionTransactions> {\n return this.http.request<PositionTransactions>(\n `/v1/prediction-markets/positions/${encodeURIComponent(positionId)}/transactions`,\n );\n }\n\n public async getPositionPartialCloses(positionId: string): Promise<PositionPartialCloseList> {\n return this.http.request<PositionPartialCloseList>(\n `/v1/prediction-markets/positions/${encodeURIComponent(positionId)}/partial-closes`,\n );\n }\n\n public async cancelPosition(positionId: string): Promise<void> {\n await this.http.request<unknown>(`/v1/prediction-markets/positions/${encodeURIComponent(positionId)}`, {\n method: \"DELETE\",\n });\n }\n\n public async getContractInfo(): Promise<ContractInfo> {\n return this.http.request<ContractInfo>(\"/v1/prediction-markets/contract-info\");\n }\n\n public async getUserLimits(): Promise<CustomerLimit> {\n return this.http.request<CustomerLimit>(\"/v1/prediction-markets/user-limits\");\n }\n\n public async getPartnerLimits(): Promise<CustomerLimit> {\n return this.http.request<CustomerLimit>(\"/v1/prediction-markets/partner-limits\");\n }\n\n /**\n * @deprecated The `/limits` path was never served by the API. Use {@link getUserLimits}\n * (JWT/user context) or {@link getPartnerLimits} (API-key/partner context). This alias\n * forwards to `getUserLimits` and will be removed in a future major.\n */\n public async getLimits(): Promise<CustomerLimit> {\n return this.getUserLimits();\n }\n\n public async getFeeRates(params?: GetFeeRatesParams): Promise<FeeRates> {\n const query = params ? buildQueryFromEntries(Object.entries(params)) : \"\";\n return this.http.request<FeeRates>(`/v1/prediction-markets/fee-rates${query}`);\n }\n\n public async getFeeReport(params: FeeReportParams): Promise<FeeReport> {\n return this.http.request<FeeReport>(\"/v1/prediction-markets/fee-reports\", {\n method: \"POST\",\n body: JSON.stringify(decamelizeKeys(params)),\n });\n }\n}\n","import { camelizeKeys, type Camelized } from \"humps\";\nimport { DimesApiError } from \"../errors/dimes-error\";\nimport type { AuthProvider } from \"./auth\";\n\nexport type { Camelized };\n\ninterface ApiErrorBody {\n error?: {\n type?: string;\n code?: string;\n message: string;\n params?: Record<string, unknown>;\n };\n}\n\nconst HTTP_UNAUTHORIZED = 401;\nconst HTTP_TOO_MANY_REQUESTS = 429;\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_MAX_RETRY_DELAY_MS = 60_000;\nconst DEFAULT_RETRY_DELAY_MS = 1000;\nconst BACKOFF_FACTOR = 2;\nconst MS_PER_SECOND = 1000;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction parseRetryAfterMs(header: string | null, attempt: number): number {\n const fallbackMs = DEFAULT_RETRY_DELAY_MS * BACKOFF_FACTOR ** attempt;\n if (!header) {\n return fallbackMs;\n }\n\n const seconds = Number(header);\n if (!Number.isNaN(seconds) && seconds >= 0) {\n return seconds * MS_PER_SECOND;\n }\n\n const dateMs = Date.parse(header);\n if (!Number.isNaN(dateMs)) {\n return Math.max(0, dateMs - Date.now());\n }\n\n return fallbackMs;\n}\n\n// eslint-disable-next-line complexity\nasync function throwFromResponse(response: Response): Promise<never> {\n const rawBody = await response.text();\n let parsed: ApiErrorBody | null;\n try {\n parsed = rawBody ? (JSON.parse(rawBody) as ApiErrorBody) : null;\n } catch {\n parsed = null;\n }\n\n const code = parsed?.error?.code ?? \"unknown_error\";\n const type = parsed?.error?.type ?? null;\n const message = parsed?.error?.message ?? `API error ${response.status}`;\n const rawParams = parsed?.error?.params;\n const params = rawParams ? (camelizeKeys(rawParams) as Record<string, unknown>) : null;\n\n throw new DimesApiError({ status: response.status, code, type, message, params });\n}\n\nexport interface HttpClientOptions {\n baseUrl: string;\n auth: AuthProvider;\n fetch?: typeof globalThis.fetch;\n maxRetries?: number;\n maxRetryDelayMs?: number;\n}\n\nexport class HttpClient {\n private readonly baseUrl: string;\n\n private readonly auth: AuthProvider;\n\n private readonly fetchFn: typeof globalThis.fetch;\n\n private readonly maxRetries: number;\n\n private readonly maxRetryDelayMs: number;\n\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl;\n this.auth = options.auth;\n this.fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);\n this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;\n this.maxRetryDelayMs = options.maxRetryDelayMs ?? DEFAULT_MAX_RETRY_DELAY_MS;\n }\n\n public async request<T>(path: string, options?: RequestInit): Promise<T> {\n const authHeaders = await this.auth.getHeaders();\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...authHeaders,\n ...(options?.headers as Record<string, string> | undefined),\n };\n\n let response = await this.fetchFn(`${this.baseUrl}${path}`, {\n ...options,\n headers,\n });\n\n if (response.status === HTTP_UNAUTHORIZED && this.auth.refresh) {\n await this.auth.refresh();\n const retryHeaders = await this.auth.getHeaders();\n response = await this.fetchFn(`${this.baseUrl}${path}`, {\n ...options,\n headers: { ...headers, ...retryHeaders },\n });\n }\n\n for (let attempt = 0; response.status === HTTP_TOO_MANY_REQUESTS && attempt < this.maxRetries; attempt++) {\n const delayMs = parseRetryAfterMs(response.headers.get(\"retry-after\"), attempt);\n if (delayMs > this.maxRetryDelayMs) {\n break;\n }\n await sleep(delayMs);\n const freshAuth = await this.auth.getHeaders();\n response = await this.fetchFn(`${this.baseUrl}${path}`, {\n ...options,\n headers: { ...headers, ...freshAuth },\n });\n }\n\n if (!response.ok) {\n await throwFromResponse(response);\n }\n\n return camelizeKeys(await response.json()) as T;\n }\n\n public async requestList<T>(path: string, options?: RequestInit): Promise<T[]> {\n const result = await this.request<{ data: T[] }>(path, options);\n return result.data;\n }\n}\n","import { DimesError } from \"../errors/dimes-error\";\n\nexport interface AuthProvider {\n getHeaders(): Promise<Record<string, string>>;\n refresh?(): Promise<void>;\n /** Synchronously return the current cached JWT, or null if not yet obtained. Used by the WebSocket clients. */\n getToken?(): string | null;\n}\n\ninterface TokenResponse {\n token: string;\n expires_at: string;\n}\n\nexport interface ApiKeyAuthOptions {\n apiKey: string;\n walletAddress: string;\n baseUrl?: string;\n fetch?: typeof globalThis.fetch;\n}\n\nexport class ApiKeyAuth implements AuthProvider {\n private jwt: string | null = null;\n\n private expiresAt = 0;\n\n private refreshPromise: Promise<void> | null = null;\n\n private readonly apiKey: string;\n\n private readonly walletAddress: string;\n\n private readonly baseUrl: string;\n\n private readonly fetchFn: typeof globalThis.fetch;\n\n constructor(options: ApiKeyAuthOptions) {\n this.apiKey = options.apiKey;\n this.walletAddress = options.walletAddress;\n this.baseUrl = options.baseUrl ?? \"https://api.dimes.fi\";\n this.fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n public async getHeaders(): Promise<Record<string, string>> {\n const TOKEN_EXPIRY_BUFFER_MS = 30_000;\n if (!this.jwt || Date.now() >= this.expiresAt - TOKEN_EXPIRY_BUFFER_MS) {\n await this.refresh();\n }\n return { Authorization: `Bearer ${this.jwt}` };\n }\n\n public getToken(): string | null {\n return this.jwt;\n }\n\n public async refresh(): Promise<void> {\n if (this.refreshPromise) {\n await this.refreshPromise;\n return;\n }\n\n this.refreshPromise = this.fetchToken();\n try {\n await this.refreshPromise;\n } finally {\n this.refreshPromise = null;\n }\n }\n\n private async fetchToken(): Promise<void> {\n const response = await this.fetchFn(`${this.baseUrl}/v1/prediction-markets/tokens`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Api-Key ${this.apiKey}`,\n },\n body: JSON.stringify({ wallet_address: this.walletAddress }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new DimesError(\"auth_token_failed\", `Failed to obtain auth token (${response.status}): ${text}`);\n }\n\n const data = (await response.json()) as TokenResponse;\n this.jwt = data.token;\n this.expiresAt = new Date(data.expires_at).getTime();\n }\n}\n\nexport interface JwtAuthOptions {\n tokenUrl: string;\n fetch?: typeof globalThis.fetch;\n}\n\nexport class JwtAuth implements AuthProvider {\n private readonly fetchFn: typeof globalThis.fetch;\n\n private readonly tokenUrl: string;\n\n private jwt: string | null = null;\n\n private expiresAt = 0;\n\n private refreshPromise: Promise<void> | null = null;\n\n constructor(options: JwtAuthOptions) {\n this.tokenUrl = options.tokenUrl;\n this.fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n public async getHeaders(): Promise<Record<string, string>> {\n const TOKEN_EXPIRY_BUFFER_MS = 30_000;\n if (!this.jwt || Date.now() >= this.expiresAt - TOKEN_EXPIRY_BUFFER_MS) {\n await this.refresh();\n }\n return { Authorization: `Bearer ${this.jwt}` };\n }\n\n public getToken(): string | null {\n return this.jwt;\n }\n\n public async refresh(): Promise<void> {\n if (this.refreshPromise) {\n await this.refreshPromise;\n return;\n }\n\n this.refreshPromise = this.fetchToken();\n try {\n await this.refreshPromise;\n } finally {\n this.refreshPromise = null;\n }\n }\n\n private async fetchToken(): Promise<void> {\n const response = await this.fetchFn(this.tokenUrl);\n\n if (!response.ok) {\n const text = await response.text();\n throw new DimesError(\n \"auth_token_failed\",\n `Failed to fetch token from ${this.tokenUrl} (${response.status}): ${text}`,\n );\n }\n\n const data = (await response.json()) as TokenResponse;\n this.jwt = data.token;\n this.expiresAt = new Date(data.expires_at).getTime();\n }\n}\n","import type { CamelizeKeys } from \"./camelize\";\nimport type { components } from \"./generated\";\n\ntype Raw = components[\"schemas\"];\n\nexport type Market = CamelizeKeys<Raw[\"CustomerMarket\"]>;\n\nexport type MarketLeverage = CamelizeKeys<Raw[\"CustomerLeverage\"]>;\n\nexport type MarketMaxLeveragePerNotional = CamelizeKeys<Raw[\"CustomerMaxMarketLeveragePerNotional\"]>;\n\nexport type MarketSidedMaxLeveragePerNotional = CamelizeKeys<Raw[\"CustomerSidedMaxMarketLeveragePerNotional\"]>;\n\nexport type MarketSidedEligibility = CamelizeKeys<Raw[\"CustomerSidedEligibility\"]>;\n\nexport type MarketFees = CamelizeKeys<Raw[\"CustomerFees\"]>;\n\nexport type MarketPrices = CamelizeKeys<Raw[\"CustomerMarketPrices\"]>;\n\nexport interface MarketPolymarket {\n conditionId: string | null;\n noTokenId: string;\n slug: string;\n yesTokenId: string;\n}\n\nexport type OriginationTier = CamelizeKeys<Raw[\"CustomerOriginationTier\"]>;\n\nexport type Quote = CamelizeKeys<Raw[\"CustomerOffer\"]>;\n\n/** @deprecated Use {@link Quote}. Back-compat alias; removed in a future major. */\n// eslint-disable-next-line no-restricted-syntax -- intentional deprecated alias\nexport type Offer = Quote;\n\nexport type OpenPosition = CamelizeKeys<Raw[\"CustomerOpenPosition\"]>;\n\nexport type ClosedPosition = CamelizeKeys<Raw[\"CustomerClosedPosition\"]>;\n\nexport type Position = OpenPosition | ClosedPosition;\n\nexport type PositionEntry = CamelizeKeys<Raw[\"CustomerPositionEntry\"]>;\n\nexport type PositionCurrent = CamelizeKeys<Raw[\"CustomerPositionCurrent\"]>;\n\nexport type PositionRisk = CamelizeKeys<Raw[\"CustomerPositionRisk\"]>;\n\nexport type PositionOpenFees = CamelizeKeys<Raw[\"CustomerPositionOpenFees\"]>;\n\nexport type PositionClosedFees = CamelizeKeys<Raw[\"CustomerPositionClosedFees\"]>;\n\nexport type PositionResult = CamelizeKeys<Raw[\"CustomerPositionResult\"]>;\n\nexport type PositionTiming = CamelizeKeys<Raw[\"CustomerPositionTiming\"]>;\n\nexport type PositionFailure = CamelizeKeys<Raw[\"CustomerPositionFailure\"]>;\n\nexport type CloseAttempt = CamelizeKeys<Raw[\"CustomerCloseAttempt\"]>;\n\nexport type PendingOperation = CamelizeKeys<Raw[\"CustomerPendingOperation\"]>;\n\nexport type PositionUnwind = CamelizeKeys<Raw[\"CustomerPositionUnwind\"]>;\n\nexport type PositionUnwindList = CamelizeKeys<Raw[\"CustomerPositionUnwindList\"]>;\n\nexport type PositionPartialClose = CamelizeKeys<Raw[\"CustomerPartialClose\"]>;\n\nexport type PositionPartialCloseList = CamelizeKeys<Raw[\"CustomerPartialCloseList\"]>;\n\nexport type PositionTransactionEntry = CamelizeKeys<Raw[\"PositionTransactionEntry\"]>;\n\nexport type PositionTransactionGroup = CamelizeKeys<Raw[\"PositionTransactionGroup\"]>;\n\nexport type PositionTransactions = CamelizeKeys<Raw[\"PositionTransactions\"]>;\n\nexport type ContractInfo = CamelizeKeys<Raw[\"CustomerContractInfo\"]>;\n\nexport type CustomerLimit = CamelizeKeys<Raw[\"CustomerLimit\"]>;\n\nexport type CreateTokenResult = CamelizeKeys<Raw[\"CreateTokenResult\"]>;\n\nexport type FeeRatesOriginationTier = CamelizeKeys<Raw[\"CustomerOriginationFeeTier\"]>;\n\nexport type FeeRatesMarket = CamelizeKeys<Raw[\"CustomerFeeRatesMarket\"]>;\n\nexport type FeeRates = CamelizeKeys<Raw[\"CustomerFeeRates\"]>;\n\nexport type FeeReport = CamelizeKeys<Raw[\"CustomerFeeReport\"]>;\n\nexport interface CreateQuoteParams {\n marketTicker: string;\n effectiveSide: \"yes\" | \"no\";\n leverageBps: number;\n notionalAmountUsdPips: string;\n slippageBps: number;\n pmProvider?: \"polymarket\" | \"kalshi\";\n allowPartialFill?: boolean;\n minFillBps?: number;\n}\n\n/** @deprecated Renamed to {@link CreateQuoteParams}. Kept as an alias for backward compatibility. */\n// eslint-disable-next-line no-restricted-syntax -- intentional deprecated alias\nexport type CreateOfferParams = CreateQuoteParams;\n\nexport interface FeeReportParams {\n marketTicker: string;\n effectiveSide: \"yes\" | \"no\";\n leverageBps: number;\n notionalAmountUsdPips: string;\n entryPriceUsdPips?: string;\n}\n\nexport function isOpenPosition(p: Position): p is OpenPosition {\n return \"current\" in p;\n}\n\nexport function isClosedPosition(p: Position): p is ClosedPosition {\n return \"result\" in p;\n}\n\nexport function leverageMaxBps(lev: MarketLeverage, side: \"yes\" | \"no\"): number {\n const perSide = side === \"yes\" ? lev.maxYesBps : lev.maxNoBps;\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n return perSide ?? lev.maxBps ?? lev.minBps;\n}\n","import type { Market } from \"../types/aliases\";\n\nexport type Side = \"yes\" | \"no\";\n\nexport interface SideEligibility {\n open: boolean;\n reasonCode: string | null;\n}\n\nexport interface SidedEligibility {\n yes: SideEligibility;\n no: SideEligibility;\n}\n\nexport function getSidedEligibility(market: Market): SidedEligibility {\n const sided = market.sidedEligibility;\n return {\n yes: {\n open: sided.yes.acceptingNewPositions,\n reasonCode: sided.yes.rejectionReasonCode ?? null,\n },\n no: {\n open: sided.no.acceptingNewPositions,\n reasonCode: sided.no.rejectionReasonCode ?? null,\n },\n };\n}\n\nexport function defaultSide(eligibility: SidedEligibility): Side | null {\n if (eligibility.yes.open && eligibility.no.open) {\n return \"yes\";\n }\n if (eligibility.yes.open) {\n return \"yes\";\n }\n if (eligibility.no.open) {\n return \"no\";\n }\n return null;\n}\n\nexport function isFullyOpen(eligibility: SidedEligibility): boolean {\n return eligibility.yes.open && eligibility.no.open;\n}\n\nexport function isFullyClosed(eligibility: SidedEligibility): boolean {\n return !eligibility.yes.open && !eligibility.no.open;\n}\n\nexport function rejectionReasonText(code: string | null | undefined): string {\n if (!code) {\n return \"Not eligible for new positions\";\n }\n const stripped = code\n .replace(/^quote_/i, \"\")\n .replace(/^notional_selector_/i, \"\")\n .replaceAll(\"_\", \" \")\n .toLowerCase();\n return stripped.charAt(0).toUpperCase() + stripped.slice(1);\n}\n\nexport function rejectionReasonShort(code: string | null | undefined): string {\n if (!code) {\n return \"unavailable\";\n }\n const stripped = code\n .replace(/^quote_/i, \"\")\n .replace(/^notional_selector_/i, \"\")\n .replace(/_exceeded$/i, \"\")\n .replace(/_too_(low|high)$/i, \"\")\n .replaceAll(\"_\", \" \")\n .toLowerCase();\n return stripped;\n}\n","import { type Market, type MarketMaxLeveragePerNotional, leverageMaxBps } from \"../types/aliases\";\nimport type { Side } from \"./eligibility\";\n\nconst USD_100 = 100;\nconst USD_500 = 500;\nconst USD_1K = 1_000;\nconst USD_10K = 10_000;\nconst BPS_PER_UNIT = 10_000;\n\nconst ANCHORS_USD = [USD_100, USD_500, USD_1K, USD_10K] as const;\n\ntype Anchor = readonly [usd: number, bps: number];\n\nfunction anchorsForSide(market: Market, side: Side): readonly Anchor[] {\n const sided = market.leverage.maxMarketLeveragePerNotional;\n const per: MarketMaxLeveragePerNotional = side === \"yes\" ? sided.yes : sided.no;\n return [\n [ANCHORS_USD[0], per.at100UsdBps],\n [ANCHORS_USD[1], per.at500UsdBps],\n [ANCHORS_USD[2], per.at1000UsdBps],\n [ANCHORS_USD[3], per.at10000UsdBps],\n ];\n}\n\nfunction snapDownToStep(bps: number, stepBps: number, minBps: number): number {\n if (stepBps <= 0) {\n return Math.max(minBps, bps);\n }\n const k = Math.floor((bps - minBps) / stepBps);\n return Math.max(minBps, minBps + Math.max(0, k) * stepBps);\n}\n\nfunction interpolateRawBps(anchors: readonly Anchor[], notionalUsd: number): number {\n const first = anchors[0];\n const last = anchors[anchors.length - 1];\n if (!first || !last) {\n return 0;\n }\n if (notionalUsd <= first[0]) {\n return first[1];\n }\n if (notionalUsd >= last[0]) {\n return last[1];\n }\n for (let i = 1; i < anchors.length; i++) {\n const hi = anchors[i];\n const lo = anchors[i - 1];\n if (!hi || !lo) {\n continue;\n }\n if (notionalUsd <= hi[0]) {\n const t = (notionalUsd - lo[0]) / (hi[0] - lo[0]);\n return lo[1] + (hi[1] - lo[1]) * t;\n }\n }\n return last[1];\n}\n\n/**\n * Maximum leverage in basis points the API will allow at a given notional, per side.\n * Piecewise-linear interpolation across the four anchor points ($100/$500/$1k/$10k).\n * Below $100 uses the $100 cap; above $10k uses the $10k cap. Result is clamped to\n * the absolute side max and rounded down to `stepBps`.\n */\nexport function maxLeverageBpsAtNotional(market: Market, side: Side, notionalUsd: number): number {\n const sideAbsMax = leverageMaxBps(market.leverage, side);\n if (!Number.isFinite(notionalUsd) || notionalUsd <= 0) {\n return sideAbsMax;\n }\n const anchors = anchorsForSide(market, side);\n const raw = interpolateRawBps(anchors, notionalUsd);\n const clamped = Math.min(sideAbsMax, raw);\n return snapDownToStep(clamped, market.leverage.stepBps, market.leverage.minBps);\n}\n\n/**\n * Largest leverage (bps) the user can pick for a given collateral such that the\n * resulting notional still satisfies the per-notional cap.\n *\n * Walks down from the absolute side max in `stepBps` increments and returns the\n * first leverage `lev` where `lev <= maxLeverageBpsAtNotional(collateral * lev / 1)`.\n */\nexport function maxViableLeverageBpsForCollateral(market: Market, side: Side, collateralUsd: number): number {\n const sideAbsMax = leverageMaxBps(market.leverage, side);\n if (!Number.isFinite(collateralUsd) || collateralUsd <= 0) {\n return sideAbsMax;\n }\n\n const step = Math.max(market.leverage.stepBps, 1);\n const minBps = market.leverage.minBps;\n const maxSteps = Math.max(0, Math.floor((sideAbsMax - minBps) / step));\n\n for (let i = maxSteps; i >= 0; i--) {\n const lev = minBps + i * step;\n const notionalUsd = collateralUsd * (lev / BPS_PER_UNIT);\n if (lev <= maxLeverageBpsAtNotional(market, side, notionalUsd)) {\n return lev;\n }\n }\n return minBps;\n}\n","import type { Position, PositionEntry } from \"../types/aliases\";\n\nconst BPS_DIVISOR = 10_000;\n\n/**\n * One leverage-tiered origination-fee rate. `maxLeverageBps` is the inclusive\n * upper bound (in basis points) of leverage covered by this tier; `feeBps` is\n * the protocol origination fee charged for any leverage at or below that bound.\n * Tiers must be supplied in ascending `maxLeverageBps` order; the final tier\n * acts as the catch-all for the highest leverages.\n */\nexport interface OriginationFeeTier {\n maxLeverageBps: number;\n feeBps: number;\n}\n\n/**\n * Resolve the protocol origination fee rate (bps) for a given leverage from an\n * ordered list of leverage tiers. Returns the `feeBps` of the first tier whose\n * `maxLeverageBps >= leverageBps`. If no tier matches (leverage exceeds every\n * bound) the last tier is used as the catch-all. The caller fetches the tiers\n * from the `fee-rates` API; the math is pure.\n *\n * Note: this returns the PROTOCOL rate only — add `partnerOriginationFeeBps`\n * separately (see {@link resolveOriginationFeeBps}).\n */\nexport function resolveProtocolOriginationFeeBps(tiers: readonly OriginationFeeTier[], leverageBps: number): number {\n const lastTier = tiers[tiers.length - 1];\n if (!lastTier) {\n return 0;\n }\n for (const tier of tiers) {\n if (leverageBps <= tier.maxLeverageBps) {\n return tier.feeBps;\n }\n }\n return lastTier.feeBps;\n}\n\n/**\n * Combined origination fee rate (bps) = protocol tier rate + partner add-on.\n * Mirrors the server: the protocol rate is leverage-tiered, the partner rate is\n * a flat add-on supplied by the partner's `fee-rates` config.\n */\nexport function resolveOriginationFeeBps(\n tiers: readonly OriginationFeeTier[],\n leverageBps: number,\n partnerOriginationFeeBps: number,\n): number {\n return resolveProtocolOriginationFeeBps(tiers, leverageBps) + partnerOriginationFeeBps;\n}\n\n/**\n * Origination fee in USDC units (1_000_000 = $1), floored, matching the server:\n * `floor(notionalUsdcUnits * combinedOriginationFeeBps / 10_000)`.\n */\nexport function computeOriginationFeeUsdcUnits(notionalUsdcUnits: number, combinedOriginationFeeBps: number): number {\n return Math.floor((notionalUsdcUnits * combinedOriginationFeeBps) / BPS_DIVISOR);\n}\n\nexport interface OriginationFeeBreakdown {\n totalBps: number;\n totalUsd: number;\n protocolBps: number;\n protocolUsd: number;\n partnerBps: number;\n partnerUsd: number;\n}\n\nfunction getEntry(position: Position): PositionEntry {\n return position.entry;\n}\n\nexport function getOriginationFeeBreakdown(position: Position): OriginationFeeBreakdown {\n const entry = getEntry(position);\n const totalBps = entry.originationFeeBps;\n const totalUsd = Number(entry.originationFeeUsd) || 0;\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const protocolBps = entry.protocolOriginationFeeBps ?? totalBps;\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const partnerBps = entry.partnerOriginationFeeBps ?? 0;\n\n const share = totalBps > 0 ? protocolBps / totalBps : 1;\n const protocolUsd = totalUsd * share;\n const partnerUsd = totalUsd - protocolUsd;\n\n return {\n totalBps,\n totalUsd,\n protocolBps,\n protocolUsd,\n partnerBps,\n partnerUsd,\n };\n}\n","const BPS_DIVISOR = 10_000;\nconst USDC_UNITS_PER_USD = 1_000_000;\nconst TOKEN_UNITS_PER_TOKEN = 1_000_000;\n\n/**\n * Inputs to the Polymarket trading-fee curve. All rates are basis points; the\n * caller fetches `feeRateBps`, `feeExponent`, and `builderTakerFeeRateBps` from\n * the `fee-rates` API (snapshotted server-side as `Quote.polymarketFeeRateBps`\n * / `polymarketFeeExponent` / `polymarketBuilderFeeRateBps`).\n */\nexport interface PolymarketTradingFeeInput {\n notionalUsdcUnits: number;\n priceUsd: number;\n feeRateBps: number;\n feeExponent?: number;\n builderTakerFeeRateBps?: number;\n}\n\n/**\n * Polymarket open/close trading fee in USDC units (1_000_000 = $1).\n *\n * Matches the canonical formula (docs: position-math/09-exchange-trading-fees):\n *\n * ```\n * protocol = feeRateBps / 10_000 * C * (p * (1 - p)) ^ feeExponent * 1e6\n * builder = builderTakerFeeRateBps / 10_000 * notionalUsdc\n * fee = ceil(protocol + builder)\n * ```\n *\n * where `C` = contracts = notionalUsd / p, `p` = price in dollars (0..1). The\n * curvature term peaks at p = 0.5 and is symmetric; the flat builder term does\n * not shrink at price extremes. `feeExponent` defaults to 1 (standard quadratic\n * curvature); some markets use 0 (flat `feeRate * C`). `builderTakerFeeRateBps`\n * defaults to 0 (Bloom's own operator builder code is always 0-fee).\n */\nexport function computePolymarketTradingFee(input: PolymarketTradingFeeInput): number {\n const { notionalUsdcUnits, priceUsd, feeRateBps } = input;\n const feeExponent = input.feeExponent ?? 1;\n const builderTakerFeeRateBps = input.builderTakerFeeRateBps ?? 0;\n\n if (priceUsd <= 0) {\n return 0;\n }\n\n const notionalUsd = notionalUsdcUnits / USDC_UNITS_PER_USD;\n const contracts = notionalUsd / priceUsd;\n const curvature = (priceUsd * (1 - priceUsd)) ** feeExponent;\n\n const protocolFeeUsdcUnits = (feeRateBps / BPS_DIVISOR) * contracts * curvature * USDC_UNITS_PER_USD;\n const builderFeeUsdcUnits = (builderTakerFeeRateBps / BPS_DIVISOR) * notionalUsdcUnits;\n\n return Math.ceil(protocolFeeUsdcUnits + builderFeeUsdcUnits);\n}\n\n/**\n * Expected position size in token units (1_000_000 = 1 whole token) for a given\n * notional and entry price, optionally discounted by slippage. A token redeems\n * at $1 on a win, so token units are numerically equal to USDC units.\n *\n * `tokens = notionalUsd / entryPrice`, then scaled down by `slippageBps`.\n * Floored to whole token units. This is an at-quote estimate of the quote's\n * `minExpectedPositionTokenUnits`; the server is authoritative.\n */\nexport function expectedPositionTokenUnits(notionalUsdcUnits: number, entryPriceUsd: number, slippageBps = 0): number {\n if (entryPriceUsd <= 0) {\n return 0;\n }\n const notionalUsd = notionalUsdcUnits / USDC_UNITS_PER_USD;\n const tokens = notionalUsd / entryPriceUsd;\n const slippageFactor = (BPS_DIVISOR - slippageBps) / BPS_DIVISOR;\n return Math.floor(tokens * slippageFactor * TOKEN_UNITS_PER_TOKEN);\n}\n\n/**\n * Estimated base liquidation price (deterministic, at-entry closed form).\n *\n * **This is an estimate, not the server's TWAP solver result.** It computes the\n * at-entry base liquidation price (F = 0, no safety margin) per the docs\n * (position-math/04-liquidation):\n *\n * ```\n * P_liq_base = entryPrice * (L - 1) / L * (1 + liquidationFeeBps / 10_000)\n * ```\n *\n * where `L = leverageBps / 10_000`. At 1x leverage the borrowed capital is zero\n * so the liquidation price is zero. `entryPriceUsd` is in dollars; the result is\n * in the same units. The live server liquidation price drifts above this as the\n * lifetime fee `F` accrues and includes a safety margin.\n */\nexport function estimateLiquidationPrice(\n entryPriceUsd: number,\n leverageBps: number,\n liquidationFeeBps: number,\n): number {\n const leverage = leverageBps / BPS_DIVISOR;\n if (leverage <= 1) {\n return 0;\n }\n const loanPerToken = entryPriceUsd * ((leverage - 1) / leverage);\n return loanPerToken * (1 + liquidationFeeBps / BPS_DIVISOR);\n}\n\n/**\n * Inputs for {@link computeMaxGain}. All amounts are in USDC units\n * (1_000_000 = $1) except `positionTokenUnits` (token units, 1_000_000 = 1\n * token) which is numerically equal to its settlement USDC value.\n */\nexport interface MaxGainInput {\n positionTokenUnits: number;\n notionalUsdcUnits: number;\n expectedOpenTradingFeeUsdcUnits: number;\n originationFeeUsdcUnits: number;\n}\n\n/**\n * Result of {@link computeMaxGain}. All amounts in USDC units (1_000_000 = $1).\n * Gains are profit OVER principal (notional = loan + collateral) and may be\n * negative — they are signed and never clamped.\n */\nexport interface MaxGainResult {\n fullValueOnWinUsdcUnits: number;\n grossMaxGainUsdcUnits: number;\n netMaxGainUsdcUnits: number;\n}\n\n/**\n * Maximum gain (gross and net) for a winning settlement exit — profit over\n * principal. On a win each position token redeems at $1 (CTF settlement), so\n * the full value equals `positionTokenUnits` and there is NO exit trading fee.\n *\n * ```\n * fullValueOnWin = positionTokenUnits\n * grossMaxGain = fullValueOnWin - notionalUsdcUnits\n * netMaxGain = grossMaxGain - expectedOpenTradingFee - originationFee\n * ```\n *\n * Lifetime fees are excluded, so net max gain is an upper bound (a position held\n * to settlement accrues lifetime fees that reduce realized profit). Gains are\n * signed — a position whose principal exceeds its winning redemption value\n * yields a negative max gain.\n */\nexport function computeMaxGain(input: MaxGainInput): MaxGainResult {\n const fullValueOnWinUsdcUnits = input.positionTokenUnits;\n const grossMaxGainUsdcUnits = fullValueOnWinUsdcUnits - input.notionalUsdcUnits;\n const netMaxGainUsdcUnits =\n grossMaxGainUsdcUnits - input.expectedOpenTradingFeeUsdcUnits - input.originationFeeUsdcUnits;\n\n return {\n fullValueOnWinUsdcUnits,\n grossMaxGainUsdcUnits,\n netMaxGainUsdcUnits,\n };\n}\n","const BPS_DIVISOR = 10_000;\nconst BPS_DIVISOR_BIG = 10_000n;\n\nexport const tokenUnitsPerToken = 1_000_000n;\n\nexport const partialCloseMinTokens = 5n;\n\nexport const partialCloseMinFractionBps = 2_000n;\n\nexport function closeTokenUnitsForPct(currentTokenUnits: bigint, pctBps: number): bigint {\n const clampedBps = BigInt(Math.max(0, Math.min(BPS_DIVISOR, Math.round(pctBps))));\n\n return (currentTokenUnits * clampedBps) / BPS_DIVISOR_BIG;\n}\n\nexport function pctBpsForCloseTokenUnits(currentTokenUnits: bigint, closeTokenUnits: bigint): number {\n if (currentTokenUnits <= 0n) {\n return 0;\n }\n\n return Number((closeTokenUnits * BPS_DIVISOR_BIG) / currentTokenUnits);\n}\n\nexport function fallbackMinPartialCloseTokenUnits(originalTokenUnits: bigint): bigint {\n const floorTokens = partialCloseMinTokens * tokenUnitsPerToken;\n const floorFraction = (originalTokenUnits * partialCloseMinFractionBps) / BPS_DIVISOR_BIG;\n\n return floorFraction > floorTokens ? floorFraction : floorTokens;\n}\n\nexport function clampCloseTokenUnits(value: bigint, min: bigint, max: bigint): bigint {\n if (value < min) {\n return min;\n }\n\n if (value > max) {\n return max;\n }\n\n return value;\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -1,10 +1,10 @@
1
- export { A as ApiKeyAuth, a as ApiKeyAuthOptions, b as AuthProvider, C as CorrectedField, D as DimesClient, c as DimesClientOptions, G as GetFeeRatesParams, d as GetMarketsParams, e as GetPositionsParams, H as HintAdjustment, J as JwtAuth, f as JwtAuthOptions, M as MarketExpand, g as MarketSort, P as Paginated, h as PositionStatus, Q as QuoteHint, S as SearchMarketsParams, i as hintAdjustment, m as marketMovedCodes, q as quoteErrorHint } from './dimes-client-ntybPwHK.cjs';
2
- export { a as DimesApiError, D as DimesContractError, b as DimesError } from './dimes-error-BhKtCgba.cjs';
3
- import { C as CreateQuoteParams, Q as Quote, M as Market, P as Position } from './aliases-BJyM8ydu.cjs';
4
- export { h as CamelizeKeys, i as CloseAttempt, j as ClosedPosition, d as ContractInfo, k as CreateOfferParams, l as CreateTokenResult, e as CustomerLimit, F as FeeRates, m as FeeRatesMarket, n as FeeRatesOriginationTier, g as FeeReport, f as FeeReportParams, o as MarketFees, b as MarketLeverage, p as MarketMaxLeveragePerNotional, q as MarketPrices, r as MarketSidedEligibility, s as MarketSidedMaxLeveragePerNotional, O as Offer, t as OpenPosition, u as OriginationTier, v as PendingOperation, w as PositionClosedFees, x as PositionCurrent, y as PositionEntry, z as PositionFailure, A as PositionOpenFees, B as PositionResult, D as PositionRisk, E as PositionTiming, G as PositionUnwind, H as PositionUnwindList, I as isClosedPosition, J as isOpenPosition, K as leverageMaxBps } from './aliases-BJyM8ydu.cjs';
5
- import { Q as QuoteParams, a as QuoteOptions, b as QuoteResult } from './quote-Bc9H5-2H.cjs';
6
- export { M as MarketMovedEvent, S as Side } from './quote-Bc9H5-2H.cjs';
7
- export { P as PositionEvent, a as PositionEventType, p as positionEventTypes } from './types-Co-2bQSi.cjs';
1
+ export { A as ApiKeyAuth, a as ApiKeyAuthOptions, b as AuthProvider, C as CorrectedField, D as DimesClient, c as DimesClientOptions, G as GetFeeRatesParams, d as GetMarketsParams, e as GetPositionsParams, H as HintAdjustment, J as JwtAuth, f as JwtAuthOptions, M as MarketExpand, g as MarketSort, P as Paginated, h as PositionStatus, Q as QuoteHint, S as SearchMarketsParams, i as hintAdjustment, m as marketMovedCodes, q as quoteErrorHint } from './dimes-client-D9tohawC.cjs';
2
+ export { a as DimesApiError, D as DimesContractError, b as DimesError } from './dimes-error-E9yPAZb-.cjs';
3
+ import { C as CreateQuoteParams, Q as Quote, M as Market, P as Position } from './aliases-Dne14KBa.cjs';
4
+ export { i as CamelizeKeys, j as CloseAttempt, k as ClosedPosition, e as ContractInfo, l as CreateOfferParams, m as CreateTokenResult, f as CustomerLimit, F as FeeRates, n as FeeRatesMarket, o as FeeRatesOriginationTier, h as FeeReport, g as FeeReportParams, p as MarketFees, b as MarketLeverage, q as MarketMaxLeveragePerNotional, r as MarketPrices, s as MarketSidedEligibility, t as MarketSidedMaxLeveragePerNotional, O as Offer, u as OpenPosition, v as OriginationTier, w as PendingOperation, x as PositionClosedFees, y as PositionCurrent, z as PositionEntry, A as PositionFailure, B as PositionOpenFees, D as PositionPartialClose, d as PositionPartialCloseList, E as PositionResult, G as PositionRisk, H as PositionTiming, I as PositionUnwind, J as PositionUnwindList, K as isClosedPosition, L as isOpenPosition, N as leverageMaxBps } from './aliases-Dne14KBa.cjs';
5
+ import { Q as QuoteParams, a as QuoteOptions, b as QuoteResult } from './quote-sWguOcoJ.cjs';
6
+ export { M as MarketMovedEvent, S as Side } from './quote-sWguOcoJ.cjs';
7
+ export { P as PositionEvent, a as PositionEventType, p as positionEventTypes } from './types-Bvj_WDbX.cjs';
8
8
 
9
9
  type Params = Record<string, unknown> | null;
10
10
 
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- export { A as ApiKeyAuth, a as ApiKeyAuthOptions, b as AuthProvider, C as CorrectedField, D as DimesClient, c as DimesClientOptions, G as GetFeeRatesParams, d as GetMarketsParams, e as GetPositionsParams, H as HintAdjustment, J as JwtAuth, f as JwtAuthOptions, M as MarketExpand, g as MarketSort, P as Paginated, h as PositionStatus, Q as QuoteHint, S as SearchMarketsParams, i as hintAdjustment, m as marketMovedCodes, q as quoteErrorHint } from './dimes-client-DLbPP30g.js';
2
- export { a as DimesApiError, D as DimesContractError, b as DimesError } from './dimes-error-DjxvjzCZ.js';
3
- import { C as CreateQuoteParams, Q as Quote, M as Market, P as Position } from './aliases-BJyM8ydu.js';
4
- export { h as CamelizeKeys, i as CloseAttempt, j as ClosedPosition, d as ContractInfo, k as CreateOfferParams, l as CreateTokenResult, e as CustomerLimit, F as FeeRates, m as FeeRatesMarket, n as FeeRatesOriginationTier, g as FeeReport, f as FeeReportParams, o as MarketFees, b as MarketLeverage, p as MarketMaxLeveragePerNotional, q as MarketPrices, r as MarketSidedEligibility, s as MarketSidedMaxLeveragePerNotional, O as Offer, t as OpenPosition, u as OriginationTier, v as PendingOperation, w as PositionClosedFees, x as PositionCurrent, y as PositionEntry, z as PositionFailure, A as PositionOpenFees, B as PositionResult, D as PositionRisk, E as PositionTiming, G as PositionUnwind, H as PositionUnwindList, I as isClosedPosition, J as isOpenPosition, K as leverageMaxBps } from './aliases-BJyM8ydu.js';
5
- import { Q as QuoteParams, a as QuoteOptions, b as QuoteResult } from './quote-BoTWtznc.js';
6
- export { M as MarketMovedEvent, S as Side } from './quote-BoTWtznc.js';
7
- export { P as PositionEvent, a as PositionEventType, p as positionEventTypes } from './types-ClHQbIcY.js';
1
+ export { A as ApiKeyAuth, a as ApiKeyAuthOptions, b as AuthProvider, C as CorrectedField, D as DimesClient, c as DimesClientOptions, G as GetFeeRatesParams, d as GetMarketsParams, e as GetPositionsParams, H as HintAdjustment, J as JwtAuth, f as JwtAuthOptions, M as MarketExpand, g as MarketSort, P as Paginated, h as PositionStatus, Q as QuoteHint, S as SearchMarketsParams, i as hintAdjustment, m as marketMovedCodes, q as quoteErrorHint } from './dimes-client-DJ1d_p31.js';
2
+ export { a as DimesApiError, D as DimesContractError, b as DimesError } from './dimes-error-hSoOierP.js';
3
+ import { C as CreateQuoteParams, Q as Quote, M as Market, P as Position } from './aliases-Dne14KBa.js';
4
+ export { i as CamelizeKeys, j as CloseAttempt, k as ClosedPosition, e as ContractInfo, l as CreateOfferParams, m as CreateTokenResult, f as CustomerLimit, F as FeeRates, n as FeeRatesMarket, o as FeeRatesOriginationTier, h as FeeReport, g as FeeReportParams, p as MarketFees, b as MarketLeverage, q as MarketMaxLeveragePerNotional, r as MarketPrices, s as MarketSidedEligibility, t as MarketSidedMaxLeveragePerNotional, O as Offer, u as OpenPosition, v as OriginationTier, w as PendingOperation, x as PositionClosedFees, y as PositionCurrent, z as PositionEntry, A as PositionFailure, B as PositionOpenFees, D as PositionPartialClose, d as PositionPartialCloseList, E as PositionResult, G as PositionRisk, H as PositionTiming, I as PositionUnwind, J as PositionUnwindList, K as isClosedPosition, L as isOpenPosition, N as leverageMaxBps } from './aliases-Dne14KBa.js';
5
+ import { Q as QuoteParams, a as QuoteOptions, b as QuoteResult } from './quote-D4QunMtN.js';
6
+ export { M as MarketMovedEvent, S as Side } from './quote-D4QunMtN.js';
7
+ export { P as PositionEvent, a as PositionEventType, p as positionEventTypes } from './types-BHU4Qq7e.js';
8
8
 
9
9
  type Params = Record<string, unknown> | null;
10
10
 
package/dist/index.mjs CHANGED
@@ -5,17 +5,17 @@ import {
5
5
  isMarketMovedError,
6
6
  marketMovedCodes,
7
7
  quoteErrorHint
8
- } from "./chunk-T67Z74J3.mjs";
8
+ } from "./chunk-IJO5E22G.mjs";
9
9
  import {
10
10
  DimesApiError,
11
11
  DimesContractError,
12
12
  DimesError,
13
13
  formatErrorMessage,
14
14
  resolveFriendlyMessage
15
- } from "./chunk-PZCBUVPD.mjs";
15
+ } from "./chunk-4OKYU5D7.mjs";
16
16
  import {
17
17
  positionEventTypes
18
- } from "./chunk-PK2PRTQW.mjs";
18
+ } from "./chunk-TYR33WJW.mjs";
19
19
 
20
20
  // src/client/dimes-client.ts
21
21
  import { decamelizeKeys } from "humps";
@@ -193,6 +193,11 @@ var DimesClient = class {
193
193
  `/v1/prediction-markets/positions/${encodeURIComponent(positionId)}/transactions`
194
194
  );
195
195
  }
196
+ async getPositionPartialCloses(positionId) {
197
+ return this.http.request(
198
+ `/v1/prediction-markets/positions/${encodeURIComponent(positionId)}/partial-closes`
199
+ );
200
+ }
196
201
  async cancelPosition(positionId) {
197
202
  await this.http.request(`/v1/prediction-markets/positions/${encodeURIComponent(positionId)}`, {
198
203
  method: "DELETE"
@@ -377,14 +382,14 @@ function rejectionReasonText(code) {
377
382
  if (!code) {
378
383
  return "Not eligible for new positions";
379
384
  }
380
- const stripped = code.replace(/^quote_/i, "").replaceAll("_", " ").toLowerCase();
385
+ const stripped = code.replace(/^quote_/i, "").replace(/^notional_selector_/i, "").replaceAll("_", " ").toLowerCase();
381
386
  return stripped.charAt(0).toUpperCase() + stripped.slice(1);
382
387
  }
383
388
  function rejectionReasonShort(code) {
384
389
  if (!code) {
385
390
  return "unavailable";
386
391
  }
387
- const stripped = code.replace(/^quote_/i, "").replace(/_exceeded$/i, "").replace(/_too_(low|high)$/i, "").replaceAll("_", " ").toLowerCase();
392
+ const stripped = code.replace(/^quote_/i, "").replace(/^notional_selector_/i, "").replace(/_exceeded$/i, "").replace(/_too_(low|high)$/i, "").replaceAll("_", " ").toLowerCase();
388
393
  return stripped;
389
394
  }
390
395