@logswap/sdk 0.5.57 → 0.5.58
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/fees.d.ts +11 -1
- package/dist/fees.js +34 -8
- package/package.json +1 -1
- package/src/fees.ts +32 -6
package/dist/fees.d.ts
CHANGED
|
@@ -30,7 +30,17 @@ export interface SwapFeeWindow {
|
|
|
30
30
|
swapFees: bigint;
|
|
31
31
|
swaps: number;
|
|
32
32
|
}
|
|
33
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* The first block with timestamp ≥ `t` in `[lo, hi]`; `hi` when none is earlier.
|
|
35
|
+
*
|
|
36
|
+
* A PARALLEL search: each round reads {@link PROBES} evenly spaced blocks at once and keeps the
|
|
37
|
+
* sixteenth of the bracket that holds the answer, so 64k blocks take 4 round trips. Bisection read
|
|
38
|
+
* one block per round trip — ~16 sequential `getBlock`s, seconds apiece against a distant node,
|
|
39
|
+
* before a fee figure could render. Interpolating on timestamps was tried and did no better: a
|
|
40
|
+
* devnet mines on demand plus a heartbeat, so its blocks are far from evenly spaced in time.
|
|
41
|
+
* Exact for monotonic timestamps; a chain restored from a snapshot can carry a genesis stamped
|
|
42
|
+
* after its later blocks, so callers bound `lo` by the block they care about (a pool's own).
|
|
43
|
+
*/
|
|
34
44
|
export declare function blockAtOrAfter(c: LogswapClient, t: bigint, lo: bigint, hi: bigint): Promise<bigint>;
|
|
35
45
|
/**
|
|
36
46
|
* Sum the swap fees of market `m` over a window: from `since` (unix seconds) or `fromBlock`, to
|
package/dist/fees.js
CHANGED
|
@@ -17,16 +17,42 @@ const YEAR_SECONDS = 31_536_000;
|
|
|
17
17
|
export function swapFeeOf(e, phi) {
|
|
18
18
|
return e.baseIn ? (e.amountOut * phi) / (WAD - phi) : (e.amountIn * phi) / (WAD + phi);
|
|
19
19
|
}
|
|
20
|
-
/**
|
|
20
|
+
/** Probes per round of {@link blockAtOrAfter}: 15 splits the bracket 16 ways. */
|
|
21
|
+
const PROBES = 15n;
|
|
22
|
+
/**
|
|
23
|
+
* The first block with timestamp ≥ `t` in `[lo, hi]`; `hi` when none is earlier.
|
|
24
|
+
*
|
|
25
|
+
* A PARALLEL search: each round reads {@link PROBES} evenly spaced blocks at once and keeps the
|
|
26
|
+
* sixteenth of the bracket that holds the answer, so 64k blocks take 4 round trips. Bisection read
|
|
27
|
+
* one block per round trip — ~16 sequential `getBlock`s, seconds apiece against a distant node,
|
|
28
|
+
* before a fee figure could render. Interpolating on timestamps was tried and did no better: a
|
|
29
|
+
* devnet mines on demand plus a heartbeat, so its blocks are far from evenly spaced in time.
|
|
30
|
+
* Exact for monotonic timestamps; a chain restored from a snapshot can carry a genesis stamped
|
|
31
|
+
* after its later blocks, so callers bound `lo` by the block they care about (a pool's own).
|
|
32
|
+
*/
|
|
21
33
|
export async function blockAtOrAfter(c, t, lo, hi) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
34
|
+
if (lo >= hi)
|
|
35
|
+
return hi;
|
|
36
|
+
const stamp = async (n) => (await c.public.getBlock({ blockNumber: n })).timestamp;
|
|
37
|
+
if ((await stamp(lo)) >= t)
|
|
38
|
+
return lo;
|
|
39
|
+
// invariant from here: ts(lo) < t, and the answer is in (lo, hi]
|
|
40
|
+
while (hi - lo > 1n) {
|
|
41
|
+
const width = hi - lo;
|
|
42
|
+
const probes = [...new Set(Array.from({ length: Number(PROBES) }, (_, i) => lo + (width * BigInt(i + 1)) / (PROBES + 1n)))].filter((n) => n > lo && n < hi);
|
|
43
|
+
if (probes.length === 0)
|
|
44
|
+
probes.push(lo + width / 2n);
|
|
45
|
+
const stamps = await Promise.all(probes.map(stamp));
|
|
46
|
+
const first = stamps.findIndex((ts) => ts >= t);
|
|
47
|
+
if (first === -1)
|
|
48
|
+
lo = probes[probes.length - 1];
|
|
49
|
+
else {
|
|
50
|
+
hi = probes[first];
|
|
51
|
+
if (first > 0)
|
|
52
|
+
lo = probes[first - 1];
|
|
53
|
+
}
|
|
28
54
|
}
|
|
29
|
-
return
|
|
55
|
+
return hi;
|
|
30
56
|
}
|
|
31
57
|
/**
|
|
32
58
|
* Sum the swap fees of market `m` over a window: from `since` (unix seconds) or `fromBlock`, to
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logswap/sdk",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.58",
|
|
4
4
|
"description": "TypeScript SDK for Logswap, the liquidity primitive introducing the logarithmic invariant — typed wrappers over the CPoolManager / FPoolManager / Router / Lens surface.",
|
|
5
5
|
"license": "GPL-2.0-or-later",
|
|
6
6
|
"type": "module",
|
package/src/fees.ts
CHANGED
|
@@ -36,14 +36,40 @@ export interface SwapFeeWindow {
|
|
|
36
36
|
swaps: number;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
/**
|
|
39
|
+
/** Probes per round of {@link blockAtOrAfter}: 15 splits the bracket 16 ways. */
|
|
40
|
+
const PROBES = 15n;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The first block with timestamp ≥ `t` in `[lo, hi]`; `hi` when none is earlier.
|
|
44
|
+
*
|
|
45
|
+
* A PARALLEL search: each round reads {@link PROBES} evenly spaced blocks at once and keeps the
|
|
46
|
+
* sixteenth of the bracket that holds the answer, so 64k blocks take 4 round trips. Bisection read
|
|
47
|
+
* one block per round trip — ~16 sequential `getBlock`s, seconds apiece against a distant node,
|
|
48
|
+
* before a fee figure could render. Interpolating on timestamps was tried and did no better: a
|
|
49
|
+
* devnet mines on demand plus a heartbeat, so its blocks are far from evenly spaced in time.
|
|
50
|
+
* Exact for monotonic timestamps; a chain restored from a snapshot can carry a genesis stamped
|
|
51
|
+
* after its later blocks, so callers bound `lo` by the block they care about (a pool's own).
|
|
52
|
+
*/
|
|
40
53
|
export async function blockAtOrAfter(c: LogswapClient, t: bigint, lo: bigint, hi: bigint): Promise<bigint> {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
if (lo >= hi) return hi;
|
|
55
|
+
const stamp = async (n: bigint) => (await c.public.getBlock({ blockNumber: n })).timestamp;
|
|
56
|
+
if ((await stamp(lo)) >= t) return lo;
|
|
57
|
+
// invariant from here: ts(lo) < t, and the answer is in (lo, hi]
|
|
58
|
+
while (hi - lo > 1n) {
|
|
59
|
+
const width = hi - lo;
|
|
60
|
+
const probes = [...new Set(Array.from({ length: Number(PROBES) }, (_, i) => lo + (width * BigInt(i + 1)) / (PROBES + 1n)))].filter(
|
|
61
|
+
(n) => n > lo && n < hi,
|
|
62
|
+
);
|
|
63
|
+
if (probes.length === 0) probes.push(lo + width / 2n);
|
|
64
|
+
const stamps = await Promise.all(probes.map(stamp));
|
|
65
|
+
const first = stamps.findIndex((ts) => ts >= t);
|
|
66
|
+
if (first === -1) lo = probes[probes.length - 1]!;
|
|
67
|
+
else {
|
|
68
|
+
hi = probes[first]!;
|
|
69
|
+
if (first > 0) lo = probes[first - 1]!;
|
|
70
|
+
}
|
|
45
71
|
}
|
|
46
|
-
return
|
|
72
|
+
return hi;
|
|
47
73
|
}
|
|
48
74
|
|
|
49
75
|
/**
|