Reproduced Exploit
g8keep migration reverts on a 1-wei swap and leaves 1,000,000 tokens in the old pool
When the pool sqrt price is below the target, migration swaps int256(uint256(1)). One wei moves the price from 100 to 101, not to 1000. adjustFailed stays true, migrate() reverts, and the 1,000,000 tokens never leave the old pool. Swapping the 900-point distance reaches 1000 and the user receives 1…
Chain
Other
Category
dos
Date
Dec 2024
Source
AuditVault
EVM Playground
Source-level debugger — step opcodes and Solidity in sync
The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.
Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 64998-h-01-migration-will-fail-trying-to-swap-1-wei-of-tokens-to-r. Standalone Foundry PoC and full write-up: 64998-h-01-migration-will-fail-trying-to-swap-1-wei-of-tokens-to-r_exp in the
evm-hack-registrymirror.
Vulnerability classes: vuln/dos/frozen-funds · vuln/logic/missing-check
Key info#
| Protocol | g8keep |
| Finding | Pashov H-01, AuditVault 64998 |
| Vulnerable code | Migrator._adjustPoolPrice |
| Harm | 1,000,000 old tokens stay in the old pool; the user receives 0 new tokens |
| Chain | local synthetic |
TL;DR#
When the pool sqrt price is below the target, migration swaps int256(uint256(1)). One wei moves the price from 100 to 101, not to 1000. adjustFailed stays true, migrate() reverts, and the 1,000,000 tokens never leave the old pool. Swapping the 900-point distance reaches 1000 and the user receives 1,000,000 new tokens.
The vulnerable code#
} else {
// @> VULN: 1 wei of the quote token cannot move sqrt price from 100 to the target 1000
IUniswapV3Pool(poolAddress).swap(address(this), false, int256(uint256(1)), sqrtPriceX96, "");
}
(uint160 sqrtPriceX96New,,,,,,) = IUniswapV3Pool(poolAddress).slot0();
adjustFailed = sqrtPriceX96 != sqrtPriceX96New;
The control passes the distance to the target, 900, and the pool writes the limit.
Root cause#
The else branch hardcodes a 1-wei specified amount. That amount cannot travel from sqrt price 100 to 1000, so the equality check against the target fails on every attempt and migration always reverts.
Preconditions#
The pool's starting sqrt price is below the target. The old pool holds 1,000,000 tokens. No privileged role is required to observe the failed migration.
Attack walkthrough#
- 1,000,000 old tokens are deposited in the old pool.
migrate()calls_adjustPoolPrice.- The else branch swaps 1 wei toward target 1000.
- The pool price becomes 101.
adjustFailedis true. migrate()reverts. The old pool still holds 1,000,000 and the user holds 0 new tokens.
Diagrams#
Impact#
The migration cannot complete. 1,000,000 tokens remain in the old pool and the user receives none of the new token. The control swap reaches sqrt price 1000, burns the old balance, and mints 1,000,000 new tokens to the user.
Remediation#
Swap the amount required to reach the target price, and compare the resulting price with a tolerance instead of exact equality.
How to reproduce#
cd 64998-h-01-migration-will-fail-trying-to-swap-1-wei-of-tokens-to-r_exp
forge test -vv
Sources#
- AuditVault finding: https://github.com/Auditware/AuditVault/blob/main/findings/64998-h-01-migration-will-fail-trying-to-swap-1-wei-of-tokens-to-r.md
- Pashov report: https://github.com/pashov/audits/blob/master/team/md/g8keep-security-review_2024-12-12.md
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 64998-h-01-migration-will-fail-trying-to-swap-1-wei-of-tokens-to-r_exp (evm-hack-registry mirror).
- AuditVault finding: 64998-h-01-migration-will-fail-trying-to-swap-1-wei-of-tokens-to-r.
Alerts & third-party analyses
These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.