@revealui/services 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/handlers/subscription-handlers.d.ts +5 -1
- package/dist/api/handlers/subscription-handlers.d.ts.map +1 -1
- package/dist/api/handlers/subscription-handlers.js +5 -1
- package/dist/api/handlers/subscription-handlers.js.map +1 -1
- package/dist/api/webhooks/index.d.ts +10 -0
- package/dist/api/webhooks/index.d.ts.map +1 -1
- package/dist/api/webhooks/index.js +10 -0
- package/dist/api/webhooks/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/revealcoin/__tests__/client.test.d.ts +2 -0
- package/dist/revealcoin/__tests__/client.test.d.ts.map +1 -0
- package/dist/revealcoin/__tests__/client.test.js +207 -0
- package/dist/revealcoin/__tests__/client.test.js.map +1 -0
- package/dist/revealcoin/__tests__/config.test.d.ts +2 -0
- package/dist/revealcoin/__tests__/config.test.d.ts.map +1 -0
- package/dist/revealcoin/__tests__/config.test.js +91 -0
- package/dist/revealcoin/__tests__/config.test.js.map +1 -0
- package/dist/revealcoin/__tests__/oracle.test.d.ts +2 -0
- package/dist/revealcoin/__tests__/oracle.test.d.ts.map +1 -0
- package/dist/revealcoin/__tests__/oracle.test.js +238 -0
- package/dist/revealcoin/__tests__/oracle.test.js.map +1 -0
- package/dist/revealcoin/__tests__/safeguards.test.d.ts +2 -0
- package/dist/revealcoin/__tests__/safeguards.test.d.ts.map +1 -0
- package/dist/revealcoin/__tests__/safeguards.test.js +571 -0
- package/dist/revealcoin/__tests__/safeguards.test.js.map +1 -0
- package/dist/revealcoin/client.d.ts +51 -0
- package/dist/revealcoin/client.d.ts.map +1 -0
- package/dist/revealcoin/client.js +211 -0
- package/dist/revealcoin/client.js.map +1 -0
- package/dist/revealcoin/config.d.ts +32 -0
- package/dist/revealcoin/config.d.ts.map +1 -0
- package/dist/revealcoin/config.js +54 -0
- package/dist/revealcoin/config.js.map +1 -0
- package/dist/revealcoin/index.d.ts +5 -0
- package/dist/revealcoin/index.d.ts.map +1 -0
- package/dist/revealcoin/index.js +5 -0
- package/dist/revealcoin/index.js.map +1 -0
- package/dist/revealcoin/oracle.d.ts +81 -0
- package/dist/revealcoin/oracle.d.ts.map +1 -0
- package/dist/revealcoin/oracle.js +211 -0
- package/dist/revealcoin/oracle.js.map +1 -0
- package/dist/revealcoin/safeguards.d.ts +92 -0
- package/dist/revealcoin/safeguards.d.ts.map +1 -0
- package/dist/revealcoin/safeguards.js +240 -0
- package/dist/revealcoin/safeguards.js.map +1 -0
- 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
|