@omnitronix/lucky-sharky-game-engine 1.1.0 → 1.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.
Files changed (77) hide show
  1. package/README.md +10 -0
  2. package/dist/__tests__/base-game.test.d.ts +2 -0
  3. package/dist/__tests__/base-game.test.d.ts.map +1 -0
  4. package/dist/__tests__/base-game.test.js +262 -0
  5. package/dist/__tests__/base-game.test.js.map +1 -0
  6. package/dist/__tests__/bonus-handlers.test.d.ts +2 -0
  7. package/dist/__tests__/bonus-handlers.test.d.ts.map +1 -0
  8. package/dist/__tests__/bonus-handlers.test.js +243 -0
  9. package/dist/__tests__/bonus-handlers.test.js.map +1 -0
  10. package/dist/__tests__/error-paths.test.d.ts +2 -0
  11. package/dist/__tests__/error-paths.test.d.ts.map +1 -0
  12. package/dist/__tests__/error-paths.test.js +328 -0
  13. package/dist/__tests__/error-paths.test.js.map +1 -0
  14. package/dist/__tests__/free-spins-handler.test.d.ts +2 -0
  15. package/dist/__tests__/free-spins-handler.test.d.ts.map +1 -0
  16. package/dist/__tests__/free-spins-handler.test.js +410 -0
  17. package/dist/__tests__/free-spins-handler.test.js.map +1 -0
  18. package/dist/__tests__/helpers/test-engine-factory.d.ts +98 -0
  19. package/dist/__tests__/helpers/test-engine-factory.d.ts.map +1 -0
  20. package/dist/__tests__/helpers/test-engine-factory.js +236 -0
  21. package/dist/__tests__/helpers/test-engine-factory.js.map +1 -0
  22. package/dist/__tests__/hold-win-handler.test.d.ts +2 -0
  23. package/dist/__tests__/hold-win-handler.test.d.ts.map +1 -0
  24. package/dist/__tests__/hold-win-handler.test.js +481 -0
  25. package/dist/__tests__/hold-win-handler.test.js.map +1 -0
  26. package/dist/__tests__/rng-gli19-compliance.test.d.ts +0 -4
  27. package/dist/__tests__/rng-gli19-compliance.test.d.ts.map +1 -1
  28. package/dist/__tests__/rng-gli19-compliance.test.js +232 -198
  29. package/dist/__tests__/rng-gli19-compliance.test.js.map +1 -1
  30. package/dist/__tests__/rng-security.test.d.ts +2 -0
  31. package/dist/__tests__/rng-security.test.d.ts.map +1 -0
  32. package/dist/__tests__/rng-security.test.js +379 -0
  33. package/dist/__tests__/rng-security.test.js.map +1 -0
  34. package/dist/__tests__/rtp-diagnostic.test.d.ts +6 -0
  35. package/dist/__tests__/rtp-diagnostic.test.d.ts.map +1 -0
  36. package/dist/__tests__/rtp-diagnostic.test.js +216 -0
  37. package/dist/__tests__/rtp-diagnostic.test.js.map +1 -0
  38. package/dist/__tests__/rtp-simulation.test.d.ts +0 -4
  39. package/dist/__tests__/rtp-simulation.test.d.ts.map +1 -1
  40. package/dist/__tests__/rtp-simulation.test.js +228 -153
  41. package/dist/__tests__/rtp-simulation.test.js.map +1 -1
  42. package/dist/__tests__/spin-generator.test.d.ts +2 -0
  43. package/dist/__tests__/spin-generator.test.d.ts.map +1 -0
  44. package/dist/__tests__/spin-generator.test.js +375 -0
  45. package/dist/__tests__/spin-generator.test.js.map +1 -0
  46. package/dist/__tests__/state-transitions.test.d.ts +2 -0
  47. package/dist/__tests__/state-transitions.test.d.ts.map +1 -0
  48. package/dist/__tests__/state-transitions.test.js +249 -0
  49. package/dist/__tests__/state-transitions.test.js.map +1 -0
  50. package/dist/__tests__/symbol-distribution.test.d.ts +2 -0
  51. package/dist/__tests__/symbol-distribution.test.d.ts.map +1 -0
  52. package/dist/__tests__/symbol-distribution.test.js +210 -0
  53. package/dist/__tests__/symbol-distribution.test.js.map +1 -0
  54. package/dist/__tests__/win-calculator.test.d.ts +2 -0
  55. package/dist/__tests__/win-calculator.test.d.ts.map +1 -0
  56. package/dist/__tests__/win-calculator.test.js +516 -0
  57. package/dist/__tests__/win-calculator.test.js.map +1 -0
  58. package/dist/config/game-logic-config/game-logic-config.d.ts.map +1 -1
  59. package/dist/config/game-logic-config/game-logic-config.js +27 -17
  60. package/dist/config/game-logic-config/game-logic-config.js.map +1 -1
  61. package/dist/logic/handlers/free-spins.handler.d.ts +2 -0
  62. package/dist/logic/handlers/free-spins.handler.d.ts.map +1 -1
  63. package/dist/logic/handlers/free-spins.handler.js +74 -6
  64. package/dist/logic/handlers/free-spins.handler.js.map +1 -1
  65. package/package.json +4 -2
  66. package/dist/__tests__/rng-seed-security.test.d.ts +0 -6
  67. package/dist/__tests__/rng-seed-security.test.d.ts.map +0 -1
  68. package/dist/__tests__/rng-seed-security.test.js +0 -263
  69. package/dist/__tests__/rng-seed-security.test.js.map +0 -1
  70. package/dist/__tests__/rng-seed-type.test.d.ts +0 -16
  71. package/dist/__tests__/rng-seed-type.test.d.ts.map +0 -1
  72. package/dist/__tests__/rng-seed-type.test.js +0 -288
  73. package/dist/__tests__/rng-seed-type.test.js.map +0 -1
  74. package/dist/__tests__/rng-stress-boundary.test.d.ts +0 -5
  75. package/dist/__tests__/rng-stress-boundary.test.d.ts.map +0 -1
  76. package/dist/__tests__/rng-stress-boundary.test.js +0 -395
  77. package/dist/__tests__/rng-stress-boundary.test.js.map +0 -1
