@polymarket/clob-client-v2 1.2.0-canary.1 → 1.2.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 (53) hide show
  1. package/README.md +40 -5
  2. package/dist/client.cjs +70 -40
  3. package/dist/client.cjs.map +1 -1
  4. package/dist/client.d.cts +16 -1
  5. package/dist/client.d.ts +16 -1
  6. package/dist/client.js +70 -40
  7. package/dist/client.js.map +1 -1
  8. package/dist/index.d.cts +2 -2
  9. package/dist/index.d.ts +2 -2
  10. package/dist/order-builder/helpers/buildMarketOrderCreationArgs.cjs +3 -2
  11. package/dist/order-builder/helpers/buildMarketOrderCreationArgs.cjs.map +1 -1
  12. package/dist/order-builder/helpers/buildMarketOrderCreationArgs.js +3 -2
  13. package/dist/order-builder/helpers/buildMarketOrderCreationArgs.js.map +1 -1
  14. package/dist/order-builder/helpers/buildOrderCreationArgs.cjs +3 -2
  15. package/dist/order-builder/helpers/buildOrderCreationArgs.cjs.map +1 -1
  16. package/dist/order-builder/helpers/buildOrderCreationArgs.js +3 -2
  17. package/dist/order-builder/helpers/buildOrderCreationArgs.js.map +1 -1
  18. package/dist/order-builder/helpers/createMarketOrder.cjs +6 -4
  19. package/dist/order-builder/helpers/createMarketOrder.cjs.map +1 -1
  20. package/dist/order-builder/helpers/createMarketOrder.js +6 -4
  21. package/dist/order-builder/helpers/createMarketOrder.js.map +1 -1
  22. package/dist/order-builder/helpers/createOrder.cjs +6 -4
  23. package/dist/order-builder/helpers/createOrder.cjs.map +1 -1
  24. package/dist/order-builder/helpers/createOrder.js +6 -4
  25. package/dist/order-builder/helpers/createOrder.js.map +1 -1
  26. package/dist/order-builder/helpers/orderAsset.cjs +18 -0
  27. package/dist/order-builder/helpers/orderAsset.cjs.map +1 -0
  28. package/dist/order-builder/helpers/orderAsset.js +16 -0
  29. package/dist/order-builder/helpers/orderAsset.js.map +1 -0
  30. package/dist/order-builder/orderBuilder.cjs +2 -2
  31. package/dist/order-builder/orderBuilder.cjs.map +1 -1
  32. package/dist/order-builder/orderBuilder.d.cts +2 -2
  33. package/dist/order-builder/orderBuilder.d.ts +2 -2
  34. package/dist/order-builder/orderBuilder.js +2 -2
  35. package/dist/order-builder/orderBuilder.js.map +1 -1
  36. package/dist/types/clob.cjs.map +1 -1
  37. package/dist/types/clob.d.cts +0 -1
  38. package/dist/types/clob.d.ts +0 -1
  39. package/dist/types/clob.js.map +1 -1
  40. package/dist/types/index.d.ts +1 -1
  41. package/dist/types/ordersV1.cjs.map +1 -1
  42. package/dist/types/ordersV1.d.cts +2 -0
  43. package/dist/types/ordersV1.d.ts +2 -0
  44. package/dist/types/ordersV1.js.map +1 -1
  45. package/dist/types/ordersV2.cjs.map +1 -1
  46. package/dist/types/ordersV2.d.cts +17 -13
  47. package/dist/types/ordersV2.d.ts +17 -13
  48. package/dist/types/ordersV2.js.map +1 -1
  49. package/package.json +1 -1
  50. package/dist/protocol.cjs +0 -22
  51. package/dist/protocol.cjs.map +0 -1
  52. package/dist/protocol.js +0 -21
  53. package/dist/protocol.js.map +0 -1
