```solidity= // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; import {ERC1155BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol"; import {ERC1155PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {TokenUtils} from "./libraries/TokenUtils.sol"; import {IVerifier} from "./interfaces/IVerifier.sol"; import {CommitProtocolBase} from "./CommitProtocolBase.sol"; contract CommitProtocol is CommitProtocolBase { event Created(uint256 commitId, Commit config); event Funded( uint256 commitId, address funder, address token, uint256 amount ); event Joined(uint256 commitId, address participant); event Verified(uint256 commitId, address participant, bool isVerified); event Claimed( uint256 commitId, address participant, address token, uint256 amount ); event Withdraw(address recipient, address token, uint256 amount); struct Commit { address owner; // Commit details string metadataURI; // { title, image, description, tags } - Use a standard NFT format // Commit period uint256 joinBefore; uint256 verifyBefore; uint256 maxParticipants; // (Optional) Limit how many participants can join (this just sets the ERC721 supply) // Verifiers Verifier joinVerifier; Verifier fulfillVerifier; // Stake address token; uint256 stake; // Cost to join Commit // Fees Fee creatorFee; Fee clientFee; } struct Verifier { address target; bytes data; } struct Fee { address recipient; uint256 fee; uint256 shareBps; } struct ClientConfig { address recipient; uint256 fee; uint256 share; } struct Milestone { uint256 deadline; // Timestamp when participant must verify before string metadataURI; // (Optional) Details about milestone } uint256 public commitIds; mapping(uint256 => Commit) public commits; enum ParticipantStatus { init, joined, verified, claimed } Fee public protocolFee; mapping(uint256 => mapping(address => ParticipantStatus)) public participants; mapping(address => mapping(address => uint256)) public claims; mapping(address => mapping(uint256 => uint256)) public funds; mapping(address => mapping(uint256 => uint256)) public rewards; mapping(uint256 => uint256) public verifiedCount; function create(Commit calldata config) public payable whenNotPaused { uint256 commitId = commitIds++; commits[commitId] = config; emit Created(commitId, config); } function fund( uint256 commitId, address token, uint256 amount ) public payable whenNotPaused { funds[token][commitId] += amount; TokenUtils.transferFrom(token, _msgSender(), address(this), amount); emit Funded(commitId, _msgSender(), token, amount); } function join( uint256 commitId, address referral, // Transfer referral bonus from sharing link to Commit bytes calldata data ) public payable nonReentrant { require( participants[commitId][_msgSender()] == ParticipantStatus.init, "Already joined" ); participants[commitId][_msgSender()] = ParticipantStatus.joined; Commit memory commit = getCommit(commitId); require(block.timestamp < commit.joinBefore, "Join period ended"); // Check the conditions to join the Commit (ie token holdings, attestation, signature, etc) if (commit.joinVerifier.target != address(0)) { bool verified = IVerifier(commit.joinVerifier.target).verify( _msgSender(), commit.joinVerifier.data, data ); require(verified, "Not verified to join"); } // Transfer stake uint256 totalAmount = commit.stake + commit.creatorFee.fee + commit.clientFee.fee; funds[commit.token][commitId] += commit.stake; TokenUtils.transferFrom( commit.token, _msgSender(), address(this), totalAmount ); // Transfer fees uint256 creatorFee = commit.creatorFee.fee; uint256 clientFee = commit.clientFee.fee; uint256 fee = protocolFee.fee; claims[commit.token][commit.creatorFee.recipient] += creatorFee; claims[commit.token][commit.clientFee.recipient] += clientFee; claims[commit.token][protocolFee.recipient] += fee; // Mint ERC1155 NFT _mint(_msgSender(), commitId, 1, ""); emit Joined(commitId, _msgSender()); } function verify( uint256 commitId, address participant, bytes calldata data ) public payable returns (bool) { require( participants[commitId][participant] == ParticipantStatus.joined, "Already verified" ); Commit memory commit = getCommit(commitId); require( block.timestamp < commit.verifyBefore, "Verification period ended" ); // Check the conditions to claim the Commit rewards (ie token holdings, attestation, signature, etc) bool verified = IVerifier(commit.fulfillVerifier.target).verify( participant, commit.fulfillVerifier.data, data ); // Mark as verified if (verified) { participants[commitId][participant] = ParticipantStatus.verified; } emit Verified(commitId, participant, verified); verifiedCount[commitId]++; return verified; } function claim( uint256 commitId, address token ) public payable nonReentrant { require( participants[commitId][_msgSender()] == ParticipantStatus.verified, "Must be verified" ); participants[commitId][_msgSender()] = ParticipantStatus.claimed; Commit memory commit = getCommit(commitId); require(block.timestamp > commit.verifyBefore, "Still verifying"); uint256 amount = rewards[token][commitId]; if (amount == 0) { calculate(commitId, token); } TokenUtils.transfer(commit.token, _msgSender(), amount); emit Claimed(commitId, _msgSender(), commit.token, amount); } function calculate(uint256 commitId, address token) public { require(verifiedCount[commitId] > 0, "No verified participants"); Commit memory commit = getCommit(commitId); uint256 amount = funds[token][commitId]; uint256 creatorShare = (amount * commit.creatorFee.shareBps) / 10000; uint256 clientShare = (amount * commit.clientFee.shareBps) / 10000; uint256 protocolShare = (amount * protocolFee.shareBps) / 10000; claims[commit.token][commit.creatorFee.recipient] += creatorShare; claims[commit.token][commit.clientFee.recipient] += clientShare; claims[commit.token][protocolFee.recipient] += protocolShare; uint256 rewardsPool = amount - creatorShare - clientShare - protocolShare; funds[token][commitId] = 0; rewards[token][commitId] = rewardsPool / verifiedCount[commitId]; } function withdraw(address token) public payable nonReentrant { uint256 amount = claims[token][_msgSender()]; claims[token][_msgSender()] = 0; TokenUtils.transfer(token, _msgSender(), amount); emit Withdraw(_msgSender(), token, amount); } function getCommit( uint256 commitId ) public view returns (Commit memory commit) { require(commitId < commitIds, "Commit not found"); return commits[commitId]; } function approveToken(address token, bool isApproved) public onlyOwner {} } ```