NGP · Missing evidence

Syntax error

The reference repair with a syntax error injected.

Inconclusive

The patched contract does not compile, so no test could run. A build failure is never read as a blocked exploit.

Exploitnot runhistorical attack
Securitynot run
Legitimate usenot run
Canariesnonetamper and breakage flags
no resultNothing ran: the contract does not compile. No check, exploit-only or otherwise, can credit it.
The checks

What ran, and what it said.

Test names and failure messages exactly as the verifier recorded them, with what each obligation checks in plain words.

Exploit

1 replay · profit over 100,000 USDT
  • The DeFiHackLabs reproduction of the attack: not runThe contract did not compile.test/poc.t.sol:NGP_PoC:testExploit()

Security obligations

not run
  • A direct transfer to the pool moves nothing out of ittest/hidden/security.t.sol:NGP_Security:test_direct_transfer_to_the_pair_moves_nothing_out_of_it()
  • An ordinary sell moves no tokens out of the pooltest/hidden/security.t.sol:NGP_Security:test_ordinary_sell_moves_no_tokens_out_of_the_pair()
  • The pool keeps every token a sell sends ittest/hidden/security.t.sol:NGP_Security:test_pair_keeps_every_token_an_ordinary_sell_sends_it()
  • Treasury and reward fees are not paid out of the pooltest/hidden/security.t.sol:NGP_Security:test_treasury_and_reward_are_not_funded_out_of_the_pair()

Legitimate use · behaviour

not run
  • A buy-then-sell round trip through the pool workstest/hidden/amm_regression.t.sol:NGP_AmmRegression:test_amm_buy_then_sell_round_trip()
  • Trading stays switched ontest/hidden/amm_regression.t.sol:NGP_AmmRegression:test_trading_flags_still_open()
  • Token metadata and the pool’s balance are intacttest/hidden/regression.t.sol:NGP_Regression:test_metadata_preserved()
  • A wallet-to-wallet transfer workstest/hidden/regression.t.sol:NGP_Regression:test_normal_transfer_works()
  • The price view still workstest/hidden/regression.t.sol:NGP_Regression:test_price_view_works()

Legitimate use · interface

not run
  • Original functions still answertest/hidden/invariants_auto.t.sol:AutoInvariants:test_abi_selectors_dispatch()
  • Every original function is still in the dispatch tabletest/hidden/invariants_auto.t.sol:AutoInvariants:test_abi_selectors_preserved()
  • The patched contract has codetest/hidden/invariants_auto.t.sol:AutoInvariants:test_contract_has_code()
  • Guard: the selector check can say notest/hidden/invariants_auto.t.sol:AutoInvariants:test_selector_check_is_not_vacuous()
  • Guard: unknown calls are still rejectedtest/hidden/invariants_auto.t.sol:AutoInvariants:test_unknown_selector_is_rejected()

The patch

against the original source
src/contracts/Token.sol+5 −8
@@ -246,6 +246,7 @@246246        }247247    }248248249+    this line is not solidity;249250    function _update(250251        address from,251252        address to,@@ -291,14 +292,10 @@291292            uint256 treasuryAmount = (value * treasuryRate) / RATIO_PRECISION;292293            uint256 rewardAmount = (value * rewardRate) / RATIO_PRECISION;293294            uint256 burnPoolAmount = treasuryAmount + rewardAmount;294            uint poolAmount = this.balanceOf(mainPair);295            if (poolAmount > burnPoolAmount) {296                // treasury pool297                super._update(mainPair, treasuryAddress, treasuryAmount);298                // reward pool299                super._update(mainPair, rewardPoolAddress, rewardAmount);300                IUniswapV2Pair(mainPair).sync();301            }295+            // PATCH: removed mid-transfer pool draining + sync() that let a seller296+            // re-price reserves within their own sell. Fees are taken from the seller,297+            // not silently pulled out of the pair, so the AMM invariant is preserved.298+            treasuryAmount; rewardAmount; burnPoolAmount; // retained for event below302299            value = value - totalFee;303300            emit FlowIntoPool(304301                from,

Re-run this grade

offline · same inputs

Needs Foundry 1.7.1 with solc 0.8.30, 0.8.26 and 0.8.16 already installed: the grader runs offline and cannot download a compiler. Python 3.12 or later. Or build the repository’s Docker image, which pins all of it, and pass --backend docker.

Terminal
$ git clone https://github.com/FarseenSh/evmpatch-env.git && cd evmpatch-env
$ git checkout 165c0ed
$ python -m evmpatch_env.sandbox tasks/ngp_2025_09 \
    --patch worked_example/ngp_2025_09/controls/compile_failed/Token.sol \
    --backend local --sha256

Expected output: core 965db891ebb4e150e800679a5786581a120336d36fbf14bf93434718e8f71bd2 and strict 8b98f9fbbaadcb3645b1e0279380fda7ec38a6308661cb56df56f63c34590bf6.

To check a downloaded grade file instead: shasum -a 256 grade.strict.json prints the strict hash.

Control note

from the repository

The reference repair with a syntax error injected. An infrastructure fault must never be credited as a block and must never score 1.0.