package/README.md CHANGED
@@ -46,12 +46,23 @@ const resp = await client.createAndPostOrder(
46
46
  console.log(resp);
47
47
  ```
48
48
 
49
- See [examples](examples/) for more information.
49
+ For a position-backed outcome, provide `positionID` instead. The client uses
50
+ the identifier field to select Exchange V3 signing automatically:
51
+
52
+ ```ts
53
+ const resp = await client.createAndPostOrder(
54
+ {
55
+ positionID: "", // position ID of the market outcome
56
+ price: 0.4,
57
+ side: Side.BUY,
58
+ size: 100,
59
+ },
60
+ { tickSize: "0.01" },
61
+ OrderType.GTC,
62
+ );
63
+ ```
50
64
 
51
- Limit and market orders automatically use Exchange V3 for protocol V2 position IDs.
52
- Legacy CTF token IDs use the server's exchange version. To override automatic
53
- selection, pass `version: 1`, `version: 2`, or `version: 3` in the order options,
54
- for example `{ tickSize: "0.01", version: 3 }`.
65
+ See [examples](examples/) for more information.
55
66
 
56
67
  ### Market Orders
57
68
 
@@ -72,6 +83,30 @@ const resp = await client.createAndPostMarketOrder(
72
83
  console.log(resp);
73
84
  ```
74
85
 
86
+ ### Warm up order cache metadata
87
+
88
+ The first order on a new client fetches the order version and the market's tick size,
89
+ neg-risk flag, and fee details before it can be signed. Both are public GET requests and
90
+ need no signer or credentials. To take them off the first trade, run them ahead of time
91
+ on the same client instance that will submit orders:
92
+
93
+ ```ts
94
+ await Promise.all([
95
+ client.getVersion(), // adopted as the order version for this client
96
+ client.getClobMarketInfo(conditionID), // caches tick size, neg risk, and fees for both outcomes
97
+ ]);
98
+ ```
99
+
100
+ Each call asks the server and refreshes the caches, so repeating it costs one request. If
101
+ the version request fails, `getVersion` adopts the default version 2 and the first order
102
+ corrects it through the mismatch recovery built into order posting. With `throwOnError`
103
+ both calls throw `ApiError` instead, so treat a rejected warm-up as a background failure.
104
+ A new client instance starts with empty caches. Order creation and `getVersion` reuse a
105
+ version or market request that is still in flight instead of starting another one. Orders
106
+ never require these calls. An order placed before `getClobMarketInfo` resolves still
107
+ performs its own token-to-market lookup. Books, balances, allowances, credentials, and
108
+ builder fee rates are not cached by these calls.
109
+
75
110
  ### Authentication
76
111
 
77
112
  The client has two authentication levels:
package/dist/client.cjs CHANGED
@@ -4,6 +4,7 @@ const require_errors = require('./errors.cjs');
4
4
  const require_index = require('./fees/index.cjs');
5
5
  const require_index$1 = require('./headers/index.cjs');
6
6
  const require_index$2 = require('./http-helpers/index.cjs');
7
+ const require_orderAsset = require('./order-builder/helpers/orderAsset.cjs');
7
8
  const require_signatureTypeV2 = require('./order-utils/model/signatureTypeV2.cjs');
8
9
  const require_side = require('./order-utils/model/side.cjs');
9
10
  const require_clob = require('./types/clob.cjs');
@@ -15,7 +16,6 @@ const require_calculateBuyMarketPrice = require('./order-builder/helpers/calcula
15
16
  const require_calculateSellMarketPrice = require('./order-builder/helpers/calculateSellMarketPrice.cjs');
16
17
  const require_roundingConfig = require('./order-builder/helpers/roundingConfig.cjs');
17
18
  const require_orderBuilder = require('./order-builder/orderBuilder.cjs');
18
- const require_protocol = require('./protocol.cjs');
19
19
 
20
20
  //#region src/client.ts
21
21
  const RESOLVE_TRADES_TIMEOUT_MS = 3e4;
@@ -40,6 +40,8 @@ var ClobClient = class {
40
40
  signatureType;
41
41
  funderAddress;
42
42
  cachedVersion;
43
+ versionRequest;
44
+ marketInfoRequests = /* @__PURE__ */ new Map();
43
45
  retryOnError;
44
46
  throwOnError;
45
47
  feeSlippage;
@@ -80,8 +82,26 @@ var ClobClient = class {
80
82
  data: { heartbeat_id: heartbeatId }
81
83
  });
82
84
  }
85
+ /**
86
+ * Fetches the current order version from the server and adopts it for the
87
+ * orders this client signs afterwards. Joins a version request that is
88
+ * already in flight. An error response yields the default version 2, which
89
+ * the first order corrects through the order version mismatch recovery.
90
+ * Throws ApiError when the client was created with throwOnError.
91
+ */
83
92
  async getVersion() {
84
- return (await this.get(`${this.host}/version`))?.version ?? 2;
93
+ return this.versionRequest ?? this.startVersionRequest();
94
+ }
95
+ startVersionRequest() {
96
+ const request = this.get(`${this.host}/version`).then((response) => {
97
+ const version = response?.version ?? 2;
98
+ this.cachedVersion = version;
99
+ return version;
100
+ }).finally(() => {
101
+ if (this.versionRequest === request) this.versionRequest = void 0;
102
+ });
103
+ this.versionRequest = request;
104
+ return request;
85
105
  }
86
106
  async getServerTime() {
87
107
  return this.get(`${this.host}${require_endpoints.TIME}`);
@@ -101,7 +121,23 @@ var ClobClient = class {
101
121
  async getMarket(conditionID) {
102
122
  return this.get(`${this.host}${require_endpoints.GET_MARKET}${conditionID}`);
103
123
  }
124
+ /**
125
+ * Fetches the market parameters for a condition and caches the tick size,
126
+ * neg-risk flag, and fee details of both outcomes for later orders. Every
127
+ * call refreshes the caches. Concurrent calls for a condition share one request.
128
+ */
104
129
  async getClobMarketInfo(conditionID) {
130
+ const pending = this.marketInfoRequests.get(conditionID);
131
+ if (pending) return pending;
132
+ const request = this.fetchClobMarketInfo(conditionID);
133
+ this.marketInfoRequests.set(conditionID, request);
134
+ try {
135
+ return await request;
136
+ } finally {
137
+ this.marketInfoRequests.delete(conditionID);
138
+ }
139
+ }
140
+ async fetchClobMarketInfo(conditionID) {
105
141
  const result = await this.get(`${this.host}${require_endpoints.GET_CLOB_MARKET}${conditionID}`);
106
142
  if (!result?.t) throw new Error(`failed to fetch market info for condition id ${conditionID}`);
107
143
  for (const token of result.t) {
@@ -430,16 +466,17 @@ var ClobClient = class {
430
466
  this.canL1Auth();
431
467
  const orderToSign = { ...userOrder };
432
468
  if (this.builderConfig?.builderCode && !orderToSign.builderCode) orderToSign.builderCode = this.builderConfig.builderCode;
433
- const { tokenID } = orderToSign;
434
- const tickSize = await this._resolveTickSize(tokenID, options?.tickSize);
469
+ const routing = require_orderAsset.resolveOrderRouting(orderToSign, options?.version);
470
+ const { assetID } = routing;
471
+ const tickSize = await this._resolveTickSize(assetID, options?.tickSize);
435
472
  if (!require_utilities.priceValid(orderToSign.price, tickSize)) throw new Error(`invalid price (${orderToSign.price}), min: ${parseFloat(tickSize)} - max: ${1 - parseFloat(tickSize)}`);
436
473
  orderToSign.price = require_utilities.roundNormal(orderToSign.price, require_roundingConfig.ROUNDING_CONFIG[tickSize].price);
437
- const version = await this.resolveOrderVersion(tokenID, options?.version);
438
- if (version !== 1 && orderToSign.side === require_side.Side.BUY && "userUSDCBalance" in orderToSign && orderToSign.userUSDCBalance !== void 0) orderToSign.size = await this.adjustBuyAmountForBalance(tokenID, orderToSign.size * orderToSign.price, orderToSign.price, orderToSign.userUSDCBalance, orderToSign.builderCode) / orderToSign.price;
439
- const negRisk = options?.negRisk ?? await this.getNegRisk(tokenID);
474
+ const version = routing.exchangeVersion ?? await this.resolveVersion();
475
+ if (version !== 1 && orderToSign.side === require_side.Side.BUY && "userUSDCBalance" in orderToSign && orderToSign.userUSDCBalance !== void 0) orderToSign.size = await this.adjustBuyAmountForBalance(assetID, orderToSign.size * orderToSign.price, orderToSign.price, orderToSign.userUSDCBalance, orderToSign.builderCode) / orderToSign.price;
476
+ const negRisk = version === 3 ? false : options?.negRisk ?? await this.getNegRisk(assetID);
440
477
  if (version === 1) {
441
478
  const userFeeRateBps = "feeRateBps" in orderToSign ? orderToSign.feeRateBps : void 0;
442
- orderToSign.feeRateBps = await this._resolveFeeRateBps(tokenID, userFeeRateBps);
479
+ orderToSign.feeRateBps = await this._resolveFeeRateBps(assetID, userFeeRateBps);
443
480
  }
444
481
  return this.orderBuilder.buildOrder(orderToSign, {
445
482
  tickSize,
@@ -448,23 +485,24 @@ var ClobClient = class {
448
485
  }
449
486
  async createMarketOrder(userMarketOrder, options) {
450
487
  this.canL1Auth();
451
- const { tokenID } = userMarketOrder;
452
- await this._ensureMarketInfoCached(tokenID);
453
- const tickSize = await this._resolveTickSize(tokenID, options?.tickSize);
454
- if (!userMarketOrder.price) userMarketOrder.price = await this.calculateMarketPrice(tokenID, userMarketOrder.side, userMarketOrder.amount, userMarketOrder.orderType);
488
+ const routing = require_orderAsset.resolveOrderRouting(userMarketOrder, options?.version);
489
+ const { assetID } = routing;
490
+ await this._ensureMarketInfoCached(assetID);
491
+ const tickSize = await this._resolveTickSize(assetID, options?.tickSize);
492
+ if (!userMarketOrder.price) userMarketOrder.price = await this.calculateMarketPrice(assetID, userMarketOrder.side, userMarketOrder.amount, userMarketOrder.orderType);
455
493
  if (!require_utilities.priceValid(userMarketOrder.price, tickSize)) throw new Error(`invalid price (${userMarketOrder.price}), min: ${parseFloat(tickSize)} - max: ${1 - parseFloat(tickSize)}`);
456
494
  const orderToSign = { ...userMarketOrder };
457
495
  if (this.builderConfig?.builderCode && !orderToSign.builderCode) orderToSign.builderCode = this.builderConfig.builderCode;
458
496
  await this.ensureBuilderFeeRateCached(orderToSign.builderCode);
459
497
  if (orderToSign.side === require_side.Side.BUY && "userUSDCBalance" in orderToSign && orderToSign.userUSDCBalance !== void 0) {
460
498
  const price = orderToSign.price;
461
- orderToSign.amount = await this.adjustBuyAmountForBalance(tokenID, orderToSign.amount, price, orderToSign.userUSDCBalance, orderToSign.builderCode);
499
+ orderToSign.amount = await this.adjustBuyAmountForBalance(assetID, orderToSign.amount, price, orderToSign.userUSDCBalance, orderToSign.builderCode);
462
500
  }
463
- const negRisk = options?.negRisk ?? await this.getNegRisk(tokenID);
464
- const version = await this.resolveOrderVersion(tokenID, options?.version);
501
+ const version = routing.exchangeVersion ?? await this.resolveVersion();
502
+ const negRisk = version === 3 ? false : options?.negRisk ?? await this.getNegRisk(assetID);
465
503
  if (version === 1) {
466
504
  const userFeeRateBps = "feeRateBps" in orderToSign ? orderToSign.feeRateBps : void 0;
467
- orderToSign.feeRateBps = await this._resolveFeeRateBps(tokenID, userFeeRateBps);
505
+ orderToSign.feeRateBps = await this._resolveFeeRateBps(assetID, userFeeRateBps);
468
506
  }
469
507
  return this.orderBuilder.buildMarketOrder(orderToSign, {
470
508
  tickSize,
@@ -478,20 +516,16 @@ var ClobClient = class {
478
516
  return this.orderBuilder.buildExchangeV3OrderFromAmounts(orderToSign);
479
517
  }
480
518
  async createAndPostOrder(userOrder, options, orderType = require_clob.OrderType.GTC, postOnly = false, deferExec = false) {
481
- let postOrderResponse;
482
- await this._retryOnVersionUpdate(userOrder.tokenID, options?.version, async () => {
519
+ return this._retryOnVersionUpdate(async () => {
483
520
  const order = await this.createOrder(userOrder, options);
484
- postOrderResponse = await this.postOrder(order, orderType, postOnly, deferExec);
521
+ return this.postOrder(order, orderType, postOnly, deferExec);
485
522
  });
486
- return postOrderResponse;
487
523
  }
488
524
  async createAndPostMarketOrder(userMarketOrder, options, orderType = require_clob.OrderType.FOK, deferExec = false) {
489
- let postOrderMarketResponse;
490
- await this._retryOnVersionUpdate(userMarketOrder.tokenID, options?.version, async () => {
525
+ return this._retryOnVersionUpdate(async () => {
491
526
  const order = await this.createMarketOrder(userMarketOrder, options);
492
- postOrderMarketResponse = await this.postOrder(order, orderType, false, deferExec);
527
+ return this.postOrder(order, orderType, false, deferExec);
493
528
  });
494
- return postOrderMarketResponse;
495
529
  }
496
530
  async getOpenOrders(params, only_first_page = false, next_cursor) {
497
531
  this.canL2Auth();
@@ -871,6 +905,7 @@ var ClobClient = class {
871
905
  if (!result?.condition_id) throw new Error(`failed to resolve condition id for token ${tokenID}`);
872
906
  this.tokenConditionMap[tokenID] = result.condition_id;
873
907
  }
908
+ if (tokenID in this.feeInfos) return;
874
909
  await this.getClobMarketInfo(this.tokenConditionMap[tokenID]);
875
910
  }
876
911
  async ensureBuilderFeeRateCached(builderCode) {
@@ -894,25 +929,20 @@ var ClobClient = class {
894
929
  if (marketFeeRateBps > 0 && userFeeRateBps !== void 0 && userFeeRateBps !== marketFeeRateBps) throw new Error(`invalid user provided fee rate: ${userFeeRateBps}, fee rate for the market must be ${marketFeeRateBps}`);
895
930
  return marketFeeRateBps;
896
931
  }
897
- async resolveOrderVersion(tokenID, version) {
898
- return version ?? (require_protocol.isV2PositionId(tokenID) ? 3 : this.resolveVersion());
899
- }
900
932
  async resolveVersion(forceUpdate = false) {
901
933
  if (!forceUpdate && this.cachedVersion !== void 0) return this.cachedVersion;
902
- const apiVersion = await this.getVersion();
903
- this.cachedVersion = apiVersion;
904
- return apiVersion;
905
- }
906
- async _retryOnVersionUpdate(tokenID, explicitVersion, retryFunc) {
907
- if (explicitVersion != null || require_protocol.isV2PositionId(tokenID)) {
908
- await retryFunc();
909
- return;
910
- }
911
- const version = await this.resolveVersion();
912
- for (let attempt = 0; attempt < 2; attempt++) {
913
- await retryFunc();
914
- if (version === await this.resolveVersion()) break;
934
+ if (!forceUpdate && this.versionRequest) return this.versionRequest;
935
+ return this.startVersionRequest();
936
+ }
937
+ async _retryOnVersionUpdate(attempt) {
938
+ try {
939
+ const response = await attempt();
940
+ if (!this._isOrderVersionMismatch(response)) return response;
941
+ } catch (err) {
942
+ const data = err instanceof require_errors.ApiError ? err.data : void 0;
943
+ if (!this._isOrderVersionMismatch(data)) throw err;
915
944
  }
945
+ return attempt();
916
946
  }
917
947
  _isOrderVersionMismatch(resp) {
918
948
  const error = resp?.error;