S Price: $0.769849 (-1.50%)

Contract Diff Checker

Contract Name:
DiamondLoupeFacet

Contract Source Code:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;
/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/

import {LibDiamond} from "../libraries/LibDiamond.sol";
import {IDiamondLoupe} from "../interfaces/IDiamondLoupe.sol";
import {IERC165} from "../interfaces/IERC165.sol";

// The functions in DiamondLoupeFacet MUST be added to a diamond.
// The EIP-2535 Diamond standard requires these functions.

contract DiamondLoupeFacet is IDiamondLoupe, IERC165 {
	// Diamond Loupe Functions
	////////////////////////////////////////////////////////////////////
	/// These functions are expected to be called frequently by tools.
	//
	// struct Facet {
	//     address facetAddress;
	//     bytes4[] functionSelectors;
	// }

	/// @notice Gets all facets and their selectors.
	/// @return facets_ Facet
	function facets() external view override returns (Facet[] memory facets_) {
		LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
		uint256 numFacets = ds.facetAddresses.length;
		facets_ = new Facet[](numFacets);
		for (uint256 i; i < numFacets; i++) {
			address facetAddress_ = ds.facetAddresses[i];
			facets_[i].facetAddress = facetAddress_;
			facets_[i].functionSelectors = ds
				.facetFunctionSelectors[facetAddress_]
				.functionSelectors;
		}
	}

	/// @notice Gets all the function selectors provided by a facet.
	/// @param _facet The facet address.
	/// @return facetFunctionSelectors_
	function facetFunctionSelectors(
		address _facet
	) external view override returns (bytes4[] memory facetFunctionSelectors_) {
		LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
		facetFunctionSelectors_ = ds
			.facetFunctionSelectors[_facet]
			.functionSelectors;
	}

	/// @notice Get all the facet addresses used by a diamond.
	/// @return facetAddresses_
	function facetAddresses()
		external
		view
		override
		returns (address[] memory facetAddresses_)
	{
		LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
		facetAddresses_ = ds.facetAddresses;
	}

	/// @notice Gets the facet that supports the given selector.
	/// @dev If facet is not found return address(0).
	/// @param _functionSelector The function selector.
	/// @return facetAddress_ The facet address.
	function facetAddress(
		bytes4 _functionSelector
	) external view override returns (address facetAddress_) {
		LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
		facetAddress_ = ds
			.selectorToFacetAndPosition[_functionSelector]
			.facetAddress;
	}

	// This implements ERC-165.
	function supportsInterface(
		bytes4 _interfaceId
	) external view override returns (bool) {
		LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
		return ds.supportedInterfaces[_interfaceId];
	}

	function addInterface(bytes4 _interfaceId) external {
		LibDiamond.enforceIsContractOwner();
		LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
		ds.supportedInterfaces[_interfaceId] = true;
	}
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;

/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/

interface IDiamondCut {
	enum FacetCutAction {
		Add,
		Replace,
		Remove
	}
	// Add=0, Replace=1, Remove=2

	struct FacetCut {
		address facetAddress;
		FacetCutAction action;
		bytes4[] functionSelectors;
	}

	/// @notice Add/replace/remove any number of functions and optionally execute
	///         a function with delegatecall
	/// @param _diamondCut Contains the facet addresses and function selectors
	/// @param _init The address of the contract or facet to execute _calldata
	/// @param _calldata A function call, including function selector and arguments
	///                  _calldata is executed with delegatecall on _init
	function diamondCut(
		FacetCut[] calldata _diamondCut,
		address _init,
		bytes calldata _calldata
	) external;

	event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;

/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/

// A loupe is a small magnifying glass used to look at diamonds.
// These functions look at diamonds
interface IDiamondLoupe {
	/// These functions are expected to be called frequently
	/// by tools.

	struct Facet {
		address facetAddress;
		bytes4[] functionSelectors;
	}

	/// @notice Gets all facet addresses and their four byte function selectors.
	/// @return facets_ Facet
	function facets() external view returns (Facet[] memory facets_);

	/// @notice Gets all the function selectors supported by a specific facet.
	/// @param _facet The facet address.
	/// @return facetFunctionSelectors_
	function facetFunctionSelectors(
		address _facet
	) external view returns (bytes4[] memory facetFunctionSelectors_);

	/// @notice Get all the facet addresses used by a diamond.
	/// @return facetAddresses_
	function facetAddresses()
		external
		view
		returns (address[] memory facetAddresses_);

	/// @notice Gets the facet that supports the given selector.
	/// @dev If facet is not found return address(0).
	/// @param _functionSelector The function selector.
	/// @return facetAddress_ The facet address.
	function facetAddress(
		bytes4 _functionSelector
	) external view returns (address facetAddress_);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;

interface IERC165 {
	/// @notice Query if a contract implements an interface
	/// @param interfaceId The interface identifier, as specified in ERC-165
	/// @dev Interface identification is specified in ERC-165. This function
	///  uses less than 30,000 gas.
	/// @return `true` if the contract implements `interfaceID` and
	///  `interfaceID` is not 0xffffffff, `false` otherwise
	function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;

/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/
import {IDiamondCut} from "../interfaces/IDiamondCut.sol";

// Remember to add the loupe functions from DiamondLoupeFacet to the diamond.
// The loupe functions are required by the EIP2535 Diamonds standard

error InitializationFunctionReverted(
	address _initializationContractAddress,
	bytes _calldata
);

library LibDiamond {
	bytes32 constant DIAMOND_STORAGE_POSITION =
		keccak256("diamond.standard.diamond.storage");

	struct FacetAddressAndPosition {
		address facetAddress;
		uint96 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array
	}

	struct FacetFunctionSelectors {
		bytes4[] functionSelectors;
		uint256 facetAddressPosition; // position of facetAddress in facetAddresses array
	}

	struct DiamondStorage {
		// maps function selector to the facet address and
		// the position of the selector in the facetFunctionSelectors.selectors array
		mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;
		// maps facet addresses to function selectors
		mapping(address => FacetFunctionSelectors) facetFunctionSelectors;
		// facet addresses
		address[] facetAddresses;
		// Used to query if a contract implements an interface.
		// Used to implement ERC-165.
		mapping(bytes4 => bool) supportedInterfaces;
		// owner of the contract
		address contractOwner;
		// owner of the diamond itself
		address diamondAddress;
	}

	function diamondStorage() internal pure returns (DiamondStorage storage ds) {
		bytes32 position = DIAMOND_STORAGE_POSITION;
		assembly {
			ds.slot := position
		}
	}

	event OwnershipTransferred(
		address indexed previousOwner,
		address indexed newOwner
	);

	function setContractOwner(address _newOwner) internal {
		DiamondStorage storage ds = diamondStorage();
		address previousOwner = ds.contractOwner;
		ds.contractOwner = _newOwner;
		emit OwnershipTransferred(previousOwner, _newOwner);
	}

	function contractOwner() internal view returns (address contractOwner_) {
		contractOwner_ = diamondStorage().contractOwner;
	}

	function enforceIsContractOwner() internal view {
		require(
			msg.sender == diamondStorage().contractOwner,
			"LibDiamond: Must be contract owner"
		);
	}

	function enforceDiamondItself() internal view {
		require(
			msg.sender == diamondStorage().diamondAddress,
			"LibDiamond: Must be the diamond"
		);
	}

	event DiamondCut(
		IDiamondCut.FacetCut[] _diamondCut,
		address _init,
		bytes _calldata
	);

	// Internal function version of diamondCut
	function diamondCut(
		IDiamondCut.FacetCut[] memory _diamondCut,
		address _init,
		bytes memory _calldata
	) internal {
		for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
			IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;
			if (action == IDiamondCut.FacetCutAction.Add) {
				addFunctions(
					_diamondCut[facetIndex].facetAddress,
					_diamondCut[facetIndex].functionSelectors
				);
			} else if (action == IDiamondCut.FacetCutAction.Replace) {
				replaceFunctions(
					_diamondCut[facetIndex].facetAddress,
					_diamondCut[facetIndex].functionSelectors
				);
			} else if (action == IDiamondCut.FacetCutAction.Remove) {
				removeFunctions(
					_diamondCut[facetIndex].facetAddress,
					_diamondCut[facetIndex].functionSelectors
				);
			} else {
				revert("LibDiamondCut: Incorrect FacetCutAction");
			}
		}
		emit DiamondCut(_diamondCut, _init, _calldata);
		initializeDiamondCut(_init, _calldata);
	}

	function addFunctions(
		address _facetAddress,
		bytes4[] memory _functionSelectors
	) internal {
		require(
			_functionSelectors.length > 0,
			"LibDiamondCut: No selectors in facet to cut"
		);
		DiamondStorage storage ds = diamondStorage();
		require(
			_facetAddress != address(0),
			"LibDiamondCut: Add facet can't be address(0)"
		);
		uint96 selectorPosition = uint96(
			ds.facetFunctionSelectors[_facetAddress].functionSelectors.length
		);
		// add new facet address if it does not exist
		if (selectorPosition == 0) {
			addFacet(ds, _facetAddress);
		}
		for (
			uint256 selectorIndex;
			selectorIndex < _functionSelectors.length;
			selectorIndex++
		) {
			bytes4 selector = _functionSelectors[selectorIndex];
			address oldFacetAddress = ds
				.selectorToFacetAndPosition[selector]
				.facetAddress;
			require(
				oldFacetAddress == address(0),
				"LibDiamondCut: Can't add function that already exists"
			);
			addFunction(ds, selector, selectorPosition, _facetAddress);
			selectorPosition++;
		}
	}

	function replaceFunctions(
		address _facetAddress,
		bytes4[] memory _functionSelectors
	) internal {
		require(
			_functionSelectors.length > 0,
			"LibDiamondCut: No selectors in facet to cut"
		);
		DiamondStorage storage ds = diamondStorage();
		require(
			_facetAddress != address(0),
			"LibDiamondCut: Add facet can't be address(0)"
		);
		uint96 selectorPosition = uint96(
			ds.facetFunctionSelectors[_facetAddress].functionSelectors.length
		);
		// add new facet address if it does not exist
		if (selectorPosition == 0) {
			addFacet(ds, _facetAddress);
		}
		for (
			uint256 selectorIndex;
			selectorIndex < _functionSelectors.length;
			selectorIndex++
		) {
			bytes4 selector = _functionSelectors[selectorIndex];
			address oldFacetAddress = ds
				.selectorToFacetAndPosition[selector]
				.facetAddress;
			require(
				oldFacetAddress != _facetAddress,
				"LibDiamondCut: Can't replace function with same function"
			);
			removeFunction(ds, oldFacetAddress, selector);
			addFunction(ds, selector, selectorPosition, _facetAddress);
			selectorPosition++;
		}
	}

	function removeFunctions(
		address _facetAddress,
		bytes4[] memory _functionSelectors
	) internal {
		require(
			_functionSelectors.length > 0,
			"LibDiamondCut: No selectors in facet to cut"
		);
		DiamondStorage storage ds = diamondStorage();
		// if function does not exist then do nothing and return
		require(
			_facetAddress == address(0),
			"LibDiamondCut: Remove facet address must be address(0)"
		);
		for (
			uint256 selectorIndex;
			selectorIndex < _functionSelectors.length;
			selectorIndex++
		) {
			bytes4 selector = _functionSelectors[selectorIndex];
			address oldFacetAddress = ds
				.selectorToFacetAndPosition[selector]
				.facetAddress;
			removeFunction(ds, oldFacetAddress, selector);
		}
	}

	function addFacet(DiamondStorage storage ds, address _facetAddress) internal {
		enforceHasContractCode(
			_facetAddress,
			"LibDiamondCut: New facet has no code"
		);
		ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = ds
			.facetAddresses
			.length;
		ds.facetAddresses.push(_facetAddress);
	}

	function addFunction(
		DiamondStorage storage ds,
		bytes4 _selector,
		uint96 _selectorPosition,
		address _facetAddress
	) internal {
		ds
			.selectorToFacetAndPosition[_selector]
			.functionSelectorPosition = _selectorPosition;
		ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(_selector);
		ds.selectorToFacetAndPosition[_selector].facetAddress = _facetAddress;
	}

	function removeFunction(
		DiamondStorage storage ds,
		address _facetAddress,
		bytes4 _selector
	) internal {
		require(
			_facetAddress != address(0),
			"LibDiamondCut: Can't remove function that doesn't exist"
		);
		// an immutable function is a function defined directly in a diamond
		require(
			_facetAddress != address(this),
			"LibDiamondCut: Can't remove immutable function"
		);
		// replace selector with last selector, then delete last selector
		uint256 selectorPosition = ds
			.selectorToFacetAndPosition[_selector]
			.functionSelectorPosition;
		uint256 lastSelectorPosition = ds
			.facetFunctionSelectors[_facetAddress]
			.functionSelectors
			.length - 1;
		// if not the same then replace _selector with lastSelector
		if (selectorPosition != lastSelectorPosition) {
			bytes4 lastSelector = ds
				.facetFunctionSelectors[_facetAddress]
				.functionSelectors[lastSelectorPosition];
			ds.facetFunctionSelectors[_facetAddress].functionSelectors[
					selectorPosition
				] = lastSelector;
			ds
				.selectorToFacetAndPosition[lastSelector]
				.functionSelectorPosition = uint96(selectorPosition);
		}
		// delete the last selector
		ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();
		delete ds.selectorToFacetAndPosition[_selector];

		// if no more selectors for facet address then delete the facet address
		if (lastSelectorPosition == 0) {
			// replace facet address with last facet address and delete last facet address
			uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;
			uint256 facetAddressPosition = ds
				.facetFunctionSelectors[_facetAddress]
				.facetAddressPosition;
			if (facetAddressPosition != lastFacetAddressPosition) {
				address lastFacetAddress = ds.facetAddresses[lastFacetAddressPosition];
				ds.facetAddresses[facetAddressPosition] = lastFacetAddress;
				ds
					.facetFunctionSelectors[lastFacetAddress]
					.facetAddressPosition = facetAddressPosition;
			}
			ds.facetAddresses.pop();
			delete ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
		}
	}

	function initializeDiamondCut(
		address _init,
		bytes memory _calldata
	) internal {
		if (_init == address(0)) {
			return;
		}
		enforceHasContractCode(_init, "LibDiamondCut: _init address has no code");
		(bool success, bytes memory error) = _init.delegatecall(_calldata);
		if (!success) {
			if (error.length > 0) {
				// bubble up error
				/// @solidity memory-safe-assembly
				assembly {
					let returndata_size := mload(error)
					revert(add(32, error), returndata_size)
				}
			} else {
				revert InitializationFunctionReverted(_init, _calldata);
			}
		}
	}

	function enforceHasContractCode(
		address _contract,
		string memory _errorMessage
	) internal view {
		uint256 contractSize;
		assembly {
			contractSize := extcodesize(_contract)
		}
		require(contractSize > 0, _errorMessage);
	}
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):