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.
- package/dist/esm/generated/src/models/OrderLevel.d.ts +6 -0
- package/dist/esm/generated/src/models/OrderLevel.js +2 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/pmxt/client.d.ts +106 -5
- package/dist/esm/pmxt/client.js +400 -6
- package/dist/esm/pmxt/constants.d.ts +11 -0
- package/dist/esm/pmxt/constants.js +13 -0
- package/dist/esm/pmxt/errors.d.ts +3 -0
- package/dist/esm/pmxt/errors.js +9 -0
- package/dist/esm/pmxt/escrow.d.ts +39 -0
- package/dist/esm/pmxt/escrow.js +78 -0
- package/dist/esm/pmxt/feed-client.d.ts +3 -0
- package/dist/esm/pmxt/feed-client.js +11 -2
- package/dist/esm/pmxt/hosted-errors.d.ts +84 -0
- package/dist/esm/pmxt/hosted-errors.js +186 -0
- package/dist/esm/pmxt/hosted-mappers.d.ts +45 -0
- package/dist/esm/pmxt/hosted-mappers.js +291 -0
- package/dist/esm/pmxt/hosted-routing.d.ts +69 -0
- package/dist/esm/pmxt/hosted-routing.js +119 -0
- package/dist/esm/pmxt/hosted-typed-data.d.ts +36 -0
- package/dist/esm/pmxt/hosted-typed-data.js +580 -0
- package/dist/esm/pmxt/models.d.ts +46 -8
- package/dist/esm/pmxt/server-manager.d.ts +4 -0
- package/dist/esm/pmxt/server-manager.js +6 -0
- package/dist/esm/pmxt/signers.d.ts +57 -0
- package/dist/esm/pmxt/signers.js +50 -0
- package/dist/esm/pmxt/ws-client.js +2 -1
- package/dist/generated/src/models/OrderLevel.d.ts +6 -0
- package/dist/generated/src/models/OrderLevel.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/pmxt/client.d.ts +106 -5
- package/dist/pmxt/client.js +399 -5
- package/dist/pmxt/constants.d.ts +11 -0
- package/dist/pmxt/constants.js +14 -1
- package/dist/pmxt/errors.d.ts +3 -0
- package/dist/pmxt/errors.js +11 -1
- package/dist/pmxt/escrow.d.ts +39 -0
- package/dist/pmxt/escrow.js +82 -0
- package/dist/pmxt/feed-client.d.ts +3 -0
- package/dist/pmxt/feed-client.js +11 -2
- package/dist/pmxt/hosted-errors.d.ts +84 -0
- package/dist/pmxt/hosted-errors.js +201 -0
- package/dist/pmxt/hosted-mappers.d.ts +45 -0
- package/dist/pmxt/hosted-mappers.js +302 -0
- package/dist/pmxt/hosted-routing.d.ts +69 -0
- package/dist/pmxt/hosted-routing.js +126 -0
- package/dist/pmxt/hosted-typed-data.d.ts +36 -0
- package/dist/pmxt/hosted-typed-data.js +619 -0
- package/dist/pmxt/models.d.ts +46 -8
- package/dist/pmxt/server-manager.d.ts +4 -0
- package/dist/pmxt/server-manager.js +6 -0
- package/dist/pmxt/signers.d.ts +57 -0
- package/dist/pmxt/signers.js +55 -0
- package/dist/pmxt/ws-client.js +2 -1
- package/generated/docs/OrderLevel.md +2 -0
- package/generated/package.json +1 -1
- package/generated/src/models/OrderLevel.ts +8 -0
- package/index.ts +1 -0
- package/package.json +11 -2
- package/pmxt/client.ts +495 -9
- package/pmxt/constants.ts +15 -0
- package/pmxt/errors.ts +11 -0
- package/pmxt/escrow.ts +93 -0
- package/pmxt/feed-client.ts +14 -2
- package/pmxt/hosted-errors.ts +216 -0
- package/pmxt/hosted-mappers.ts +312 -0
- package/pmxt/hosted-routing.ts +165 -0
- package/pmxt/hosted-typed-data.ts +767 -0
- package/pmxt/models.ts +65 -8
- package/pmxt/server-manager.ts +7 -0
- package/pmxt/signers.ts +86 -0
- package/pmxt/ws-client.ts +2 -1
package/dist/pmxt/client.js
CHANGED
|
@@ -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;
|
package/dist/pmxt/constants.d.ts
CHANGED
|
@@ -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>;
|
package/dist/pmxt/constants.js
CHANGED
|
@@ -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();
|
package/dist/pmxt/errors.d.ts
CHANGED
|
@@ -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;
|
package/dist/pmxt/errors.js
CHANGED
|
@@ -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
|
+
}
|