@polymarket/clob-client-v2 1.0.3-canary.0 → 1.0.4

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/index.cjs CHANGED
@@ -141,6 +141,28 @@ var ApiError = class extends Error {
141
141
  }
142
142
  };
143
143
 
144
+ // src/fees/index.ts
145
+ var MIN_FEE_SLIPPAGE_PERCENTAGE = 1;
146
+ var MAX_FEE_SLIPPAGE_PERCENTAGE = 100;
147
+ function validateFeeSlippage(feeSlippage) {
148
+ if (!Number.isFinite(feeSlippage) || feeSlippage < 0 || feeSlippage > MAX_FEE_SLIPPAGE_PERCENTAGE || feeSlippage > 0 && feeSlippage < MIN_FEE_SLIPPAGE_PERCENTAGE) {
149
+ throw new Error("feeSlippage must be 0 or a percentage between 1 and 100");
150
+ }
151
+ }
152
+ function adjustBuyAmountForFees(amount, price, userUSDCBalance, feeRate, feeExponent, builderTakerFeeRate, feeSlippage = 0) {
153
+ validateFeeSlippage(feeSlippage);
154
+ const platformFeeRate = feeRate * (price * (1 - price)) ** feeExponent;
155
+ const effectivePlatformFeeRate = platformFeeRate * (1 + feeSlippage / 100);
156
+ const feeBaseAmount = Math.min(amount, userUSDCBalance);
157
+ const platformFee = feeBaseAmount / price * effectivePlatformFeeRate;
158
+ const builderFee = feeBaseAmount * builderTakerFeeRate;
159
+ const totalCost = amount + platformFee + builderFee;
160
+ if (userUSDCBalance <= totalCost) {
161
+ return Math.max(userUSDCBalance - platformFee - builderFee, 0);
162
+ }
163
+ return amount;
164
+ }
165
+
144
166
  // src/signing/constants.ts
145
167
  var MSG_TO_SIGN = "This message attests that I control the given wallet";
146
168
 
@@ -235,20 +257,34 @@ var buildClobEip712Signature = async (signer, chainId, timestamp, nonce, address
235
257
  };
236
258
 
237
259
  // src/signing/hmac.ts
