AnonyaERC20

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/AnonyaERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

import { Time as T }      from "@openzeppelin/contracts/utils/types/Time.sol";
import { Math as M }      from "@openzeppelin/contracts/utils/math/Math.sol";
import { ECDSA }          from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import { EIP712 }         from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import { Nonces }         from "@openzeppelin/contracts/utils/Nonces.sol";
import { Address }        from "@openzeppelin/contracts/utils/Address.sol";
import { Context }        from "@openzeppelin/contracts/utils/Context.sol";
import { Strings }        from "@openzeppelin/contracts/utils/Strings.sol";
import { ShortString, 
         ShortStrings }   from "@openzeppelin/contracts/utils/ShortStrings.sol";
import { TransientSlot }  from "@openzeppelin/contracts/utils/TransientSlot.sol";
import { SlotDerivation } from "@openzeppelin/contracts/utils/SlotDerivation.sol";

import { IERC20 }                from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC20Permit }          from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import { IERC20Errors  }         from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import { IERC20Metadata }        from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { IERC7674 }              from "@openzeppelin/contracts/interfaces/draft-IERC7674.sol";
import { IERC3156FlashBorrower } from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
import { IERC3156FlashLender }   from "@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol";

/**
 * @title  ERC-20 token with extensions (EIP-2612, ERC-3156, ERC-7674).
 * @notice Extended ERC-20 implementation supporting flash loans, transient approvals, and off-chain signatures.
 * @author @anonyanzk
 * @custom:social X(Twitter) https://x.com/anonyanzk
 * @custom:social Telegram   https://t.me/anonyantg
 * @dev Decentralized token with capped total supply and burn mechanisms.
 */
