pmxtjs 2.48.6 → 2.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/esm/generated/src/models/OrderLevel.d.ts +6 -0
  2. package/dist/esm/generated/src/models/OrderLevel.js +2 -0
  3. package/dist/esm/index.d.ts +2 -0
  4. package/dist/esm/index.js +1 -0
  5. package/dist/esm/pmxt/client.d.ts +106 -5
  6. package/dist/esm/pmxt/client.js +400 -6
  7. package/dist/esm/pmxt/constants.d.ts +11 -0
  8. package/dist/esm/pmxt/constants.js +13 -0
  9. package/dist/esm/pmxt/errors.d.ts +3 -0
  10. package/dist/esm/pmxt/errors.js +9 -0
  11. package/dist/esm/pmxt/escrow.d.ts +39 -0
  12. package/dist/esm/pmxt/escrow.js +78 -0
  13. package/dist/esm/pmxt/feed-client.d.ts +3 -0
  14. package/dist/esm/pmxt/feed-client.js +11 -2
  15. package/dist/esm/pmxt/hosted-errors.d.ts +84 -0
  16. package/dist/esm/pmxt/hosted-errors.js +186 -0
  17. package/dist/esm/pmxt/hosted-mappers.d.ts +45 -0
  18. package/dist/esm/pmxt/hosted-mappers.js +291 -0
  19. package/dist/esm/pmxt/hosted-routing.d.ts +69 -0
  20. package/dist/esm/pmxt/hosted-routing.js +119 -0
  21. package/dist/esm/pmxt/hosted-typed-data.d.ts +36 -0
  22. package/dist/esm/pmxt/hosted-typed-data.js +580 -0
  23. package/dist/esm/pmxt/models.d.ts +46 -8
  24. package/dist/esm/pmxt/server-manager.d.ts +4 -0
  25. package/dist/esm/pmxt/server-manager.js +6 -0
  26. package/dist/esm/pmxt/signers.d.ts +57 -0
  27. package/dist/esm/pmxt/signers.js +50 -0
  28. package/dist/esm/pmxt/ws-client.js +2 -1
  29. package/dist/generated/src/models/OrderLevel.d.ts +6 -0
  30. package/dist/generated/src/models/OrderLevel.js +2 -0
  31. package/dist/index.d.ts +2 -0
  32. package/dist/index.js +1 -0
  33. package/dist/pmxt/client.d.ts +106 -5
  34. package/dist/pmxt/client.js +399 -5
  35. package/dist/pmxt/constants.d.ts +11 -0
  36. package/dist/pmxt/constants.js +14 -1
  37. package/dist/pmxt/errors.d.ts +3 -0
  38. package/dist/pmxt/errors.js +11 -1
  39. package/dist/pmxt/escrow.d.ts +39 -0
  40. package/dist/pmxt/escrow.js +82 -0
  41. package/dist/pmxt/feed-client.d.ts +3 -0
  42. package/dist/pmxt/feed-client.js +11 -2
  43. package/dist/pmxt/hosted-errors.d.ts +84 -0
  44. package/dist/pmxt/hosted-errors.js +201 -0
  45. package/dist/pmxt/hosted-mappers.d.ts +45 -0
  46. package/dist/pmxt/hosted-mappers.js +302 -0
  47. package/dist/pmxt/hosted-routing.d.ts +69 -0
  48. package/dist/pmxt/hosted-routing.js +126 -0
  49. package/dist/pmxt/hosted-typed-data.d.ts +36 -0
  50. package/dist/pmxt/hosted-typed-data.js +619 -0
  51. package/dist/pmxt/models.d.ts +46 -8
  52. package/dist/pmxt/server-manager.d.ts +4 -0
  53. package/dist/pmxt/server-manager.js +6 -0
  54. package/dist/pmxt/signers.d.ts +57 -0
  55. package/dist/pmxt/signers.js +55 -0
  56. package/dist/pmxt/ws-client.js +2 -1
  57. package/generated/docs/OrderLevel.md +2 -0
  58. package/generated/package.json +1 -1
  59. package/generated/src/models/OrderLevel.ts +8 -0
  60. package/index.ts +1 -0
  61. package/package.json +11 -2
  62. package/pmxt/client.ts +495 -9
  63. package/pmxt/constants.ts +15 -0
  64. package/pmxt/errors.ts +11 -0
  65. package/pmxt/escrow.ts +93 -0
  66. package/pmxt/feed-client.ts +14 -2
  67. package/pmxt/hosted-errors.ts +216 -0
  68. package/pmxt/hosted-mappers.ts +312 -0
  69. package/pmxt/hosted-routing.ts +165 -0
  70. package/pmxt/hosted-typed-data.ts +767 -0
  71. package/pmxt/models.ts +65 -8
  72. package/pmxt/server-manager.ts +7 -0
  73. package/pmxt/signers.ts +86 -0
  74. package/pmxt/ws-client.ts +2 -1
@@ -13,6 +13,18 @@ const server_manager_js_1 = require("./server-manager.js");
13
13
  const errors_js_1 = require("./errors.js");
