pmxt-core 2.23.0 → 2.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/exchanges/kalshi/api.d.ts +1 -1
- package/dist/exchanges/kalshi/api.js +1 -1
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +1 -1
- package/dist/exchanges/opinion/api.d.ts +1 -1
- package/dist/exchanges/opinion/api.js +1 -1
- package/dist/exchanges/polymarket/api-clob.d.ts +1 -1
- package/dist/exchanges/polymarket/api-clob.js +1 -1
- package/dist/exchanges/polymarket/api-data.d.ts +1 -1
- package/dist/exchanges/polymarket/api-data.js +1 -1
- package/dist/exchanges/polymarket/api-gamma.d.ts +1 -1
- package/dist/exchanges/polymarket/api-gamma.js +1 -1
- package/dist/exchanges/polymarket/auth.js +42 -8
- package/dist/exchanges/polymarket/index.js +56 -19
- package/dist/exchanges/polymarket_us/config.d.ts +18 -0
- package/dist/exchanges/polymarket_us/config.js +22 -0
- package/dist/exchanges/polymarket_us/errors.d.ts +19 -0
- package/dist/exchanges/polymarket_us/errors.js +123 -0
- package/dist/exchanges/polymarket_us/errors.test.d.ts +1 -0
- package/dist/exchanges/polymarket_us/errors.test.js +54 -0
- package/dist/exchanges/polymarket_us/index.d.ts +90 -0
- package/dist/exchanges/polymarket_us/index.js +366 -0
- package/dist/exchanges/polymarket_us/index.test.d.ts +8 -0
- package/dist/exchanges/polymarket_us/index.test.js +237 -0
- package/dist/exchanges/polymarket_us/normalizer.d.ts +55 -0
- package/dist/exchanges/polymarket_us/normalizer.js +385 -0
- package/dist/exchanges/polymarket_us/normalizer.test.d.ts +1 -0
- package/dist/exchanges/polymarket_us/normalizer.test.js +224 -0
- package/dist/exchanges/polymarket_us/price.d.ts +94 -0
- package/dist/exchanges/polymarket_us/price.js +149 -0
- package/dist/exchanges/polymarket_us/price.test.d.ts +1 -0
- package/dist/exchanges/polymarket_us/price.test.js +131 -0
- package/dist/exchanges/polymarket_us/websocket.d.ts +39 -0
- package/dist/exchanges/polymarket_us/websocket.js +181 -0
- package/dist/exchanges/polymarket_us/websocket.test.d.ts +8 -0
- package/dist/exchanges/polymarket_us/websocket.test.js +162 -0
- package/dist/exchanges/probable/api.d.ts +1 -1
- package/dist/exchanges/probable/api.js +1 -1
- package/dist/exchanges/smarkets/api.d.ts +8067 -0
- package/dist/exchanges/smarkets/api.js +10698 -0
- package/dist/exchanges/smarkets/auth.d.ts +56 -0
- package/dist/exchanges/smarkets/auth.js +105 -0
- package/dist/exchanges/smarkets/config.d.ts +41 -0
- package/dist/exchanges/smarkets/config.js +47 -0
- package/dist/exchanges/smarkets/errors.d.ts +31 -0
- package/dist/exchanges/smarkets/errors.js +186 -0
- package/dist/exchanges/smarkets/fetcher.d.ts +177 -0
- package/dist/exchanges/smarkets/fetcher.js +342 -0
- package/dist/exchanges/smarkets/index.d.ts +54 -0
- package/dist/exchanges/smarkets/index.js +285 -0
- package/dist/exchanges/smarkets/normalizer.d.ts +18 -0
- package/dist/exchanges/smarkets/normalizer.js +267 -0
- package/dist/exchanges/smarkets/price.d.ts +26 -0
- package/dist/exchanges/smarkets/price.js +44 -0
- package/dist/exchanges/smarkets/price.test.d.ts +1 -0
- package/dist/exchanges/smarkets/price.test.js +50 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +9 -1
- package/dist/server/app.js +18 -2
- package/package.json +4 -3
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ExchangeCredentials } from '../../BaseExchange';
|
|
2
|
+
/**
|
|
3
|
+
* Manages Smarkets session-based authentication.
|
|
4
|
+
*
|
|
5
|
+
* Authentication flow:
|
|
6
|
+
* 1. POST /v3/sessions/ with username (email) and password to obtain a session token.
|
|
7
|
+
* 2. If the response `factor` is 'totp', POST /v3/sessions/verify/ with the TOTP code.
|
|
8
|
+
* 3. Once complete, use the token in the Authorization header as `Session-Token <token>`.
|
|
9
|
+
*
|
|
10
|
+
* This class does NOT make HTTP calls directly. The exchange index.ts handles the
|
|
11
|
+
* async login flow via callApi and calls `setToken()` with the result.
|
|
12
|
+
* `getHeaders()` returns the session token header synchronously.
|
|
13
|
+
*/
|
|
14
|
+
export declare class SmarketsAuth {
|
|
15
|
+
private readonly credentials;
|
|
16
|
+
private sessionToken;
|
|
17
|
+
private tokenExpiry;
|
|
18
|
+
constructor(credentials: ExchangeCredentials);
|
|
19
|
+
private validateCredentials;
|
|
20
|
+
/**
|
|
21
|
+
* Returns the username (email) used for session creation.
|
|
22
|
+
*/
|
|
23
|
+
getUsername(): string;
|
|
24
|
+
/**
|
|
25
|
+
* Returns the password used for session creation.
|
|
26
|
+
*/
|
|
27
|
+
getPassword(): string;
|
|
28
|
+
/**
|
|
29
|
+
* Stores the session token and its expiry after a successful login.
|
|
30
|
+
*
|
|
31
|
+
* @param token The session token returned by /v3/sessions/.
|
|
32
|
+
* @param expiry The `stop` datetime string from the API response (ISO 8601).
|
|
33
|
+
*/
|
|
34
|
+
setToken(token: string, expiry: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* Returns true if the session token is present and has not expired.
|
|
37
|
+
*/
|
|
38
|
+
isAuthenticated(): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Returns true if the token has expired or is about to expire.
|
|
41
|
+
*/
|
|
42
|
+
isExpired(): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Generates the required headers for an authenticated request.
|
|
45
|
+
*
|
|
46
|
+
* @param _method The HTTP method (unused, kept for interface consistency with sign()).
|
|
47
|
+
* @param _path The request path (unused, kept for interface consistency with sign()).
|
|
48
|
+
* @returns An object containing the Authorization header with the session token.
|
|
49
|
+
* @throws Error if no valid session token is available.
|
|
50
|
+
*/
|
|
51
|
+
getHeaders(_method: string, _path: string): Record<string, string>;
|
|
52
|
+
/**
|
|
53
|
+
* Clears the stored session token (e.g. after logout or for testing).
|
|
54
|
+
*/
|
|
55
|
+
reset(): void;
|
|
56
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SmarketsAuth = void 0;
|
|
4
|
+
/** Default session TTL in milliseconds (30 minutes). */
|
|
5
|
+
const SESSION_TTL_MS = 30 * 60 * 1000;
|
|
6
|
+
/** Safety margin subtracted from TTL to avoid using an about-to-expire token. */
|
|
7
|
+
const EXPIRY_MARGIN_MS = 60 * 1000;
|
|
8
|
+
/**
|
|
9
|
+
* Manages Smarkets session-based authentication.
|
|
10
|
+
*
|
|
11
|
+
* Authentication flow:
|
|
12
|
+
* 1. POST /v3/sessions/ with username (email) and password to obtain a session token.
|
|
13
|
+
* 2. If the response `factor` is 'totp', POST /v3/sessions/verify/ with the TOTP code.
|
|
14
|
+
* 3. Once complete, use the token in the Authorization header as `Session-Token <token>`.
|
|
15
|
+
*
|
|
16
|
+
* This class does NOT make HTTP calls directly. The exchange index.ts handles the
|
|
17
|
+
* async login flow via callApi and calls `setToken()` with the result.
|
|
18
|
+
* `getHeaders()` returns the session token header synchronously.
|
|
19
|
+
*/
|
|
20
|
+
class SmarketsAuth {
|
|
21
|
+
credentials;
|
|
22
|
+
sessionToken = null;
|
|
23
|
+
tokenExpiry = 0;
|
|
24
|
+
constructor(credentials) {
|
|
25
|
+
this.credentials = credentials;
|
|
26
|
+
this.validateCredentials();
|
|
27
|
+
}
|
|
28
|
+
validateCredentials() {
|
|
29
|
+
if (!this.credentials.apiKey) {
|
|
30
|
+
throw new Error('Smarkets requires an apiKey (email address) for authentication');
|
|
31
|
+
}
|
|
32
|
+
if (!this.credentials.privateKey) {
|
|
33
|
+
throw new Error('Smarkets requires a privateKey (account password) for authentication');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Returns the username (email) used for session creation.
|
|
38
|
+
*/
|
|
39
|
+
getUsername() {
|
|
40
|
+
return this.credentials.apiKey;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Returns the password used for session creation.
|
|
44
|
+
*/
|
|
45
|
+
getPassword() {
|
|
46
|
+
return this.credentials.privateKey;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Stores the session token and its expiry after a successful login.
|
|
50
|
+
*
|
|
51
|
+
* @param token The session token returned by /v3/sessions/.
|
|
52
|
+
* @param expiry The `stop` datetime string from the API response (ISO 8601).
|
|
53
|
+
*/
|
|
54
|
+
setToken(token, expiry) {
|
|
55
|
+
this.sessionToken = token;
|
|
56
|
+
const expiryTime = new Date(expiry).getTime();
|
|
57
|
+
if (isNaN(expiryTime)) {
|
|
58
|
+
// Fall back to a 30-minute TTL from now if the expiry cannot be parsed.
|
|
59
|
+
this.tokenExpiry = Date.now() + SESSION_TTL_MS - EXPIRY_MARGIN_MS;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
this.tokenExpiry = expiryTime - EXPIRY_MARGIN_MS;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Returns true if the session token is present and has not expired.
|
|
67
|
+
*/
|
|
68
|
+
isAuthenticated() {
|
|
69
|
+
return this.sessionToken !== null && Date.now() < this.tokenExpiry;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Returns true if the token has expired or is about to expire.
|
|
73
|
+
*/
|
|
74
|
+
isExpired() {
|
|
75
|
+
if (this.sessionToken === null) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
return Date.now() >= this.tokenExpiry;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Generates the required headers for an authenticated request.
|
|
82
|
+
*
|
|
83
|
+
* @param _method The HTTP method (unused, kept for interface consistency with sign()).
|
|
84
|
+
* @param _path The request path (unused, kept for interface consistency with sign()).
|
|
85
|
+
* @returns An object containing the Authorization header with the session token.
|
|
86
|
+
* @throws Error if no valid session token is available.
|
|
87
|
+
*/
|
|
88
|
+
getHeaders(_method, _path) {
|
|
89
|
+
if (!this.sessionToken) {
|
|
90
|
+
throw new Error('Smarkets session token is not set. Call the login endpoint first.');
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
'Authorization': `Session-Token ${this.sessionToken}`,
|
|
94
|
+
'Content-Type': 'application/json',
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Clears the stored session token (e.g. after logout or for testing).
|
|
99
|
+
*/
|
|
100
|
+
reset() {
|
|
101
|
+
this.sessionToken = null;
|
|
102
|
+
this.tokenExpiry = 0;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
exports.SmarketsAuth = SmarketsAuth;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smarkets runtime configuration.
|
|
3
|
+
*
|
|
4
|
+
* This file is hand-authored and is the single source of truth for:
|
|
5
|
+
* - Base URL constant
|
|
6
|
+
* - API path constants (SMARKETS_PATHS)
|
|
7
|
+
* - Config interface and factory
|
|
8
|
+
*
|
|
9
|
+
* The OpenAPI spec lives in core/specs/smarkets/Smarkets.yaml and is compiled
|
|
10
|
+
* into core/src/exchanges/smarkets/api.ts by `npm run fetch:openapi`.
|
|
11
|
+
* Do NOT put runtime config into api.ts -- it will be overwritten.
|
|
12
|
+
*/
|
|
13
|
+
export declare const SMARKETS_BASE_URL = "https://api.smarkets.com";
|
|
14
|
+
export declare const SMARKETS_PATHS: {
|
|
15
|
+
SESSIONS: string;
|
|
16
|
+
SESSIONS_VERIFY: string;
|
|
17
|
+
ACCOUNTS: string;
|
|
18
|
+
ACCOUNTS_ACTIVITY: string;
|
|
19
|
+
ACCOUNT_ACTIVITY_CSV: string;
|
|
20
|
+
CURRENCIES: string;
|
|
21
|
+
EVENTS: string;
|
|
22
|
+
EVENTS_COMPETITORS: string;
|
|
23
|
+
EVENTS_MARKETS: string;
|
|
24
|
+
EVENTS_MARKETS_COUNT: string;
|
|
25
|
+
EVENTS_STATES: string;
|
|
26
|
+
MARKETS_CONTRACTS: string;
|
|
27
|
+
MARKETS_LAST_EXECUTED_PRICES: string;
|
|
28
|
+
MARKETS_QUOTES: string;
|
|
29
|
+
MARKETS_VOLUMES: string;
|
|
30
|
+
ORDERS: string;
|
|
31
|
+
ORDERS_FULLCOVER: string;
|
|
32
|
+
ORDERS_BY_ID: string;
|
|
33
|
+
};
|
|
34
|
+
export interface SmarketsApiConfig {
|
|
35
|
+
/** Base REST API URL */
|
|
36
|
+
apiUrl: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Return a typed config object for the Smarkets API.
|
|
40
|
+
*/
|
|
41
|
+
export declare function getSmarketsConfig(): SmarketsApiConfig;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Smarkets runtime configuration.
|
|
4
|
+
*
|
|
5
|
+
* This file is hand-authored and is the single source of truth for:
|
|
6
|
+
* - Base URL constant
|
|
7
|
+
* - API path constants (SMARKETS_PATHS)
|
|
8
|
+
* - Config interface and factory
|
|
9
|
+
*
|
|
10
|
+
* The OpenAPI spec lives in core/specs/smarkets/Smarkets.yaml and is compiled
|
|
11
|
+
* into core/src/exchanges/smarkets/api.ts by `npm run fetch:openapi`.
|
|
12
|
+
* Do NOT put runtime config into api.ts -- it will be overwritten.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.SMARKETS_PATHS = exports.SMARKETS_BASE_URL = void 0;
|
|
16
|
+
exports.getSmarketsConfig = getSmarketsConfig;
|
|
17
|
+
// -- Base URL constant --------------------------------------------------------
|
|
18
|
+
exports.SMARKETS_BASE_URL = "https://api.smarkets.com";
|
|
19
|
+
// -- Path constants -----------------------------------------------------------
|
|
20
|
+
exports.SMARKETS_PATHS = {
|
|
21
|
+
SESSIONS: "/v3/sessions/",
|
|
22
|
+
SESSIONS_VERIFY: "/v3/sessions/verify/",
|
|
23
|
+
ACCOUNTS: "/v3/accounts/",
|
|
24
|
+
ACCOUNTS_ACTIVITY: "/v3/accounts/activity/",
|
|
25
|
+
ACCOUNT_ACTIVITY_CSV: "/v3/account_activity_csv/{start_datetime}/{end_datetime}/",
|
|
26
|
+
CURRENCIES: "/v3/currencies/{code}/",
|
|
27
|
+
EVENTS: "/v3/events/",
|
|
28
|
+
EVENTS_COMPETITORS: "/v3/events/{event_ids}/competitors/",
|
|
29
|
+
EVENTS_MARKETS: "/v3/events/{event_ids}/markets/",
|
|
30
|
+
EVENTS_MARKETS_COUNT: "/v3/events/{event_ids}/markets_count/",
|
|
31
|
+
EVENTS_STATES: "/v3/events/{event_ids}/states/",
|
|
32
|
+
MARKETS_CONTRACTS: "/v3/markets/{market_ids}/contracts/",
|
|
33
|
+
MARKETS_LAST_EXECUTED_PRICES: "/v3/markets/{market_ids}/last_executed_prices/",
|
|
34
|
+
MARKETS_QUOTES: "/v3/markets/{market_ids}/quotes/",
|
|
35
|
+
MARKETS_VOLUMES: "/v3/markets/{market_ids}/volumes/",
|
|
36
|
+
ORDERS: "/v3/orders/",
|
|
37
|
+
ORDERS_FULLCOVER: "/v3/orders/fullcover/",
|
|
38
|
+
ORDERS_BY_ID: "/v3/orders/{order_id}/",
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Return a typed config object for the Smarkets API.
|
|
42
|
+
*/
|
|
43
|
+
function getSmarketsConfig() {
|
|
44
|
+
return {
|
|
45
|
+
apiUrl: exports.SMARKETS_BASE_URL,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ErrorMapper } from '../../utils/error-mapper';
|
|
2
|
+
import { BadRequest } from '../../errors';
|
|
3
|
+
/**
|
|
4
|
+
* Smarkets-specific error mapper
|
|
5
|
+
*
|
|
6
|
+
* Handles Smarkets API error patterns where errors use an error_type
|
|
7
|
+
* field to identify the error category.
|
|
8
|
+
*/
|
|
9
|
+
export declare class SmarketsErrorMapper extends ErrorMapper {
|
|
10
|
+
constructor();
|
|
11
|
+
/**
|
|
12
|
+
* Override to handle the Smarkets { error_type, data } format
|
|
13
|
+
*/
|
|
14
|
+
protected extractErrorMessage(error: any): string;
|
|
15
|
+
/**
|
|
16
|
+
* Override to map Smarkets error_type values before falling back
|
|
17
|
+
* to the default status-code-based mapping
|
|
18
|
+
*/
|
|
19
|
+
mapError(error: any): ReturnType<ErrorMapper['mapError']>;
|
|
20
|
+
/**
|
|
21
|
+
* Override to detect order-specific errors within 400 responses
|
|
22
|
+
*/
|
|
23
|
+
protected mapBadRequestError(message: string, data: any): BadRequest;
|
|
24
|
+
/**
|
|
25
|
+
* Maps a Smarkets error_type string to a PMXT error class.
|
|
26
|
+
* Returns undefined if the error_type is not recognized, allowing
|
|
27
|
+
* the base class to handle it via HTTP status code.
|
|
28
|
+
*/
|
|
29
|
+
private mapByErrorType;
|
|
30
|
+
}
|
|
31
|
+
export declare const smarketsErrorMapper: SmarketsErrorMapper;
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.smarketsErrorMapper = exports.SmarketsErrorMapper = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const error_mapper_1 = require("../../utils/error-mapper");
|
|
9
|
+
const errors_1 = require("../../errors");
|
|
10
|
+
/**
|
|
11
|
+
* Maps Smarkets error_type values to PMXT error classes.
|
|
12
|
+
*
|
|
13
|
+
* Smarkets errors follow the format:
|
|
14
|
+
* { "error_type": "ERROR_CODE", "data": "message or object" }
|
|
15
|
+
*/
|
|
16
|
+
const AUTHENTICATION_ERRORS = new Set([
|
|
17
|
+
'INVALID_CREDENTIALS',
|
|
18
|
+
'PASSWORD_RESET_NEEDED',
|
|
19
|
+
'AUTH_REQUIRED',
|
|
20
|
+
]);
|
|
21
|
+
const RATE_LIMIT_ERRORS = new Set([
|
|
22
|
+
'RATE_LIMIT_EXCEEDED',
|
|
23
|
+
'EVENTS_API_RATE_LIMIT',
|
|
24
|
+
]);
|
|
25
|
+
const PERMISSION_DENIED_ERRORS = new Set([
|
|
26
|
+
'USER_EXCLUDED',
|
|
27
|
+
'USER_SUSPENDED',
|
|
28
|
+
'SOURCE_BLOCKED',
|
|
29
|
+
'IP_NOT_TRUSTED',
|
|
30
|
+
'CLIENT_JURISDICTION_MISMATCH',
|
|
31
|
+
'COUNTRY_BLOCKED',
|
|
32
|
+
'FORBIDDEN',
|
|
33
|
+
'ACCOUNT_UNVERIFIED',
|
|
34
|
+
]);
|
|
35
|
+
const INSUFFICIENT_FUNDS_ERRORS = new Set([
|
|
36
|
+
'ORDER_REJECTED_INSUFFICIENT_FUNDS',
|
|
37
|
+
]);
|
|
38
|
+
const INVALID_ORDER_ERRORS = new Set([
|
|
39
|
+
'ORDER_INVALID_INVALID_PRICE',
|
|
40
|
+
'ORDER_INVALID_INVALID_QUANTITY',
|
|
41
|
+
'ORDER_REJECTED_CROSSED_SELF',
|
|
42
|
+
'ORDER_REJECTED_LIMIT_EXCEEDED',
|
|
43
|
+
'ORDER_REJECTED_STAKE_LIMIT_EXCEEDED',
|
|
44
|
+
'ORDER_REJECTED_CAPACITY_REACHED',
|
|
45
|
+
'ORDER_REJECTED_CONTRACT_SETTLED',
|
|
46
|
+
'ORDER_REJECTED_MARKET_SETTLED',
|
|
47
|
+
'ORDER_REJECTED_MARKET_NOT_OPEN',
|
|
48
|
+
'ORDER_REJECTED_MARKET_HALTED',
|
|
49
|
+
'ORDER_CANCELLED_MARKET_HALTED',
|
|
50
|
+
'ORDER_REJECTED_TRADING_SUSPENDED',
|
|
51
|
+
'ORDER_CANCELLED_TRADING_SUSPENDED',
|
|
52
|
+
'ORDER_REJECTED_ACCOUNT_SUSPENDED',
|
|
53
|
+
'ORDER_REJECTED_THROTTLE_EXCEEDED',
|
|
54
|
+
]);
|
|
55
|
+
const MARKET_NOT_FOUND_ERRORS = new Set([
|
|
56
|
+
'ORDER_REJECTED_MARKET_NOT_FOUND',
|
|
57
|
+
'ORDER_REJECTED_CONTRACT_NOT_FOUND',
|
|
58
|
+
]);
|
|
59
|
+
const ORDER_NOT_FOUND_ERRORS = new Set([
|
|
60
|
+
'ORDER_CANCEL_REJECTED_NOT_FOUND',
|
|
61
|
+
]);
|
|
62
|
+
const UNAVAILABLE_ERRORS = new Set([
|
|
63
|
+
'INTERNAL_ERROR',
|
|
64
|
+
'FOREX_SERVICE_INTERNAL_ERROR',
|
|
65
|
+
'KYC_SERVICE_INTERNAL_ERROR',
|
|
66
|
+
'MDS_SERVICE_UNAVAILABLE',
|
|
67
|
+
'RECKONATOR_UNAVAILABLE',
|
|
68
|
+
'AUTH_UNAVAILABLE',
|
|
69
|
+
'ZEUS_CONNECTION_ERROR',
|
|
70
|
+
'ZEUS_TIMEOUT',
|
|
71
|
+
'ORDER_REJECTED_SERVICE_TEMPORARILY_UNAVAILABLE',
|
|
72
|
+
]);
|
|
73
|
+
/**
|
|
74
|
+
* Smarkets-specific error mapper
|
|
75
|
+
*
|
|
76
|
+
* Handles Smarkets API error patterns where errors use an error_type
|
|
77
|
+
* field to identify the error category.
|
|
78
|
+
*/
|
|
79
|
+
class SmarketsErrorMapper extends error_mapper_1.ErrorMapper {
|
|
80
|
+
constructor() {
|
|
81
|
+
super('Smarkets');
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Override to handle the Smarkets { error_type, data } format
|
|
85
|
+
*/
|
|
86
|
+
extractErrorMessage(error) {
|
|
87
|
+
if (axios_1.default.isAxiosError(error) && error.response?.data) {
|
|
88
|
+
const body = error.response.data;
|
|
89
|
+
const errorType = body.error_type;
|
|
90
|
+
const data = body.data;
|
|
91
|
+
if (errorType) {
|
|
92
|
+
const status = error.response.status;
|
|
93
|
+
const detail = typeof data === 'string'
|
|
94
|
+
? data
|
|
95
|
+
: data != null
|
|
96
|
+
? JSON.stringify(data)
|
|
97
|
+
: '';
|
|
98
|
+
return detail
|
|
99
|
+
? `[${status}] ${errorType}: ${detail}`
|
|
100
|
+
: `[${status}] ${errorType}`;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return super.extractErrorMessage(error);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Override to map Smarkets error_type values before falling back
|
|
107
|
+
* to the default status-code-based mapping
|
|
108
|
+
*/
|
|
109
|
+
mapError(error) {
|
|
110
|
+
if (axios_1.default.isAxiosError(error) && error.response?.data) {
|
|
111
|
+
const errorType = error.response.data.error_type;
|
|
112
|
+
if (errorType) {
|
|
113
|
+
const message = this.extractErrorMessage(error);
|
|
114
|
+
const mapped = this.mapByErrorType(errorType, message, error.response);
|
|
115
|
+
if (mapped) {
|
|
116
|
+
return mapped;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return super.mapError(error);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Override to detect order-specific errors within 400 responses
|
|
124
|
+
*/
|
|
125
|
+
mapBadRequestError(message, data) {
|
|
126
|
+
const errorType = data?.error_type;
|
|
127
|
+
if (errorType) {
|
|
128
|
+
if (INSUFFICIENT_FUNDS_ERRORS.has(errorType)) {
|
|
129
|
+
return new errors_1.InsufficientFunds(message, this.exchangeName);
|
|
130
|
+
}
|
|
131
|
+
if (INVALID_ORDER_ERRORS.has(errorType)) {
|
|
132
|
+
return new errors_1.InvalidOrder(message, this.exchangeName);
|
|
133
|
+
}
|
|
134
|
+
if (MARKET_NOT_FOUND_ERRORS.has(errorType)) {
|
|
135
|
+
return new errors_1.MarketNotFound(errorType, this.exchangeName);
|
|
136
|
+
}
|
|
137
|
+
if (ORDER_NOT_FOUND_ERRORS.has(errorType)) {
|
|
138
|
+
return new errors_1.OrderNotFound(errorType, this.exchangeName);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return super.mapBadRequestError(message, data);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Maps a Smarkets error_type string to a PMXT error class.
|
|
145
|
+
* Returns undefined if the error_type is not recognized, allowing
|
|
146
|
+
* the base class to handle it via HTTP status code.
|
|
147
|
+
*/
|
|
148
|
+
mapByErrorType(errorType, message, response) {
|
|
149
|
+
if (AUTHENTICATION_ERRORS.has(errorType)) {
|
|
150
|
+
return new errors_1.AuthenticationError(message, this.exchangeName);
|
|
151
|
+
}
|
|
152
|
+
if (RATE_LIMIT_ERRORS.has(errorType)) {
|
|
153
|
+
const retryAfter = response?.headers?.['retry-after'];
|
|
154
|
+
const retryAfterSeconds = retryAfter
|
|
155
|
+
? parseInt(retryAfter, 10)
|
|
156
|
+
: undefined;
|
|
157
|
+
return new errors_1.RateLimitExceeded(message, retryAfterSeconds, this.exchangeName);
|
|
158
|
+
}
|
|
159
|
+
if (PERMISSION_DENIED_ERRORS.has(errorType)) {
|
|
160
|
+
return new errors_1.PermissionDenied(message, this.exchangeName);
|
|
161
|
+
}
|
|
162
|
+
if (INSUFFICIENT_FUNDS_ERRORS.has(errorType)) {
|
|
163
|
+
return new errors_1.InsufficientFunds(message, this.exchangeName);
|
|
164
|
+
}
|
|
165
|
+
if (INVALID_ORDER_ERRORS.has(errorType)) {
|
|
166
|
+
return new errors_1.InvalidOrder(message, this.exchangeName);
|
|
167
|
+
}
|
|
168
|
+
if (MARKET_NOT_FOUND_ERRORS.has(errorType)) {
|
|
169
|
+
return new errors_1.MarketNotFound(errorType, this.exchangeName);
|
|
170
|
+
}
|
|
171
|
+
if (ORDER_NOT_FOUND_ERRORS.has(errorType)) {
|
|
172
|
+
return new errors_1.OrderNotFound(errorType, this.exchangeName);
|
|
173
|
+
}
|
|
174
|
+
if (UNAVAILABLE_ERRORS.has(errorType)) {
|
|
175
|
+
return new errors_1.ExchangeNotAvailable(message, this.exchangeName);
|
|
176
|
+
}
|
|
177
|
+
// Catch-all for any *_UNAVAILABLE or *_TIMEOUT patterns not in the set
|
|
178
|
+
if (errorType.endsWith('_UNAVAILABLE') || errorType.endsWith('_TIMEOUT')) {
|
|
179
|
+
return new errors_1.ExchangeNotAvailable(message, this.exchangeName);
|
|
180
|
+
}
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
exports.SmarketsErrorMapper = SmarketsErrorMapper;
|
|
185
|
+
// Export singleton instance for convenience
|
|
186
|
+
exports.smarketsErrorMapper = new SmarketsErrorMapper();
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { MarketFilterParams, EventFetchParams, TradesParams } from '../../BaseExchange';
|
|
2
|
+
import { IExchangeFetcher, FetcherContext } from '../interfaces';
|
|
3
|
+
export interface SmarketsRawEvent {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
description: string | null;
|
|
7
|
+
slug: string;
|
|
8
|
+
full_slug: string;
|
|
9
|
+
state: string;
|
|
10
|
+
type: string | {
|
|
11
|
+
domain: string;
|
|
12
|
+
scope: string;
|
|
13
|
+
};
|
|
14
|
+
parent_id: string | null;
|
|
15
|
+
start_datetime: string | null;
|
|
16
|
+
start_date: string | null;
|
|
17
|
+
end_date: string | null;
|
|
18
|
+
created: string;
|
|
19
|
+
modified: string;
|
|
20
|
+
bettable?: boolean;
|
|
21
|
+
hidden?: boolean;
|
|
22
|
+
inplay_enabled?: boolean;
|
|
23
|
+
short_name?: string | null;
|
|
24
|
+
seo_description?: string | null;
|
|
25
|
+
special_rules?: string | null;
|
|
26
|
+
chart_time_period?: string | null;
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
}
|
|
29
|
+
export interface SmarketsRawMarket {
|
|
30
|
+
id: string;
|
|
31
|
+
event_id: string;
|
|
32
|
+
name: string;
|
|
33
|
+
slug: string;
|
|
34
|
+
state: string;
|
|
35
|
+
description: string | null;
|
|
36
|
+
bet_delay: number;
|
|
37
|
+
complete: boolean;
|
|
38
|
+
winner_count: number;
|
|
39
|
+
hidden: boolean;
|
|
40
|
+
display_type: string;
|
|
41
|
+
display_order: number | null;
|
|
42
|
+
cashout_enabled: boolean;
|
|
43
|
+
inplay_enabled?: boolean;
|
|
44
|
+
created: string;
|
|
45
|
+
modified: string;
|
|
46
|
+
market_type: {
|
|
47
|
+
name: string;
|
|
48
|
+
param?: string;
|
|
49
|
+
params?: Record<string, string>;
|
|
50
|
+
} | null;
|
|
51
|
+
category?: string;
|
|
52
|
+
categories?: string[];
|
|
53
|
+
info?: Record<string, unknown> | null;
|
|
54
|
+
[key: string]: unknown;
|
|
55
|
+
}
|
|
56
|
+
export interface SmarketsRawContract {
|
|
57
|
+
id: string;
|
|
58
|
+
market_id: string;
|
|
59
|
+
name: string;
|
|
60
|
+
slug: string;
|
|
61
|
+
state_or_outcome: string;
|
|
62
|
+
created: string;
|
|
63
|
+
modified: string;
|
|
64
|
+
outcome_timestamp: string | null;
|
|
65
|
+
display_order: number | null;
|
|
66
|
+
hidden?: boolean;
|
|
67
|
+
competitor_id?: number | null;
|
|
68
|
+
contract_type?: {
|
|
69
|
+
name: string;
|
|
70
|
+
param?: string;
|
|
71
|
+
} | null;
|
|
72
|
+
reduction_factor?: string;
|
|
73
|
+
info?: {
|
|
74
|
+
color_primary?: string;
|
|
75
|
+
color_secondary?: string;
|
|
76
|
+
primary?: boolean;
|
|
77
|
+
} | null;
|
|
78
|
+
[key: string]: unknown;
|
|
79
|
+
}
|
|
80
|
+
export interface SmarketsRawQuote {
|
|
81
|
+
bids: Array<{
|
|
82
|
+
price: number;
|
|
83
|
+
quantity: number;
|
|
84
|
+
}>;
|
|
85
|
+
offers: Array<{
|
|
86
|
+
price: number;
|
|
87
|
+
quantity: number;
|
|
88
|
+
}>;
|
|
89
|
+
}
|
|
90
|
+
export interface SmarketsRawOrder {
|
|
91
|
+
id: string;
|
|
92
|
+
market_id: string;
|
|
93
|
+
contract_id: string;
|
|
94
|
+
side: string;
|
|
95
|
+
state: string;
|
|
96
|
+
type: string;
|
|
97
|
+
price: number;
|
|
98
|
+
quantity: number;
|
|
99
|
+
quantity_filled: number;
|
|
100
|
+
quantity_unfilled: number;
|
|
101
|
+
created_datetime: string;
|
|
102
|
+
last_modified_datetime: string;
|
|
103
|
+
average_price_matched?: number;
|
|
104
|
+
label?: string | null;
|
|
105
|
+
[key: string]: unknown;
|
|
106
|
+
}
|
|
107
|
+
export interface SmarketsRawVolume {
|
|
108
|
+
market_id: string;
|
|
109
|
+
volume: number;
|
|
110
|
+
double_stake_volume: number;
|
|
111
|
+
}
|
|
112
|
+
export interface SmarketsRawLastExecutedPrice {
|
|
113
|
+
contract_id: string;
|
|
114
|
+
last_executed_price: string | null;
|
|
115
|
+
timestamp: string | null;
|
|
116
|
+
}
|
|
117
|
+
export interface SmarketsRawBalance {
|
|
118
|
+
account_id: string;
|
|
119
|
+
balance: string;
|
|
120
|
+
available_balance: string;
|
|
121
|
+
exposure: string;
|
|
122
|
+
currency: string;
|
|
123
|
+
bonus_balance?: string;
|
|
124
|
+
commission_type?: string;
|
|
125
|
+
signup_date?: string;
|
|
126
|
+
}
|
|
127
|
+
export interface SmarketsRawActivityRow {
|
|
128
|
+
amount: string | null;
|
|
129
|
+
commission: string | null;
|
|
130
|
+
contract_id: string | null;
|
|
131
|
+
event_id: string | null;
|
|
132
|
+
market_id: string | null;
|
|
133
|
+
order_id: string | null;
|
|
134
|
+
price: number | null;
|
|
135
|
+
quantity: number | null;
|
|
136
|
+
quantity_change: number | null;
|
|
137
|
+
side: string | null;
|
|
138
|
+
source: string;
|
|
139
|
+
timestamp: string;
|
|
140
|
+
seq: number;
|
|
141
|
+
subseq: number;
|
|
142
|
+
money: string | null;
|
|
143
|
+
money_change: string | null;
|
|
144
|
+
exposure: string | null;
|
|
145
|
+
label: string | null;
|
|
146
|
+
[key: string]: unknown;
|
|
147
|
+
}
|
|
148
|
+
export interface SmarketsRawEventWithMarkets {
|
|
149
|
+
event: SmarketsRawEvent;
|
|
150
|
+
markets: SmarketsRawMarket[];
|
|
151
|
+
contracts: SmarketsRawContract[];
|
|
152
|
+
volumes: SmarketsRawVolume[];
|
|
153
|
+
}
|
|
154
|
+
export declare class SmarketsFetcher implements IExchangeFetcher<SmarketsRawEventWithMarkets, SmarketsRawEventWithMarkets> {
|
|
155
|
+
private readonly ctx;
|
|
156
|
+
constructor(ctx: FetcherContext);
|
|
157
|
+
fetchRawMarkets(params?: MarketFilterParams): Promise<SmarketsRawEventWithMarkets[]>;
|
|
158
|
+
fetchRawEvents(params: EventFetchParams): Promise<SmarketsRawEventWithMarkets[]>;
|
|
159
|
+
fetchRawOrderBook(id: string): Promise<Record<string, SmarketsRawQuote>>;
|
|
160
|
+
fetchRawTradeActivity(marketId: string, _params: TradesParams): Promise<SmarketsRawActivityRow[]>;
|
|
161
|
+
fetchRawMyTradeActivity(params?: Record<string, any>): Promise<SmarketsRawActivityRow[]>;
|
|
162
|
+
fetchRawBalance(): Promise<SmarketsRawBalance>;
|
|
163
|
+
fetchRawOrders(queryParams?: Record<string, any>): Promise<SmarketsRawOrder[]>;
|
|
164
|
+
fetchRawOrderById(orderId: string): Promise<SmarketsRawOrder>;
|
|
165
|
+
fetchRawPositions(): Promise<SmarketsRawOrder[]>;
|
|
166
|
+
fetchRawClosedOrders(params?: Record<string, any>): Promise<SmarketsRawOrder[]>;
|
|
167
|
+
private fetchEnrichedEventById;
|
|
168
|
+
private fetchEnrichedEventByMarketId;
|
|
169
|
+
private fetchAllEnrichedEvents;
|
|
170
|
+
private enrichEvents;
|
|
171
|
+
private fetchPaginatedEvents;
|
|
172
|
+
private fetchMarketsByEventIds;
|
|
173
|
+
private fetchContractsByMarketIds;
|
|
174
|
+
private fetchVolumesByMarketIds;
|
|
175
|
+
private mapEventStatus;
|
|
176
|
+
private batchArray;
|
|
177
|
+
}
|