@revealui/services 0.1.0 → 0.2.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 (49) hide show
  1. package/dist/api/handlers/subscription-handlers.d.ts +5 -1
  2. package/dist/api/handlers/subscription-handlers.d.ts.map +1 -1
  3. package/dist/api/handlers/subscription-handlers.js +5 -1
  4. package/dist/api/handlers/subscription-handlers.js.map +1 -1
  5. package/dist/api/webhooks/index.d.ts +10 -0
  6. package/dist/api/webhooks/index.d.ts.map +1 -1
  7. package/dist/api/webhooks/index.js +10 -0
  8. package/dist/api/webhooks/index.js.map +1 -1
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/revealcoin/__tests__/client.test.d.ts +2 -0
  14. package/dist/revealcoin/__tests__/client.test.d.ts.map +1 -0
  15. package/dist/revealcoin/__tests__/client.test.js +207 -0
  16. package/dist/revealcoin/__tests__/client.test.js.map +1 -0
  17. package/dist/revealcoin/__tests__/config.test.d.ts +2 -0
  18. package/dist/revealcoin/__tests__/config.test.d.ts.map +1 -0
  19. package/dist/revealcoin/__tests__/config.test.js +91 -0
  20. package/dist/revealcoin/__tests__/config.test.js.map +1 -0
  21. package/dist/revealcoin/__tests__/oracle.test.d.ts +2 -0
  22. package/dist/revealcoin/__tests__/oracle.test.d.ts.map +1 -0
  23. package/dist/revealcoin/__tests__/oracle.test.js +238 -0
  24. package/dist/revealcoin/__tests__/oracle.test.js.map +1 -0
  25. package/dist/revealcoin/__tests__/safeguards.test.d.ts +2 -0
  26. package/dist/revealcoin/__tests__/safeguards.test.d.ts.map +1 -0
  27. package/dist/revealcoin/__tests__/safeguards.test.js +571 -0
  28. package/dist/revealcoin/__tests__/safeguards.test.js.map +1 -0
  29. package/dist/revealcoin/client.d.ts +51 -0
  30. package/dist/revealcoin/client.d.ts.map +1 -0
  31. package/dist/revealcoin/client.js +211 -0
  32. package/dist/revealcoin/client.js.map +1 -0
  33. package/dist/revealcoin/config.d.ts +32 -0
  34. package/dist/revealcoin/config.d.ts.map +1 -0
  35. package/dist/revealcoin/config.js +54 -0
  36. package/dist/revealcoin/config.js.map +1 -0
  37. package/dist/revealcoin/index.d.ts +5 -0
  38. package/dist/revealcoin/index.d.ts.map +1 -0
  39. package/dist/revealcoin/index.js +5 -0
  40. package/dist/revealcoin/index.js.map +1 -0
  41. package/dist/revealcoin/oracle.d.ts +81 -0
  42. package/dist/revealcoin/oracle.d.ts.map +1 -0
  43. package/dist/revealcoin/oracle.js +211 -0
  44. package/dist/revealcoin/oracle.js.map +1 -0
  45. package/dist/revealcoin/safeguards.d.ts +92 -0
  46. package/dist/revealcoin/safeguards.d.ts.map +1 -0
  47. package/dist/revealcoin/safeguards.js +240 -0
  48. package/dist/revealcoin/safeguards.js.map +1 -0
  49. package/package.json +9 -3
