// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/******************************************************************************\
* Author: Nick Mudge <nick@perfectabstractions.com> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
*
* Implementation of a diamond.
/******************************************************************************/import { LibDiamond } from"./libraries/LibDiamond.sol";
import { IDiamondCut } from"./interfaces/IDiamondCut.sol";
contractDiamond{
constructor(address _contractOwner, address _diamondCutFacet) payable{
LibDiamond.setContractOwner(_contractOwner);
// Add the diamondCut external function from the diamondCutFacet
IDiamondCut.FacetCut[] memory cut =new IDiamondCut.FacetCut[](1);
bytes4[] memory functionSelectors =newbytes4[](1);
functionSelectors[0] = IDiamondCut.diamondCut.selector;
cut[0] = IDiamondCut.FacetCut({
facetAddress: _diamondCutFacet,
action: IDiamondCut.FacetCutAction.Add,
functionSelectors: functionSelectors
});
LibDiamond.diamondCut(cut, address(0), "");
}
// Find facet for function that is called and execute the// function if a facet is found and return any value.fallback() externalpayable{
LibDiamond.DiamondStorage storage ds;
bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION;
// get diamond storageassembly {
ds.slot:= position
}
// get facet from function selectoraddress facet =address(bytes20(ds.facets[msg.sig]));
require(facet !=address(0), "Diamond: Function does not exist");
// Execute external function from facet using delegatecall and return any value.assembly {
// copy function selector and any argumentscalldatacopy(0, 0, calldatasize())
// execute function call using the facetlet result :=delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
// get any return valuereturndatacopy(0, 0, returndatasize())
// return any return value or error back to the callerswitch result
case0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
receive() externalpayable{}
}
Contract Source Code
File 2 of 10: DiamondCutFacet.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/******************************************************************************\
* Author: Nick Mudge <nick@perfectabstractions.com> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/import { IDiamondCut } from"../interfaces/IDiamondCut.sol";
import { LibDiamond } from"../libraries/LibDiamond.sol";
// Remember to add the loupe functions from DiamondLoupeFacet to the diamond.// The loupe functions are required by the EIP2535 Diamonds standardcontractDiamondCutFacetisIDiamondCut{
/// @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 _initfunctiondiamondCut(
FacetCut[] calldata _diamondCut,
address _init,
bytescalldata _calldata
) externaloverride{
LibDiamond.enforceIsContractOwner();
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
uint256 originalSelectorCount = ds.selectorCount;
uint256 selectorCount = originalSelectorCount;
bytes32 selectorSlot;
// Check if last selector slot is not full// "selectorCount & 7" is a gas efficient modulo by eight "selectorCount % 8" if (selectorCount &7>0) {
// get last selectorSlot// "selectorCount >> 3" is a gas efficient division by 8 "selectorCount / 8"
selectorSlot = ds.selectorSlots[selectorCount >>3];
}
// loop through diamond cutfor (uint256 facetIndex; facetIndex < _diamondCut.length; ) {
(selectorCount, selectorSlot) = LibDiamond.addReplaceRemoveFacetSelectors(
selectorCount,
selectorSlot,
_diamondCut[facetIndex].facetAddress,
_diamondCut[facetIndex].action,
_diamondCut[facetIndex].functionSelectors
);
unchecked {
facetIndex++;
}
}
if (selectorCount != originalSelectorCount) {
ds.selectorCount =uint16(selectorCount);
}
// If last selector slot is not full// "selectorCount & 7" is a gas efficient modulo by eight "selectorCount % 8" if (selectorCount &7>0) {
// "selectorCount >> 3" is a gas efficient division by 8 "selectorCount / 8"
ds.selectorSlots[selectorCount >>3] = selectorSlot;
}
emit DiamondCut(_diamondCut, _init, _calldata);
LibDiamond.initializeDiamondCut(_init, _calldata);
}
}
Contract Source Code
File 3 of 10: DiamondLoupeFacet.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/******************************************************************************\
* Author: Nick Mudge <nick@perfectabstractions.com> (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 functionscontractDiamondLoupeFacetisIDiamondLoupe, 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_ Facetfunctionfacets() externaloverrideviewreturns (Facet[] memory facets_) {
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
facets_ =new Facet[](ds.selectorCount);
uint16[] memory numFacetSelectors =newuint16[](ds.selectorCount);
uint256 numFacets;
uint256 selectorIndex;
// loop through function selectorsfor (uint256 slotIndex; selectorIndex < ds.selectorCount; slotIndex++) {
bytes32 slot = ds.selectorSlots[slotIndex];
for (uint256 selectorSlotIndex; selectorSlotIndex <8; selectorSlotIndex++) {
selectorIndex++;
if (selectorIndex > ds.selectorCount) {
break;
}
// " << 5 is the same as multiplying by 32 ( * 32)bytes4 selector =bytes4(slot << (selectorSlotIndex <<5));
address facetAddress_ =address(bytes20(ds.facets[selector]));
bool continueLoop;
for (uint256 facetIndex; facetIndex < numFacets; facetIndex++) {
if (facets_[facetIndex].facetAddress == facetAddress_) {
facets_[facetIndex].functionSelectors[numFacetSelectors[facetIndex]] = selector;
// probably will never have more than 256 functions from one facet contractrequire(numFacetSelectors[facetIndex] <255);
numFacetSelectors[facetIndex]++;
continueLoop =true;
break;
}
}
if (continueLoop) {
continue;
}
facets_[numFacets].facetAddress = facetAddress_;
facets_[numFacets].functionSelectors =newbytes4[](ds.selectorCount);
facets_[numFacets].functionSelectors[0] = selector;
numFacetSelectors[numFacets] =1;
numFacets++;
}
}
for (uint256 facetIndex; facetIndex < numFacets; facetIndex++) {
uint256 numSelectors = numFacetSelectors[facetIndex];
bytes4[] memory selectors = facets_[facetIndex].functionSelectors;
// setting the number of selectorsassembly {
mstore(selectors, numSelectors)
}
}
// setting the number of facetsassembly {
mstore(facets_, numFacets)
}
}
/// @notice Gets all the function selectors supported by a specific facet./// @param _facet The facet address./// @return _facetFunctionSelectors The selectors associated with a facet address.functionfacetFunctionSelectors(address _facet) externaloverrideviewreturns (bytes4[] memory _facetFunctionSelectors) {
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
uint256 numSelectors;
_facetFunctionSelectors =newbytes4[](ds.selectorCount);
uint256 selectorIndex;
// loop through function selectorsfor (uint256 slotIndex; selectorIndex < ds.selectorCount; slotIndex++) {
bytes32 slot = ds.selectorSlots[slotIndex];
for (uint256 selectorSlotIndex; selectorSlotIndex <8; selectorSlotIndex++) {
selectorIndex++;
if (selectorIndex > ds.selectorCount) {
break;
}
// " << 5 is the same as multiplying by 32 ( * 32)bytes4 selector =bytes4(slot << (selectorSlotIndex <<5));
address facet =address(bytes20(ds.facets[selector]));
if (_facet == facet) {
_facetFunctionSelectors[numSelectors] = selector;
numSelectors++;
}
}
}
// Set the number of selectors in the arrayassembly {
mstore(_facetFunctionSelectors, numSelectors)
}
}
/// @notice Get all the facet addresses used by a diamond./// @return facetAddresses_functionfacetAddresses() externaloverrideviewreturns (address[] memory facetAddresses_) {
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
facetAddresses_ =newaddress[](ds.selectorCount);
uint256 numFacets;
uint256 selectorIndex;
// loop through function selectorsfor (uint256 slotIndex; selectorIndex < ds.selectorCount; slotIndex++) {
bytes32 slot = ds.selectorSlots[slotIndex];
for (uint256 selectorSlotIndex; selectorSlotIndex <8; selectorSlotIndex++) {
selectorIndex++;
if (selectorIndex > ds.selectorCount) {
break;
}
// " << 5 is the same as multiplying by 32 ( * 32)bytes4 selector =bytes4(slot << (selectorSlotIndex <<5));
address facetAddress_ =address(bytes20(ds.facets[selector]));
bool continueLoop;
for (uint256 facetIndex; facetIndex < numFacets; facetIndex++) {
if (facetAddress_ == facetAddresses_[facetIndex]) {
continueLoop =true;
break;
}
}
if (continueLoop) {
continue;
}
facetAddresses_[numFacets] = facetAddress_;
numFacets++;
}
}
// Set the number of facet addresses in the arrayassembly {
mstore(facetAddresses_, numFacets)
}
}
/// @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.functionfacetAddress(bytes4 _functionSelector) externaloverrideviewreturns (address facetAddress_) {
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
facetAddress_ =address(bytes20(ds.facets[_functionSelector]));
}
// This implements ERC-165.functionsupportsInterface(bytes4 _interfaceId) externaloverrideviewreturns (bool) {
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
return ds.supportedInterfaces[_interfaceId];
}
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/******************************************************************************\
* Author: Nick Mudge <nick@perfectabstractions.com> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/interfaceIDiamondCut{
enumFacetCutAction {Add, Replace, Remove}
// Add=0, Replace=1, Remove=2structFacetCut {
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 _initfunctiondiamondCut(
FacetCut[] calldata _diamondCut,
address _init,
bytescalldata _calldata
) external;
eventDiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
}
Contract Source Code
File 6 of 10: IDiamondLoupe.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/******************************************************************************\
* Author: Nick Mudge <nick@perfectabstractions.com> (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 diamondsinterfaceIDiamondLoupe{
/// These functions are expected to be called frequently/// by tools.structFacet {
address facetAddress;
bytes4[] functionSelectors;
}
/// @notice Gets all facet addresses and their four byte function selectors./// @return facets_ Facetfunctionfacets() externalviewreturns (Facet[] memory facets_);
/// @notice Gets all the function selectors supported by a specific facet./// @param _facet The facet address./// @return facetFunctionSelectors_functionfacetFunctionSelectors(address _facet) externalviewreturns (bytes4[] memory facetFunctionSelectors_);
/// @notice Get all the facet addresses used by a diamond./// @return facetAddresses_functionfacetAddresses() externalviewreturns (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.functionfacetAddress(bytes4 _functionSelector) externalviewreturns (address facetAddress_);
}
Contract Source Code
File 7 of 10: IERC165.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;interfaceIERC165{
/// @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` otherwisefunctionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
Contract Source Code
File 8 of 10: IERC173.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/// @title ERC-173 Contract Ownership Standard/// Note: the ERC-165 identifier for this interface is 0x7f5828d0/* is ERC165 */interfaceIERC173{
/// @dev This emits when ownership of a contract changes.eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/// @notice Get the address of the owner/// @return owner_ The address of the owner.functionowner() externalviewreturns (address owner_);
/// @notice Set the address of the new owner of the contract/// @dev Set _newOwner to address(0) to renounce any ownership./// @param _newOwner The address of the new owner of the contractfunctiontransferOwnership(address _newOwner) external;
}
Contract Source Code
File 9 of 10: LibDiamond.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/******************************************************************************\
* Author: Nick Mudge <nick@perfectabstractions.com> (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 standarderrorInitializationFunctionReverted(address _initializationContractAddress, bytes _calldata);
libraryLibDiamond{
bytes32constant DIAMOND_STORAGE_POSITION =keccak256("diamond.standard.diamond.storage");
structDiamondStorage {
// maps function selectors to the facets that execute the functions.// and maps the selectors to their position in the selectorSlots array.// func selector => address facet, selector positionmapping(bytes4=>bytes32) facets;
// array of slots of function selectors.// each slot holds 8 function selectors.mapping(uint256=>bytes32) selectorSlots;
// The number of function selectors in selectorSlotsuint16 selectorCount;
// Used to query if a contract implements an interface.// Used to implement ERC-165.mapping(bytes4=>bool) supportedInterfaces;
// owner of the contractaddress contractOwner;
}
functiondiamondStorage() internalpurereturns (DiamondStorage storage ds) {
bytes32 position = DIAMOND_STORAGE_POSITION;
assembly {
ds.slot:= position
}
}
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
functionsetContractOwner(address _newOwner) internal{
DiamondStorage storage ds = diamondStorage();
address previousOwner = ds.contractOwner;
ds.contractOwner = _newOwner;
emit OwnershipTransferred(previousOwner, _newOwner);
}
functioncontractOwner() internalviewreturns (address contractOwner_) {
contractOwner_ = diamondStorage().contractOwner;
}
functionenforceIsContractOwner() internalview{
require(msg.sender== diamondStorage().contractOwner, "LibDiamond: Must be contract owner");
}
eventDiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);
bytes32constant CLEAR_ADDRESS_MASK =bytes32(uint256(0xffffffffffffffffffffffff));
bytes32constant CLEAR_SELECTOR_MASK =bytes32(uint256(0xffffffff<<224));
// Internal function version of diamondCut// This code is almost the same as the external diamondCut,// except it is using 'Facet[] memory _diamondCut' instead of// 'Facet[] calldata _diamondCut'.// The code is duplicated to prevent copying calldata to memory which// causes an error for a two dimensional array.functiondiamondCut(
IDiamondCut.FacetCut[] memory _diamondCut,
address _init,
bytesmemory _calldata
) internal{
DiamondStorage storage ds = diamondStorage();
uint256 originalSelectorCount = ds.selectorCount;
uint256 selectorCount = originalSelectorCount;
bytes32 selectorSlot;
// Check if last selector slot is not full// "selectorCount & 7" is a gas efficient modulo by eight "selectorCount % 8" if (selectorCount &7>0) {
// get last selectorSlot// "selectorSlot >> 3" is a gas efficient division by 8 "selectorSlot / 8"
selectorSlot = ds.selectorSlots[selectorCount >>3];
}
// loop through diamond cutfor (uint256 facetIndex; facetIndex < _diamondCut.length; ) {
(selectorCount, selectorSlot) = addReplaceRemoveFacetSelectors(
selectorCount,
selectorSlot,
_diamondCut[facetIndex].facetAddress,
_diamondCut[facetIndex].action,
_diamondCut[facetIndex].functionSelectors
);
unchecked {
facetIndex++;
}
}
if (selectorCount != originalSelectorCount) {
ds.selectorCount =uint16(selectorCount);
}
// If last selector slot is not full// "selectorCount & 7" is a gas efficient modulo by eight "selectorCount % 8" if (selectorCount &7>0) {
// "selectorSlot >> 3" is a gas efficient division by 8 "selectorSlot / 8"
ds.selectorSlots[selectorCount >>3] = selectorSlot;
}
emit DiamondCut(_diamondCut, _init, _calldata);
initializeDiamondCut(_init, _calldata);
}
functionaddReplaceRemoveFacetSelectors(uint256 _selectorCount,
bytes32 _selectorSlot,
address _newFacetAddress,
IDiamondCut.FacetCutAction _action,
bytes4[] memory _selectors
) internalreturns (uint256, bytes32) {
DiamondStorage storage ds = diamondStorage();
require(_selectors.length>0, "LibDiamondCut: No selectors in facet to cut");
if (_action == IDiamondCut.FacetCutAction.Add) {
enforceHasContractCode(_newFacetAddress, "LibDiamondCut: Add facet has no code");
for (uint256 selectorIndex; selectorIndex < _selectors.length; ) {
bytes4 selector = _selectors[selectorIndex];
bytes32 oldFacet = ds.facets[selector];
require(address(bytes20(oldFacet)) ==address(0), "LibDiamondCut: Can't add function that already exists");
// add facet for selector
ds.facets[selector] =bytes20(_newFacetAddress) |bytes32(_selectorCount);
// "_selectorCount & 7" is a gas efficient modulo by eight "_selectorCount % 8" // " << 5 is the same as multiplying by 32 ( * 32)uint256 selectorInSlotPosition = (_selectorCount &7) <<5;
// clear selector position in slot and add selector
_selectorSlot = (_selectorSlot &~(CLEAR_SELECTOR_MASK >> selectorInSlotPosition)) | (bytes32(selector) >> selectorInSlotPosition);
// if slot is full then write it to storageif (selectorInSlotPosition ==224) {
// "_selectorSlot >> 3" is a gas efficient division by 8 "_selectorSlot / 8"
ds.selectorSlots[_selectorCount >>3] = _selectorSlot;
_selectorSlot =0;
}
_selectorCount++;
unchecked {
selectorIndex++;
}
}
} elseif (_action == IDiamondCut.FacetCutAction.Replace) {
enforceHasContractCode(_newFacetAddress, "LibDiamondCut: Replace facet has no code");
for (uint256 selectorIndex; selectorIndex < _selectors.length; ) {
bytes4 selector = _selectors[selectorIndex];
bytes32 oldFacet = ds.facets[selector];
address oldFacetAddress =address(bytes20(oldFacet));
// only useful if immutable functions existrequire(oldFacetAddress !=address(this), "LibDiamondCut: Can't replace immutable function");
require(oldFacetAddress != _newFacetAddress, "LibDiamondCut: Can't replace function with same function");
require(oldFacetAddress !=address(0), "LibDiamondCut: Can't replace function that doesn't exist");
// replace old facet address
ds.facets[selector] = (oldFacet & CLEAR_ADDRESS_MASK) |bytes20(_newFacetAddress);
unchecked {
selectorIndex++;
}
}
} elseif (_action == IDiamondCut.FacetCutAction.Remove) {
require(_newFacetAddress ==address(0), "LibDiamondCut: Remove facet address must be address(0)");
// "_selectorCount >> 3" is a gas efficient division by 8 "_selectorCount / 8"uint256 selectorSlotCount = _selectorCount >>3;
// "_selectorCount & 7" is a gas efficient modulo by eight "_selectorCount % 8" uint256 selectorInSlotIndex = _selectorCount &7;
for (uint256 selectorIndex; selectorIndex < _selectors.length; ) {
if (_selectorSlot ==0) {
// get last selectorSlot
selectorSlotCount--;
_selectorSlot = ds.selectorSlots[selectorSlotCount];
selectorInSlotIndex =7;
} else {
selectorInSlotIndex--;
}
bytes4 lastSelector;
uint256 oldSelectorsSlotCount;
uint256 oldSelectorInSlotPosition;
// adding a block here prevents stack too deep error
{
bytes4 selector = _selectors[selectorIndex];
bytes32 oldFacet = ds.facets[selector];
require(address(bytes20(oldFacet)) !=address(0), "LibDiamondCut: Can't remove function that doesn't exist");
// only useful if immutable functions existrequire(address(bytes20(oldFacet)) !=address(this), "LibDiamondCut: Can't remove immutable function");
// replace selector with last selector in ds.facets// gets the last selector// " << 5 is the same as multiplying by 32 ( * 32)
lastSelector =bytes4(_selectorSlot << (selectorInSlotIndex <<5));
if (lastSelector != selector) {
// update last selector slot position info
ds.facets[lastSelector] = (oldFacet & CLEAR_ADDRESS_MASK) |bytes20(ds.facets[lastSelector]);
}
delete ds.facets[selector];
uint256 oldSelectorCount =uint16(uint256(oldFacet));
// "oldSelectorCount >> 3" is a gas efficient division by 8 "oldSelectorCount / 8"
oldSelectorsSlotCount = oldSelectorCount >>3;
// "oldSelectorCount & 7" is a gas efficient modulo by eight "oldSelectorCount % 8" // " << 5 is the same as multiplying by 32 ( * 32)
oldSelectorInSlotPosition = (oldSelectorCount &7) <<5;
}
if (oldSelectorsSlotCount != selectorSlotCount) {
bytes32 oldSelectorSlot = ds.selectorSlots[oldSelectorsSlotCount];
// clears the selector we are deleting and puts the last selector in its place.
oldSelectorSlot =
(oldSelectorSlot &~(CLEAR_SELECTOR_MASK >> oldSelectorInSlotPosition)) |
(bytes32(lastSelector) >> oldSelectorInSlotPosition);
// update storage with the modified slot
ds.selectorSlots[oldSelectorsSlotCount] = oldSelectorSlot;
} else {
// clears the selector we are deleting and puts the last selector in its place.
_selectorSlot =
(_selectorSlot &~(CLEAR_SELECTOR_MASK >> oldSelectorInSlotPosition)) |
(bytes32(lastSelector) >> oldSelectorInSlotPosition);
}
if (selectorInSlotIndex ==0) {
delete ds.selectorSlots[selectorSlotCount];
_selectorSlot =0;
}
unchecked {
selectorIndex++;
}
}
_selectorCount = selectorSlotCount *8+ selectorInSlotIndex;
} else {
revert("LibDiamondCut: Incorrect FacetCutAction");
}
return (_selectorCount, _selectorSlot);
}
functioninitializeDiamondCut(address _init, bytesmemory _calldata) internal{
if (_init ==address(0)) {
return;
}
enforceHasContractCode(_init, "LibDiamondCut: _init address has no code");
(bool success, bytesmemoryerror) = _init.delegatecall(_calldata);
if (!success) {
if (error.length>0) {
// bubble up error/// @solidity memory-safe-assemblyassembly {
let returndata_size :=mload(error)
revert(add(32, error), returndata_size)
}
} else {
revert InitializationFunctionReverted(_init, _calldata);
}
}
}
functionenforceHasContractCode(address _contract, stringmemory _errorMessage) internalview{
uint256 contractSize;
assembly {
contractSize :=extcodesize(_contract)
}
require(contractSize >0, _errorMessage);
}
}