Skip to content

Commit

Permalink
core: initialize the project
Browse files Browse the repository at this point in the history
- 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
florianleger committed Jun 12, 2022
1 parent 838db7a commit 2eb66d3
Show file tree
Hide file tree
Showing 24 changed files with 10,634 additions and 0 deletions.
65 changes: 65 additions & 0 deletions contracts/GuildDiamond.sol
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 <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";
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 {}
}
27 changes: 27 additions & 0 deletions contracts/facets/DiamondCutFacet.sol
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 <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";

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);
}
}
149 changes: 149 additions & 0 deletions contracts/facets/DiamondLoupeFacet.sol
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 <nick@perfectabstractions.com> (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];
}
}
15 changes: 15 additions & 0 deletions contracts/facets/LootboxFacet.sol
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");
}

}
16 changes: 16 additions & 0 deletions contracts/facets/OwnershipFacet.sol
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();
}
}
20 changes: 20 additions & 0 deletions contracts/facets/PlayerFacet.sol
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;
}
}
9 changes: 9 additions & 0 deletions contracts/facets/RulesFacet.sol
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;

}
9 changes: 9 additions & 0 deletions contracts/facets/TreasuryFacet.sol
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;

}
32 changes: 32 additions & 0 deletions contracts/interfaces/IDiamondCut.sol
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 <nick@perfectabstractions.com> (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);
}
38 changes: 38 additions & 0 deletions contracts/interfaces/IDiamondLoupe.sol
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 <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 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_);
}
Loading

0 comments on commit 2eb66d3

Please sign in to comment.