// SPDX-License-Identifier: MIT

pragma solidity >=0.8.4;

/// @author OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
/// (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Context.sol)

/// @dev Provides information about the current execution context, including the
/// sender of the transaction and its data. While these are generally available
/// via msg.sender and msg.data, they should not be accessed in such a direct
/// manner, since when dealing with meta-transactions the account sending and
/// paying for execution may not be the actual sender (as far as an application
/// is concerned).
///
/// This contract is only required for intermediate, library-like contracts.
abstract contract Context {
    function _msgSender()
        internal
        view
        virtual
        returns (address)
    {
        return msg.sender;
    }

    function _msgData()
        internal
        view
        virtual
        returns (bytes calldata)
    {
        return msg.data;
    }
}

/// @author Modified from OpenZeppelin Contracts (last updated v4.7.0) (metatx/ERC2771Context.sol)
/// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/metatx/ERC2771Context.sol

/// @dev Context variant with ERC2771 support.
abstract contract ERC2771Context is Context {
    // address private immutable _trustedForwarder;
    mapping(address => bool) public trustedForwarders;

    /// @custom:oz-upgrades-unsafe-allow constructor
    // constructor(address trustedForwarder) {
    //     _trustedForwarder = trustedForwarder;
    // }

    function _msgSender()
        internal
        view
        virtual
        override
        returns (address sender)
    {
        if (trustedForwarders[msg.sender]) {
            // The assembly code is more direct than the Solidity version using `abi.decode`.
            /// @solidity memory-safe-assembly
            assembly {
                sender := shr(
                    96,
                    calldataload(sub(calldatasize(), 20))
                )
            }
        } else {
            return super._msgSender();
        }
    }

    function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
      return trustedForwarders[forwarder];
    }

    function _msgData()
        internal
        view
        virtual
        override
        returns (bytes calldata)
    {
        if (isTrustedForwarder(msg.sender)) {
            return msg.data[:msg.data.length - 20];
        } else {
            return super._msgData();
        }
    }
}
