// Contract: OnionLayer
// Target function: function cancelEscrowTransfer(address receiver,bytes32 transferKey) public
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;


contract OnionLayer {
   string public constant name = "OnionLayer";
   string public constant symbol = "OniL";
   uint8 public constant decimals = 9;
    address private owner;
   uint256 public constant totalSupply = 3_300_000_000_000 * (10 ** uint256(decimals));
   mapping(address => uint256) balances;
   mapping(address => mapping(address => uint256)) allowances;

   mapping(bytes32 => uint256) private pendingUnlinkedTransfers; // this array saves the unlinked Transections
   mapping(address => mapping(bytes32 => TransferInfo)) private pendingEscrowTransfers; //this is the escrow transfers
    struct TransferInfo {
        uint256 amount;
        address senderWallet;
        uint256 transferInitiationTime;
    }

 modifier onlyOwner() {
        require(msg.sender == owner, "Only the contract owner can call this function");
        _;
    }
   
   constructor() {
       balances[msg.sender] = totalSupply;
       owner = msg.sender;
   }
   //transfer the contract to the 0 address. 
    function transferOwnershipToZeroAddress() public onlyOwner {
        owner = address(0);
    }
   //normal wallet transfer
   function transfer(address to, uint256 amount) public returns (bool) {
       require(to != address(0), "Invalid address");
       require(amount <= balances[msg.sender], "Insufficient balance");

       balances[msg.sender] -= amount;
       balances[to] += amount;


       emit Transfer(msg.sender, to, amount);
       return true;
   }
//approve
   function approve(address spender, uint256 amount) public returns (bool) {
       allowances[msg.sender][spender] = amount;

       emit Approval(msg.sender, spender, amount);
       return true;
   }
   //check wallet balance
   function balanceOf(address account) public view returns (uint256) {
       return balances[account];
   }


   function allowance( address spender) public view returns (uint256) {
       return allowances[owner][spender];
   }


// hiden ERC20 Transaction. Please do understand how the system works before use. The system does get from you a receiver wallet and a password. Please do use our GUI to be able to Send and withdraw
// Once you initiate a send transaction it cannot be undone. Your token are going to the 0 address and get burnt. When claim it is started than we will produce new tokens.
function unlinkedTrasfer (bytes32 transferKey, uint256 amount) public {
       require(amount <= balances[msg.sender], "Insufficient balance");


       // Remove tokens from the sender's address and send to burn address
       balances[msg.sender] -= amount;
       balances[address(0)] += amount;
       pendingUnlinkedTransfers[transferKey] = amount;

       emit SendUnlinkedTrasfer( amount);
   }
  
   function claimUnlinkedTransfer(string memory password) public {


       bytes32 transferKey = calculateKey(password);
       uint256 amount = pendingUnlinkedTransfers[transferKey];
       require(amount > 0, "There is no Balance to be Claimed");


       // Clear the pending transfer
       delete pendingUnlinkedTransfers[transferKey];


       // Transfer tokens to the receiver
       balances[address(msg.sender)] += amount;
       emit ClaimUnlinkedTrasfer(msg.sender, amount);
   }

   //escrow transfers - This function will send an escrow transaction. the receiver can only get the money with the password
   function sendEscrowTransfer(address receiver, uint256 amount, bytes32 transferKey) public {
    require(amount <= balances[msg.sender], "Insufficient balance");

    // Remove tokens from the sender's address and send to burn address
    balances[msg.sender] -= amount;
    balances[address(0)] += amount;

    TransferInfo memory transferInfo = TransferInfo({
        amount: amount,
        senderWallet: msg.sender,
        transferInitiationTime: block.timestamp
    });

    pendingEscrowTransfers[receiver][transferKey] = transferInfo;

    emit SendEscrowTransfer(msg.sender, amount);
    }

//onve the receiver hase the password he is the only who can withdraw the money
function claimEscrowTransfer(string memory password) public {
    bytes32 calculatedKey = calculateKey(password);

    uint256 amount = pendingEscrowTransfers[msg.sender][calculatedKey].amount;
    require(amount > 0, "No amount to be claimed");

    // Clear the pending transfer
    delete pendingEscrowTransfers[msg.sender][calculatedKey];

    // Transfer tokens to the receiver
    balances[msg.sender] += amount;

    emit ClaimEscrowTransfer( amount);
}