Skip to content

Instantly share code, notes, and snippets.

@Wollac
Created April 12, 2024 19:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Wollac/b0f0188a7ae8d6219e0565ee5006f428 to your computer and use it in GitHub Desktop.
Save Wollac/b0f0188a7ae8d6219e0565ee5006f428 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.25+commit.b61c2a91.js&optimize=false&runs=200&gist=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract ProofMarketFIFO is ReentrancyGuard {
Proof public emptyProof;
uint256 public constant MIN_REQUEST_VALUE = 0.00001 ether;
address constant STARK_VERIFIER = address(0x51);
/// @notice Special public claims about a zkVM guest execution.
/// @dev This is essentially a ReceiptClaim of an Halted execution with no addiional assumptions.
struct Assertion {
/// @notice Digest of the SystemState just before execution has begun.
bytes32 preState;
/// @notice Digest of the SystemState just after execution has completed.
bytes32 postState;
/// @notice A digest of the input to the guest.
bytes32 input;
/// @notice Digest of the journal committed to by the guest execution.
bytes32 journal;
}
/// @notice Result of an execution proof creation.
/// @dev The actiual receipt is not stored on chain.
struct Proof {
Assertion assertion;
string receiptURI;
}
struct ProofRequest {
bytes32 imageID;
string programURI;
string inputURI;
uint256 reward;
bytes32[] merkleProof;
}
mapping(uint256 => ProofRequest) private requests; // Maps request IDs to proof requests
mapping(uint256 => Proof) private proofs; // Maps request IDs to proofs
mapping(bytes32 => address) private merkleRoots; // Maps merkle roots to L2 addresses for reward claims
uint256 private requestCount;
event RequestProcessed(uint256 indexed requestID, uint256 reward);
event RequestProven(uint256 indexed requestID, Assertion assertion);
event RequestAggregated(uint256 indexed requestID, bytes32[] merkleProof);
constructor() {
requestCount = 0;
}
function submitRequest(
bytes32 imageID,
string calldata programURI,
string calldata inputURI
) external payable {
require(msg.value >= MIN_REQUEST_VALUE, "Insufficient payment to submit request");
uint256 newRequestID = requestCount++;
requests[newRequestID] = ProofRequest({
imageID: imageID,
programURI: programURI,
inputURI: inputURI,
reward: msg.value,
merkleProof: new bytes32[](0)
});
emit RequestProcessed(newRequestID, msg.value);
}
function submitProof(
uint256 requestID,
bytes32 pre,
bytes32 post,
bytes32 journal,
string calldata receiptURI
) external nonReentrant {
require(requestID < requestCount, "Invalid request ID");
ProofRequest storage request = requests[requestID];
require(request.reward > 0, "Request already proven");
require(verify(request.imageID, receiptURI), "Proof verification failed");
Assertion memory assertion = Assertion(pre, post, bytes32(0), journal);
proofs[requestID] = Proof(assertion, receiptURI);
uint256 payment = request.reward;
request.reward = 0;
payable(msg.sender).transfer(payment);
emit RequestProven(requestID, assertion);
}
function submitMerkleRoot(bytes32 root, address aggregator) external {
require(merkleRoots[root] == address(0), "Merkle root allready present");
merkleRoots[root] = aggregator;
}
function submitMerkleProof(uint256 requestID, bytes32[] calldata proof) external {
require(requestID < requestCount, "Invalid request ID");
require(requests[requestID].merkleProof.length == 0, "Merkle proof allready present");
require(bytes(proofs[requestID].receiptURI).length > 0, "Request not proven");
bytes32 hash = hashAssertion(proofs[requestID].assertion);
for (uint256 i = 0; i < proof.length; i++) {
hash = hashPair(proof[i], hash);
}
require(merkleRoots[hash] == msg.sender, "Invalid Merkle root");
requests[requestID].merkleProof = proof;
emit RequestAggregated(requestID, proof);
}
function hashAssertion(Assertion memory a) internal pure returns (bytes32) {
return sha256(abi.encodePacked("Leaf", a.preState, a.postState, a.input, a.journal));
}
function hashPair(bytes32 a, bytes32 b) internal pure returns (bytes32) {
return a < b ? sha256(abi.encodePacked(a, b)) : sha256(abi.encodePacked(b, a));
}
function verify(bytes32 imageID, string memory receiptURI) internal view returns (bool) {
(bool success, bytes memory result) = STARK_VERIFIER.staticcall(abi.encodePacked(imageID, receiptURI));
require(success, "Verification call failed");
return abi.decode(result, (bool));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment