// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.18; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; /** * @title MutableERC2771Context * @notice Context variant with ERC2771 support (with mutable `_trustedForwarder`). * @dev Based on OpenZeppelin ERC2771Context contract. */ abstract contract MutableERC2771ContextUpgradeable is Initializable, ContextUpgradeable, OwnableUpgradeable { address private _trustedForwarder; event TrustedForwarderSet(address indexed previousForwarder, address indexed newForwarder); function __MutableERC2771ContextUpgradeable_init(address trustedForwarder_) internal onlyInitializing { __Context_init(); __Ownable_init(); __MutableERC2771ContextUpgradeable_init_unchained(trustedForwarder_); } function __MutableERC2771ContextUpgradeable_init_unchained(address trustedForwarder_) internal onlyInitializing { _setTrustedForwarder(trustedForwarder_); } function setTrustedForwarder(address trustedForwarder) external virtual onlyOwner { _setTrustedForwarder(trustedForwarder); } function _setTrustedForwarder(address trustedForwarder) internal virtual { address previousForwarder = _trustedForwarder; _trustedForwarder = trustedForwarder; emit TrustedForwarderSet(previousForwarder, trustedForwarder); } function isTrustedForwarder(address forwarder) public view virtual returns (bool) { return forwarder == _trustedForwarder; } function _msgSender() internal view virtual override returns (address sender) { if (isTrustedForwarder(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 _msgData() internal view virtual override returns (bytes calldata) { if (isTrustedForwarder(msg.sender)) { return msg.data[:msg.data.length - 20]; } else { return super._msgData(); } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }