@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 +92 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -11
- package/dist/index.d.ts +47 -11
- package/dist/index.js +92 -50
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
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
|
|
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
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
1983
|
-
|
|
1984
|
-
orderToSign.amount = adjustBuyAmountForFees(
|
|
2009
|
+
orderToSign.amount = await this.adjustBuyAmountForBalance(
|
|
2010
|
+
tokenID,
|
|
1985
2011
|
orderToSign.amount,
|
|
1986
2012
|
price,
|
|
1987
|
-
userUSDCBalance,
|
|
1988
|
-
|
|
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)) {
|