@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.
Files changed (193) hide show
  1. package/dist/api/middleware/error-handler.d.ts +1 -1
  2. package/dist/api/middleware/error-handler.js +2 -2
  3. package/dist/api/middleware/error-handler.js.map +1 -1
  4. package/dist/api/routes/admin.d.ts.map +1 -1
  5. package/dist/api/routes/admin.js +6 -30
  6. package/dist/api/routes/admin.js.map +1 -1
  7. package/dist/api/routes/connect-info.d.ts.map +1 -1
  8. package/dist/api/routes/connect-info.js +6 -0
  9. package/dist/api/routes/connect-info.js.map +1 -1
  10. package/dist/api/routes/incoming.d.ts +40 -0
  11. package/dist/api/routes/incoming.d.ts.map +1 -0
  12. package/dist/api/routes/incoming.js +281 -0
  13. package/dist/api/routes/incoming.js.map +1 -0
  14. package/dist/api/routes/openapi-schemas.d.ts +337 -24
  15. package/dist/api/routes/openapi-schemas.d.ts.map +1 -1
  16. package/dist/api/routes/openapi-schemas.js +78 -0
  17. package/dist/api/routes/openapi-schemas.js.map +1 -1
  18. package/dist/api/routes/tokens.d.ts.map +1 -1
  19. package/dist/api/routes/tokens.js +1 -0
  20. package/dist/api/routes/tokens.js.map +1 -1
  21. package/dist/api/routes/wallets.d.ts +4 -0
  22. package/dist/api/routes/wallets.d.ts.map +1 -1
  23. package/dist/api/routes/wallets.js +173 -1
  24. package/dist/api/routes/wallets.js.map +1 -1
  25. package/dist/api/routes/x402.js +1 -1
  26. package/dist/api/routes/x402.js.map +1 -1
  27. package/dist/api/server.d.ts +4 -0
  28. package/dist/api/server.d.ts.map +1 -1
  29. package/dist/api/server.js +12 -0
  30. package/dist/api/server.js.map +1 -1
  31. package/dist/infrastructure/config/loader.d.ts +43 -0
  32. package/dist/infrastructure/config/loader.d.ts.map +1 -1
  33. package/dist/infrastructure/config/loader.js +13 -1
  34. package/dist/infrastructure/config/loader.js.map +1 -1
  35. package/dist/infrastructure/database/index.d.ts +1 -1
  36. package/dist/infrastructure/database/index.d.ts.map +1 -1
  37. package/dist/infrastructure/database/index.js +1 -1
  38. package/dist/infrastructure/database/index.js.map +1 -1
  39. package/dist/infrastructure/database/migrate.d.ts +2 -2
  40. package/dist/infrastructure/database/migrate.d.ts.map +1 -1
  41. package/dist/infrastructure/database/migrate.js +123 -6
  42. package/dist/infrastructure/database/migrate.js.map +1 -1
  43. package/dist/infrastructure/database/schema.d.ts +400 -1
  44. package/dist/infrastructure/database/schema.d.ts.map +1 -1
  45. package/dist/infrastructure/database/schema.js +43 -2
  46. package/dist/infrastructure/database/schema.js.map +1 -1
  47. package/dist/infrastructure/oracle/coingecko-oracle.d.ts +9 -1
  48. package/dist/infrastructure/oracle/coingecko-oracle.d.ts.map +1 -1
  49. package/dist/infrastructure/oracle/coingecko-oracle.js +40 -23
  50. package/dist/infrastructure/oracle/coingecko-oracle.js.map +1 -1
  51. package/dist/infrastructure/oracle/coingecko-platform-ids.d.ts +11 -10
  52. package/dist/infrastructure/oracle/coingecko-platform-ids.d.ts.map +1 -1
  53. package/dist/infrastructure/oracle/coingecko-platform-ids.js +20 -12
  54. package/dist/infrastructure/oracle/coingecko-platform-ids.js.map +1 -1
  55. package/dist/infrastructure/oracle/index.d.ts +1 -1
  56. package/dist/infrastructure/oracle/index.d.ts.map +1 -1
  57. package/dist/infrastructure/oracle/index.js +1 -1
  58. package/dist/infrastructure/oracle/index.js.map +1 -1
  59. package/dist/infrastructure/oracle/oracle-chain.d.ts.map +1 -1
  60. package/dist/infrastructure/oracle/oracle-chain.js +7 -4
  61. package/dist/infrastructure/oracle/oracle-chain.js.map +1 -1
  62. package/dist/infrastructure/oracle/price-cache.d.ts +24 -8
  63. package/dist/infrastructure/oracle/price-cache.d.ts.map +1 -1
  64. package/dist/infrastructure/oracle/price-cache.js +32 -11
  65. package/dist/infrastructure/oracle/price-cache.js.map +1 -1
  66. package/dist/infrastructure/oracle/pyth-feed-ids.d.ts +11 -8
  67. package/dist/infrastructure/oracle/pyth-feed-ids.d.ts.map +1 -1
  68. package/dist/infrastructure/oracle/pyth-feed-ids.js +16 -17
  69. package/dist/infrastructure/oracle/pyth-feed-ids.js.map +1 -1
  70. package/dist/infrastructure/oracle/pyth-oracle.d.ts.map +1 -1
  71. package/dist/infrastructure/oracle/pyth-oracle.js +7 -4
  72. package/dist/infrastructure/oracle/pyth-oracle.js.map +1 -1
  73. package/dist/infrastructure/settings/hot-reload.d.ts +9 -0
  74. package/dist/infrastructure/settings/hot-reload.d.ts.map +1 -1
  75. package/dist/infrastructure/settings/hot-reload.js +34 -5
  76. package/dist/infrastructure/settings/hot-reload.js.map +1 -1
  77. package/dist/infrastructure/settings/setting-keys.d.ts +2 -2
  78. package/dist/infrastructure/settings/setting-keys.d.ts.map +1 -1
  79. package/dist/infrastructure/settings/setting-keys.js +12 -3
  80. package/dist/infrastructure/settings/setting-keys.js.map +1 -1
  81. package/dist/infrastructure/token-registry/token-registry-service.d.ts +1 -0
  82. package/dist/infrastructure/token-registry/token-registry-service.d.ts.map +1 -1
  83. package/dist/infrastructure/token-registry/token-registry-service.js +15 -1
  84. package/dist/infrastructure/token-registry/token-registry-service.js.map +1 -1
  85. package/dist/lifecycle/daemon.d.ts +3 -1
  86. package/dist/lifecycle/daemon.d.ts.map +1 -1
  87. package/dist/lifecycle/daemon.js +84 -4
  88. package/dist/lifecycle/daemon.js.map +1 -1
  89. package/dist/notifications/channels/discord.d.ts.map +1 -1
  90. package/dist/notifications/channels/discord.js +21 -8
  91. package/dist/notifications/channels/discord.js.map +1 -1
  92. package/dist/notifications/channels/format-utils.d.ts +11 -0
  93. package/dist/notifications/channels/format-utils.d.ts.map +1 -0
  94. package/dist/notifications/channels/format-utils.js +19 -0
  95. package/dist/notifications/channels/format-utils.js.map +1 -0
  96. package/dist/notifications/channels/ntfy.d.ts.map +1 -1
  97. package/dist/notifications/channels/ntfy.js +18 -2
  98. package/dist/notifications/channels/ntfy.js.map +1 -1
  99. package/dist/notifications/channels/slack.d.ts.map +1 -1
  100. package/dist/notifications/channels/slack.js +20 -7
  101. package/dist/notifications/channels/slack.js.map +1 -1
  102. package/dist/notifications/channels/telegram.d.ts.map +1 -1
  103. package/dist/notifications/channels/telegram.js +21 -5
  104. package/dist/notifications/channels/telegram.js.map +1 -1
  105. package/dist/notifications/notification-service.d.ts +14 -0
  106. package/dist/notifications/notification-service.d.ts.map +1 -1
  107. package/dist/notifications/notification-service.js +89 -2
  108. package/dist/notifications/notification-service.js.map +1 -1
  109. package/dist/pipeline/database-policy-engine.d.ts +9 -5
  110. package/dist/pipeline/database-policy-engine.d.ts.map +1 -1
  111. package/dist/pipeline/database-policy-engine.js +42 -10
  112. package/dist/pipeline/database-policy-engine.js.map +1 -1
  113. package/dist/pipeline/resolve-effective-amount-usd.d.ts +1 -1
  114. package/dist/pipeline/resolve-effective-amount-usd.d.ts.map +1 -1
  115. package/dist/pipeline/resolve-effective-amount-usd.js +5 -3
  116. package/dist/pipeline/resolve-effective-amount-usd.js.map +1 -1
  117. package/dist/pipeline/stages.d.ts.map +1 -1
  118. package/dist/pipeline/stages.js +7 -1
  119. package/dist/pipeline/stages.js.map +1 -1
  120. package/dist/services/incoming/__tests__/incoming-tx-monitor-service.test.d.ts +11 -0
  121. package/dist/services/incoming/__tests__/incoming-tx-monitor-service.test.d.ts.map +1 -0
  122. package/dist/services/incoming/__tests__/incoming-tx-monitor-service.test.js +432 -0
  123. package/dist/services/incoming/__tests__/incoming-tx-monitor-service.test.js.map +1 -0
  124. package/dist/services/incoming/__tests__/incoming-tx-queue.test.d.ts +12 -0
  125. package/dist/services/incoming/__tests__/incoming-tx-queue.test.d.ts.map +1 -0
  126. package/dist/services/incoming/__tests__/incoming-tx-queue.test.js +419 -0
  127. package/dist/services/incoming/__tests__/incoming-tx-queue.test.js.map +1 -0
  128. package/dist/services/incoming/__tests__/incoming-tx-workers.test.d.ts +14 -0
  129. package/dist/services/incoming/__tests__/incoming-tx-workers.test.d.ts.map +1 -0
  130. package/dist/services/incoming/__tests__/incoming-tx-workers.test.js +452 -0
  131. package/dist/services/incoming/__tests__/incoming-tx-workers.test.js.map +1 -0
  132. package/dist/services/incoming/__tests__/integration-pitfall.test.d.ts +17 -0
  133. package/dist/services/incoming/__tests__/integration-pitfall.test.d.ts.map +1 -0
  134. package/dist/services/incoming/__tests__/integration-pitfall.test.js +653 -0
  135. package/dist/services/incoming/__tests__/integration-pitfall.test.js.map +1 -0
  136. package/dist/services/incoming/__tests__/integration-resilience.test.d.ts +14 -0
  137. package/dist/services/incoming/__tests__/integration-resilience.test.d.ts.map +1 -0
  138. package/dist/services/incoming/__tests__/integration-resilience.test.js +501 -0
  139. package/dist/services/incoming/__tests__/integration-resilience.test.js.map +1 -0
  140. package/dist/services/incoming/__tests__/integration-wiring.test.d.ts +15 -0
  141. package/dist/services/incoming/__tests__/integration-wiring.test.d.ts.map +1 -0
  142. package/dist/services/incoming/__tests__/integration-wiring.test.js +355 -0
  143. package/dist/services/incoming/__tests__/integration-wiring.test.js.map +1 -0
  144. package/dist/services/incoming/__tests__/safety-rules.test.d.ts +10 -0
  145. package/dist/services/incoming/__tests__/safety-rules.test.d.ts.map +1 -0
  146. package/dist/services/incoming/__tests__/safety-rules.test.js +165 -0
  147. package/dist/services/incoming/__tests__/safety-rules.test.js.map +1 -0
  148. package/dist/services/incoming/__tests__/subscription-multiplexer.test.d.ts +2 -0
  149. package/dist/services/incoming/__tests__/subscription-multiplexer.test.d.ts.map +1 -0
  150. package/dist/services/incoming/__tests__/subscription-multiplexer.test.js +267 -0
  151. package/dist/services/incoming/__tests__/subscription-multiplexer.test.js.map +1 -0
  152. package/dist/services/incoming/incoming-tx-monitor-service.d.ts +98 -0
  153. package/dist/services/incoming/incoming-tx-monitor-service.d.ts.map +1 -0
  154. package/dist/services/incoming/incoming-tx-monitor-service.js +357 -0
  155. package/dist/services/incoming/incoming-tx-monitor-service.js.map +1 -0
  156. package/dist/services/incoming/incoming-tx-queue.d.ts +52 -0
  157. package/dist/services/incoming/incoming-tx-queue.d.ts.map +1 -0
  158. package/dist/services/incoming/incoming-tx-queue.js +109 -0
  159. package/dist/services/incoming/incoming-tx-queue.js.map +1 -0
  160. package/dist/services/incoming/incoming-tx-workers.d.ts +89 -0
  161. package/dist/services/incoming/incoming-tx-workers.d.ts.map +1 -0
  162. package/dist/services/incoming/incoming-tx-workers.js +176 -0
  163. package/dist/services/incoming/incoming-tx-workers.js.map +1 -0
  164. package/dist/services/incoming/index.d.ts +14 -0
  165. package/dist/services/incoming/index.d.ts.map +1 -0
  166. package/dist/services/incoming/index.js +11 -0
  167. package/dist/services/incoming/index.js.map +1 -0
  168. package/dist/services/incoming/safety-rules.d.ts +70 -0
  169. package/dist/services/incoming/safety-rules.d.ts.map +1 -0
  170. package/dist/services/incoming/safety-rules.js +68 -0
  171. package/dist/services/incoming/safety-rules.js.map +1 -0
  172. package/dist/services/incoming/subscription-multiplexer.d.ts +87 -0
  173. package/dist/services/incoming/subscription-multiplexer.d.ts.map +1 -0
  174. package/dist/services/incoming/subscription-multiplexer.js +169 -0
  175. package/dist/services/incoming/subscription-multiplexer.js.map +1 -0
  176. package/dist/services/signing-sdk/approval-channel-router.d.ts +1 -1
  177. package/dist/services/signing-sdk/approval-channel-router.d.ts.map +1 -1
  178. package/dist/services/signing-sdk/approval-channel-router.js +2 -3
  179. package/dist/services/signing-sdk/approval-channel-router.js.map +1 -1
  180. package/dist/services/signing-sdk/channels/wallet-notification-channel.js +1 -1
  181. package/dist/services/signing-sdk/channels/wallet-notification-channel.js.map +1 -1
  182. package/dist/services/wc-session-service.d.ts +0 -2
  183. package/dist/services/wc-session-service.d.ts.map +1 -1
  184. package/dist/services/wc-session-service.js +2 -23
  185. package/dist/services/wc-session-service.js.map +1 -1
  186. package/dist/services/x402/x402-domain-policy.d.ts +6 -1
  187. package/dist/services/x402/x402-domain-policy.d.ts.map +1 -1
  188. package/dist/services/x402/x402-domain-policy.js +6 -2
  189. package/dist/services/x402/x402-domain-policy.js.map +1 -1
  190. package/package.json +4 -4
  191. package/public/admin/assets/index-D06O_cSo.js +1 -0
  192. package/public/admin/index.html +1 -1
  193. 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"}