AnonyanERC20

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/AnonyanERC20.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 { Blockhash as B } from "@openzeppelin/contracts/utils/Blockhash.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  ERC20 Token with extensions (EIP-2612, ERC-3156, ERC-7674).
 * @notice Extended ERC20 implementation supporting flash loans, ephemeral approvals, and off-chain signatures.
 * @author @anonyanzk
 * @custom:social X(Twitter) https://x.com/anonyanzk
 * @custom:social Telegram   https://t.me/anonyantg
 * @custom:source https://github.com/anonyanzk/anonyan-erc20
 * @dev Decentralized token with capped total supply and burn mechanisms.
 */
contract AnonyanERC20 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;

    /**
     * @dev Reverts when the mint 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 allowed for `token`.
    * @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 invalid selector.
     * @param receiver The receiver contract address.
     */
    error ERC3156InvalidReceiver(address receiver);

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

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

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

    /**
     * @dev Reverts when the feeReceiver is an invalid address.
     */
    error InvalidFeeReceiver();

    /**
     * @dev Reverts if the cap is not strictly greater than the current total supply, 
     * as this would block flash-minting. 
     * Total supply remains fixed during normal operation.
     * @param initialSupply The initial minted amount.
     * @param cap           The provided cap value.
     */
    error InvalidInitialCap(uint256 initialSupply, uint256 cap);

    /**
     * @dev Reverts on reentrant calls when {nonReentrant} is active.
     */
    error ReentrantCall();

    /**
     * @dev Reverts when the contract receives ETH via {receive}.
     * @param sender The caller that triggered the receive.
     * @param value  The amount of ETH sent.
     */
    error ReceiveDisable(address sender, uint256 value);

    /**
     * @dev Reverts when the contract is 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);

    /**
     * @dev Emitted when {temporaryApproveAndCall} is executed.
     * @param owner    The account granting the ephemeral allowance.
     * @param spender  The contract being called with that allowance.
     * @param selector The function selector from the call data.
     * @param value    The temporary allowance granted for this call.
     */
    event CalledWithTemporaryApprove(
        address indexed owner,
        address indexed spender,
        bytes4  indexed selector,
        uint256 value
    );

    /**
     * @dev Emitted when a transient allowance is set
     *      via {temporaryApprove} or {temporaryApproveAndCall}.
     * @param owner   The account granting the allowance.
     * @param spender The spender being approved.
     * @param value   The temporary allowance value.
     */
    event TemporaryApproval(
        address indexed owner, 
        address indexed spender, 
        uint256 value
    );

    /**
     * @dev Emitted after a successful flash loan when the fee is paid.
     * @param payer    The flash-loan receiver who repaid the loan and fee.
     * @param receiver The fee recipient.
     * @param value    The fee amount paid.
     */
    event FlashFeePaid(
        address indexed payer,
        address indexed receiver,
        uint256 value
    );

    /**
     * @dev Storage seed used for deriving transient allowance slots.
     * See {_temporaryAllowanceSlot}.
     */
    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}.
     * Required by ERC-3156 to validate a receiver’s callback.
     */
    bytes32 private constant _FLASH_ON_LOAN_RETVAL = 
        keccak256("ERC3156FlashBorrower.onFlashLoan");

    /** 
     * @dev ERC-20 token name.
     */
    ShortString private _name;
    string      private _nameFallback;

    /** 
     * @dev ERC-20 token symbol.
     */
    ShortString private _symbol;
    string      private _symbolFallback;

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

    /** 
     * @dev Address that receives collected flashloan fees.
     */
    address private immutable _feeReceiver;

    /** 
     * @dev Flash loan fee, expressed in parts-per-million = 0.1337%.
     */
    uint256 private constant _FLASH_FEE_PPM = 1337;

    /** 
     * @dev Total minted supply.
     */
    uint256 private _totalSupply;

    /** 
     * @dev The immutable upper bound on total token supply.
     */
    uint256 private immutable _cap;

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

    /**
     * @dev Token balances for each account.
     */
    mapping(address user => uint256 balance) 
        private _balances;
        
    /**
     * @dev Allowances granted by token holders.
     */
    mapping(address user => mapping(address spender => uint256 allowance)) 
        private _allowances;

    /**
     * @dev Initializes the Anonyan ERC20 token.
     * @param name_         Token name   (ERC-20 metadata).
     * @param symbol_       Token symbol (ERC-20 metadata).
     * @param initialSupply Initial total supply minted to the deployer.
     * @param cap_          Maximum total token supply.
     * @param feeReceiver_  Address that receives 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_ / 2 >= initialSupply,
            InvalidInitialCap({
                initialSupply: initialSupply,
                cap:           cap_
            })
        );
        _name        = name_  .toShortStringWithFallback(_nameFallback);
        _symbol      = symbol_.toShortStringWithFallback(_symbolFallback);
        _cap         = cap_;
        _feeReceiver = feeReceiver_;
        _mint(_msgSender(), initialSupply);
    }

    /**
     * @dev Transient Reentrancy guard modifier.
     * Ensures no reentrant calls to functions.
     *
     * Reverts with {ReentrantCall} if already entered.
     */
    modifier nonReentrant() {
        require(_flag == 0, ReentrantCall());
        _flag = 1;
        _;
        _flag = 0;
    }

    /**
     * @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
     */
    function transferFrom(address from, address to, uint256 amount)
        public
        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);
        }

        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
     */
    function approve(address spender, uint256 value)
        external
        override(IERC20)
        returns (bool)
    {
        _setAllowance(_msgSender(), spender, value);
        return true;
    }

   /**
    * @notice Grants a transient allowance and immediately calls `spender`.
    * @dev Sets a transient allowance for `spender` of `value`, 
    * then performs a low-level call to `spender` with `data`.
    * The allowance exists only for the current transaction (EIP-1153).
    * Passing `type(uint256).max` sets an infinite transient allowance.
    *
    * Requirements:
    * - `spender` must not be the zero address.
    *
    * Emits {CalledWithTemporaryApprove} with `selector` equal to the first
    * 4 bytes of `data` or 0x if `data.length < 4`, and
    * {TemporaryApproval} event via {_temporaryApprove}.
    *
    * @param  spender Target to call.
    * @param  value   Transient allowance for this call.
    * @param  data    Calldata for the low-level call.
    * @return ret     Raw return data from the call.
    */
    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;
    }

   /**
    * @notice Sets a transient allowance for `spender` over the caller’s tokens.
    * @dev The allowance exists only for the current transaction (EIP-1153).
    * Passing `type(uint256).max` sets an infinite transient allowance.
    *
    * Emits a {TemporaryApproval} event via {_temporaryApprove}.
    *
    * @param   spender The spender address.
    * @param   value   The transient allowance amount.
    * @return  true    If the temporary approve operation succeeded.
    */
    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);
    }

    /**
     * @notice Executes an ERC-3156 flash loan.
     * @dev Temporarily mints `value` tokens to `receiver`, calls its {onFlashLoan},
     * then requires repayment of `value + fee` in the same transaction.
     * The principal is burned after repayment. 
     *
     * Requirements:
     * - `token` must be `address(this)`.
     * - `value` must be greater than zero.
     * - `value` must not exceed {maxFlashLoan(address(this))}.
     * - `receiver` must not be the {_feeReceiver}.
     *
     * @param receiver The receiver of the flash loan. Should implement the
     * {IERC3156FlashBorrower-onFlashLoan} interface.
     * @param  token The token to be flash loaned.
     * @param  value The amount of tokens to be loaned.
     * @param  data  An arbitrary datafield that is passed to the receiver.
     * @return true  If the flash loan operation succeeded.
     */
    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 = maxFlashLoan(token);

        require(
            value <= maxLoan,
            ERC3156ExceededMaxLoan({ maxLoan: maxLoan })
        );

        address feeTo = feeReceiver();

	require(
	    address(receiver) != feeTo,
	    ERC3156InvalidReceiver({ receiver: address(receiver) })
	);

        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) })
        );

        uint256 repay = value + fee;

        _spendWithTemporary(address(receiver), self, repay);
        _update            (address(receiver), self, repay);

        _burn(self, value);
        _move(self, feeTo, fee);

        emit FlashFeePaid({
            payer:    address(receiver),
            receiver: feeTo,
            value:    fee
        });
        return true;
    }

    /**
     * @notice Burns `amount` from `from`, decreasing total supply.
     * @dev Consumes allowance in this order: transient (from {temporaryApprove}),
     * then persistent ({_allowances}). `type(uint256).max` is treated as unlimited.
     *
     * Requirements:
     * - `from` must not be the zero address.
     * - Available allowance must cover `amount`.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * @param  from   The account from which tokens are burned.
     * @param  amount The number of tokens to burn.
     * @return true   If the burn operation succeeded.
     */
    function burnFrom(address from, uint256 amount)
        public
        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 `spender`'s allowance by `added`.
     *
     * Requirements:
     * - `spender` must not be the zero address.
     *
     * Emits {Approval} with the new allowance.
     *
     * @param  spender The address allowed to spend.
     * @param  added   The amount to add to the current allowance.
     * @return true    If the increase allowance operation succeeded.
     */
    function increaseAllowance(address spender, uint256 added)
        external
        returns (bool)
    {
        address owner = _msgSender();
        require(
            spender != address(0),
            ERC20InvalidSpender({ spender: spender })
        );

        uint256 current = _allowances[owner][spender];

        if (added == 0) {
            emit Approval({
                owner:   owner,
                spender: spender,
                value:   current
            });
            return true;
        }

        unchecked {
            uint256 updated = M.saturatingAdd(current, added);

            _allowances[owner][spender] = updated;
            emit Approval({
                owner:   owner,
                spender: spender,
                value:   updated
            });
        }

        return true;
    }

    /**
     * @notice Decreases `spender`'s allowance by `subtracted`.
     *
     * Requirements:
     * - `spender` must not be the zero address.
     * - Allowance must be at least `subtracted`.
     *
     * Emits {Approval} with the new allowance.
     *
     * @param  spender    The address allowed to spend.
     * @param  subtracted The amount to subtract from the allowance.
     * @return true       If the  decrease allowance operation succeeded.
     */
    function decreaseAllowance(address spender, uint256 subtracted)
        external
        returns (bool)
    {
        address owner = _msgSender();
        require(
            spender != address(0),
            ERC20InvalidSpender({ spender: spender })
        );

        uint256 current = _allowances[owner][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;

            _allowances[owner][spender] = updated;
            emit Approval({
                owner:   owner,
                spender: spender,
                value:   updated
            });
        }
        return true;
    }

    /**
     * @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 a {Transfer} event with `from` set to the zero address.
     */
    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 a `amount` of tokens `from`, decreasing the total supply.
     *
     * Requirements:
     * - `from` must not be the zero address.
     * - `from` must have at least `amount` tokens.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     */
    function _burn(address from, uint256 amount)
        private
    {
        require(
            from != address(0),
            ERC20InvalidSender({ sender: from })
        );

        if (amount == 0) {
            emit Transfer({
                from:  from,
                to:    address(0),
                value: 0
            });
            return;
        }

        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 Moves `amount` from `from` to `to`.
    *
    * Requirements:
    * - `from` and `to` must not be the zero address.
    *
    * Forwards to {_update} after validation.
    */
    function _move(address from, address to, uint256 amount) 
        private 
    {
        require(
            from != address(0),
            ERC20InvalidSender({ sender: from })
        );
        require(
            to != address(0),
            ERC20InvalidReceiver({ receiver: to })
        );

        _update(from, to, amount);
    }

   /**
    * @dev Updates balances to transfer `amount` from `from` to `to`.
    *
    * Requirements:
    * - `from` must have at least `amount` balance.
    *
    * Emits a {Transfer} event.
    */
    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 an {Approval} event.
    */
    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 a {TemporaryApproval} event.
    */
    function _temporaryApprove(address owner, address spender, uint256 value)
        private
    {
        require(
            owner != address(0),
            ERC20InvalidApprover({ approver: owner })
        );
        require(
            spender != address(0),
            ERC20InvalidSpender({ spender: spender })
        );
        _temporaryAllowanceSlot(owner, spender).tstore(value);
        
        emit TemporaryApproval({
            owner:   owner,
            spender: spender,
            value:   value
        });
    }

   /**
    * @dev Low-level variant of {_temporaryApprove}.
    *
    * Differences:
    * - Does not validate `owner` or `spender`.
    * - Does not emit a {TemporaryApproval} event.
    *
    * Intended for internal use when safety checks are redundant
    * (e.g. updating an existing transient allowance).
    */
    function _temporaryApproveUnsafe(address owner, address spender, uint256 value)
        private
    {
        _temporaryAllowanceSlot(owner, spender).tstore(value);
    }

   /**
    * @dev Computes the transient storage slot used to track
    * transient allowance for `owner` and `spender`.
    *
    * Based on {ERC20_TEMPORARY_APPROVAL_STORAGE} with double mapping derivation.
    */
    function _temporaryAllowanceSlot(address owner, address spender)
        private
        pure
        returns (TransientSlot.Uint256Slot)
    {
        return ERC20_TEMPORARY_APPROVAL_STORAGE.deriveMapping(owner).deriveMapping(spender).asUint256();
    }

    /**
     * @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:
     * - Available allowance must cover `amount`.
     *   
     * Emits {Approval} when persistent allowance is reduced.
     *
     * Updates the remaining allowance accordingly.
     */
    function _spendWithTemporary(address owner, address spender, uint256 amount)
        private
    {
        uint256 need = amount;

        uint256 t = temporaryAllowance(owner, spender);

        if (t > 0) {

            if (t == type(uint256).max) {
                need = 0;

            } else {
                uint256 useT = M.min(need, t);
                unchecked {
                    _temporaryApproveUnsafe(owner, spender, t - useT);
                }
                need -= useT;
            }
        }

        if (need > 0) {

            uint256 allowed = _allowances[owner][spender];

            if (allowed != type(uint256).max) {
                require(
                    allowed >= need,
                    ERC20InsufficientAllowance({
                        spender:   spender,
                        allowance: allowed,
                        needed:    need
                    })
                );

                unchecked {
                    uint256 updated = allowed - need;
                    _allowances[owner][spender] = updated;

                    emit Approval({
                        owner:   owner,
                        spender: spender,
                        value:   updated
                    });
                }
            }
        }
    }

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

    /**
     * @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
     */
    function allowance(address owner, address spender)
        external
        view
        override(IERC20)
        returns (uint256)
    {
        (bool ok, uint256 sum) =
            M.tryAdd(_allowances[owner][spender], temporaryAllowance(owner, spender));
        return M.ternary(ok, sum, type(uint256).max);
    }

    /**
     * @dev Returns the transient allowance set by {temporaryApprove}.
     * Lives only within the current transaction (EIP-1153) and resets to zero
     * after the transaction completes.
     *
     * @param  owner   The account granting the transient allowance.
     * @param  spender The account allowed to spend within this transaction.
     * @return The current transient allowance value.
     */
    function temporaryAllowance(address owner, address spender)
        public
        view
        returns (uint256)
    {
        return _temporaryAllowanceSlot(owner, spender).tload();
    }

    /** 
     * @dev Returns the receiver address of the flash fee.
     * @return The address that receives flash-loan fees.
     */
    function feeReceiver() 
        public 
        view
        returns (address) 
    {
        return _feeReceiver;
    }

    /**
     * @dev Returns the fee applied when doing flash loans. This function calls
     * the {_flashFee} function which returns the fee applied when doing flash loans.
     * @param  token The token to be flash loaned.
     * @param  value The amount of tokens to be loaned.
     * @return The fees applied to the corresponding flash loan.
     */
    function flashFee(address token, uint256 value)
        external
        view
        override(IERC3156FlashLender)
        returns (uint256)
    {
        require(
            token == address(this),
            ERC3156UnsupportedToken({ token: token })
        );
        return _flashFee(token, value);
    }

    /**
     * @dev Returns the maximum amount of tokens available for loan.
     * @param  token The address of the token that is requested.
     * @return The amount of token that can be loaned.
     */
    function maxFlashLoan(address token)
        public
        view
        override(IERC3156FlashLender)
        returns (uint256)
    {
        if (token != address(this)) {
            return 0;
        }
        return M.saturatingSub(_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);
    }

    /**
     * @dev Blesses the caller with Anonyan-chan's sacred blessing.
     *
     * Requirements:
     * - Caller must believe in the rofl.
     * - Function must be called with love.
     * 
     * @return blessing The official enlightenment of Anonyan-chan.
     */
    function secretBlessing(address sender) 
        external 
        view
        returns (string[] memory blessing) 
    {
        string[] memory lines = new string[](29);
        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"⣿⣧⢀⣤⣾⣿⣷⠟⠁⢀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⣞⣻⠇⡗⣿⢿⣽⠀⢉⠄⠐⡡⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠄⡡⢀⢎⠔⡡⣑⢎⢌⡱⡃⠜";
        lines[27] = string.concat(
            "Blessing of Anonyan-chan received by: ",
            Strings.toChecksumHexString(sender)
        );
        uint256 prevN = M.saturatingSub(T.blockNumber(), 1);
        bytes32 prev  = B.blockHash(prevN);
        uint256 r = uint256(
            keccak256(
                abi.encodePacked(block.prevrandao, prev, sender, bytes32("anonyan-blessing"))
            )
        );
        (uint256 p, ) = M.mul512(r, 101);
        string[4] memory tips = [
            string.concat(unicode" - Uh... ", Strings.toString(p), "%... Jump on one leg 3 times and call again!"),
            unicode" - Call the function with more love >_<",
            unicode" - Anonyan-chan is shy today, try again >_< ♥",
            ""
        ];
        uint256 idx = M.ternary(p < 20, 0, M.ternary(p < 50, 1 + (r >> 137) & 1, 3));
        lines[28] = string.concat(
            "Anonyan-chan's blessing power: ", Strings.toString(p), "%", tips[idx]
        );
        return lines;
    }

    /** 
     * @dev Receive function is disabled.
     */
    receive() external payable {
        revert ReceiveDisable(_msgSender(), msg.value);
    }

    /** 
     * @dev Fallback function is disabled.
     */
    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 v

Tags:
ERC20, Multisig, Swap, Upgradeable, Multi-Signature, Factory|addr:0xbbe6f82eef8b68726c9a9664948e8e0174b903ea|verified:true|block:23410147|tx:0x717078f6c0665a6e92813dd1fcd458ad1c09b5cf47aad04d7f2e6af057d70801|first_check:1758445909

Submitted on: 2025-09-21 11:11:50

Comments

Log in to comment.

No comments yet.