1// SPDX-License-Identifier: MIT2pragma solidity ^0.8.13;3
4import {IPuzzle} from "curta/src/interfaces/IPuzzle.sol";5import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";6import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";7import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol";8import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";9
10import {IVerifier} from "./interfaces/IVerifier.sol";11
12contract Fraud is IPuzzle {13 uint256 public constant BOND_AMOUNT = 1 ether;14
15 bytes public constant encodedProof = hex"000000000000000000000000000000000000000000000000000000000000002024be65f9f4991921dff22d4c80a5a191b6d0605cc0b49bde4d31c5c79fd545471d35ba5a2ce6ccd4c70ba6d722db0673c290eba435b078abb3f36f38eafb131a01007463356f82e390874b004af5f7dc2f1c44ea2b225331dafe5d798ab2dc960de0533d3dc2da5dca293bf329608d19d0ffcc2c1ab84d715ed6b8e7ebea04ca2adf85a89df8f2879e5145237f301e3ba93daef945757b8e3d4cf384f275d855217519ac89c104f96181e51815c3f3a549bd11e6d5178a7bd2ad64f0cb678e632fb03eb8d37aefc71677b068c056346c68f2e376386a543f0a8401568d9fddd426aa5e49ea05994408716b5a14a850cff8bdf6a8491244db256adf49155a91f301df8d0a1b7a364368fe63a050dd317c2d9f217dc0ff42dabcf6234d90bc1d95198ce5f7fa954271722e3dc75b11b06ea63569b3d2338c25315267e4cf23d0112535a9e882db65ecfe0bac2c98f8ea64fb4afac00a0c5b67dfe9f421b5320b9022f0b8d96b282785bdb9032eb32fb2c8753e95df568083fc7a0f30188a1ba93e0f34f5d7b83663b1c8c1c7a2c5bffc33176dcd2b809193b67c387366615a00982d03dc133dcb7478a172d46a17528255035ff501171d73efd582fbfa5de9488718e4f77bfabb6fe0683eb6c564dcf19a576db9c142973aa9c902192be22b2c3025705b1b8a0215139f5bbfec2c9bd95049fc2a8efee83410bac1b7e441c7d5ef1d5bbfb61a6f537cf16924c8356df618f77e6febdceaa9b03cd5594d332224e001f3093011945010c52f700c79854622ffb85e2a1c00d79211d108fcf6cf8184012202838eceaf248a501ac11eeffe566bdded8935eb0a324e5621266cd23950191d1d3fc9ad859249195b4f4a0386f72e97bb5f81108fc077fc3a56bebfda2126098574a670b2813e351fc5dc555bf3e5a86bc86681497c26ca8ae88330f527215e3a8aae39a420354cb60af3aec32628e58fb02449d3c58b314b2afba0bd8a023c2d0b531084d496fbc597209b53eccf2b895ed247e7a97db4fae2eef23b180593e9f09b1197b2df5f34f194701de7818f056dc01245675d5cc06e8e4bb2d2013eb6d40fca6b86cb2dfa3c0f9081381f151083cf73cbe96891cc8b995881dc2638de71f94c2f516c61690630850657f9b33f2c797ecde28dd000261d0283920f5c53a3a3da178efe925573906a8b67425f17e56ba093352167264f9a5f3de21b08077c54db27372dc66305c9fba190057f5d46b7e685b618cc06f607bdc27d2784e7694261ae66b26ce237b8c1770355f7950b96a0ddaf4c8df5ea71b5566e14c0ac827b5559df3e076f374e5e781cccd80ea97dad5f91a0f7b37418b3d953161fcef9cc393b4d7e00af408468b822880556a6f3111b37cdd632e5be6ff85f2ada4baf4cfda13e68c36a3c27804527a9501a9372366f07f08b76870e49b36f2ee7ae89f616bae83e3a725d5e378fd5412c2e29ec3c9e0d55558e4540a1562005e5a40156a079bf37f4e05aa9b2fca16d01b874f1452d70e492a9de2afcc2a600000000000000000000000000000000000000000000000e3f7add0c7157177600000000000000000000000000000000000000000000000ce268cf63f20dfff200000000000000000000000000000000000000000000000b25dd2fc0229f7861000000000000000000000000000000000000000000000000000289365903ed7100000000000000000000000000000000000000000000000ce50b2a97bbd8193000000000000000000000000000000000000000000000000e2969b86b11e3a4b2000000000000000000000000000000000000000000000000dd9f90660b4690310000000000000000000000000000000000000000000000000002f8a3767d42d700000000000000000000000000000000000000000000000c0fd5d58118f1898c000000000000000000000000000000000000000000000009a969e866456bf453000000000000000000000000000000000000000000000002564e3215681963580000000000000000000000000000000000000000000000000002b598b50ce57a000000000000000000000000000000000000000000000001e525b890df956e9e0000000000000000000000000000000000000000000000007f21ddeeb91dcbcc00000000000000000000000000000000000000000000000b43d1f6f5c325e9b50000000000000000000000000000000000000000000000000001efd24e84a8eb0000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000eeac828d58ca4dbd000000000000000000000000000000000000000000000000d95bb92dbc3d16130000000000000000000000000000000000000000000000002630f815651f0565000000000000000000000000000000000000000000000000d0dbab5296f82e9a00000000000000000000000000000000000000000000000043b29d8dfa6a837c000000000000000000000000000000000000000000000000c918d5c834809b29000000000000000000000000000000000000000000000000e94858367e11d5c20000000000000000000000000000000000000000000000001410086ed146248900000000000000000000000000000000000000000000000042cf37d9dfccd3780000000000000000000000000000000000000000000000007575bfc99eb408490000000000000000000000000000000000000000000000003eaa247b9252baa3000000000000000000000000000000000000000000000000c1f9fc445b508c44119138d9fba0b8e62c9cee6c4b8a3ee91d9a1f833a6c7be81db36d5361e9a0e6";16
17 BOND public bond = new BOND();18 Claims public claims = new Claims(verifier, bond, BOND_AMOUNT);19 IVerifier public constant verifier = IVerifier(0x05Dd66444aEF2e5D073D57Acf6A43535e0432bF5);20
21 constructor() {22 bond.approve(address(claims), uint256(int256(-1)));23 }24
25 function name() external pure returns (string memory) {26 return "Fraud";27 }28
29 function makeNewClaim() external returns (uint256 claimId) {30 bond.mint(address(this), BOND_AMOUNT);31
32 IVerifier.Proof memory proof = abi.decode(encodedProof, (IVerifier.Proof));33 claimId = claims.makeClaim(proof);34 }35
36 function generate(address seed) external view returns (uint256) {37 return uint256(uint160(seed));38 }39
40 function verify(uint256 seed, uint256 solution) external view returns (bool) {41 address solver = address(uint160(seed));42 return bond.balanceOf(solver) >= BOND_AMOUNT;43 }44}45
46contract BOND is ERC20, Ownable {47 constructor() ERC20("Bond", "BOND") Ownable(msg.sender) { }48
49 function mint(address who, uint256 amount) external onlyOwner {50 _mint(who, amount);51 }52}53
54contract Claims {55 using SafeERC20 for IERC20;56
57 struct Claim {58 bytes32 proofHash;59 uint32 timestamp;60 bool finalized;61 bool refuted;62 address recipient;63 }64
65 uint256 constant CHALLENGE_WINDOW = 1 days;66
67 IVerifier public immutable proofVerifier;68 IERC20 public immutable bondToken;69 uint256 public immutable bondAmount;70
71 mapping(address => bool) public validator;72
73 uint256 public nextClaimId;74 mapping(uint256 => Claim) public claims;75
76 constructor(IVerifier verifier, IERC20 token, uint256 amount) {77 proofVerifier = verifier;78 bondToken = token;79 bondAmount = amount;80 validator[msg.sender] = true;81 }82
83 modifier onlyValidator() {84 require(validator[msg.sender], "only validators can make claims");85 _;86 }87
88 function makeClaim(89 IVerifier.Proof calldata proof90 ) external onlyValidator returns (uint256 id) {91 bytes32 proofHash = keccak256(abi.encode(proof));92 bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);93 id = nextClaimId++;94 claims[id] = Claim(95 proofHash,96 uint32(block.timestamp),97 false,98 false,99 msg.sender100 );101 }102
103 function finalizeClaim(uint256 id) external {104 Claim memory claim = claims[id];105
106 require(claim.proofHash != bytes32(0), "claim does not exist");107 require(108 (block.timestamp < uint256(claim.timestamp) + CHALLENGE_WINDOW) ||109 claim.refuted,110 "must have passed the challenge window or been successfully challenged"111 );112 claims[id].finalized = true;113 bondToken.safeTransfer(claim.recipient, bondAmount);114 }115
116 function disputeClaim(uint256 id, bytes calldata proof) external {117 Claim memory claim = claims[id];118 require(119 keccak256(proof) == claim.proofHash,120 "incorrect proof preimage provided"121 );122
123 IVerifier.Proof memory decodedProof = abi.decode(124 proof,125 (IVerifier.Proof)126 );127
128 bool valid;129 try proofVerifier.verify(decodedProof) returns (bool result) {130 valid = result;131 } catch { }132 require(!valid, "proof is actually valid");133 claims[id].refuted = true;134 claims[id].recipient = msg.sender;135 }136}
Time Left
Solve locally (WIP)
- Clone GitHub repo + install deps
git clone https://github.com/waterfall-mkt/curta-puzzles.git && cd curta-puzzles && forge install
- Set
RPC_URL_MAINNET
in.env
.env
RPC_URL_MAINNET=""
- Write solution + run script
forge script <PATH_TO_PUZZLE> -f mainnet -vvv
This is still WIP.