pmxtjs 2.49.11 → 2.50.2
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/esm/generated/src/apis/DefaultApi.d.ts +28 -0
- package/dist/esm/generated/src/apis/DefaultApi.js +28 -0
- package/dist/esm/index.d.ts +4 -3
- package/dist/esm/index.js +4 -3
- package/dist/esm/pmxt/client.d.ts +37 -25
- package/dist/esm/pmxt/client.js +117 -202
- package/dist/esm/pmxt/constants.d.ts +4 -0
- package/dist/esm/pmxt/constants.js +6 -0
- package/dist/esm/pmxt/hosted-routing.js +1 -0
- package/dist/esm/pmxt/hosted-typed-data.d.ts +1 -1
- package/dist/esm/pmxt/hosted-typed-data.js +30 -1
- package/dist/esm/pmxt/models.d.ts +1 -0
- package/dist/esm/pmxt/router.js +12 -3
- package/dist/generated/src/apis/DefaultApi.d.ts +28 -0
- package/dist/generated/src/apis/DefaultApi.js +28 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.js +6 -1
- package/dist/pmxt/client.d.ts +37 -25
- package/dist/pmxt/client.js +116 -200
- package/dist/pmxt/constants.d.ts +4 -0
- package/dist/pmxt/constants.js +7 -1
- package/dist/pmxt/hosted-routing.js +1 -0
- package/dist/pmxt/hosted-typed-data.d.ts +1 -1
- package/dist/pmxt/hosted-typed-data.js +30 -1
- package/dist/pmxt/models.d.ts +1 -0
- package/dist/pmxt/router.js +12 -3
- package/generated/docs/DefaultApi.md +56 -56
- package/generated/package.json +1 -1
- package/generated/src/apis/DefaultApi.ts +28 -0
- package/index.ts +12 -3
- package/package.json +2 -2
- package/pmxt/client.ts +123 -219
- package/pmxt/constants.ts +7 -0
- package/pmxt/hosted-routing.ts +1 -0
- package/pmxt/hosted-typed-data.ts +33 -1
- package/pmxt/models.ts +3 -0
- package/pmxt/router.ts +14 -3
package/pmxt/client.ts
CHANGED
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
UnifiedSeries,
|
|
47
47
|
UserTrade,
|
|
48
48
|
FirehoseEvent,
|
|
49
|
+
FetchMatchedMarketClustersParams,
|
|
49
50
|
} from "./models.js";
|
|
50
51
|
|
|
51
52
|
import { ServerManager } from "./server-manager.js";
|
|
@@ -1131,9 +1132,6 @@ export abstract class Exchange {
|
|
|
1131
1132
|
}
|
|
1132
1133
|
|
|
1133
1134
|
async submitOrder(built: BuiltOrder): Promise<Order> {
|
|
1134
|
-
if (this.isHostedTradingMode()) {
|
|
1135
|
-
return this._hostedSubmitOrder(built);
|
|
1136
|
-
}
|
|
1137
1135
|
await this.initPromise;
|
|
1138
1136
|
if (this.isHosted) {
|
|
1139
1137
|
throw new PmxtError("submitOrder is not available in hosted mode. Use createOrder instead.");
|
|
@@ -1162,88 +1160,7 @@ export abstract class Exchange {
|
|
|
1162
1160
|
}
|
|
1163
1161
|
}
|
|
1164
1162
|
|
|
1165
|
-
/**
|
|
1166
|
-
* Hosted-mode submitOrder: validate the stored build response, sign the
|
|
1167
|
-
* typed_data (and pull_typed_data for Opinion cross-chain sells), then
|
|
1168
|
-
* POST to `/v0/trade/submit-order`.
|
|
1169
|
-
*/
|
|
1170
|
-
private async _hostedSubmitOrder(built: BuiltOrder): Promise<Order> {
|
|
1171
|
-
const signer = this.requireHostedSigner();
|
|
1172
|
-
if (!this.walletAddress) {
|
|
1173
|
-
throw new MissingWalletAddress(
|
|
1174
|
-
"hosted submitOrder requires walletAddress",
|
|
1175
|
-
);
|
|
1176
|
-
}
|
|
1177
|
-
// BuiltOrder is the SDK-side wrapper around the build response —
|
|
1178
|
-
// expect typed_data, optional pull_typed_data, built_order_id, and
|
|
1179
|
-
// the originating build_request to be present.
|
|
1180
|
-
const payload = built as unknown as Record<string, unknown>;
|
|
1181
|
-
const typedData = payload["typed_data"] as TypedData | undefined;
|
|
1182
|
-
if (!typedData) {
|
|
1183
|
-
throw new HostedInvalidSignature(0, "typed_data missing from built order");
|
|
1184
|
-
}
|
|
1185
|
-
const buildRequest = (payload["build_request"] as Record<string, unknown> | undefined)
|
|
1186
|
-
?? ((payload["params"] as Record<string, unknown> | undefined)?.["build_request"] as Record<string, unknown> | undefined);
|
|
1187
|
-
|
|
1188
|
-
const side = String(buildRequest?.["side"] ?? "buy");
|
|
1189
|
-
const primaryRoute = this._hostedTypedDataRoute(side, false);
|
|
1190
|
-
// Layer 1: schema, Layer 2: economics.
|
|
1191
|
-
validateTypedData(typedData, primaryRoute, this.walletAddress);
|
|
1192
|
-
if (buildRequest) {
|
|
1193
|
-
validateEconomics(typedData, primaryRoute, buildRequest, payload);
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
const signature = await signer.signTypedData(typedData);
|
|
1197
|
-
// Layer 3: post-sign recovery + canonical check.
|
|
1198
|
-
verifySignature(typedData, signature, signer.address);
|
|
1199
|
-
|
|
1200
|
-
const body: Record<string, unknown> = {
|
|
1201
|
-
built_order_id: payload["built_order_id"],
|
|
1202
|
-
signature,
|
|
1203
|
-
};
|
|
1204
|
-
|
|
1205
|
-
const pullTypedData = payload["pull_typed_data"] as TypedData | undefined;
|
|
1206
|
-
if (pullTypedData) {
|
|
1207
|
-
const pullRoute = this._hostedTypedDataRoute(side, true);
|
|
1208
|
-
if (pullRoute) {
|
|
1209
|
-
validateTypedData(pullTypedData, pullRoute, this.walletAddress);
|
|
1210
|
-
}
|
|
1211
|
-
const pullSig = await signer.signTypedData(pullTypedData);
|
|
1212
|
-
verifySignature(pullTypedData, pullSig, signer.address);
|
|
1213
|
-
body["pull_signature"] = pullSig;
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
|
-
const route = HOSTED_METHOD_ROUTES.get("submitOrder")!;
|
|
1217
|
-
const data = await _tradingRequest(this, { method: route.method, path: route.path, body });
|
|
1218
|
-
return orderFromV0(data as Record<string, unknown>);
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
/**
|
|
1222
|
-
* Resolve the per-(venue, side, pull) typed-data schema route used by
|
|
1223
|
-
* `validateTypedData` / `validateEconomics`. Returns undefined for the
|
|
1224
|
-
* pull leg when a venue/side combo doesn't have one.
|
|
1225
|
-
*/
|
|
1226
|
-
private _hostedTypedDataRoute(side: string, isPull: boolean): string {
|
|
1227
|
-
const venue = this.exchangeName;
|
|
1228
|
-
const sideLower = side.toLowerCase();
|
|
1229
|
-
if (venue === "polymarket") {
|
|
1230
|
-
return sideLower === "sell" ? "polymarket_sell" : "polymarket_buy";
|
|
1231
|
-
}
|
|
1232
|
-
// opinion
|
|
1233
|
-
if (sideLower === "buy") return "opinion_buy";
|
|
1234
|
-
// sell — polygon, or BSC pull leg for cross-chain
|
|
1235
|
-
return isPull ? "opinion_sell_bsc_pull" : "opinion_sell_polygon";
|
|
1236
|
-
}
|
|
1237
|
-
|
|
1238
|
-
private _hostedCancelTypedDataRoute(isPull: boolean): string {
|
|
1239
|
-
if (this.exchangeName === "polymarket") return "cancel_polymarket";
|
|
1240
|
-
return isPull ? "cancel_opinion_bsc_pull" : "cancel_opinion_polygon";
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
1163
|
async cancelOrder(orderId: string): Promise<Order> {
|
|
1244
|
-
if (this.isHostedTradingMode()) {
|
|
1245
|
-
return this._hostedCancelOrder(orderId);
|
|
1246
|
-
}
|
|
1247
1164
|
await this.initPromise;
|
|
1248
1165
|
try {
|
|
1249
1166
|
const args: any[] = [];
|
|
@@ -1269,56 +1186,7 @@ export abstract class Exchange {
|
|
|
1269
1186
|
}
|
|
1270
1187
|
}
|
|
1271
1188
|
|
|
1272
|
-
/**
|
|
1273
|
-
* Hosted-mode cancelOrder: build the cancel typed_data on the server,
|
|
1274
|
-
* validate + sign (dual-sign for Opinion cross-chain), then submit.
|
|
1275
|
-
*/
|
|
1276
|
-
private async _hostedCancelOrder(orderId: string): Promise<Order> {
|
|
1277
|
-
const signer = this.requireHostedSigner();
|
|
1278
|
-
if (!this.walletAddress) {
|
|
1279
|
-
throw new MissingWalletAddress(
|
|
1280
|
-
"hosted cancelOrder requires walletAddress",
|
|
1281
|
-
);
|
|
1282
|
-
}
|
|
1283
|
-
|
|
1284
|
-
const buildRoute = HOSTED_METHOD_ROUTES.get("cancelOrderBuild")!;
|
|
1285
|
-
const buildResp = await _tradingRequest(this, {
|
|
1286
|
-
method: buildRoute.method,
|
|
1287
|
-
path: buildRoute.path,
|
|
1288
|
-
body: { order_id: orderId },
|
|
1289
|
-
}) as Record<string, unknown>;
|
|
1290
|
-
|
|
1291
|
-
const typedData = buildResp["typed_data"] as TypedData | undefined;
|
|
1292
|
-
if (!typedData) {
|
|
1293
|
-
throw new HostedInvalidSignature(0, "typed_data missing from cancel build response");
|
|
1294
|
-
}
|
|
1295
|
-
|
|
1296
|
-
validateTypedData(typedData, this._hostedCancelTypedDataRoute(false), this.walletAddress);
|
|
1297
|
-
const signature = await signer.signTypedData(typedData);
|
|
1298
|
-
verifySignature(typedData, signature, signer.address);
|
|
1299
|
-
|
|
1300
|
-
const body: Record<string, unknown> = {
|
|
1301
|
-
cancel_id: buildResp["cancel_id"],
|
|
1302
|
-
signature,
|
|
1303
|
-
};
|
|
1304
|
-
|
|
1305
|
-
const pullTypedData = buildResp["pull_typed_data"] as TypedData | undefined;
|
|
1306
|
-
if (pullTypedData) {
|
|
1307
|
-
validateTypedData(pullTypedData, this._hostedCancelTypedDataRoute(true), this.walletAddress);
|
|
1308
|
-
const pullSig = await signer.signTypedData(pullTypedData);
|
|
1309
|
-
verifySignature(pullTypedData, pullSig, signer.address);
|
|
1310
|
-
body["pull_signature"] = pullSig;
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
const route = HOSTED_METHOD_ROUTES.get("cancelOrder")!;
|
|
1314
|
-
const data = await _tradingRequest(this, { method: route.method, path: route.path, body });
|
|
1315
|
-
return orderFromV0(data as Record<string, unknown>);
|
|
1316
|
-
}
|
|
1317
|
-
|
|
1318
1189
|
async fetchOrder(orderId: string): Promise<Order> {
|
|
1319
|
-
if (this.isHostedTradingMode()) {
|
|
1320
|
-
return this._hostedFetchOrder(orderId);
|
|
1321
|
-
}
|
|
1322
1190
|
await this.initPromise;
|
|
1323
1191
|
try {
|
|
1324
1192
|
const args: any[] = [];
|
|
@@ -1344,17 +1212,7 @@ export abstract class Exchange {
|
|
|
1344
1212
|
}
|
|
1345
1213
|
}
|
|
1346
1214
|
|
|
1347
|
-
private async _hostedFetchOrder(orderId: string): Promise<Order> {
|
|
1348
|
-
const route = HOSTED_METHOD_ROUTES.get("fetchOrder")!;
|
|
1349
|
-
const path = formatRoutePath(route, { order_id: orderId });
|
|
1350
|
-
const data = await _tradingRequest(this, { method: route.method, path });
|
|
1351
|
-
return orderFromV0(data as Record<string, unknown>);
|
|
1352
|
-
}
|
|
1353
|
-
|
|
1354
1215
|
async fetchOpenOrders(marketId?: string): Promise<Order[]> {
|
|
1355
|
-
if (this.isHostedTradingMode()) {
|
|
1356
|
-
return this._hostedFetchOpenOrders(marketId);
|
|
1357
|
-
}
|
|
1358
1216
|
await this.initPromise;
|
|
1359
1217
|
try {
|
|
1360
1218
|
const args: any[] = [];
|
|
@@ -1380,24 +1238,7 @@ export abstract class Exchange {
|
|
|
1380
1238
|
}
|
|
1381
1239
|
}
|
|
1382
1240
|
|
|
1383
|
-
private async _hostedFetchOpenOrders(marketId?: string): Promise<Order[]> {
|
|
1384
|
-
const address = resolveWalletAddress(this, undefined);
|
|
1385
|
-
const route = HOSTED_METHOD_ROUTES.get("fetchOpenOrders")!;
|
|
1386
|
-
const params: Record<string, string> = { address };
|
|
1387
|
-
if (marketId !== undefined) params["market_id"] = marketId;
|
|
1388
|
-
const data = await _tradingRequest(this, {
|
|
1389
|
-
method: route.method,
|
|
1390
|
-
path: route.path,
|
|
1391
|
-
params,
|
|
1392
|
-
});
|
|
1393
|
-
const items = (Array.isArray(data) ? data : (data as Record<string, unknown>)?.["orders"] ?? []) as unknown[];
|
|
1394
|
-
return (items as Record<string, unknown>[]).map(orderFromV0);
|
|
1395
|
-
}
|
|
1396
|
-
|
|
1397
1241
|
async fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]> {
|
|
1398
|
-
if (this.isHostedTradingMode()) {
|
|
1399
|
-
return this._hostedFetchMyTrades(params);
|
|
1400
|
-
}
|
|
1401
1242
|
await this.initPromise;
|
|
1402
1243
|
try {
|
|
1403
1244
|
const args: any[] = [];
|
|
@@ -1423,32 +1264,7 @@ export abstract class Exchange {
|
|
|
1423
1264
|
}
|
|
1424
1265
|
}
|
|
1425
1266
|
|
|
1426
|
-
private async _hostedFetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]> {
|
|
1427
|
-
const address = resolveWalletAddress(this, undefined);
|
|
1428
|
-
const route = HOSTED_METHOD_ROUTES.get("fetchMyTrades")!;
|
|
1429
|
-
const path = formatRoutePath(route, { address });
|
|
1430
|
-
const q: Record<string, string> = {};
|
|
1431
|
-
if (params?.marketId) q["market_id"] = params.marketId;
|
|
1432
|
-
if (params?.outcomeId) q["outcome_id"] = params.outcomeId;
|
|
1433
|
-
if (params?.limit !== undefined) q["limit"] = String(params.limit);
|
|
1434
|
-
if (params?.cursor) q["cursor"] = params.cursor;
|
|
1435
|
-
if (params?.since) q["since"] = String(params.since.getTime());
|
|
1436
|
-
if (params?.until) q["until"] = String(params.until.getTime());
|
|
1437
|
-
const data = await _tradingRequest(this, {
|
|
1438
|
-
method: route.method,
|
|
1439
|
-
path,
|
|
1440
|
-
params: Object.keys(q).length ? q : undefined,
|
|
1441
|
-
});
|
|
1442
|
-
const items = (Array.isArray(data) ? data : (data as Record<string, unknown>)?.["trades"] ?? []) as unknown[];
|
|
1443
|
-
return (items as Record<string, unknown>[]).map(userTradeFromV0);
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
1267
|
async fetchClosedOrders(params?: OrderHistoryParams): Promise<Order[]> {
|
|
1447
|
-
if (this.isHostedTradingMode()) {
|
|
1448
|
-
throw new NotSupported(
|
|
1449
|
-
"Settled orders are modeled as trades — use fetchMyTrades().",
|
|
1450
|
-
);
|
|
1451
|
-
}
|
|
1452
1268
|
await this.initPromise;
|
|
1453
1269
|
try {
|
|
1454
1270
|
const args: any[] = [];
|
|
@@ -1475,11 +1291,6 @@ export abstract class Exchange {
|
|
|
1475
1291
|
}
|
|
1476
1292
|
|
|
1477
1293
|
async fetchAllOrders(params?: OrderHistoryParams): Promise<Order[]> {
|
|
1478
|
-
if (this.isHostedTradingMode()) {
|
|
1479
|
-
throw new NotSupported(
|
|
1480
|
-
"Use fetchOpenOrders() and fetchMyTrades() separately.",
|
|
1481
|
-
);
|
|
1482
|
-
}
|
|
1483
1294
|
await this.initPromise;
|
|
1484
1295
|
try {
|
|
1485
1296
|
const args: any[] = [];
|
|
@@ -1506,9 +1317,6 @@ export abstract class Exchange {
|
|
|
1506
1317
|
}
|
|
1507
1318
|
|
|
1508
1319
|
async fetchPositions(address?: string): Promise<Position[]> {
|
|
1509
|
-
if (this.isHostedTradingMode()) {
|
|
1510
|
-
return this._hostedFetchPositions(address);
|
|
1511
|
-
}
|
|
1512
1320
|
await this.initPromise;
|
|
1513
1321
|
try {
|
|
1514
1322
|
const args: any[] = [];
|
|
@@ -1534,19 +1342,7 @@ export abstract class Exchange {
|
|
|
1534
1342
|
}
|
|
1535
1343
|
}
|
|
1536
1344
|
|
|
1537
|
-
private async _hostedFetchPositions(address?: string): Promise<Position[]> {
|
|
1538
|
-
const resolvedAddr = resolveWalletAddress(this, address);
|
|
1539
|
-
const route = HOSTED_METHOD_ROUTES.get("fetchPositions")!;
|
|
1540
|
-
const path = formatRoutePath(route, { address: resolvedAddr });
|
|
1541
|
-
const data = await _tradingRequest(this, { method: route.method, path });
|
|
1542
|
-
const items = (Array.isArray(data) ? data : (data as Record<string, unknown>)?.["positions"] ?? []) as unknown[];
|
|
1543
|
-
return (items as Record<string, unknown>[]).map(positionFromV0);
|
|
1544
|
-
}
|
|
1545
|
-
|
|
1546
1345
|
async fetchBalance(address?: string): Promise<Balance[]> {
|
|
1547
|
-
if (this.isHostedTradingMode()) {
|
|
1548
|
-
return this._hostedFetchBalance(address);
|
|
1549
|
-
}
|
|
1550
1346
|
await this.initPromise;
|
|
1551
1347
|
try {
|
|
1552
1348
|
const args: any[] = [];
|
|
@@ -1572,19 +1368,6 @@ export abstract class Exchange {
|
|
|
1572
1368
|
}
|
|
1573
1369
|
}
|
|
1574
1370
|
|
|
1575
|
-
private async _hostedFetchBalance(address?: string): Promise<Balance[]> {
|
|
1576
|
-
const resolvedAddr = resolveWalletAddress(this, address);
|
|
1577
|
-
const route = HOSTED_METHOD_ROUTES.get("fetchBalance")!;
|
|
1578
|
-
const path = formatRoutePath(route, { address: resolvedAddr });
|
|
1579
|
-
const data = await _tradingRequest(this, { method: route.method, path });
|
|
1580
|
-
// Hosted balance is a single USDC escrow record; wrap in an array
|
|
1581
|
-
// to match the existing Balance[] return shape.
|
|
1582
|
-
if (Array.isArray(data)) {
|
|
1583
|
-
return (data as Record<string, unknown>[]).map(balanceFromV0);
|
|
1584
|
-
}
|
|
1585
|
-
return [balanceFromV0(data as Record<string, unknown>)];
|
|
1586
|
-
}
|
|
1587
|
-
|
|
1588
1371
|
async unwatchOrderBook(outcomeId: string | MarketOutcome): Promise<void> {
|
|
1589
1372
|
await this.initPromise;
|
|
1590
1373
|
try {
|
|
@@ -1784,7 +1567,7 @@ export abstract class Exchange {
|
|
|
1784
1567
|
}
|
|
1785
1568
|
}
|
|
1786
1569
|
|
|
1787
|
-
async fetchMatchedMarkets(params?:
|
|
1570
|
+
async fetchMatchedMarkets(params?: FetchMatchedMarketClustersParams): Promise<any[]> {
|
|
1788
1571
|
await this.initPromise;
|
|
1789
1572
|
try {
|
|
1790
1573
|
const args: any[] = [];
|
|
@@ -2322,6 +2105,15 @@ export abstract class Exchange {
|
|
|
2322
2105
|
if (params.fee !== undefined) {
|
|
2323
2106
|
paramsDict.fee = params.fee;
|
|
2324
2107
|
}
|
|
2108
|
+
if (params.tickSize !== undefined) {
|
|
2109
|
+
paramsDict.tickSize = params.tickSize;
|
|
2110
|
+
}
|
|
2111
|
+
if (params.negRisk !== undefined) {
|
|
2112
|
+
paramsDict.negRisk = params.negRisk;
|
|
2113
|
+
}
|
|
2114
|
+
if (params.onBehalfOf !== undefined) {
|
|
2115
|
+
paramsDict.onBehalfOf = params.onBehalfOf;
|
|
2116
|
+
}
|
|
2325
2117
|
|
|
2326
2118
|
const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/buildOrder`, {
|
|
2327
2119
|
method: 'POST',
|
|
@@ -2445,6 +2237,87 @@ export abstract class Exchange {
|
|
|
2445
2237
|
return this._hostedSubmitOrder(built);
|
|
2446
2238
|
}
|
|
2447
2239
|
|
|
2240
|
+
/**
|
|
2241
|
+
* Hosted-mode submitOrder: validate the stored build response, sign the
|
|
2242
|
+
* typed_data (and pull_typed_data for cross-chain venue sells), then
|
|
2243
|
+
* POST to `/v0/trade/submit-order`.
|
|
2244
|
+
*
|
|
2245
|
+
* Restored after PR #1058 (Limitless hosted wire-up) accidentally
|
|
2246
|
+
* removed it but left the call site + signing imports intact.
|
|
2247
|
+
*/
|
|
2248
|
+
private async _hostedSubmitOrder(built: BuiltOrder): Promise<Order> {
|
|
2249
|
+
const signer = this.requireHostedSigner();
|
|
2250
|
+
if (!this.walletAddress) {
|
|
2251
|
+
throw new MissingWalletAddress(
|
|
2252
|
+
"hosted submitOrder requires walletAddress",
|
|
2253
|
+
);
|
|
2254
|
+
}
|
|
2255
|
+
const payload = built as unknown as Record<string, unknown>;
|
|
2256
|
+
const typedData = payload["typed_data"] as TypedData | undefined;
|
|
2257
|
+
if (!typedData) {
|
|
2258
|
+
throw new HostedInvalidSignature(0, "typed_data missing from built order");
|
|
2259
|
+
}
|
|
2260
|
+
const buildRequest = (payload["build_request"] as Record<string, unknown> | undefined)
|
|
2261
|
+
?? ((payload["params"] as Record<string, unknown> | undefined)?.["build_request"] as Record<string, unknown> | undefined);
|
|
2262
|
+
|
|
2263
|
+
const side = String(buildRequest?.["side"] ?? "buy");
|
|
2264
|
+
const primaryRoute = this._hostedTypedDataRoute(side, false);
|
|
2265
|
+
validateTypedData(typedData, primaryRoute, this.walletAddress);
|
|
2266
|
+
if (buildRequest) {
|
|
2267
|
+
validateEconomics(typedData, primaryRoute, buildRequest, payload);
|
|
2268
|
+
}
|
|
2269
|
+
|
|
2270
|
+
const signature = await signer.signTypedData(typedData);
|
|
2271
|
+
verifySignature(typedData, signature, signer.address);
|
|
2272
|
+
|
|
2273
|
+
const body: Record<string, unknown> = {
|
|
2274
|
+
built_order_id: payload["built_order_id"],
|
|
2275
|
+
signature,
|
|
2276
|
+
};
|
|
2277
|
+
|
|
2278
|
+
const pullTypedData = payload["pull_typed_data"] as TypedData | undefined;
|
|
2279
|
+
if (pullTypedData) {
|
|
2280
|
+
const pullRoute = this._hostedTypedDataRoute(side, true);
|
|
2281
|
+
if (pullRoute) {
|
|
2282
|
+
validateTypedData(pullTypedData, pullRoute, this.walletAddress);
|
|
2283
|
+
}
|
|
2284
|
+
const pullSig = await signer.signTypedData(pullTypedData);
|
|
2285
|
+
verifySignature(pullTypedData, pullSig, signer.address);
|
|
2286
|
+
body["pull_signature"] = pullSig;
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2289
|
+
const route = HOSTED_METHOD_ROUTES.get("submitOrder")!;
|
|
2290
|
+
const data = await _tradingRequest(this, { method: route.method, path: route.path, body });
|
|
2291
|
+
return orderFromV0(data as Record<string, unknown>);
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
/**
|
|
2295
|
+
* Resolve the per-(venue, side, pull) typed-data schema route used by
|
|
2296
|
+
* `validateTypedData` / `validateEconomics`. Returns the cross-chain
|
|
2297
|
+
* pull-leg route name for Opinion sells and Limitless cross-chain orders.
|
|
2298
|
+
*/
|
|
2299
|
+
private _hostedTypedDataRoute(side: string, isPull: boolean): string {
|
|
2300
|
+
const venue = this.exchangeName;
|
|
2301
|
+
const sideLower = side.toLowerCase();
|
|
2302
|
+
if (venue === "polymarket") {
|
|
2303
|
+
return sideLower === "sell" ? "polymarket_sell" : "polymarket_buy";
|
|
2304
|
+
}
|
|
2305
|
+
if (venue === "limitless") {
|
|
2306
|
+
if (sideLower === "buy") return "limitless_buy";
|
|
2307
|
+
return isPull ? "limitless_sell_base_pull" : "limitless_sell_polygon";
|
|
2308
|
+
}
|
|
2309
|
+
// opinion
|
|
2310
|
+
if (sideLower === "buy") return "opinion_buy";
|
|
2311
|
+
return isPull ? "opinion_sell_bsc_pull" : "opinion_sell_polygon";
|
|
2312
|
+
}
|
|
2313
|
+
|
|
2314
|
+
private _hostedCancelTypedDataRoute(isPull: boolean): string {
|
|
2315
|
+
const venue = this.exchangeName;
|
|
2316
|
+
if (venue === "polymarket") return "cancel_polymarket";
|
|
2317
|
+
if (venue === "limitless") return isPull ? "cancel_limitless_base_pull" : "cancel_limitless_polygon";
|
|
2318
|
+
return isPull ? "cancel_opinion_bsc_pull" : "cancel_opinion_polygon";
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2448
2321
|
/**
|
|
2449
2322
|
* Construct the hosted build-order request body and validate inputs
|
|
2450
2323
|
* locally per the v0 contract (denom/side compatibility, > 6-decimal
|
|
@@ -2624,6 +2497,15 @@ export abstract class Exchange {
|
|
|
2624
2497
|
if (params.fee !== undefined) {
|
|
2625
2498
|
paramsDict.fee = params.fee;
|
|
2626
2499
|
}
|
|
2500
|
+
if (params.tickSize !== undefined) {
|
|
2501
|
+
paramsDict.tickSize = params.tickSize;
|
|
2502
|
+
}
|
|
2503
|
+
if (params.negRisk !== undefined) {
|
|
2504
|
+
paramsDict.negRisk = params.negRisk;
|
|
2505
|
+
}
|
|
2506
|
+
if (params.onBehalfOf !== undefined) {
|
|
2507
|
+
paramsDict.onBehalfOf = params.onBehalfOf;
|
|
2508
|
+
}
|
|
2627
2509
|
|
|
2628
2510
|
const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/createOrder`, {
|
|
2629
2511
|
method: 'POST',
|
|
@@ -3373,6 +3255,28 @@ export class SuiBets extends Exchange {
|
|
|
3373
3255
|
// Backwards-compatible casing alias matching the Python SDK export.
|
|
3374
3256
|
export const Suibets = SuiBets;
|
|
3375
3257
|
|
|
3258
|
+
/**
|
|
3259
|
+
* Rain exchange client.
|
|
3260
|
+
*
|
|
3261
|
+
* Rain is a permissionless AMM-plus-orderbook prediction market on Arbitrum One.
|
|
3262
|
+
* Reads are unauthenticated; trading requires an EVM privateKey.
|
|
3263
|
+
*
|
|
3264
|
+
* @example
|
|
3265
|
+
* ```typescript
|
|
3266
|
+
* const rain = new Rain();
|
|
3267
|
+
* const markets = await rain.fetchMarkets({ limit: 20 });
|
|
3268
|
+
*
|
|
3269
|
+
* // With wallet for trading
|
|
3270
|
+
* const me = new Rain({ privateKey: '0x...' });
|
|
3271
|
+
* await me.createOrder({ marketId, outcomeId, side: 'buy', type: 'market', amount: 10 });
|
|
3272
|
+
* ```
|
|
3273
|
+
*/
|
|
3274
|
+
export class Rain extends Exchange {
|
|
3275
|
+
constructor(options: ExchangeOptions = {}) {
|
|
3276
|
+
super("rain", options);
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
3279
|
+
|
|
3376
3280
|
/**
|
|
3377
3281
|
* Mock exchange client.
|
|
3378
3282
|
*
|
package/pmxt/constants.ts
CHANGED
|
@@ -80,3 +80,10 @@ export const PREFUNDED_ESCROW_ADDRESSES: ReadonlySet<string> = new Set([
|
|
|
80
80
|
* as venue-owned escrows. Currently empty; populated as venues onboard.
|
|
81
81
|
*/
|
|
82
82
|
export const VENUE_ESCROW_ADDRESSES: ReadonlySet<string> = new Set<string>();
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Limitless VenueEscrow contract addresses on Base (chain 8453).
|
|
86
|
+
*/
|
|
87
|
+
export const LIMITLESS_VENUE_ESCROW_ADDRESSES: ReadonlySet<string> = new Set([
|
|
88
|
+
"0x34c42d01aad6ded00f1a6830d90b0e9204db7855",
|
|
89
|
+
]);
|
package/pmxt/hosted-routing.ts
CHANGED
|
@@ -123,10 +123,19 @@ const VENUE_DOMAIN: DomainSchema = {
|
|
|
123
123
|
chainId: 56,
|
|
124
124
|
allowlistKey: "venue",
|
|
125
125
|
};
|
|
126
|
+
const LIMITLESS_VENUE_DOMAIN: DomainSchema = {
|
|
127
|
+
name: "VenueEscrow",
|
|
128
|
+
version: "1",
|
|
129
|
+
chainId: 8453,
|
|
130
|
+
allowlistKey: "venue",
|
|
131
|
+
};
|
|
126
132
|
|
|
127
133
|
export type HostedRoute =
|
|
128
134
|
| "polymarket_buy"
|
|
129
135
|
| "polymarket_sell"
|
|
136
|
+
| "limitless_buy"
|
|
137
|
+
| "limitless_sell_polygon"
|
|
138
|
+
| "limitless_sell_base_pull"
|
|
130
139
|
| "opinion_buy"
|
|
131
140
|
| "opinion_sell_polygon"
|
|
132
141
|
| "opinion_sell_bsc_pull"
|
|
@@ -142,6 +151,27 @@ const SCHEMAS: Readonly<Record<HostedRoute, TypedDataSchema>> = {
|
|
|
142
151
|
messageKeys: messageKeysFromFields(ORDER_PARAMS_FIELDS),
|
|
143
152
|
walletField: "user",
|
|
144
153
|
},
|
|
154
|
+
limitless_buy: {
|
|
155
|
+
primaryType: "CrossChainOrderParams",
|
|
156
|
+
domain: PREFUNDED_DOMAIN,
|
|
157
|
+
fields: CROSS_CHAIN_ORDER_PARAMS_FIELDS,
|
|
158
|
+
messageKeys: messageKeysFromFields(CROSS_CHAIN_ORDER_PARAMS_FIELDS),
|
|
159
|
+
walletField: "user",
|
|
160
|
+
},
|
|
161
|
+
limitless_sell_polygon: {
|
|
162
|
+
primaryType: "CrossChainSellPayParams",
|
|
163
|
+
domain: PREFUNDED_DOMAIN,
|
|
164
|
+
fields: CROSS_CHAIN_SELL_PAY_PARAMS_FIELDS,
|
|
165
|
+
messageKeys: messageKeysFromFields(CROSS_CHAIN_SELL_PAY_PARAMS_FIELDS),
|
|
166
|
+
walletField: "user",
|
|
167
|
+
},
|
|
168
|
+
limitless_sell_base_pull: {
|
|
169
|
+
primaryType: "CrossChainSellPullParams",
|
|
170
|
+
domain: LIMITLESS_VENUE_DOMAIN,
|
|
171
|
+
fields: CROSS_CHAIN_SELL_PULL_PARAMS_FIELDS,
|
|
172
|
+
messageKeys: messageKeysFromFields(CROSS_CHAIN_SELL_PULL_PARAMS_FIELDS),
|
|
173
|
+
walletField: "user",
|
|
174
|
+
},
|
|
145
175
|
polymarket_sell: {
|
|
146
176
|
primaryType: "SellOrderParams",
|
|
147
177
|
domain: PREFUNDED_DOMAIN,
|
|
@@ -698,7 +728,9 @@ function allowedAddresses(
|
|
|
698
728
|
const raw =
|
|
699
729
|
key === "prefunded"
|
|
700
730
|
? (constants as any).PREFUNDED_ESCROW_ADDRESSES
|
|
701
|
-
:
|
|
731
|
+
: chainId === 8453
|
|
732
|
+
? (constants as any).LIMITLESS_VENUE_ESCROW_ADDRESSES
|
|
733
|
+
: (constants as any).VENUE_ESCROW_ADDRESSES;
|
|
702
734
|
const list: unknown[] = [];
|
|
703
735
|
if (raw == null) {
|
|
704
736
|
// empty
|
package/pmxt/models.ts
CHANGED
|
@@ -1048,6 +1048,9 @@ export interface FetchMatchedMarketClustersParams extends MatchedClusterFilterPa
|
|
|
1048
1048
|
url?: string;
|
|
1049
1049
|
}
|
|
1050
1050
|
|
|
1051
|
+
// Alias for SDK consistency with Python
|
|
1052
|
+
export type MatchedMarketClusterParams = FetchMatchedMarketClustersParams;
|
|
1053
|
+
|
|
1051
1054
|
/** Parameters for fetching matched event clusters. */
|
|
1052
1055
|
export interface FetchMatchedEventClustersParams extends MatchedClusterFilterParams {
|
|
1053
1056
|
/** Pass a UnifiedEvent directly instead of eventId/slug/url. */
|
package/pmxt/router.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
EventMatchResult,
|
|
14
14
|
FetchMatchedEventClustersParams,
|
|
15
15
|
FetchMatchedMarketClustersParams,
|
|
16
|
+
MatchedMarketClusterParams,
|
|
16
17
|
MatchedEventCluster,
|
|
17
18
|
MatchedMarketCluster,
|
|
18
19
|
PriceComparison,
|
|
@@ -21,6 +22,15 @@ import {
|
|
|
21
22
|
UnifiedEvent,
|
|
22
23
|
} from "./models.js";
|
|
23
24
|
|
|
25
|
+
function withQuestionAlias<T extends UnifiedMarket>(market: T): T {
|
|
26
|
+
Object.defineProperty(market, 'question', {
|
|
27
|
+
get() { return this.title; },
|
|
28
|
+
enumerable: false,
|
|
29
|
+
configurable: true,
|
|
30
|
+
});
|
|
31
|
+
return market;
|
|
32
|
+
}
|
|
33
|
+
|
|
24
34
|
function convertMarket(raw: any): UnifiedMarket {
|
|
25
35
|
const outcomes = (raw.outcomes || []).map((o: any) => ({
|
|
26
36
|
outcomeId: o.outcomeId,
|
|
@@ -44,7 +54,7 @@ function convertMarket(raw: any): UnifiedMarket {
|
|
|
44
54
|
metadata: o.metadata,
|
|
45
55
|
}) : undefined;
|
|
46
56
|
|
|
47
|
-
return {
|
|
57
|
+
return withQuestionAlias({
|
|
48
58
|
marketId: raw.marketId,
|
|
49
59
|
title: raw.title,
|
|
50
60
|
slug: raw.slug,
|
|
@@ -68,7 +78,7 @@ function convertMarket(raw: any): UnifiedMarket {
|
|
|
68
78
|
no: convertOutcome(raw.no),
|
|
69
79
|
up: convertOutcome(raw.up),
|
|
70
80
|
down: convertOutcome(raw.down),
|
|
71
|
-
};
|
|
81
|
+
});
|
|
72
82
|
}
|
|
73
83
|
|
|
74
84
|
function convertEvent(raw: any): UnifiedEvent {
|
|
@@ -91,7 +101,7 @@ function convertEvent(raw: any): UnifiedEvent {
|
|
|
91
101
|
function parseMatchResult(raw: any): MatchResult {
|
|
92
102
|
const marketData = raw.market || {};
|
|
93
103
|
const market = convertMarket(marketData);
|
|
94
|
-
|
|
104
|
+
const result: MatchResult = {
|
|
95
105
|
...market,
|
|
96
106
|
market,
|
|
97
107
|
relation: raw.relation || 'identity',
|
|
@@ -101,6 +111,7 @@ function parseMatchResult(raw: any): MatchResult {
|
|
|
101
111
|
bestAsk: raw.bestAsk ?? marketData.bestAsk,
|
|
102
112
|
sourceMarket: raw.sourceMarket ? convertMarket(raw.sourceMarket) : undefined,
|
|
103
113
|
};
|
|
114
|
+
return withQuestionAlias(result);
|
|
104
115
|
}
|
|
105
116
|
|
|
106
117
|
function normalizeQueryValue(value: unknown): unknown {
|