238
- var import_node_crypto = __toESM(require("crypto"), 1);
239
- function replaceAll(s, search, replace) {
240
- return s.split(search).join(replace);
241
- }
242
- var buildPolyHmacSignature = (secret, timestamp, method, requestPath, body) => {
260
+ var buildPolyHmacSignature = async (secret, timestamp, method, requestPath, body) => {
243
261
  let message = timestamp + method + requestPath;
244
262
  if (body !== void 0) {
245
263
  message += body;
246
264
  }
247
- const base64Secret = Buffer.from(secret, "base64");
248
- const hmac = import_node_crypto.default.createHmac("sha256", base64Secret);
249
- const sig = hmac.update(message).digest("base64");
250
- const sigUrlSafe = replaceAll(replaceAll(sig, "+", "-"), "/", "_");
251
- return sigUrlSafe;
265
+ const binarySecret = atob(secret);
266
+ const keyBytes = new Uint8Array(binarySecret.length);
267
+ for (let i = 0; i < binarySecret.length; i++) {
268
+ keyBytes[i] = binarySecret.charCodeAt(i);
269
+ }
270
+ const key = await globalThis.crypto.subtle.importKey(
271
+ "raw",
272
+ keyBytes,
273
+ { name: "HMAC", hash: "SHA-256" },
274
+ false,
275
+ ["sign"]
276
+ );
277
+ const sigBuffer = await globalThis.crypto.subtle.sign(
278
+ "HMAC",
279
+ key,
280
+ new TextEncoder().encode(message)
281
+ );
282
+ const sigBytes = new Uint8Array(sigBuffer);
283
+ let binary = "";
284
+ for (let i = 0; i < sigBytes.length; i++) {
285
+ binary += String.fromCharCode(sigBytes[i]);
286
+ }
287
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_");
252
288
  };
253
289
 
254
290
  // src/headers/index.ts
@@ -277,7 +313,7 @@ var createL2Headers = async (signer, creds, l2HeaderArgs, timestamp) => {
277
313
  ts = timestamp;
278
314
  }
279
315
  const address = await getSignerAddress(signer);
280
- const sig = buildPolyHmacSignature(
316
+ const sig = await buildPolyHmacSignature(
281
317
  creds.secret,
282
318
  ts,
283
319
  l2HeaderArgs.method,
@@ -329,7 +365,6 @@ var post = async (endpoint, options, retryOnError = false) => {
329
365
  return resp.data;
330
366
  } catch (err) {
331
367
  if (retryOnError && isTransientAxiosError(err)) {
332
- console.log("[CLOB Client-v2] transient error, retrying once after 30 ms");
333
368
  await sleep(30);
334
369
  try {
335
370
  const resp = await request(
@@ -372,15 +407,6 @@ var del = async (endpoint, options) => {
372
407
  var errorHandling = (err) => {
373
408
  if (import_axios.default.isAxiosError(err)) {
374
409
  if (err.response) {
375
- console.error(
376
- "[CLOB Client] request error",
377
- JSON.stringify({
378
- status: err.response?.status,
379
- statusText: err.response?.statusText,
380
- data: err.response?.data,
381
- config: err.response?.config
382
- })
383
- );
384
410
  if (err.response?.data) {
385
411
  if (typeof err.response?.data === "string" || err.response?.data instanceof String) {
386
412
  return { error: err.response?.data, status: err.response?.status };
@@ -392,16 +418,9 @@ var errorHandling = (err) => {
392
418
  }
393
419
  }
394
420
  if (err.message) {
395
- console.error(
396
- "[CLOB Client] request error",
397
- JSON.stringify({
398
- error: err.message
399
- })
400
- );
401
421
  return { error: err.message };
402
422
  }
403
423
  }
404
- console.error("[CLOB Client] request error", err);
405
424
  return { error: err };
406
425
  };
407
426
  var isTransientAxiosError = (err) => {
@@ -1030,7 +1049,6 @@ function isV2Order(order) {
1030
1049
  }
1031
1050
 
1032
1051
  // src/utilities.ts
1033
- var import_node_crypto2 = require("crypto");
1034
1052
  var roundNormal = (num, decimals) => {
1035
1053
  if (decimalPlaces(num) <= decimals) {
1036
1054
  return num;
@@ -1059,9 +1077,12 @@ var decimalPlaces = (num) => {
1059
1077
  }
1060
1078
  return arr[1].length;
1061
1079
  };
1062
- var generateOrderBookSummaryHash = (orderbook) => {
1080
+ var generateOrderBookSummaryHash = async (orderbook) => {
1063
1081
  orderbook.hash = "";
1064
- const hash = (0, import_node_crypto2.createHash)("sha1").update(JSON.stringify(orderbook)).digest("hex");
1082
+ const data = new TextEncoder().encode(JSON.stringify(orderbook));
1083
+ const hashBuffer = await globalThis.crypto.subtle.digest("SHA-1", data);
1084
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
1085
+ const hash = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
1065
1086
  orderbook.hash = hash;
1066
1087
  return hash;
1067
1088
  };
@@ -1372,15 +1393,6 @@ var OrderBuilder = class {
1372
1393
  };
1373
1394
 
1374
1395
  // src/client.ts
1375
- function adjustBuyAmountForFees(amount, price, userUSDCBalance, feeRate, feeExponent, builderTakerFeeRate) {
1376
- const platformFeeRate = feeRate * (price * (1 - price)) ** feeExponent;
1377
- const platformFee = amount / price * platformFeeRate;
1378
- const totalCost = amount + platformFee + amount * builderTakerFeeRate;
1379
- if (userUSDCBalance <= totalCost) {
1380
- return userUSDCBalance / (1 + platformFeeRate / price + builderTakerFeeRate);
1381
- }
1382
- return amount;
1383
- }
1384
1396
  var ClobClient = class {
1385
1397
  host;
1386
1398
  chainId;
@@ -1403,6 +1415,7 @@ var ClobClient = class {
1403
1415
  cachedVersion;
1404
1416
  retryOnError;
1405
1417
  throwOnError;
1418
+ feeSlippage;
1406
1419
  constructor({
1407
1420
  host,
1408
1421
  chain,
@@ -1414,7 +1427,8 @@ var ClobClient = class {
1414
1427
  builderConfig,
1415
1428
  getSigner,
1416
1429
  retryOnError,
1417
- throwOnError
1430
+ throwOnError,
1431
+ feeSlippage
1418
1432
  }) {
1419
1433
  this.host = host.endsWith("/") ? host.slice(0, -1) : host;
1420
1434
  this.chainId = chain;
@@ -1441,6 +1455,8 @@ var ClobClient = class {
1441
1455
  this.tokenConditionMap = {};
1442
1456
  this.retryOnError = retryOnError;
1443
1457
  this.throwOnError = throwOnError;
1458
+ this.feeSlippage = feeSlippage ?? 0;
1459
+ validateFeeSlippage(this.feeSlippage);
1444
1460
  this.useServerTime = useServerTime;
1445
1461
  if (builderConfig !== void 0) {
1446
1462
  this.builderConfig = builderConfig;
@@ -1574,7 +1590,7 @@ var ClobClient = class {
1574
1590
  * @param orderbook
1575
1591
  * @returns
1576
1592
  */
1577
- getOrderBookHash(orderbook) {
1593
+ async getOrderBookHash(orderbook) {
1578
1594
  return generateOrderBookSummaryHash(orderbook);
1579
1595
  }
1580
1596
  async getMidpoint(tokenID) {
@@ -1938,8 +1954,19 @@ var ClobClient = class {
1938
1954
  `invalid price (${orderToSign.price}), min: ${parseFloat(tickSize)} - max: ${1 - parseFloat(tickSize)}`
1939
1955
  );
1940
1956
  }
1941
- const negRisk = options?.negRisk ?? await this.getNegRisk(tokenID);
1957
+ orderToSign.price = roundNormal(orderToSign.price, ROUNDING_CONFIG[tickSize].price);
1942
1958
  const version = await this.resolveVersion();
1959
+ if (version === 2 && orderToSign.side === "BUY" /* BUY */ && "userUSDCBalance" in orderToSign && orderToSign.userUSDCBalance !== void 0) {
1960
+ const adjustedAmount = await this.adjustBuyAmountForBalance(
1961
+ tokenID,
1962
+ orderToSign.size * orderToSign.price,
1963
+ orderToSign.price,
1964
+ orderToSign.userUSDCBalance,
1965
+ orderToSign.builderCode
1966
+ );
1967
+ orderToSign.size = adjustedAmount / orderToSign.price;
1968
+ }
1969
+ const negRisk = options?.negRisk ?? await this.getNegRisk(tokenID);
1943
1970
  if (version === 1) {
1944
1971
  const userFeeRateBps = "feeRateBps" in orderToSign ? orderToSign.feeRateBps : void 0;
1945
1972
  const feeRateBps = await this._resolveFeeRateBps(tokenID, userFeeRateBps);
@@ -1979,15 +2006,12 @@ var ClobClient = class {
1979
2006
  await this.ensureBuilderFeeRateCached(orderToSign.builderCode);
1980
2007
  if (orderToSign.side === "BUY" /* BUY */ && "userUSDCBalance" in orderToSign && orderToSign.userUSDCBalance !== void 0) {
1981
2008
  const price = orderToSign.price;
1982
- const { userUSDCBalance } = orderToSign;
1983
- const builderTakerFeeRate = this.isBuilderOrder(orderToSign.builderCode) ? this.builderFeeRates[orderToSign.builderCode ?? ""]?.taker ?? 0 : 0;
1984
- orderToSign.amount = adjustBuyAmountForFees(
2009
+ orderToSign.amount = await this.adjustBuyAmountForBalance(
2010
+ tokenID,
1985
2011
  orderToSign.amount,
1986
2012
  price,
1987
- userUSDCBalance,
1988
- this.feeInfos[tokenID].rate,
1989
- this.feeInfos[tokenID].exponent,
1990
- builderTakerFeeRate
2013
+ orderToSign.userUSDCBalance,
2014
+ orderToSign.builderCode
1991
2015
  );
1992
2016
  }
1993
2017
  const negRisk = options?.negRisk ?? await this.getNegRisk(tokenID);
@@ -2447,6 +2471,24 @@ var ClobClient = class {
2447
2471
  isBuilderOrder(builderCode) {
2448
2472
  return builderCode !== void 0 && builderCode !== bytes32Zero;
2449
2473
  }
2474
+ async getBuilderTakerFeeRate(builderCode) {
2475
+ if (!this.isBuilderOrder(builderCode)) return 0;
2476
+ await this.ensureBuilderFeeRateCached(builderCode);
2477
+ return this.builderFeeRates[builderCode ?? ""]?.taker ?? 0;
2478
+ }
2479
+ async adjustBuyAmountForBalance(tokenID, amount, price, userUSDCBalance, builderCode) {
2480
+ await this._ensureMarketInfoCached(tokenID);
2481
+ const builderTakerFeeRate = await this.getBuilderTakerFeeRate(builderCode);
2482
+ return adjustBuyAmountForFees(
2483
+ amount,
2484
+ price,
2485
+ userUSDCBalance,
2486
+ this.feeInfos[tokenID].rate,
2487
+ this.feeInfos[tokenID].exponent,
2488
+ builderTakerFeeRate,
2489
+ this.feeSlippage
2490
+ );
2491
+ }
2450
2492
  async _ensureMarketInfoCached(tokenID) {
2451
2493
  if (tokenID in this.feeInfos) return;
2452
2494
  if (!(tokenID in this.tokenConditionMap)) {