@@ -0,0 +1,571 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+ // Chainable mock DB — every method returns `chain` so any Drizzle query order works.
3
+ let queryResult = [];
4
+ const chain = {};
5
+ chain.select = vi.fn(() => chain);
6
+ chain.from = vi.fn(() => chain);
7
+ chain.where = vi.fn(() => chain);
8
+ chain.orderBy = vi.fn(() => chain);
9
+ chain.limit = vi.fn(() => chain);
10
+ chain.values = vi.fn(() => Promise.resolve());
11
+ chain.insert = vi.fn(() => chain);
12
+ // Make chain thenable so `await db.select().from()...` resolves to queryResult
13
+ chain.then = vi.fn((resolve) => resolve(queryResult));
14
+ vi.mock('@revealui/db', () => ({
15
+ getClient: vi.fn(() => chain),
16
+ }));
17
+ vi.mock('@revealui/db/schema', () => ({
18
+ revealcoinPayments: {
19
+ id: 'id',
20
+ txSignature: 'txSignature',
21
+ walletAddress: 'walletAddress',
22
+ userId: 'userId',
23
+ amountRvui: 'amountRvui',
24
+ amountUsd: 'amountUsd',
25
+ discountUsd: 'discountUsd',
26
+ purpose: 'purpose',
27
+ status: 'status',
28
+ createdAt: 'createdAt',
29
+ },
30
+ revealcoinPriceSnapshots: {
31
+ id: 'id',
32
+ priceUsd: 'priceUsd',
33
+ source: 'source',
34
+ recordedAt: 'recordedAt',
35
+ },
36
+ }));
37
+ vi.mock('drizzle-orm', () => ({
38
+ and: vi.fn((...args) => args),
39
+ desc: vi.fn((col) => `desc(${String(col)})`),
40
+ eq: vi.fn((col, val) => `eq(${String(col)},${String(val)})`),
41
+ gte: vi.fn((col, val) => `gte(${String(col)},${String(val)})`),
42
+ sql: vi.fn(),
43
+ }));
44
+ vi.mock('@revealui/core/observability/logger', () => ({
45
+ createLogger: () => ({
46
+ debug: vi.fn(),
47
+ info: vi.fn(),
48
+ warn: vi.fn(),
49
+ error: vi.fn(),
50
+ }),
51
+ }));
52
+ import { configureSafeguards, getSafeguardsConfig, getTwapPrice, isDuplicateTransaction, isDiscountCapExceeded, isPaymentOverMaximum, isPriceCircuitBreakerOpen, isWalletRateLimited, recordPayment, recordPriceSnapshot, resetSafeguardsConfig, validatePayment, } from '../safeguards.js';
53
+ describe('SafeguardsConfig', () => {
54
+ afterEach(() => {
55
+ resetSafeguardsConfig();
56
+ });
57
+ it('returns default config', () => {
58
+ const config = getSafeguardsConfig();
59
+ expect(config.twapWindowMs).toBe(3_600_000);
60
+ expect(config.priceCircuitBreakerThreshold).toBe(0.30);
61
+ expect(config.maxPaymentsPerWalletPerHour).toBe(3);
62
+ expect(config.maxSinglePaymentUsd).toBe(500);
63
+ expect(config.maxMonthlyDiscountUsd).toBe(100);
64
+ });
65
+ it('overrides config', () => {
66
+ configureSafeguards({ maxSinglePaymentUsd: 200, maxPaymentsPerWalletPerHour: 5 });
67
+ const config = getSafeguardsConfig();
68
+ expect(config.maxSinglePaymentUsd).toBe(200);
69
+ expect(config.maxPaymentsPerWalletPerHour).toBe(5);
70
+ expect(config.twapWindowMs).toBe(3_600_000); // unchanged
71
+ });
72
+ it('resets to defaults', () => {
73
+ configureSafeguards({ maxSinglePaymentUsd: 1 });
74
+ resetSafeguardsConfig();
75
+ expect(getSafeguardsConfig().maxSinglePaymentUsd).toBe(500);
76
+ });
77
+ it('returns a copy (not mutable reference)', () => {
78
+ const a = getSafeguardsConfig();
79
+ const b = getSafeguardsConfig();
80
+ expect(a).not.toBe(b);
81
+ expect(a).toEqual(b);
82
+ });
83
+ });
84
+ describe('isPaymentOverMaximum', () => {
85
+ afterEach(() => resetSafeguardsConfig());
86
+ it('returns false for amounts under cap', () => {
87
+ expect(isPaymentOverMaximum(499)).toBe(false);
88
+ });
89
+ it('returns false for amounts at cap', () => {
90
+ expect(isPaymentOverMaximum(500)).toBe(false);
91
+ });
92
+ it('returns true for amounts over cap', () => {
93
+ expect(isPaymentOverMaximum(501)).toBe(true);
94
+ });
95
+ it('respects configured cap', () => {
96
+ configureSafeguards({ maxSinglePaymentUsd: 100 });
97
+ expect(isPaymentOverMaximum(101)).toBe(true);
98
+ expect(isPaymentOverMaximum(100)).toBe(false);
99
+ });
100
+ });
101
+ describe('getTwapPrice', () => {
102
+ beforeEach(() => {
103
+ vi.clearAllMocks();
104
+ // Re-bind chain methods after clearAllMocks
105
+ chain.select = vi.fn(() => chain);
106
+ chain.from = vi.fn(() => chain);
107
+ chain.where = vi.fn(() => chain);
108
+ chain.orderBy = vi.fn(() => chain);
109
+ chain.limit = vi.fn(() => chain);
110
+ });
111
+ it('returns null with fewer than 2 snapshots', async () => {
112
+ queryResult = [];
113
+ chain.then = vi.fn((resolve) => resolve(queryResult));
114
+ const result = await getTwapPrice();
115
+ expect(result).toBeNull();
116
+ });
117
+ it('returns null with exactly 1 snapshot', async () => {
118
+ queryResult = [{ priceUsd: '0.005', recordedAt: new Date() }];
119
+ chain.then = vi.fn((resolve) => resolve(queryResult));
120
+ const result = await getTwapPrice();
121
+ expect(result).toBeNull();
122
+ });
123
+ it('calculates time-weighted average with 2 snapshots', async () => {
124
+ const now = Date.now();
125
+ queryResult = [
126
+ { priceUsd: '0.004', recordedAt: new Date(now - 60_000) },
127
+ { priceUsd: '0.006', recordedAt: new Date(now) },
128
+ ];
129
+ chain.then = vi.fn((resolve) => resolve(queryResult));
130
+ const result = await getTwapPrice();
131
+ expect(result).not.toBeNull();
132
+ // Only 1 interval: price 0.004 for 60s → TWAP = 0.004
133
+ expect(result).toBeCloseTo(0.004, 6);
134
+ });
135
+ it('calculates time-weighted average with 3 snapshots', async () => {
136
+ const now = Date.now();
137
+ queryResult = [
138
+ { priceUsd: '0.004', recordedAt: new Date(now - 120_000) },
139
+ { priceUsd: '0.006', recordedAt: new Date(now - 60_000) },
140
+ { priceUsd: '0.008', recordedAt: new Date(now) },
141
+ ];
142
+ chain.then = vi.fn((resolve) => resolve(queryResult));
143
+ const result = await getTwapPrice();
144
+ expect(result).not.toBeNull();
145
+ // TWAP: (0.004 * 60000 + 0.006 * 60000) / 120000 = 0.005
146
+ expect(result).toBeCloseTo(0.005, 6);
147
+ });
148
+ it('returns null when total duration is 0', async () => {
149
+ const now = Date.now();
150
+ const sameTime = new Date(now);
151
+ queryResult = [
152
+ { priceUsd: '0.004', recordedAt: sameTime },
153
+ { priceUsd: '0.006', recordedAt: sameTime },
154
+ ];
155
+ chain.then = vi.fn((resolve) => resolve(queryResult));
156
+ const result = await getTwapPrice();
157
+ expect(result).toBeNull();
158
+ });
159
+ });
160
+ describe('isDuplicateTransaction', () => {
161
+ beforeEach(() => {
162
+ vi.clearAllMocks();
163
+ chain.select = vi.fn(() => chain);
164
+ chain.from = vi.fn(() => chain);
165
+ chain.where = vi.fn(() => chain);
166
+ chain.limit = vi.fn(() => chain);
167
+ });
168
+ it('returns false for new transaction', async () => {
169
+ queryResult = [];
170
+ chain.then = vi.fn((resolve) => resolve(queryResult));
171
+ const result = await isDuplicateTransaction('new-tx-sig');
172
+ expect(result).toBe(false);
173
+ });
174
+ it('returns true for existing transaction', async () => {
175
+ queryResult = [{ id: 'existing-payment-id' }];
176
+ chain.then = vi.fn((resolve) => resolve(queryResult));
177
+ const result = await isDuplicateTransaction('existing-tx-sig');
178
+ expect(result).toBe(true);
179
+ });
180
+ });
181
+ describe('isWalletRateLimited', () => {
182
+ beforeEach(() => {
183
+ vi.clearAllMocks();
184
+ resetSafeguardsConfig();
185
+ chain.select = vi.fn(() => chain);
186
+ chain.from = vi.fn(() => chain);
187
+ chain.where = vi.fn(() => chain);
188
+ });
189
+ it('returns false when under limit', async () => {
190
+ queryResult = [{ count: 2 }];
191
+ chain.then = vi.fn((resolve) => resolve(queryResult));
192
+ const result = await isWalletRateLimited('wallet-abc');
193
+ expect(result).toBe(false);
194
+ });
195
+ it('returns true when at limit', async () => {
196
+ queryResult = [{ count: 3 }];
197
+ chain.then = vi.fn((resolve) => resolve(queryResult));
198
+ const result = await isWalletRateLimited('wallet-abc');
199
+ expect(result).toBe(true);
200
+ });
201
+ it('returns true when over limit', async () => {
202
+ queryResult = [{ count: 5 }];
203
+ chain.then = vi.fn((resolve) => resolve(queryResult));
204
+ const result = await isWalletRateLimited('wallet-abc');
205
+ expect(result).toBe(true);
206
+ });
207
+ it('returns false when result is empty (no payments)', async () => {
208
+ queryResult = [{ count: 0 }];
209
+ chain.then = vi.fn((resolve) => resolve(queryResult));
210
+ const result = await isWalletRateLimited('wallet-abc');
211
+ expect(result).toBe(false);
212
+ });
213
+ });
214
+ describe('isDiscountCapExceeded', () => {
215
+ beforeEach(() => {
216
+ vi.clearAllMocks();
217
+ resetSafeguardsConfig();
218
+ chain.select = vi.fn(() => chain);
219
+ chain.from = vi.fn(() => chain);
220
+ chain.where = vi.fn(() => chain);
221
+ });
222
+ it('returns false when under cap', async () => {
223
+ queryResult = [{ total: 50 }];
224
+ chain.then = vi.fn((resolve) => resolve(queryResult));
225
+ const result = await isDiscountCapExceeded('user-1');
226
+ expect(result).toBe(false);
227
+ });
228
+ it('returns true when at cap', async () => {
229
+ queryResult = [{ total: 100 }];
230
+ chain.then = vi.fn((resolve) => resolve(queryResult));
231
+ const result = await isDiscountCapExceeded('user-1');
232
+ expect(result).toBe(true);
233
+ });
234
+ it('returns true when over cap', async () => {
235
+ queryResult = [{ total: 150 }];
236
+ chain.then = vi.fn((resolve) => resolve(queryResult));
237
+ const result = await isDiscountCapExceeded('user-1');
238
+ expect(result).toBe(true);
239
+ });
240
+ it('returns false when no discounts yet', async () => {
241
+ queryResult = [{ total: 0 }];
242
+ chain.then = vi.fn((resolve) => resolve(queryResult));
243
+ const result = await isDiscountCapExceeded('user-1');
244
+ expect(result).toBe(false);
245
+ });
246
+ it('respects configured cap', async () => {
247
+ configureSafeguards({ maxMonthlyDiscountUsd: 50 });
248
+ queryResult = [{ total: 50 }];
249
+ chain.then = vi.fn((resolve) => resolve(queryResult));
250
+ const result = await isDiscountCapExceeded('user-1');
251
+ expect(result).toBe(true);
252
+ });
253
+ });
254
+ describe('recordPriceSnapshot', () => {
255
+ beforeEach(() => {
256
+ vi.clearAllMocks();
257
+ chain.insert = vi.fn(() => chain);
258
+ chain.values = vi.fn(() => Promise.resolve());
259
+ });
260
+ it('inserts a snapshot record', async () => {
261
+ await recordPriceSnapshot(0.0042, 'jupiter-v3');
262
+ expect(chain.insert).toHaveBeenCalled();
263
+ expect(chain.values).toHaveBeenCalledWith(expect.objectContaining({
264
+ priceUsd: '0.0042',
265
+ source: 'jupiter-v3',
266
+ }));
267
+ });
268
+ });
269
+ describe('recordPayment', () => {
270
+ beforeEach(() => {
271
+ vi.clearAllMocks();
272
+ chain.insert = vi.fn(() => chain);
273
+ chain.values = vi.fn(() => Promise.resolve());
274
+ });
275
+ it('inserts a payment record with all fields', async () => {
276
+ await recordPayment({
277
+ txSignature: 'tx-sig-123',
278
+ walletAddress: 'wallet-abc',
279
+ userId: 'user-1',
280
+ amountRvui: '1000000000',
281
+ amountUsd: 4.2,
282
+ discountUsd: 0.63,
283
+ purpose: 'subscription',
284
+ });
285
+ expect(chain.insert).toHaveBeenCalled();
286
+ expect(chain.values).toHaveBeenCalledWith(expect.objectContaining({
287
+ txSignature: 'tx-sig-123',
288
+ walletAddress: 'wallet-abc',
289
+ userId: 'user-1',
290
+ amountRvui: '1000000000',
291
+ amountUsd: '4.2',
292
+ discountUsd: '0.63',
293
+ purpose: 'subscription',
294
+ status: 'verified',
295
+ }));
296
+ });
297
+ });
298
+ // ---------------------------------------------------------------------------
299
+ // TWAP — Extended Scenarios
300
+ // ---------------------------------------------------------------------------
301
+ describe('getTwapPrice — extended', () => {
302
+ beforeEach(() => {
303
+ vi.clearAllMocks();
304
+ chain.select = vi.fn(() => chain);
305
+ chain.from = vi.fn(() => chain);
306
+ chain.where = vi.fn(() => chain);
307
+ chain.orderBy = vi.fn(() => chain);
308
+ chain.limit = vi.fn(() => chain);
309
+ });
310
+ it('calculates TWAP correctly with many snapshots (simulated 1-hour polling)', async () => {
311
+ const now = Date.now();
312
+ // 60 snapshots over 1 hour — price ramps from 0.004 to 0.006
313
+ const snapshots = Array.from({ length: 60 }, (_, i) => ({
314
+ priceUsd: String(0.004 + (i / 59) * 0.002),
315
+ recordedAt: new Date(now - (59 - i) * 60_000),
316
+ }));
317
+ queryResult = snapshots;
318
+ chain.then = vi.fn((resolve) => resolve(queryResult));
319
+ const result = await getTwapPrice();
320
+ expect(result).not.toBeNull();
321
+ // Linear ramp: TWAP should be close to midpoint (0.005)
322
+ expect(result).toBeCloseTo(0.005, 3);
323
+ });
324
+ it('handles price spike correctly (weights by duration)', async () => {
325
+ const now = Date.now();
326
+ // Price is stable at 0.005, then spikes to 0.050 for the last minute
327
+ queryResult = [
328
+ { priceUsd: '0.005', recordedAt: new Date(now - 600_000) }, // t=-10min
329
+ { priceUsd: '0.005', recordedAt: new Date(now - 300_000) }, // t=-5min
330
+ { priceUsd: '0.005', recordedAt: new Date(now - 60_000) }, // t=-1min
331
+ { priceUsd: '0.050', recordedAt: new Date(now) }, // spike at end
332
+ ];
333
+ chain.then = vi.fn((resolve) => resolve(queryResult));
334
+ const result = await getTwapPrice();
335
+ expect(result).not.toBeNull();
336
+ // 0.005 * 300s + 0.005 * 240s + 0.005 * 60s = 0.005 * 600s / 600s = 0.005
337
+ // The spike at the end is the LAST snapshot, so it's not weighted
338
+ expect(result).toBeCloseTo(0.005, 6);
339
+ });
340
+ it('handles uniform price (all snapshots same value)', async () => {
341
+ const now = Date.now();
342
+ queryResult = [
343
+ { priceUsd: '0.010', recordedAt: new Date(now - 180_000) },
344
+ { priceUsd: '0.010', recordedAt: new Date(now - 120_000) },
345
+ { priceUsd: '0.010', recordedAt: new Date(now - 60_000) },
346
+ { priceUsd: '0.010', recordedAt: new Date(now) },
347
+ ];
348
+ chain.then = vi.fn((resolve) => resolve(queryResult));
349
+ const result = await getTwapPrice();
350
+ expect(result).toBe(0.010);
351
+ });
352
+ });
353
+ // ---------------------------------------------------------------------------
354
+ // isPriceCircuitBreakerOpen
355
+ // ---------------------------------------------------------------------------
356
+ describe('isPriceCircuitBreakerOpen', () => {
357
+ // This function makes 2 DB calls:
358
+ // 1. db.select().from().orderBy().limit(1) — latest snapshot
359
+ // 2. getTwapPrice() — db.select().from().where().orderBy() — all snapshots in window
360
+ //
361
+ // We need to return different data for each call. We do this by making
362
+ // chain.then return different values on sequential calls.
363
+ beforeEach(() => {
364
+ vi.clearAllMocks();
365
+ resetSafeguardsConfig();
366
+ chain.select = vi.fn(() => chain);
367
+ chain.from = vi.fn(() => chain);
368
+ chain.where = vi.fn(() => chain);
369
+ chain.orderBy = vi.fn(() => chain);
370
+ chain.limit = vi.fn(() => chain);
371
+ });
372
+ it('returns true when no price data exists', async () => {
373
+ queryResult = [];
374
+ chain.then = vi.fn((resolve) => resolve(queryResult));
375
+ const result = await isPriceCircuitBreakerOpen();
376
+ expect(result).toBe(true);
377
+ });
378
+ it('returns true when TWAP is unavailable (only 1 snapshot)', async () => {
379
+ const now = Date.now();
380
+ const snapshot = { priceUsd: '0.005', recordedAt: new Date(now) };
381
+ // First call: latest snapshot → returns [snapshot]
382
+ // Second call: TWAP query → returns [snapshot] (only 1 = insufficient)
383
+ let callCount = 0;
384
+ chain.then = vi.fn((resolve) => {
385
+ callCount++;
386
+ if (callCount === 1)
387
+ resolve([snapshot]); // latest
388
+ else
389
+ resolve([snapshot]); // TWAP — 1 snapshot, returns null
390
+ });
391
+ const result = await isPriceCircuitBreakerOpen();
392
+ expect(result).toBe(true);
393
+ });
394
+ it('returns false when price is stable', async () => {
395
+ const now = Date.now();
396
+ const latest = { priceUsd: '0.005', recordedAt: new Date(now) };
397
+ const snapshots = [
398
+ { priceUsd: '0.005', recordedAt: new Date(now - 120_000) },
399
+ { priceUsd: '0.005', recordedAt: new Date(now - 60_000) },
400
+ { priceUsd: '0.005', recordedAt: new Date(now) },
401
+ ];
402
+ let callCount = 0;
403
+ chain.then = vi.fn((resolve) => {
404
+ callCount++;
405
+ if (callCount === 1)
406
+ resolve([latest]);
407
+ else
408
+ resolve(snapshots);
409
+ });
410
+ const result = await isPriceCircuitBreakerOpen();
411
+ expect(result).toBe(false);
412
+ });
413
+ it('returns true when price drops 30% or more below TWAP', async () => {
414
+ const now = Date.now();
415
+ // TWAP is 0.010, latest price is 0.006 → 40% drop → circuit breaker open
416
+ const latest = { priceUsd: '0.006', recordedAt: new Date(now) };
417
+ const snapshots = [
418
+ { priceUsd: '0.010', recordedAt: new Date(now - 120_000) },
419
+ { priceUsd: '0.010', recordedAt: new Date(now - 60_000) },
420
+ { priceUsd: '0.006', recordedAt: new Date(now) },
421
+ ];
422
+ let callCount = 0;
423
+ chain.then = vi.fn((resolve) => {
424
+ callCount++;
425
+ if (callCount === 1)
426
+ resolve([latest]);
427
+ else
428
+ resolve(snapshots);
429
+ });
430
+ const result = await isPriceCircuitBreakerOpen();
431
+ expect(result).toBe(true);
432
+ });
433
+ it('returns false when price drop is under threshold', async () => {
434
+ const now = Date.now();
435
+ // TWAP is 0.010, latest is 0.008 → 20% drop → under 30% threshold
436
+ const latest = { priceUsd: '0.008', recordedAt: new Date(now) };
437
+ const snapshots = [
438
+ { priceUsd: '0.010', recordedAt: new Date(now - 120_000) },
439
+ { priceUsd: '0.010', recordedAt: new Date(now - 60_000) },
440
+ { priceUsd: '0.008', recordedAt: new Date(now) },
441
+ ];
442
+ let callCount = 0;
443
+ chain.then = vi.fn((resolve) => {
444
+ callCount++;
445
+ if (callCount === 1)
446
+ resolve([latest]);
447
+ else
448
+ resolve(snapshots);
449
+ });
450
+ const result = await isPriceCircuitBreakerOpen();
451
+ expect(result).toBe(false);
452
+ });
453
+ });
454
+ // ---------------------------------------------------------------------------
455
+ // validatePayment (composite safeguard check)
456
+ // ---------------------------------------------------------------------------
457
+ describe('validatePayment', () => {
458
+ const baseParams = {
459
+ walletAddress: 'wallet-abc',
460
+ userId: 'user-1',
461
+ txSignature: 'unique-tx-sig',
462
+ amountUsd: 100,
463
+ };
464
+ beforeEach(() => {
465
+ vi.clearAllMocks();
466
+ resetSafeguardsConfig();
467
+ chain.select = vi.fn(() => chain);
468
+ chain.from = vi.fn(() => chain);
469
+ chain.where = vi.fn(() => chain);
470
+ chain.orderBy = vi.fn(() => chain);
471
+ chain.limit = vi.fn(() => chain);
472
+ });
473
+ it('rejects duplicate transactions first', async () => {
474
+ // isDuplicateTransaction → [{ id: 'existing' }] → true
475
+ queryResult = [{ id: 'existing' }];
476
+ chain.then = vi.fn((resolve) => resolve(queryResult));
477
+ const result = await validatePayment(baseParams);
478
+ expect(result.allowed).toBe(false);
479
+ expect(result.reason).toContain('already used');
480
+ });
481
+ it('rejects when payment exceeds maximum', async () => {
482
+ // isDuplicateTransaction → [] → false
483
+ // isPriceCircuitBreakerOpen → needs data (we'll return stable price)
484
+ // isPaymentOverMaximum → amountUsd > 500
485
+ let callCount = 0;
486
+ chain.then = vi.fn((resolve) => {
487
+ callCount++;
488
+ if (callCount === 1)
489
+ resolve([]); // duplicate check: not duplicate
490
+ else if (callCount === 2)
491
+ resolve([]); // circuit breaker: no data → open
492
+ // Circuit breaker returns true (no data) → but validatePayment checks
493
+ // it after duplicate, so this will fail on circuit breaker first
494
+ else
495
+ resolve([]);
496
+ });
497
+ // Since circuit breaker will be open (no price data), let's test with
498
+ // enough price data to pass the circuit breaker, then a high amount
499
+ const now = Date.now();
500
+ const stableSnapshots = [
501
+ { priceUsd: '0.01', recordedAt: new Date(now - 120_000) },
502
+ { priceUsd: '0.01', recordedAt: new Date(now - 60_000) },
503
+ { priceUsd: '0.01', recordedAt: new Date(now) },
504
+ ];
505
+ callCount = 0;
506
+ chain.then = vi.fn((resolve) => {
507
+ callCount++;
508
+ if (callCount === 1)
509
+ resolve([]); // duplicate: not found
510
+ if (callCount === 2)
511
+ resolve([stableSnapshots[2]]); // latest snapshot
512
+ if (callCount === 3)
513
+ resolve(stableSnapshots); // TWAP snapshots
514
+ if (callCount === 4)
515
+ resolve([{ count: 0 }]); // rate limit
516
+ if (callCount === 5)
517
+ resolve([{ total: 0 }]); // discount cap
518
+ });
519
+ const result = await validatePayment({ ...baseParams, amountUsd: 501 });
520
+ expect(result.allowed).toBe(false);
521
+ expect(result.reason).toContain('exceeds maximum');
522
+ });
523
+ it('rejects when wallet is rate limited', async () => {
524
+ const now = Date.now();
525
+ const stableSnapshots = [
526
+ { priceUsd: '0.01', recordedAt: new Date(now - 120_000) },
527
+ { priceUsd: '0.01', recordedAt: new Date(now - 60_000) },
528
+ { priceUsd: '0.01', recordedAt: new Date(now) },
529
+ ];
530
+ let callCount = 0;
531
+ chain.then = vi.fn((resolve) => {
532
+ callCount++;
533
+ if (callCount === 1)
534
+ resolve([]); // duplicate: not found
535
+ if (callCount === 2)
536
+ resolve([stableSnapshots[2]]); // latest
537
+ if (callCount === 3)
538
+ resolve(stableSnapshots); // TWAP
539
+ if (callCount === 4)
540
+ resolve([{ count: 3 }]); // rate limited!
541
+ });
542
+ const result = await validatePayment(baseParams);
543
+ expect(result.allowed).toBe(false);
544
+ expect(result.reason).toContain('rate limit');
545
+ });
546
+ it('allows valid payment when all checks pass', async () => {
547
+ const now = Date.now();
548
+ const stableSnapshots = [
549
+ { priceUsd: '0.01', recordedAt: new Date(now - 120_000) },
550
+ { priceUsd: '0.01', recordedAt: new Date(now - 60_000) },
551
+ { priceUsd: '0.01', recordedAt: new Date(now) },
552
+ ];
553
+ let callCount = 0;
554
+ chain.then = vi.fn((resolve) => {
555
+ callCount++;
556
+ if (callCount === 1)
557
+ resolve([]); // duplicate: not found
558
+ if (callCount === 2)
559
+ resolve([stableSnapshots[2]]); // latest
560
+ if (callCount === 3)
561
+ resolve(stableSnapshots); // TWAP
562
+ if (callCount === 4)
563
+ resolve([{ count: 0 }]); // rate limit: under
564
+ if (callCount === 5)
565
+ resolve([{ total: 0 }]); // discount cap: under
566
+ });
567
+ const result = await validatePayment(baseParams);
568
+ expect(result.allowed).toBe(true);
569
+ });
570
+ });
571
+ //# sourceMappingURL=safeguards.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safeguards.test.js","sourceRoot":"","sources":["../../../src/revealcoin/__tests__/safeguards.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * RevealCoin RPC Client
3
+ *
4
+ * Provides balance queries and payment verification for RevealCoin (RVUI)
5
+ * on the Solana blockchain. Uses circuit breaker + retry pattern mirroring
6
+ * the Stripe client in packages/services/src/stripe/stripeClient.ts.
7
+ */
8
+ import { DbCircuitBreaker } from '../stripe/db-circuit-breaker.js';
9
+ export interface RvuiBalance {
10
+ /** Raw token amount (with decimals). */
11
+ raw: bigint;
12
+ /** Human-readable balance (e.g., "1,234.56"). */
13
+ formatted: string;
14
+ /** Balance as a plain number (may lose precision for very large amounts). */
15
+ uiAmount: number;
16
+ }
17
+ /**
18
+ * Get the RVUI balance for a wallet address.
19
+ *
20
+ * Queries the Token-2022 Associated Token Account for the RVUI mint.
21
+ * Returns zero balance if the ATA does not exist (wallet has never held RVUI).
22
+ */
23
+ export declare function getRvuiBalance(walletAddress: string): Promise<RvuiBalance>;
24
+ /**
25
+ * Verify an RVUI payment transaction on-chain.
26
+ *
27
+ * Confirms that a Solana transaction contains a Token-2022 transfer of
28
+ * the correct amount to the expected recipient for the RVUI mint.
29
+ *
30
+ * Uses `finalized` commitment to prevent rollback exploits.
31
+ */
32
+ export declare function verifyRvuiPayment(txSignature: string, expectedAmountRaw: bigint, expectedRecipient: string): Promise<{
33
+ valid: true;
34
+ } | {
35
+ valid: false;
36
+ error: string;
37
+ }>;
38
+ export declare const __solanaCircuitBreaker: DbCircuitBreaker;
39
+ export declare const __CIRCUIT_BREAKER_CONFIG: {
40
+ failureThreshold: number;
41
+ resetTimeout: number;
42
+ successThreshold: number;
43
+ };
44
+ export declare const __RETRY_CONFIG: {
45
+ maxAttempts: number;
46
+ backoff: number[];
47
+ timeout: number;
48
+ };
49
+ export declare const __resetCircuitBreaker: () => Promise<void>;
50
+ export declare const __resetConnection: () => void;
51
+ //# sourceMappingURL=client.d.ts.map