@dimes-dot-fi/sdk 2.4.0 → 2.7.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.
- package/README.md +16 -0
- package/dist/{aliases-Dne14KBa.d.cts → aliases-BI1c3Yt0.d.cts} +981 -787
- package/dist/{aliases-Dne14KBa.d.ts → aliases-BI1c3Yt0.d.ts} +981 -787
- package/dist/{chunk-KNGEIWFR.cjs → chunk-ERM4WP6D.cjs} +8 -4
- package/dist/chunk-ERM4WP6D.cjs.map +1 -0
- package/dist/{chunk-LXZAXWLO.mjs → chunk-GA7ZBK6W.mjs} +8 -4
- package/dist/chunk-GA7ZBK6W.mjs.map +1 -0
- package/dist/{chunk-Q34TMZ5J.mjs → chunk-HJ5EVO5A.mjs} +11 -6
- package/dist/chunk-HJ5EVO5A.mjs.map +1 -0
- package/dist/{chunk-IZI65LZF.cjs → chunk-L273PAD4.cjs} +14 -9
- package/dist/chunk-L273PAD4.cjs.map +1 -0
- package/dist/contract/index.cjs +1487 -136
- package/dist/contract/index.cjs.map +1 -1
- package/dist/contract/index.d.cts +135 -8
- package/dist/contract/index.d.ts +135 -8
- package/dist/contract/index.mjs +1470 -119
- package/dist/contract/index.mjs.map +1 -1
- package/dist/{dimes-client-DJ1d_p31.d.ts → dimes-client-C4SsCNrZ.d.cts} +48 -3
- package/dist/{dimes-client-D9tohawC.d.cts → dimes-client-Ckn8yRG6.d.ts} +48 -3
- package/dist/{dimes-error-E9yPAZb-.d.cts → dimes-error-BRysMNV_.d.cts} +2 -2
- package/dist/{dimes-error-hSoOierP.d.ts → dimes-error-Ke7yuX1m.d.ts} +2 -2
- package/dist/index.cjs +78 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -9
- package/dist/index.d.ts +10 -9
- package/dist/index.mjs +74 -4
- package/dist/index.mjs.map +1 -1
- package/dist/{quote-sWguOcoJ.d.cts → quote-06n723we.d.ts} +7 -2
- package/dist/{quote-D4QunMtN.d.ts → quote-CcIqLwKb.d.cts} +7 -2
- package/dist/react/index.cjs +34 -33
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +12 -8
- package/dist/react/index.d.ts +12 -8
- package/dist/react/index.mjs +7 -6
- package/dist/react/index.mjs.map +1 -1
- package/dist/{types-Bvj_WDbX.d.cts → types-B881zrxm.d.cts} +1 -1
- package/dist/{types-BHU4Qq7e.d.ts → types-CcoiGMbT.d.ts} +1 -1
- package/dist/ws/index.d.cts +3 -3
- package/dist/ws/index.d.ts +3 -3
- package/package.json +1 -1
- package/dist/chunk-IZI65LZF.cjs.map +0 -1
- package/dist/chunk-KNGEIWFR.cjs.map +0 -1
- package/dist/chunk-LXZAXWLO.mjs.map +0 -1
- package/dist/chunk-Q34TMZ5J.mjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { M as Market, C as CreateQuoteParams, Q as Quote, P as Position, c as PositionTransactions, d as
|
|
1
|
+
import { M as Market, C as CreateQuoteParams, Q as Quote, R as RiskMode, P as Position, c as PositionTransactions, d as PositionUnwindList, e as PositionPartialCloseList, f as ContractInfo, g as CustomerLimit, F as FeeRates, h as FeeReportParams, i as FeeReport } from './aliases-BI1c3Yt0.cjs';
|
|
2
2
|
|
|
3
3
|
declare const marketMovedCodes: Set<string>;
|
|
4
4
|
type QuoteHint = {
|
|
@@ -142,6 +142,12 @@ interface GetMarketsParams {
|
|
|
142
142
|
interface SearchMarketsParams extends GetMarketsParams {
|
|
143
143
|
query: string;
|
|
144
144
|
}
|
|
145
|
+
interface PromoteDraftQuoteParams {
|
|
146
|
+
riskMode?: RiskMode;
|
|
147
|
+
}
|
|
148
|
+
interface GetPositionUnwindsParams {
|
|
149
|
+
status?: "executed" | "planned" | "all";
|
|
150
|
+
}
|
|
145
151
|
interface GetPositionsParams {
|
|
146
152
|
limit?: number;
|
|
147
153
|
startingAfter?: string;
|
|
@@ -165,16 +171,55 @@ declare class DimesClient {
|
|
|
165
171
|
getToken(): string | null;
|
|
166
172
|
getMarkets(params?: GetMarketsParams): Promise<Paginated<Market>>;
|
|
167
173
|
getMarket(ticker: string): Promise<Market>;
|
|
174
|
+
/**
|
|
175
|
+
* Markets belonging to one event — the real-world happening a market resolves against, such as a
|
|
176
|
+
* single game or one hourly price window. Read the ticker from `market.event.ticker`.
|
|
177
|
+
*
|
|
178
|
+
* Accepts the same params as {@link getMarkets} and returns the same market objects.
|
|
179
|
+
*/
|
|
180
|
+
getEventMarkets(eventTicker: string, params?: GetMarketsParams): Promise<Paginated<Market>>;
|
|
181
|
+
/**
|
|
182
|
+
* Markets belonging to one series, across every event in it — a series is the recurring template an
|
|
183
|
+
* event comes from, such as the 5-minute BTC up/down series. Read the ticker from
|
|
184
|
+
* `market.event.seriesTicker`, which is null for events with no series.
|
|
185
|
+
*
|
|
186
|
+
* Accepts the same params as {@link getMarkets}. A series commonly holds more markets than fit on one
|
|
187
|
+
* page, so paginate with `startingAfter`.
|
|
188
|
+
*/
|
|
189
|
+
getSeriesMarkets(seriesTicker: string, params?: GetMarketsParams): Promise<Paginated<Market>>;
|
|
168
190
|
/**
|
|
169
191
|
* @deprecated The `/markets/search` path is deprecated. Use {@link getMarkets} with a `query` param:
|
|
170
192
|
* `getMarkets({ query: "bitcoin" })`.
|
|
171
193
|
*/
|
|
172
194
|
searchMarkets(params: SearchMarketsParams): Promise<Paginated<Market>>;
|
|
173
195
|
createDraftQuote(params: CreateQuoteParams): Promise<Quote>;
|
|
174
|
-
|
|
196
|
+
/**
|
|
197
|
+
* Promote a draft into a real, signed quote.
|
|
198
|
+
*
|
|
199
|
+
* A draft carries no risk mode at all — sending `riskMode` on the draft body does nothing, and a
|
|
200
|
+
* draft always reports adaptive terms. The mode the position actually opens in is chosen here, and
|
|
201
|
+
* omitting it means adaptive, so a client that showed the user committed terms from the draft's
|
|
202
|
+
* `committedUnwinds` must repeat the choice at promotion or it will get adaptive terms.
|
|
203
|
+
*/
|
|
204
|
+
promoteDraftQuote(draftId: string, params?: PromoteDraftQuoteParams): Promise<Quote>;
|
|
175
205
|
createQuote(params: CreateQuoteParams): Promise<Quote>;
|
|
176
206
|
getPositions(params?: GetPositionsParams): Promise<Position[]>;
|
|
207
|
+
/** Your positions on a single market. Accepts the same params as {@link getPositions}. */
|
|
208
|
+
getMarketPositions(ticker: string, params?: GetPositionsParams): Promise<Position[]>;
|
|
209
|
+
/** Your positions across every market on one event. Accepts the same params as {@link getPositions}. */
|
|
210
|
+
getEventPositions(eventTicker: string, params?: GetPositionsParams): Promise<Position[]>;
|
|
211
|
+
/** Your positions across every market in one series, spanning all of its events. */
|
|
212
|
+
getSeriesPositions(seriesTicker: string, params?: GetPositionsParams): Promise<Position[]>;
|
|
177
213
|
getPositionTransactions(positionId: string): Promise<PositionTransactions>;
|
|
214
|
+
/**
|
|
215
|
+
* Deleverage history for a position, and — for committed-mode positions — the signed ladder.
|
|
216
|
+
*
|
|
217
|
+
* `status` defaults to `executed` (unwinds that already landed on-chain). Ask for `planned` to get
|
|
218
|
+
* the ladder rungs instead, or `all` for both. Rung rows carry `triggerPriceUsdPips` and a `status`
|
|
219
|
+
* of `planned`, `triggered` (its price was reached) or `superseded` (a partial close put the
|
|
220
|
+
* position below its target, so it can never fire).
|
|
221
|
+
*/
|
|
222
|
+
getPositionUnwinds(positionId: string, params?: GetPositionUnwindsParams): Promise<PositionUnwindList>;
|
|
178
223
|
getPositionPartialCloses(positionId: string): Promise<PositionPartialCloseList>;
|
|
179
224
|
cancelPosition(positionId: string): Promise<void>;
|
|
180
225
|
getContractInfo(): Promise<ContractInfo>;
|
|
@@ -190,4 +235,4 @@ declare class DimesClient {
|
|
|
190
235
|
getFeeReport(params: FeeReportParams): Promise<FeeReport>;
|
|
191
236
|
}
|
|
192
237
|
|
|
193
|
-
export { ApiKeyAuth as A, type CorrectedField as C, DimesClient as D, type GetFeeRatesParams as G, type HintAdjustment as H, JwtAuth as J, type MarketExpand as M, type
|
|
238
|
+
export { ApiKeyAuth as A, type CorrectedField as C, DimesClient as D, type GetFeeRatesParams as G, type HintAdjustment as H, JwtAuth as J, type MarketExpand as M, type PromoteDraftQuoteParams as P, type QuoteHint as Q, type SearchMarketsParams as S, type ApiKeyAuthOptions as a, type AuthProvider as b, type DimesClientOptions as c, type GetMarketsParams as d, type GetPositionUnwindsParams as e, type GetPositionsParams as f, type JwtAuthOptions as g, type MarketSort as h, type Paginated as i, type PositionStatus as j, hintAdjustment as k, marketMovedCodes as m, quoteErrorHint as q };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { M as Market, C as CreateQuoteParams, Q as Quote, P as Position, c as PositionTransactions, d as
|
|
1
|
+
import { M as Market, C as CreateQuoteParams, Q as Quote, R as RiskMode, P as Position, c as PositionTransactions, d as PositionUnwindList, e as PositionPartialCloseList, f as ContractInfo, g as CustomerLimit, F as FeeRates, h as FeeReportParams, i as FeeReport } from './aliases-BI1c3Yt0.js';
|
|
2
2
|
|
|
3
3
|
declare const marketMovedCodes: Set<string>;
|
|
4
4
|
type QuoteHint = {
|
|
@@ -142,6 +142,12 @@ interface GetMarketsParams {
|
|
|
142
142
|
interface SearchMarketsParams extends GetMarketsParams {
|
|
143
143
|
query: string;
|
|
144
144
|
}
|
|
145
|
+
interface PromoteDraftQuoteParams {
|
|
146
|
+
riskMode?: RiskMode;
|
|
147
|
+
}
|
|
148
|
+
interface GetPositionUnwindsParams {
|
|
149
|
+
status?: "executed" | "planned" | "all";
|
|
150
|
+
}
|
|
145
151
|
interface GetPositionsParams {
|
|
146
152
|
limit?: number;
|
|
147
153
|
startingAfter?: string;
|
|
@@ -165,16 +171,55 @@ declare class DimesClient {
|
|
|
165
171
|
getToken(): string | null;
|
|
166
172
|
getMarkets(params?: GetMarketsParams): Promise<Paginated<Market>>;
|
|
167
173
|
getMarket(ticker: string): Promise<Market>;
|
|
174
|
+
/**
|
|
175
|
+
* Markets belonging to one event — the real-world happening a market resolves against, such as a
|
|
176
|
+
* single game or one hourly price window. Read the ticker from `market.event.ticker`.
|
|
177
|
+
*
|
|
178
|
+
* Accepts the same params as {@link getMarkets} and returns the same market objects.
|
|
179
|
+
*/
|
|
180
|
+
getEventMarkets(eventTicker: string, params?: GetMarketsParams): Promise<Paginated<Market>>;
|
|
181
|
+
/**
|
|
182
|
+
* Markets belonging to one series, across every event in it — a series is the recurring template an
|
|
183
|
+
* event comes from, such as the 5-minute BTC up/down series. Read the ticker from
|
|
184
|
+
* `market.event.seriesTicker`, which is null for events with no series.
|
|
185
|
+
*
|
|
186
|
+
* Accepts the same params as {@link getMarkets}. A series commonly holds more markets than fit on one
|
|
187
|
+
* page, so paginate with `startingAfter`.
|
|
188
|
+
*/
|
|
189
|
+
getSeriesMarkets(seriesTicker: string, params?: GetMarketsParams): Promise<Paginated<Market>>;
|
|
168
190
|
/**
|
|
169
191
|
* @deprecated The `/markets/search` path is deprecated. Use {@link getMarkets} with a `query` param:
|
|
170
192
|
* `getMarkets({ query: "bitcoin" })`.
|
|
171
193
|
*/
|
|
172
194
|
searchMarkets(params: SearchMarketsParams): Promise<Paginated<Market>>;
|
|
173
195
|
createDraftQuote(params: CreateQuoteParams): Promise<Quote>;
|
|
174
|
-
|
|
196
|
+
/**
|
|
197
|
+
* Promote a draft into a real, signed quote.
|
|
198
|
+
*
|
|
199
|
+
* A draft carries no risk mode at all — sending `riskMode` on the draft body does nothing, and a
|
|
200
|
+
* draft always reports adaptive terms. The mode the position actually opens in is chosen here, and
|
|
201
|
+
* omitting it means adaptive, so a client that showed the user committed terms from the draft's
|
|
202
|
+
* `committedUnwinds` must repeat the choice at promotion or it will get adaptive terms.
|
|
203
|
+
*/
|
|
204
|
+
promoteDraftQuote(draftId: string, params?: PromoteDraftQuoteParams): Promise<Quote>;
|
|
175
205
|
createQuote(params: CreateQuoteParams): Promise<Quote>;
|
|
176
206
|
getPositions(params?: GetPositionsParams): Promise<Position[]>;
|
|
207
|
+
/** Your positions on a single market. Accepts the same params as {@link getPositions}. */
|
|
208
|
+
getMarketPositions(ticker: string, params?: GetPositionsParams): Promise<Position[]>;
|
|
209
|
+
/** Your positions across every market on one event. Accepts the same params as {@link getPositions}. */
|
|
210
|
+
getEventPositions(eventTicker: string, params?: GetPositionsParams): Promise<Position[]>;
|
|
211
|
+
/** Your positions across every market in one series, spanning all of its events. */
|
|
212
|
+
getSeriesPositions(seriesTicker: string, params?: GetPositionsParams): Promise<Position[]>;
|
|
177
213
|
getPositionTransactions(positionId: string): Promise<PositionTransactions>;
|
|
214
|
+
/**
|
|
215
|
+
* Deleverage history for a position, and — for committed-mode positions — the signed ladder.
|
|
216
|
+
*
|
|
217
|
+
* `status` defaults to `executed` (unwinds that already landed on-chain). Ask for `planned` to get
|
|
218
|
+
* the ladder rungs instead, or `all` for both. Rung rows carry `triggerPriceUsdPips` and a `status`
|
|
219
|
+
* of `planned`, `triggered` (its price was reached) or `superseded` (a partial close put the
|
|
220
|
+
* position below its target, so it can never fire).
|
|
221
|
+
*/
|
|
222
|
+
getPositionUnwinds(positionId: string, params?: GetPositionUnwindsParams): Promise<PositionUnwindList>;
|
|
178
223
|
getPositionPartialCloses(positionId: string): Promise<PositionPartialCloseList>;
|
|
179
224
|
cancelPosition(positionId: string): Promise<void>;
|
|
180
225
|
getContractInfo(): Promise<ContractInfo>;
|
|
@@ -190,4 +235,4 @@ declare class DimesClient {
|
|
|
190
235
|
getFeeReport(params: FeeReportParams): Promise<FeeReport>;
|
|
191
236
|
}
|
|
192
237
|
|
|
193
|
-
export { ApiKeyAuth as A, type CorrectedField as C, DimesClient as D, type GetFeeRatesParams as G, type HintAdjustment as H, JwtAuth as J, type MarketExpand as M, type
|
|
238
|
+
export { ApiKeyAuth as A, type CorrectedField as C, DimesClient as D, type GetFeeRatesParams as G, type HintAdjustment as H, JwtAuth as J, type MarketExpand as M, type PromoteDraftQuoteParams as P, type QuoteHint as Q, type SearchMarketsParams as S, type ApiKeyAuthOptions as a, type AuthProvider as b, type DimesClientOptions as c, type GetMarketsParams as d, type GetPositionUnwindsParams as e, type GetPositionsParams as f, type JwtAuthOptions as g, type MarketSort as h, type Paginated as i, type PositionStatus as j, hintAdjustment as k, marketMovedCodes as m, quoteErrorHint as q };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Q as QuoteHint } from './dimes-client-
|
|
1
|
+
import { Q as QuoteHint } from './dimes-client-C4SsCNrZ.cjs';
|
|
2
2
|
|
|
3
3
|
declare class DimesError extends Error {
|
|
4
4
|
readonly code: string;
|
|
@@ -23,4 +23,4 @@ declare class DimesContractError extends DimesError {
|
|
|
23
23
|
constructor(code: string, message: string);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export {
|
|
26
|
+
export { DimesApiError as D, DimesContractError as a, DimesError as b };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Q as QuoteHint } from './dimes-client-
|
|
1
|
+
import { Q as QuoteHint } from './dimes-client-Ckn8yRG6.js';
|
|
2
2
|
|
|
3
3
|
declare class DimesError extends Error {
|
|
4
4
|
readonly code: string;
|
|
@@ -23,4 +23,4 @@ declare class DimesContractError extends DimesError {
|
|
|
23
23
|
constructor(code: string, message: string);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export {
|
|
26
|
+
export { DimesApiError as D, DimesContractError as a, DimesError as b };
|
package/dist/index.cjs
CHANGED
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
var
|
|
8
|
+
var _chunkL273PAD4cjs = require('./chunk-L273PAD4.cjs');
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
var
|
|
15
|
+
var _chunkERM4WP6Dcjs = require('./chunk-ERM4WP6D.cjs');
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
var _chunkUYDXDYEPcjs = require('./chunk-UYDXDYEP.cjs');
|
|
@@ -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,
|
|
63
|
+
throw new (0, _chunkERM4WP6Dcjs.DimesApiError)({ status: response.status, code, type, message, params });
|
|
64
64
|
}
|
|
65
65
|
var HttpClient = class {
|
|
66
66
|
|
|
@@ -159,6 +159,32 @@ var DimesClient = class {
|
|
|
159
159
|
async getMarket(ticker) {
|
|
160
160
|
return this.http.request(`/v1/prediction-markets/markets/${encodeURIComponent(ticker)}`);
|
|
161
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Markets belonging to one event — the real-world happening a market resolves against, such as a
|
|
164
|
+
* single game or one hourly price window. Read the ticker from `market.event.ticker`.
|
|
165
|
+
*
|
|
166
|
+
* Accepts the same params as {@link getMarkets} and returns the same market objects.
|
|
167
|
+
*/
|
|
168
|
+
async getEventMarkets(eventTicker, params) {
|
|
169
|
+
const query = params ? buildQueryFromEntries(Object.entries(params)) : "";
|
|
170
|
+
return this.http.request(
|
|
171
|
+
`/v1/prediction-markets/events/${encodeURIComponent(eventTicker)}/markets${query}`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Markets belonging to one series, across every event in it — a series is the recurring template an
|
|
176
|
+
* event comes from, such as the 5-minute BTC up/down series. Read the ticker from
|
|
177
|
+
* `market.event.seriesTicker`, which is null for events with no series.
|
|
178
|
+
*
|
|
179
|
+
* Accepts the same params as {@link getMarkets}. A series commonly holds more markets than fit on one
|
|
180
|
+
* page, so paginate with `startingAfter`.
|
|
181
|
+
*/
|
|
182
|
+
async getSeriesMarkets(seriesTicker, params) {
|
|
183
|
+
const query = params ? buildQueryFromEntries(Object.entries(params)) : "";
|
|
184
|
+
return this.http.request(
|
|
185
|
+
`/v1/prediction-markets/series/${encodeURIComponent(seriesTicker)}/markets${query}`
|
|
186
|
+
);
|
|
187
|
+
}
|
|
162
188
|
/**
|
|
163
189
|
* @deprecated The `/markets/search` path is deprecated. Use {@link getMarkets} with a `query` param:
|
|
164
190
|
* `getMarkets({ query: "bitcoin" })`.
|
|
@@ -173,9 +199,18 @@ var DimesClient = class {
|
|
|
173
199
|
body: JSON.stringify(_humps.decamelizeKeys.call(void 0, params))
|
|
174
200
|
});
|
|
175
201
|
}
|
|
176
|
-
|
|
202
|
+
/**
|
|
203
|
+
* Promote a draft into a real, signed quote.
|
|
204
|
+
*
|
|
205
|
+
* A draft carries no risk mode at all — sending `riskMode` on the draft body does nothing, and a
|
|
206
|
+
* draft always reports adaptive terms. The mode the position actually opens in is chosen here, and
|
|
207
|
+
* omitting it means adaptive, so a client that showed the user committed terms from the draft's
|
|
208
|
+
* `committedUnwinds` must repeat the choice at promotion or it will get adaptive terms.
|
|
209
|
+
*/
|
|
210
|
+
async promoteDraftQuote(draftId, params) {
|
|
177
211
|
return this.http.request(`/v1/prediction-markets/promoted-quotes/${encodeURIComponent(draftId)}`, {
|
|
178
|
-
method: "POST"
|
|
212
|
+
method: "POST",
|
|
213
|
+
body: JSON.stringify(_humps.decamelizeKeys.call(void 0, _nullishCoalesce(params, () => ( {}))))
|
|
179
214
|
});
|
|
180
215
|
}
|
|
181
216
|
async createQuote(params) {
|
|
@@ -188,11 +223,46 @@ var DimesClient = class {
|
|
|
188
223
|
const query = params ? buildQueryFromEntries(Object.entries(params)) : "";
|
|
189
224
|
return this.http.requestList(`/v1/prediction-markets/positions${query}`);
|
|
190
225
|
}
|
|
226
|
+
/** Your positions on a single market. Accepts the same params as {@link getPositions}. */
|
|
227
|
+
async getMarketPositions(ticker, params) {
|
|
228
|
+
const query = params ? buildQueryFromEntries(Object.entries(params)) : "";
|
|
229
|
+
return this.http.requestList(
|
|
230
|
+
`/v1/prediction-markets/markets/${encodeURIComponent(ticker)}/positions${query}`
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
/** Your positions across every market on one event. Accepts the same params as {@link getPositions}. */
|
|
234
|
+
async getEventPositions(eventTicker, params) {
|
|
235
|
+
const query = params ? buildQueryFromEntries(Object.entries(params)) : "";
|
|
236
|
+
return this.http.requestList(
|
|
237
|
+
`/v1/prediction-markets/events/${encodeURIComponent(eventTicker)}/positions${query}`
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
/** Your positions across every market in one series, spanning all of its events. */
|
|
241
|
+
async getSeriesPositions(seriesTicker, params) {
|
|
242
|
+
const query = params ? buildQueryFromEntries(Object.entries(params)) : "";
|
|
243
|
+
return this.http.requestList(
|
|
244
|
+
`/v1/prediction-markets/series/${encodeURIComponent(seriesTicker)}/positions${query}`
|
|
245
|
+
);
|
|
246
|
+
}
|
|
191
247
|
async getPositionTransactions(positionId) {
|
|
192
248
|
return this.http.request(
|
|
193
249
|
`/v1/prediction-markets/positions/${encodeURIComponent(positionId)}/transactions`
|
|
194
250
|
);
|
|
195
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* Deleverage history for a position, and — for committed-mode positions — the signed ladder.
|
|
254
|
+
*
|
|
255
|
+
* `status` defaults to `executed` (unwinds that already landed on-chain). Ask for `planned` to get
|
|
256
|
+
* the ladder rungs instead, or `all` for both. Rung rows carry `triggerPriceUsdPips` and a `status`
|
|
257
|
+
* of `planned`, `triggered` (its price was reached) or `superseded` (a partial close put the
|
|
258
|
+
* position below its target, so it can never fire).
|
|
259
|
+
*/
|
|
260
|
+
async getPositionUnwinds(positionId, params) {
|
|
261
|
+
const query = params ? buildQueryFromEntries(Object.entries(params)) : "";
|
|
262
|
+
return this.http.request(
|
|
263
|
+
`/v1/prediction-markets/positions/${encodeURIComponent(positionId)}/unwinds${query}`
|
|
264
|
+
);
|
|
265
|
+
}
|
|
196
266
|
async getPositionPartialCloses(positionId) {
|
|
197
267
|
return this.http.request(
|
|
198
268
|
`/v1/prediction-markets/positions/${encodeURIComponent(positionId)}/partial-closes`
|
|
@@ -280,7 +350,7 @@ var ApiKeyAuth = (_class = class {
|
|
|
280
350
|
});
|
|
281
351
|
if (!response.ok) {
|
|
282
352
|
const text = await response.text();
|
|
283
|
-
throw new (0,
|
|
353
|
+
throw new (0, _chunkERM4WP6Dcjs.DimesError)("auth_token_failed", `Failed to obtain auth token (${response.status}): ${text}`);
|
|
284
354
|
}
|
|
285
355
|
const data = await response.json();
|
|
286
356
|
this.jwt = data.token;
|
|
@@ -323,7 +393,7 @@ var JwtAuth = (_class2 = class {
|
|
|
323
393
|
const response = await this.fetchFn(this.tokenUrl);
|
|
324
394
|
if (!response.ok) {
|
|
325
395
|
const text = await response.text();
|
|
326
|
-
throw new (0,
|
|
396
|
+
throw new (0, _chunkERM4WP6Dcjs.DimesError)(
|
|
327
397
|
"auth_token_failed",
|
|
328
398
|
`Failed to fetch token from ${this.tokenUrl} (${response.status}): ${text}`
|
|
329
399
|
);
|
|
@@ -630,5 +700,5 @@ function clampCloseTokenUnits(value, min, max) {
|
|
|
630
700
|
|
|
631
701
|
|
|
632
702
|
|
|
633
|
-
exports.ApiKeyAuth = ApiKeyAuth; exports.DimesApiError =
|
|
703
|
+
exports.ApiKeyAuth = ApiKeyAuth; exports.DimesApiError = _chunkERM4WP6Dcjs.DimesApiError; exports.DimesClient = DimesClient; exports.DimesContractError = _chunkERM4WP6Dcjs.DimesContractError; exports.DimesError = _chunkERM4WP6Dcjs.DimesError; exports.JwtAuth = JwtAuth; exports.buildQuoteParams = _chunkL273PAD4cjs.buildQuoteParams; exports.clampCloseTokenUnits = clampCloseTokenUnits; exports.closeTokenUnitsForPct = closeTokenUnitsForPct; exports.computeMaxGain = computeMaxGain; exports.computeOriginationFeeUsdcUnits = computeOriginationFeeUsdcUnits; exports.computePolymarketTradingFee = computePolymarketTradingFee; exports.defaultSide = defaultSide; exports.estimateLiquidationPrice = estimateLiquidationPrice; exports.executeQuote = _chunkL273PAD4cjs.executeQuote; exports.expectedPositionTokenUnits = expectedPositionTokenUnits; exports.fallbackMinPartialCloseTokenUnits = fallbackMinPartialCloseTokenUnits; exports.formatErrorMessage = _chunkERM4WP6Dcjs.formatErrorMessage; exports.getOriginationFeeBreakdown = getOriginationFeeBreakdown; exports.getSidedEligibility = getSidedEligibility; exports.hintAdjustment = _chunkL273PAD4cjs.hintAdjustment; exports.isClosedPosition = isClosedPosition; exports.isFullyClosed = isFullyClosed; exports.isFullyOpen = isFullyOpen; exports.isMarketMovedError = _chunkL273PAD4cjs.isMarketMovedError; exports.isOpenPosition = isOpenPosition; exports.leverageMaxBps = leverageMaxBps; exports.marketMovedCodes = _chunkL273PAD4cjs.marketMovedCodes; exports.maxLeverageBpsAtNotional = maxLeverageBpsAtNotional; exports.maxViableLeverageBpsForCollateral = maxViableLeverageBpsForCollateral; exports.partialCloseMinFractionBps = partialCloseMinFractionBps; exports.partialCloseMinTokens = partialCloseMinTokens; exports.pctBpsForCloseTokenUnits = pctBpsForCloseTokenUnits; exports.positionEventTypes = _chunkUYDXDYEPcjs.positionEventTypes; exports.quoteErrorHint = _chunkL273PAD4cjs.quoteErrorHint; exports.rejectionReasonShort = rejectionReasonShort; exports.rejectionReasonText = rejectionReasonText; exports.resolveFriendlyMessage = _chunkERM4WP6Dcjs.resolveFriendlyMessage; exports.resolveOriginationFeeBps = resolveOriginationFeeBps; exports.resolveProtocolOriginationFeeBps = resolveProtocolOriginationFeeBps; exports.tokenUnitsPerToken = tokenUnitsPerToken;
|
|
634
704
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -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;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"]}
|
|
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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","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 PositionUnwindList,\n PositionTransactions,\n Quote,\n RiskMode,\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 PromoteDraftQuoteParams {\n riskMode?: RiskMode;\n}\n\nexport interface GetPositionUnwindsParams {\n status?: \"executed\" | \"planned\" | \"all\";\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 * Markets belonging to one event — the real-world happening a market resolves against, such as a\n * single game or one hourly price window. Read the ticker from `market.event.ticker`.\n *\n * Accepts the same params as {@link getMarkets} and returns the same market objects.\n */\n public async getEventMarkets(eventTicker: string, params?: GetMarketsParams): Promise<Paginated<Market>> {\n const query = params ? buildQueryFromEntries(Object.entries(params)) : \"\";\n return this.http.request<Paginated<Market>>(\n `/v1/prediction-markets/events/${encodeURIComponent(eventTicker)}/markets${query}`,\n );\n }\n\n /**\n * Markets belonging to one series, across every event in it — a series is the recurring template an\n * event comes from, such as the 5-minute BTC up/down series. Read the ticker from\n * `market.event.seriesTicker`, which is null for events with no series.\n *\n * Accepts the same params as {@link getMarkets}. A series commonly holds more markets than fit on one\n * page, so paginate with `startingAfter`.\n */\n public async getSeriesMarkets(seriesTicker: string, params?: GetMarketsParams): Promise<Paginated<Market>> {\n const query = params ? buildQueryFromEntries(Object.entries(params)) : \"\";\n return this.http.request<Paginated<Market>>(\n `/v1/prediction-markets/series/${encodeURIComponent(seriesTicker)}/markets${query}`,\n );\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 /**\n * Promote a draft into a real, signed quote.\n *\n * A draft carries no risk mode at all — sending `riskMode` on the draft body does nothing, and a\n * draft always reports adaptive terms. The mode the position actually opens in is chosen here, and\n * omitting it means adaptive, so a client that showed the user committed terms from the draft's\n * `committedUnwinds` must repeat the choice at promotion or it will get adaptive terms.\n */\n public async promoteDraftQuote(draftId: string, params?: PromoteDraftQuoteParams): Promise<Quote> {\n return this.http.request<Quote>(`/v1/prediction-markets/promoted-quotes/${encodeURIComponent(draftId)}`, {\n method: \"POST\",\n body: JSON.stringify(decamelizeKeys(params ?? {})),\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 /** Your positions on a single market. Accepts the same params as {@link getPositions}. */\n public async getMarketPositions(ticker: string, params?: GetPositionsParams): Promise<Position[]> {\n const query = params ? buildQueryFromEntries(Object.entries(params)) : \"\";\n return this.http.requestList<Position>(\n `/v1/prediction-markets/markets/${encodeURIComponent(ticker)}/positions${query}`,\n );\n }\n\n /** Your positions across every market on one event. Accepts the same params as {@link getPositions}. */\n public async getEventPositions(eventTicker: string, params?: GetPositionsParams): Promise<Position[]> {\n const query = params ? buildQueryFromEntries(Object.entries(params)) : \"\";\n return this.http.requestList<Position>(\n `/v1/prediction-markets/events/${encodeURIComponent(eventTicker)}/positions${query}`,\n );\n }\n\n /** Your positions across every market in one series, spanning all of its events. */\n public async getSeriesPositions(seriesTicker: string, params?: GetPositionsParams): Promise<Position[]> {\n const query = params ? buildQueryFromEntries(Object.entries(params)) : \"\";\n return this.http.requestList<Position>(\n `/v1/prediction-markets/series/${encodeURIComponent(seriesTicker)}/positions${query}`,\n );\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 /**\n * Deleverage history for a position, and — for committed-mode positions — the signed ladder.\n *\n * `status` defaults to `executed` (unwinds that already landed on-chain). Ask for `planned` to get\n * the ladder rungs instead, or `all` for both. Rung rows carry `triggerPriceUsdPips` and a `status`\n * of `planned`, `triggered` (its price was reached) or `superseded` (a partial close put the\n * position below its target, so it can never fire).\n */\n public async getPositionUnwinds(positionId: string, params?: GetPositionUnwindsParams): Promise<PositionUnwindList> {\n const query = params ? buildQueryFromEntries(Object.entries(params)) : \"\";\n return this.http.request<PositionUnwindList>(\n `/v1/prediction-markets/positions/${encodeURIComponent(positionId)}/unwinds${query}`,\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\n/**\n * The event a market belongs to — the real-world happening it resolves against (one game, one\n * hourly price window). `seriesTicker` names the recurring template the event came from, and is\n * null for events with no series.\n *\n * Hand-written rather than derived from `Raw` because `generated.ts` is currently pinned to an API\n * version that predates this block. Delete this and let `CustomerMarket` supply `event` the next\n * time the types are regenerated against a spec that has it.\n */\nexport interface MarketEvent {\n seriesTicker: string | null;\n ticker: string;\n title: string | null;\n}\n\nexport type Market = CamelizeKeys<Raw[\"CustomerMarket\"]> & { event: MarketEvent };\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 type RiskMode = \"adaptive\" | \"committed\";\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 * Ask for a committed deleverage plan (a fixed ladder of trigger prices, backed by a refundable\n * margin deposit) instead of the adaptive risk engine. Defaults to `adaptive`.\n *\n * A committed request is answered in committed mode or rejected with\n * `quote_committed_risk_mode_unavailable` — you never get an adaptive quote back from it. Take a\n * draft first and read `committedUnwinds.available` to know whether the mode is on offer.\n */\n riskMode?: RiskMode;\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"]}
|