@@ -0,0 +1,379 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * RNG Security Tests — Lucky Sharky
5
+ *
6
+ * Tests attack surface hardening for the RNG system:
7
+ * - Seed injection attacks
8
+ * - Type confusion
9
+ * - Integer overflow/underflow
10
+ * - Replay attack prevention
11
+ * - RNG isolation between commands
12
+ */
13
+ const test_engine_factory_1 = require("./helpers/test-engine-factory");
14
+ describe('RNG Security — Lucky Sharky', () => {
15
+ beforeEach(() => {
16
+ (0, test_engine_factory_1.resetCommandIdCounter)();
17
+ });
18
+ describe('Seed Injection Attacks', () => {
19
+ it('should handle undefined seed gracefully', async () => {
20
+ const engine = (0, test_engine_factory_1.createEngine)();
21
+ const session = await (0, test_engine_factory_1.initSession)(engine);
22
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
23
+ expect(result.success).toBe(true);
24
+ });
25
+ it('should handle null state gracefully for INIT', async () => {
26
+ const engine = (0, test_engine_factory_1.createEngine)();
27
+ await (0, test_engine_factory_1.waitForEngineReady)(engine);
28
+ const result = await engine.processCommand(null, null, {
29
+ id: (0, test_engine_factory_1.nextCommandId)('init'),
30
+ type: 'INIT_SESSION_STATE',
31
+ payload: { betAmountThresholds: [1.0], defaultBetAmount: 1.0 },
32
+ });
33
+ expect(result.success).toBe(true);
34
+ expect(result.publicState).toBeDefined();
35
+ expect(result.privateState).toBeDefined();
36
+ // Validate structure: publicState and privateState should be objects
37
+ expect(typeof result.publicState).toBe('object');
38
+ expect(typeof result.privateState).toBe('object');
39
+ });
40
+ it('should reject spin with missing public state', async () => {
41
+ const engine = (0, test_engine_factory_1.createEngine)();
42
+ const session = await (0, test_engine_factory_1.initSession)(engine);
43
+ try {
44
+ await (0, test_engine_factory_1.executeSpin)(engine, null, session.privateState);
45
+ // If it doesn't throw, that's also acceptable
46
+ }
47
+ catch (error) {
48
+ expect(error).toBeInstanceOf(Error);
49
+ expect(error.message).toBeDefined();
50
+ }
51
+ });
52
+ it('should reject spin with missing private state', async () => {
53
+ const engine = (0, test_engine_factory_1.createEngine)();
54
+ const session = await (0, test_engine_factory_1.initSession)(engine);
55
+ try {
56
+ await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, null);
57
+ // If it doesn't throw, that's also acceptable
58
+ }
59
+ catch (error) {
60
+ expect(error).toBeInstanceOf(Error);
61
+ expect(error.message).toBeDefined();
62
+ }
63
+ });
64
+ });
65
+ describe('Type Confusion', () => {
66
+ it('should handle string bet amount', async () => {
67
+ const engine = (0, test_engine_factory_1.createEngine)();
68
+ const session = await (0, test_engine_factory_1.initSession)(engine);
69
+ const result = await engine.processCommand(session.publicState, session.privateState, {
70
+ id: (0, test_engine_factory_1.nextCommandId)('spin'),
71
+ type: 'SPIN',
72
+ payload: {
73
+ sessionId: 'test',
74
+ betAmount: '1.0',
75
+ creditsPerLine: 1,
76
+ gameId: 'lucky-sharky',
77
+ gameVersion: '1.0.0',
78
+ },
79
+ });
80
+ // Should either succeed with coercion or fail gracefully
81
+ expect(result).toBeDefined();
82
+ });
83
+ it('should handle negative bet amount', async () => {
84
+ const engine = (0, test_engine_factory_1.createEngine)();
85
+ const session = await (0, test_engine_factory_1.initSession)(engine);
86
+ try {
87
+ const result = await engine.processCommand(session.publicState, session.privateState, {
88
+ id: (0, test_engine_factory_1.nextCommandId)('spin'),
89
+ type: 'SPIN',
90
+ payload: {
91
+ sessionId: 'test',
92
+ betAmount: -1.0,
93
+ creditsPerLine: 1,
94
+ gameId: 'lucky-sharky',
95
+ gameVersion: '1.0.0',
96
+ },
97
+ });
98
+ // If no exception, verify it doesn't produce negative wins
99
+ if (result.success && result.outcome) {
100
+ expect(result.outcome.totalWin).toBeGreaterThanOrEqual(0);
101
+ }
102
+ }
103
+ catch (error) {
104
+ expect(error).toBeInstanceOf(Error);
105
+ expect(error.message).toBeDefined();
106
+ }
107
+ });
108
+ it('should handle zero bet amount', async () => {
109
+ const engine = (0, test_engine_factory_1.createEngine)();
110
+ const session = await (0, test_engine_factory_1.initSession)(engine);
111
+ try {
112
+ const result = await engine.processCommand(session.publicState, session.privateState, {
113
+ id: (0, test_engine_factory_1.nextCommandId)('spin'),
114
+ type: 'SPIN',
115
+ payload: {
116
+ sessionId: 'test',
117
+ betAmount: 0,
118
+ creditsPerLine: 1,
119
+ gameId: 'lucky-sharky',
120
+ gameVersion: '1.0.0',
121
+ },
122
+ });
123
+ // If no exception, result should have valid structure
124
+ expect(typeof result).toBe('object');
125
+ expect(typeof result.success).toBe('boolean');
126
+ }
127
+ catch (error) {
128
+ expect(error).toBeInstanceOf(Error);
129
+ expect(error.message).toBeDefined();
130
+ }
131
+ });
132
+ it('should handle NaN bet amount', async () => {
133
+ const engine = (0, test_engine_factory_1.createEngine)();
134
+ const session = await (0, test_engine_factory_1.initSession)(engine);
135
+ try {
136
+ const result = await engine.processCommand(session.publicState, session.privateState, {
137
+ id: (0, test_engine_factory_1.nextCommandId)('spin'),
138
+ type: 'SPIN',
139
+ payload: {
140
+ sessionId: 'test',
141
+ betAmount: NaN,
142
+ creditsPerLine: 1,
143
+ gameId: 'lucky-sharky',
144
+ gameVersion: '1.0.0',
145
+ },
146
+ });
147
+ // If no exception, result should have valid structure
148
+ expect(typeof result).toBe('object');
149
+ expect(typeof result.success).toBe('boolean');
150
+ }
151
+ catch (error) {
152
+ expect(error).toBeInstanceOf(Error);
153
+ expect(error.message).toBeDefined();
154
+ }
155
+ });
156
+ it('should handle Infinity bet amount', async () => {
157
+ const engine = (0, test_engine_factory_1.createEngine)();
158
+ const session = await (0, test_engine_factory_1.initSession)(engine);
159
+ try {
160
+ const result = await engine.processCommand(session.publicState, session.privateState, {
161
+ id: (0, test_engine_factory_1.nextCommandId)('spin'),
162
+ type: 'SPIN',
163
+ payload: {
164
+ sessionId: 'test',
165
+ betAmount: Infinity,
166
+ creditsPerLine: 1,
167
+ gameId: 'lucky-sharky',
168
+ gameVersion: '1.0.0',
169
+ },
170
+ });
171
+ // If no exception, result should have valid structure
172
+ expect(typeof result).toBe('object');
173
+ expect(typeof result.success).toBe('boolean');
174
+ }
175
+ catch (error) {
176
+ expect(error).toBeInstanceOf(Error);
177
+ expect(error.message).toBeDefined();
178
+ }
179
+ });
180
+ });
181
+ describe('Integer Overflow/Underflow', () => {
182
+ it('should handle MAX_SAFE_INTEGER in RNG sequence', async () => {
183
+ const { engine } = (0, test_engine_factory_1.createEngineWithMockRng)([Number.MAX_SAFE_INTEGER]);
184
+ const session = await (0, test_engine_factory_1.initSession)(engine);
185
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
186
+ // Should handle gracefully - values clamped to range
187
+ expect(result.success).toBe(true);
188
+ const validation = (0, test_engine_factory_1.validateRngOutcome)(result.rngOutcome);
189
+ expect(validation.valid).toBe(true);
190
+ });
191
+ it('should handle negative values in RNG sequence', async () => {
192
+ const { engine } = (0, test_engine_factory_1.createEngineWithMockRng)([-1, -100, -999]);
193
+ const session = await (0, test_engine_factory_1.initSession)(engine);
194
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
195
+ expect(result.success).toBe(true);
196
+ // Results should be within valid bounds
197
+ for (const [, record] of Object.entries(result.rngOutcome || {})) {
198
+ const rec = record;
199
+ expect(rec.result).toBeGreaterThanOrEqual(rec.min);
200
+ expect(rec.result).toBeLessThanOrEqual(rec.max);
201
+ }
202
+ });
203
+ it('should handle zero values in RNG sequence', async () => {
204
+ const { engine } = (0, test_engine_factory_1.createEngineWithMockRng)([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
205
+ const session = await (0, test_engine_factory_1.initSession)(engine);
206
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
207
+ expect(result.success).toBe(true);
208
+ });
209
+ it('should handle large values in RNG sequence', async () => {
210
+ const { engine } = (0, test_engine_factory_1.createEngineWithMockRng)([999999, 888888, 777777]);
211
+ const session = await (0, test_engine_factory_1.initSession)(engine);
212
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
213
+ expect(result.success).toBe(true);
214
+ for (const [, record] of Object.entries(result.rngOutcome || {})) {
215
+ const rec = record;
216
+ expect(rec.result).toBeGreaterThanOrEqual(rec.min);
217
+ expect(rec.result).toBeLessThanOrEqual(rec.max);
218
+ }
219
+ });
220
+ });
221
+ describe('Prototype Pollution Defense', () => {
222
+ it('should not be affected by Object.prototype pollution', async () => {
223
+ const engine = (0, test_engine_factory_1.createEngine)();
224
+ const session = await (0, test_engine_factory_1.initSession)(engine);
225
+ // Attempt prototype pollution on state
226
+ const pollutedState = (0, test_engine_factory_1.cloneState)(session.privateState);
227
+ pollutedState.__proto__ = { malicious: true };
228
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, pollutedState);
229
+ expect(result.success).toBe(true);
230
+ });
231
+ it('should handle extra properties on state without issues', async () => {
232
+ const engine = (0, test_engine_factory_1.createEngine)();
233
+ const session = await (0, test_engine_factory_1.initSession)(engine);
234
+ const modifiedState = { ...session.privateState, extraProp: 'malicious', hack: true };
235
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, modifiedState);
236
+ expect(result.success).toBe(true);
237
+ });
238
+ });
239
+ describe('Replay Attack Prevention', () => {
240
+ it('should produce different RNG outcomes for different command IDs', async () => {
241
+ const engine = (0, test_engine_factory_1.createEngine)();
242
+ const session = await (0, test_engine_factory_1.initSession)(engine);
243
+ const result1 = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
244
+ const result2 = await (0, test_engine_factory_1.executeSpin)(engine, result1.publicState, result1.privateState);
245
+ // Different commands should have different RNG outcomes
246
+ expect(result1.rngOutcome).not.toEqual(result2.rngOutcome);
247
+ });
248
+ it('should not allow state replay to get same outcome', async () => {
249
+ const engine = (0, test_engine_factory_1.createEngine)();
250
+ const session = await (0, test_engine_factory_1.initSession)(engine);
251
+ // Execute spin and save state before
252
+ const stateBefore = (0, test_engine_factory_1.cloneState)(session);
253
+ const result1 = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
254
+ // Try to replay with same state (DummyRngClient uses Math.random so results will differ)
255
+ const result2 = await (0, test_engine_factory_1.executeSpin)(engine, stateBefore.publicState, stateBefore.privateState);
256
+ // With non-deterministic RNG, replaying same state should give different outcomes
257
+ // (unless mock is used, which is intentional for testing)
258
+ expect(result1).toBeDefined();
259
+ expect(result2).toBeDefined();
260
+ });
261
+ });
262
+ describe('RNG Isolation Between Commands', () => {
263
+ it('should not leak RNG state between init and spin', async () => {
264
+ const engine = (0, test_engine_factory_1.createEngine)();
265
+ const session = await (0, test_engine_factory_1.initSession)(engine);
266
+ // The spin's RNG should be independent of init's RNG
267
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
268
+ expect(result.success).toBe(true);
269
+ // RNG outcome should only contain actions from this spin
270
+ const actionIds = Object.keys(result.rngOutcome || {});
271
+ for (const id of actionIds) {
272
+ expect(id).not.toContain('init');
273
+ }
274
+ });
275
+ it('should isolate RNG between consecutive spins', async () => {
276
+ const engine = (0, test_engine_factory_1.createEngine)();
277
+ const session = await (0, test_engine_factory_1.initSession)(engine);
278
+ const result1 = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
279
+ const result2 = await (0, test_engine_factory_1.executeSpin)(engine, result1.publicState, result1.privateState);
280
+ // Each spin should produce its own independent RNG outcome
281
+ expect(result1.rngOutcome).toBeDefined();
282
+ expect(result2.rngOutcome).toBeDefined();
283
+ // Validate structure: both must have at least 3 RNG calls
284
+ expect(Object.keys(result1.rngOutcome || {}).length).toBeGreaterThanOrEqual(3);
285
+ expect(Object.keys(result2.rngOutcome || {}).length).toBeGreaterThanOrEqual(3);
286
+ // Outcomes should differ (different random values even if action IDs repeat)
287
+ expect(result1.rngOutcome).not.toEqual(result2.rngOutcome);
288
+ });
289
+ });
290
+ describe('Command Type Validation', () => {
291
+ it('should reject unknown command types', async () => {
292
+ const engine = (0, test_engine_factory_1.createEngine)();
293
+ const session = await (0, test_engine_factory_1.initSession)(engine);
294
+ try {
295
+ const result = await engine.processCommand(session.publicState, session.privateState, {
296
+ id: (0, test_engine_factory_1.nextCommandId)('unknown'),
297
+ type: 'UNKNOWN_COMMAND',
298
+ payload: {},
299
+ });
300
+ // Should either fail or return error
301
+ expect(result.success).toBe(false);
302
+ }
303
+ catch (error) {
304
+ expect(error).toBeInstanceOf(Error);
305
+ expect(error.message).toBeDefined();
306
+ }
307
+ });
308
+ it('should reject empty command type', async () => {
309
+ const engine = (0, test_engine_factory_1.createEngine)();
310
+ const session = await (0, test_engine_factory_1.initSession)(engine);
311
+ try {
312
+ const result = await engine.processCommand(session.publicState, session.privateState, {
313
+ id: (0, test_engine_factory_1.nextCommandId)('empty'),
314
+ type: '',
315
+ payload: {},
316
+ });
317
+ expect(result.success).toBe(false);
318
+ }
319
+ catch (error) {
320
+ expect(error).toBeInstanceOf(Error);
321
+ expect(error.message).toBeDefined();
322
+ }
323
+ });
324
+ it('should handle missing command ID gracefully', async () => {
325
+ const engine = (0, test_engine_factory_1.createEngine)();
326
+ const session = await (0, test_engine_factory_1.initSession)(engine);
327
+ try {
328
+ const result = await engine.processCommand(session.publicState, session.privateState, {
329
+ id: '',
330
+ type: 'SPIN',
331
+ payload: {
332
+ sessionId: 'test',
333
+ betAmount: 1.0,
334
+ creditsPerLine: 1,
335
+ gameId: 'lucky-sharky',
336
+ gameVersion: '1.0.0',
337
+ },
338
+ });
339
+ // If no exception, result should have valid structure
340
+ expect(typeof result).toBe('object');
341
+ expect(typeof result.success).toBe('boolean');
342
+ }
343
+ catch (error) {
344
+ expect(error).toBeInstanceOf(Error);
345
+ expect(error.message).toBeDefined();
346
+ }
347
+ });
348
+ });
349
+ describe('State Integrity', () => {
350
+ it('should not mutate input public state', async () => {
351
+ const engine = (0, test_engine_factory_1.createEngine)();
352
+ const session = await (0, test_engine_factory_1.initSession)(engine);
353
+ const originalPublic = (0, test_engine_factory_1.cloneState)(session.publicState);
354
+ await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
355
+ expect((0, test_engine_factory_1.statesEqual)(session.publicState, originalPublic)).toBe(true);
356
+ });
357
+ it('should not mutate input private state', async () => {
358
+ const engine = (0, test_engine_factory_1.createEngine)();
359
+ const session = await (0, test_engine_factory_1.initSession)(engine);
360
+ const originalPrivate = (0, test_engine_factory_1.cloneState)(session.privateState);
361
+ await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
362
+ expect((0, test_engine_factory_1.statesEqual)(session.privateState, originalPrivate)).toBe(true);
363
+ });
364
+ it('should return valid state after each spin', async () => {
365
+ const engine = (0, test_engine_factory_1.createEngine)();
366
+ const session = await (0, test_engine_factory_1.initSession)(engine);
367
+ const results = await (0, test_engine_factory_1.executeSpins)(engine, session.publicState, session.privateState, 5);
368
+ for (const result of results) {
369
+ expect(result.success).toBe(true);
370
+ expect(result.publicState).toBeDefined();
371
+ expect(result.privateState).toBeDefined();
372
+ // Validate structure: states should be objects
373
+ expect(typeof result.publicState).toBe('object');
374
+ expect(typeof result.privateState).toBe('object');
375
+ }
376
+ });
377
+ });
378
+ });
379
+ //# sourceMappingURL=rng-security.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rng-security.test.js","sourceRoot":"","sources":["../../src/__tests__/rng-security.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * RTP Diagnostic Test - Detailed breakdown for Lucky Sharky
3
+ * This test provides granular data to identify RTP discrepancies
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=rtp-diagnostic.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rtp-diagnostic.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/rtp-diagnostic.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,216 @@
1
+ "use strict";
2
+ /**
3
+ * RTP Diagnostic Test - Detailed breakdown for Lucky Sharky
4
+ * This test provides granular data to identify RTP discrepancies
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const lucky_sharky_v1_game_engine_1 = require("../lucky-sharky-v1.game-engine");
8
+ const waitForPreload = (ms) => new Promise(resolve => setTimeout(resolve, ms));
9
+ describe('Lucky Sharky RTP Diagnostics', () => {
10
+ const NUM_SPINS = 100000; // 100k spins (increase for more accuracy)
11
+ const BET_AMOUNT = 20;
12
+ const BET_STAKE = 1; // betAmount / 20
13
+ let engine;
14
+ beforeAll(async () => {
15
+ engine = new lucky_sharky_v1_game_engine_1.LuckySharkyV1GameEngine();
16
+ await waitForPreload(500);
17
+ });
18
+ async function spin(publicState, privateState) {
19
+ return engine.processCommand(publicState, privateState, {
20
+ id: `spin-${Math.random().toString(36).slice(2)}`,
21
+ type: 'SPIN',
22
+ payload: {
23
+ sessionId: 'rtp-diag',
24
+ betAmount: BET_AMOUNT,
25
+ creditsPerLine: 20,
26
+ gameId: 'lucky-sharky',
27
+ gameVersion: '1.0.0',
28
+ },
29
+ });
30
+ }
31
+ async function startBonusRound(publicState, privateState) {
32
+ const pendingBonus = privateState.pendingBonuses?.[0];
33
+ if (!pendingBonus)
34
+ throw new Error('No pending bonus');
35
+ return engine.processCommand(publicState, privateState, {
36
+ id: `bonus-${Math.random().toString(36).slice(2)}`,
37
+ type: 'START_BONUS_ROUND',
38
+ payload: {
39
+ sessionId: 'rtp-diag',
40
+ betAmount: pendingBonus.betAmount || BET_AMOUNT,
41
+ bonusId: pendingBonus.bonusId,
42
+ bonusType: pendingBonus.bonusType,
43
+ gameCode: 'lucky-sharky',
44
+ gameVersion: '1.0.0',
45
+ },
46
+ });
47
+ }
48
+ it('should provide detailed RTP breakdown', async () => {
49
+ const initResult = await engine.processCommand(null, null, {
50
+ id: 'init',
51
+ type: 'INIT_SESSION_STATE',
52
+ payload: {
53
+ betAmountThresholds: [0.2, 1.0, 5.0, 10.0, 20.0],
54
+ defaultBetAmount: BET_AMOUNT,
55
+ },
56
+ });
57
+ let publicState = initResult.publicState;
58
+ let privateState = initResult.privateState;
59
+ // Detailed tracking
60
+ const stats = {
61
+ totalWagered: 0,
62
+ totalWon: 0,
63
+ // Paid spins
64
+ paidSpins: 0,
65
+ paidLineWins: 0,
66
+ paidCoinWins: 0,
67
+ paidScatterWins: 0,
68
+ // Free spins
69
+ freeSpinsTriggers: 0,
70
+ freeSpinsTotal: 0,
71
+ freeSpinLineWins: 0,
72
+ freeSpinCoinWins: 0,
73
+ freeSpinRetriggers: 0,
74
+ freeSpinRetriggerSpins: 0,
75
+ avgBoosterAtTrigger: 0,
76
+ boosterAtTriggerSum: 0,
77
+ // Hold-Win
78
+ holdWinTriggers: 0,
79
+ holdWinWins: 0,
80
+ };
81
+ console.log(`Running RTP diagnostics with ${NUM_SPINS.toLocaleString()} spins...`);
82
+ const startTime = Date.now();
83
+ for (let i = 0; i < NUM_SPINS; i++) {
84
+ stats.totalWagered += BET_AMOUNT;
85
+ stats.paidSpins++;
86
+ const spinResult = await spin(publicState, privateState);
87
+ if (!spinResult.success)
88
+ throw new Error(`Spin failed: ${spinResult.message}`);
89
+ const outcome = spinResult.outcome;
90
+ // Track paid spin wins
91
+ if (outcome?.result) {
92
+ const result = outcome.result;
93
+ // Line wins
94
+ if (result.winResult?.totalWin) {
95
+ stats.paidLineWins += result.winResult.totalWin;
96
+ stats.totalWon += result.winResult.totalWin;
97
+ }
98
+ // Coin wins
99
+ if (result.coinCollection?.finalWin) {
100
+ stats.paidCoinWins += result.coinCollection.finalWin;
101
+ stats.totalWon += result.coinCollection.finalWin;
102
+ }
103
+ // Scatter wins
104
+ if (result.scatterWin) {
105
+ stats.paidScatterWins += result.scatterWin;
106
+ stats.totalWon += result.scatterWin;
107
+ }
108
+ // Check for free spins trigger
109
+ if (result.triggeredBonus?.bonusType === 'FREE_SPINS') {
110
+ stats.freeSpinsTriggers++;
111
+ stats.boosterAtTriggerSum += publicState.boosterLevel || 0;
112
+ }
113
+ // Check for hold-win trigger
114
+ if (result.triggeredBonus?.bonusType === 'HOLD_WIN_BONUS') {
115
+ stats.holdWinTriggers++;
116
+ }
117
+ }
118
+ publicState = spinResult.publicState;
119
+ privateState = spinResult.privateState;
120
+ // Handle bonuses
121
+ while (privateState.pendingBonuses && privateState.pendingBonuses.length > 0) {
122
+ const bonusResult = await startBonusRound(publicState, privateState);
123
+ if (!bonusResult.success)
124
+ throw new Error(`Bonus failed`);
125
+ const bonusOutcome = bonusResult.outcome;
126
+ if (Array.isArray(bonusOutcome?.results)) {
127
+ const results = bonusOutcome.results;
128
+ const firstResult = results[0]?.result;
129
+ if (firstResult?.spinType === 'FREE_SPIN') {
130
+ stats.freeSpinsTotal += results.length;
131
+ for (const r of results) {
132
+ const res = r.result;
133
+ if (res?.winResult?.totalWin) {
134
+ stats.freeSpinLineWins += res.winResult.totalWin;
135
+ stats.totalWon += res.winResult.totalWin;
136
+ }
137
+ if (res?.coinCollection?.finalWin) {
138
+ stats.freeSpinCoinWins += res.coinCollection.finalWin;
139
+ stats.totalWon += res.coinCollection.finalWin;
140
+ }
141
+ if (res?.retrigger?.triggered) {
142
+ stats.freeSpinRetriggers++;
143
+ stats.freeSpinRetriggerSpins += res.retrigger.additionalSpins || 0;
144
+ }
145
+ }
146
+ }
147
+ else if (firstResult?.spinType === 'HOLD_WIN_BONUS_SPIN') {
148
+ for (const r of results) {
149
+ const res = r.result;
150
+ if (res?.playerWinning) {
151
+ stats.holdWinWins += res.playerWinning;
152
+ stats.totalWon += res.playerWinning;
153
+ }
154
+ }
155
+ }
156
+ }
157
+ publicState = bonusResult.publicState;
158
+ privateState = bonusResult.privateState;
159
+ }
160
+ if ((i + 1) % 10000 === 0) {
161
+ const rtp = (stats.totalWon / stats.totalWagered) * 100;
162
+ console.log(` Progress: ${((i + 1) / NUM_SPINS * 100).toFixed(0)}% - RTP: ${rtp.toFixed(2)}%`);
163
+ }
164
+ }
165
+ const elapsed = (Date.now() - startTime) / 1000;
166
+ // Calculate percentages
167
+ const paidLineRtp = (stats.paidLineWins / stats.totalWagered) * 100;
168
+ const paidCoinRtp = (stats.paidCoinWins / stats.totalWagered) * 100;
169
+ const paidScatterRtp = (stats.paidScatterWins / stats.totalWagered) * 100;
170
+ const paidTotalRtp = paidLineRtp + paidCoinRtp + paidScatterRtp;
171
+ const freeLineRtp = (stats.freeSpinLineWins / stats.totalWagered) * 100;
172
+ const freeCoinRtp = (stats.freeSpinCoinWins / stats.totalWagered) * 100;
173
+ const freeTotalRtp = freeLineRtp + freeCoinRtp;
174
+ const holdWinRtp = (stats.holdWinWins / stats.totalWagered) * 100;
175
+ const totalRtp = (stats.totalWon / stats.totalWagered) * 100;
176
+ const avgSpinsPerSeries = stats.freeSpinsTriggers > 0
177
+ ? stats.freeSpinsTotal / stats.freeSpinsTriggers
178
+ : 0;
179
+ const avgBooster = stats.freeSpinsTriggers > 0
180
+ ? stats.boosterAtTriggerSum / stats.freeSpinsTriggers
181
+ : 0;
182
+ console.log('\n========================================');
183
+ console.log(' RTP DIAGNOSTIC RESULTS');
184
+ console.log('========================================');
185
+ console.log(`\nTotal wagered: ${stats.totalWagered.toLocaleString()}`);
186
+ console.log(`Total won: ${stats.totalWon.toFixed(2)}`);
187
+ console.log(`Total RTP: ${totalRtp.toFixed(2)}% (target: 96.17%)`);
188
+ console.log('\n--- PAID SPINS (target: 63.64%) ---');
189
+ console.log(` Line wins: ${paidLineRtp.toFixed(2)}% (target: 37.29%)`);
190
+ console.log(` Coin wins: ${paidCoinRtp.toFixed(2)}% (target: 26.35%)`);
191
+ console.log(` Scatter wins: ${paidScatterRtp.toFixed(2)}%`);
192
+ console.log(` TOTAL: ${paidTotalRtp.toFixed(2)}%`);
193
+ console.log('\n--- FREE SPINS (target: 16.13%) ---');
194
+ console.log(` Triggers: ${stats.freeSpinsTriggers} (${(stats.freeSpinsTriggers / stats.paidSpins * 100).toFixed(3)}%)`);
195
+ console.log(` Total spins: ${stats.freeSpinsTotal}`);
196
+ console.log(` Avg per series: ${avgSpinsPerSeries.toFixed(1)}`);
197
+ console.log(` Retriggers: ${stats.freeSpinRetriggers} (+${stats.freeSpinRetriggerSpins} spins)`);
198
+ console.log(` Avg booster at trigger: ${avgBooster.toFixed(2)}`);
199
+ console.log(` Line wins: ${freeLineRtp.toFixed(2)}% (target: 11.76%)`);
200
+ console.log(` Coin wins: ${freeCoinRtp.toFixed(2)}% (target: 4.37%)`);
201
+ console.log(` TOTAL: ${freeTotalRtp.toFixed(2)}%`);
202
+ console.log('\n--- HOLD-WIN BONUS (target: 16.40%) ---');
203
+ console.log(` Triggers: ${stats.holdWinTriggers}`);
204
+ console.log(` TOTAL: ${holdWinRtp.toFixed(2)}%`);
205
+ console.log('\n--- DISCREPANCY ANALYSIS ---');
206
+ console.log(` Paid spins: ${(paidTotalRtp - 63.64).toFixed(2)}% (${paidTotalRtp > 63.64 ? 'HIGH' : 'LOW'})`);
207
+ console.log(` Free spins: ${(freeTotalRtp - 16.13).toFixed(2)}% (${freeTotalRtp > 16.13 ? 'HIGH' : 'LOW'})`);
208
+ console.log(` Hold-Win: ${(holdWinRtp - 16.40).toFixed(2)}% (${holdWinRtp > 16.40 ? 'HIGH' : 'LOW'})`);
209
+ console.log(` TOTAL GAP: ${(totalRtp - 96.17).toFixed(2)}%`);
210
+ console.log(`\nTime: ${elapsed.toFixed(1)}s`);
211
+ console.log('========================================\n');
212
+ // Pass if we got meaningful data
213
+ expect(stats.totalWon).toBeGreaterThan(0);
214
+ }, 600000);
215
+ });
216
+ //# sourceMappingURL=rtp-diagnostic.test.js.map