// SPDX-License-Identifier: Apache-2.0pragmasolidity 0.7.6;pragmaexperimentalABIEncoderV2;import"./interfaces/IDiamondCut.sol";
import"./interfaces/IDiamondLoupe.sol";
import"./libraries/LibDiamond.sol";
import"./libraries/LibOwnership.sol";
import"./libraries/LibDiamondStorage.sol";
import"./interfaces/IERC165.sol";
import"./interfaces/IERC173.sol";
contractComitium{
constructor(IDiamondCut.FacetCut[] memory _diamondCut, address _owner) payable{
require(_owner !=address(0), "owner must not be 0x0");
LibDiamond.diamondCut(_diamondCut, address(0), newbytes(0));
LibOwnership.setContractOwner(_owner);
LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage.diamondStorage();
// adding ERC165 data
ds.supportedInterfaces[type(IERC165).interfaceId] =true;
ds.supportedInterfaces[type(IDiamondCut).interfaceId] =true;
ds.supportedInterfaces[type(IDiamondLoupe).interfaceId] =true;
ds.supportedInterfaces[type(IERC173).interfaceId] =true;
}
// Find facet for function that is called and execute the// function if a facet is found and return any value.fallback() externalpayable{
LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage.diamondStorage();
address facet =address(bytes20(ds.facets[msg.sig].facetAddress));
require(facet !=address(0), "Diamond: Function does not exist");
assembly {
calldatacopy(0, 0, calldatasize())
let result :=delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case0 {
revert(0, returndatasize())
}
default {
return (0, returndatasize())
}
}
}
receive() externalpayable{}
}
Contract Source Code
File 2 of 8: IDiamondCut.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity 0.7.6;pragmaexperimentalABIEncoderV2;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 3 of 8: IDiamondLoupe.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity 0.7.6;pragmaexperimentalABIEncoderV2;// 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 4 of 8: IERC165.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity 0.7.6;pragmaexperimentalABIEncoderV2;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 5 of 8: IERC173.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity 0.7.6;/// @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 6 of 8: LibDiamond.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity 0.7.6;pragmaexperimentalABIEncoderV2;import"../interfaces/IDiamondCut.sol";
import"./LibDiamondStorage.sol";
libraryLibDiamond{
eventDiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);
// 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{
uint256 selectorCount = LibDiamondStorage.diamondStorage().selectors.length;
for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
selectorCount = executeDiamondCut(selectorCount, _diamondCut[facetIndex]);
}
emit DiamondCut(_diamondCut, _init, _calldata);
initializeDiamondCut(_init, _calldata);
}
// executeDiamondCut takes one single FacetCut action and executes it// if FacetCutAction can't be identified, it revertsfunctionexecuteDiamondCut(uint256 selectorCount, IDiamondCut.FacetCut memory cut) internalreturns (uint256) {
require(cut.functionSelectors.length>0, "LibDiamond: No selectors in facet to cut");
if (cut.action == IDiamondCut.FacetCutAction.Add) {
require(cut.facetAddress !=address(0), "LibDiamond: add facet address can't be address(0)");
enforceHasContractCode(cut.facetAddress, "LibDiamond: add facet must have code");
return _handleAddCut(selectorCount, cut);
}
if (cut.action == IDiamondCut.FacetCutAction.Replace) {
require(cut.facetAddress !=address(0), "LibDiamond: remove facet address can't be address(0)");
enforceHasContractCode(cut.facetAddress, "LibDiamond: remove facet must have code");
return _handleReplaceCut(selectorCount, cut);
}
if (cut.action == IDiamondCut.FacetCutAction.Remove) {
require(cut.facetAddress ==address(0), "LibDiamond: remove facet address must be address(0)");
return _handleRemoveCut(selectorCount, cut);
}
revert("LibDiamondCut: Incorrect FacetCutAction");
}
// _handleAddCut executes a cut with the type Add// it reverts if the selector already existsfunction_handleAddCut(uint256 selectorCount, IDiamondCut.FacetCut memory cut) internalreturns (uint256) {
LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage.diamondStorage();
for (uint256 selectorIndex; selectorIndex < cut.functionSelectors.length; selectorIndex++) {
bytes4 selector = cut.functionSelectors[selectorIndex];
address oldFacetAddress = ds.facets[selector].facetAddress;
require(oldFacetAddress ==address(0), "LibDiamondCut: Can't add function that already exists");
ds.facets[selector] = LibDiamondStorage.Facet(
cut.facetAddress,
uint16(selectorCount)
);
ds.selectors.push(selector);
selectorCount++;
}
return selectorCount;
}
// _handleReplaceCut executes a cut with the type Replace// it does not allow replacing immutable functions// it does not allow replacing with the same function// it does not allow replacing a function that does not existfunction_handleReplaceCut(uint256 selectorCount, IDiamondCut.FacetCut memory cut) internalreturns (uint256) {
LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage.diamondStorage();
for (uint256 selectorIndex; selectorIndex < cut.functionSelectors.length; selectorIndex++) {
bytes4 selector = cut.functionSelectors[selectorIndex];
address oldFacetAddress = ds.facets[selector].facetAddress;
// only useful if immutable functions existrequire(oldFacetAddress !=address(this), "LibDiamondCut: Can't replace immutable function");
require(oldFacetAddress != cut.facetAddress, "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].facetAddress = cut.facetAddress;
}
return selectorCount;
}
// _handleRemoveCut executes a cut with the type Remove// for efficiency, the selector to be deleted is replaced with the last one and then the last one is popped// it reverts if the function doesn't exist or it's immutablefunction_handleRemoveCut(uint256 selectorCount, IDiamondCut.FacetCut memory cut) internalreturns (uint256) {
LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage.diamondStorage();
for (uint256 selectorIndex; selectorIndex < cut.functionSelectors.length; selectorIndex++) {
bytes4 selector = cut.functionSelectors[selectorIndex];
LibDiamondStorage.Facet memory oldFacet = ds.facets[selector];
require(oldFacet.facetAddress !=address(0), "LibDiamondCut: Can't remove function that doesn't exist");
require(oldFacet.facetAddress !=address(this), "LibDiamondCut: Can't remove immutable function.");
// replace selector with last selectorif (oldFacet.selectorPosition != selectorCount -1) {
bytes4 lastSelector = ds.selectors[selectorCount -1];
ds.selectors[oldFacet.selectorPosition] = lastSelector;
ds.facets[lastSelector].selectorPosition = oldFacet.selectorPosition;
}
// delete last selector
ds.selectors.pop();
delete ds.facets[selector];
selectorCount--;
}
return selectorCount;
}
functioninitializeDiamondCut(address _init, bytesmemory _calldata) internal{
if (_init ==address(0)) {
require(_calldata.length==0, "LibDiamondCut: _init is address(0) but _calldata is not empty");
return;
}
require(_calldata.length>0, "LibDiamondCut: _calldata is empty but _init is not address(0)");
if (_init !=address(this)) {
enforceHasContractCode(_init, "LibDiamondCut: _init address has no code");
}
(bool success, bytesmemoryerror) = _init.delegatecall(_calldata);
if (!success) {
if (error.length>0) {
// bubble up the errorrevert(string(error));
} else {
revert("LibDiamondCut: _init function reverted");
}
}
}
functionenforceHasContractCode(address _contract, stringmemory _errorMessage) internalview{
uint256 contractSize;
assembly {
contractSize :=extcodesize(_contract)
}
require(contractSize >0, _errorMessage);
}
}
Contract Source Code
File 7 of 8: LibDiamondStorage.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity 0.7.6;pragmaexperimentalABIEncoderV2;libraryLibDiamondStorage{
bytes32constant DIAMOND_STORAGE_POSITION =keccak256("diamond.standard.diamond.storage");
structFacet {
address facetAddress;
uint16 selectorPosition;
}
structDiamondStorage {
// function selector => facet address and selector position in selectors arraymapping(bytes4=> Facet) facets;
bytes4[] selectors;
// ERC165mapping(bytes4=>bool) supportedInterfaces;
// owner of the contractaddress contractOwner;
}
functiondiamondStorage() internalpurereturns (DiamondStorage storage ds) {
bytes32 position = DIAMOND_STORAGE_POSITION;
assembly {
ds.slot:= position
}
}
}