@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,16 @@
|
|
|
1
|
+
// Public surface types for @shroud-fi/scanning (Phase 3 — detection only).
|
|
2
|
+
//
|
|
3
|
+
// Privacy contract:
|
|
4
|
+
// - ScannerConfig accepts branded ScanningKey + SpendingKey directly. These
|
|
5
|
+
// remain in-process; the scanner never logs them, serializes them, or
|
|
6
|
+
// surfaces them in errors. Spending key is required because ECDH derivation
|
|
7
|
+
// of the per-payment stealth private key needs it; see compute-key.ts.
|
|
8
|
+
// - DetectedPayment.stealthPrivateKey is the recovered private key for the
|
|
9
|
+
// one-time stealth address. It NEVER touches a relayer or logger. Caller
|
|
10
|
+
// drives the sweep (via @shroud-fi/payments sweepETH/sweepERC20) and is
|
|
11
|
+
// responsible for not leaking it.
|
|
12
|
+
// - Detection is idempotent. Cursor is in-memory only and resets to
|
|
13
|
+
// `startBlock` on restart. The dedup LRU prevents double-yield within a
|
|
14
|
+
// single Scanner lifetime.
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,EAAE;AACF,oBAAoB;AACpB,8EAA8E;AAC9E,0EAA0E;AAC1E,gFAAgF;AAChF,2EAA2E;AAC3E,6EAA6E;AAC7E,6EAA6E;AAC7E,4EAA4E;AAC5E,sCAAsC;AACtC,sEAAsE;AACtE,4EAA4E;AAC5E,+BAA+B"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type PublicClient } from 'viem';
|
|
2
|
+
import type { AnnouncementHandler, BackendWatchOptions, FinalityLevel, RawAnnouncement, ScannerBackend, UnsubscribeFn } from './types.js';
|
|
3
|
+
interface ViemBackendOptions {
|
|
4
|
+
readonly getLogsChunkSize?: bigint;
|
|
5
|
+
}
|
|
6
|
+
export declare class ViemScannerBackend implements ScannerBackend {
|
|
7
|
+
#private;
|
|
8
|
+
constructor(publicClient: PublicClient, options?: ViemBackendOptions);
|
|
9
|
+
watchAnnouncements(handler: AnnouncementHandler, options: BackendWatchOptions): UnsubscribeFn;
|
|
10
|
+
getAnnouncementsInRange(fromBlock: bigint, toBlock: bigint, options: BackendWatchOptions): Promise<readonly RawAnnouncement[]>;
|
|
11
|
+
getLatestBlock(level: FinalityLevel): Promise<bigint>;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=viem-backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viem-backend.d.ts","sourceRoot":"","sources":["../../src/viem-backend.ts"],"names":[],"mappings":"AAYA,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,MAAM,CAAC;AAO3E,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,cAAc,EACd,aAAa,EACd,MAAM,YAAY,CAAC;AAOpB,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAkBD,qBAAa,kBAAmB,YAAW,cAAc;;gBAI3C,YAAY,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,kBAAkB;IAKpE,kBAAkB,CAChB,OAAO,EAAE,mBAAmB,EAC5B,OAAO,EAAE,mBAAmB,GAC3B,aAAa;IA+BV,uBAAuB,CAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC;IA8ChC,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;CA2B5D"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// viem-backed ScannerBackend. The only backend that ships in Phase 3.
|
|
2
|
+
//
|
|
3
|
+
// Privacy contract (binding):
|
|
4
|
+
// - No console.* anywhere in this file.
|
|
5
|
+
// - Error messages NEVER embed hex strings, key material, amounts, or raw RPC
|
|
6
|
+
// payloads. Short reason tags only ("getLogs failed", "watch failed",
|
|
7
|
+
// "getBlockNumber failed").
|
|
8
|
+
// - No JSON.stringify of args or logs.
|
|
9
|
+
// - Pending / malformed logs (missing blockNumber, blockHash, transactionHash,
|
|
10
|
+
// or logIndex) are silently skipped — they aren't actionable for detection
|
|
11
|
+
// and we don't want to leak their existence via thrown errors.
|
|
12
|
+
import { getAbiItem, hexToBytes } from 'viem';
|
|
13
|
+
import { ERC5564AnnouncerAbi } from '@shroud-fi/transport';
|
|
14
|
+
import { DEFAULT_GETLOGS_CHUNK_SIZE } from './constants.js';
|
|
15
|
+
import { BackendUnreachableError, InvalidFinalityLevelError, } from './errors.js';
|
|
16
|
+
const ANNOUNCEMENT_EVENT = getAbiItem({
|
|
17
|
+
abi: ERC5564AnnouncerAbi,
|
|
18
|
+
name: 'Announcement',
|
|
19
|
+
});
|
|
20
|
+
export class ViemScannerBackend {
|
|
21
|
+
#publicClient;
|
|
22
|
+
#chunkSize;
|
|
23
|
+
constructor(publicClient, options) {
|
|
24
|
+
this.#publicClient = publicClient;
|
|
25
|
+
this.#chunkSize = options?.getLogsChunkSize ?? DEFAULT_GETLOGS_CHUNK_SIZE;
|
|
26
|
+
}
|
|
27
|
+
watchAnnouncements(handler, options) {
|
|
28
|
+
const watchArgs = {
|
|
29
|
+
address: options.contractAddress,
|
|
30
|
+
abi: ERC5564AnnouncerAbi,
|
|
31
|
+
eventName: 'Announcement',
|
|
32
|
+
onLogs: (logs) => {
|
|
33
|
+
for (const log of logs) {
|
|
34
|
+
const decoded = decodeAnnouncementLog(log);
|
|
35
|
+
if (decoded === null)
|
|
36
|
+
continue;
|
|
37
|
+
// Fire-and-forget. Handler may return a promise; we intentionally do
|
|
38
|
+
// not await — backend semantics are "deliver, don't gate".
|
|
39
|
+
void handler(decoded);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
onError: (_err) => {
|
|
43
|
+
// Privacy: do not surface the underlying RPC error payload. Tag only.
|
|
44
|
+
throw new BackendUnreachableError('watch failed');
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
const unsubscribe = options.schemeId !== undefined
|
|
48
|
+
? this.#publicClient.watchContractEvent({
|
|
49
|
+
...watchArgs,
|
|
50
|
+
args: { schemeId: options.schemeId },
|
|
51
|
+
})
|
|
52
|
+
: this.#publicClient.watchContractEvent(watchArgs);
|
|
53
|
+
return unsubscribe;
|
|
54
|
+
}
|
|
55
|
+
async getAnnouncementsInRange(fromBlock, toBlock, options) {
|
|
56
|
+
if (toBlock < fromBlock)
|
|
57
|
+
return [];
|
|
58
|
+
const collected = [];
|
|
59
|
+
let cursor = fromBlock;
|
|
60
|
+
while (cursor <= toBlock) {
|
|
61
|
+
const chunkEnd = cursor + this.#chunkSize - 1n > toBlock
|
|
62
|
+
? toBlock
|
|
63
|
+
: cursor + this.#chunkSize - 1n;
|
|
64
|
+
let logs;
|
|
65
|
+
try {
|
|
66
|
+
const getLogsArgs = options.schemeId !== undefined
|
|
67
|
+
? {
|
|
68
|
+
address: options.contractAddress,
|
|
69
|
+
event: ANNOUNCEMENT_EVENT,
|
|
70
|
+
args: { schemeId: options.schemeId },
|
|
71
|
+
fromBlock: cursor,
|
|
72
|
+
toBlock: chunkEnd,
|
|
73
|
+
}
|
|
74
|
+
: {
|
|
75
|
+
address: options.contractAddress,
|
|
76
|
+
event: ANNOUNCEMENT_EVENT,
|
|
77
|
+
fromBlock: cursor,
|
|
78
|
+
toBlock: chunkEnd,
|
|
79
|
+
};
|
|
80
|
+
logs = await this.#publicClient.getLogs(getLogsArgs);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// Privacy: short tag only. No original error payload.
|
|
84
|
+
throw new BackendUnreachableError('getLogs failed');
|
|
85
|
+
}
|
|
86
|
+
for (const log of logs) {
|
|
87
|
+
const decoded = decodeAnnouncementLog(log);
|
|
88
|
+
if (decoded === null)
|
|
89
|
+
continue;
|
|
90
|
+
collected.push(decoded);
|
|
91
|
+
}
|
|
92
|
+
cursor = chunkEnd + 1n;
|
|
93
|
+
}
|
|
94
|
+
return collected;
|
|
95
|
+
}
|
|
96
|
+
async getLatestBlock(level) {
|
|
97
|
+
// viem.getBlockNumber() always returns the *latest* head; for 'safe' and
|
|
98
|
+
// 'finalized' we must go through getBlock({ blockTag }) and extract .number.
|
|
99
|
+
if (level === 'unsafe') {
|
|
100
|
+
try {
|
|
101
|
+
return await this.#publicClient.getBlockNumber();
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
throw new BackendUnreachableError('getBlockNumber failed');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (level !== 'safe' && level !== 'finalized') {
|
|
108
|
+
throw new InvalidFinalityLevelError(String(level));
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
const block = await this.#publicClient.getBlock({ blockTag: level });
|
|
112
|
+
const num = block.number;
|
|
113
|
+
if (num === null) {
|
|
114
|
+
throw new BackendUnreachableError('getBlockNumber failed');
|
|
115
|
+
}
|
|
116
|
+
return num;
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
if (err instanceof BackendUnreachableError)
|
|
120
|
+
throw err;
|
|
121
|
+
throw new BackendUnreachableError('getBlockNumber failed');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Convert a viem decoded log into a RawAnnouncement. Returns null for any
|
|
127
|
+
* pending / malformed log (missing block fields, missing args). Never throws.
|
|
128
|
+
*/
|
|
129
|
+
function decodeAnnouncementLog(log) {
|
|
130
|
+
const args = log.args;
|
|
131
|
+
if (args === undefined)
|
|
132
|
+
return null;
|
|
133
|
+
if (args.schemeId === undefined ||
|
|
134
|
+
args.stealthAddress === undefined ||
|
|
135
|
+
args.caller === undefined ||
|
|
136
|
+
args.ephemeralPubKey === undefined ||
|
|
137
|
+
args.metadata === undefined) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
if (log.blockNumber === undefined ||
|
|
141
|
+
log.blockNumber === null ||
|
|
142
|
+
log.blockHash === undefined ||
|
|
143
|
+
log.blockHash === null ||
|
|
144
|
+
log.transactionHash === undefined ||
|
|
145
|
+
log.transactionHash === null ||
|
|
146
|
+
log.logIndex === undefined ||
|
|
147
|
+
log.logIndex === null) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
schemeId: args.schemeId,
|
|
152
|
+
stealthAddress: args.stealthAddress,
|
|
153
|
+
caller: args.caller,
|
|
154
|
+
ephemeralPubKey: hexToBytes(args.ephemeralPubKey),
|
|
155
|
+
metadata: hexToBytes(args.metadata),
|
|
156
|
+
blockNumber: log.blockNumber,
|
|
157
|
+
blockHash: log.blockHash,
|
|
158
|
+
txHash: log.transactionHash,
|
|
159
|
+
logIndex: log.logIndex,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=viem-backend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viem-backend.js","sourceRoot":"","sources":["../../src/viem-backend.ts"],"names":[],"mappings":"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"}
|