A custom overflow guard with the wrong threshold. checked_shlw was supposed to reject any value that would overflow when shifted left by 64 bits — that limit is 1 << 192. The code compared against 0xffffffffffffffff << 192 instead: a bound roughly 2⁶⁴ times too high. Everything in that gap sailed through the "safe" branch and silently truncated. In Move, << does not abort on overflow. The attacker opened a position credited with astronomic liquidity while depositing 1 unit of token A.
// ❌ vulnerable public fun checked_shlw(n: u256): (u256, bool) { let mask = 0xffffffffffffffff << 192; // ≈ 2^256 − 2^192 if (n > mask) { (0, true) // "overflow" } else { ((n << 64), false) // silently truncates } } // ✅ fixed public fun checked_shlw(n: u256): (u256, bool) { let mask = 1 << 192; // the real overflow boundary if (n >= mask) { (0, true) } else { ((n << 64), false) } } // get_delta_a() uses this to price how much token A a position must deposit. // Truncated numerator → required deposit rounds down to 1. → result: near-infinite liquidity minted for ~1 unit of token A
1<<192 versus 0xffff…<<192 is invisible on a read-through and obvious the moment you fuzz it.Entries in the SAFE database that describe this failure. These share its failure class.
Every figure on this page comes from the post-mortems above, not from us. Losses are US dollars at the time of the incident.
Arithmetic is one of the 203 classes the SaferICO scanner checks for. It will not review your signing process — but it will read your Solidity.