Eth being stolen by Mev bot from smart contract

I am working on smart contract for a simple payment system where u deposit and get a code. Then u can give a code to anyone and they can withdraw to any address.
I have already tested on all testnets and it works fine.
But on ethereum mainnet as soon as I deposit the eth, it is stolen and transferred by a mev bot.
Please help.

//SPDX-License-Identifier: UNLICENSED

// It will be used by the Solidity compiler to validate its version.
pragma solidity ^0.8.9;

// We import this library to be able to use console.log
import "hardhat/console.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract Payment is Ownable {
    address payable public feeWallet;
    uint256 public feeAmount;
    uint256 private numberOfDeposits = 0;

    struct Deposit {
        uint256 time;
        bytes32 id;
        uint256 amount;
    // mapping(address => bytes32[]) public addressToHashes;
    mapping(bytes32 => uint256) public hashToAmount;
    mapping(address => Deposit[]) public addressToDeposits;
    mapping(bytes32 => bool) public isWithdrawn;

    event DepositCreated(address _payer, uint256 _amount);
    event DepositWithdrawn(
        address _withdrawer,
        uint256 _amount,
        address indexed _withdrawTo

    constructor(address _feeWallet) {
        feeWallet = payable(_feeWallet);

    function createDeposit(string memory _id) public payable returns (bytes32) {
        //Check if value is greater than 0
        require(msg.value > 0, "Amount cannot be equal to 0");
        //Fetch mapppings
        Deposit[] storage deposits = addressToDeposits[msg.sender];
        //Create Hash from id
        bytes32 hash = generateId(_id);
        //Update Mappings
        hashToAmount[hash] = msg.value;
        numberOfDeposits += 1;
        deposits.push(Deposit(block.timestamp, hash, msg.value));
        addressToDeposits[msg.sender] = deposits;
        emit DepositCreated(msg.sender, msg.value);
        return hash;

    function generateId(string memory _id) internal view returns (bytes32) {
        uint id = uint(
        return bytes32(id % 100000000000000);

    function checkDepositExist(uint _id) public view returns (bool) {
        bytes32 hash = bytes32(_id);
        uint256 amount = hashToAmount[hash];
        console.log("amount", amount);
        if (amount > 0) {
            return true;
        } else {
            return false;

    function viewDeposit(uint _id) public view returns (uint256) {
        bytes32 hash = bytes32(_id);
        uint256 amount = hashToAmount[hash];
        return amount;

    function withdrawDeposit(uint _id, address _to) public {
        require(checkDepositExist(_id), "ID invalid");
        bytes32 hash = bytes32(_id);
        uint256 amount = hashToAmount[hash] - feeAmount;
        hashToAmount[hash] = 0;
        (bool sent, bytes memory data) = payable(_to).call{value: amount}("");
        require(sent, "Failed to send deposit amount");
        require(sendFees(), "Failed to send fee amount");

        isWithdrawn[hash] = true;

        emit DepositWithdrawn(msg.sender, amount, _to);

    function getUserDeposits() public view returns (Deposit[] memory) {
        Deposit[] memory deposits = addressToDeposits[msg.sender];
        return deposits;

    function setFeeAmount(uint _amount) public onlyOwner {
        feeAmount = _amount;

    function setFeeWallet(address _wallet) public onlyOwner {
        feeWallet = payable(_wallet);

    function sendFees() internal returns (bool) {
        (bool sent, bytes memory data) = payable(feeWallet).call{
            value: feeAmount
        return sent;

Here's the transaction of eth being stolen
See the second one.

Thank you.

well I don't know a lot about MEV bots but I know that this contract is not really secure.

Hello, thanks for replying. Can u please point out the unsecure parts and how to make it more secure please. Thanks again.

Well anybody could lock up things like difficulty or time stamp of the time when the transaction was done.
With this data they can regenerate the id and steal the funds. Or they use the addressToDeposits mapping to get all ids of a address and then steal the funds.
I know that you shouldn't handle things like passwords in solidity, everything that's stored, could be read.
I think that there are things like merkle proofs or something like that.

Can u guide to some guide for merkle proofs. i want to implement password like feature to withdraw eth.

Here some information about merkle proofs in general and also with smart contract examples:

Um, you're aware that transactions are public, right? Like, the hash that gets returned by your deposit function is viewable by anyone, and once you have it, stealing the ether stored in the contract is trivial.

Fun fact:
For OTP you could hashing.
Solidity supports sha256 hashing so a user could hash their password off-chain and enter the hash at the deposit.
At withdraw the user can use their password as they need a new hash for a new deposit.
The password is revealed at the withdraw but that's not a problem as the user already received his funds.

There are indeed a lot of security issues with your contract. Basic things like checking that the sender is the same address as who deposited would already go a long way, Or by having the sender sign the message. As it currently stands please don't use that code and either invest more time in learning solidity and all security best practices or hire someone who did and after that get an security audit on your contract.