@pear-protocol/exchanges-sdk 0.6.2 → 0.6.3
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/README.md
CHANGED
|
@@ -101,7 +101,7 @@ const exchanges = new ExchangesSDK({
|
|
|
101
101
|
|
|
102
102
|
Hyperliquid status requires the builder address and the minimum approved fee in tenths of a basis point. Lighter status requires the integrator account and minimum maker/taker approval caps in Lighter fee ticks (parts per million). These thresholds must match the fees configured by the trading backend.
|
|
103
103
|
|
|
104
|
-
Historical Hyperliquid fill synchronization
|
|
104
|
+
Historical Hyperliquid fill synchronization identifies fills by bare `tid` and requests them aggregated by time, so partial fills of one crossing order arrive as a single fill. Consumers that persisted composite `time:coin:tid` identifiers must account for the transition overlap. Hyperliquid serves only the 10,000 most recent fills; an account with a longer history imports from that boundary forward, and the snapshot-alignment synthetics cover the residual gap. Synchronization fails closed when the exchange reports a maker rebate: the current core external-fill contract accepts only non-negative fees, so the SDK will not silently turn a rebate into a cost or advance the synchronization watermark past it.
|
|
105
105
|
|
|
106
106
|
## Account Status
|
|
107
107
|
|
|
@@ -64,11 +64,10 @@ class HyperliquidAccountSyncer extends BaseAccountSyncer {
|
|
|
64
64
|
return acc;
|
|
65
65
|
}, {});
|
|
66
66
|
const allFills = [];
|
|
67
|
-
const
|
|
67
|
+
const seenTids = /* @__PURE__ */ new Set();
|
|
68
68
|
const addFill = (fill) => {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
seenFillIds.add(fillId);
|
|
69
|
+
if (!seenTids.has(fill.tid)) {
|
|
70
|
+
seenTids.add(fill.tid);
|
|
72
71
|
allFills.push(fill);
|
|
73
72
|
}
|
|
74
73
|
};
|
|
@@ -80,7 +79,7 @@ class HyperliquidAccountSyncer extends BaseAccountSyncer {
|
|
|
80
79
|
type: "userFillsByTime",
|
|
81
80
|
user: this.address,
|
|
82
81
|
startTime: cursor,
|
|
83
|
-
aggregateByTime:
|
|
82
|
+
aggregateByTime: true
|
|
84
83
|
},
|
|
85
84
|
this.demo
|
|
86
85
|
);
|
|
@@ -104,7 +103,7 @@ class HyperliquidAccountSyncer extends BaseAccountSyncer {
|
|
|
104
103
|
type: "userTwapSliceFillsByTime",
|
|
105
104
|
user: this.address,
|
|
106
105
|
startTime: cursor,
|
|
107
|
-
aggregateByTime:
|
|
106
|
+
aggregateByTime: true
|
|
108
107
|
},
|
|
109
108
|
this.demo
|
|
110
109
|
);
|
|
@@ -131,12 +130,12 @@ class HyperliquidAccountSyncer extends BaseAccountSyncer {
|
|
|
131
130
|
const tradeFee = new BigNumber(rawFill.fee).minus(rawFill.builderFee ?? "0");
|
|
132
131
|
if (tradeFee.isNegative()) {
|
|
133
132
|
throw new Error(
|
|
134
|
-
`Hyperliquid fill ${
|
|
133
|
+
`Hyperliquid fill ${rawFill.tid} has a negative net trade fee (${tradeFee.toFixed()}); the backend external-fill contract does not accept Hyperliquid rebates.`
|
|
135
134
|
);
|
|
136
135
|
}
|
|
137
136
|
fills.push({
|
|
138
137
|
connector: "hyperliquid",
|
|
139
|
-
exchangeFillId:
|
|
138
|
+
exchangeFillId: rawFill.tid.toFixed(),
|
|
140
139
|
cloid: rawFill.cloid ?? null,
|
|
141
140
|
symbol: instrumentId,
|
|
142
141
|
price: rawFill.px,
|
|
@@ -191,9 +190,6 @@ class HyperliquidAccountSyncer extends BaseAccountSyncer {
|
|
|
191
190
|
return rawFill.dir.includes("Close");
|
|
192
191
|
}
|
|
193
192
|
}
|
|
194
|
-
function hyperliquidFillId(fill) {
|
|
195
|
-
return `${fill.time}:${fill.coin}:${fill.tid}`;
|
|
196
|
-
}
|
|
197
193
|
function warnStalledPagination(stream, cursor) {
|
|
198
194
|
console.warn(`Hyperliquid ${stream} pagination stalled at timestamp ${cursor}; returned history may be incomplete.`);
|
|
199
195
|
}
|
|
@@ -77,18 +77,18 @@ describe("HyperliquidAccountSyncer fill mapping", () => {
|
|
|
77
77
|
});
|
|
78
78
|
expect(fills).toEqual([
|
|
79
79
|
expect.objectContaining({
|
|
80
|
-
exchangeFillId: "
|
|
80
|
+
exchangeFillId: "456",
|
|
81
81
|
tradeFee: "0.8",
|
|
82
82
|
builderFee: "0.2"
|
|
83
83
|
})
|
|
84
84
|
]);
|
|
85
85
|
expect(fetchInfoMock).toHaveBeenCalledWith(expect.objectContaining({ type: "userFillsByTime" }), true);
|
|
86
86
|
expect(fetchInfoMock).toHaveBeenCalledWith(
|
|
87
|
-
expect.objectContaining({ type: "userFillsByTime", aggregateByTime:
|
|
87
|
+
expect.objectContaining({ type: "userFillsByTime", aggregateByTime: true }),
|
|
88
88
|
true
|
|
89
89
|
);
|
|
90
90
|
expect(fetchInfoMock).toHaveBeenCalledWith(
|
|
91
|
-
expect.objectContaining({ type: "userTwapSliceFillsByTime", aggregateByTime:
|
|
91
|
+
expect.objectContaining({ type: "userTwapSliceFillsByTime", aggregateByTime: true }),
|
|
92
92
|
true
|
|
93
93
|
);
|
|
94
94
|
});
|
|
@@ -125,7 +125,7 @@ describe("HyperliquidAccountSyncer fill mapping", () => {
|
|
|
125
125
|
provisionalFills: []
|
|
126
126
|
})
|
|
127
127
|
).rejects.toThrow(
|
|
128
|
-
"Hyperliquid fill
|
|
128
|
+
"Hyperliquid fill 456 has a negative net trade fee (-0.1); the backend external-fill contract does not accept Hyperliquid rebates."
|
|
129
129
|
);
|
|
130
130
|
});
|
|
131
131
|
it("warns when inclusive fill pagination cannot move past the current timestamp", async () => {
|
|
@@ -181,7 +181,7 @@ describe("HyperliquidAccountSyncer fill mapping", () => {
|
|
|
181
181
|
provisionalFills: []
|
|
182
182
|
});
|
|
183
183
|
expect(fills).toHaveLength(1e4);
|
|
184
|
-
expect(fetchInfoMock).toHaveBeenCalledWith(expect.objectContaining({ aggregateByTime:
|
|
184
|
+
expect(fetchInfoMock).toHaveBeenCalledWith(expect.objectContaining({ aggregateByTime: true }), true);
|
|
185
185
|
});
|
|
186
186
|
it("pages through a full retention window of fills", async () => {
|
|
187
187
|
let page = 0;
|