@pear-protocol/utils 1.5.0 → 1.6.1
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.js +124 -176
- package/dist/precise-quantity.d.ts +9 -3
- package/dist/reduce-only-minimum.d.ts +5 -4
- package/dist/sync/applicables/basket.d.ts +0 -4
- package/dist/sync/applicables/exposure.d.ts +1 -9
- package/dist/sync/applicables/fills.d.ts +2 -15
- package/dist/sync/applicables/index.d.ts +7 -4
- package/dist/sync/applicables/matching.d.ts +1 -3
- package/dist/sync/applicables/position.d.ts +6 -4
- package/dist/sync/applicables/synthetics.d.ts +2 -1
- package/dist/sync/applicables/types.d.ts +8 -8
- package/dist/sync/types.d.ts +1 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1288,35 +1288,43 @@ BigNumber7.config({
|
|
|
1288
1288
|
DECIMAL_PLACES: 30,
|
|
1289
1289
|
ROUNDING_MODE: BigNumber7.ROUND_DOWN
|
|
1290
1290
|
});
|
|
1291
|
-
function preciseQuantity(connector, raw, precision, side) {
|
|
1291
|
+
function preciseQuantity(connector, raw, precision, side, rounding = "side") {
|
|
1292
|
+
const roundingMode = resolveRoundingMode2(side, rounding);
|
|
1292
1293
|
switch (connector) {
|
|
1293
1294
|
case "hyperliquid":
|
|
1294
|
-
return preciseHyperliquidQuantity(raw, precision,
|
|
1295
|
+
return preciseHyperliquidQuantity(raw, precision, roundingMode);
|
|
1295
1296
|
case "binance":
|
|
1296
1297
|
case "bybit":
|
|
1297
1298
|
case "okx":
|
|
1298
1299
|
case "lighter":
|
|
1299
1300
|
case "lighter_rhc":
|
|
1300
|
-
return preciseStepGridQuantity(raw, precision,
|
|
1301
|
+
return preciseStepGridQuantity(raw, precision, roundingMode);
|
|
1301
1302
|
}
|
|
1302
1303
|
}
|
|
1303
1304
|
__name(preciseQuantity, "preciseQuantity");
|
|
1304
|
-
function
|
|
1305
|
+
function resolveRoundingMode2(side, rounding) {
|
|
1306
|
+
if (rounding === "floor") {
|
|
1307
|
+
return BigNumber7.ROUND_FLOOR;
|
|
1308
|
+
}
|
|
1309
|
+
return side === "BUY" ? BigNumber7.ROUND_FLOOR : BigNumber7.ROUND_CEIL;
|
|
1310
|
+
}
|
|
1311
|
+
__name(resolveRoundingMode2, "resolveRoundingMode");
|
|
1312
|
+
function preciseHyperliquidQuantity(raw, precision, roundingMode) {
|
|
1305
1313
|
const decimals = precision.quantity.decimals;
|
|
1306
1314
|
const quantity = new BigNumber7(raw);
|
|
1307
|
-
const rounded = quantity.decimalPlaces(decimals,
|
|
1315
|
+
const rounded = quantity.decimalPlaces(decimals, roundingMode);
|
|
1308
1316
|
return rounded.toFixed();
|
|
1309
1317
|
}
|
|
1310
1318
|
__name(preciseHyperliquidQuantity, "preciseHyperliquidQuantity");
|
|
1311
|
-
function preciseStepGridQuantity(raw, precision,
|
|
1319
|
+
function preciseStepGridQuantity(raw, precision, roundingMode) {
|
|
1312
1320
|
const step = precision.quantity.step;
|
|
1313
1321
|
const contractQuantity = baseToContracts(raw, precision.quantity.contractSize);
|
|
1314
1322
|
const stepBN = new BigNumber7(step);
|
|
1315
1323
|
const scaled = contractQuantity.div(stepBN);
|
|
1316
|
-
const rounded =
|
|
1324
|
+
const rounded = scaled.integerValue(roundingMode);
|
|
1317
1325
|
const result = rounded.times(stepBN);
|
|
1318
1326
|
const maxDecimals = precision.quantity.decimals;
|
|
1319
|
-
const final = result.decimalPlaces(maxDecimals,
|
|
1327
|
+
const final = result.decimalPlaces(maxDecimals, roundingMode);
|
|
1320
1328
|
return final.toFixed();
|
|
1321
1329
|
}
|
|
1322
1330
|
__name(preciseStepGridQuantity, "preciseStepGridQuantity");
|
|
@@ -1429,8 +1437,8 @@ function requestedBaseQuantity(leg, referencePrice) {
|
|
|
1429
1437
|
}
|
|
1430
1438
|
}
|
|
1431
1439
|
__name(requestedBaseQuantity, "requestedBaseQuantity");
|
|
1432
|
-
function isRefusedBelowMinimum(quantity, price, precision,
|
|
1433
|
-
if (!
|
|
1440
|
+
function isRefusedBelowMinimum(quantity, price, precision, isPartialVenueReduce) {
|
|
1441
|
+
if (!isPartialVenueReduce) {
|
|
1434
1442
|
return false;
|
|
1435
1443
|
}
|
|
1436
1444
|
const minQuantity = precision.quantity.min;
|
|
@@ -1490,14 +1498,6 @@ var Basket = class _Basket {
|
|
|
1490
1498
|
static detect(fills) {
|
|
1491
1499
|
return groupFillsIntoBaskets(fills).map((group) => new _Basket(combineFillsBySymbolAndSide(group), group));
|
|
1492
1500
|
}
|
|
1493
|
-
/** Active long symbol set the matcher compares against open positions. */
|
|
1494
|
-
get longs() {
|
|
1495
|
-
return new Set(this.legs.filter((leg) => leg.side === "BUY").map((leg) => leg.symbol));
|
|
1496
|
-
}
|
|
1497
|
-
/** Active short symbol set the matcher compares against open positions. */
|
|
1498
|
-
get shorts() {
|
|
1499
|
-
return new Set(this.legs.filter((leg) => leg.side === "SELL").map((leg) => leg.symbol));
|
|
1500
|
-
}
|
|
1501
1501
|
};
|
|
1502
1502
|
var CombinedLeg = class {
|
|
1503
1503
|
static {
|
|
@@ -1649,15 +1649,6 @@ var Exposure = class _Exposure {
|
|
|
1649
1649
|
shorts
|
|
1650
1650
|
};
|
|
1651
1651
|
}
|
|
1652
|
-
/** True once every leg sits within DUST of zero (effectively closed). */
|
|
1653
|
-
isFlat() {
|
|
1654
|
-
for (const qty of this.legs.values()) {
|
|
1655
|
-
if (isGreaterThanOrEqual(qty.abs(), DUST)) {
|
|
1656
|
-
return false;
|
|
1657
|
-
}
|
|
1658
|
-
}
|
|
1659
|
-
return true;
|
|
1660
|
-
}
|
|
1661
1652
|
/** True when every leg is exactly zero (a fully CLOSED position). */
|
|
1662
1653
|
isAllZero() {
|
|
1663
1654
|
for (const qty of this.legs.values()) {
|
|
@@ -1667,18 +1658,6 @@ var Exposure = class _Exposure {
|
|
|
1667
1658
|
}
|
|
1668
1659
|
return true;
|
|
1669
1660
|
}
|
|
1670
|
-
/**
|
|
1671
|
-
* Snap every non-zero leg to exactly zero. Called once a position is flat so it
|
|
1672
|
-
* reads CLOSED (all-zero exposure) and never lingers in the open list with stray
|
|
1673
|
-
* dust that a later reopen of the same pair could merge into.
|
|
1674
|
-
*/
|
|
1675
|
-
snapToZero() {
|
|
1676
|
-
for (const [symbol, qty] of this.legs) {
|
|
1677
|
-
if (!qty.isZero()) {
|
|
1678
|
-
this.legs.set(symbol, ZERO);
|
|
1679
|
-
}
|
|
1680
|
-
}
|
|
1681
|
-
}
|
|
1682
1661
|
/** All symbols with a leg, including zeroed ones (a closed leg still carries cost basis). */
|
|
1683
1662
|
symbols() {
|
|
1684
1663
|
return [
|
|
@@ -1727,7 +1706,7 @@ function buildSyntheticFill(args) {
|
|
|
1727
1706
|
return {
|
|
1728
1707
|
// Content-addressed id — no wall-clock, no positionId, so re-syncs collide
|
|
1729
1708
|
// on the dedup index and synthetic generation stays idempotent.
|
|
1730
|
-
exchangeFillId:
|
|
1709
|
+
exchangeFillId: syntheticFillId(args),
|
|
1731
1710
|
cloid: null,
|
|
1732
1711
|
connector: args.connector,
|
|
1733
1712
|
symbol: args.symbol,
|
|
@@ -1750,6 +1729,13 @@ function buildSyntheticFill(args) {
|
|
|
1750
1729
|
};
|
|
1751
1730
|
}
|
|
1752
1731
|
__name(buildSyntheticFill, "buildSyntheticFill");
|
|
1732
|
+
function syntheticFillId(args) {
|
|
1733
|
+
if (args.lifecycleStartedAt === null) {
|
|
1734
|
+
return `synthetic-${args.positionKey}-${args.symbol}-${args.side}`;
|
|
1735
|
+
}
|
|
1736
|
+
return `synthetic-${args.positionKey}-${args.lifecycleStartedAt}-${args.symbol}-${args.side}`;
|
|
1737
|
+
}
|
|
1738
|
+
__name(syntheticFillId, "syntheticFillId");
|
|
1753
1739
|
function buildMissedHistoryFills(args) {
|
|
1754
1740
|
const { orphanFills, pear, connector, entryBySymbol, snapshot } = args;
|
|
1755
1741
|
const fillTotals = /* @__PURE__ */ new Map();
|
|
@@ -1858,7 +1844,7 @@ function findNeededSynthetics(args) {
|
|
|
1858
1844
|
symbol: gap.symbol,
|
|
1859
1845
|
side: gap.side,
|
|
1860
1846
|
quantity: gap.quantity,
|
|
1861
|
-
closedReason: "
|
|
1847
|
+
closedReason: "USER"
|
|
1862
1848
|
});
|
|
1863
1849
|
break;
|
|
1864
1850
|
case "gap":
|
|
@@ -1894,20 +1880,22 @@ function assignSyntheticsToPositions(args) {
|
|
|
1894
1880
|
if (!target) {
|
|
1895
1881
|
target = existing ? (
|
|
1896
1882
|
// seed its exposure and origin so folding the synthetic yields the true
|
|
1897
|
-
// final state (a gone-close nets to zero -> CLOSED/
|
|
1883
|
+
// final state (a gone-close nets to zero -> CLOSED/USER, a gap writes
|
|
1898
1884
|
// the full total, not just the delta).
|
|
1899
1885
|
{
|
|
1900
1886
|
positionKey,
|
|
1901
1887
|
parts: [],
|
|
1902
1888
|
closed: false,
|
|
1903
1889
|
exposure: Exposure.fromRecord(existing.exposure),
|
|
1904
|
-
existingOrigin: existing.origin
|
|
1890
|
+
existingOrigin: existing.origin,
|
|
1891
|
+
lifecycleStartedAt: Date.parse(existing.createdAt)
|
|
1905
1892
|
}
|
|
1906
1893
|
) : {
|
|
1907
1894
|
positionKey,
|
|
1908
1895
|
parts: [],
|
|
1909
1896
|
closed: false,
|
|
1910
|
-
exposure: Exposure.empty()
|
|
1897
|
+
exposure: Exposure.empty(),
|
|
1898
|
+
lifecycleStartedAt: null
|
|
1911
1899
|
};
|
|
1912
1900
|
created.push(target);
|
|
1913
1901
|
}
|
|
@@ -1977,11 +1965,9 @@ function matchPositions(args) {
|
|
|
1977
1965
|
for (const basket of Basket.detect(orphanFills)) {
|
|
1978
1966
|
const at = basketTime(basket);
|
|
1979
1967
|
book.foldIntoLive(at);
|
|
1980
|
-
const exactCloseTarget = findExactCloseTarget(book.live(at), basket.longs, basket.shorts);
|
|
1981
1968
|
const leftover = applyCloses({
|
|
1982
1969
|
legs: basket.legs,
|
|
1983
1970
|
book,
|
|
1984
|
-
exactCloseTarget,
|
|
1985
1971
|
at
|
|
1986
1972
|
});
|
|
1987
1973
|
if (leftover.length === 0) {
|
|
@@ -2025,6 +2011,8 @@ var WorkingBook = class WorkingBook2 {
|
|
|
2025
2011
|
// A partial fill on the original order leaves exposure short of the
|
|
2026
2012
|
// symbols the key was hashed from, so a recomputed key would never match.
|
|
2027
2013
|
positionKey: p.positionKey,
|
|
2014
|
+
createdAt: Date.parse(p.createdAt),
|
|
2015
|
+
orderId: p.id,
|
|
2028
2016
|
exposure: Exposure.fromRecord(p.exposure),
|
|
2029
2017
|
parts: [],
|
|
2030
2018
|
closed: false,
|
|
@@ -2043,9 +2031,9 @@ var WorkingBook = class WorkingBook2 {
|
|
|
2043
2031
|
symbols
|
|
2044
2032
|
});
|
|
2045
2033
|
}
|
|
2046
|
-
/** Working positions open and already existing at basket time `at`, in
|
|
2034
|
+
/** Working positions open and already existing at basket time `at`, in creation order. */
|
|
2047
2035
|
live(at) {
|
|
2048
|
-
return this.all.filter((position) => !position.closed && position.liveFrom <= at);
|
|
2036
|
+
return this.all.filter((position) => !position.closed && position.liveFrom <= at).sort((a, b) => a.createdAt - b.createdAt || a.orderId.localeCompare(b.orderId));
|
|
2049
2037
|
}
|
|
2050
2038
|
/** Look up a position open and existing at `at` by its positionKey (for dedup on merge). */
|
|
2051
2039
|
findLiveByKey(key, at) {
|
|
@@ -2073,9 +2061,11 @@ var WorkingBook = class WorkingBook2 {
|
|
|
2073
2061
|
}
|
|
2074
2062
|
}
|
|
2075
2063
|
/** Register a fresh empty working position under `key` and return it. */
|
|
2076
|
-
create(key) {
|
|
2064
|
+
create(key, createdAt) {
|
|
2077
2065
|
const position = {
|
|
2078
2066
|
positionKey: key,
|
|
2067
|
+
createdAt,
|
|
2068
|
+
orderId: key,
|
|
2079
2069
|
exposure: Exposure.empty(),
|
|
2080
2070
|
parts: [],
|
|
2081
2071
|
closed: false,
|
|
@@ -2085,12 +2075,11 @@ var WorkingBook = class WorkingBook2 {
|
|
|
2085
2075
|
this.all.push(position);
|
|
2086
2076
|
return position;
|
|
2087
2077
|
}
|
|
2088
|
-
/** Flip a position to closed once every leg is
|
|
2078
|
+
/** Flip a position to closed once every leg is exactly zero. */
|
|
2089
2079
|
markClosedIfFlat(position) {
|
|
2090
|
-
if (position.closed || !position.exposure.
|
|
2080
|
+
if (position.closed || !position.exposure.isAllZero()) {
|
|
2091
2081
|
return;
|
|
2092
2082
|
}
|
|
2093
|
-
position.exposure.snapToZero();
|
|
2094
2083
|
position.closed = true;
|
|
2095
2084
|
}
|
|
2096
2085
|
/** Working positions that received fills become MatchedPosition records; untouched ones are dropped. */
|
|
@@ -2100,22 +2089,13 @@ var WorkingBook = class WorkingBook2 {
|
|
|
2100
2089
|
parts: position.parts,
|
|
2101
2090
|
closed: position.closed,
|
|
2102
2091
|
exposure: position.exposure,
|
|
2103
|
-
existingOrigin: position.existingOrigin
|
|
2092
|
+
existingOrigin: position.existingOrigin,
|
|
2093
|
+
lifecycleStartedAt: position.createdAt
|
|
2104
2094
|
}));
|
|
2105
2095
|
}
|
|
2106
2096
|
};
|
|
2107
|
-
function findExactCloseTarget(openList, basketLongs, basketShorts) {
|
|
2108
|
-
return openList.find((position) => {
|
|
2109
|
-
const { longs, shorts } = position.exposure.activeLegs();
|
|
2110
|
-
return setEq(longs, basketShorts) && setEq(shorts, basketLongs);
|
|
2111
|
-
});
|
|
2112
|
-
}
|
|
2113
|
-
__name(findExactCloseTarget, "findExactCloseTarget");
|
|
2114
|
-
var setEq = /* @__PURE__ */ __name((a, b) => a.size === b.size && [
|
|
2115
|
-
...a
|
|
2116
|
-
].every((x) => b.has(x)), "setEq");
|
|
2117
2097
|
function applyCloses(args) {
|
|
2118
|
-
const { legs, book,
|
|
2098
|
+
const { legs, book, at } = args;
|
|
2119
2099
|
const openList = book.live(at);
|
|
2120
2100
|
const leftover = [];
|
|
2121
2101
|
for (const leg of legs) {
|
|
@@ -2128,9 +2108,6 @@ function applyCloses(args) {
|
|
|
2128
2108
|
}
|
|
2129
2109
|
return closeTargetIsLong ? qty.isPositive() : qty.isNegative();
|
|
2130
2110
|
});
|
|
2131
|
-
if (exactCloseTarget) {
|
|
2132
|
-
holders.sort((a, b) => a === exactCloseTarget ? -1 : b === exactCloseTarget ? 1 : 0);
|
|
2133
|
-
}
|
|
2134
2111
|
for (const position of holders) {
|
|
2135
2112
|
if (isLessThanOrEqual(remaining, ZERO)) {
|
|
2136
2113
|
break;
|
|
@@ -2142,7 +2119,7 @@ function applyCloses(args) {
|
|
|
2142
2119
|
remaining = remaining.minus(reduce);
|
|
2143
2120
|
book.markClosedIfFlat(position);
|
|
2144
2121
|
}
|
|
2145
|
-
if (
|
|
2122
|
+
if (isGreaterThan(remaining, ZERO)) {
|
|
2146
2123
|
leftover.push({
|
|
2147
2124
|
side: leg.side,
|
|
2148
2125
|
qty: remaining,
|
|
@@ -2173,143 +2150,99 @@ function resolveLeftoverTarget(args) {
|
|
|
2173
2150
|
])
|
|
2174
2151
|
];
|
|
2175
2152
|
const positionKey = book.keyFor(symbols);
|
|
2176
|
-
return book.findLiveByKey(positionKey, at) ?? book.create(positionKey);
|
|
2153
|
+
return book.findLiveByKey(positionKey, at) ?? book.create(positionKey, at);
|
|
2177
2154
|
}
|
|
2178
2155
|
__name(resolveLeftoverTarget, "resolveLeftoverTarget");
|
|
2179
2156
|
function applyLeftover(target, leftover) {
|
|
2180
2157
|
for (const entry of leftover) {
|
|
2181
|
-
|
|
2158
|
+
const parts = entry.leg.take(entry.qty);
|
|
2159
|
+
target.parts.push(...parts);
|
|
2160
|
+
if (target.existingOrigin === void 0) {
|
|
2161
|
+
target.createdAt = Math.min(...target.parts.map((part) => part.source.timestamp));
|
|
2162
|
+
target.orderId = target.parts.filter((part) => part.source.timestamp === target.createdAt).map((part) => part.source.exchangeFillId).sort()[0] ?? target.positionKey;
|
|
2163
|
+
}
|
|
2182
2164
|
target.exposure.addSigned(entry.leg.symbol, entry.qty.toFixed(), entry.side);
|
|
2183
2165
|
}
|
|
2184
2166
|
}
|
|
2185
2167
|
__name(applyLeftover, "applyLeftover");
|
|
2168
|
+
function setEq(a, b) {
|
|
2169
|
+
return a.size === b.size && [
|
|
2170
|
+
...a
|
|
2171
|
+
].every((symbol) => b.has(symbol));
|
|
2172
|
+
}
|
|
2173
|
+
__name(setEq, "setEq");
|
|
2186
2174
|
|
|
2187
2175
|
// src/sync/applicables/fills.ts
|
|
2188
|
-
function
|
|
2189
|
-
const
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
const list = bySource.get(part.source.exchangeFillId) ?? [];
|
|
2193
|
-
list.push(part);
|
|
2194
|
-
bySource.set(part.source.exchangeFillId, list);
|
|
2195
|
-
}
|
|
2196
|
-
}
|
|
2197
|
-
const resolution = /* @__PURE__ */ new Map();
|
|
2198
|
-
for (const [sourceId, parts] of bySource) {
|
|
2199
|
-
const single = parts.length === 1 ? parts[0] : void 0;
|
|
2200
|
-
if (single && isEqualTo(single.quantity, single.source.quantity)) {
|
|
2201
|
-
resolution.set(single, {
|
|
2202
|
-
exchangeFillId: sourceId
|
|
2203
|
-
});
|
|
2204
|
-
continue;
|
|
2205
|
-
}
|
|
2206
|
-
parts.forEach((part, i) => {
|
|
2207
|
-
resolution.set(part, {
|
|
2208
|
-
exchangeFillId: `${sourceId}-p${i}`,
|
|
2209
|
-
original: {
|
|
2210
|
-
exchangeFillId: sourceId,
|
|
2211
|
-
quantity: part.source.quantity
|
|
2212
|
-
}
|
|
2213
|
-
});
|
|
2214
|
-
});
|
|
2215
|
-
}
|
|
2216
|
-
return (part) => {
|
|
2217
|
-
const id = resolution.get(part);
|
|
2218
|
-
if (!id) {
|
|
2219
|
-
throw new Error("applicables: fill part was never assigned an id");
|
|
2220
|
-
}
|
|
2221
|
-
return id;
|
|
2222
|
-
};
|
|
2223
|
-
}
|
|
2224
|
-
__name(assignPartIds, "assignPartIds");
|
|
2225
|
-
function partToApplicableFill(part, id, connector, liquidationOutcome) {
|
|
2226
|
-
const fill = part.source;
|
|
2227
|
-
const base = {
|
|
2228
|
-
exchangeFillId: id.exchangeFillId,
|
|
2176
|
+
function sourceToApplicableFill(fill, connector) {
|
|
2177
|
+
const synthetic = isMissedHistoryFill(fill);
|
|
2178
|
+
return {
|
|
2179
|
+
exchangeFillId: fill.exchangeFillId,
|
|
2229
2180
|
connector,
|
|
2230
2181
|
symbol: fill.symbol,
|
|
2231
2182
|
side: fill.side,
|
|
2232
|
-
quantity:
|
|
2183
|
+
quantity: fill.quantity,
|
|
2233
2184
|
price: fill.price,
|
|
2234
|
-
usd: multiply(
|
|
2235
|
-
timestamp: fill.timestamp
|
|
2185
|
+
usd: multiply(fill.quantity, fill.price).toFixed(),
|
|
2186
|
+
timestamp: fill.timestamp,
|
|
2187
|
+
cloid: synthetic ? null : fill.cloid ?? null,
|
|
2188
|
+
reduceOnly: synthetic ? false : fill.reduceOnly,
|
|
2189
|
+
synthetic,
|
|
2190
|
+
isExternal: synthetic || !isPearCloid(connector, fill.cloid),
|
|
2191
|
+
tradeFee: synthetic ? "0" : fill.tradeFee,
|
|
2192
|
+
builderFee: synthetic ? "0" : fill.builderFee,
|
|
2193
|
+
liquidation: synthetic ? null : fill.liquidation
|
|
2236
2194
|
};
|
|
2237
|
-
if (isMissedHistoryFill(fill)) {
|
|
2238
|
-
return {
|
|
2239
|
-
...base,
|
|
2240
|
-
cloid: null,
|
|
2241
|
-
reduceOnly: false,
|
|
2242
|
-
synthetic: true,
|
|
2243
|
-
isExternal: true,
|
|
2244
|
-
tradeFee: "0",
|
|
2245
|
-
builderFee: "0",
|
|
2246
|
-
liquidation: null
|
|
2247
|
-
};
|
|
2248
|
-
}
|
|
2249
|
-
const fromPear = isPearCloid(connector, fill.cloid);
|
|
2250
|
-
return {
|
|
2251
|
-
...base,
|
|
2252
|
-
cloid: fill.cloid ?? null,
|
|
2253
|
-
reduceOnly: fill.reduceOnly,
|
|
2254
|
-
synthetic: false,
|
|
2255
|
-
isExternal: !fromPear,
|
|
2256
|
-
tradeFee: feeShareForPart(fill.tradeFee, part.quantity, fill.quantity),
|
|
2257
|
-
builderFee: feeShareForPart(fill.builderFee, part.quantity, fill.quantity),
|
|
2258
|
-
liquidation: fill.liquidation ? {
|
|
2259
|
-
mark: fill.liquidation.mark,
|
|
2260
|
-
outcome: liquidationOutcome ?? void 0
|
|
2261
|
-
} : null,
|
|
2262
|
-
...id.original ? {
|
|
2263
|
-
original: id.original
|
|
2264
|
-
} : {}
|
|
2265
|
-
};
|
|
2266
|
-
}
|
|
2267
|
-
__name(partToApplicableFill, "partToApplicableFill");
|
|
2268
|
-
function feeShareForPart(totalFee, partQty, sourceQty) {
|
|
2269
|
-
if (isEqualTo(partQty, sourceQty)) {
|
|
2270
|
-
return totalFee;
|
|
2271
|
-
}
|
|
2272
|
-
if (isZero(sourceQty)) {
|
|
2273
|
-
return "0";
|
|
2274
|
-
}
|
|
2275
|
-
const feeShare = divide(multiply(totalFee, partQty), sourceQty);
|
|
2276
|
-
return feeShare.toFixed();
|
|
2277
2195
|
}
|
|
2278
|
-
__name(
|
|
2196
|
+
__name(sourceToApplicableFill, "sourceToApplicableFill");
|
|
2279
2197
|
|
|
2280
2198
|
// src/sync/applicables/position.ts
|
|
2281
2199
|
function assembleApplicables(args) {
|
|
2282
2200
|
const { positions, connector, synthByPosition, now } = args;
|
|
2283
|
-
const
|
|
2201
|
+
const fillsById = /* @__PURE__ */ new Map();
|
|
2284
2202
|
const applicables = [];
|
|
2285
2203
|
for (const pos of positions) {
|
|
2286
|
-
const applicable = assembleOneApplicable(pos, connector,
|
|
2204
|
+
const applicable = assembleOneApplicable(pos, connector, fillsById, synthByPosition.get(pos) ?? [], now);
|
|
2287
2205
|
if (applicable) {
|
|
2288
2206
|
applicables.push(applicable);
|
|
2289
2207
|
}
|
|
2290
2208
|
}
|
|
2291
|
-
return
|
|
2209
|
+
return {
|
|
2210
|
+
fills: [
|
|
2211
|
+
...fillsById.values()
|
|
2212
|
+
].sort((a, b) => a.timestamp - b.timestamp || a.exchangeFillId.localeCompare(b.exchangeFillId)),
|
|
2213
|
+
applicables
|
|
2214
|
+
};
|
|
2292
2215
|
}
|
|
2293
2216
|
__name(assembleApplicables, "assembleApplicables");
|
|
2294
|
-
function assembleOneApplicable(pos, connector,
|
|
2295
|
-
const { realFills, closedReason } = finalizeRealFills(pos, connector
|
|
2217
|
+
function assembleOneApplicable(pos, connector, fillsById, assignedSynthetics, now) {
|
|
2218
|
+
const { realFills, assignments, closedReason } = finalizeRealFills(pos, connector);
|
|
2296
2219
|
const syntheticFills = assignedSynthetics.map((synthetic) => buildSyntheticFill({
|
|
2297
2220
|
positionKey: pos.positionKey,
|
|
2221
|
+
lifecycleStartedAt: pos.lifecycleStartedAt,
|
|
2298
2222
|
connector,
|
|
2299
2223
|
timestamp: anchorSyntheticTimestamp(realFills, synthetic.symbol, now),
|
|
2300
2224
|
...synthetic
|
|
2301
2225
|
}));
|
|
2302
|
-
const
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2226
|
+
for (const part of pos.parts) {
|
|
2227
|
+
fillsById.set(part.source.exchangeFillId, sourceToApplicableFill(part.source, connector));
|
|
2228
|
+
}
|
|
2229
|
+
for (const fill of syntheticFills) {
|
|
2230
|
+
fillsById.set(fill.exchangeFillId, fill);
|
|
2231
|
+
assignments.push({
|
|
2232
|
+
exchangeFillId: fill.exchangeFillId,
|
|
2233
|
+
quantity: fill.quantity
|
|
2234
|
+
});
|
|
2235
|
+
}
|
|
2236
|
+
if (realFills.length === 0 && syntheticFills.length === 0) {
|
|
2307
2237
|
return null;
|
|
2308
2238
|
}
|
|
2309
2239
|
const exposure = finalExposure(pos, assignedSynthetics);
|
|
2310
2240
|
const closed = exposure.isAllZero();
|
|
2311
2241
|
const status = closed ? "CLOSED" : "OPEN";
|
|
2312
|
-
const origin = mergeOrigin(pos.existingOrigin,
|
|
2242
|
+
const origin = mergeOrigin(pos.existingOrigin, [
|
|
2243
|
+
...realFills,
|
|
2244
|
+
...syntheticFills
|
|
2245
|
+
]);
|
|
2313
2246
|
return {
|
|
2314
2247
|
positionKey: pos.positionKey,
|
|
2315
2248
|
exposure: exposure.toSigned(),
|
|
@@ -2318,32 +2251,46 @@ function assembleOneApplicable(pos, connector, partIdFor, assignedSynthetics, no
|
|
|
2318
2251
|
...closed ? {
|
|
2319
2252
|
closedReason
|
|
2320
2253
|
} : {},
|
|
2321
|
-
|
|
2254
|
+
assignments: assignments.sort((a, b) => (fillsById.get(a.exchangeFillId)?.timestamp ?? 0) - (fillsById.get(b.exchangeFillId)?.timestamp ?? 0)),
|
|
2322
2255
|
metadata: buildMetadata(new Set(exposure.symbols()), realFills)
|
|
2323
2256
|
};
|
|
2324
2257
|
}
|
|
2325
2258
|
__name(assembleOneApplicable, "assembleOneApplicable");
|
|
2326
|
-
function finalizeRealFills(position, connector
|
|
2259
|
+
function finalizeRealFills(position, connector) {
|
|
2327
2260
|
const newestFirst = [
|
|
2328
2261
|
...position.parts
|
|
2329
2262
|
].sort((a, b) => a.source.timestamp - b.source.timestamp).reverse();
|
|
2330
2263
|
const exposure = position.exposure.clone();
|
|
2331
2264
|
const realFills = [];
|
|
2332
|
-
|
|
2265
|
+
const assignments = [];
|
|
2266
|
+
let closedReason = "USER";
|
|
2333
2267
|
for (const [index, part] of newestFirst.entries()) {
|
|
2334
2268
|
const after = exposure.get(part.source.symbol);
|
|
2335
|
-
const flatAfter = exposure.
|
|
2269
|
+
const flatAfter = exposure.isAllZero();
|
|
2336
2270
|
exposure.addDelta(part.source.symbol, negate(signedBySide(part.quantity, part.source.side)));
|
|
2337
2271
|
const reducesLeg = isGreaterThan(exposure.get(part.source.symbol).abs(), after.abs());
|
|
2338
2272
|
const liquidationOutcome = part.source.liquidation && reducesLeg ? flatAfter ? "CLOSED" : "REDUCED" : null;
|
|
2339
2273
|
if (index === 0 && position.closed && liquidationOutcome === "CLOSED") {
|
|
2340
2274
|
closedReason = "LIQUIDATED";
|
|
2341
2275
|
}
|
|
2342
|
-
realFills.push(
|
|
2276
|
+
realFills.push({
|
|
2277
|
+
...sourceToApplicableFill(part.source, connector),
|
|
2278
|
+
quantity: part.quantity,
|
|
2279
|
+
usd: multiply(part.quantity, part.source.price).toFixed()
|
|
2280
|
+
});
|
|
2281
|
+
assignments.push({
|
|
2282
|
+
exchangeFillId: part.source.exchangeFillId,
|
|
2283
|
+
quantity: part.quantity,
|
|
2284
|
+
...liquidationOutcome === null ? {} : {
|
|
2285
|
+
liquidationOutcome
|
|
2286
|
+
}
|
|
2287
|
+
});
|
|
2343
2288
|
}
|
|
2344
2289
|
realFills.reverse();
|
|
2290
|
+
assignments.reverse();
|
|
2345
2291
|
return {
|
|
2346
2292
|
realFills,
|
|
2293
|
+
assignments,
|
|
2347
2294
|
closedReason
|
|
2348
2295
|
};
|
|
2349
2296
|
}
|
|
@@ -2468,7 +2415,7 @@ var PearHoldings = class _PearHoldings {
|
|
|
2468
2415
|
/** Filter `openPositions` to the given connector and wrap. */
|
|
2469
2416
|
static from(args) {
|
|
2470
2417
|
const { openPositions, connector } = args;
|
|
2471
|
-
return new _PearHoldings(openPositions.filter((position) => position.connector === connector));
|
|
2418
|
+
return new _PearHoldings(openPositions.filter((position) => position.connector === connector).sort((a, b) => Date.parse(a.createdAt) - Date.parse(b.createdAt) || a.id.localeCompare(b.id)));
|
|
2472
2419
|
}
|
|
2473
2420
|
/** The open Pear positions for this connector. */
|
|
2474
2421
|
positions() {
|
|
@@ -2598,7 +2545,7 @@ __name(isStrictTimestampBoundary, "isStrictTimestampBoundary");
|
|
|
2598
2545
|
async function computeSyncPayload(args) {
|
|
2599
2546
|
const { tradeAccountId, connector, openPositions, entryBySymbol, provisionalFills, confirmedExchangeFillIds, externalFills, exchangePositions, neverSynced } = args;
|
|
2600
2547
|
const fillsToProcess = _prepareExternalFills(externalFills, confirmedExchangeFillIds);
|
|
2601
|
-
const orphans = _excludeClaimedFills(provisionalFills, fillsToProcess);
|
|
2548
|
+
const orphans = _excludeClaimedFills(provisionalFills.filter((fill) => fill.tradeAccountId === tradeAccountId && fill.connector === connector), fillsToProcess);
|
|
2602
2549
|
const { keptOrphans, firstSyncTrim } = applyFirstSyncCutoff({
|
|
2603
2550
|
neverSynced,
|
|
2604
2551
|
fillsToProcess,
|
|
@@ -2606,7 +2553,7 @@ async function computeSyncPayload(args) {
|
|
|
2606
2553
|
exchangePositions,
|
|
2607
2554
|
connector
|
|
2608
2555
|
});
|
|
2609
|
-
const applicables = buildApplicables({
|
|
2556
|
+
const { fills, applicables } = buildApplicables({
|
|
2610
2557
|
tradeAccountId,
|
|
2611
2558
|
connector,
|
|
2612
2559
|
orphanFills: keptOrphans,
|
|
@@ -2620,6 +2567,7 @@ async function computeSyncPayload(args) {
|
|
|
2620
2567
|
}
|
|
2621
2568
|
const externalMaxTs = latestFillTimestamp(fillsToProcess);
|
|
2622
2569
|
return {
|
|
2570
|
+
fills,
|
|
2623
2571
|
applicables,
|
|
2624
2572
|
exchangePositions,
|
|
2625
2573
|
meta: {
|
|
@@ -2666,12 +2614,12 @@ function _excludeClaimedFills(provisionalFills, externalFills) {
|
|
|
2666
2614
|
for (const fill of provisionalFills) {
|
|
2667
2615
|
const cloid = _normalizeCloid(fill.cloid);
|
|
2668
2616
|
if (cloid) {
|
|
2669
|
-
ownedCloids.add(cloid);
|
|
2617
|
+
ownedCloids.add(`${fill.connector}:${cloid}`);
|
|
2670
2618
|
}
|
|
2671
2619
|
}
|
|
2672
2620
|
return externalFills.filter((fill) => {
|
|
2673
2621
|
const cloid = _normalizeCloid(fill.cloid);
|
|
2674
|
-
return cloid === void 0 || !ownedCloids.has(cloid);
|
|
2622
|
+
return cloid === void 0 || !ownedCloids.has(`${fill.connector}:${cloid}`);
|
|
2675
2623
|
});
|
|
2676
2624
|
}
|
|
2677
2625
|
__name(_excludeClaimedFills, "_excludeClaimedFills");
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import type { Connector, InstrumentPrecision, Side } from '@pear-protocol/types';
|
|
2
2
|
import BigNumber from 'bignumber.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* (BUY
|
|
4
|
+
* Rounding strategy for quantities that fall off the venue grid.
|
|
5
|
+
* 'side' keeps the historical behavior (BUY floors, SELL ceils); 'floor'
|
|
6
|
+
* rounds down on both sides so a fractional amount is never exceeded.
|
|
6
7
|
*/
|
|
7
|
-
export
|
|
8
|
+
export type QuantityRounding = 'side' | 'floor';
|
|
9
|
+
/**
|
|
10
|
+
* Round a raw quantity to an exchange-valid string for the given connector.
|
|
11
|
+
* Default 'side' rounding: BUY rounds down, SELL rounds up.
|
|
12
|
+
*/
|
|
13
|
+
export declare function preciseQuantity(connector: Connector, raw: BigNumber.Value, precision: InstrumentPrecision, side: Side, rounding?: QuantityRounding): string;
|
|
@@ -35,8 +35,9 @@ export declare function requestedBaseQuantity(leg: {
|
|
|
35
35
|
amount: string;
|
|
36
36
|
}, referencePrice: string): string;
|
|
37
37
|
/**
|
|
38
|
-
* Whether a close leg is refused for its size. A close
|
|
39
|
-
* the venue
|
|
40
|
-
*
|
|
38
|
+
* Whether a close leg is refused for its size. A close that flattens the venue position is valid at any
|
|
39
|
+
* size. When the venue reads it as a partial reduce instead, because another position holds the asset or
|
|
40
|
+
* the close leaves part of the position open, it is held to the venue's minimum order quantity and minimum
|
|
41
|
+
* order value at the order price (#1184).
|
|
41
42
|
*/
|
|
42
|
-
export declare function isRefusedBelowMinimum(quantity: string, price: string, precision: InstrumentPrecision,
|
|
43
|
+
export declare function isRefusedBelowMinimum(quantity: string, price: string, precision: InstrumentPrecision, isPartialVenueReduce: boolean): boolean;
|
|
@@ -16,10 +16,6 @@ export declare class Basket {
|
|
|
16
16
|
private constructor();
|
|
17
17
|
/** Detect baskets from a fill stream, returned in ascending time order. */
|
|
18
18
|
static detect(fills: HttpTypes.UnknownExternalFill[]): Basket[];
|
|
19
|
-
/** Active long symbol set the matcher compares against open positions. */
|
|
20
|
-
get longs(): Set<string>;
|
|
21
|
-
/** Active short symbol set the matcher compares against open positions. */
|
|
22
|
-
get shorts(): Set<string>;
|
|
23
19
|
}
|
|
24
20
|
/**
|
|
25
21
|
* One combined symbol+side leg of a basket. Owns the per-source FIFO queue, so
|
|
@@ -3,7 +3,7 @@ import type { FillPart } from './types';
|
|
|
3
3
|
/**
|
|
4
4
|
* Signed per-asset exposure of a position — the running `symbol -> quantity` book
|
|
5
5
|
* (BUY positive, SELL negative). Wraps the raw map so the signed-quantity math, the
|
|
6
|
-
*
|
|
6
|
+
* exact-zero closure rule, and leg-set queries live in one place instead of scattered helpers.
|
|
7
7
|
*
|
|
8
8
|
* Mutable by design: the matcher mutates a working position's exposure in place while
|
|
9
9
|
* replaying fills. Use {@link clone} when a caller needs an independent copy.
|
|
@@ -30,16 +30,8 @@ export declare class Exposure {
|
|
|
30
30
|
longs: Set<string>;
|
|
31
31
|
shorts: Set<string>;
|
|
32
32
|
};
|
|
33
|
-
/** True once every leg sits within DUST of zero (effectively closed). */
|
|
34
|
-
isFlat(): boolean;
|
|
35
33
|
/** True when every leg is exactly zero (a fully CLOSED position). */
|
|
36
34
|
isAllZero(): boolean;
|
|
37
|
-
/**
|
|
38
|
-
* Snap every non-zero leg to exactly zero. Called once a position is flat so it
|
|
39
|
-
* reads CLOSED (all-zero exposure) and never lingers in the open list with stray
|
|
40
|
-
* dust that a later reopen of the same pair could merge into.
|
|
41
|
-
*/
|
|
42
|
-
snapToZero(): void;
|
|
43
35
|
/** All symbols with a leg, including zeroed ones (a closed leg still carries cost basis). */
|
|
44
36
|
symbols(): string[];
|
|
45
37
|
/** Canonical signed-string view for the wire (`+0` for zero). */
|
|
@@ -1,16 +1,3 @@
|
|
|
1
1
|
import type { HttpTypes } from '@pear-protocol/types';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* A source fill may be split into multiple slices (different positions). Build a
|
|
5
|
-
* stable id per slice: unsplit slices keep the native id; split slices get a
|
|
6
|
-
* deterministic `-pN` suffix plus an `original` pointer to the source.
|
|
7
|
-
* Returns an accessor; every part of every given position has an id by construction.
|
|
8
|
-
*/
|
|
9
|
-
export declare function assignPartIds(positions: MatchedPosition[]): (part: FillPart) => PartId;
|
|
10
|
-
/**
|
|
11
|
-
* Convert a matched fill slice into the wire-shape ApplicableFill the server persists.
|
|
12
|
-
* Three shapes emerge: a real external fill, a real Pear fill (cloid we minted), or a
|
|
13
|
-
* missed-history synthetic (external, priced to reconcile with the exchange entry).
|
|
14
|
-
* Fees are quantity-prorated when the source fill was split across positions.
|
|
15
|
-
*/
|
|
16
|
-
export declare function partToApplicableFill(part: FillPart, id: PartId, connector: HttpTypes.Connector, liquidationOutcome: 'CLOSED' | 'REDUCED' | null): HttpTypes.ApplicableFill;
|
|
2
|
+
/** Format one canonical source receipt without changing its quantity or fees. */
|
|
3
|
+
export declare function sourceToApplicableFill(fill: HttpTypes.UnknownExternalFill, connector: HttpTypes.Connector): HttpTypes.ApplicableFill;
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* find-or-creates into positions.
|
|
4
4
|
*
|
|
5
5
|
* Each fill is processed against the currently open positions, oldest first:
|
|
6
|
-
* 1.
|
|
7
|
-
* 2.
|
|
6
|
+
* 1. reduce opposing positions in creation order,
|
|
7
|
+
* 2. consume each opposing leg before opening its remainder,
|
|
8
8
|
* 3. else merge the leftover into an open position already holding those legs, or open a new one.
|
|
9
9
|
* A fill can be split across several positions when it closes more than one.
|
|
10
10
|
*
|
|
@@ -20,7 +20,7 @@ import type { HttpTypes } from '@pear-protocol/types';
|
|
|
20
20
|
/**
|
|
21
21
|
* Build the `applicables` bucket: baskets of fills (real + synthetic) keyed by a
|
|
22
22
|
* deterministic positionKey, plus creation metadata. Positions are derived by
|
|
23
|
-
* replaying fills through dynamic matching (
|
|
23
|
+
* replaying fills through dynamic matching (oldest-first cross-
|
|
24
24
|
* position close, subset-merge of leftover opens), so same-asset exposure
|
|
25
25
|
* consolidates instead of fragmenting per basket symbol-set.
|
|
26
26
|
*/
|
|
@@ -31,4 +31,7 @@ export declare function buildApplicables(args: {
|
|
|
31
31
|
openPositions: HttpTypes.OpenPositionLite[];
|
|
32
32
|
entryBySymbol: Record<string, string>;
|
|
33
33
|
exchangePositions: HttpTypes.ExternalPosition[];
|
|
34
|
-
}):
|
|
34
|
+
}): {
|
|
35
|
+
fills: HttpTypes.ApplicableFill[];
|
|
36
|
+
applicables: HttpTypes.ApplicablePosition[];
|
|
37
|
+
};
|
|
@@ -3,9 +3,7 @@ import type { PearHoldings } from './snapshot';
|
|
|
3
3
|
import type { MatchedPosition } from './types';
|
|
4
4
|
/**
|
|
5
5
|
* Replay external fills to decide which position each fill slice belongs to. Flow :
|
|
6
|
-
* -
|
|
7
|
-
* basket (dead legs ignored) — the basket closes that position first,
|
|
8
|
-
* - applyCloses reduces holders (the mirrored target first, then any other),
|
|
6
|
+
* - applyCloses reduces holders (the oldest eligible position first),
|
|
9
7
|
* - resolveLeftoverTarget merges into a position whose FULL leg set (active and
|
|
10
8
|
* dormant) is exactly the leftover's, else opens new (same-shape ADDs consolidate here).
|
|
11
9
|
* The asset SET of a position never grows, so positionKey == key(opening symbols).
|
|
@@ -5,13 +5,15 @@
|
|
|
5
5
|
import type { HttpTypes } from '@pear-protocol/types';
|
|
6
6
|
import type { MatchedPosition, NeededSynthetic } from './types';
|
|
7
7
|
/**
|
|
8
|
-
* Assemble
|
|
9
|
-
*
|
|
10
|
-
* positions that produced no fills).
|
|
8
|
+
* Assemble canonical receipts once and position assignments separately, dropping
|
|
9
|
+
* unchanged positions that produced no fills.
|
|
11
10
|
*/
|
|
12
11
|
export declare function assembleApplicables(args: {
|
|
13
12
|
positions: MatchedPosition[];
|
|
14
13
|
connector: HttpTypes.Connector;
|
|
15
14
|
synthByPosition: Map<MatchedPosition, NeededSynthetic[]>;
|
|
16
15
|
now: number;
|
|
17
|
-
}):
|
|
16
|
+
}): {
|
|
17
|
+
fills: HttpTypes.ApplicableFill[];
|
|
18
|
+
applicables: HttpTypes.ApplicablePosition[];
|
|
19
|
+
};
|
|
@@ -40,9 +40,10 @@ export declare function alignPositionsWithExchange(args: {
|
|
|
40
40
|
positions: MatchedPosition[];
|
|
41
41
|
synthByPosition: Map<MatchedPosition, NeededSynthetic[]>;
|
|
42
42
|
};
|
|
43
|
-
/** Build the content-addressed synthetic fill for a position/asset/side
|
|
43
|
+
/** Build the content-addressed synthetic fill for a position lifecycle/asset/side. */
|
|
44
44
|
export declare function buildSyntheticFill(args: {
|
|
45
45
|
positionKey: string;
|
|
46
|
+
lifecycleStartedAt: number | null;
|
|
46
47
|
connector: HttpTypes.Connector;
|
|
47
48
|
symbol: string;
|
|
48
49
|
side: Side;
|
|
@@ -26,6 +26,8 @@ export type FillPart = {
|
|
|
26
26
|
*/
|
|
27
27
|
export type WorkingPosition = {
|
|
28
28
|
positionKey: string;
|
|
29
|
+
createdAt: number;
|
|
30
|
+
orderId: string;
|
|
29
31
|
exposure: Exposure;
|
|
30
32
|
parts: FillPart[];
|
|
31
33
|
closed: boolean;
|
|
@@ -51,6 +53,12 @@ export type MatchedPosition = {
|
|
|
51
53
|
exposure: Exposure;
|
|
52
54
|
/** Origin of the seeded existing position; undefined when this applicable creates a position. */
|
|
53
55
|
existingOrigin?: HttpTypes.PositionOrigin;
|
|
56
|
+
/**
|
|
57
|
+
* When this lifecycle of the position key began (ms): the stored creation time of a seeded
|
|
58
|
+
* position, else the earliest fill this replay assigned to it. Null for a position the align
|
|
59
|
+
* step mints from the snapshot alone — no fill or stored row dates that lifecycle.
|
|
60
|
+
*/
|
|
61
|
+
lifecycleStartedAt: number | null;
|
|
54
62
|
};
|
|
55
63
|
/** One combined leg that could not be closed against existing exposure — an open. */
|
|
56
64
|
export type Leftover = {
|
|
@@ -72,11 +80,3 @@ export type NeededSynthetic = {
|
|
|
72
80
|
quantity: string;
|
|
73
81
|
closedReason?: HttpTypes.PositionClosedReason;
|
|
74
82
|
};
|
|
75
|
-
/** Per-slice id + `original` pointer, resolved once across ALL positions so split slices stay unique. */
|
|
76
|
-
export type PartId = {
|
|
77
|
-
exchangeFillId: string;
|
|
78
|
-
original?: {
|
|
79
|
-
exchangeFillId: string;
|
|
80
|
-
quantity: string;
|
|
81
|
-
};
|
|
82
|
-
};
|
package/dist/sync/types.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export type ComputeSyncPayloadArgs = {
|
|
|
11
11
|
neverSynced: boolean;
|
|
12
12
|
};
|
|
13
13
|
export type ComputeSyncPayloadResult = {
|
|
14
|
+
fills: HttpTypes.ApplicableFill[];
|
|
14
15
|
applicables: HttpTypes.ApplicablePosition[];
|
|
15
16
|
exchangePositions: HttpTypes.ExternalPosition[];
|
|
16
17
|
meta: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pear-protocol/utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.1",
|
|
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.25.0",
|
|
31
31
|
"@scure/base": "^2.3.0",
|
|
32
32
|
"bignumber.js": "9.3.1"
|
|
33
33
|
},
|