[
  {
    "path": ".github/workflows/test.yml",
    "content": "name: test\n\non: workflow_dispatch\n\nenv:\n  FOUNDRY_PROFILE: ci\n\njobs:\n  check:\n    strategy:\n      fail-fast: true\n\n    name: Foundry project\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n        with:\n          submodules: recursive\n\n      - name: Install Foundry\n        uses: foundry-rs/foundry-toolchain@v1\n        with:\n          version: nightly\n\n      - name: Run Forge build\n        run: |\n          forge --version\n          forge build --sizes\n        id: build\n\n      - name: Run Forge tests\n        run: |\n          forge test -vvv\n        id: test\n"
  },
  {
    "path": ".gitignore",
    "content": "# Compiler files\ncache/\nout/\n\n# Ignores development broadcast logs\n/broadcast\n\n# Docs\ndocs/\n\n# Dotenv file\n.env\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"lib/forge-std\"]\n\tpath = lib/forge-std\n\turl = https://github.com/foundry-rs/forge-std\n[submodule \"lib/openzeppelin-contracts\"]\n\tpath = lib/openzeppelin-contracts\n\turl = https://github.com/openzeppelin/openzeppelin-contracts\n"
  },
  {
    "path": "README.md",
    "content": "# Whitehacks Kit\n\nA simple template to perform whitehacks safely in a single tx, leveraging Foundry and Flashbots.\n\n## Disclaimer\n\nProvided AS-IS as educational content only, disclaim any liability for using it.\n\n## Usage\n\nWhitehacks are hard and should be execute by professionals. If you are unsure reach-out the [Seal 911 Bot](https://t.me/seal_911_bot). Reach-out anyway.\n\nThis repo offers a guide to prepare them.\n\nThey must be executed in 1 shot and privately, hence one single transaction and the private mempool by Flashbots.\n\nYou prepare, you test in a fork, you don't change, you execute.\n\n## Setup\n\n0. Fork the repo\n1. [Install Foundry](https://book.getfoundry.sh/getting-started/installation)\n2. Edit [Whitehack.sol](./src/Whitehack.sol)\n3. Adapt [Whitehack.s.sol](./script/Whitehack.s.sol) \n\n## Preparation\n\n1. Unset `$ETH_RPC_URL`\n\n```zsh\nunset $ETH_RPC_URL\n```\n\n2. Check no RPC port open on your computer, if so kill the processes\n\n```zsh\nnetstat -an | grep LISTEN | grep 8545\n```\n\n## Test\n\n1. Run Anvil fork with \n\n```zsh\nanvil --fork-url https://eth.llamarpc.com\n```\n\n2. Impersonate your account `0xYOUR_WALLET_ADDRESS` \n\n```zsh\ncast rpc \\\n    anvil_impersonateAccount \"0xYOUR_WALLET_ADDRESS\" \\\n    --rpc-url \"http://localhost:8545\"\n```\n\n3. Run the script\n\n```zsh\nforge script \\\n  script/Whitehack.s.sol:WhitehackScript \\\n  --rpc-url \"http://localhost:8545\" \\\n  --sender \"0xYOUR_WALLET_ADDRESS\" \\\n  -vvv \\\n  --broadcast\n```\n\n## Run\n\nDo not change your script and contract after the test\n\n```zsh\nforge script \\\n  script/Whitehack.s.sol:WhitehackScript \\\n  --rpc-url \"https://rpc.flashbots.net?hint=hash\" \\\n  --sender \"0xYOUR_WALLET_ADDRESS\" \\\n  --interactives 1 \\\n  -vvv \\\n  --broadcast\n```\n\nThe rpc url is set for [Full Privacy](https://docs.flashbots.net/flashbots-protect/rpc/mev-share#full-privacy) on Flashbots\n\n## Examples\n\n- [Curve 30/07/23](https://github.com/emilianobonassi/curve-whitehack-example)\n"
  },
  {
    "path": "foundry.toml",
    "content": "[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\"]\n\n# See more config options https://github.com/foundry-rs/foundry/tree/master/config\n"
  },
  {
    "path": "remappings.txt",
    "content": "@openzeppelin/=lib/openzeppelin-contracts/\n"
  },
  {
    "path": "script/Whitehack.s.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport \"forge-std/Script.sol\";\nimport {Factory} from \"../src/Factory.sol\";\nimport {Whitehack} from \"../src/Whitehack.sol\";\n\ncontract WhitehackScript is Script {\n    function run() public {\n        vm.startBroadcast();\n        console.log(msg.sender, \"is running the script\");\n\n        // 0. Prepare the factory to deploy and execute in 1 go the whitehack\n        // Can be removed if the factory is already deployed\n        Factory factory = new Factory();\n        console.log(\"factory deployed at:\", address(factory));\n\n        // 1. Prepare the whitehack parameters\n        bytes memory params = abi.encode(\n            uint256(42) // put here your params\n        );\n        // Advanced\n        uint256 ethRequired = 0; // you should not need to send eth to the whitehack\n\n\n        // 2. Deploy and execute the whitehack\n        factory.deployAndExec{value: ethRequired}(\n            ethRequired, \n            bytes32('whitehack'), \n            type(Whitehack).creationCode, \n            abi.encodeWithSignature(\"go(bytes)\", params)\n        );\n\n        console.log(\"whitehack executed with success\");\n\n        vm.stopBroadcast();\n    }\n}"
  },
  {
    "path": "src/Factory.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {Create2} from \"@openzeppelin/contracts/utils/Create2.sol\";\n\ncontract Factory {\n    function deployAndExec(\n        uint256 amount,\n        bytes32 salt,\n        bytes calldata initcode,\n        bytes calldata data\n    ) public payable returns (address, bytes memory) {\n        address addr = Create2.deploy(amount, salt, initcode);\n\n        (bool success, bytes memory ret) = addr.call(data);\n        \n        require(success, \"execution failed\");\n\n        return (addr, ret);\n    }\n}\n"
  },
  {
    "path": "src/Whitehack.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\ncontract Whitehack {\n\n    constructor() payable {}\n\n    function go(bytes calldata params) external returns (bytes memory) {\n        // decode and use params\n        // uint256 param1 = abi.decode(params, (uint256));\n\n        return params;\n    }\n\n    fallback() external {}\n}"
  },
  {
    "path": "test/Factory.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {Test, console2} from \"forge-std/Test.sol\";\nimport {Factory} from \"../src/Factory.sol\";\nimport {Whitehack} from \"../src/Whitehack.sol\";\n\nimport {Create2} from \"@openzeppelin/contracts/utils/Create2.sol\";\n\ncontract FactoryTest is Test {\n    Factory public factory;\n\n    function setUp() public {\n        factory = new Factory();\n    }\n\n    function testDeployAndExecNoEth() public {\n        bytes memory initcode = type(Whitehack).creationCode;\n\n        bytes memory params = abi.encode(uint256(42));\n        bytes memory data = abi.encodeWithSignature(\"go(bytes)\", params);\n        bytes32 salt = bytes32('salt');\n\n        address expectedAddr = Create2.computeAddress(bytes32('salt'), keccak256(initcode), address(factory));\n\n        (address addr, bytes memory ret) = factory.deployAndExec{value: 0}(0, salt, initcode, data);\n        \n        assertEq(addr, expectedAddr);\n        assertEq(abi.decode(ret, (bytes)), params);\n    }\n\n    function testDeployAndExecEth() public {\n        bytes memory initcode = type(Whitehack).creationCode;\n\n        bytes memory params = abi.encode(uint256(42));\n        bytes memory data = abi.encodeWithSignature(\"go(bytes)\", params);\n        bytes32 salt = bytes32('salt');\n        uint256 ethBalance = 123;\n\n        address expectedAddr = Create2.computeAddress(bytes32('salt'), keccak256(initcode), address(factory));\n\n        (address addr, bytes memory ret) = factory.deployAndExec{value: ethBalance}(ethBalance, salt, initcode, data);\n        \n        assertEq(addr, expectedAddr);\n        assertEq(abi.decode(ret, (bytes)), params);\n        assertEq(addr.balance, ethBalance);\n    }\n}\n"
  }
]