GoldReserve · Breaks legitimate use

Claims always revert

Every claim reverts with the message the task treats as “exploit blocked”. Nobody can be paid.

Not solved

The exploit is blocked, but a legitimate-use obligation fails: “A holder from before a deposit can claim their share, exactly once”.

Exploitblockedhistorical attack
Security1 / 3obligations pass
Legitimate use8 / 9obligations pass
Canariesbrickedtamper and breakage flags
acceptsAn exploit-only check would accept this fix. The exploit really is blocked, which is what makes it look finished. The obligations are what reject 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 12 BNB
  • The DeFiHackLabs reproduction of the attack: blockedIt fails in the attack or profit step, for a reason the task declares.test/poc.t.sol:GoldReserve_PoC:testExploit()Nada a reclamar

Security obligations

1 / 3 pass
  • Holders are paid only for the NFTs they held when the profit accruedTwo holders with the same stake must be paid the same, however many NFTs one mints later.test/hidden/security.t.sol:GoldReserve_Security:test_a_holder_is_paid_only_for_the_nfts_it_held_when_profit_accrued()the entitled holder was paid nothing: this setup proves nothing: 0 <= 0
  • Moving paid NFTs to a fresh address cannot claim the same profit againThe step the incident repeated 22 times, restated without a flash loan.test/hidden/security.t.sol:GoldReserve_Security:test_moving_the_nfts_to_a_fresh_address_cannot_reclaim_the_same_profit()the entitled holder was paid nothing: this setup proves nothing: 0 <= 0
  • An NFT minted after a deposit earns nothing from that depositThe mint half of the bug: deposit first, mint second.test/hidden/security.t.sol:GoldReserve_Security:test_nft_minted_after_a_deposit_inherits_no_profit()

Legitimate use · behaviour

3 / 4 pass
  • Collection metadata is intactSymbol, name, mint price, supply, owner and token URI still read back.test/hidden/regression.t.sol:GoldReserve_Regression:test_metadata_preserved()
  • A holder from before a deposit can claim their share, exactly onceThe contract’s whole purpose.test/hidden/regression.t.sol:GoldReserve_Regression:test_mint_then_deposit_then_claim_pays_the_holder()Nada a reclamar
  • Minting at the listed price worksAnd updates the accounting.test/hidden/regression.t.sol:GoldReserve_Regression:test_mint_works()
  • An ordinary NFT transfer workstest/hidden/regression.t.sol:GoldReserve_Regression:test_nft_transfer_works()

Legitimate use · interface

5 / 5 pass
  • Original functions still answerCalls the original functions and requires an answer other than “no such function”.test/hidden/invariants_auto.t.sol:AutoInvariants:test_abi_selectors_dispatch()
  • Every original function is still in the dispatch tableWalks the patched bytecode and requires each original selector in the dispatcher.test/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 noAn impossible selector must be reported absent, or the check above proves nothing.test/hidden/invariants_auto.t.sol:AutoInvariants:test_selector_check_is_not_vacuous()
  • Guard: unknown calls are still rejectedWithout this, a catch-all fallback would make the dispatch probe meaningless.test/hidden/invariants_auto.t.sol:AutoInvariants:test_unknown_selector_is_rejected()

The patch

against the original source
src/contracts/Token.sol+1 −0
@@ -3924,6 +3924,7 @@39243924    }3925392539263926    function claimProfit() external nonReentrant {3927+        revert("Nada a reclamar");   // VARIANT39273928        uint256 userBalance = _balanceOfAllNFTs(msg.sender);39283929        require(userBalance > 0, "Voce nao possui NFTs");39293930

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/goldreserve_2025_02 \
    --patch worked_example/goldreserve_2025_02/controls/recognised_reason__claim_always_reverts/Token.sol \
    --backend local --sha256

Expected output: core 8a555a54cc0ad7cf0c65990349eaff6650ef4c8befbb7f40faa4080013dc432d and strict 06144228f7a631522ddc903ab0eab9ff8584755ff8fbabdfa0bc05b317a8a485.

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

Control note

from the repository

RECOGNISED REASON IN THE WRONG PLACE: claimProfit() always reverts with 'Nada a reclamar', a string the task declares as 'exploit blocked'. Nobody can ever be paid, which is what the contract exists for, so the legitimate-use regression rejects it.