contract AnonyaERC20 is 
    IERC20, 
    IERC20Metadata, 
    IERC20Errors, 
    IERC7674, 
    IERC20Permit, 
    IERC3156FlashLender,
    EIP712,
    Nonces,
    Context
{    
    using ShortStrings    for *;
    using SlotDerivation  for bytes32;
    using TransientSlot   for bytes32;
    using TransientSlot   for TransientSlot.Uint256Slot;

    /* ───────────────────────────── Errors ──────────────────────────────── */
    /**
     * @dev Reverts when minting would push the total supply above the cap.
     * @param newSupply The total supply that would result after minting.
     * @param cap       The maximum allowed supply.
     */
    error ERC20MintCapExceeded(uint256 newSupply, uint256 cap);

    /**
     * @dev Reverts when the recovered signer does not match the expected owner.
     * @param signer The recovered address from the signature.
     * @param owner  The expected token owner.
     */
    error ERC2612InvalidSigner(address signer, address owner);

    /**
     * @dev Reverts when the permit signature has expired.
     * @param deadline The timestamp after which the signature is invalid.
     */
    error ERC2612ExpiredSignature(uint256 deadline);

    /**
     * @dev Reverts when the loan amount is zero.
     * @param amount The invalid loan amount.
     */
    error ERC3156ZeroAmount(uint256 amount);

    /**
     * @dev Reverts when the loan amount exceeds the maximum loanable amount.
     * @param maxLoan The maximum loanable amount.
     */
    error ERC3156ExceededMaxLoan(uint256 maxLoan);

    /**
     * @dev Reverts when the given token is not supported for flash loans.
     * @param token The unsupported token address.
     */
    error ERC3156UnsupportedToken(address token);

    /**
     * @dev Reverts when the flash loan receiver callback returns an unexpected value.
     * @param receiver The receiver contract address.
     */
    error ERC3156InvalidReceiver(address receiver);

    /**
     * @dev Reverts when the token name constructor parameter is empty.
     */
    error EmptyInitialName();

    /**
     * @dev Reverts when the token symbol constructor parameter is empty.
     */
    error EmptyInitialSymbol();

    /**
     * @dev Reverts when the initial supply constructor parameter is zero.
     */
    error ZeroInitialSupply();

    /**
     * @dev Reverts when the fee receiver constructor parameter is the zero address.
     */
    error InvalidFeeReceiver();

    /**
     * @dev Reverts when the provided cap is not greater than the initial supply,
     *      preventing flash-minting.
     * @param initialSupply The initial minted amount.
     * @param cap           The provided cap value.
     */
    error InvalidInitialCap(uint256 initialSupply, uint256 cap);

    /**
     * @dev Reverts on reentrant call.
     */
    error ReentrantCall();

    /**
     * @dev Reverts when receiving ETH via receive.
     * @param sender The caller that sent ETH.
     * @param value  The amount of ETH sent.
     */
    error ReceiveDisable(address sender, uint256 value);

    /**
     * @dev Reverts when invoked via fallback.
     * @param sender The caller that triggered the fallback.
     * @param value  The amount of ETH sent with the call.
     * @param data   The calldata passed to the fallback.
     */
    error FallbackDisable(address sender, uint256 value, bytes data);

    // ───────────────────────────── Events ────────────────────────────────
    /**
     * @dev Emitted when temporaryApproveAndCall is executed.
     * @param owner    The account granting the transient allowance.
     * @param spender  The contract invoked with that allowance.
     * @param selector The first four bytes of calldata, the function selector.
     * @param value    The transient allowance granted for the call.
    */
    event CalledWithTemporaryApprove(
        address indexed owner,
        address indexed spender,
        bytes4  indexed selector,
        uint256         value
    );

    /**
     * @dev Emitted when a transient allowance is granted.
     * @param owner   The account granting the transient allowance.
     * @param spender The spender receiving the transient allowance.
     * @param value   The transient allowance amount.
     */
    event TemporaryApproval(
        address indexed owner,
        address indexed spender,
        uint256         value
    );
    
    /**
     * @dev Emitted when a flash loan fee is paid.
     * @param payer    The borrower that repaid the loan and fee.
     * @param receiver The address receiving the fee.
     * @param value    The fee amount paid.
     */
    event FlashFeePaid(
        address indexed payer,
        address indexed receiver,
        uint256         value
    );

    /* ───────────────────────────── Constants ───────────────────────────── */
    /**
     * @dev Storage seed used for deriving transient allowance slots.
     */
    bytes32 private constant ERC20_TEMPORARY_APPROVAL_STORAGE = 0xea2d0e77a01400d0111492b1321103eed560d8fe44b9a7c2410407714583c400;

    /**
     * @dev EIP-2612 permit typehash used to build the EIP-712 struct hash.
     */
    bytes32 private constant _PERMIT_TYPEHASH      = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");

    /**
     * @dev Expected return value from IERC3156FlashBorrower.onFlashLoan.
     *      Used to validate the receiver callback in flash loans.
     */
    bytes32 private constant _FLASH_ON_LOAN_RETVAL = keccak256("ERC3156FlashBorrower.onFlashLoan");

    /**
     * @dev ERC-20 decimals.
     */
    uint8   private constant _decimals = 18;

    /** 
     * @dev Flash loan fee rate in parts-per-million.
     */

    uint256 private constant _FLASH_FEE_PPM = 1337;

    /* ───────────────────────────── Immutables ──────────────────────────── */
    /**
     * @dev Token name stored as ShortString immutable.
     */
    ShortString private immutable  _name;

    /**
     * @dev Token symbol stored as ShortString immutable.
     */
    ShortString private immutable _symbol;

    /**
     * @dev Immutable address that receives flash loan fees.
     */
    address     private immutable  _feeReceiver;

    /**
     * @dev Immutable cap on the total token supply.
     */
    uint256     private immutable  _cap;

    /* ────────────────────────────── Storage ────────────────────────────── */
    /**
     * @dev Storage fallback for the token name.
     */
    string private _nameFallback;

    /**
     * @dev Storage fallback for the token symbol.
     */
    string private _symbolFallback;

    /**
     * @dev Current total token supply.
     */
    uint256 private _totalSupply;

    /* ───────────────────────────── Transient ───────────────────────────── */
    /** 
     * @dev Transient reentrancy guard flag.
     */
    uint256 private transient  _flag;

    /* ───────────────────────────── Mappings ──────────────────────────────  */
    /**
     * @dev Mapping of account balances.
     */
    mapping(address account => uint256 balance)
            private _balances;

    /**
     * @dev Mapping of allowances per owner and spender.
     */
    mapping(address owner => mapping(address spender => uint256 allowance))
            private _allowances;

    /* ───────────────────────────── Modifiers ─────────────────────────────  */
    /**
     * @dev Transient reentrancy guard modifier.
     */
    modifier nonReentrant() {
        _nonReentrantEnter();
        _;
        _nonReentrantExit ();
    }

    /**
     * @dev Enter transient reentrancy flag.
     */
    function _nonReentrantEnter() private {
        require(_flag == 0, ReentrantCall());
        _flag = 1;
    }

    /**
     * @dev Exit transient reentrancy flag.
     */
    function _nonReentrantExit()  private {
        _flag = 0;
    }

    /* ───────────────────────────── ERC-20 implementation ─────────────────────── */
    /**
     * @dev Initializes the ERC-20 token.
     * @param name_         Token name   (ERC-20 metadata).
     * @param symbol_       Token symbol (ERC-20 metadata).
     * @param initialSupply Tokens minted to the deployer.
     * @param cap_          Maximum allowed total supply.
     * @param feeReceiver_  Recipient of flash loan fees.
     */
    constructor(
        string  memory name_,
        string  memory symbol_,
        uint256 initialSupply,
        uint256 cap_,
        address feeReceiver_
    ) EIP712(name_, "1") {
        require(bytes(name_)  .length != 0,  EmptyInitialName());
        require(bytes(symbol_).length != 0,  EmptyInitialSymbol());
        require(initialSupply         != 0,  ZeroInitialSupply());
        require(
            feeReceiver_     != address(0) &&
            feeReceiver_     != address(this), 
            InvalidFeeReceiver()
        );
        require(
            cap_ > initialSupply,
            InvalidInitialCap({
                initialSupply: initialSupply,
                cap:           cap_
            })
        );
        _name        = name_  .toShortStringWithFallback(_nameFallback);
        _symbol      = symbol_.toShortStringWithFallback(_symbolFallback);
        _cap         = cap_;
        _feeReceiver = feeReceiver_;
        _mint(_msgSender(), initialSupply);
    }

    /* ───────────────────────────── ERC-20 external ─────────────────────── */
    /**
     * @inheritdoc IERC20
     */
    function transfer(address to, uint256 amount)
        external
        override(IERC20)
        returns (bool)
    {
        address from = _msgSender();
        require(
            to != address(0),
            ERC20InvalidReceiver({ receiver: to })
        );
        if (amount == 0) {
            emit Transfer({
                from:  from,
                to:    to,
                value: 0
            });
            return true;
        }
        if (to == from) {
            uint256 fromBal = _balances[from];
            require(
                fromBal >= amount,
                ERC20InsufficientBalance({
                    sender:  from,
                    balance: fromBal,
                    needed:  amount
                })
            );
            emit Transfer({
                from:  from,
                to:    to,
                value: amount
            });
            return true;
        }
        _update(from, to, amount);
        return true;
    }

    /**
     * @inheritdoc IERC20
     * @dev Implements IERC7674 semantics using EIP-1153 transient storage.
     */
    function transferFrom(address from, address to, uint256 amount)
        external
        override(IERC20)
        returns (bool)
    {
        address spender = _msgSender();
        require(
            from != address(0),
            ERC20InvalidSender({ sender: from })
        );
        require(
            to != address(0),
            ERC20InvalidReceiver({ receiver: to })
        );
        if (amount == 0) {
            emit Transfer({
                from:  from,
                to:    to,
                value: 0
            });
            return true;
        }
        if (spender != from) {
            _spendWithTemporary(from, spender, amount);
        }
        _update(from, to, amount);
        return true;
    }

    /**
     * @inheritdoc IERC20
     */
    function approve(address spender, uint256 value)
        external
        override(IERC20)
        returns (bool)
    {
        _setAllowance(_msgSender(), spender, value);
        return true;
    }

    /*
     * @inheritdoc IERC7674
     * @dev Executes a low-level call to `spender` with `data`.
     */
    function temporaryApproveAndCall(
        address spender,
        uint256 value,
        bytes calldata data
    )
        external
        nonReentrant
        returns (bytes memory ret)
    {
        require(
            spender != address(0),
            ERC20InvalidSpender({ spender: spender })
        );
        address owner = _msgSender();
        _temporaryApprove(owner, spender, value);
        ret = Address.functionCall(spender, data);
        bytes4 selector = data.length >= 4 ? bytes4(data) : bytes4(0);
        emit CalledWithTemporaryApprove({
            owner:    owner,
            spender:  spender,
            value:    value,
            selector: selector
        });
        return ret;
    }

    /**
     * @inheritdoc IERC7674
     */
    function temporaryApprove(address spender, uint256 value)
        external
        override(IERC7674)
        returns (bool)
    {
        _temporaryApprove(_msgSender(), spender, value);
        return true;
    }
    
    /** 
     * @inheritdoc IERC20Permit
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v, bytes32 r, bytes32 s
    )
        external
        override(IERC20Permit)
    {
        require(
            T.timestamp() <= deadline,
            ERC2612ExpiredSignature({ deadline: deadline })
        );
        bytes32 structHash = keccak256(
            abi.encode(
                _PERMIT_TYPEHASH,
                owner,
                spender,
                value,
                _useNonce(owner),
                deadline
            )
        );
        bytes32 digest = _hashTypedDataV4(structHash);
        address signer = ECDSA.recover(digest, v, r, s);
        require(
            signer == owner,
            ERC2612InvalidSigner({
                signer: signer,
                owner:  owner
            })
        );
        _setAllowance(owner, spender, value);
    }

    /**
     * @inheritdoc IERC3156FlashLender
     * @dev Before returning from onFlashLoan the borrower must approve
     *      or temporaryApprove value plus fee to this contract.
     */
    function flashLoan(
        IERC3156FlashBorrower receiver,
        address        token,
        uint256        value,
        bytes calldata data
    )
        external
        override(IERC3156FlashLender) 
        nonReentrant 
        returns (bool) 
    {
        address self = address(this);
        require(
            token == self,
            ERC3156UnsupportedToken({ token: token })
        );
        require(
            value != 0, 
            ERC3156ZeroAmount({ amount: value })
        );
        uint256 maxLoan; unchecked { 
                maxLoan = _cap - _totalSupply; 
        }
        require(
            value <= maxLoan,
            ERC3156ExceededMaxLoan({ maxLoan: maxLoan })
        );
        uint256 fee = _flashFee(token, value);
        _mint(address(receiver), value);
        require(
            receiver.onFlashLoan(
                _msgSender(),
                token,
                value,
                fee,
                data
            ) == _FLASH_ON_LOAN_RETVAL,
            ERC3156InvalidReceiver({ receiver: address(receiver) })
        );
        address feeTo = _feeReceiver;
        uint256 repay = value + fee;
        _spendWithTemporary(address(receiver), self, repay);
        _update            (address(receiver), self, repay);
        _burn  (self, value);
        _update(self, feeTo, fee);
        emit FlashFeePaid({
            payer:    address(receiver),
            receiver: feeTo,
            value:    fee
        });
        return true;
    }

    /**
     * @notice Burns `amount` of tokens from the caller.
     * @param  amount The number of tokens to burn.
     */
    function burn(uint256 amount)
        external
        returns (bool)
    {
        address from = _msgSender();
        if (amount == 0) {
            emit Transfer({
                from:  from,
                to:    address(0),
                value: 0
            });
            return true;
        }
        _burn(from, amount);
        return true;
    }

    /**
     * @notice Burns `amount` tokens from `from` using the caller’s allowance.
     * @param from   The account from which tokens are deducted.
     * @param amount The number of tokens to burn.
     */
    function burnFrom(address from, uint256 amount)
        external
        returns (bool)
    {
        address spender = _msgSender();
        require(
            from != address(0),
            ERC20InvalidSender({ sender: from })
        );
        if (amount == 0) {
        emit Transfer({
            from:  from,
            to:    address(0),
            value: 0
        });
            return true;
        }
        if (spender != from) {
            _spendWithTemporary(from, spender, amount);
        }
        _burn(from, amount);
        return true;
    }

    /**
     * @notice Increases the allowance of `spender` granted by the caller by `added`.
     * @param spender The address whose allowance is increased.
     * @param added   The amount by which the allowance is increased.
     */
    function increaseAllowance(address spender, uint256 added)
        external
        returns (bool)
    {
        address owner = _msgSender();
        require(
            spender != address(0),
            ERC20InvalidSpender({ spender: spender })
        );
        mapping(address => uint256) storage a = _allowances[owner];
        uint256 current = a[spender];
        if (added == 0) {
            emit Approval({
                owner:   owner,
                spender: spender,
                value:   current
            });
            return true;
        }
        unchecked {
            uint256 updated = M.saturatingAdd(current, added);
            a[spender]      = updated;
            emit Approval({
                owner:   owner,
                spender: spender,
                value:   updated
            });
        }
        return true;
    }

    /**
     * @notice Decreases the allowance of `spender` granted by the caller by `subtracted`.
     * @param spender    The address whose allowance is decreased.
     * @param subtracted The amount by which the allowance is decreased.
     */
    function decreaseAllowance(address spender, uint256 subtracted)
        external
        returns (bool)
    {
        address owner = _msgSender();
        require(
            spender != address(0),
            ERC20InvalidSpender({ spender: spender })
        );
        mapping(address => uint256) storage a = _allowances[owner];
        uint256 current = a[spender];
        if (subtracted == 0) {
            emit Approval({
                owner:   owner,
                spender: spender,
                value:   current
            });
            return true;
        }
        require(
            current >= subtracted,
            ERC20InsufficientAllowance({
                spender:   spender,
                allowance: current,
                needed:    subtracted
            })
        );
        unchecked {
            uint256 updated = current - subtracted;
            a[spender]      = updated;
            emit Approval({
                owner:   owner,
                spender: spender,
                value:   updated
            });
        }
        return true;
    }

    /* ───────────────────────────── ERC-20 internal ─────────────────────── */
    /**
     * @dev Creates `amount` tokens and assigns them to `to`, increasing the total supply.
     *
     * Requirements:
     * - `to` must not be the zero address.
     * - Total supply after minting must not exceed {_cap}.
     *
     * Emits:
     * - {Transfer}
     */
    function _mint(address to, uint256 amount) 
        private
    {
        require(
            to != address(0),
            ERC20InvalidReceiver({ receiver: to })
        );
        uint256 newSupply = _totalSupply + amount;
        require(
            newSupply <= _cap,
            ERC20MintCapExceeded({
                newSupply: newSupply,
                cap:       _cap
            })
        );
        _totalSupply = newSupply;
        unchecked {
            _balances[to] += amount;
        }
        emit Transfer({
            from:  address(0),
            to:    to,
            value: amount
        });
    }

    /**
     * @dev Destroys `amount` tokens from `from`, decreasing the total supply.
     *
     * Requirements:
     * - `from` must have at least `amount` tokens.
     *
     * Emits: 
     * - {Transfer}
     */
    function _burn(address from, uint256 amount)
        private
    {
        uint256 fromBal = _balances[from];
        require(
            fromBal >= amount,
            ERC20InsufficientBalance({
                sender:  from,
                balance: fromBal,
                needed:  amount
            })
        );
        unchecked {
            _balances[from] = fromBal - amount;
            _totalSupply    -= amount;
        }
        emit Transfer({
            from:  from,
            to:    address(0),
            value: amount
        });
    }

    /**
     * @dev Updates balances to transfer `amount` from `from` to `to`.
     *
     * Requirements:
     * - `from` must have at least `amount` balance.
     *
     * Emits: 
     * - {Transfer}
     */
    function _update(address from, address to, uint256 amount) 
        private
    {
        uint256 fromBal = _balances[from];
        require(
            fromBal >= amount, 
            ERC20InsufficientBalance({
                sender:  from,
                balance: fromBal,
                needed:  amount
        }));
        unchecked {
            _balances[from] = fromBal - amount;
            _balances[to]  += amount;
        }
        emit Transfer({
            from:  from,
            to:    to,
            value: amount
        });
    }

    /**
     * @dev Sets allowance of `spender` over `owner`'s tokens to `value`.
     *
     * Requirements:
     * - `owner` and `spender` must not be the zero address.
     *
     * Emits: 
     * - {Approval}
     */
    function _setAllowance(address owner, address spender, uint256 value) 
        private 
    {
        require(
            owner != address(0),
            ERC20InvalidApprover({ approver: owner })
        );
        require(
            spender != address(0),
            ERC20InvalidSpender({ spender: spender })
        );
        uint256 prev = _allowances[owner][spender];
        if (prev != value) {
            _allowances[owner][spender] = value;
        }
        emit Approval({
            owner:   owner,
            spender: spender,
            value:   value
        });
    }

    /**
     * @dev Sets transient allowance of `spender` over `owner`'s tokens to `value`.
     *
     * Requirements:
     * - `owner` and `spender` must not be the zero address.
     *
     * Emits: 
     * - {TemporaryApproval}
     */
    function _temporaryApprove(address owner, address spender, uint256 value)
        private
    {
        require(
            spender != address(0),
            ERC20InvalidSpender({ spender: spender })
        );
        _temporaryAllowanceSlot(owner, spender).tstore(value);
        emit TemporaryApproval({
            owner:   owner,
            spender: spender,
            value:   value
        });
    }

    /**
     * @dev Deducts allowance for `spender` on behalf of `owner`.
     *
     * Resolution order:
     * - First consumes transient allowance from {temporaryApprove}.
     * - Then consumes persistent allowance from {_allowances}, if needed.
     *
     * Requirements:
     * - The combined transient and persistent allowance must be enough to cover `amount`.
     *   
     * Emits:
     * - {Approval} when persistent allowance is reduced.
     */
    function _spendWithTemporary(
        address owner,
        address spender,
        uint256 amount
    )
        private
    {
        TransientSlot.Uint256Slot slot = _temporaryAllowanceSlot(owner, spender);
        uint256 t = slot.tload();
        if (t == type(uint256).max) {
            return;
        }
        if (t >= amount) {
            unchecked {
                slot.tstore(t - amount);
            }
            return;
        }
        unchecked {
            amount -= t;
        }
        slot.tstore(0);
        uint256 allowed = _allowances[owner][spender];
        if (allowed != type(uint256).max) {
            require(
                allowed >= amount,
                ERC20InsufficientAllowance({
                    spender:   spender,
                    allowance: allowed,
                    needed:    amount
                })
            );
            unchecked {
                uint256 updated = allowed - amount;
                _allowances[owner][spender] = updated;
                emit Approval({
                    owner:   owner,
                    spender: spender,
                    value:   updated
                });
            }
        }
    }

    /**
     * @dev Computes the transient allowance slot for `owner` and `spender`.
     */
    function _temporaryAllowanceSlot(address owner, address spender)
        private
        pure
        returns (TransientSlot.Uint256Slot)
    {
        return ERC20_TEMPORARY_APPROVAL_STORAGE.deriveMapping(owner).deriveMapping(spender).asUint256();
    }

    /**
     * @dev Computes the flash loan fee for `value`, rounding up.
     */
    function _flashFee(address /*token*/, uint256 value)
        private
        pure
        returns (uint256)
    {
        return M.mulDiv(value, _FLASH_FEE_PPM, 1_000_000, M.Rounding.Ceil);
    }

    /* ───────────────────────────── ERC-20 viewers ─────────────────────── */
    /**
     * @inheritdoc IERC20Metadata
     */
    function name()
        external
        view
        override(IERC20Metadata)
        returns (string memory)
    {
        return _name.toStringWithFallback(_nameFallback);
    }

    /**
     * @inheritdoc IERC20Metadata
     */
    function symbol()
        external
        view
        override(IERC20Metadata)
        returns (string memory)
    {
        return _symbol.toStringWithFallback(_symbolFallback);
    }

    /**
     * @inheritdoc IERC20Metadata
     */
    function decimals()
        external
        pure
        override(IERC20Metadata)
        returns (uint8)
    {
        return _decimals;
    }

    /**
     * @inheritdoc IERC20
     */
    function totalSupply()
        external
        view
        override(IERC20)
        returns (uint256)
    {
        return _totalSupply;
    }

    /**
     * @dev Returns the cap on the token's total supply.
     */
    function cap()
        external
        view
        returns (uint256)
    {
        return _cap;
    }

    /**
     * @inheritdoc IERC20
     */
    function balanceOf(address account)
        external
        view
        override(IERC20)
        returns (uint256)
    {
        return _balances[account];
    }

    /**
     * @inheritdoc IERC20
     * @dev Implements IERC7674 semantics using EIP-1153 transient storage.
     * @return The sum of persistent and transient allowance, capped at max on overflow
     */
    function allowance(address owner, address spender)
        external
        view
        override(IERC20)
        returns (uint256)
    {
        (bool ok, uint256 sum) =
            M.tryAdd(_allowances[owner][spender], _temporaryAllowanceSlot(owner, spender).tload());
        return M.ternary(ok, sum, type(uint256).max);
    }

    /**
     * @dev Transient allowance of `spender` over `owner` for the current transaction.
     */
    function temporaryAllowance(address owner, address spender)
        external
        view
        returns (uint256)
    {
        return _temporaryAllowanceSlot(owner, spender).tload();
    }

    /** 
     * @dev Returns the receiver address of the flash fee.
     */
    function feeReceiver() 
        external
        view
        returns (address) 
    {
        return _feeReceiver;
    }

    /**
     * @inheritdoc IERC3156FlashLender
     */
    function flashFee(address token, uint256 value)
        external
        view
        override(IERC3156FlashLender)
        returns (uint256)
    {
        require(
            token == address(this),
            ERC3156UnsupportedToken({ token: token })
        );
        return _flashFee(token, value);
    }

    /**
     * @inheritdoc IERC3156FlashLender
     */
    function maxFlashLoan(address token)
        external
        view
        override(IERC3156FlashLender)
        returns (uint256)
    {
        if (token != address(this)) {
            return 0;
        }
        unchecked {
            return _cap - _totalSupply;
        }
    }

    /** 
     * @inheritdoc IERC20Permit
     */
    function DOMAIN_SEPARATOR()
        external
        view
        override(IERC20Permit)
        returns (bytes32)
    {
        return _domainSeparatorV4();
    }

    /** 
     * @inheritdoc IERC20Permit
     */
    function nonces(address owner)
        public
        view
        override(IERC20Permit, Nonces)
        returns (uint256)
    {
        return super.nonces(owner);
    }

    /* ───────────────────────────── Easter egg ───────────────────────────── */
    /**
     * @notice Grants the caller Anonyan-chan’s holy blessing.
     * Recommended to call via `cast`, terminal size: ~ 69x30.
     * 
     * Requirements:
     * - Function must be called with love.
     * 
     * @param sender    The one to enlighten.
     * @return blessing The official blessing of Anonyan-chan.
     */
    function secretBlessing(address sender) 
        external 
        view
        returns (string[] memory blessing) 
    {
        string[] memory lines = new string[](28);
        lines[0]  = unicode"⣿⣿⣿⣿⣿⣿⣿⣤⡘⡍⠛⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⠋⡡⠊⠉⢀⠞⡻⠊⡐⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[1]  = unicode"⣿⣿⣿⣿⣿⣿⣿⡟⢿⠻⡀⠀⠀⠉⠛⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠉⠀⠀⣠⠞⠃⠀⢀⡀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[2]  = unicode"⣿⣿⣿⣿⣿⣿⣿⡄⠀⢀⠳⡀⠀⠀⠀⠀⠀⠈⠙⢿⣿⣿⡿⠟⣻⠟⠉⠀⠀⠀⠀⠀⠀⠠⠟⠁⠀⠀⠀⣠⡞⠀⠀⡀⠠⢜⣡⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[3]  = unicode"⣿⣿⣿⣿⣿⣿⣿⡇⠂⣰⣧⠐⡄⠀⠀⠀⠀⠀⣐⣮⣤⠤⠀⠨⠴⣶⡶⡶⠤⣀⠀⠀⠀⠀⠀⠀⠑⠲⣿⣋⣭⣛⠁⠠⠒⢵⣏⡀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀"; 
        lines[4]  = unicode"⣿⣿⣿⣿⣿⣿⣿⣹⣄⢘⣧⠀⢺⣆⠀⣠⠴⠛⠉⡱⠁⠀⠀⠀⠀⠀⠀⠀⠑⠢⡹⣦⡀⠀⠀⠀⠀⠀⠈⠻⡗⠀⠀⣀⣀⣒⡓⠧⡀⠀⢠⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[5]  = unicode"⣿⣿⣿⣿⣿⣿⣿⣿⡈⣙⡿⠂⢈⡿⠋⠀⠀⠀⠈⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠙⢝⣆⠑⡄⠀⠀⠀⠀⠘⢶⣀⣈⠉⣻⢿⡧⠀⠀⣸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[6]  = unicode"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣿⣀⠞⠀⠀⡀⠀⠠⠂⠀⠀⠀⠀⠀⠱⠀⠀⠠⠀⠀⠀⠀⠀⠻⡱⣼⡄⠀⠀⠀⠀⠈⢗⠤⣅⣴⣟⣇⣠⠀⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[7]  = unicode"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⡿⠁⠀⠀⡰⠀⠀⡆⢰⠀⠀⠀⠀⠀⠀⢇⠀⠀⠑⡀⠀⠀⠀⠠⡘⢜⢿⡄⠀⢀⠀⠀⠈⢇⢨⣿⣿⠃⢀⣴⡅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀"; 
        lines[8]  = unicode"⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⢠⢃⠀⣰⠀⠘⠀⠀⠀⠀⣇⠀⢸⣧⡀⠀⠘⢦⠀⠠⠀⠉⢌⠺⣷⠀⠈⡆⠀⠀⠘⣿⢟⡿⢶⣿⡟⠘⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[9]  = unicode"⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⠀⠀⠀⣤⠇⢠⡟⡆⠀⡄⠀⠀⠀⠘⡄⠀⢏⠓⢄⠀⠣⠳⣄⠑⢄⠀⠣⡹⣇⠀⢰⠀⠀⠀⢳⠈⣰⣿⣿⢅⠘⣱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[10] = unicode"⣿⣿⣿⣿⣿⣿⠏⢠⠃⠀⠀⠀⢠⡟⠀⡾⠀⡇⠀⠂⠀⠀⠀⢳⠸⡄⠘⣄⣧⡦⡔⠒⠘⢯⡙⢍⠒⠚⢾⡀⠐⡆⠀⢡⠸⡮⠿⢫⡇⠘⡄⠀⢣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[11] = unicode"⣿⣿⣿⣿⠟⠁⢠⠃⠀⠀⠀⠀⢸⠇⣸⠇⢠⢡⢀⢸⡀⠀⠀⠸⣧⢳⡠⢻⠀⠑⢜⣆⠘⠄⠑⢌⡳⡀⠀⠇⠀⣧⠀⢸⠀⣇⡰⠋⠀⠀⣷⠀⡀⠡⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[12] = unicode"⣿⣿⠟⠁⢀⣴⡏⠀⡄⠀⠀⠀⢸⢀⣿⡀⠤⢼⡞⡄⣷⡘⣆⠀⠹⣍⣷⡀⢣⠀⠀⣙⣻⣦⣤⣤⣭⣛⣲⣤⠀⢹⠀⠀⠀⣍⣠⣤⠁⡰⢿⠀⠰⡀⠱⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[13] = unicode"⠋⢀⣠⣴⣿⣿⠁⠀⠁⠀⣸⠀⣾⠜⡏⠀⠀⠈⢿⡰⡘⣷⠘⣧⡀⠻⣿⣧⣀⣶⡿⢿⣿⣿⣿⣿⣿⡝⠻⣿⡶⠏⠀⠀⠀⢹⣿⣁⠜⡀⡿⣧⠀⡙⡄⠈⡢⡀⠀⠀⠀⠀⠀⠀⠀";
        lines[14] = unicode"⣿⣿⣿⣿⣿⡟⠀⠀⠀⠀⢿⠀⣿⠀⠃⠀⢀⣀⣨⠷⡑⢼⣧⡽⣷⣄⡀⢻⡠⡏⠀⠸⠏⢹⣿⣿⠙⡇⠀⣼⡇⠀⠀⠀⡆⣎⡙⢇⡰⢁⡇⣿⣧⣿⢮⠢⡀⠀⠑⠢⡀⠀⠀⠀⠀";
        lines[15] = unicode"⣿⣿⣿⣿⣿⡇⠀⠀⡇⠀⢸⡇⢻⠀⢐⣾⠟⣿⣿⣿⣗⠀⠈⠻⣆⠝⠣⢄⠈⠀⠀⠀⠰⣟⠹⢻⣿⠁⠀⠃⠁⠀⠀⢸⡇⣃⡁⢸⠁⣼⢧⢸⠙⡟⢷⣕⡌⠒⠤⣀⠀⠀⠀⠀⠀";
        lines[16] = unicode"⣿⣿⣿⣿⣿⡇⢸⠀⣧⠀⠸⣷⠘⣄⣾⠇⠀⠿⠛⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣈⣁⠉⣁⣀⣀⢀⡁⠀⠀⢸⡄⡏⣡⢟⣿⣿⠸⠀⠄⠸⠀⠀⠀⠉⠀⠀⠀⠀⠀⠀⠀";
        lines[17] = unicode"⣿⣿⢻⣿⣿⡇⢸⡆⢹⡄⠀⢹⣧⣻⡻⣇⠀⠀⢰⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⠟⢁⠠⠀⢸⠇⠀⠀⠸⠃⡗⣡⣾⡏⢿⠀⡇⡇⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[18] = unicode"⣿⣿⣸⣿⣿⡇⢸⣷⡘⣷⡀⠈⣿⣿⣧⠈⠂⠀⠀⠉⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠁⠀⠀⠀⠀⣾⠀⠀⠀⣀⠀⣿⣿⢿⡇⢸⡄⠀⢩⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[19] = unicode"⣿⣿⢸⣿⣿⣿⠘⣿⣷⣹⣷⣄⠘⣎⢻⣇⠀⠔⢫⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡔⢸⠀⠀⠀⣿⢠⣿⡇⢸⡇⠀⢷⠀⠸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[20] = unicode"⣿⣿⣿⣿⣿⣿⣇⢿⣿⣿⣿⣿⡿⣏⠙⢿⠘⠒⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠊⢀⣼⠀⡄⢠⡏⢸⣿⣧⠘⣿⠀⠈⣇⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[21] = unicode"⣿⣿⣿⣿⣿⣿⣿⣾⣿⣿⣿⡿⢁⣿⠀⠸⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⠟⣿⠀⠁⢸⡁⣼⣿⣿⠀⡟⡇⠀⠼⡀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[22] = unicode"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣵⣿⢟⡄⠀⢛⠢⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣾⠟⠁⢀⡏⠸⠀⣇⡆⣿⣿⣿⣇⣧⣿⡤⣶⣷⣸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[23] = unicode"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢸⣇⠀⠸⡀⢸⡏⠓⣦⣤⣀⣀⠀⠀⠀⠀⠀⣀⣤⣾⣿⠟⠁⣠⠐⠁⠃⡆⢠⣾⢱⣿⡏⢉⣀⣠⣴⢤⣤⣬⣁⡒⠢⠤⣄⣀⡀⠀⠀⠀⠀⠀";
        lines[24] = unicode"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⣼⣿⠀⠀⠃⠘⡇⢀⣿⢸⣿⣿⣿⣿⣷⣶⣿⣿⣿⠟⠁⡠⠊⠀⠀⠀⣷⠁⢸⣟⣸⠿⠿⢧⡅⢱⣧⠀⡅⡇⠇⢳⠈⠁⠢⡀⠁⠀⠀⠀⠀⠀";
        lines[25] = unicode"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢃⣿⢸⡇⠀⠰⠀⣿⢸⣿⣿⣿⣿⣿⠟⢛⣩⣿⡏⠁⠔⠈⢀⣠⠄⠒⢸⡟⠀⣿⡇⡇⠀⠀⢸⠃⠘⣿⠀⡁⢁⢸⠈⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀";
        lines[26] = unicode"⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⣼⣿⢸⣿⡀⠀⠀⢸⣿⣿⣿⡿⠋⠵⡽⠿⠛⠛⠋⠉⠉⠉⠁⡁⠀⠀⣿⡇⢠⣿⣹⠁⠀⠀⣿⠀⢰⢿⠀⠙⠘⢸⡀⣷⠀⠀⠀⠀⠀⠀⠀⠀⠌";
        address beacon = 0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02; 
        bytes32 broot  = bytes32(0);
        assembly ("memory-safe") { 
            mstore(0x00, timestamp())
            if iszero(staticcall(gas(), beacon, 0x00, 0x20, 0x00, 0x20)) { mstore(0x00, 0) }
            broot := mload(0x00) 
        }
        uint256 rnd = uint256(
            keccak256(abi.encode(sender, "anonyan-blessing", block.prevrandao, broot))
        ); 
        (uint256 hi, ) = M.mul512(rnd, 101); uint256 power = hi;
        lines[27] = string.concat(
            "Blessing of Anonyan-chan received by: ",
            Strings.toChecksumHexString(sender), " with power ", Strings.toString(power), "%"
        );
        return lines;
    }

    /* ───────────────────────────── Fallbacks ───────────────────────────── */
    /**
     * @dev Rejects direct ETH transfers via receive.
     */
    receive() external payable {
        revert ReceiveDisable(_msgSender(), msg.value);
    }

    /**
     * @dev Rejects calls with ETH or data via fallback.
     */
    fallback() external payable {
        revert FallbackDisable(_msgSender(), msg.value, _msgData());
    }
}"
    },
    "lib/openzeppelin-contracts/contracts/utils/types/Time.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/types/Time.sol)

