// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import "../IListingConfiguratorController.sol"; import "../IListingConfigurator.sol"; import "./mechanics/reward/IERC20RewardAware.sol"; import "./mechanics/renting/IIsRentableListing.sol"; import "./mechanics/listing/ICanListAssets.sol"; contract ListingConfiguratorController is IListingConfiguratorController, ERC165 { using Listings for IListingTermsRegistry.ListingTerms; function validateListing( Assets.Asset[] calldata assets, Listings.Params calldata params, uint32 maxLockPeriod, bool immediatePayout ) external view { if (params.configurator == address(0)) return; _validateListingMechanics(assets, params, maxLockPeriod, immediatePayout); } function validateRenting( Rentings.Params calldata params, Listings.Listing calldata listing, uint256 universeId ) external view override { if (listing.configurator == address(0)) return; _validateRentingMechanics(params, listing, universeId); _validateListingTerms(params, listing, universeId); } function getERC20RewardTarget(Listings.Listing calldata listing) external view override returns (address) { address defaultTarget = listing.lister; if (listing.configurator == address(0)) return defaultTarget; bytes4[] memory mechanics = new bytes4[](1); mechanics[0] = type(IERC20RewardAware).interfaceId; bool[] memory supportedMechanics = IListingConfigurator(listing.configurator).__supportedInterfaces(mechanics); if (supportedMechanics[0]) { address target = IERC20RewardAware(listing.configurator).__getRewardTarget(listing); if (target != address(0)) return target; } return defaultTarget; } function supportsInterface(bytes4 interfaceId) public view override(IERC165, ERC165) returns (bool) { return interfaceId == type(IListingConfiguratorController).interfaceId || super.supportsInterface(interfaceId); } function _validateListingMechanics( Assets.Asset[] calldata assets, Listings.Params calldata params, uint32 maxLockPeriod, bool immediatePayout ) internal view { bytes4[] memory mechanics = new bytes4[](1); mechanics[0] = type(ICanListAssets).interfaceId; bool[] memory supportedMechanics = IListingConfigurator(params.configurator).__supportedInterfaces(mechanics); if (supportedMechanics[0]) { (bool canList, string memory errorMessage) = ICanListAssets(params.configurator).__canListAssets( assets, params, maxLockPeriod, immediatePayout ); if (!canList) { revert ICanListAssets.AssetsAreNotListable(errorMessage); } } } function _validateRentingMechanics( Rentings.Params calldata params, Listings.Listing calldata listing, uint256 universeId ) internal view { bytes4[] memory mechanics = new bytes4[](1); mechanics[0] = type(IIsRentableListing).interfaceId; bool[] memory supportedMechanics = IListingConfigurator(listing.configurator).__supportedInterfaces(mechanics); if (supportedMechanics[0]) { (bool isRentable, string memory errorMessage) = IIsRentableListing(listing.configurator) .__isRentableListing(params, listing, universeId); if (!isRentable) { revert IIsRentableListing.ListingIsNotRentable(errorMessage); } } } function _validateListingTerms( Rentings.Params calldata params, Listings.Listing calldata listing, uint256 universeId ) internal view { IListingTermsRegistry.ListingTerms[] memory listingTerms = IListingConfigurator(listing.configurator) .__getListingTerms(params, listing, universeId); bytes32 configHash = params.selectedConfiguratorListingTerms.hash(); for (uint256 i = 0; i < listingTerms.length; i++) { if (configHash == listingTerms[i].hash()) return; } revert ListingTermsNotFound(params.selectedConfiguratorListingTerms); } }