An adversarial posting set of two MaxInt64 legs plus one of 2 wraps to
zero in int64 arithmetic, so the balance check passed and the ledger
minted 18 quintillion millisatoshis from nothing. The sum is now
accumulated in big.Int, per-account balance arithmetic is checked for
wraparound, and the audit totals parse through big.Int so a corrupt
ledger reports a clear error rather than failing to scan.
Adds room package tests (0% -> covered) and ledger edge cases.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Round length is now bounded: the multiplier follows a hyperbolic curve
diverging at 60s, replacing an exponential one where a 275x crash point
produced a two-and-a-half minute round.
Fixes seed reveal, which silently failed every round because pgx cannot
encode a fixed-size byte array as bytea.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Scratch odds tables are derived from the same tier list that generates
outcomes, so the published odds cannot drift from reality. Tests assert
observed frequencies and empirical RTP against the published figures;
the initial prize tables claimed 98% but actually paid 56%.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Lightning bridge is modelled as the boundary with the outside
world and is the one account permitted to go negative; its negative
balance is exactly what is owed to players inside the system. All
other accounts are floored at zero by both the application and a
database trigger.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Seed expansion uses SplitMix64 so all 32 seed bytes affect the stream;
copying the seed directly into xoshiro state left the first draw
dependent only on bytes 8-15.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>