@shroud-fi/scanning 0.1.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/LICENSE +21 -0
- package/README.md +57 -0
- package/dist/cjs/backend.d.ts +2 -0
- package/dist/cjs/backend.d.ts.map +1 -0
- package/dist/cjs/backend.js +6 -0
- package/dist/cjs/backend.js.map +1 -0
- package/dist/cjs/constants.d.ts +14 -0
- package/dist/cjs/constants.d.ts.map +1 -0
- package/dist/cjs/constants.js +17 -0
- package/dist/cjs/constants.js.map +1 -0
- package/dist/cjs/cursor.d.ts +8 -0
- package/dist/cjs/cursor.d.ts.map +1 -0
- package/dist/cjs/cursor.js +28 -0
- package/dist/cjs/cursor.js.map +1 -0
- package/dist/cjs/dedup.d.ts +10 -0
- package/dist/cjs/dedup.d.ts.map +1 -0
- package/dist/cjs/dedup.js +48 -0
- package/dist/cjs/dedup.js.map +1 -0
- package/dist/cjs/detector.d.ts +9 -0
- package/dist/cjs/detector.d.ts.map +1 -0
- package/dist/cjs/detector.js +425 -0
- package/dist/cjs/detector.js.map +1 -0
- package/dist/cjs/errors.d.ts +21 -0
- package/dist/cjs/errors.d.ts.map +1 -0
- package/dist/cjs/errors.js +49 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/index.d.ts +9 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +33 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/types.d.ts +90 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +17 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/viem-backend.d.ts +14 -0
- package/dist/cjs/viem-backend.d.ts.map +1 -0
- package/dist/cjs/viem-backend.js +166 -0
- package/dist/cjs/viem-backend.js.map +1 -0
- package/dist/esm/backend.d.ts +2 -0
- package/dist/esm/backend.d.ts.map +1 -0
- package/dist/esm/backend.js +5 -0
- package/dist/esm/backend.js.map +1 -0
- package/dist/esm/constants.d.ts +14 -0
- package/dist/esm/constants.d.ts.map +1 -0
- package/dist/esm/constants.js +14 -0
- package/dist/esm/constants.js.map +1 -0
- package/dist/esm/cursor.d.ts +8 -0
- package/dist/esm/cursor.d.ts.map +1 -0
- package/dist/esm/cursor.js +24 -0
- package/dist/esm/cursor.js.map +1 -0
- package/dist/esm/dedup.d.ts +10 -0
- package/dist/esm/dedup.d.ts.map +1 -0
- package/dist/esm/dedup.js +44 -0
- package/dist/esm/dedup.js.map +1 -0
- package/dist/esm/detector.d.ts +9 -0
- package/dist/esm/detector.d.ts.map +1 -0
- package/dist/esm/detector.js +422 -0
- package/dist/esm/detector.js.map +1 -0
- package/dist/esm/errors.d.ts +21 -0
- package/dist/esm/errors.d.ts.map +1 -0
- package/dist/esm/errors.js +41 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/index.d.ts +9 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +15 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/types.d.ts +90 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +16 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/viem-backend.d.ts +14 -0
- package/dist/esm/viem-backend.d.ts.map +1 -0
- package/dist/esm/viem-backend.js +162 -0
- package/dist/esm/viem-backend.js.map +1 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Stealth-payment detector — orchestrates view-tag prefilter, ECDH recovery,
|
|
3
|
+
// finality gating, dedup, and reconciliation backfill.
|
|
4
|
+
//
|
|
5
|
+
// Privacy contract (binding — enforced by tests):
|
|
6
|
+
// - No console.* anywhere in this file.
|
|
7
|
+
// - No error message embeds key material, ephemeral pubkey bytes, or stealth
|
|
8
|
+
// private key. Short structured tags only ("verify failed", "backend
|
|
9
|
+
// unreachable").
|
|
10
|
+
// - No JSON.stringify of keys, raw announcements, or RawAnnouncement.metadata.
|
|
11
|
+
// - The recovered stealth private key only surfaces via the explicit return
|
|
12
|
+
// value DetectedPayment.stealthPrivateKey — never logged.
|
|
13
|
+
// - Backpressure note: the live watch() queue is unbounded by design for v1.
|
|
14
|
+
// A consumer that ignores yields will see memory grow; document if surfaces.
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.createScanner = createScanner;
|
|
17
|
+
const viem_1 = require("viem");
|
|
18
|
+
const accounts_1 = require("viem/accounts");
|
|
19
|
+
const core_1 = require("@shroud-fi/core");
|
|
20
|
+
const transport_1 = require("@shroud-fi/transport");
|
|
21
|
+
const constants_js_1 = require("./constants.js");
|
|
22
|
+
const cursor_js_1 = require("./cursor.js");
|
|
23
|
+
const dedup_js_1 = require("./dedup.js");
|
|
24
|
+
const errors_js_1 = require("./errors.js");
|
|
25
|
+
const viem_backend_js_1 = require("./viem-backend.js");
|
|
26
|
+
/**
|
|
27
|
+
* Build a Scanner instance.
|
|
28
|
+
*
|
|
29
|
+
* Construction validates config + resolves defaults. The Scanner is inert until
|
|
30
|
+
* the caller starts iterating watch() or scanRange(). close() is idempotent.
|
|
31
|
+
*/
|
|
32
|
+
function createScanner(config) {
|
|
33
|
+
if (config.transport === undefined || config.transport.publicClient === undefined) {
|
|
34
|
+
throw new errors_js_1.MissingPublicClientError();
|
|
35
|
+
}
|
|
36
|
+
if (config.startBlock < 0n) {
|
|
37
|
+
throw new errors_js_1.ScanningError('startBlock must be non-negative');
|
|
38
|
+
}
|
|
39
|
+
const schemeId = config.schemeId ?? constants_js_1.DEFAULT_SCHEME_ID;
|
|
40
|
+
const finality = config.finality ?? constants_js_1.DEFAULT_FINALITY;
|
|
41
|
+
const reconcileIntervalMs = config.reconcileIntervalMs ?? constants_js_1.DEFAULT_RECONCILE_INTERVAL_MS;
|
|
42
|
+
const dedupCapacity = config.dedupCapacity ?? constants_js_1.DEFAULT_DEDUP_CAPACITY;
|
|
43
|
+
const getLogsChunkSize = config.getLogsChunkSize ?? constants_js_1.DEFAULT_GETLOGS_CHUNK_SIZE;
|
|
44
|
+
const contractAddress = config.contractAddress ?? transport_1.ERC5564_ANNOUNCER;
|
|
45
|
+
const backend = config.backend ??
|
|
46
|
+
new viem_backend_js_1.ViemScannerBackend(config.transport.publicClient, {
|
|
47
|
+
getLogsChunkSize,
|
|
48
|
+
});
|
|
49
|
+
const dedup = new dedup_js_1.LRUDeduper(dedupCapacity);
|
|
50
|
+
const cursor = new cursor_js_1.Cursor(config.startBlock);
|
|
51
|
+
const pendingFinality = new Map();
|
|
52
|
+
let reconcileTimer;
|
|
53
|
+
let unsubscribe;
|
|
54
|
+
let closed = false;
|
|
55
|
+
// Reject concurrent watch() calls. The closure singletons above can hold at
|
|
56
|
+
// most one live subscription + timer; a second watch() would silently leak
|
|
57
|
+
// the first iterator's resources. Caller must close() before re-watching.
|
|
58
|
+
let watchActive = false;
|
|
59
|
+
// Cap pending events so a stuck backend can't grow memory unboundedly.
|
|
60
|
+
const pendingCap = Math.max(dedupCapacity, 100);
|
|
61
|
+
// ---- Verification pipeline ----------------------------------------------
|
|
62
|
+
/**
|
|
63
|
+
* Run view-tag prefilter + ECDH derivation + address-match check against
|
|
64
|
+
* a raw announcement. Returns recovered stealth private key bytes on match,
|
|
65
|
+
* or null when the announcement is not for this recipient (or is malformed).
|
|
66
|
+
* Never throws — returning null is the privacy-preserving signal.
|
|
67
|
+
*/
|
|
68
|
+
function verifyAnnouncement(raw) {
|
|
69
|
+
// Defence: metadata too short to even contain a view tag.
|
|
70
|
+
if (raw.metadata.length < constants_js_1.MIN_METADATA_LENGTH)
|
|
71
|
+
return null;
|
|
72
|
+
const viewTag = raw.metadata[0];
|
|
73
|
+
// Fast-path filter — drops ~99.6% of non-matching announcements.
|
|
74
|
+
let viewTagMatch;
|
|
75
|
+
try {
|
|
76
|
+
viewTagMatch = (0, core_1.checkViewTag)(config.scanningKey, raw.ephemeralPubKey, viewTag);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// Garbage ephemeral pubkey — drop silently.
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
if (!viewTagMatch)
|
|
83
|
+
return null;
|
|
84
|
+
// ECDH derivation of stealth private key.
|
|
85
|
+
let stealthPriv;
|
|
86
|
+
try {
|
|
87
|
+
stealthPriv = (0, core_1.computeStealthKey)(config.scanningKey, config.spendingKey, raw.ephemeralPubKey);
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
if (err instanceof core_1.InvalidKeyError || err instanceof core_1.StealthAddressError) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
// Re-wrap unknown failure with a privacy-safe message.
|
|
94
|
+
throw new errors_js_1.ScanningError('verify failed');
|
|
95
|
+
}
|
|
96
|
+
// Address-match check — guards against view-tag false positives and any
|
|
97
|
+
// log unrelated to this recipient.
|
|
98
|
+
let derivedAddress;
|
|
99
|
+
try {
|
|
100
|
+
const stealthPrivHex = (0, viem_1.bytesToHex)(stealthPriv);
|
|
101
|
+
derivedAddress = (0, accounts_1.privateKeyToAccount)(stealthPrivHex).address;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
if (derivedAddress.toLowerCase() !== raw.stealthAddress.toLowerCase()) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
return stealthPriv;
|
|
110
|
+
}
|
|
111
|
+
function dedupKey(raw) {
|
|
112
|
+
return `${raw.txHash}:${raw.logIndex}`;
|
|
113
|
+
}
|
|
114
|
+
function toDetected(raw, stealthPriv, payloadFinality) {
|
|
115
|
+
return {
|
|
116
|
+
stealthAddress: raw.stealthAddress,
|
|
117
|
+
ephemeralPubKey: (0, viem_1.bytesToHex)(raw.ephemeralPubKey),
|
|
118
|
+
stealthPrivateKey: (0, viem_1.bytesToHex)(stealthPriv),
|
|
119
|
+
blockNumber: raw.blockNumber,
|
|
120
|
+
blockHash: raw.blockHash,
|
|
121
|
+
txHash: raw.txHash,
|
|
122
|
+
logIndex: raw.logIndex,
|
|
123
|
+
finality: payloadFinality,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
// The configured `finality` is 'unsafe' | 'safe' | 'finalized', but the
|
|
127
|
+
// emitted DetectedPayment.finality is only 'safe' | 'finalized'. Treat
|
|
128
|
+
// 'unsafe' as 'safe' on the emit path (caller asked for no gating; we still
|
|
129
|
+
// tag what we yield as the safer label).
|
|
130
|
+
const emitFinality = finality === 'finalized' ? 'finalized' : 'safe';
|
|
131
|
+
// ---- watch() ------------------------------------------------------------
|
|
132
|
+
function watch(signal) {
|
|
133
|
+
return {
|
|
134
|
+
[Symbol.asyncIterator]: () => {
|
|
135
|
+
if (watchActive) {
|
|
136
|
+
// Surface as a rejecting first next() so callers learn via the
|
|
137
|
+
// async-iterator protocol instead of a sync throw from `for await`.
|
|
138
|
+
return {
|
|
139
|
+
next: () => Promise.reject(new errors_js_1.ScanningError('watch already active — close() first')),
|
|
140
|
+
return: () => Promise.resolve({ value: undefined, done: true }),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
watchActive = true;
|
|
144
|
+
const queue = [];
|
|
145
|
+
let waiter;
|
|
146
|
+
let finished = false;
|
|
147
|
+
let abortListener;
|
|
148
|
+
function finish() {
|
|
149
|
+
if (finished)
|
|
150
|
+
return;
|
|
151
|
+
finished = true;
|
|
152
|
+
if (waiter !== undefined) {
|
|
153
|
+
const w = waiter;
|
|
154
|
+
waiter = undefined;
|
|
155
|
+
w.resolve({ value: undefined, done: true });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function emit(payment) {
|
|
159
|
+
if (finished)
|
|
160
|
+
return;
|
|
161
|
+
if (waiter !== undefined) {
|
|
162
|
+
const w = waiter;
|
|
163
|
+
waiter = undefined;
|
|
164
|
+
w.resolve({ value: payment, done: false });
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
queue.push(payment);
|
|
168
|
+
}
|
|
169
|
+
async function tryEmitOrDefer(raw) {
|
|
170
|
+
const key = dedupKey(raw);
|
|
171
|
+
// Two-tier dedup: emitted (LRU) + in-flight pending. Skip duplicates
|
|
172
|
+
// arriving while the first delivery is still mid-pipeline.
|
|
173
|
+
if (dedup.has(key) || pendingFinality.has(key))
|
|
174
|
+
return;
|
|
175
|
+
const stealthPriv = verifyAnnouncement(raw);
|
|
176
|
+
if (stealthPriv === null)
|
|
177
|
+
return;
|
|
178
|
+
let tip;
|
|
179
|
+
try {
|
|
180
|
+
tip = await backend.getLatestBlock(finality);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
// Backend transient failure — keep the candidate around for the
|
|
184
|
+
// next reconciliation tick. Do not throw into the consumer stream.
|
|
185
|
+
pendingFinality.set(key, raw);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (raw.blockNumber > tip) {
|
|
189
|
+
// Cap pending map to prevent unbounded growth on stuck finality.
|
|
190
|
+
if (pendingFinality.size >= pendingCap) {
|
|
191
|
+
const oldest = pendingFinality.keys().next().value;
|
|
192
|
+
if (oldest !== undefined)
|
|
193
|
+
pendingFinality.delete(oldest);
|
|
194
|
+
}
|
|
195
|
+
pendingFinality.set(key, raw);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
// Race guard: if a concurrent path already added this key (e.g. the
|
|
199
|
+
// same announcement was delivered twice and both passed the initial
|
|
200
|
+
// has() check before either reached this point), drop the dup.
|
|
201
|
+
if (!dedup.add(key))
|
|
202
|
+
return;
|
|
203
|
+
pendingFinality.delete(key);
|
|
204
|
+
emit(toDetected(raw, stealthPriv, emitFinality));
|
|
205
|
+
}
|
|
206
|
+
// Already-aborted: bail before touching the backend.
|
|
207
|
+
if (signal?.aborted === true) {
|
|
208
|
+
finished = true;
|
|
209
|
+
return {
|
|
210
|
+
next: () => Promise.resolve({ value: undefined, done: true }),
|
|
211
|
+
return: () => Promise.resolve({ value: undefined, done: true }),
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
// Subscribe to live announcements.
|
|
215
|
+
try {
|
|
216
|
+
unsubscribe = backend.watchAnnouncements((raw) => {
|
|
217
|
+
if (finished || closed)
|
|
218
|
+
return;
|
|
219
|
+
// Fire-and-forget per backend contract.
|
|
220
|
+
void tryEmitOrDefer(raw).catch(() => {
|
|
221
|
+
// Swallow — never let pipeline errors crash the watcher.
|
|
222
|
+
});
|
|
223
|
+
}, { contractAddress, schemeId });
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
// If subscription fails outright, surface a privacy-safe error on
|
|
227
|
+
// the first next() and shut down.
|
|
228
|
+
finished = true;
|
|
229
|
+
return {
|
|
230
|
+
next: () => Promise.reject(new errors_js_1.BackendUnreachableError('watch subscribe failed')),
|
|
231
|
+
return: () => Promise.resolve({ value: undefined, done: true }),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
// Reconciliation tick — backfill missed blocks + re-check pending.
|
|
235
|
+
const timer = setInterval(() => {
|
|
236
|
+
void reconcileOnce().catch(() => {
|
|
237
|
+
// Never throw out of the interval.
|
|
238
|
+
});
|
|
239
|
+
}, reconcileIntervalMs);
|
|
240
|
+
// Don't keep the Node event loop alive solely on this timer.
|
|
241
|
+
if (typeof timer.unref === 'function') {
|
|
242
|
+
timer.unref();
|
|
243
|
+
}
|
|
244
|
+
reconcileTimer = timer;
|
|
245
|
+
async function reconcileOnce() {
|
|
246
|
+
if (finished || closed)
|
|
247
|
+
return;
|
|
248
|
+
// Phase 1: backfill any blocks between cursor and current tip.
|
|
249
|
+
let tip;
|
|
250
|
+
try {
|
|
251
|
+
tip = await backend.getLatestBlock(finality);
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
return; // Skip this tick — try again later.
|
|
255
|
+
}
|
|
256
|
+
const from = cursor.last + 1n;
|
|
257
|
+
if (tip >= from) {
|
|
258
|
+
let logs = [];
|
|
259
|
+
try {
|
|
260
|
+
logs = await backend.getAnnouncementsInRange(from, tip, {
|
|
261
|
+
contractAddress,
|
|
262
|
+
schemeId,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
// Leave cursor alone — try again next tick.
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
for (const raw of logs) {
|
|
270
|
+
if (finished || closed)
|
|
271
|
+
return;
|
|
272
|
+
const key = dedupKey(raw);
|
|
273
|
+
if (dedup.has(key))
|
|
274
|
+
continue;
|
|
275
|
+
const stealthPriv = verifyAnnouncement(raw);
|
|
276
|
+
if (stealthPriv === null)
|
|
277
|
+
continue;
|
|
278
|
+
if (!dedup.add(key))
|
|
279
|
+
continue;
|
|
280
|
+
pendingFinality.delete(key);
|
|
281
|
+
emit(toDetected(raw, stealthPriv, emitFinality));
|
|
282
|
+
}
|
|
283
|
+
// Re-check after the loop: close() may have run mid-iteration.
|
|
284
|
+
if (finished || closed)
|
|
285
|
+
return;
|
|
286
|
+
cursor.advanceTo(tip);
|
|
287
|
+
}
|
|
288
|
+
// Phase 2: re-check pending announcements that had not finalized.
|
|
289
|
+
if (pendingFinality.size > 0) {
|
|
290
|
+
for (const [key, raw] of Array.from(pendingFinality.entries())) {
|
|
291
|
+
if (finished || closed)
|
|
292
|
+
return;
|
|
293
|
+
if (raw.blockNumber <= tip) {
|
|
294
|
+
pendingFinality.delete(key);
|
|
295
|
+
if (dedup.has(key))
|
|
296
|
+
continue;
|
|
297
|
+
const stealthPriv = verifyAnnouncement(raw);
|
|
298
|
+
if (stealthPriv === null)
|
|
299
|
+
continue;
|
|
300
|
+
if (!dedup.add(key))
|
|
301
|
+
continue;
|
|
302
|
+
emit(toDetected(raw, stealthPriv, emitFinality));
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
// Wire abort. Listener handle retained so we can remove it on return().
|
|
308
|
+
if (signal !== undefined) {
|
|
309
|
+
abortListener = () => {
|
|
310
|
+
finish();
|
|
311
|
+
close();
|
|
312
|
+
};
|
|
313
|
+
signal.addEventListener('abort', abortListener, { once: true });
|
|
314
|
+
}
|
|
315
|
+
function teardown() {
|
|
316
|
+
if (signal !== undefined && abortListener !== undefined) {
|
|
317
|
+
try {
|
|
318
|
+
signal.removeEventListener('abort', abortListener);
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
// Some environments swallow this; safe to ignore.
|
|
322
|
+
}
|
|
323
|
+
abortListener = undefined;
|
|
324
|
+
}
|
|
325
|
+
watchActive = false;
|
|
326
|
+
}
|
|
327
|
+
return {
|
|
328
|
+
next() {
|
|
329
|
+
// queue.length and waiter assignment are both synchronous within
|
|
330
|
+
// this tick — no interleaving window exists between the empty
|
|
331
|
+
// check and the executor body. emit() will see `waiter` set by
|
|
332
|
+
// the time it can fire (next microtask).
|
|
333
|
+
if (queue.length > 0) {
|
|
334
|
+
const value = queue.shift();
|
|
335
|
+
return Promise.resolve({ value, done: false });
|
|
336
|
+
}
|
|
337
|
+
if (finished) {
|
|
338
|
+
return Promise.resolve({ value: undefined, done: true });
|
|
339
|
+
}
|
|
340
|
+
return new Promise((resolve) => {
|
|
341
|
+
waiter = { resolve };
|
|
342
|
+
});
|
|
343
|
+
},
|
|
344
|
+
return() {
|
|
345
|
+
finish();
|
|
346
|
+
teardown();
|
|
347
|
+
close();
|
|
348
|
+
return Promise.resolve({ value: undefined, done: true });
|
|
349
|
+
},
|
|
350
|
+
throw() {
|
|
351
|
+
finish();
|
|
352
|
+
teardown();
|
|
353
|
+
close();
|
|
354
|
+
return Promise.resolve({ value: undefined, done: true });
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
},
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
// ---- scanRange() --------------------------------------------------------
|
|
361
|
+
function scanRange(fromBlock, toBlock, signal) {
|
|
362
|
+
return {
|
|
363
|
+
[Symbol.asyncIterator]: async function* () {
|
|
364
|
+
if (signal !== undefined && signal.aborted)
|
|
365
|
+
return;
|
|
366
|
+
if (toBlock < fromBlock)
|
|
367
|
+
return;
|
|
368
|
+
let logs;
|
|
369
|
+
try {
|
|
370
|
+
logs = await backend.getAnnouncementsInRange(fromBlock, toBlock, {
|
|
371
|
+
contractAddress,
|
|
372
|
+
schemeId,
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
throw new errors_js_1.BackendUnreachableError('getLogs failed');
|
|
377
|
+
}
|
|
378
|
+
// Sort deterministically by (blockNumber, logIndex).
|
|
379
|
+
const sorted = [...logs].sort((a, b) => {
|
|
380
|
+
if (a.blockNumber === b.blockNumber) {
|
|
381
|
+
return a.logIndex - b.logIndex;
|
|
382
|
+
}
|
|
383
|
+
return a.blockNumber < b.blockNumber ? -1 : 1;
|
|
384
|
+
});
|
|
385
|
+
for (const raw of sorted) {
|
|
386
|
+
if (signal !== undefined && signal.aborted)
|
|
387
|
+
return;
|
|
388
|
+
const key = dedupKey(raw);
|
|
389
|
+
if (dedup.has(key))
|
|
390
|
+
continue;
|
|
391
|
+
const stealthPriv = verifyAnnouncement(raw);
|
|
392
|
+
if (stealthPriv === null)
|
|
393
|
+
continue;
|
|
394
|
+
if (!dedup.add(key))
|
|
395
|
+
continue;
|
|
396
|
+
// Caller invoked a historical range — finality is achieved.
|
|
397
|
+
yield toDetected(raw, stealthPriv, 'safe');
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
// ---- close() ------------------------------------------------------------
|
|
403
|
+
function close() {
|
|
404
|
+
if (closed)
|
|
405
|
+
return;
|
|
406
|
+
closed = true;
|
|
407
|
+
if (unsubscribe !== undefined) {
|
|
408
|
+
try {
|
|
409
|
+
unsubscribe();
|
|
410
|
+
}
|
|
411
|
+
catch {
|
|
412
|
+
// Swallow — close must not throw.
|
|
413
|
+
}
|
|
414
|
+
unsubscribe = undefined;
|
|
415
|
+
}
|
|
416
|
+
if (reconcileTimer !== undefined) {
|
|
417
|
+
clearInterval(reconcileTimer);
|
|
418
|
+
reconcileTimer = undefined;
|
|
419
|
+
}
|
|
420
|
+
// Reset re-entry guard so close() + new watch() works.
|
|
421
|
+
watchActive = false;
|
|
422
|
+
}
|
|
423
|
+
return { watch, scanRange, close };
|
|
424
|
+
}
|
|
425
|
+
//# sourceMappingURL=detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.js","sourceRoot":"","sources":["../../src/detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare class ScanningError extends Error {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
export declare class BackendUnreachableError extends ScanningError {
|
|
6
|
+
readonly name: string;
|
|
7
|
+
constructor(reason: string);
|
|
8
|
+
}
|
|
9
|
+
export declare class MalformedAnnouncementError extends ScanningError {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
constructor(reason: string);
|
|
12
|
+
}
|
|
13
|
+
export declare class MissingPublicClientError extends ScanningError {
|
|
14
|
+
readonly name: string;
|
|
15
|
+
constructor();
|
|
16
|
+
}
|
|
17
|
+
export declare class InvalidFinalityLevelError extends ScanningError {
|
|
18
|
+
readonly name: string;
|
|
19
|
+
constructor(level: string);
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAWA,qBAAa,aAAc,SAAQ,KAAK;IACtC,SAAkB,IAAI,EAAE,MAAM,CAAmB;gBACrC,OAAO,EAAE,MAAM;CAG5B;AAED,qBAAa,uBAAwB,SAAQ,aAAa;IACxD,SAAkB,IAAI,EAAE,MAAM,CAA6B;gBAC/C,MAAM,EAAE,MAAM;CAG3B;AAED,qBAAa,0BAA2B,SAAQ,aAAa;IAC3D,SAAkB,IAAI,EAAE,MAAM,CAAgC;gBAClD,MAAM,EAAE,MAAM;CAG3B;AAED,qBAAa,wBAAyB,SAAQ,aAAa;IACzD,SAAkB,IAAI,EAAE,MAAM,CAA8B;;CAI7D;AAED,qBAAa,yBAA0B,SAAQ,aAAa;IAC1D,SAAkB,IAAI,EAAE,MAAM,CAA+B;gBACjD,KAAK,EAAE,MAAM;CAG1B"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Privacy-safe error classes for @shroud-fi/scanning.
|
|
3
|
+
//
|
|
4
|
+
// Invariants enforced by tests in test/privacy-invariants.test.ts:
|
|
5
|
+
// - Error messages MUST NOT embed any 32-byte hex (key material, txHash is
|
|
6
|
+
// allowed but should not be the whole error payload).
|
|
7
|
+
// - Error messages MUST NOT embed ephemeral pubkey bytes.
|
|
8
|
+
// - Error messages MUST NOT embed transfer amounts.
|
|
9
|
+
// - Constructors take only short, structured tags (chainId, block, logIndex,
|
|
10
|
+
// short reason). The thrown error gets its full stack from V8; we don't
|
|
11
|
+
// attach extra fields.
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.InvalidFinalityLevelError = exports.MissingPublicClientError = exports.MalformedAnnouncementError = exports.BackendUnreachableError = exports.ScanningError = void 0;
|
|
14
|
+
class ScanningError extends Error {
|
|
15
|
+
name = 'ScanningError';
|
|
16
|
+
constructor(message) {
|
|
17
|
+
super(message);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.ScanningError = ScanningError;
|
|
21
|
+
class BackendUnreachableError extends ScanningError {
|
|
22
|
+
name = 'BackendUnreachableError';
|
|
23
|
+
constructor(reason) {
|
|
24
|
+
super(`Scanner backend unreachable: ${reason}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.BackendUnreachableError = BackendUnreachableError;
|
|
28
|
+
class MalformedAnnouncementError extends ScanningError {
|
|
29
|
+
name = 'MalformedAnnouncementError';
|
|
30
|
+
constructor(reason) {
|
|
31
|
+
super(`Malformed announcement skipped: ${reason}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.MalformedAnnouncementError = MalformedAnnouncementError;
|
|
35
|
+
class MissingPublicClientError extends ScanningError {
|
|
36
|
+
name = 'MissingPublicClientError';
|
|
37
|
+
constructor() {
|
|
38
|
+
super('Scanner transport has no publicClient');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.MissingPublicClientError = MissingPublicClientError;
|
|
42
|
+
class InvalidFinalityLevelError extends ScanningError {
|
|
43
|
+
name = 'InvalidFinalityLevelError';
|
|
44
|
+
constructor(level) {
|
|
45
|
+
super(`Invalid finality level: ${level}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.InvalidFinalityLevelError = InvalidFinalityLevelError;
|
|
49
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,EAAE;AACF,mEAAmE;AACnE,6EAA6E;AAC7E,0DAA0D;AAC1D,4DAA4D;AAC5D,sDAAsD;AACtD,+EAA+E;AAC/E,4EAA4E;AAC5E,2BAA2B;;;AAE3B,MAAa,aAAc,SAAQ,KAAK;IACpB,IAAI,GAAW,eAAe,CAAC;IACjD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;CACF;AALD,sCAKC;AAED,MAAa,uBAAwB,SAAQ,aAAa;IACtC,IAAI,GAAW,yBAAyB,CAAC;IAC3D,YAAY,MAAc;QACxB,KAAK,CAAC,gCAAgC,MAAM,EAAE,CAAC,CAAC;IAClD,CAAC;CACF;AALD,0DAKC;AAED,MAAa,0BAA2B,SAAQ,aAAa;IACzC,IAAI,GAAW,4BAA4B,CAAC;IAC9D,YAAY,MAAc;QACxB,KAAK,CAAC,mCAAmC,MAAM,EAAE,CAAC,CAAC;IACrD,CAAC;CACF;AALD,gEAKC;AAED,MAAa,wBAAyB,SAAQ,aAAa;IACvC,IAAI,GAAW,0BAA0B,CAAC;IAC5D;QACE,KAAK,CAAC,uCAAuC,CAAC,CAAC;IACjD,CAAC;CACF;AALD,4DAKC;AAED,MAAa,yBAA0B,SAAQ,aAAa;IACxC,IAAI,GAAW,2BAA2B,CAAC;IAC7D,YAAY,KAAa;QACvB,KAAK,CAAC,2BAA2B,KAAK,EAAE,CAAC,CAAC;IAC5C,CAAC;CACF;AALD,8DAKC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { createScanner } from './detector.js';
|
|
2
|
+
export { ViemScannerBackend } from './viem-backend.js';
|
|
3
|
+
export type { ScannerBackend, RawAnnouncement, AnnouncementHandler, UnsubscribeFn, BackendWatchOptions, FinalityLevel, } from './backend.js';
|
|
4
|
+
export type { Scanner, ScannerConfig, ScannerTransportLike, DetectedPayment, } from './types.js';
|
|
5
|
+
export { ScanningError, BackendUnreachableError, MalformedAnnouncementError, MissingPublicClientError, InvalidFinalityLevelError, } from './errors.js';
|
|
6
|
+
export { LRUDeduper } from './dedup.js';
|
|
7
|
+
export { Cursor } from './cursor.js';
|
|
8
|
+
export { DEFAULT_SCHEME_ID, DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_DEDUP_CAPACITY, DEFAULT_GETLOGS_CHUNK_SIZE, DEFAULT_FINALITY, MIN_METADATA_LENGTH, } from './constants.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,YAAY,EACV,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,mBAAmB,EACnB,aAAa,GACd,MAAM,cAAc,CAAC;AAGtB,YAAY,EACV,OAAO,EACP,aAAa,EACb,oBAAoB,EACpB,eAAe,GAChB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,aAAa,EACb,uBAAuB,EACvB,0BAA0B,EAC1B,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EACL,iBAAiB,EACjB,6BAA6B,EAC7B,sBAAsB,EACtB,0BAA0B,EAC1B,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Public surface — @shroud-fi/scanning
|
|
3
|
+
// Phase 3: detection-only stealth payment scanner. Caller drives sweep.
|
|
4
|
+
// Sweep queue / log-normal delay / destination rotation are deferred phases.
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.MIN_METADATA_LENGTH = exports.DEFAULT_FINALITY = exports.DEFAULT_GETLOGS_CHUNK_SIZE = exports.DEFAULT_DEDUP_CAPACITY = exports.DEFAULT_RECONCILE_INTERVAL_MS = exports.DEFAULT_SCHEME_ID = exports.Cursor = exports.LRUDeduper = exports.InvalidFinalityLevelError = exports.MissingPublicClientError = exports.MalformedAnnouncementError = exports.BackendUnreachableError = exports.ScanningError = exports.ViemScannerBackend = exports.createScanner = void 0;
|
|
7
|
+
// Factory
|
|
8
|
+
var detector_js_1 = require("./detector.js");
|
|
9
|
+
Object.defineProperty(exports, "createScanner", { enumerable: true, get: function () { return detector_js_1.createScanner; } });
|
|
10
|
+
// Backend interface + viem implementation
|
|
11
|
+
var viem_backend_js_1 = require("./viem-backend.js");
|
|
12
|
+
Object.defineProperty(exports, "ViemScannerBackend", { enumerable: true, get: function () { return viem_backend_js_1.ViemScannerBackend; } });
|
|
13
|
+
// Errors
|
|
14
|
+
var errors_js_1 = require("./errors.js");
|
|
15
|
+
Object.defineProperty(exports, "ScanningError", { enumerable: true, get: function () { return errors_js_1.ScanningError; } });
|
|
16
|
+
Object.defineProperty(exports, "BackendUnreachableError", { enumerable: true, get: function () { return errors_js_1.BackendUnreachableError; } });
|
|
17
|
+
Object.defineProperty(exports, "MalformedAnnouncementError", { enumerable: true, get: function () { return errors_js_1.MalformedAnnouncementError; } });
|
|
18
|
+
Object.defineProperty(exports, "MissingPublicClientError", { enumerable: true, get: function () { return errors_js_1.MissingPublicClientError; } });
|
|
19
|
+
Object.defineProperty(exports, "InvalidFinalityLevelError", { enumerable: true, get: function () { return errors_js_1.InvalidFinalityLevelError; } });
|
|
20
|
+
// Utilities (advanced consumers)
|
|
21
|
+
var dedup_js_1 = require("./dedup.js");
|
|
22
|
+
Object.defineProperty(exports, "LRUDeduper", { enumerable: true, get: function () { return dedup_js_1.LRUDeduper; } });
|
|
23
|
+
var cursor_js_1 = require("./cursor.js");
|
|
24
|
+
Object.defineProperty(exports, "Cursor", { enumerable: true, get: function () { return cursor_js_1.Cursor; } });
|
|
25
|
+
// Defaults
|
|
26
|
+
var constants_js_1 = require("./constants.js");
|
|
27
|
+
Object.defineProperty(exports, "DEFAULT_SCHEME_ID", { enumerable: true, get: function () { return constants_js_1.DEFAULT_SCHEME_ID; } });
|
|
28
|
+
Object.defineProperty(exports, "DEFAULT_RECONCILE_INTERVAL_MS", { enumerable: true, get: function () { return constants_js_1.DEFAULT_RECONCILE_INTERVAL_MS; } });
|
|
29
|
+
Object.defineProperty(exports, "DEFAULT_DEDUP_CAPACITY", { enumerable: true, get: function () { return constants_js_1.DEFAULT_DEDUP_CAPACITY; } });
|
|
30
|
+
Object.defineProperty(exports, "DEFAULT_GETLOGS_CHUNK_SIZE", { enumerable: true, get: function () { return constants_js_1.DEFAULT_GETLOGS_CHUNK_SIZE; } });
|
|
31
|
+
Object.defineProperty(exports, "DEFAULT_FINALITY", { enumerable: true, get: function () { return constants_js_1.DEFAULT_FINALITY; } });
|
|
32
|
+
Object.defineProperty(exports, "MIN_METADATA_LENGTH", { enumerable: true, get: function () { return constants_js_1.MIN_METADATA_LENGTH; } });
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,wEAAwE;AACxE,6EAA6E;;;AAE7E,UAAU;AACV,6CAA8C;AAArC,4GAAA,aAAa,OAAA;AAEtB,0CAA0C;AAC1C,qDAAuD;AAA9C,qHAAA,kBAAkB,OAAA;AAkB3B,SAAS;AACT,yCAMqB;AALnB,0GAAA,aAAa,OAAA;AACb,oHAAA,uBAAuB,OAAA;AACvB,uHAAA,0BAA0B,OAAA;AAC1B,qHAAA,wBAAwB,OAAA;AACxB,sHAAA,yBAAyB,OAAA;AAG3B,iCAAiC;AACjC,uCAAwC;AAA/B,sGAAA,UAAU,OAAA;AACnB,yCAAqC;AAA5B,mGAAA,MAAM,OAAA;AAEf,WAAW;AACX,+CAOwB;AANtB,iHAAA,iBAAiB,OAAA;AACjB,6HAAA,6BAA6B,OAAA;AAC7B,sHAAA,sBAAsB,OAAA;AACtB,0HAAA,0BAA0B,OAAA;AAC1B,gHAAA,gBAAgB,OAAA;AAChB,mHAAA,mBAAmB,OAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|