GatewayHelper

Description:

Smart contract deployed on Ethereum with Factory features.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "contracts/GatewayHelper.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

import "./protocol/OptimexAdminGuard.sol";
import "./protocol/OptimexDomain.sol";
import "./interfaces/IOptimexProtocol.sol";
import "./interfaces/IGatewayHelper.sol";
import "./libraries/ErrorLib.sol";

/**
    @title GatewayHelper
    @notice A helper contract helps the `MorphoLiquidationGateway` to build the transaction data for the liquidator
    @dev This contract supports two types of liquidator contracts:
        - The legacy `MorphoLiquidator` contract
        - Other liquidator contracts
    @dev When additional types of liquidator contracts are needed, new contract versions are deployed to replace the old ones.
*/
contract GatewayHelper is OptimexDomain, IGatewayHelper {
    /**
        @notice The enum that defines the type of liquidator contract
        @param NO_USE This is the default value and should not be used
        @param LEGACY This is for the legacy `MorphoLiquidator` contract
    */
    enum LiquidatorType {
        NO_USE,
        LEGACY
    }

    /// bytes4(keccak256("payment(address,bytes32,bytes32,uint256,bool,bytes)"))
    bytes4 private constant _LEGACY_PAYMENT_SELECTOR = 0x52403932;
    /// keccak256("MORPHO_LIQUIDATOR_ROLE");
    bytes32 private constant _MORPHO_LIQUIDATOR_ROLE =
        0x8d711590108002b9213cc869b2031e136b963689adee0a363cdecb47bea125a0;

    /// @dev The address of the GATEWAY that this Helper relies on
    address public immutable GATEWAY;

    /// @dev Mapping that stores the type of the liquidator
    mapping(address => LiquidatorType) public liquidatorTypes;

    /**
        @notice Emitted when the type of the liquidator is updated
        @param operator The address who performed the update
        @param liquidator The address of the liquidator
        @param liqType The type of the liquidator
        @dev Related function: `setLiquidatorType()`
    */
    event LiqTypeUpdated(
        address indexed operator,
        address indexed liquidator,
        LiquidatorType liqType
    );

    constructor(
        address gateway,
        string memory name,
        string memory version
    ) OptimexDomain(name, version) {
        require(gateway != address(0), ErrorLib.ZeroAddress());
        GATEWAY = gateway;
    }

    /**
        @notice Set the type of the liquidator
        @param liquidator The address of the liquidator
        @param liqType The type of the liquidator
        @dev Caller must be the owner of the OptimexProtocol
     */
    function setLiquidatorType(
        address liquidator,
        LiquidatorType liqType
    ) external {
        /// @dev Ensure the following:
        /// - Only gateway owner can perform this action
        /// - The liqudiator has `_MORPHO_LIQUIDATOR_ROLE`
        IOptimexProtocol protocol = _getProtocol();
        require(
            protocol.owner() == msg.sender,
            ErrorLib.Unauthorized(msg.sender)
        );
        require(
            protocol.hasRole(_MORPHO_LIQUIDATOR_ROLE, liquidator),
            ErrorLib.Unauthorized(liquidator)
        );

        liquidatorTypes[liquidator] = liqType;

        emit LiqTypeUpdated(msg.sender, liquidator, liqType);
    }

    /**
        @notice Build the transaction data for the liquidator
        @param token The token being paid
        @param amount The amount paid by the payer
        @param externalCall The external call data the payer passed to the `MorphoLiquidationGateway`
        @return liquidator The address of the liquidator
        @return txCallData The transaction data for the liquidator
        @dev token is not used in the current implementation, but it's kept for future compatibility
     */
    function buildTxCalldata(
        address token,
        uint256 amount,
        bytes calldata externalCall
    ) external view returns (address liquidator, bytes memory txCallData) {
        token; // unused; prevents compiler warning
        /// Ensure the liquidator has the MORPHO_LIQUIDATOR_ROLE
        (liquidator, txCallData) = abi.decode(externalCall, (address, bytes));
        require(
            _getProtocol().hasRole(_MORPHO_LIQUIDATOR_ROLE, liquidator),
            ErrorLib.Unauthorized(liquidator)
        );

        /// @dev For legacy liquidator contracts:
        ///   - decode the `txCallData`
        ///   - rebuild the transaction call with the expected arguments
        /// Otherwise, return the calldata unchanged
        LiquidatorType liqType = liquidatorTypes[liquidator];
        if (liqType == LiquidatorType.LEGACY) {
            (
                address apm,
                bytes32 positionId,
                bytes32 tradeId,
                bool isLiquidate,
                bytes memory signature
            ) = abi.decode(
                    txCallData,
                    (address, bytes32, bytes32, bool, bytes)
                );
            txCallData = abi.encodeWithSelector(
                _LEGACY_PAYMENT_SELECTOR,
                apm,
                positionId,
                tradeId,
                amount,
                isLiquidate,
                signature
            );
        }
    }

    function _getProtocol() internal view returns (IOptimexProtocol protocol) {
        protocol = IOptimexProtocol(OptimexAdminGuard(GATEWAY).getProtocol());
    }
}
"
    },
    "contracts/interfaces/IGatewayHelper.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