14
14
  const constants_js_1 = require("./constants.js");
15
15
  const ws_client_js_1 = require("./ws-client.js");
16
+ // Hosted-mode trading dispatch.
17
+ // These modules are introduced as part of the hosted trading mode rollout.
18
+ // Some of them may be authored by parallel agents; until they all land, the
19
+ // import names below are the conventional ones from the plan. Cross-module
20
+ // "Cannot find module" errors during the parallel landing window resolve
21
+ // once the matching files exist.
22
+ const hosted_routing_js_1 = require("./hosted-routing.js");
23
+ const hosted_mappers_js_1 = require("./hosted-mappers.js");
24
+ const hosted_typed_data_js_1 = require("./hosted-typed-data.js");
25
+ const signers_js_1 = require("./signers.js");
26
+ const escrow_js_1 = require("./escrow.js");
27
+ const hosted_errors_js_1 = require("./hosted-errors.js");
16
28
  /**
17
29
  * Resolve a MarketOutcome shorthand to a plain outcome ID string.
18
30
  * Accepts either a raw string ID or a MarketOutcome object.
@@ -139,10 +151,13 @@ class Exchange {
139
151
  "kalshi",
140
152
  "opinion",
141
153
  ]);
154
+ // Public so structural interfaces like `HostedClientLike`
155
+ // (./hosted-routing) can read the venue name and hosted credentials
156
+ // without violating protected-access on this base class.
142
157
  exchangeName;
158
+ pmxtApiKey;
143
159
  apiKey;
144
160
  privateKey;
145
- pmxtApiKey;
146
161
  proxyAddress;
147
162
  signatureType;
148
163
  api;
@@ -150,6 +165,12 @@ class Exchange {
150
165
  serverManager;
151
166
  initPromise;
152
167
  isHosted;
168
+ /** Wallet address used for hosted endpoints that operate on a wallet. */
169
+ walletAddress;
170
+ /** External signer used for hosted writes. */
171
+ signer;
172
+ /** Escrow namespace — populated in hosted mode for trading-allowlisted venues. */
173
+ escrow;
153
174
  _hostedAccount;
154
175
  _accountDiscoveryPromise;
