// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; contract SimpleToken { mapping(address => uint256) public balanceOf; constructor(address to, uint256 amt) { balanceOf[to] = amt; } function transferFrom(address f, address t, uint256 a) external { require(balanceOf[f] >= a); balanceOf[f] -= a; balanceOf[t] += a; } } contract MegaAirdrop { address public signer; SimpleToken public token; mapping(bytes => bool) public usedSigs; bool public solved; address public solver; bytes32 private flag; constructor(address _signer, bytes32 _flag) { signer = _signer; token = new SimpleToken(address(this), 10_000 ether); flag = _flag; } function claim(address recipient, uint256 amount, bytes memory sig) external { require(!usedSigs[sig], "Used!"); bytes32 h = keccak256(abi.encodePacked( "\x19Ethereum Signed Message:\n32", keccak256(abi.encodePacked(recipient, amount)) )); require(_recover(h, sig) == signer, "Bad sig"); usedSigs[sig] = true; token.transferFrom(address(this), recipient, amount); if (token.balanceOf(recipient) >= 200 ether && !solved) { solved = true; solver = tx.origin; } } function isSolved() external view returns (bool) { return solved; } function getFlag() external view returns (string memory) { require(solved, "Solve the challenge first to get the flag!"); return string(abi.encodePacked(flag)); } function _recover(bytes32 h, bytes memory sig) internal pure returns (address) { bytes32 r; bytes32 s; uint8 v; assembly { r := mload(add(sig, 32)) s := mload(add(sig, 64)) v := byte(0, mload(add(sig, 96))) } if (v < 27) v += 27; return ecrecover(h, v, r, s); } }