interface IGatewayHelper {
    /**
        @notice Build the transaction data for the liquidator
        @param token The token being paid
        @param amount The amount paid by the payer
        @param externalCall The external call data the payer passed to the `MorphoLiquidationGateway`
        @return liquidator The address of the liquidator
        @return txCallData The transaction data for the liquidator
     */
    function buildTxCalldata(
        address token,
        uint256 amount,
        bytes calldata externalCall
    ) external view returns (address liquidator, bytes memory txCallData);
}
"
    },
    "contracts/interfaces/IOptimexProtocol.sol": {
      "content": "// SPDX-License-Identifier: None
pragma solidity ^0.8.20;

import "./IProtocol.sol";

interface IOptimexProtocol is IProtocol {
    /**
        @notice Checks whether the specified `account` has been granted the given `role`.
        @param role The role to check, represented as a `bytes32` value.
        @param account The address of the account to check.
        @return `true` if the `account` has been granted the `role`, otherwise `false`.
    */
    function hasRole(
        bytes32 role,
        address account
    ) external view returns (bool);
}
"
    },
    "contracts/interfaces/IProtocol.sol": {
      "content": "// SPDX-License-Identifier: None
pragma solidity ^0.8.20;

interface IProtocol {
    /**
        @notice Returns the address of the current owner.
        @return The address of the contract owner.
    */
    function owner() external view returns (address);

    /**
        @notice Returns the current address of the Protocol Fee Receiver.
        @return The protocol fee receiver's address.
    */
    function pFeeAddr() external view returns (address);
}
"
    },
    "contracts/libraries/ErrorLib.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

/// @title ErrorLib
/// @notice Provides common error messages for the Optimex protocol
/// @dev Designed as a library to be used by other Optimex contracts
library ErrorLib {
    error AccessDenied(bytes32 positionId);
    error AuthorizerMismatch();
    error DeadlineExpired();
    error InvalidAmount();
    error InvalidAPM();
    error InvalidAuthorizerSig();
    error InvalidOwnerSig();
    error InvalidPositionId(bytes32 positionId);
    error InvalidPubkey();
    error InvalidValidator(address validator);
    error MarketMismatch(bytes32 expected, bytes32 actual);
    error RecipientNotPermitted(address recipient);
    error StateAlreadySet();
    error TokenMismatch(address expected, address actual);
    error Unauthorized(address sender);
    error ZeroAddress();
    error ZeroAmount();
    error InvalidBorrowShares();
    error IncompleteConsumption();
    error InvalidThreshold();
    error InvalidLIF();
    error Liquidatable();
    error NotPreLiquidatable();
    error PreLiqDisabled(bytes32 marketId);
    error NoHelper();
}
"
    },
    "contracts/protocol/OptimexAdminGuard.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

import "../libraries/ErrorLib.sol";
import "../interfaces/IOptimexProtocol.sol";

/// @title OptimexAdminGuard
/// @notice Access control contract that provides admin-only functionality.
/// @dev This contract serves as a base contract for other Optimex contracts that need admin access control.
contract OptimexAdminGuard {
    /// @dev Address of the OptimexProtocol contract
    IOptimexProtocol internal _protocol;

    /**
        @notice Emitted when the OptimexProtocol address is updated.
        @param operator The address of the caller (owner) who performed the update.
        @param newProtocol The new OptimexProtocol contract address.
        @dev Related function: `setProtocol()`
    */
    event ProtocolUpdated(
        address indexed operator,
        address indexed newProtocol
    );

    modifier onlyAdmin() {
        address sender = msg.sender;
        if (sender != _getProtocol().owner())
            revert ErrorLib.Unauthorized(sender);
        _;
    }

    constructor(IOptimexProtocol protocol) {
        _protocol = protocol;
    }

    /**
        @notice Returns the current address of the OptimexProtocol contract.
        @dev Can be called by anyone.
        @return protocol The OptimexProtocol address.
    */
    function getProtocol() external view returns (address protocol) {
        protocol = address(_getProtocol());
    }

    /** 
        @notice Updates the OptimexProtocol contract to a new address.
        @dev Caller must be the current Admin of the OptimexProtocol contract.
        @param newProtocol The new OptimexProtocol contract address.
    */
    function setProtocol(address newProtocol) external onlyAdmin {
        if (newProtocol == address(0)) revert ErrorLib.ZeroAddress();

        _protocol = IOptimexProtocol(newProtocol);

        emit ProtocolUpdated(msg.sender, newProtocol);
    }

    function _isAuthorized(
        bytes32 role,
        address account
    ) internal view virtual returns (bool) {
        return _getProtocol().hasRole(role, account);
    }

    function _getProtocol() internal view virtual returns (IOptimexProtocol) {
        return _protocol;
    }
}
"
    },
    "contracts/protocol/OptimexDomain.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

/// @title Optimex Domain Information
/// @notice Provides a standardized way to expose the contract's name and version.
/// @dev Designed as an abstract base contract to be inherited by other Optimex contracts.
abstract contract OptimexDomain {
    /// @notice The name identifier for the Optimex contract domain.
    string internal _name;

    /// @notice The version identifier for the Optimex contract domain.
    string internal _version;

    constructor(string memory name, string memory version) {
        _name = name;
        _version = version;
    }

    /**
        @notice Returns the domain information of the Optimex contract.
        @dev Can be called by anyone
        @return name The name of the contract.
        @return version The current version of the contract.
    */
    function optimexDomain()
        external
        view
        virtual
        returns (string memory name, string memory version)
    {
        name = _name;
        version = _version;
    }
}
"
    }
  },
  "settings": {
    "viaIR": true,
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "evmVersion": "cancun",
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    }
  }
}}

Tags:
Factory|addr:0xf66dcec7f4570148f3f31eddb6edae1cd1aca880|verified:true|block:23587287|tx:0x817a6024932de1e5bdfdaf899185464f25dc8b4eaffbb7fe42f24ee8baeb047f|first_check:1760604648

Submitted on: 2025-10-16 10:50:51

Comments

Log in to comment.

No comments yet.