@waiaas/daemon 2.5.0 → 2.6.0-rc.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/api/middleware/error-handler.d.ts +1 -1
- package/dist/api/middleware/error-handler.js +2 -2
- package/dist/api/middleware/error-handler.js.map +1 -1
- package/dist/api/routes/admin.d.ts.map +1 -1
- package/dist/api/routes/admin.js +6 -30
- package/dist/api/routes/admin.js.map +1 -1
- package/dist/api/routes/connect-info.d.ts.map +1 -1
- package/dist/api/routes/connect-info.js +6 -0
- package/dist/api/routes/connect-info.js.map +1 -1
- package/dist/api/routes/incoming.d.ts +40 -0
- package/dist/api/routes/incoming.d.ts.map +1 -0
- package/dist/api/routes/incoming.js +281 -0
- package/dist/api/routes/incoming.js.map +1 -0
- package/dist/api/routes/openapi-schemas.d.ts +337 -24
- package/dist/api/routes/openapi-schemas.d.ts.map +1 -1
- package/dist/api/routes/openapi-schemas.js +78 -0
- package/dist/api/routes/openapi-schemas.js.map +1 -1
- package/dist/api/routes/tokens.d.ts.map +1 -1
- package/dist/api/routes/tokens.js +1 -0
- package/dist/api/routes/tokens.js.map +1 -1
- package/dist/api/routes/wallets.d.ts +4 -0
- package/dist/api/routes/wallets.d.ts.map +1 -1
- package/dist/api/routes/wallets.js +173 -1
- package/dist/api/routes/wallets.js.map +1 -1
- package/dist/api/routes/x402.js +1 -1
- package/dist/api/routes/x402.js.map +1 -1
- package/dist/api/server.d.ts +4 -0
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +12 -0
- package/dist/api/server.js.map +1 -1
- package/dist/infrastructure/config/loader.d.ts +43 -0
- package/dist/infrastructure/config/loader.d.ts.map +1 -1
- package/dist/infrastructure/config/loader.js +13 -1
- package/dist/infrastructure/config/loader.js.map +1 -1
- package/dist/infrastructure/database/index.d.ts +1 -1
- package/dist/infrastructure/database/index.d.ts.map +1 -1
- package/dist/infrastructure/database/index.js +1 -1
- package/dist/infrastructure/database/index.js.map +1 -1
- package/dist/infrastructure/database/migrate.d.ts +2 -2
- package/dist/infrastructure/database/migrate.d.ts.map +1 -1
- package/dist/infrastructure/database/migrate.js +123 -6
- package/dist/infrastructure/database/migrate.js.map +1 -1
- package/dist/infrastructure/database/schema.d.ts +400 -1
- package/dist/infrastructure/database/schema.d.ts.map +1 -1
- package/dist/infrastructure/database/schema.js +43 -2
- package/dist/infrastructure/database/schema.js.map +1 -1
- package/dist/infrastructure/oracle/coingecko-oracle.d.ts +9 -1
- package/dist/infrastructure/oracle/coingecko-oracle.d.ts.map +1 -1
- package/dist/infrastructure/oracle/coingecko-oracle.js +40 -23
- package/dist/infrastructure/oracle/coingecko-oracle.js.map +1 -1
- package/dist/infrastructure/oracle/coingecko-platform-ids.d.ts +11 -10
- package/dist/infrastructure/oracle/coingecko-platform-ids.d.ts.map +1 -1
- package/dist/infrastructure/oracle/coingecko-platform-ids.js +20 -12
- package/dist/infrastructure/oracle/coingecko-platform-ids.js.map +1 -1
- package/dist/infrastructure/oracle/index.d.ts +1 -1
- package/dist/infrastructure/oracle/index.d.ts.map +1 -1
- package/dist/infrastructure/oracle/index.js +1 -1
- package/dist/infrastructure/oracle/index.js.map +1 -1
- package/dist/infrastructure/oracle/oracle-chain.d.ts.map +1 -1
- package/dist/infrastructure/oracle/oracle-chain.js +7 -4
- package/dist/infrastructure/oracle/oracle-chain.js.map +1 -1
- package/dist/infrastructure/oracle/price-cache.d.ts +24 -8
- package/dist/infrastructure/oracle/price-cache.d.ts.map +1 -1
- package/dist/infrastructure/oracle/price-cache.js +32 -11
- package/dist/infrastructure/oracle/price-cache.js.map +1 -1
- package/dist/infrastructure/oracle/pyth-feed-ids.d.ts +11 -8
- package/dist/infrastructure/oracle/pyth-feed-ids.d.ts.map +1 -1
- package/dist/infrastructure/oracle/pyth-feed-ids.js +16 -17
- package/dist/infrastructure/oracle/pyth-feed-ids.js.map +1 -1
- package/dist/infrastructure/oracle/pyth-oracle.d.ts.map +1 -1
- package/dist/infrastructure/oracle/pyth-oracle.js +7 -4
- package/dist/infrastructure/oracle/pyth-oracle.js.map +1 -1
- package/dist/infrastructure/settings/hot-reload.d.ts +9 -0
- package/dist/infrastructure/settings/hot-reload.d.ts.map +1 -1
- package/dist/infrastructure/settings/hot-reload.js +34 -5
- package/dist/infrastructure/settings/hot-reload.js.map +1 -1
- package/dist/infrastructure/settings/setting-keys.d.ts +2 -2
- package/dist/infrastructure/settings/setting-keys.d.ts.map +1 -1
- package/dist/infrastructure/settings/setting-keys.js +12 -3
- package/dist/infrastructure/settings/setting-keys.js.map +1 -1
- package/dist/infrastructure/token-registry/token-registry-service.d.ts +1 -0
- package/dist/infrastructure/token-registry/token-registry-service.d.ts.map +1 -1
- package/dist/infrastructure/token-registry/token-registry-service.js +15 -1
- package/dist/infrastructure/token-registry/token-registry-service.js.map +1 -1
- package/dist/lifecycle/daemon.d.ts +3 -1
- package/dist/lifecycle/daemon.d.ts.map +1 -1
- package/dist/lifecycle/daemon.js +84 -4
- package/dist/lifecycle/daemon.js.map +1 -1
- package/dist/notifications/channels/discord.d.ts.map +1 -1
- package/dist/notifications/channels/discord.js +21 -8
- package/dist/notifications/channels/discord.js.map +1 -1
- package/dist/notifications/channels/format-utils.d.ts +11 -0
- package/dist/notifications/channels/format-utils.d.ts.map +1 -0
- package/dist/notifications/channels/format-utils.js +19 -0
- package/dist/notifications/channels/format-utils.js.map +1 -0
- package/dist/notifications/channels/ntfy.d.ts.map +1 -1
- package/dist/notifications/channels/ntfy.js +18 -2
- package/dist/notifications/channels/ntfy.js.map +1 -1
- package/dist/notifications/channels/slack.d.ts.map +1 -1
- package/dist/notifications/channels/slack.js +20 -7
- package/dist/notifications/channels/slack.js.map +1 -1
- package/dist/notifications/channels/telegram.d.ts.map +1 -1
- package/dist/notifications/channels/telegram.js +21 -5
- package/dist/notifications/channels/telegram.js.map +1 -1
- package/dist/notifications/notification-service.d.ts +14 -0
- package/dist/notifications/notification-service.d.ts.map +1 -1
- package/dist/notifications/notification-service.js +89 -2
- package/dist/notifications/notification-service.js.map +1 -1
- package/dist/pipeline/database-policy-engine.d.ts +9 -5
- package/dist/pipeline/database-policy-engine.d.ts.map +1 -1
- package/dist/pipeline/database-policy-engine.js +42 -10
- package/dist/pipeline/database-policy-engine.js.map +1 -1
- package/dist/pipeline/resolve-effective-amount-usd.d.ts +1 -1
- package/dist/pipeline/resolve-effective-amount-usd.d.ts.map +1 -1
- package/dist/pipeline/resolve-effective-amount-usd.js +5 -3
- package/dist/pipeline/resolve-effective-amount-usd.js.map +1 -1
- package/dist/pipeline/stages.d.ts.map +1 -1
- package/dist/pipeline/stages.js +7 -1
- package/dist/pipeline/stages.js.map +1 -1
- package/dist/services/incoming/__tests__/incoming-tx-monitor-service.test.d.ts +11 -0
- package/dist/services/incoming/__tests__/incoming-tx-monitor-service.test.d.ts.map +1 -0
- package/dist/services/incoming/__tests__/incoming-tx-monitor-service.test.js +432 -0
- package/dist/services/incoming/__tests__/incoming-tx-monitor-service.test.js.map +1 -0
- package/dist/services/incoming/__tests__/incoming-tx-queue.test.d.ts +12 -0
- package/dist/services/incoming/__tests__/incoming-tx-queue.test.d.ts.map +1 -0
- package/dist/services/incoming/__tests__/incoming-tx-queue.test.js +419 -0
- package/dist/services/incoming/__tests__/incoming-tx-queue.test.js.map +1 -0
- package/dist/services/incoming/__tests__/incoming-tx-workers.test.d.ts +14 -0
- package/dist/services/incoming/__tests__/incoming-tx-workers.test.d.ts.map +1 -0
- package/dist/services/incoming/__tests__/incoming-tx-workers.test.js +452 -0
- package/dist/services/incoming/__tests__/incoming-tx-workers.test.js.map +1 -0
- package/dist/services/incoming/__tests__/integration-pitfall.test.d.ts +17 -0
- package/dist/services/incoming/__tests__/integration-pitfall.test.d.ts.map +1 -0
- package/dist/services/incoming/__tests__/integration-pitfall.test.js +653 -0
- package/dist/services/incoming/__tests__/integration-pitfall.test.js.map +1 -0
- package/dist/services/incoming/__tests__/integration-resilience.test.d.ts +14 -0
- package/dist/services/incoming/__tests__/integration-resilience.test.d.ts.map +1 -0
- package/dist/services/incoming/__tests__/integration-resilience.test.js +501 -0
- package/dist/services/incoming/__tests__/integration-resilience.test.js.map +1 -0
- package/dist/services/incoming/__tests__/integration-wiring.test.d.ts +15 -0
- package/dist/services/incoming/__tests__/integration-wiring.test.d.ts.map +1 -0
- package/dist/services/incoming/__tests__/integration-wiring.test.js +355 -0
- package/dist/services/incoming/__tests__/integration-wiring.test.js.map +1 -0
- package/dist/services/incoming/__tests__/safety-rules.test.d.ts +10 -0
- package/dist/services/incoming/__tests__/safety-rules.test.d.ts.map +1 -0
- package/dist/services/incoming/__tests__/safety-rules.test.js +165 -0
- package/dist/services/incoming/__tests__/safety-rules.test.js.map +1 -0
- package/dist/services/incoming/__tests__/subscription-multiplexer.test.d.ts +2 -0
- package/dist/services/incoming/__tests__/subscription-multiplexer.test.d.ts.map +1 -0
- package/dist/services/incoming/__tests__/subscription-multiplexer.test.js +267 -0
- package/dist/services/incoming/__tests__/subscription-multiplexer.test.js.map +1 -0
- package/dist/services/incoming/incoming-tx-monitor-service.d.ts +98 -0
- package/dist/services/incoming/incoming-tx-monitor-service.d.ts.map +1 -0
- package/dist/services/incoming/incoming-tx-monitor-service.js +357 -0
- package/dist/services/incoming/incoming-tx-monitor-service.js.map +1 -0
- package/dist/services/incoming/incoming-tx-queue.d.ts +52 -0
- package/dist/services/incoming/incoming-tx-queue.d.ts.map +1 -0
- package/dist/services/incoming/incoming-tx-queue.js +109 -0
- package/dist/services/incoming/incoming-tx-queue.js.map +1 -0
- package/dist/services/incoming/incoming-tx-workers.d.ts +89 -0
- package/dist/services/incoming/incoming-tx-workers.d.ts.map +1 -0
- package/dist/services/incoming/incoming-tx-workers.js +176 -0
- package/dist/services/incoming/incoming-tx-workers.js.map +1 -0
- package/dist/services/incoming/index.d.ts +14 -0
- package/dist/services/incoming/index.d.ts.map +1 -0
- package/dist/services/incoming/index.js +11 -0
- package/dist/services/incoming/index.js.map +1 -0
- package/dist/services/incoming/safety-rules.d.ts +70 -0
- package/dist/services/incoming/safety-rules.d.ts.map +1 -0
- package/dist/services/incoming/safety-rules.js +68 -0
- package/dist/services/incoming/safety-rules.js.map +1 -0
- package/dist/services/incoming/subscription-multiplexer.d.ts +87 -0
- package/dist/services/incoming/subscription-multiplexer.d.ts.map +1 -0
- package/dist/services/incoming/subscription-multiplexer.js +169 -0
- package/dist/services/incoming/subscription-multiplexer.js.map +1 -0
- package/dist/services/signing-sdk/approval-channel-router.d.ts +1 -1
- package/dist/services/signing-sdk/approval-channel-router.d.ts.map +1 -1
- package/dist/services/signing-sdk/approval-channel-router.js +2 -3
- package/dist/services/signing-sdk/approval-channel-router.js.map +1 -1
- package/dist/services/signing-sdk/channels/wallet-notification-channel.js +1 -1
- package/dist/services/signing-sdk/channels/wallet-notification-channel.js.map +1 -1
- package/dist/services/wc-session-service.d.ts +0 -2
- package/dist/services/wc-session-service.d.ts.map +1 -1
- package/dist/services/wc-session-service.js +2 -23
- package/dist/services/wc-session-service.js.map +1 -1
- package/dist/services/x402/x402-domain-policy.d.ts +6 -1
- package/dist/services/x402/x402-domain-policy.d.ts.map +1 -1
- package/dist/services/x402/x402-domain-policy.js +6 -2
- package/dist/services/x402/x402-domain-policy.js.map +1 -1
- package/package.json +4 -4
- package/public/admin/assets/index-D06O_cSo.js +1 -0
- package/public/admin/index.html +1 -1
- package/public/admin/assets/index-BLLOYSZp.js +0 -1
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for incoming transaction worker handlers and cursor utilities.
|
|
3
|
+
*
|
|
4
|
+
* Covers:
|
|
5
|
+
* - Confirmation worker (Solana finalized check + EVM block threshold)
|
|
6
|
+
* - Retention policy worker (configurable days, hot-reload)
|
|
7
|
+
* - Gap recovery handler (pollAll() delegation)
|
|
8
|
+
* - Cursor utilities (updateCursor, loadCursor)
|
|
9
|
+
*
|
|
10
|
+
* Uses mock better-sqlite3 Database objects to isolate worker logic
|
|
11
|
+
* from actual database operations.
|
|
12
|
+
*/
|
|
13
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
14
|
+
import { createConfirmationWorkerHandler, createRetentionWorkerHandler, createGapRecoveryHandler, updateCursor, loadCursor, EVM_CONFIRMATION_THRESHOLDS, DEFAULT_EVM_CONFIRMATIONS, } from '../incoming-tx-workers.js';
|
|
15
|
+
/** Create a mock DETECTED transaction row. */
|
|
16
|
+
function makeDetectedTx(chain, overrides) {
|
|
17
|
+
return {
|
|
18
|
+
id: `tx-id-${Math.random().toString(36).slice(2, 8)}`,
|
|
19
|
+
tx_hash: `hash-${Math.random().toString(36).slice(2, 10)}`,
|
|
20
|
+
chain,
|
|
21
|
+
network: chain === 'solana' ? 'mainnet' : 'mainnet',
|
|
22
|
+
block_number: chain === 'ethereum' ? 100 : null,
|
|
23
|
+
...overrides,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a mock SQLite Database for confirmation worker tests.
|
|
28
|
+
*
|
|
29
|
+
* @param rows - DETECTED rows to return from the SELECT query
|
|
30
|
+
* @returns Mock DB and helpers to inspect update calls
|
|
31
|
+
*/
|
|
32
|
+
function createConfirmationMockDb(rows) {
|
|
33
|
+
const updateCalls = [];
|
|
34
|
+
const selectStmt = { all: () => rows };
|
|
35
|
+
const updateStmt = {
|
|
36
|
+
run: (...args) => {
|
|
37
|
+
updateCalls.push(args);
|
|
38
|
+
return { changes: 1 };
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
let prepareCallIndex = 0;
|
|
42
|
+
const mockDb = {
|
|
43
|
+
prepare: (_sql) => {
|
|
44
|
+
prepareCallIndex++;
|
|
45
|
+
// First prepare() is the SELECT, second is the UPDATE
|
|
46
|
+
return prepareCallIndex === 1 ? selectStmt : updateStmt;
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
db: mockDb,
|
|
51
|
+
getUpdateCalls: () => updateCalls,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Create a mock SQLite Database for retention worker tests.
|
|
56
|
+
*/
|
|
57
|
+
function createRetentionMockDb(deletedCount = 0) {
|
|
58
|
+
let runArgs = [];
|
|
59
|
+
let prepareSql = '';
|
|
60
|
+
const mockStmt = {
|
|
61
|
+
run: (...args) => {
|
|
62
|
+
runArgs = args;
|
|
63
|
+
return { changes: deletedCount };
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
const mockDb = {
|
|
67
|
+
prepare: (sql) => {
|
|
68
|
+
prepareSql = sql;
|
|
69
|
+
return mockStmt;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
return {
|
|
73
|
+
db: mockDb,
|
|
74
|
+
getRunArgs: () => runArgs,
|
|
75
|
+
getPrepareSql: () => prepareSql,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Create a mock SQLite Database for cursor utility tests.
|
|
80
|
+
*/
|
|
81
|
+
function createCursorMockDb() {
|
|
82
|
+
const runCalls = [];
|
|
83
|
+
const getCalls = [];
|
|
84
|
+
let getResult;
|
|
85
|
+
const mockDb = {
|
|
86
|
+
prepare: (_sql) => ({
|
|
87
|
+
run: (...args) => {
|
|
88
|
+
runCalls.push(args);
|
|
89
|
+
return { changes: 1 };
|
|
90
|
+
},
|
|
91
|
+
get: (...args) => {
|
|
92
|
+
getCalls.push(args);
|
|
93
|
+
return getResult;
|
|
94
|
+
},
|
|
95
|
+
}),
|
|
96
|
+
};
|
|
97
|
+
return {
|
|
98
|
+
db: mockDb,
|
|
99
|
+
getRunCalls: () => runCalls,
|
|
100
|
+
getGetCalls: () => getCalls,
|
|
101
|
+
setGetResult: (result) => {
|
|
102
|
+
getResult = result;
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// Tests
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
describe('incoming-tx-workers', () => {
|
|
110
|
+
// -----------------------------------------------------------------------
|
|
111
|
+
// 1. Confirmation worker - Solana
|
|
112
|
+
// -----------------------------------------------------------------------
|
|
113
|
+
describe('createConfirmationWorkerHandler - Solana', () => {
|
|
114
|
+
it('should upgrade DETECTED Solana tx to CONFIRMED when checkSolanaFinalized returns true', async () => {
|
|
115
|
+
const row = makeDetectedTx('solana', { id: 'sol-1', tx_hash: 'sol-hash-1' });
|
|
116
|
+
const mock = createConfirmationMockDb([row]);
|
|
117
|
+
const checkSolanaFinalized = vi.fn().mockResolvedValue(true);
|
|
118
|
+
const handler = createConfirmationWorkerHandler({
|
|
119
|
+
sqlite: mock.db,
|
|
120
|
+
checkSolanaFinalized,
|
|
121
|
+
});
|
|
122
|
+
await handler();
|
|
123
|
+
expect(checkSolanaFinalized).toHaveBeenCalledWith('sol-hash-1');
|
|
124
|
+
const updates = mock.getUpdateCalls();
|
|
125
|
+
expect(updates).toHaveLength(1);
|
|
126
|
+
// confirmed_at should be a Unix timestamp
|
|
127
|
+
expect(typeof updates[0][0]).toBe('number');
|
|
128
|
+
expect(updates[0][1]).toBe('sol-1');
|
|
129
|
+
});
|
|
130
|
+
it('should NOT upgrade when checkSolanaFinalized returns false', async () => {
|
|
131
|
+
const row = makeDetectedTx('solana');
|
|
132
|
+
const mock = createConfirmationMockDb([row]);
|
|
133
|
+
const checkSolanaFinalized = vi.fn().mockResolvedValue(false);
|
|
134
|
+
const handler = createConfirmationWorkerHandler({
|
|
135
|
+
sqlite: mock.db,
|
|
136
|
+
checkSolanaFinalized,
|
|
137
|
+
});
|
|
138
|
+
await handler();
|
|
139
|
+
expect(mock.getUpdateCalls()).toHaveLength(0);
|
|
140
|
+
});
|
|
141
|
+
it('should isolate errors: one Solana tx failure does not block others', async () => {
|
|
142
|
+
const row1 = makeDetectedTx('solana', { id: 'sol-err', tx_hash: 'hash-err' });
|
|
143
|
+
const row2 = makeDetectedTx('solana', { id: 'sol-ok', tx_hash: 'hash-ok' });
|
|
144
|
+
const mock = createConfirmationMockDb([row1, row2]);
|
|
145
|
+
const checkSolanaFinalized = vi.fn().mockImplementation((hash) => {
|
|
146
|
+
if (hash === 'hash-err')
|
|
147
|
+
throw new Error('RPC unavailable');
|
|
148
|
+
return Promise.resolve(true);
|
|
149
|
+
});
|
|
150
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
151
|
+
const handler = createConfirmationWorkerHandler({
|
|
152
|
+
sqlite: mock.db,
|
|
153
|
+
checkSolanaFinalized,
|
|
154
|
+
});
|
|
155
|
+
await handler();
|
|
156
|
+
// Only sol-ok should be updated
|
|
157
|
+
const updates = mock.getUpdateCalls();
|
|
158
|
+
expect(updates).toHaveLength(1);
|
|
159
|
+
expect(updates[0][1]).toBe('sol-ok');
|
|
160
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
161
|
+
warnSpy.mockRestore();
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
// -----------------------------------------------------------------------
|
|
165
|
+
// 2. Confirmation worker - EVM
|
|
166
|
+
// -----------------------------------------------------------------------
|
|
167
|
+
describe('createConfirmationWorkerHandler - EVM', () => {
|
|
168
|
+
it('should upgrade DETECTED EVM tx when block confirmations >= mainnet threshold (12)', async () => {
|
|
169
|
+
const row = makeDetectedTx('ethereum', {
|
|
170
|
+
id: 'evm-1',
|
|
171
|
+
network: 'mainnet',
|
|
172
|
+
block_number: 100,
|
|
173
|
+
});
|
|
174
|
+
const mock = createConfirmationMockDb([row]);
|
|
175
|
+
const getBlockNumber = vi.fn().mockResolvedValue(112n); // 112 - 100 = 12 confirmations
|
|
176
|
+
const handler = createConfirmationWorkerHandler({
|
|
177
|
+
sqlite: mock.db,
|
|
178
|
+
getBlockNumber,
|
|
179
|
+
});
|
|
180
|
+
await handler();
|
|
181
|
+
expect(getBlockNumber).toHaveBeenCalledWith('ethereum', 'mainnet');
|
|
182
|
+
expect(mock.getUpdateCalls()).toHaveLength(1);
|
|
183
|
+
expect(mock.getUpdateCalls()[0][1]).toBe('evm-1');
|
|
184
|
+
});
|
|
185
|
+
it('should NOT upgrade EVM tx when confirmations < mainnet threshold', async () => {
|
|
186
|
+
const row = makeDetectedTx('ethereum', {
|
|
187
|
+
id: 'evm-2',
|
|
188
|
+
network: 'mainnet',
|
|
189
|
+
block_number: 100,
|
|
190
|
+
});
|
|
191
|
+
const mock = createConfirmationMockDb([row]);
|
|
192
|
+
const getBlockNumber = vi.fn().mockResolvedValue(110n); // 110 - 100 = 10 < 12
|
|
193
|
+
const handler = createConfirmationWorkerHandler({
|
|
194
|
+
sqlite: mock.db,
|
|
195
|
+
getBlockNumber,
|
|
196
|
+
});
|
|
197
|
+
await handler();
|
|
198
|
+
expect(mock.getUpdateCalls()).toHaveLength(0);
|
|
199
|
+
});
|
|
200
|
+
it('should use DEFAULT_EVM_CONFIRMATIONS (12) for unknown network', async () => {
|
|
201
|
+
const row = makeDetectedTx('ethereum', {
|
|
202
|
+
id: 'evm-3',
|
|
203
|
+
network: 'unknown-testnet',
|
|
204
|
+
block_number: 100,
|
|
205
|
+
});
|
|
206
|
+
const mock = createConfirmationMockDb([row]);
|
|
207
|
+
// 112 - 100 = 12 = DEFAULT_EVM_CONFIRMATIONS
|
|
208
|
+
const getBlockNumber = vi.fn().mockResolvedValue(112n);
|
|
209
|
+
const handler = createConfirmationWorkerHandler({
|
|
210
|
+
sqlite: mock.db,
|
|
211
|
+
getBlockNumber,
|
|
212
|
+
});
|
|
213
|
+
await handler();
|
|
214
|
+
expect(mock.getUpdateCalls()).toHaveLength(1);
|
|
215
|
+
expect(DEFAULT_EVM_CONFIRMATIONS).toBe(12);
|
|
216
|
+
});
|
|
217
|
+
it('should use sepolia threshold (1) for sepolia network', async () => {
|
|
218
|
+
const row = makeDetectedTx('ethereum', {
|
|
219
|
+
id: 'evm-sep',
|
|
220
|
+
network: 'sepolia',
|
|
221
|
+
block_number: 100,
|
|
222
|
+
});
|
|
223
|
+
const mock = createConfirmationMockDb([row]);
|
|
224
|
+
const getBlockNumber = vi.fn().mockResolvedValue(101n); // 101 - 100 = 1
|
|
225
|
+
const handler = createConfirmationWorkerHandler({
|
|
226
|
+
sqlite: mock.db,
|
|
227
|
+
getBlockNumber,
|
|
228
|
+
});
|
|
229
|
+
await handler();
|
|
230
|
+
expect(EVM_CONFIRMATION_THRESHOLDS['sepolia']).toBe(1);
|
|
231
|
+
expect(mock.getUpdateCalls()).toHaveLength(1);
|
|
232
|
+
});
|
|
233
|
+
it('should do nothing when no DETECTED transactions exist', async () => {
|
|
234
|
+
const mock = createConfirmationMockDb([]);
|
|
235
|
+
const getBlockNumber = vi.fn();
|
|
236
|
+
const handler = createConfirmationWorkerHandler({
|
|
237
|
+
sqlite: mock.db,
|
|
238
|
+
getBlockNumber,
|
|
239
|
+
});
|
|
240
|
+
await handler();
|
|
241
|
+
expect(getBlockNumber).not.toHaveBeenCalled();
|
|
242
|
+
expect(mock.getUpdateCalls()).toHaveLength(0);
|
|
243
|
+
});
|
|
244
|
+
it('should cache block numbers per network to avoid redundant RPC calls', async () => {
|
|
245
|
+
const row1 = makeDetectedTx('ethereum', {
|
|
246
|
+
id: 'evm-c1',
|
|
247
|
+
network: 'mainnet',
|
|
248
|
+
block_number: 100,
|
|
249
|
+
});
|
|
250
|
+
const row2 = makeDetectedTx('ethereum', {
|
|
251
|
+
id: 'evm-c2',
|
|
252
|
+
network: 'mainnet',
|
|
253
|
+
block_number: 90,
|
|
254
|
+
});
|
|
255
|
+
const mock = createConfirmationMockDb([row1, row2]);
|
|
256
|
+
const getBlockNumber = vi.fn().mockResolvedValue(120n);
|
|
257
|
+
const handler = createConfirmationWorkerHandler({
|
|
258
|
+
sqlite: mock.db,
|
|
259
|
+
getBlockNumber,
|
|
260
|
+
});
|
|
261
|
+
await handler();
|
|
262
|
+
// getBlockNumber should be called only once for mainnet (cached)
|
|
263
|
+
expect(getBlockNumber).toHaveBeenCalledTimes(1);
|
|
264
|
+
// Both should be confirmed
|
|
265
|
+
expect(mock.getUpdateCalls()).toHaveLength(2);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
// -----------------------------------------------------------------------
|
|
269
|
+
// 3. Retention worker
|
|
270
|
+
// -----------------------------------------------------------------------
|
|
271
|
+
describe('createRetentionWorkerHandler', () => {
|
|
272
|
+
it('should delete records older than retention_days', async () => {
|
|
273
|
+
const mock = createRetentionMockDb(5);
|
|
274
|
+
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
275
|
+
const handler = createRetentionWorkerHandler({
|
|
276
|
+
sqlite: mock.db,
|
|
277
|
+
getRetentionDays: () => 30,
|
|
278
|
+
});
|
|
279
|
+
await handler();
|
|
280
|
+
const sql = mock.getPrepareSql();
|
|
281
|
+
expect(sql).toContain('DELETE FROM incoming_transactions WHERE detected_at < ?');
|
|
282
|
+
// Cutoff should be roughly now - 30 days
|
|
283
|
+
const cutoff = mock.getRunArgs()[0];
|
|
284
|
+
const expectedCutoff = Math.floor(Date.now() / 1000) - 30 * 86400;
|
|
285
|
+
expect(Math.abs(cutoff - expectedCutoff)).toBeLessThan(2); // within 2 seconds
|
|
286
|
+
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('deleted 5'));
|
|
287
|
+
logSpy.mockRestore();
|
|
288
|
+
});
|
|
289
|
+
it('should support hot-reload: changing retention_days adjusts cutoff', async () => {
|
|
290
|
+
let retentionDays = 30;
|
|
291
|
+
const mock1 = createRetentionMockDb(0);
|
|
292
|
+
const handler = createRetentionWorkerHandler({
|
|
293
|
+
sqlite: mock1.db,
|
|
294
|
+
getRetentionDays: () => retentionDays,
|
|
295
|
+
});
|
|
296
|
+
// First run with 30 days
|
|
297
|
+
await handler();
|
|
298
|
+
const cutoff30 = mock1.getRunArgs()[0];
|
|
299
|
+
// Change to 7 days (hot-reload)
|
|
300
|
+
retentionDays = 7;
|
|
301
|
+
const mock2 = createRetentionMockDb(0);
|
|
302
|
+
const handler2 = createRetentionWorkerHandler({
|
|
303
|
+
sqlite: mock2.db,
|
|
304
|
+
getRetentionDays: () => retentionDays,
|
|
305
|
+
});
|
|
306
|
+
await handler2();
|
|
307
|
+
const cutoff7 = mock2.getRunArgs()[0];
|
|
308
|
+
// 7-day cutoff should be more recent (larger) than 30-day cutoff
|
|
309
|
+
expect(cutoff7).toBeGreaterThan(cutoff30);
|
|
310
|
+
});
|
|
311
|
+
it('should not log when 0 deletions', async () => {
|
|
312
|
+
const mock = createRetentionMockDb(0);
|
|
313
|
+
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
314
|
+
const handler = createRetentionWorkerHandler({
|
|
315
|
+
sqlite: mock.db,
|
|
316
|
+
getRetentionDays: () => 30,
|
|
317
|
+
});
|
|
318
|
+
await handler();
|
|
319
|
+
expect(logSpy).not.toHaveBeenCalled();
|
|
320
|
+
logSpy.mockRestore();
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
// -----------------------------------------------------------------------
|
|
324
|
+
// 4. Cursor utilities
|
|
325
|
+
// -----------------------------------------------------------------------
|
|
326
|
+
describe('updateCursor', () => {
|
|
327
|
+
it('should INSERT OR REPLACE cursor for Solana wallet (last_signature)', () => {
|
|
328
|
+
const mock = createCursorMockDb();
|
|
329
|
+
updateCursor(mock.db, 'wallet-1', 'solana', 'mainnet', 'sig-abc123');
|
|
330
|
+
const calls = mock.getRunCalls();
|
|
331
|
+
expect(calls).toHaveLength(1);
|
|
332
|
+
// walletId, chain, network, last_signature, last_block_number, updated_at
|
|
333
|
+
expect(calls[0][0]).toBe('wallet-1');
|
|
334
|
+
expect(calls[0][1]).toBe('solana');
|
|
335
|
+
expect(calls[0][2]).toBe('mainnet');
|
|
336
|
+
expect(calls[0][3]).toBe('sig-abc123'); // last_signature
|
|
337
|
+
expect(calls[0][4]).toBeNull(); // last_block_number null for Solana
|
|
338
|
+
expect(typeof calls[0][5]).toBe('number'); // updated_at
|
|
339
|
+
});
|
|
340
|
+
it('should INSERT OR REPLACE cursor for EVM wallet (last_block_number)', () => {
|
|
341
|
+
const mock = createCursorMockDb();
|
|
342
|
+
updateCursor(mock.db, 'wallet-2', 'ethereum', 'mainnet', '12345');
|
|
343
|
+
const calls = mock.getRunCalls();
|
|
344
|
+
expect(calls).toHaveLength(1);
|
|
345
|
+
expect(calls[0][0]).toBe('wallet-2');
|
|
346
|
+
expect(calls[0][1]).toBe('ethereum');
|
|
347
|
+
expect(calls[0][2]).toBe('mainnet');
|
|
348
|
+
expect(calls[0][3]).toBeNull(); // last_signature null for EVM
|
|
349
|
+
expect(calls[0][4]).toBe(12345); // last_block_number parsed
|
|
350
|
+
});
|
|
351
|
+
it('should replace existing cursor for same wallet+chain+network', () => {
|
|
352
|
+
const mock = createCursorMockDb();
|
|
353
|
+
updateCursor(mock.db, 'wallet-1', 'solana', 'mainnet', 'sig-1');
|
|
354
|
+
updateCursor(mock.db, 'wallet-1', 'solana', 'mainnet', 'sig-2');
|
|
355
|
+
// Both should execute (INSERT OR REPLACE handles the update at DB level)
|
|
356
|
+
const calls = mock.getRunCalls();
|
|
357
|
+
expect(calls).toHaveLength(2);
|
|
358
|
+
expect(calls[0][3]).toBe('sig-1');
|
|
359
|
+
expect(calls[1][3]).toBe('sig-2');
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
describe('loadCursor', () => {
|
|
363
|
+
it('should return Solana cursor value (last_signature) when exists', () => {
|
|
364
|
+
const mock = createCursorMockDb();
|
|
365
|
+
mock.setGetResult({ last_signature: 'sig-xyz', last_block_number: null });
|
|
366
|
+
const result = loadCursor(mock.db, 'wallet-1', 'solana', 'mainnet');
|
|
367
|
+
expect(result).toBe('sig-xyz');
|
|
368
|
+
});
|
|
369
|
+
it('should return EVM cursor value (last_block_number as string) when exists', () => {
|
|
370
|
+
const mock = createCursorMockDb();
|
|
371
|
+
mock.setGetResult({ last_signature: null, last_block_number: 9999 });
|
|
372
|
+
const result = loadCursor(mock.db, 'wallet-2', 'ethereum', 'mainnet');
|
|
373
|
+
expect(result).toBe('9999');
|
|
374
|
+
});
|
|
375
|
+
it('should return null when no cursor exists', () => {
|
|
376
|
+
const mock = createCursorMockDb();
|
|
377
|
+
mock.setGetResult(undefined);
|
|
378
|
+
const result = loadCursor(mock.db, 'wallet-3', 'solana', 'devnet');
|
|
379
|
+
expect(result).toBeNull();
|
|
380
|
+
});
|
|
381
|
+
it('should return null when both cursor fields are null/zero', () => {
|
|
382
|
+
const mock = createCursorMockDb();
|
|
383
|
+
mock.setGetResult({ last_signature: null, last_block_number: null });
|
|
384
|
+
const result = loadCursor(mock.db, 'wallet-4', 'ethereum', 'sepolia');
|
|
385
|
+
expect(result).toBeNull();
|
|
386
|
+
});
|
|
387
|
+
it('should pass correct params to SELECT query', () => {
|
|
388
|
+
const mock = createCursorMockDb();
|
|
389
|
+
mock.setGetResult(undefined);
|
|
390
|
+
loadCursor(mock.db, 'w-abc', 'solana', 'devnet');
|
|
391
|
+
const getCalls = mock.getGetCalls();
|
|
392
|
+
expect(getCalls).toHaveLength(1);
|
|
393
|
+
expect(getCalls[0]).toEqual(['w-abc', 'solana', 'devnet']);
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
// -----------------------------------------------------------------------
|
|
397
|
+
// 5. Gap recovery handler
|
|
398
|
+
// -----------------------------------------------------------------------
|
|
399
|
+
describe('createGapRecoveryHandler', () => {
|
|
400
|
+
it('should call pollAll() on the correct subscriber for chain:network', async () => {
|
|
401
|
+
const mockPollAll = vi.fn().mockResolvedValue(undefined);
|
|
402
|
+
const subscribers = new Map([
|
|
403
|
+
['solana:mainnet', { subscriber: { pollAll: mockPollAll } }],
|
|
404
|
+
]);
|
|
405
|
+
const handler = createGapRecoveryHandler({ subscribers });
|
|
406
|
+
await handler('solana', 'mainnet', ['wallet-1', 'wallet-2']);
|
|
407
|
+
expect(mockPollAll).toHaveBeenCalledTimes(1);
|
|
408
|
+
});
|
|
409
|
+
it('should gracefully skip when no subscriber exists for chain:network', async () => {
|
|
410
|
+
const subscribers = new Map();
|
|
411
|
+
const handler = createGapRecoveryHandler({ subscribers });
|
|
412
|
+
// Should not throw
|
|
413
|
+
await expect(handler('solana', 'devnet', ['wallet-x'])).resolves.toBeUndefined();
|
|
414
|
+
});
|
|
415
|
+
it('should warn but not throw when pollAll() fails', async () => {
|
|
416
|
+
const mockPollAll = vi.fn().mockRejectedValue(new Error('RPC down'));
|
|
417
|
+
const subscribers = new Map([
|
|
418
|
+
['ethereum:mainnet', { subscriber: { pollAll: mockPollAll } }],
|
|
419
|
+
]);
|
|
420
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
421
|
+
const handler = createGapRecoveryHandler({ subscribers });
|
|
422
|
+
await expect(handler('ethereum', 'mainnet', ['w1'])).resolves.toBeUndefined();
|
|
423
|
+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Gap recovery failed'), expect.any(Error));
|
|
424
|
+
warnSpy.mockRestore();
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
// -----------------------------------------------------------------------
|
|
428
|
+
// 6. EVM_CONFIRMATION_THRESHOLDS validation
|
|
429
|
+
// -----------------------------------------------------------------------
|
|
430
|
+
describe('EVM_CONFIRMATION_THRESHOLDS', () => {
|
|
431
|
+
it('should have mainnet = 12', () => {
|
|
432
|
+
expect(EVM_CONFIRMATION_THRESHOLDS['mainnet']).toBe(12);
|
|
433
|
+
});
|
|
434
|
+
it('should have polygon-mainnet = 128', () => {
|
|
435
|
+
expect(EVM_CONFIRMATION_THRESHOLDS['polygon-mainnet']).toBe(128);
|
|
436
|
+
});
|
|
437
|
+
it('should have all testnet thresholds = 1', () => {
|
|
438
|
+
expect(EVM_CONFIRMATION_THRESHOLDS['sepolia']).toBe(1);
|
|
439
|
+
expect(EVM_CONFIRMATION_THRESHOLDS['polygon-amoy']).toBe(1);
|
|
440
|
+
expect(EVM_CONFIRMATION_THRESHOLDS['arbitrum-mainnet']).toBe(1);
|
|
441
|
+
expect(EVM_CONFIRMATION_THRESHOLDS['arbitrum-sepolia']).toBe(1);
|
|
442
|
+
expect(EVM_CONFIRMATION_THRESHOLDS['base-sepolia']).toBe(1);
|
|
443
|
+
});
|
|
444
|
+
it('should have base-mainnet = 12', () => {
|
|
445
|
+
expect(EVM_CONFIRMATION_THRESHOLDS['base-mainnet']).toBe(12);
|
|
446
|
+
});
|
|
447
|
+
it('DEFAULT_EVM_CONFIRMATIONS should be 12', () => {
|
|
448
|
+
expect(DEFAULT_EVM_CONFIRMATIONS).toBe(12);
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
//# sourceMappingURL=incoming-tx-workers.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"incoming-tx-workers.test.js","sourceRoot":"","sources":["../../../../src/services/incoming/__tests__/incoming-tx-workers.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for incoming TX monitoring pipeline pitfalls.
|
|
3
|
+
*
|
|
4
|
+
* Verifies that the 5 core pitfalls from design doc 76 Section 12 are
|
|
5
|
+
* defended when components work together:
|
|
6
|
+
*
|
|
7
|
+
* C-01: WebSocket listener leak (addWallet/removeWallet cycles)
|
|
8
|
+
* C-02: SQLite event loop contention (batch write + flush chunking)
|
|
9
|
+
* C-04: Duplicate event prevention (Map dedup + ON CONFLICT)
|
|
10
|
+
* C-05: Shutdown data loss (drain on stop())
|
|
11
|
+
* C-06: EVM reorg safety (block confirmation thresholds)
|
|
12
|
+
*
|
|
13
|
+
* These tests use real internal classes (IncomingTxQueue, SubscriptionMultiplexer,
|
|
14
|
+
* IncomingTxMonitorService) with mock boundaries (DB, IChainSubscriber).
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=integration-pitfall.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration-pitfall.test.d.ts","sourceRoot":"","sources":["../../../../src/services/incoming/__tests__/integration-pitfall.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
|