-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Implementation of the [EIP-2535 Diamonds](ethereum/EIPs#2535) standard by using the [diamond-1-hardhat](https://github.com/mudgen/diamond-1-hardhat) boilerplate - Migrated to Typescript - Added empty Facets and some declarations in the AppStorage - Updated dependencies - Added typechain-types for a better contracts integration in TypeScript
- Loading branch information
1 parent
838db7a
commit 68e48d8
Showing
23 changed files
with
1,259 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
/******************************************************************************\ | ||
* Author: Nick Mudge <[email protected]> (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"; | ||
import { AppStorage } from "./libraries/LibAppStorage.sol"; | ||
|
||
contract GuildDiamond { | ||
AppStorage s; | ||
|
||
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 = new bytes4[](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() external payable { | ||
LibDiamond.DiamondStorage storage ds; | ||
bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION; | ||
// get diamond storage | ||
assembly { | ||
ds.slot := position | ||
} | ||
// get facet from function selector | ||
address facet = ds.facetAddressAndSelectorPosition[msg.sig].facetAddress; | ||
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 arguments | ||
calldatacopy(0, 0, calldatasize()) | ||
// execute function call using the facet | ||
let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0) | ||
// get any return value | ||
returndatacopy(0, 0, returndatasize()) | ||
// return any return value or error back to the caller | ||
switch result | ||
case 0 { | ||
revert(0, returndatasize()) | ||
} | ||
default { | ||
return(0, returndatasize()) | ||
} | ||
} | ||
} | ||
|
||
receive() external payable {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
/******************************************************************************\ | ||
* 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"; | ||
import { LibDiamond } from "../libraries/LibDiamond.sol"; | ||
|
||
contract DiamondCutFacet is IDiamondCut { | ||
/// @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 override { | ||
LibDiamond.enforceIsContractOwner(); | ||
LibDiamond.diamondCut(_diamondCut, _init, _calldata); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
/******************************************************************************\ | ||
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) | ||
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 | ||
/******************************************************************************/ | ||
|
||
// The functions in DiamondLoupeFacet MUST be added to a diamond. | ||
// The EIP-2535 Diamond standard requires these functions. | ||
|
||
import { LibDiamond } from "../libraries/LibDiamond.sol"; | ||
import { IDiamondLoupe } from "../interfaces/IDiamondLoupe.sol"; | ||
import { IERC165 } from "../interfaces/IERC165.sol"; | ||
|
||
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 override view returns (Facet[] memory facets_) { | ||
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage(); | ||
uint256 selectorCount = ds.selectors.length; | ||
// create an array set to the maximum size possible | ||
facets_ = new Facet[](selectorCount); | ||
// create an array for counting the number of selectors for each facet | ||
uint8[] memory numFacetSelectors = new uint8[](selectorCount); | ||
// total number of facets | ||
uint256 numFacets; | ||
// loop through function selectors | ||
for (uint256 selectorIndex; selectorIndex < selectorCount; selectorIndex++) { | ||
bytes4 selector = ds.selectors[selectorIndex]; | ||
address facetAddress_ = ds.facetAddressAndSelectorPosition[selector].facetAddress; | ||
bool continueLoop = false; | ||
// find the functionSelectors array for selector and add selector to it | ||
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 contract | ||
require(numFacetSelectors[facetIndex] < 255); | ||
numFacetSelectors[facetIndex]++; | ||
continueLoop = true; | ||
break; | ||
} | ||
} | ||
// if functionSelectors array exists for selector then continue loop | ||
if (continueLoop) { | ||
continueLoop = false; | ||
continue; | ||
} | ||
// create a new functionSelectors array for selector | ||
facets_[numFacets].facetAddress = facetAddress_; | ||
facets_[numFacets].functionSelectors = new bytes4[](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 selectors | ||
assembly { | ||
mstore(selectors, numSelectors) | ||
} | ||
} | ||
// setting the number of facets | ||
assembly { | ||
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. | ||
function facetFunctionSelectors(address _facet) external override view returns (bytes4[] memory _facetFunctionSelectors) { | ||
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage(); | ||
uint256 selectorCount = ds.selectors.length; | ||
uint256 numSelectors; | ||
_facetFunctionSelectors = new bytes4[](selectorCount); | ||
// loop through function selectors | ||
for (uint256 selectorIndex; selectorIndex < selectorCount; selectorIndex++) { | ||
bytes4 selector = ds.selectors[selectorIndex]; | ||
address facetAddress_ = ds.facetAddressAndSelectorPosition[selector].facetAddress; | ||
if (_facet == facetAddress_) { | ||
_facetFunctionSelectors[numSelectors] = selector; | ||
numSelectors++; | ||
} | ||
} | ||
// Set the number of selectors in the array | ||
assembly { | ||
mstore(_facetFunctionSelectors, numSelectors) | ||
} | ||
} | ||
|
||
/// @notice Get all the facet addresses used by a diamond. | ||
/// @return facetAddresses_ | ||
function facetAddresses() external override view returns (address[] memory facetAddresses_) { | ||
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage(); | ||
uint256 selectorCount = ds.selectors.length; | ||
// create an array set to the maximum size possible | ||
facetAddresses_ = new address[](selectorCount); | ||
uint256 numFacets; | ||
// loop through function selectors | ||
for (uint256 selectorIndex; selectorIndex < selectorCount; selectorIndex++) { | ||
bytes4 selector = ds.selectors[selectorIndex]; | ||
address facetAddress_ = ds.facetAddressAndSelectorPosition[selector].facetAddress; | ||
bool continueLoop = false; | ||
// see if we have collected the address already and break out of loop if we have | ||
for (uint256 facetIndex; facetIndex < numFacets; facetIndex++) { | ||
if (facetAddress_ == facetAddresses_[facetIndex]) { | ||
continueLoop = true; | ||
break; | ||
} | ||
} | ||
// continue loop if we already have the address | ||
if (continueLoop) { | ||
continueLoop = false; | ||
continue; | ||
} | ||
// include address | ||
facetAddresses_[numFacets] = facetAddress_; | ||
numFacets++; | ||
} | ||
// Set the number of facet addresses in the array | ||
assembly { | ||
mstore(facetAddresses_, numFacets) | ||
} | ||
} | ||
|
||
/// @notice Gets the facet address 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 override view returns (address facetAddress_) { | ||
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage(); | ||
facetAddress_ = ds.facetAddressAndSelectorPosition[_functionSelector].facetAddress; | ||
} | ||
|
||
// This implements ERC-165. | ||
function supportsInterface(bytes4 _interfaceId) external override view returns (bool) { | ||
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage(); | ||
return ds.supportedInterfaces[_interfaceId]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import {AppStorage} from "../libraries/LibAppStorage.sol"; | ||
|
||
contract LootboxFacet { | ||
AppStorage internal s; | ||
event OpenLootboxEvent(address player, uint32 lootboxId); | ||
|
||
function openLootbox(address player, uint32 lootboxId) external { | ||
require(player != address(0), "Player address is not valid"); | ||
require(s.playersExists[player], "Player does not exist"); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import { LibDiamond } from "../libraries/LibDiamond.sol"; | ||
import { IERC173 } from "../interfaces/IERC173.sol"; | ||
|
||
contract OwnershipFacet is IERC173 { | ||
function transferOwnership(address _newOwner) external override { | ||
LibDiamond.enforceIsContractOwner(); | ||
LibDiamond.setContractOwner(_newOwner); | ||
} | ||
|
||
function owner() external override view returns (address owner_) { | ||
owner_ = LibDiamond.contractOwner(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import {AppStorage} from "../libraries/LibAppStorage.sol"; | ||
|
||
contract PlayerFacet { | ||
AppStorage internal s; | ||
event LevelUpEvent(address player, uint16 level); | ||
|
||
function levelUp(address player) external { | ||
require(player != address(0), "Player address is not valid"); | ||
//require(s.playersExists[player], "Player does not exist"); | ||
//s.players[player].level++; | ||
} | ||
|
||
// for testing purposes | ||
function supportsInterface(bytes4 _interfaceID) external view returns (bool) { | ||
return false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import {AppStorage} from "../libraries/LibAppStorage.sol"; | ||
|
||
contract RulesFacet { | ||
AppStorage internal s; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import {AppStorage} from "../libraries/LibAppStorage.sol"; | ||
|
||
contract TreasuryFacet { | ||
AppStorage internal s; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
/******************************************************************************\ | ||
* 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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
/******************************************************************************\ | ||
* 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_); | ||
} |
Oops, something went wrong.