@pear-protocol/utils 1.2.0 → 1.4.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/copy/equity-fraction.d.ts +13 -0
- package/dist/copy/index.d.ts +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +220 -127
- package/dist/position/key.d.ts +2 -2
- package/dist/precise-price.d.ts +25 -3
- package/dist/reduce-only-minimum.d.ts +42 -0
- package/dist/sync/applicables/fills.d.ts +1 -1
- package/dist/sync/compute.d.ts +3 -8
- package/dist/sync/types.d.ts +0 -2
- package/dist/validate-quantity.d.ts +3 -2
- package/package.json +2 -2
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Pure gross-notional valuation for copy sizing. */
|
|
2
|
+
import type { Fill, InstrumentPriceMap, PositionExposure, TradeLeg, UnsignedDecimalString } from '@pear-protocol/types';
|
|
3
|
+
/** Size a non-empty set of validated positive fill notionals without a market-price lookup. */
|
|
4
|
+
export declare function computeFilledEntrySizing(fills: ReadonlyArray<Pick<Fill, 'symbol' | 'usd'>>, equity: UnsignedDecimalString): {
|
|
5
|
+
equityFraction: UnsignedDecimalString;
|
|
6
|
+
legNotionals: Record<string, UnsignedDecimalString>;
|
|
7
|
+
};
|
|
8
|
+
/** Value signed exposure against equity; missing prices contribute no notional. */
|
|
9
|
+
export declare function computeEquityFraction(exposure: PositionExposure, priceMap: InstrumentPriceMap, equity: UnsignedDecimalString): UnsignedDecimalString;
|
|
10
|
+
/** Value USD and quantity entry legs; missing quantity prices contribute no notional. */
|
|
11
|
+
export declare function computeEntryEquityFraction(legs: ReadonlyArray<Pick<TradeLeg, 'symbol' | 'mode' | 'amount'>>, priceMap: InstrumentPriceMap, equity: UnsignedDecimalString): UnsignedDecimalString;
|
|
12
|
+
/** Divide valued notional by validated positive equity without capping leverage. */
|
|
13
|
+
export declare function computeNotionalEquityFraction(notional: Fill['usd'], equity: UnsignedDecimalString): UnsignedDecimalString;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './equity-fraction';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
export * from './asset/index';
|
|
2
2
|
export * from './basket/index';
|
|
3
3
|
export * from './contract-size';
|
|
4
|
+
export * from './copy/index';
|
|
4
5
|
export * from './fills/index';
|
|
5
6
|
export * from './math/index';
|
|
6
7
|
export * from './position/index';
|
|
7
8
|
export * from './precise-price';
|
|
8
9
|
export * from './precise-quantity';
|
|
9
10
|
export * from './proxy';
|
|
11
|
+
export * from './reduce-only-minimum';
|
|
10
12
|
export * from './sync/index';
|
|
11
13
|
export * from './validate-leverage';
|
|
12
14
|
export * from './validate-quantity';
|
package/dist/index.js
CHANGED
|
@@ -875,6 +875,61 @@ function baseToContracts(base, contractSize) {
|
|
|
875
875
|
}
|
|
876
876
|
__name(baseToContracts, "baseToContracts");
|
|
877
877
|
|
|
878
|
+
// src/copy/equity-fraction.ts
|
|
879
|
+
function computeFilledEntrySizing(fills, equity) {
|
|
880
|
+
const notionals = /* @__PURE__ */ new Map();
|
|
881
|
+
let total = parse("0");
|
|
882
|
+
for (const fill of fills) {
|
|
883
|
+
const notional = parse(fill.usd);
|
|
884
|
+
notionals.set(fill.symbol, (notionals.get(fill.symbol) ?? parse("0")).plus(notional));
|
|
885
|
+
total = total.plus(notional);
|
|
886
|
+
}
|
|
887
|
+
const legNotionals = {};
|
|
888
|
+
for (const [symbol, notional] of notionals) {
|
|
889
|
+
legNotionals[symbol] = notional.toFixed();
|
|
890
|
+
}
|
|
891
|
+
return {
|
|
892
|
+
equityFraction: computeNotionalEquityFraction(total.toFixed(), equity),
|
|
893
|
+
legNotionals
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
__name(computeFilledEntrySizing, "computeFilledEntrySizing");
|
|
897
|
+
function computeEquityFraction(exposure, priceMap, equity) {
|
|
898
|
+
let notional = parse("0");
|
|
899
|
+
for (const [symbol, quantity] of Object.entries(exposure)) {
|
|
900
|
+
const price = priceMap[symbol];
|
|
901
|
+
if (price !== void 0) {
|
|
902
|
+
notional = notional.plus(parse(quantity).abs().multipliedBy(price));
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
return computeNotionalEquityFraction(notional.toFixed(), equity);
|
|
906
|
+
}
|
|
907
|
+
__name(computeEquityFraction, "computeEquityFraction");
|
|
908
|
+
function computeEntryEquityFraction(legs, priceMap, equity) {
|
|
909
|
+
let notional = parse("0");
|
|
910
|
+
for (const leg of legs) {
|
|
911
|
+
const amount = parse(leg.amount).abs();
|
|
912
|
+
switch (leg.mode) {
|
|
913
|
+
case "USD":
|
|
914
|
+
notional = notional.plus(amount);
|
|
915
|
+
break;
|
|
916
|
+
case "QUANTITY": {
|
|
917
|
+
const price = priceMap[leg.symbol];
|
|
918
|
+
if (price !== void 0) {
|
|
919
|
+
notional = notional.plus(amount.multipliedBy(price));
|
|
920
|
+
}
|
|
921
|
+
break;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
return computeNotionalEquityFraction(notional.toFixed(), equity);
|
|
926
|
+
}
|
|
927
|
+
__name(computeEntryEquityFraction, "computeEntryEquityFraction");
|
|
928
|
+
function computeNotionalEquityFraction(notional, equity) {
|
|
929
|
+
return parse(notional).dividedBy(equity).toFixed();
|
|
930
|
+
}
|
|
931
|
+
__name(computeNotionalEquityFraction, "computeNotionalEquityFraction");
|
|
932
|
+
|
|
878
933
|
// src/fills/group.ts
|
|
879
934
|
function groupFillsByPosition(fills) {
|
|
880
935
|
const byPosition = /* @__PURE__ */ new Map();
|
|
@@ -1133,21 +1188,56 @@ BigNumber7.config({
|
|
|
1133
1188
|
DECIMAL_PLACES: 30,
|
|
1134
1189
|
ROUNDING_MODE: BigNumber7.ROUND_DOWN
|
|
1135
1190
|
});
|
|
1136
|
-
|
|
1191
|
+
var InvalidPriceError = class extends Error {
|
|
1192
|
+
static {
|
|
1193
|
+
__name(this, "InvalidPriceError");
|
|
1194
|
+
}
|
|
1195
|
+
};
|
|
1196
|
+
function precisePrice(connector, raw, precision, side = "BUY", slippageToleranceBps = 0, rounding = "marketable") {
|
|
1137
1197
|
const normalized = normalizePrice(raw);
|
|
1198
|
+
if (!normalized.isFinite() || !normalized.isGreaterThan(0)) {
|
|
1199
|
+
throw new InvalidPriceError(`Price ${String(raw)} is not a positive, finite price`);
|
|
1200
|
+
}
|
|
1138
1201
|
const effectiveRaw = withSlippageTolerance(normalized, slippageToleranceBps, side);
|
|
1202
|
+
const roundingMode = resolveRoundingMode(side, rounding);
|
|
1203
|
+
const precise = preciseOnGrid(connector, effectiveRaw, precision, roundingMode);
|
|
1204
|
+
const clampsToOneStep = rounding === "marketable" && side === "SELL" && !new BigNumber7(precise).isGreaterThan(0);
|
|
1205
|
+
const result = clampsToOneStep ? smallestGridPrice(connector, precision) : precise;
|
|
1206
|
+
const resultBN = new BigNumber7(result);
|
|
1207
|
+
if (!resultBN.isFinite() || !resultBN.isGreaterThan(0)) {
|
|
1208
|
+
throw new InvalidPriceError(`Price ${effectiveRaw.toFixed()} has no valid ${side} price on the grid`);
|
|
1209
|
+
}
|
|
1210
|
+
return result;
|
|
1211
|
+
}
|
|
1212
|
+
__name(precisePrice, "precisePrice");
|
|
1213
|
+
function preciseOnGrid(connector, price, precision, rounding) {
|
|
1139
1214
|
switch (connector) {
|
|
1140
1215
|
case "hyperliquid":
|
|
1141
|
-
return preciseHyperliquidPrice(
|
|
1216
|
+
return preciseHyperliquidPrice(price, precision, rounding);
|
|
1142
1217
|
case "binance":
|
|
1143
1218
|
case "bybit":
|
|
1144
1219
|
case "okx":
|
|
1145
1220
|
case "lighter":
|
|
1146
1221
|
case "lighter_rhc":
|
|
1147
|
-
return preciseTickGridPrice(
|
|
1222
|
+
return preciseTickGridPrice(price, precision, rounding);
|
|
1148
1223
|
}
|
|
1149
1224
|
}
|
|
1150
|
-
__name(
|
|
1225
|
+
__name(preciseOnGrid, "preciseOnGrid");
|
|
1226
|
+
function smallestGridPrice(connector, precision) {
|
|
1227
|
+
return preciseOnGrid(connector, new BigNumber7(1).shiftedBy(-precision.price.decimals), precision, BigNumber7.ROUND_CEIL);
|
|
1228
|
+
}
|
|
1229
|
+
__name(smallestGridPrice, "smallestGridPrice");
|
|
1230
|
+
function resolveRoundingMode(side, rounding) {
|
|
1231
|
+
switch (rounding) {
|
|
1232
|
+
// Towards crossing: the buffer survives rounding.
|
|
1233
|
+
case "marketable":
|
|
1234
|
+
return side === "BUY" ? BigNumber7.ROUND_CEIL : BigNumber7.ROUND_FLOOR;
|
|
1235
|
+
// Away from crossing: the limit holds.
|
|
1236
|
+
case "within_limit":
|
|
1237
|
+
return side === "BUY" ? BigNumber7.ROUND_FLOOR : BigNumber7.ROUND_CEIL;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
__name(resolveRoundingMode, "resolveRoundingMode");
|
|
1151
1241
|
function withSlippageTolerance(normalized, slippageToleranceBps, side) {
|
|
1152
1242
|
if (slippageToleranceBps === 0) {
|
|
1153
1243
|
return normalized;
|
|
@@ -1157,18 +1247,16 @@ function withSlippageTolerance(normalized, slippageToleranceBps, side) {
|
|
|
1157
1247
|
return side === "BUY" ? normalized.times(new BigNumber7(1).plus(factor)) : normalized.times(new BigNumber7(1).minus(factor));
|
|
1158
1248
|
}
|
|
1159
1249
|
__name(withSlippageTolerance, "withSlippageTolerance");
|
|
1160
|
-
function preciseHyperliquidPrice(price, precision,
|
|
1250
|
+
function preciseHyperliquidPrice(price, precision, rounding) {
|
|
1161
1251
|
const maxDecimals = precision.price.decimals;
|
|
1162
1252
|
const maxSigFigs = precision.price.sigFigs ?? 5;
|
|
1163
|
-
const rounding = side === "BUY" ? BigNumber7.ROUND_FLOOR : BigNumber7.ROUND_CEIL;
|
|
1164
1253
|
price = price.decimalPlaces(maxDecimals, rounding);
|
|
1165
1254
|
price = clampSigFigs(price, maxSigFigs, maxDecimals, rounding);
|
|
1166
1255
|
return price.toFixed();
|
|
1167
1256
|
}
|
|
1168
1257
|
__name(preciseHyperliquidPrice, "preciseHyperliquidPrice");
|
|
1169
|
-
function preciseTickGridPrice(price, precision,
|
|
1258
|
+
function preciseTickGridPrice(price, precision, rounding) {
|
|
1170
1259
|
const tick = precision.price.tick ?? 1e-4;
|
|
1171
|
-
const rounding = side === "BUY" ? BigNumber7.ROUND_FLOOR : BigNumber7.ROUND_CEIL;
|
|
1172
1260
|
const tickBN = new BigNumber7(tick);
|
|
1173
1261
|
const scaled = price.div(tickBN);
|
|
1174
1262
|
const snapped = scaled.integerValue(rounding).times(tickBN);
|
|
@@ -1182,13 +1270,13 @@ function clampSigFigs(price, maxSigFigs, maxDecimals, rounding) {
|
|
|
1182
1270
|
if (countSigFigs(price) <= maxSigFigs) {
|
|
1183
1271
|
return price;
|
|
1184
1272
|
}
|
|
1185
|
-
for (let decimals = maxDecimals; decimals >=
|
|
1273
|
+
for (let decimals = maxDecimals; decimals >= 1; decimals--) {
|
|
1186
1274
|
const candidate = price.decimalPlaces(decimals, rounding);
|
|
1187
1275
|
if (countSigFigs(candidate) <= maxSigFigs) {
|
|
1188
1276
|
return candidate;
|
|
1189
1277
|
}
|
|
1190
1278
|
}
|
|
1191
|
-
return price;
|
|
1279
|
+
return price.decimalPlaces(0, rounding);
|
|
1192
1280
|
}
|
|
1193
1281
|
__name(clampSigFigs, "clampSigFigs");
|
|
1194
1282
|
function normalizePrice(value) {
|
|
@@ -1275,6 +1363,85 @@ function proxyFetch(input, init) {
|
|
|
1275
1363
|
}), () => fetch(input, init));
|
|
1276
1364
|
}
|
|
1277
1365
|
__name(proxyFetch, "proxyFetch");
|
|
1366
|
+
function validateQuantity(quantity, price, precision) {
|
|
1367
|
+
const parsedQuantity = new BigNumber7(quantity);
|
|
1368
|
+
if (!parsedQuantity.isFinite() || parsedQuantity.lte(0)) {
|
|
1369
|
+
return false;
|
|
1370
|
+
}
|
|
1371
|
+
const parsedPrice = new BigNumber7(price);
|
|
1372
|
+
if (!parsedPrice.isFinite() || parsedPrice.lte(0)) {
|
|
1373
|
+
return false;
|
|
1374
|
+
}
|
|
1375
|
+
const step = new BigNumber7(precision.quantity.step);
|
|
1376
|
+
const scaled = parsedQuantity.div(step);
|
|
1377
|
+
if (!scaled.isInteger()) {
|
|
1378
|
+
return false;
|
|
1379
|
+
}
|
|
1380
|
+
const minQuantity = precision.quantity.min;
|
|
1381
|
+
if (minQuantity !== void 0 && minQuantity !== null && parsedQuantity.lt(minQuantity)) {
|
|
1382
|
+
return false;
|
|
1383
|
+
}
|
|
1384
|
+
const notional = contractsToBase(parsedQuantity, precision.quantity.contractSize).times(parsedPrice);
|
|
1385
|
+
if (precision.notional?.min !== void 0 && precision.notional.min !== null && precision.notional.min > 0) {
|
|
1386
|
+
if (notional.lt(new BigNumber7(precision.notional.min))) {
|
|
1387
|
+
return false;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
if (precision.notional?.max !== void 0 && precision.notional.max !== null && precision.notional.max > 0) {
|
|
1391
|
+
if (notional.gt(new BigNumber7(precision.notional.max))) {
|
|
1392
|
+
return false;
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
return true;
|
|
1396
|
+
}
|
|
1397
|
+
__name(validateQuantity, "validateQuantity");
|
|
1398
|
+
|
|
1399
|
+
// src/reduce-only-minimum.ts
|
|
1400
|
+
function findWholeCloseQuantity(input) {
|
|
1401
|
+
if (input.heldByAnotherPosition) {
|
|
1402
|
+
return void 0;
|
|
1403
|
+
}
|
|
1404
|
+
if (input.exposure === void 0 || isZero(input.exposure)) {
|
|
1405
|
+
return void 0;
|
|
1406
|
+
}
|
|
1407
|
+
if (input.side === "BUY" !== isNegative(input.exposure)) {
|
|
1408
|
+
return void 0;
|
|
1409
|
+
}
|
|
1410
|
+
const { step, contractSize } = input.precision.quantity;
|
|
1411
|
+
const exposureQuantity = divide(abs(input.exposure), String(contractSize));
|
|
1412
|
+
const coversExposure = isGreaterThanOrEqual(input.quantity, exposureQuantity);
|
|
1413
|
+
const requestsExposure = isGreaterThanOrEqual(input.requestedQuantity, abs(input.exposure));
|
|
1414
|
+
const roundedShort = isGreaterThan(input.requestedQuantity, subtract(abs(input.exposure), multiply(String(step), String(contractSize))));
|
|
1415
|
+
const refusedShort = roundedShort && !validateQuantity(input.quantity, input.price, input.precision);
|
|
1416
|
+
if (!coversExposure && !requestsExposure && !refusedShort) {
|
|
1417
|
+
return void 0;
|
|
1418
|
+
}
|
|
1419
|
+
const steps = divide(exposureQuantity, String(step)).integerValue(BigNumber7.ROUND_CEIL);
|
|
1420
|
+
return multiply(steps, String(step)).toFixed();
|
|
1421
|
+
}
|
|
1422
|
+
__name(findWholeCloseQuantity, "findWholeCloseQuantity");
|
|
1423
|
+
function requestedBaseQuantity(leg, referencePrice) {
|
|
1424
|
+
switch (leg.mode) {
|
|
1425
|
+
case "QUANTITY":
|
|
1426
|
+
return leg.amount;
|
|
1427
|
+
case "USD":
|
|
1428
|
+
return divide(leg.amount, referencePrice).toFixed();
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
__name(requestedBaseQuantity, "requestedBaseQuantity");
|
|
1432
|
+
function isRefusedBelowMinimum(quantity, price, precision, heldByAnotherPosition) {
|
|
1433
|
+
if (!heldByAnotherPosition) {
|
|
1434
|
+
return false;
|
|
1435
|
+
}
|
|
1436
|
+
const minQuantity = precision.quantity.min;
|
|
1437
|
+
if (minQuantity !== void 0 && minQuantity !== null && isLessThan(quantity, String(minQuantity))) {
|
|
1438
|
+
return true;
|
|
1439
|
+
}
|
|
1440
|
+
const notional = multiply(contractsToBase(quantity, precision.quantity.contractSize), price);
|
|
1441
|
+
const minNotional = precision.notional?.min;
|
|
1442
|
+
return minNotional !== void 0 && minNotional !== null && isLessThan(notional, String(minNotional));
|
|
1443
|
+
}
|
|
1444
|
+
__name(isRefusedBelowMinimum, "isRefusedBelowMinimum");
|
|
1278
1445
|
|
|
1279
1446
|
// src/sync/applicables/constants.ts
|
|
1280
1447
|
var DUST = parse("0.00000001");
|
|
@@ -2055,7 +2222,7 @@ function assignPartIds(positions) {
|
|
|
2055
2222
|
};
|
|
2056
2223
|
}
|
|
2057
2224
|
__name(assignPartIds, "assignPartIds");
|
|
2058
|
-
function partToApplicableFill(part, id, connector) {
|
|
2225
|
+
function partToApplicableFill(part, id, connector, liquidationOutcome) {
|
|
2059
2226
|
const fill = part.source;
|
|
2060
2227
|
const base = {
|
|
2061
2228
|
exchangeFillId: id.exchangeFillId,
|
|
@@ -2088,7 +2255,10 @@ function partToApplicableFill(part, id, connector) {
|
|
|
2088
2255
|
isExternal: !fromPear,
|
|
2089
2256
|
tradeFee: feeShareForPart(fill.tradeFee, part.quantity, fill.quantity),
|
|
2090
2257
|
builderFee: feeShareForPart(fill.builderFee, part.quantity, fill.quantity),
|
|
2091
|
-
liquidation: fill.liquidation
|
|
2258
|
+
liquidation: fill.liquidation ? {
|
|
2259
|
+
mark: fill.liquidation.mark,
|
|
2260
|
+
outcome: liquidationOutcome ?? void 0
|
|
2261
|
+
} : null,
|
|
2092
2262
|
...id.original ? {
|
|
2093
2263
|
original: id.original
|
|
2094
2264
|
} : {}
|
|
@@ -2122,7 +2292,7 @@ function assembleApplicables(args) {
|
|
|
2122
2292
|
}
|
|
2123
2293
|
__name(assembleApplicables, "assembleApplicables");
|
|
2124
2294
|
function assembleOneApplicable(pos, connector, partIdFor, assignedSynthetics, now) {
|
|
2125
|
-
const realFills
|
|
2295
|
+
const { realFills, closedReason } = finalizeRealFills(pos, connector, partIdFor);
|
|
2126
2296
|
const syntheticFills = assignedSynthetics.map((synthetic) => buildSyntheticFill({
|
|
2127
2297
|
positionKey: pos.positionKey,
|
|
2128
2298
|
connector,
|
|
@@ -2146,13 +2316,38 @@ function assembleOneApplicable(pos, connector, partIdFor, assignedSynthetics, no
|
|
|
2146
2316
|
origin,
|
|
2147
2317
|
status,
|
|
2148
2318
|
...closed ? {
|
|
2149
|
-
closedReason
|
|
2319
|
+
closedReason
|
|
2150
2320
|
} : {},
|
|
2151
2321
|
fills,
|
|
2152
2322
|
metadata: buildMetadata(new Set(exposure.symbols()), realFills)
|
|
2153
2323
|
};
|
|
2154
2324
|
}
|
|
2155
2325
|
__name(assembleOneApplicable, "assembleOneApplicable");
|
|
2326
|
+
function finalizeRealFills(position, connector, partIdFor) {
|
|
2327
|
+
const newestFirst = [
|
|
2328
|
+
...position.parts
|
|
2329
|
+
].sort((a, b) => a.source.timestamp - b.source.timestamp).reverse();
|
|
2330
|
+
const exposure = position.exposure.clone();
|
|
2331
|
+
const realFills = [];
|
|
2332
|
+
let closedReason = "NETTED";
|
|
2333
|
+
for (const [index, part] of newestFirst.entries()) {
|
|
2334
|
+
const after = exposure.get(part.source.symbol);
|
|
2335
|
+
const flatAfter = exposure.isFlat();
|
|
2336
|
+
exposure.addDelta(part.source.symbol, negate(signedBySide(part.quantity, part.source.side)));
|
|
2337
|
+
const reducesLeg = isGreaterThan(exposure.get(part.source.symbol).abs(), after.abs());
|
|
2338
|
+
const liquidationOutcome = part.source.liquidation && reducesLeg ? flatAfter ? "CLOSED" : "REDUCED" : null;
|
|
2339
|
+
if (index === 0 && position.closed && liquidationOutcome === "CLOSED") {
|
|
2340
|
+
closedReason = "LIQUIDATED";
|
|
2341
|
+
}
|
|
2342
|
+
realFills.push(partToApplicableFill(part, partIdFor(part), connector, liquidationOutcome));
|
|
2343
|
+
}
|
|
2344
|
+
realFills.reverse();
|
|
2345
|
+
return {
|
|
2346
|
+
realFills,
|
|
2347
|
+
closedReason
|
|
2348
|
+
};
|
|
2349
|
+
}
|
|
2350
|
+
__name(finalizeRealFills, "finalizeRealFills");
|
|
2156
2351
|
function finalExposure(pos, synthetics) {
|
|
2157
2352
|
const exposure = pos.exposure.clone();
|
|
2158
2353
|
for (const synthetic of synthetics) {
|
|
@@ -2403,8 +2598,7 @@ __name(isStrictTimestampBoundary, "isStrictTimestampBoundary");
|
|
|
2403
2598
|
async function computeSyncPayload(args) {
|
|
2404
2599
|
const { tradeAccountId, connector, openPositions, entryBySymbol, provisionalFills, confirmedExchangeFillIds, externalFills, exchangePositions, neverSynced } = args;
|
|
2405
2600
|
const fillsToProcess = _prepareExternalFills(externalFills, confirmedExchangeFillIds);
|
|
2406
|
-
const
|
|
2407
|
-
const confirmablesByPosition = groupConfirmablesByPosition(confirmableFills);
|
|
2601
|
+
const orphans = _excludeClaimedFills(provisionalFills, fillsToProcess);
|
|
2408
2602
|
const { keptOrphans, firstSyncTrim } = applyFirstSyncCutoff({
|
|
2409
2603
|
neverSynced,
|
|
2410
2604
|
fillsToProcess,
|
|
@@ -2421,13 +2615,11 @@ async function computeSyncPayload(args) {
|
|
|
2421
2615
|
exchangePositions
|
|
2422
2616
|
});
|
|
2423
2617
|
const mustPostFirstSyncCheckpoint = neverSynced;
|
|
2424
|
-
if (!mustPostFirstSyncCheckpoint &&
|
|
2618
|
+
if (!mustPostFirstSyncCheckpoint && applicables.length === 0) {
|
|
2425
2619
|
return null;
|
|
2426
2620
|
}
|
|
2427
2621
|
const externalMaxTs = latestFillTimestamp(fillsToProcess);
|
|
2428
2622
|
return {
|
|
2429
|
-
reconcilables: Object.keys(reconcilables).length > 0 ? reconcilables : null,
|
|
2430
|
-
confirmables: Object.keys(confirmablesByPosition).length > 0 ? confirmablesByPosition : null,
|
|
2431
2623
|
applicables,
|
|
2432
2624
|
exchangePositions,
|
|
2433
2625
|
meta: {
|
|
@@ -2469,77 +2661,20 @@ function _prepareExternalFills(externalFills, confirmedExchangeFillIdsInput) {
|
|
|
2469
2661
|
return Array.from(dedupedByExchangeFillId.values()).sort((a, b) => a.timestamp - b.timestamp);
|
|
2470
2662
|
}
|
|
2471
2663
|
__name(_prepareExternalFills, "_prepareExternalFills");
|
|
2472
|
-
function
|
|
2473
|
-
const
|
|
2664
|
+
function _excludeClaimedFills(provisionalFills, externalFills) {
|
|
2665
|
+
const ownedCloids = /* @__PURE__ */ new Set();
|
|
2474
2666
|
for (const fill of provisionalFills) {
|
|
2475
2667
|
const cloid = _normalizeCloid(fill.cloid);
|
|
2476
|
-
if (
|
|
2477
|
-
|
|
2668
|
+
if (cloid) {
|
|
2669
|
+
ownedCloids.add(cloid);
|
|
2478
2670
|
}
|
|
2479
|
-
provisionalFillsMap.set(cloid, fill);
|
|
2480
2671
|
}
|
|
2481
|
-
|
|
2482
|
-
const fillsByCloid = /* @__PURE__ */ new Map();
|
|
2483
|
-
for (const fill of externalFills) {
|
|
2672
|
+
return externalFills.filter((fill) => {
|
|
2484
2673
|
const cloid = _normalizeCloid(fill.cloid);
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
} else {
|
|
2488
|
-
fillsByCloid.set(cloid, [
|
|
2489
|
-
...fillsByCloid.get(cloid) || [],
|
|
2490
|
-
fill
|
|
2491
|
-
]);
|
|
2492
|
-
}
|
|
2493
|
-
}
|
|
2494
|
-
const reconcilables = {};
|
|
2495
|
-
const confirmableFills = [];
|
|
2496
|
-
for (const [cloid, fills] of fillsByCloid.entries()) {
|
|
2497
|
-
if (fills.length > 1) {
|
|
2498
|
-
const provisional = provisionalFillsMap.get(cloid);
|
|
2499
|
-
if (provisional) {
|
|
2500
|
-
const [first, second, ...rest] = fills;
|
|
2501
|
-
if (!first || !second) {
|
|
2502
|
-
throw new Error("Corrupted state: sibling group must contain at least 2 fills for reconcile");
|
|
2503
|
-
}
|
|
2504
|
-
reconcilables[cloid] = [
|
|
2505
|
-
{
|
|
2506
|
-
...first,
|
|
2507
|
-
cloid
|
|
2508
|
-
},
|
|
2509
|
-
{
|
|
2510
|
-
...second,
|
|
2511
|
-
cloid
|
|
2512
|
-
},
|
|
2513
|
-
...rest.map((fill) => ({
|
|
2514
|
-
...fill,
|
|
2515
|
-
cloid
|
|
2516
|
-
}))
|
|
2517
|
-
];
|
|
2518
|
-
} else {
|
|
2519
|
-
orphans.push(...fills);
|
|
2520
|
-
}
|
|
2521
|
-
} else {
|
|
2522
|
-
const fill = fills[0];
|
|
2523
|
-
const provisional = provisionalFillsMap.get(cloid);
|
|
2524
|
-
if (provisional) {
|
|
2525
|
-
confirmableFills.push({
|
|
2526
|
-
...fill,
|
|
2527
|
-
type: "confirm",
|
|
2528
|
-
cloid,
|
|
2529
|
-
positionId: provisional.positionId
|
|
2530
|
-
});
|
|
2531
|
-
} else {
|
|
2532
|
-
orphans.push(fill);
|
|
2533
|
-
}
|
|
2534
|
-
}
|
|
2535
|
-
}
|
|
2536
|
-
return {
|
|
2537
|
-
reconcilables,
|
|
2538
|
-
confirmables: confirmableFills,
|
|
2539
|
-
orphans
|
|
2540
|
-
};
|
|
2674
|
+
return cloid === void 0 || !ownedCloids.has(cloid);
|
|
2675
|
+
});
|
|
2541
2676
|
}
|
|
2542
|
-
__name(
|
|
2677
|
+
__name(_excludeClaimedFills, "_excludeClaimedFills");
|
|
2543
2678
|
function _normalizeCloid(cloid) {
|
|
2544
2679
|
const value = cloid?.trim();
|
|
2545
2680
|
if (!value) {
|
|
@@ -2573,16 +2708,6 @@ function _isValidExternalTimestamp(timestamp) {
|
|
|
2573
2708
|
return timestamp <= Date.now() + WATERMARK_FUTURE_SKEW_MS;
|
|
2574
2709
|
}
|
|
2575
2710
|
__name(_isValidExternalTimestamp, "_isValidExternalTimestamp");
|
|
2576
|
-
function groupConfirmablesByPosition(confirmableFills) {
|
|
2577
|
-
return confirmableFills.reduce((acc, fill) => {
|
|
2578
|
-
acc[fill.positionId] = [
|
|
2579
|
-
...acc[fill.positionId] || [],
|
|
2580
|
-
fill
|
|
2581
|
-
];
|
|
2582
|
-
return acc;
|
|
2583
|
-
}, {});
|
|
2584
|
-
}
|
|
2585
|
-
__name(groupConfirmablesByPosition, "groupConfirmablesByPosition");
|
|
2586
2711
|
function latestFillTimestamp(fills) {
|
|
2587
2712
|
const last = fills[fills.length - 1];
|
|
2588
2713
|
if (!last) {
|
|
@@ -2633,10 +2758,6 @@ function applyFirstSyncCutoff(args) {
|
|
|
2633
2758
|
};
|
|
2634
2759
|
}
|
|
2635
2760
|
__name(applyFirstSyncCutoff, "applyFirstSyncCutoff");
|
|
2636
|
-
function isEmptyCycle(reconcilables, confirmablesByPosition, applicables) {
|
|
2637
|
-
return Object.keys(reconcilables).length === 0 && Object.keys(confirmablesByPosition).length === 0 && applicables.length === 0;
|
|
2638
|
-
}
|
|
2639
|
-
__name(isEmptyCycle, "isEmptyCycle");
|
|
2640
2761
|
|
|
2641
2762
|
// src/validate-leverage.ts
|
|
2642
2763
|
function validateLeverage(leverage, instrument) {
|
|
@@ -2649,34 +2770,6 @@ function validateLeverage(leverage, instrument) {
|
|
|
2649
2770
|
return true;
|
|
2650
2771
|
}
|
|
2651
2772
|
__name(validateLeverage, "validateLeverage");
|
|
2652
|
-
function validateQuantity(quantity, price, precision) {
|
|
2653
|
-
const parsedQuantity = new BigNumber7(quantity);
|
|
2654
|
-
if (!parsedQuantity.isFinite() || parsedQuantity.lte(0)) {
|
|
2655
|
-
return false;
|
|
2656
|
-
}
|
|
2657
|
-
const parsedPrice = new BigNumber7(price);
|
|
2658
|
-
if (!parsedPrice.isFinite() || parsedPrice.lte(0)) {
|
|
2659
|
-
return false;
|
|
2660
|
-
}
|
|
2661
|
-
const step = new BigNumber7(precision.quantity.step);
|
|
2662
|
-
const scaled = parsedQuantity.div(step);
|
|
2663
|
-
if (!scaled.isInteger()) {
|
|
2664
|
-
return false;
|
|
2665
|
-
}
|
|
2666
|
-
const notional = contractsToBase(parsedQuantity, precision.quantity.contractSize).times(parsedPrice);
|
|
2667
|
-
if (precision.notional?.min !== void 0 && precision.notional.min !== null && precision.notional.min > 0) {
|
|
2668
|
-
if (notional.lt(new BigNumber7(precision.notional.min))) {
|
|
2669
|
-
return false;
|
|
2670
|
-
}
|
|
2671
|
-
}
|
|
2672
|
-
if (precision.notional?.max !== void 0 && precision.notional.max !== null && precision.notional.max > 0) {
|
|
2673
|
-
if (notional.gt(new BigNumber7(precision.notional.max))) {
|
|
2674
|
-
return false;
|
|
2675
|
-
}
|
|
2676
|
-
}
|
|
2677
|
-
return true;
|
|
2678
|
-
}
|
|
2679
|
-
__name(validateQuantity, "validateQuantity");
|
|
2680
2773
|
var VAULT_ACTION_DOMAIN = {
|
|
2681
2774
|
name: "PearVaultService",
|
|
2682
2775
|
version: "1",
|
|
@@ -2988,4 +3081,4 @@ function takeVerifier(handoffId, storage) {
|
|
|
2988
3081
|
}
|
|
2989
3082
|
__name(takeVerifier, "takeVerifier");
|
|
2990
3083
|
|
|
2991
|
-
export { BIPS, CREATE_VAULT_TYPES, VAULT_ACTION_DOMAIN, VAULT_ACTION_TYPES, ZERO, abs, add, aggregateRealizedPositionState, baseToContracts, buildApplicables, buildCreateVaultMessage, buildLeaderActionTypedData, compareValue, computeAssetEntryNotional, computeAssetGrossRealizedPnL, computeAssetRealizedPnLs, computeAssetUndeterminedSizes, computeAssetUnrealizedPnL, computeAssetUnrealizedPnLs, computeBasketWeightedRatioV1, computeDeployedCapital, computeDeployedCapitalState, computeEntryPriceForAsset, computeFillTransitions, computeMaxBasketSize, computeMultiQuoteBasketSize, computePositionEntryPrices, computeRealizedPnlBySymbol, computeRealizedPnlFromFills, computeRealizedPositionState, computeSyncPayload, computeUnrealizedPositionState, computeUnrealizedPositionStateFromEntryPrices, configureProxy, contractsToBase, countDecimals, deriveBasketKey, divide, exponentiate, finishXHandoff, generateDeterministicPositionKey, groupFillsByAsset, groupFillsByPosition, isEqualTo, isFiniteDecimal, isGreaterThan, isGreaterThanOrEqual, isLessThan, isLessThanOrEqual, isNegative, isPositive, isZero, min, multiply, negate, parse, precisePrice, preciseQuantity, proxyFetch, sideSign, sign, signed, signedBySide, sizeBasket, sizeBasketByLeverageMode, sizeBasketPerAssetLeverage, startXHandoff, stripXReturn, subtract, sumAttributedFunding, toDecimalString, validateLeverage, validateQuantity, walkPositionLedger, walkPositionTransitions };
|
|
3084
|
+
export { BIPS, CREATE_VAULT_TYPES, InvalidPriceError, VAULT_ACTION_DOMAIN, VAULT_ACTION_TYPES, ZERO, abs, add, aggregateRealizedPositionState, baseToContracts, buildApplicables, buildCreateVaultMessage, buildLeaderActionTypedData, compareValue, computeAssetEntryNotional, computeAssetGrossRealizedPnL, computeAssetRealizedPnLs, computeAssetUndeterminedSizes, computeAssetUnrealizedPnL, computeAssetUnrealizedPnLs, computeBasketWeightedRatioV1, computeDeployedCapital, computeDeployedCapitalState, computeEntryEquityFraction, computeEntryPriceForAsset, computeEquityFraction, computeFillTransitions, computeFilledEntrySizing, computeMaxBasketSize, computeMultiQuoteBasketSize, computeNotionalEquityFraction, computePositionEntryPrices, computeRealizedPnlBySymbol, computeRealizedPnlFromFills, computeRealizedPositionState, computeSyncPayload, computeUnrealizedPositionState, computeUnrealizedPositionStateFromEntryPrices, configureProxy, contractsToBase, countDecimals, deriveBasketKey, divide, exponentiate, findWholeCloseQuantity, finishXHandoff, generateDeterministicPositionKey, groupFillsByAsset, groupFillsByPosition, isEqualTo, isFiniteDecimal, isGreaterThan, isGreaterThanOrEqual, isLessThan, isLessThanOrEqual, isNegative, isPositive, isRefusedBelowMinimum, isZero, min, multiply, negate, parse, precisePrice, preciseQuantity, proxyFetch, requestedBaseQuantity, sideSign, sign, signed, signedBySide, sizeBasket, sizeBasketByLeverageMode, sizeBasketPerAssetLeverage, startXHandoff, stripXReturn, subtract, sumAttributedFunding, toDecimalString, validateLeverage, validateQuantity, walkPositionLedger, walkPositionTransitions };
|
package/dist/position/key.d.ts
CHANGED
|
@@ -11,8 +11,8 @@ type PositionKeyInput = {
|
|
|
11
11
|
* exactly what the active-position unique index relies on and what makes the
|
|
12
12
|
* apply UPSERT find-or-create the single correct target.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
* (`leg.id ?? leg.symbol`, or exposure keys). A
|
|
14
|
+
* SYMBOL-MIGRATION id-forever: `symbols` must be instrument ids
|
|
15
|
+
* (`leg.id ?? leg.symbol`, or exposure keys). A display ticker here re-hashes and orphans every position.
|
|
16
16
|
*/
|
|
17
17
|
export declare function generateDeterministicPositionKey(input: PositionKeyInput): string;
|
|
18
18
|
export {};
|
package/dist/precise-price.d.ts
CHANGED
|
@@ -1,8 +1,30 @@
|
|
|
1
1
|
import type { Connector, InstrumentPrecision, Side } from '@pear-protocol/types';
|
|
2
2
|
import BigNumber from 'bignumber.js';
|
|
3
|
+
/**
|
|
4
|
+
* Which way a price is rounded onto the exchange grid.
|
|
5
|
+
* - `marketable`: towards crossing (BUY up, SELL down), so a market order keeps its slippage buffer
|
|
6
|
+
* and still reaches the opposite touch; it may cost up to one grid step beyond the buffer (#785).
|
|
7
|
+
* - `within_limit`: away from crossing (BUY down, SELL up), so a user-set limit is never exceeded.
|
|
8
|
+
*/
|
|
9
|
+
export type PriceRounding = 'marketable' | 'within_limit';
|
|
10
|
+
/**
|
|
11
|
+
* A price `precisePrice` produced: on the venue's grid and greater than zero (#1157), so it can be an
|
|
12
|
+
* order's limit. USD sizing deliberately does not require it: an unconstrained leg is sized off the
|
|
13
|
+
* unpadded mid, a raw reference price (#1145). It is still a string, so it passes anywhere a string is
|
|
14
|
+
* accepted, `validateQuantity` included.
|
|
15
|
+
*/
|
|
16
|
+
export type GridPrice = string & {
|
|
17
|
+
readonly __brand: 'GridPrice';
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Thrown by `precisePrice` when no placeable price exists: a raw price that is not positive and
|
|
21
|
+
* finite, or a limit that rounds to zero on the grid (a BUY cap below one grid step).
|
|
22
|
+
*/
|
|
23
|
+
export declare class InvalidPriceError extends Error {
|
|
24
|
+
}
|
|
3
25
|
/**
|
|
4
26
|
* Round a raw price to an exchange-valid string for the given connector,
|
|
5
|
-
*
|
|
6
|
-
*
|
|
27
|
+
* optionally padded with slippage tolerance first, biased per `rounding`.
|
|
28
|
+
* The result is always on the grid and above zero; otherwise this throws `InvalidPriceError`.
|
|
7
29
|
*/
|
|
8
|
-
export declare function precisePrice(connector: Connector, raw: BigNumber.Value, precision: InstrumentPrecision, side?: Side, slippageToleranceBps?: number):
|
|
30
|
+
export declare function precisePrice(connector: Connector, raw: BigNumber.Value, precision: InstrumentPrecision, side?: Side, slippageToleranceBps?: number, rounding?: PriceRounding): GridPrice;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** When a reduce-only order is held to the venue minimum (#1184). Pure, so the backend and the frontend share one rule. */
|
|
2
|
+
import type { InstrumentPrecision, Side } from '@pear-protocol/types';
|
|
3
|
+
/**
|
|
4
|
+
* The quantity that closes the whole venue position a reduce-only leg reduces, or undefined when the leg
|
|
5
|
+
* is only a partial reduce. Under #1184's rule a whole close is the only reduce-only order exempt from the
|
|
6
|
+
* venue minimum; this is Pear's product rule, not a venue constraint (Binance, for one, exempts every
|
|
7
|
+
* reduce-only order from its minimum order value, -4164, though not from its minimum quantity, -4004).
|
|
8
|
+
*
|
|
9
|
+
* The venue nets every position of the account holding the asset, so the leg is a whole close only when no
|
|
10
|
+
* other position holds the asset, its side opposes the exposure (a BUY closes a short, a SELL a long), and
|
|
11
|
+
* it covers the exposure: its rounded quantity reaches it, the quantity requested before rounding reaches it
|
|
12
|
+
* (so a request for the whole position always closes it), or that request falls short of it by less than
|
|
13
|
+
* one step and the rounded partial would be refused at the order price, so a USD amount sized at a slightly
|
|
14
|
+
* different price that rounds a step short below the minimum still closes it, while a partial the venue
|
|
15
|
+
* accepts, or an exact reduce of one step less, stays partial. A whole close is
|
|
16
|
+
* the exposure rounded up onto the venue's step grid; the venue caps reduce-only at the position. The
|
|
17
|
+
* quantity and the returned quantity are in the venue's contract units (base units where a contract is one
|
|
18
|
+
* unit); the requested quantity and the exposure are in base units.
|
|
19
|
+
*/
|
|
20
|
+
export declare function findWholeCloseQuantity(input: {
|
|
21
|
+
quantity: string;
|
|
22
|
+
requestedQuantity: string;
|
|
23
|
+
side: Side;
|
|
24
|
+
exposure: string | undefined;
|
|
25
|
+
price: string;
|
|
26
|
+
precision: InstrumentPrecision;
|
|
27
|
+
heldByAnotherPosition: boolean;
|
|
28
|
+
}): string | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* The base quantity a leg asked for before venue rounding: a quantity leg's own amount, a USD leg's amount
|
|
31
|
+
* at the price it is sized against.
|
|
32
|
+
*/
|
|
33
|
+
export declare function requestedBaseQuantity(leg: {
|
|
34
|
+
mode: 'QUANTITY' | 'USD';
|
|
35
|
+
amount: string;
|
|
36
|
+
}, referencePrice: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Whether a close leg is refused for its size. A close places the position's whole exposure, so it closes
|
|
39
|
+
* the venue position, valid at any size, unless another position holds the asset: then the venue reads it
|
|
40
|
+
* as a partial reduce, held to its minimum order quantity and minimum order value at the order price (#1184).
|
|
41
|
+
*/
|
|
42
|
+
export declare function isRefusedBelowMinimum(quantity: string, price: string, precision: InstrumentPrecision, heldByAnotherPosition: boolean): boolean;
|
|
@@ -13,4 +13,4 @@ export declare function assignPartIds(positions: MatchedPosition[]): (part: Fill
|
|
|
13
13
|
* missed-history synthetic (external, priced to reconcile with the exchange entry).
|
|
14
14
|
* Fees are quantity-prorated when the source fill was split across positions.
|
|
15
15
|
*/
|
|
16
|
-
export declare function partToApplicableFill(part: FillPart, id: PartId, connector: HttpTypes.Connector): HttpTypes.ApplicableFill;
|
|
16
|
+
export declare function partToApplicableFill(part: FillPart, id: PartId, connector: HttpTypes.Connector, liquidationOutcome: 'CLOSED' | 'REDUCED' | null): HttpTypes.ApplicableFill;
|
package/dist/sync/compute.d.ts
CHANGED
|
@@ -14,15 +14,10 @@ export declare function computeSyncPayload(args: ComputeSyncPayloadArgs): Promis
|
|
|
14
14
|
*/
|
|
15
15
|
export declare function _prepareExternalFills(externalFills: HttpTypes.UnknownExternalFill[], confirmedExchangeFillIdsInput: string[]): HttpTypes.UnknownExternalFill[];
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* everything else (no cloid, or cloid we do not own) becomes an orphan.
|
|
17
|
+
* Drop external fills whose cloid is claimed by a provisional fill we own.
|
|
18
|
+
* The server-side syncer owns confirming those fills; the client applies orphans only.
|
|
20
19
|
*/
|
|
21
|
-
export declare function
|
|
22
|
-
reconcilables: HttpTypes.ReconcileFillsRequest;
|
|
23
|
-
confirmables: HttpTypes.ConfirmableExternalFill[];
|
|
24
|
-
orphans: HttpTypes.UnknownExternalFill[];
|
|
25
|
-
};
|
|
20
|
+
export declare function _excludeClaimedFills(provisionalFills: HttpTypes.ProvisionalFill[], externalFills: HttpTypes.UnknownExternalFill[]): HttpTypes.UnknownExternalFill[];
|
|
26
21
|
/** Trim a cloid; empty or whitespace-only collapses to undefined. */
|
|
27
22
|
export declare function _normalizeCloid(cloid?: string | null): string | undefined;
|
|
28
23
|
/** Normalise an exchange fill id: trim + lowercase; absent or blank → undefined. */
|
package/dist/sync/types.d.ts
CHANGED
|
@@ -11,8 +11,6 @@ export type ComputeSyncPayloadArgs = {
|
|
|
11
11
|
neverSynced: boolean;
|
|
12
12
|
};
|
|
13
13
|
export type ComputeSyncPayloadResult = {
|
|
14
|
-
reconcilables: HttpTypes.ReconcileFillsRequest | null;
|
|
15
|
-
confirmables: HttpTypes.ConfirmFillsRequest | null;
|
|
16
14
|
applicables: HttpTypes.ApplicablePosition[];
|
|
17
15
|
exchangePositions: HttpTypes.ExternalPosition[];
|
|
18
16
|
meta: {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { InstrumentPrecision } from '@pear-protocol/types';
|
|
2
2
|
/**
|
|
3
|
-
* True when an order quantity is positive, step-aligned,
|
|
4
|
-
*
|
|
3
|
+
* True when an order quantity is positive, step-aligned, at or above the venue's
|
|
4
|
+
* optional minimum order quantity, and within the instrument's optional notional
|
|
5
|
+
* bounds at the given price.
|
|
5
6
|
*/
|
|
6
7
|
export declare function validateQuantity(quantity: string, price: string, precision: InstrumentPrecision): boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pear-protocol/utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Pear Protocol Utility functions",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@noble/hashes": "^1.3.2",
|
|
30
|
-
"@pear-protocol/types": "^2.
|
|
30
|
+
"@pear-protocol/types": "^2.19.0",
|
|
31
31
|
"@scure/base": "^2.3.0",
|
|
32
32
|
"bignumber.js": "9.3.1"
|
|
33
33
|
},
|