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"
]
}
}
}
}}
Submitted on: 2025-10-16 10:50:51
Comments
Log in to comment.
No comments yet.