155
176
  /**
@@ -169,6 +190,8 @@ class Exchange {
169
190
  this.privateKey = options.privateKey;
170
191
  this.proxyAddress = options.proxyAddress;
171
192
  this.signatureType = options.signatureType;
193
+ this.walletAddress = options.walletAddress;
194
+ this.signer = options.signer;
172
195
  // Resolve base URL + hosted API key via the shared precedence
173
196
  // rules. See constants.ts for the full resolution table.
174
197
  const resolved = (0, constants_js_1.resolvePmxtBaseUrl)({
@@ -178,6 +201,26 @@ class Exchange {
178
201
  const baseUrl = resolved.baseUrl;
179
202
  this.pmxtApiKey = resolved.pmxtApiKey;
180
203
  this.isHosted = resolved.isHosted;
204
+ // Hosted trading bridge: if the caller passed a privateKey but no
205
+ // explicit signer, lazily wrap it in an EthersSigner so that
206
+ // `pmxt.Polymarket(pmxtApiKey, privateKey)` just works without the
207
+ // user touching `signer`. EthersSigner's constructor synchronously
208
+ // builds an ethers.Wallet, so this remains a synchronous bridge —
209
+ // the constructor stays sync.
210
+ if (this.pmxtApiKey && this.privateKey && !this.signer) {
211
+ try {
212
+ this.signer = new signers_js_1.EthersSigner(this.privateKey);
213
+ }
214
+ catch {
215
+ // ethers not installed — defer the error to the first
216
+ // hosted write that actually needs the signer. Read-only
217
+ // hosted callers don't need ethers.
218
+ }
219
+ }
220
+ // Instantiate Escrow namespace for hosted-trading-allowlisted venues.
221
+ if (this.pmxtApiKey && hosted_routing_js_1.HOSTED_TRADING_VENUES.has(this.exchangeName)) {
222
+ this.escrow = new escrow_js_1.Escrow(this);
223
+ }
181
224
  // auto_start_server defaults: true for local, false for hosted.
182
225
  // An explicit value in the options always wins.
183
226
  const autoStartServer = options.autoStartServer !== undefined
@@ -258,6 +301,25 @@ class Exchange {
258
301
  }
259
302
  return headers;
260
303
  }
304
+ /**
305
+ * Returns true when this client should dispatch trading methods through
306
+ * the hosted PMXT trading API (`pmxtApiKey` set AND venue is on the
307
+ * hosted-trading allowlist). Used to gate every Group A method.
308
+ */
309
+ isHostedTradingMode() {
310
+ return Boolean(this.pmxtApiKey) && hosted_routing_js_1.HOSTED_TRADING_VENUES.has(this.exchangeName);
311
+ }
312
+ /**
313
+ * Require a configured signer for a hosted write. Returns the signer or
314
+ * throws {@link MissingWalletAddress} (consistent with the error class
315
+ * surfaced for missing wallet wiring on hosted writes).
316
+ */
317
+ requireHostedSigner() {
318
+ if (!this.signer) {
319
+ throw new hosted_errors_js_1.MissingWalletAddress("hosted write requires a signer (pass `signer` or `privateKey`)");
320
+ }
321
+ return this.signer;
322
+ }
261
323
  /**
262
324
  * Resolve the current sidecar base URL.
263
325
  *
@@ -852,6 +914,9 @@ class Exchange {
852
914
  }
853
915
  }
854
916
  async submitOrder(built) {
917
+ if (this.isHostedTradingMode()) {
918
+ return this._hostedSubmitOrder(built);
919
+ }
855
920
  await this.initPromise;
856
921
  try {
857
922
  const args = [];
@@ -878,7 +943,80 @@ class Exchange {
878
943
  throw new errors_js_1.PmxtError(`Failed to submitOrder: ${error}`);
879
944
  }
880
945
  }
946
+ /**
947
+ * Hosted-mode submitOrder: validate the stored build response, sign the
948
+ * typed_data (and pull_typed_data for Opinion cross-chain sells), then
949
+ * POST to `/v0/trade/submit-order`.
950
+ */
951
+ async _hostedSubmitOrder(built) {
952
+ const signer = this.requireHostedSigner();
953
+ if (!this.walletAddress) {
954
+ throw new hosted_errors_js_1.MissingWalletAddress("hosted submitOrder requires walletAddress");
955
+ }
956
+ // BuiltOrder is the SDK-side wrapper around the build response —
957
+ // expect typed_data, optional pull_typed_data, built_order_id, and
958
+ // the originating build_request to be present.
959
+ const payload = built;
960
+ const typedData = payload["typed_data"];
961
+ if (!typedData) {
962
+ throw new hosted_errors_js_1.InvalidSignature(0, "typed_data missing from built order");
963
+ }
964
+ const buildRequest = payload["build_request"]
965
+ ?? payload["params"]?.["build_request"];
966
+ const side = String(buildRequest?.["side"] ?? "buy");
967
+ const primaryRoute = this._hostedTypedDataRoute(side, false);
968
+ // Layer 1: schema, Layer 2: economics.
969
+ (0, hosted_typed_data_js_1.validateTypedData)(typedData, primaryRoute, this.walletAddress);
970
+ if (buildRequest) {
971
+ (0, hosted_typed_data_js_1.validateEconomics)(typedData, primaryRoute, buildRequest, payload);
972
+ }
973
+ const signature = await signer.signTypedData(typedData);
974
+ // Layer 3: post-sign recovery + canonical check.
975
+ (0, hosted_typed_data_js_1.verifySignature)(typedData, signature, signer.address);
976
+ const body = {
977
+ built_order_id: payload["built_order_id"],
978
+ signature,
979
+ };
980
+ const pullTypedData = payload["pull_typed_data"];
981
+ if (pullTypedData) {
982
+ const pullRoute = this._hostedTypedDataRoute(side, true);
983
+ if (pullRoute) {
984
+ (0, hosted_typed_data_js_1.validateTypedData)(pullTypedData, pullRoute, this.walletAddress);
985
+ }
986
+ const pullSig = await signer.signTypedData(pullTypedData);
987
+ (0, hosted_typed_data_js_1.verifySignature)(pullTypedData, pullSig, signer.address);
988
+ body["pull_signature"] = pullSig;
989
+ }
990
+ const route = hosted_routing_js_1.HOSTED_METHOD_ROUTES.get("submitOrder");
991
+ const data = await (0, hosted_routing_js_1._tradingRequest)(this, { method: route.method, path: route.path, body });
992
+ return (0, hosted_mappers_js_1.orderFromV0)(data);
993
+ }
994
+ /**
995
+ * Resolve the per-(venue, side, pull) typed-data schema route used by
996
+ * `validateTypedData` / `validateEconomics`. Returns undefined for the
997
+ * pull leg when a venue/side combo doesn't have one.
998
+ */
999
+ _hostedTypedDataRoute(side, isPull) {
1000
+ const venue = this.exchangeName;
1001
+ const sideLower = side.toLowerCase();
1002
+ if (venue === "polymarket") {
1003
+ return sideLower === "sell" ? "polymarket_sell" : "polymarket_buy";
1004
+ }
1005
+ // opinion
1006
+ if (sideLower === "buy")
1007
+ return "opinion_buy";
1008
+ // sell — polygon, or BSC pull leg for cross-chain
1009
+ return isPull ? "opinion_sell_bsc_pull" : "opinion_sell_polygon";
1010
+ }
1011
+ _hostedCancelTypedDataRoute(isPull) {
1012
+ if (this.exchangeName === "polymarket")
1013
+ return "cancel_polymarket";
1014
+ return isPull ? "cancel_opinion_bsc_pull" : "cancel_opinion_polygon";
1015
+ }
881
1016
  async cancelOrder(orderId) {
1017
+ if (this.isHostedTradingMode()) {
1018
+ return this._hostedCancelOrder(orderId);
1019
+ }
882
1020
  await this.initPromise;
883
1021
  try {
884
1022
  const args = [];
@@ -905,7 +1043,47 @@ class Exchange {
905
1043
  throw new errors_js_1.PmxtError(`Failed to cancelOrder: ${error}`);
906
1044
  }
907
1045
  }
1046
+ /**
1047
+ * Hosted-mode cancelOrder: build the cancel typed_data on the server,
1048
+ * validate + sign (dual-sign for Opinion cross-chain), then submit.
1049
+ */
1050
+ async _hostedCancelOrder(orderId) {
1051
+ const signer = this.requireHostedSigner();
1052
+ if (!this.walletAddress) {
1053
+ throw new hosted_errors_js_1.MissingWalletAddress("hosted cancelOrder requires walletAddress");
1054
+ }
1055
+ const buildRoute = hosted_routing_js_1.HOSTED_METHOD_ROUTES.get("cancelOrderBuild");
1056
+ const buildResp = await (0, hosted_routing_js_1._tradingRequest)(this, {
1057
+ method: buildRoute.method,
1058
+ path: buildRoute.path,
1059
+ body: { order_id: orderId },
1060
+ });
1061
+ const typedData = buildResp["typed_data"];
1062
+ if (!typedData) {
1063
+ throw new hosted_errors_js_1.InvalidSignature(0, "typed_data missing from cancel build response");
1064
+ }
1065
+ (0, hosted_typed_data_js_1.validateTypedData)(typedData, this._hostedCancelTypedDataRoute(false), this.walletAddress);
1066
+ const signature = await signer.signTypedData(typedData);
1067
+ (0, hosted_typed_data_js_1.verifySignature)(typedData, signature, signer.address);
1068
+ const body = {
1069
+ cancel_id: buildResp["cancel_id"],
1070
+ signature,
1071
+ };
1072
+ const pullTypedData = buildResp["pull_typed_data"];
1073
+ if (pullTypedData) {
1074
+ (0, hosted_typed_data_js_1.validateTypedData)(pullTypedData, this._hostedCancelTypedDataRoute(true), this.walletAddress);
1075
+ const pullSig = await signer.signTypedData(pullTypedData);
1076
+ (0, hosted_typed_data_js_1.verifySignature)(pullTypedData, pullSig, signer.address);
1077
+ body["pull_signature"] = pullSig;
1078
+ }
1079
+ const route = hosted_routing_js_1.HOSTED_METHOD_ROUTES.get("cancelOrder");
1080
+ const data = await (0, hosted_routing_js_1._tradingRequest)(this, { method: route.method, path: route.path, body });
1081
+ return (0, hosted_mappers_js_1.orderFromV0)(data);
1082
+ }
908
1083
  async fetchOrder(orderId) {
1084
+ if (this.isHostedTradingMode()) {
1085
+ return this._hostedFetchOrder(orderId);
1086
+ }
909
1087
  await this.initPromise;
910
1088
  try {
911
1089
  const args = [];
@@ -932,7 +1110,16 @@ class Exchange {
932
1110
  throw new errors_js_1.PmxtError(`Failed to fetchOrder: ${error}`);
933
1111
  }
934
1112
  }
1113
+ async _hostedFetchOrder(orderId) {
1114
+ const route = hosted_routing_js_1.HOSTED_METHOD_ROUTES.get("fetchOrder");
1115
+ const path = (0, hosted_routing_js_1.formatRoutePath)(route, { order_id: orderId });
1116
+ const data = await (0, hosted_routing_js_1._tradingRequest)(this, { method: route.method, path });
1117
+ return (0, hosted_mappers_js_1.orderFromV0)(data);
1118
+ }
935
1119
  async fetchOpenOrders(marketId) {
1120
+ if (this.isHostedTradingMode()) {
1121
+ return this._hostedFetchOpenOrders(marketId);
1122
+ }
936
1123
  await this.initPromise;
937
1124
  try {
938
1125
  const args = [];
@@ -960,7 +1147,24 @@ class Exchange {
960
1147
  throw new errors_js_1.PmxtError(`Failed to fetchOpenOrders: ${error}`);
961
1148
  }
962
1149
  }
1150
+ async _hostedFetchOpenOrders(marketId) {
1151
+ const address = (0, hosted_routing_js_1.resolveWalletAddress)(this, undefined);
1152
+ const route = hosted_routing_js_1.HOSTED_METHOD_ROUTES.get("fetchOpenOrders");
1153
+ const params = { address };
1154
+ if (marketId !== undefined)
1155
+ params["market_id"] = marketId;
1156
+ const data = await (0, hosted_routing_js_1._tradingRequest)(this, {
1157
+ method: route.method,
1158
+ path: route.path,
1159
+ params,
1160
+ });
1161
+ const items = (Array.isArray(data) ? data : data?.["orders"] ?? []);
1162
+ return items.map(hosted_mappers_js_1.orderFromV0);
1163
+ }
963
1164
  async fetchMyTrades(params) {
1165
+ if (this.isHostedTradingMode()) {
1166
+ return this._hostedFetchMyTrades(params);
1167
+ }
964
1168
  await this.initPromise;
965
1169
  try {
966
1170
  const args = [];
@@ -988,7 +1192,35 @@ class Exchange {
988
1192
  throw new errors_js_1.PmxtError(`Failed to fetchMyTrades: ${error}`);
989
1193
  }
990
1194
  }
1195
+ async _hostedFetchMyTrades(params) {
1196
+ const address = (0, hosted_routing_js_1.resolveWalletAddress)(this, undefined);
1197
+ const route = hosted_routing_js_1.HOSTED_METHOD_ROUTES.get("fetchMyTrades");
1198
+ const path = (0, hosted_routing_js_1.formatRoutePath)(route, { address });
1199
+ const q = {};
1200
+ if (params?.marketId)
1201
+ q["market_id"] = params.marketId;
1202
+ if (params?.outcomeId)
1203
+ q["outcome_id"] = params.outcomeId;
1204
+ if (params?.limit !== undefined)
1205
+ q["limit"] = String(params.limit);
1206
+ if (params?.cursor)
1207
+ q["cursor"] = params.cursor;
1208
+ if (params?.since)
1209
+ q["since"] = String(params.since.getTime());
1210
+ if (params?.until)
1211
+ q["until"] = String(params.until.getTime());
1212
+ const data = await (0, hosted_routing_js_1._tradingRequest)(this, {
1213
+ method: route.method,
1214
+ path,
1215
+ params: Object.keys(q).length ? q : undefined,
1216
+ });
1217
+ const items = (Array.isArray(data) ? data : data?.["trades"] ?? []);
1218
+ return items.map(hosted_mappers_js_1.userTradeFromV0);
1219
+ }
991
1220
  async fetchClosedOrders(params) {
1221
+ if (this.isHostedTradingMode()) {
1222
+ throw new errors_js_1.NotSupported("Settled orders are modeled as trades — use fetchMyTrades().");
1223
+ }
992
1224
  await this.initPromise;
993
1225
  try {
994
1226
  const args = [];
@@ -1017,6 +1249,9 @@ class Exchange {
1017
1249
  }
1018
1250
  }
1019
1251
  async fetchAllOrders(params) {
1252
+ if (this.isHostedTradingMode()) {
1253
+ throw new errors_js_1.NotSupported("Use fetchOpenOrders() and fetchMyTrades() separately.");
1254
+ }
1020
1255
  await this.initPromise;
1021
1256
  try {
1022
1257
  const args = [];
@@ -1045,6 +1280,9 @@ class Exchange {
1045
1280
  }
1046
1281
  }
1047
1282
  async fetchPositions(address) {
1283
+ if (this.isHostedTradingMode()) {
1284
+ return this._hostedFetchPositions(address);
1285
+ }
1048
1286
  await this.initPromise;
1049
1287
  try {
1050
1288
  const args = [];
@@ -1072,7 +1310,18 @@ class Exchange {
1072
1310
  throw new errors_js_1.PmxtError(`Failed to fetchPositions: ${error}`);
1073
1311
  }
1074
1312
  }
1313
+ async _hostedFetchPositions(address) {
1314
+ const resolvedAddr = (0, hosted_routing_js_1.resolveWalletAddress)(this, address);
1315
+ const route = hosted_routing_js_1.HOSTED_METHOD_ROUTES.get("fetchPositions");
1316
+ const path = (0, hosted_routing_js_1.formatRoutePath)(route, { address: resolvedAddr });
1317
+ const data = await (0, hosted_routing_js_1._tradingRequest)(this, { method: route.method, path });
1318
+ const items = (Array.isArray(data) ? data : data?.["positions"] ?? []);
1319
+ return items.map(hosted_mappers_js_1.positionFromV0);
1320
+ }
1075
1321
  async fetchBalance(address) {
1322
+ if (this.isHostedTradingMode()) {
1323
+ return this._hostedFetchBalance(address);
1324
+ }
1076
1325
  await this.initPromise;
1077
1326
  try {
1078
1327
  const args = [];
@@ -1100,6 +1349,18 @@ class Exchange {
1100
1349
  throw new errors_js_1.PmxtError(`Failed to fetchBalance: ${error}`);
1101
1350
  }
1102
1351
  }
1352
+ async _hostedFetchBalance(address) {
1353
+ const resolvedAddr = (0, hosted_routing_js_1.resolveWalletAddress)(this, address);
1354
+ const route = hosted_routing_js_1.HOSTED_METHOD_ROUTES.get("fetchBalance");
1355
+ const path = (0, hosted_routing_js_1.formatRoutePath)(route, { address: resolvedAddr });
1356
+ const data = await (0, hosted_routing_js_1._tradingRequest)(this, { method: route.method, path });
1357
+ // Hosted balance is a single USDC escrow record; wrap in an array
1358
+ // to match the existing Balance[] return shape.
1359
+ if (Array.isArray(data)) {
1360
+ return data.map(hosted_mappers_js_1.balanceFromV0);
1361
+ }
1362
+ return [(0, hosted_mappers_js_1.balanceFromV0)(data)];
1363
+ }
1103
1364
  async unwatchOrderBook(outcomeId) {
1104
1365
  await this.initPromise;
1105
1366
  try {
@@ -1772,6 +2033,9 @@ class Exchange {
1772
2033
  * ```
1773
2034
  */
1774
2035
  async buildOrder(params) {
2036
+ if (this.isHostedTradingMode()) {
2037
+ return this._hostedBuildOrder(params);
2038
+ }
1775
2039
  if (this.isHosted) {
1776
2040
  throw new errors_js_1.PmxtError("Trade execution is not available through the hosted API. " +
1777
2041
  "Use the local PMXT SDK with your venue credentials instead. " +
@@ -1902,6 +2166,106 @@ class Exchange {
1902
2166
  }
1903
2167
  return convertOrder(submitData);
1904
2168
  }
2169
+ /**
2170
+ * Hosted-mode buildOrder: validate inputs locally, then POST to the
2171
+ * trading service's `build-order` endpoint and return a BuiltOrder
2172
+ * that carries the original build_request for Layer-2 economic checks
2173
+ * at submit time.
2174
+ */
2175
+ async _hostedBuildOrder(params) {
2176
+ const body = this._hostedBuildOrderBody(params);
2177
+ const route = hosted_routing_js_1.HOSTED_METHOD_ROUTES.get("buildOrder");
2178
+ const data = await (0, hosted_routing_js_1._tradingRequest)(this, {
2179
+ method: route.method,
2180
+ path: route.path,
2181
+ body,
2182
+ });
2183
+ // Attach the originating build_request so submit can run economic
2184
+ // validation without an extra catalog round-trip.
2185
+ const built = { ...data, build_request: body };
2186
+ return built;
2187
+ }
2188
+ /**
2189
+ * Hosted-mode createOrder: build → sign → submit single-call wrapper.
2190
+ */
2191
+ async _hostedCreateOrder(params) {
2192
+ const built = await this._hostedBuildOrder(params);
2193
+ return this._hostedSubmitOrder(built);
2194
+ }
2195
+ /**
2196
+ * Construct the hosted build-order request body and validate inputs
2197
+ * locally per the v0 contract (denom/side compatibility, > 6-decimal
2198
+ * precision rejected via {@link to6dec}).
2199
+ */
2200
+ _hostedBuildOrderBody(params) {
2201
+ let marketId = params.marketId;
2202
+ let outcomeId = params.outcomeId;
2203
+ if (params.outcome) {
2204
+ if (marketId !== undefined || outcomeId !== undefined) {
2205
+ throw new errors_js_1.InvalidOrder("cannot specify both 'outcome' and 'marketId'/'outcomeId'");
2206
+ }
2207
+ const outcome = params.outcome;
2208
+ if (!outcome.marketId) {
2209
+ throw new errors_js_1.InvalidOrder("outcome.marketId is not set; ensure the outcome comes from a fetched market");
2210
+ }
2211
+ marketId = outcome.marketId;
2212
+ outcomeId = outcome.outcomeId;
2213
+ }
2214
+ const side = String(params.side);
2215
+ const orderType = String(params.type ?? "market");
2216
+ const denom = params["denom"];
2217
+ // denom/side compatibility per v0:
2218
+ // market buy -> denom='usdc'
2219
+ // market sell -> denom='shares'
2220
+ // any limit -> denom='shares'
2221
+ let resolvedDenom;
2222
+ if (orderType === "market") {
2223
+ if (side === "buy") {
2224
+ if (denom && denom !== "usdc") {
2225
+ throw new errors_js_1.InvalidOrder("market buy requires denom='usdc'");
2226
+ }
2227
+ resolvedDenom = "usdc";
2228
+ }
2229
+ else if (side === "sell") {
2230
+ if (denom && denom !== "shares") {
2231
+ throw new errors_js_1.InvalidOrder("market sell requires denom='shares'");
2232
+ }
2233
+ resolvedDenom = "shares";
2234
+ }
2235
+ else {
2236
+ throw new errors_js_1.InvalidOrder(`unknown side: ${side}`);
2237
+ }
2238
+ }
2239
+ else {
2240
+ if (denom && denom !== "shares") {
2241
+ throw new errors_js_1.InvalidOrder("limit orders require denom='shares'");
2242
+ }
2243
+ resolvedDenom = "shares";
2244
+ }
2245
+ if (!(Number(params.amount) > 0)) {
2246
+ throw new errors_js_1.InvalidOrder("amount must be positive");
2247
+ }
2248
+ // to6dec throws InvalidOrder for sub-micro precision.
2249
+ const amount6dec = (0, hosted_mappers_js_1.to6dec)(params.amount).toString();
2250
+ const body = {
2251
+ market_id: marketId,
2252
+ outcome_id: outcomeId,
2253
+ side,
2254
+ order_type: orderType,
2255
+ denom: resolvedDenom,
2256
+ amount: params.amount,
2257
+ amount_6dec: amount6dec,
2258
+ };
2259
+ if (params.price !== undefined)
2260
+ body["price"] = params.price;
2261
+ const extra = params;
2262
+ if (extra["slippage_pct"] !== undefined) {
2263
+ body["slippage_pct"] = extra["slippage_pct"];
2264
+ }
2265
+ if (this.walletAddress)
2266
+ body["user_address"] = this.walletAddress;
2267
+ return body;
2268
+ }
1905
2269
  /**
1906
2270
  * @example
1907
2271
  * ```typescript
@@ -1916,10 +2280,15 @@ class Exchange {
1916
2280
  * ```
1917
2281
  */
1918
2282
  async createOrder(params) {
2283
+ // SOR escape path (preserved): legacy hosted SOR flow uses a venue-side
2284
+ // SDK to execute the legs, only when a privateKey is present.
2285
+ if (this.isHosted && this.exchangeName === 'sor' && this.privateKey) {
2286
+ return this._executeSorOrder(params);
2287
+ }
2288
+ if (this.isHostedTradingMode()) {
2289
+ return this._hostedCreateOrder(params);
2290
+ }
1919
2291
  if (this.isHosted) {
1920
- if (this.exchangeName === 'sor' && this.privateKey) {
1921
- return this._executeSorOrder(params);
1922
- }
1923
2292
  throw new errors_js_1.PmxtError("Trade execution is not available through the hosted API. " +
1924
2293
  "Use the local PMXT SDK with your venue credentials instead. " +
1925
2294
  "See https://pmxt.dev/docs/quickstart for setup instructions.");
@@ -2565,15 +2934,40 @@ exports.Hyperliquid = Hyperliquid;
2565
2934
  /**
2566
2935
  * SuiBets exchange client.
2567
2936
  *
2937
+ * SuiBets is a decentralised P2P sports betting exchange on Sui mainnet.
2938
+ * No house edge. 2% platform fee.
2939
+ * Contract: 0xd51fe151bec66a15b086a67c1cfce9b05759ddac1d73fcd3e14324ad202b2e59
2940
+ *
2568
2941
  * @example
2569
2942
  * ```typescript
2570
2943
  * const suibets = new SuiBets();
2571
- * const markets = await suibets.fetchMarkets();
2944
+ * const markets = await suibets.fetchMarkets({ limit: 20 });
2945
+ *
2946
+ * // With wallet for fetchPositions()
2947
+ * const me = new SuiBets({ walletAddress: '0xabc...' });
2948
+ * const positions = await me.fetchPositions();
2572
2949
  * ```
2573
2950
  */
2574
2951
  class SuiBets extends Exchange {
2952
+ _walletAddress;
2575
2953
  constructor(options = {}) {
2576
2954
  super("suibets", options);
2955
+ this._walletAddress = options.walletAddress;
2956
+ }
2957
+ /**
2958
+ * Includes walletAddress in the credentials sent to the sidecar so
2959
+ * that fetchPositions() can reach the /api/p2p/my endpoint.
2960
+ * Falls back to SUIBETS_WALLET_ADDRESS env var on the sidecar side
2961
+ * when walletAddress is not set here.
2962
+ */
2963
+ getCredentials() {
2964
+ const base = super.getCredentials();
2965
+ if (!this._walletAddress)
2966
+ return base;
2967
+ return {
2968
+ ...(base ?? {}),
2969
+ walletAddress: this._walletAddress,
2970
+ };
2577
2971
  }
2578
2972
  }
2579
2973
  exports.SuiBets = SuiBets;
@@ -51,3 +51,14 @@ export declare function resolvePmxtBaseUrl(args: {
51
51
  pmxtApiKey?: string;
52
52
  isHosted: boolean;
53
53
  };
54
+ /**
55
+ * Lowercase 0x-prefixed escrow addresses that are pre-funded by pmxt for
56
+ * hosted trading. Orders routed through these addresses use the shared
57
+ * escrow balance rather than a per-venue deposit.
58
+ */
59
+ export declare const PREFUNDED_ESCROW_ADDRESSES: ReadonlySet<string>;
60
+ /**
61
+ * Lowercase 0x-prefixed escrow addresses that the hosted trading API treats
62
+ * as venue-owned escrows. Currently empty; populated as venues onboard.
63
+ */
64
+ export declare const VENUE_ESCROW_ADDRESSES: ReadonlySet<string>;
@@ -6,7 +6,7 @@
6
6
  * can be imported from any module without creating import cycles.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.ENV = exports.LOCAL_URL = exports.HOSTED_URL = void 0;
9
+ exports.VENUE_ESCROW_ADDRESSES = exports.PREFUNDED_ESCROW_ADDRESSES = exports.ENV = exports.LOCAL_URL = exports.HOSTED_URL = void 0;
10
10
  exports.resolvePmxtBaseUrl = resolvePmxtBaseUrl;
11
11
  /**
12
12
  * The hosted pmxt production endpoint.
@@ -62,3 +62,16 @@ function resolvePmxtBaseUrl(args) {
62
62
  return pick(exports.HOSTED_URL);
63
63
  return pick(exports.LOCAL_URL);
64
64
  }
65
+ /**
66
+ * Lowercase 0x-prefixed escrow addresses that are pre-funded by pmxt for
67
+ * hosted trading. Orders routed through these addresses use the shared
68
+ * escrow balance rather than a per-venue deposit.
69
+ */
70
+ exports.PREFUNDED_ESCROW_ADDRESSES = new Set([
71
+ "0x3ad326f78b1390b9a5dc5f00e7f62f8632de23e2",
72
+ ]);
73
+ /**
74
+ * Lowercase 0x-prefixed escrow addresses that the hosted trading API treats
75
+ * as venue-owned escrows. Currently empty; populated as venues onboard.
76
+ */
77
+ exports.VENUE_ESCROW_ADDRESSES = new Set();
@@ -51,5 +51,8 @@ export declare class NetworkError extends PmxtError {
51
51
  export declare class ExchangeNotAvailable extends PmxtError {
52
52
  constructor(message: string, exchange?: string);
53
53
  }
54
+ export declare class NotSupported extends PmxtError {
55
+ constructor(message: string, exchange?: string);
56
+ }
54
57
  /** Convert a server error response object into a typed PmxtError. */
55
58
  export declare function fromServerError(errorData: unknown): PmxtError;
@@ -6,7 +6,7 @@
6
6
  * enabling users to catch specific error types.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.ExchangeNotAvailable = exports.NetworkError = exports.ValidationError = exports.InsufficientFunds = exports.InvalidOrder = exports.RateLimitExceeded = exports.EventNotFound = exports.MarketNotFound = exports.OrderNotFound = exports.NotFoundError = exports.PermissionDenied = exports.AuthenticationError = exports.BadRequest = exports.PmxtError = void 0;
9
+ exports.NotSupported = exports.ExchangeNotAvailable = exports.NetworkError = exports.ValidationError = exports.InsufficientFunds = exports.InvalidOrder = exports.RateLimitExceeded = exports.EventNotFound = exports.MarketNotFound = exports.OrderNotFound = exports.NotFoundError = exports.PermissionDenied = exports.AuthenticationError = exports.BadRequest = exports.PmxtError = void 0;
10
10
  exports.fromServerError = fromServerError;
11
11
  class PmxtError extends Error {
12
12
  code;
@@ -108,6 +108,12 @@ class ExchangeNotAvailable extends PmxtError {
108
108
  }
109
109
  }
110
110
  exports.ExchangeNotAvailable = ExchangeNotAvailable;
111
+ class NotSupported extends PmxtError {
112
+ constructor(message, exchange) {
113
+ super(message, "NOT_SUPPORTED", false, exchange);
114
+ }
115
+ }
116
+ exports.NotSupported = NotSupported;
111
117
  // Error code to class mapping
112
118
  const ERROR_CODE_MAP = {
113
119
  BAD_REQUEST: BadRequest,
@@ -148,3 +154,7 @@ function fromServerError(errorData) {
148
154
  }
149
155
  return new PmxtError(message, code, retryable, exchange);
150
156
  }
157
+ // Hosted error classes live in ./hosted-errors. Re-exported from index.ts
158
+ // at the package root, NOT here — re-exporting from errors.ts creates a
159
+ // circular dependency (hosted-errors imports PmxtError from errors.ts)
160
+ // that crashes tsx/CJS module loaders even though tsc and ts-jest tolerate it.
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Hosted-mode escrow namespace.
3
+ *
4
+ * Exposes the `/v0/escrow/*` endpoints of the pmxt hosted trading API as a
5
+ * small ergonomic helper class. Each method returns the raw upstream JSON
6
+ * payload as `unknown` — typed mappers can be layered on later without
7
+ * breaking the wire shape.
8
+ *
9
+ * Mirrors `sdks/python/pmxt/escrow.py`.
10
+ */
11
+ import { HostedClientLike } from "./hosted-routing";
12
+ export declare class Escrow {
13
+ private readonly client;
14
+ constructor(client: HostedClientLike);
15
+ /**
16
+ * Build an unsigned approve transaction for a given ERC-20 `token`. When
17
+ * `amountWei` is omitted, the server returns an unlimited approval.
18
+ */
19
+ approveTx(token: string, amountWei?: bigint): Promise<unknown>;
20
+ /**
21
+ * Build an unsigned deposit transaction for `amount` (USDC, 6-decimal
22
+ * grid). Accepts number, decimal string, or BigInt in micro-units.
23
+ */
24
+ depositTx(amount: number | string | bigint): Promise<unknown>;
25
+ /**
26
+ * Build an unsigned withdraw transaction. `action` selects the stage of
27
+ * the withdrawal lifecycle: `request` initiates, `claim` finalizes after
28
+ * the timelock, `cancel` aborts a pending request.
29
+ */
30
+ withdrawTx(action: "request" | "claim" | "cancel", amount?: number | string | bigint): Promise<unknown>;
31
+ /**
32
+ * List the user's withdrawal records. `include` is forwarded verbatim and
33
+ * defaults to `"pending,events"` to match the Python SDK.
34
+ */
35
+ withdrawals(opts?: {
36
+ include?: string;
37
+ address?: string;
38
+ }): Promise<unknown>;
39
+ }