// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/**************************************************************\
* Diamond contract authored by Bling Artist Lab
* Version 0.1.0
*
* Adapted from work by Nick Mudge
* <nick@perfectabstractions.com> (https://twitter.com/mudgen)
*
* This contract is part of a project which adheres to
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/**************************************************************/import { GlobalState } from"./libraries/GlobalState.sol";
import { LibDiamond } from"./libraries/LibDiamond.sol";
import { IDiamondCut } from"./interfaces/IDiamondCut.sol";
contractMomentsAsia365{
constructor(address _diamondCutFacet) payable{
GlobalState.getState().owner =msg.sender;
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), "");
}
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 4: GlobalState.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/**************************************************************\
* Global Storage Library for NFT Smart Contracts
* Authored by Bling Artist Lab
* Version 0.2.1
*
* This library is designed to provide diamond storage and
* shared functionality to all facets of a diamond used for an
* NFT collection.
/**************************************************************/libraryGlobalState{
bytes32constant DIAMOND_STORAGE_POSITION =keccak256("globalstate.storage");
structstate {
address owner;
mapping(address=>bool) admins;
bool paused;
}
/**
* @dev Return stored state struct.
*/functiongetState() internalpurereturns (state storage _state) {
bytes32 position = DIAMOND_STORAGE_POSITION;
assembly {
_state.slot:= position
}
}
// GLOBAL FUNCTIONS ///**
* @dev Returns true if provided address is an admin or the
* contract owner.
*/functionisAdmin(address _addr) internalviewreturns (bool) {
state storage s = getState();
return s.owner == _addr || s.admins[_addr];
}
/**
* @dev Reverts if caller is not an admin or contract owner.
*/functionrequireCallerIsAdmin() internalview{
require(isAdmin(msg.sender), "GlobalState: caller is not admin or owner");
}
/**
* @dev Reverts if contract is paused.
*/functionrequireContractIsNotPaused() internalview{
require(!getState().paused || isAdmin(msg.sender), "GlobalState: contract is paused");
}
}
Contract Source Code
File 3 of 4: IDiamondCut.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
/******************************************************************************/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 4 of 4: LibDiamond.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/**************************************************************\
* Diamond Library authored by Bling Artist Lab
* Version 0.1.0
*
* Adapted from work by Nick Mudge
* <nick@perfectabstractions.com> (https://twitter.com/mudgen)
*
* This contract is part of a project which adheres to
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/**************************************************************/import { IDiamondCut } from"../interfaces/IDiamondCut.sol";
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;
}
functiondiamondStorage() internalpurereturns (DiamondStorage storage ds) {
bytes32 position = DIAMOND_STORAGE_POSITION;
assembly {
ds.slot:= position
}
}
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; facetIndex++) {
(selectorCount, selectorSlot) = addReplaceRemoveFacetSelectors(
selectorCount,
selectorSlot,
_diamondCut[facetIndex].facetAddress,
_diamondCut[facetIndex].action,
_diamondCut[facetIndex].functionSelectors
);
}
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; selectorIndex++) {
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++;
}
} elseif (_action == IDiamondCut.FacetCutAction.Replace) {
enforceHasContractCode(_newFacetAddress, "LibDiamondCut: Replace facet has no code");
for (uint256 selectorIndex; selectorIndex < _selectors.length; selectorIndex++) {
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);
}
} 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; selectorIndex++) {
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;
}
}
_selectorCount = selectorSlotCount *8+ selectorInSlotIndex;
} else {
revert("LibDiamondCut: Incorrect FacetCutAction");
}
return (_selectorCount, _selectorSlot);
}
functioninitializeDiamondCut(address _init, bytesmemory _calldata) internal{
if (_init ==address(0)) {
require(_calldata.length==0, "LibDiamondCut: _init is address(0) but_calldata is not empty");
} else {
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);
}
}