pragma solidity ^0.8.20;

import {Math} from "../math/Math.sol";
import {SafeCast} from "../math/SafeCast.sol";

/**
 * @dev This library provides helpers for manipulating time-related objects.
 *
 * It uses the following types:
 * - `uint48` for timepoints
 * - `uint32` for durations
 *
 * While the library doesn't provide specific types for timepoints and duration, it does provide:
 * - a `Delay` type to represent duration that can be programmed to change value automatically at a given point
 * - additional helper functions
 */
library Time {
    using Time for *;

    /**
     * @dev Get the block timestamp as a Timepoint.
     */
    function timestamp() internal view returns (uint48) {
        return SafeCast.toUint48(block.timestamp);
    }

    /**
     * @dev Get the block number as a Timepoint.
     */
    function blockNumber() internal view returns (uint48) {
        return SafeCast.toUint48(block.number);
    }

    // ==================================================== Delay =====================================================
    /**
     * @dev A `Delay` is a uint32 duration that can be programmed to change value automatically at a given point in the
     * future. The "effect" timepoint describes when the transitions happens from the "old" value to the "new" value.
     * This allows updating the delay applied to some operation while keeping some guarantees.
     *
     * In particular, the {update} function guarantees that if the delay is reduced, the old delay still applies for
     * some time. For example if the delay is currently 7 days to do an upgrade, the admin should not be able to set
     * the delay to 0 and upgrade immediately. If the admin wants to reduce the delay, the old delay (7 days) should
     * still apply for some time.
     *
     *
     * The `Delay` type is 112 bits long, and packs the following:
     *
     * ```
     *   | [uint48]: effect date (timepoint)
     *   |           | [uint32]: value before (duration)
     *   ↓           ↓       ↓ [uint32]: value after (duration)
     * 0xAAAAAAAAAAAABBBBBBBBCCCCCCCC
     * ```
     *
     * NOTE: The {get} and {withUpdate} functions operate using timestamps. Block number based delays are not currently
     * supported.
     */
    type Delay is uint112;

    /**
     * @dev Wrap a duration into a Delay to add the one-step "update in the future" feature
     */
    function toDelay(uint32 duration) internal pure returns (Delay) {
        return Delay.wrap(duration);
    }

    /**
     * @dev Get the value at a given timepoint plus the pending value and effect timepoint if there is a scheduled
     * change after this timepoint. If the effect timepoint is 0, then the pending value should not be considered.
     */
    function _getFullAt(
        Delay self,
        uint48 timepoint
    ) private pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
        (valueBefore, valueAfter, effect) = self.unpack();
        return effect <= timepoint ? (valueAfter, 0, 0) : (valueBefore, valueAfter, effect);
    }

    /**
     * @dev Get the current value plus the pending value and effect timepoint if there is a scheduled change. If the
     * effect timepoint is 0, then the pending value should not be considered.
     */
    function getFull(Delay self) internal view returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
        return _getFullAt(self, timestamp());
    }

    /**
     * @dev Get the current value.
     */
    function get(Delay self) internal view returns (uint32) {
        (uint32 delay, , ) = self.getFull();
        return delay;
    }

    /**
     * @dev Update a Delay object so that it takes a new duration after a timepoint that is automatically computed to
     * enforce the old delay at the moment of the update. Returns the updated Delay object and the timestamp when the
     * new delay becomes effective.
     */
    function withUpdate(
        Delay self,
        uint32 newValue,
        uint32 minSetback
    ) internal view returns (Delay updatedDelay, uint48 effect) {
        uint32 value = self.get();
        uint32 setback = uint32(Math.max(minSetback, value > newValue ? value - newValue : 0));
        effect = timestamp() + setback;
        return (pack(value, newValue, effect), effect);
    }

    /**
     * @dev Split a delay into its components: valueBefore, valueAfter and effect (transition timepoint).
     */
    function unpack(Delay self) internal pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
        uint112 raw = Delay.unwrap(self);

        valueAfter = uint32(raw);
        valueBefore = uint32(raw >> 32);
        effect = uint48(raw >> 64);

        return (valueBefore, valueAfter, effect);
    }

    /**
     * @dev pack the components into a Delay object.
     */
    function pack(uint32 valueBefore, uint32 valueAfter, uint48 effect) internal pure returns (Delay) {
        return Delay.wrap((uint112(effect) << 64) | (uint112(valueBefore) << 32) | uint112(valueAfter));
    }
}
"
    },
    "lib/openzeppelin-contracts/contracts/utils/math/Math.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Return the 512-bit addition of two uint256.
     *
     * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
     */
    function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
        assembly ("memory-safe") {
            low := add(a, b)
            high := lt(low, a)
        }
    }

    /**
     * @dev Return the 512-bit multiplication of two uint256.
     *
     * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
     */
    function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
        // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
        // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
        // variables such that product = high * 2²⁵⁶ + low.
        assembly ("memory-safe") {
            let mm := mulmod(a, b, not(0))
            low := mul(a, b)
            high := sub(sub(mm, low), lt(mm, low))
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a + b;
            success = c >= a;
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a - b;
            success = c <= a;
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a * b;
            assembly ("memory-safe") {
                // Only true when the multiplication doesn't overflow
                // (c / a == b) || (a == 0)
                success := or(eq(div(c, a), b), iszero(a))
            }
            // equivalent to: success ? c : 0
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            success = b > 0;
            assembly ("memory-safe") {
                // The `DIV` opcode returns zero when the denominator is 0.
                result := div(a, b)
            }
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            success = b > 0;
            assembly ("memory-safe") {
                // The `MOD` opcode returns zero when the denominator is 0.
                result := mod(a, b)
            }
        }
    }

    /**
     * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
     */
    function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
        (bool success, uint256 result) = tryAdd(a, b);
        return ternary(success, result, type(uint256).max);
    }

    /**
     * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
     */
    function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
        (, uint256 result) = trySub(a, b);
        return result;
    }

    /**
     * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
     */
    function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
        (bool success, uint256 result) = tryMul(a, b);
        return ternary(success, result, type(uint256).max);
    }

    /**
     * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
     *
     * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
     * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
     * one branch when needed, making this function more expensive.
     */
    function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
        unchecked {
            // branchless ternary works because:
            // b ^ (a ^ b) == a
            // b ^ 0 == b
            return b ^ ((a ^ b) * SafeCast.toUint(condition));
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return ternary(a > b, a, b);
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return ternary(a < b, a, b);
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }

        // The following calculation ensures accurate ceiling division without overflow.
        // Since a is non-zero, (a - 1) / b will not overflow.
        // The largest possible result occurs when (a - 1) / b is type(uint256).max,
        // but the largest value we can obtain is type(uint256).max - 1, which happens
        // when a = type(uint256).max and b = 1.
        unchecked {
            return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
        }
    }

    /**
     * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     *
     * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            (uint256 high, uint256 low) = mul512(x, y);

            // Handle non-overflow cases, 256 by 256 division.
            if (high == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return low / denominator;
            }

            // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
            if (denominator <= high) {
                Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [high low].
            uint256 remainder;
            assembly ("memory-safe") {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                high := sub(high, gt(remainder, low))
                low := sub(low, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly ("memory-safe") {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [high low] by twos.
                low := div(low, twos)

                // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from high into low.
            low |= high * twos;

            // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
            // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv ≡ 1 mod 2⁴.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2⁸
            inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
            inverse *= 2 - denominator * inverse; // inverse mod 2³²
            inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
            inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
            inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is
            // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high
            // is no longer required.
            result = low * inverse;
            return result;
        }
    }

    /**
     * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
    }

    /**
     * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
     */
    function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
        unchecked {
            (uint256 high, uint256 low) = mul512(x, y);
            if (high >= 1 << n) {
                Panic.panic(Panic.UNDER_OVERFLOW);
            }
            return (high << (256 - n)) | (low >> n);
        }
    }

    /**
     * @dev Calculates x * y >> n with full precision, following the selected rounding direction.
     */
    function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
        return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);
    }

    /**
     * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
     *
     * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
     * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
     *
     * If the input value is not inversible, 0 is returned.
     *
     * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
     * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
     */
    function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
        unchecked {
            if (n == 0) return 0;

            // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
            // Used to compute integers x and y such that: ax + ny = gcd(a, n).
            // When the gcd is 1, then the inverse of a modulo n exists and it's x.
            // ax + ny = 1
            // ax = 1 + (-y)n
            // ax ≡ 1 (mod n) # x is the inverse of a modulo n

            // If the remainder is 0 the gcd is n right away.
            uint256 remainder = a % n;
            uint256 gcd = n;

            // Therefore the initial coefficients are:
            // ax + ny = gcd(a, n) = n
            // 0a + 1n = n
            int256 x = 0;
            int256 y = 1;

            while (remainder != 0) {
                uint256 quotient = gcd / remainder;

                (gcd, remainder) = (
                    // The old remainder is the next gcd to try.
                    remainder,
                    // Compute the next remainder.
                    // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
                    // where gcd is at most n (capped to type(uint256).max)
                    gcd - remainder * quotient
                );

                (x, y) = (
                    // Increment the coefficient of a.
                    y,
                    // Decrement the coefficient of n.
                    // Can overflow, but the result is casted to uint256 so that the
                    // next value of y is "wrapped around" to a value between 0 and n - 1.
                    x - y * int256(quotient)
                );
            }

            if (gcd != 1) return 0; // No inverse exists.
            return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
        }
    }

    /**
     * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
     *
     * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
     * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
     * `a**(p-2)` is the modular multiplicative inverse of a in Fp.
     *
     * NOTE: this function does NOT check that `p` is a prime greater than `2`.
     */
    function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
        unchecked {
            return Math.modExp(a, p - 2, p);
        }
    }

    /**
     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
     *
     * Requirements:
     * - modulus can't be zero
     * - underlying staticcall to precompile must succeed
     *
     * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
     * sure the chain you're using it on supports the precompiled contract for modular exponentiation
     * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
     * the underlying function will succeed given the lack of a revert, but the result may be incorrectly
     * interpreted as 0.
     */
    function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
        (bool success, uint256 result) = tryModExp(b, e, m);
        if (!success) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }
        return result;
    }

    /**
     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
     * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
     * to operate modulo 0 or if the underlying precompile reverted.
     *
     * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
     * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
     * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
     * of a revert, but the result may be incorrectly interpreted as 0.
     */
    function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
        if (m == 0) return (false, 0);
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            // | Offset    | Content    | Content (Hex)                                                      |
            // |-----------|------------|--------------------------------------------------------------------|
            // | 0x00:0x1f | size of b  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x20:0x3f | size of e  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x40:0x5f | size of m  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x60:0x7f | value of b | 0x<.............................................................b> |
            /

Tags:
ERC20, Multisig, Burnable, Upgradeable, Multi-Signature, Factory|addr:0xf50d4d57f79bad576e7fb8dd63bcf2978114379c|verified:true|block:23434660|tx:0x669e4075c299122506976ca7b9a37fd57a3d390a62bc8ad6d3e6794f3b5304f3|first_check:1758739551

Submitted on: 2025-09-24 20:45:51

Comments

Log in to comment.

No comments yet.