Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ca4767e
chore: increase minimum solidity version to 0.8.20
dadadave80 Sep 13, 2025
4af0d7b
chore: arrange imports alphabetically
dadadave80 Sep 13, 2025
4672d4d
chore: return values directly if not used multiply
dadadave80 Sep 13, 2025
f8a2baa
feat: add OZ Initializable contract, with minor mods
dadadave80 Sep 13, 2025
f3f99c1
chore: inherit Initializable and use initializer modifier on the init…
dadadave80 Sep 13, 2025
e81c92c
chore: change Diamond to an abstract contract
dadadave80 Sep 13, 2025
6409a11
chore: rename _diamondCut to _facetCuts
dadadave80 Sep 13, 2025
efd3d1b
chore: add beforeFallback function for running custom logic before ca…
dadadave80 Sep 13, 2025
51b1b3c
chore: add view functions
dadadave80 Oct 9, 2025
6c6311d
revert on missing facet internally
dadadave80 Oct 10, 2025
54b5826
Create a mock diamond for tests
dadadave80 Oct 12, 2025
d3b67fe
Use only diamond init
dadadave80 Oct 12, 2025
88df54f
Rearrange Diamond storage
dadadave80 Oct 12, 2025
e5c6045
Get selectors from contract arifacts and don't use ffi
dadadave80 Oct 12, 2025
79bc0fc
Update authors
dadadave80 Oct 12, 2025
041fb6c
Trim Diamond art
dadadave80 Oct 12, 2025
1551b14
Sort imports with forge fmt
dadadave80 Oct 12, 2025
d4cee49
Update deployed diamond state
dadadave80 Oct 12, 2025
4992895
Add and use LibContext
dadadave80 Oct 12, 2025
0431c4b
Update Diamond test
dadadave80 Oct 12, 2025
fd646af
Rename EIP to ERC
dadadave80 Oct 12, 2025
861b881
Refactor diamond cut logic and add calldata support
dadadave80 Oct 12, 2025
f6a68dc
Refactor Diamond proxy contract structure
dadadave80 Oct 12, 2025
b13110f
Update DiamondErrors.sol
dadadave80 Oct 12, 2025
a070c8e
Use _diamondCutCalldata in DiamondCutFacet
dadadave80 Oct 12, 2025
6412970
Increase optimizer runs and set via_ir to false
dadadave80 Oct 12, 2025
6660ad0
Specify nightly version for Foundry installation
dadadave80 Oct 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ jobs:

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly

- name: Show Forge version
run: |
Expand Down
7 changes: 5 additions & 2 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@ remappings = [
'@diamond-logs/=src/libraries/logs/',
'@diamond-errors/=src/libraries/errors/'
]
optimizer_runs = 20_000
ffi = true
optimizer_runs = 999_999
via_ir = false

[fmt]
sort_imports = true
25 changes: 10 additions & 15 deletions script/DeployDiamond.s.sol
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
pragma solidity ^0.8.20;

import {Script} from "forge-std/Script.sol";
import {Diamond} from "@diamond/Diamond.sol";
import {FacetCut, FacetCutAction} from "@diamond-storage/DiamondStorage.sol";
import {GetSelectors} from "@diamond-test/helpers/GetSelectors.sol";
import {MockDiamond} from "@diamond-test/mocks/MockDiamond.sol";
import {DiamondCutFacet} from "@diamond/facets/DiamondCutFacet.sol";
import {DiamondLoupeFacet} from "@diamond/facets/DiamondLoupeFacet.sol";
import {OwnableRolesFacet} from "@diamond/facets/OwnableRolesFacet.sol";
import {ERC165Init} from "@diamond/initializers/ERC165Init.sol";
import {FacetCutAction, FacetCut, DiamondArgs} from "@diamond-storage/DiamondStorage.sol";
import {GetSelectors} from "@diamond-test/helpers/GetSelectors.sol";
import {DiamondInit} from "@diamond/initializers/DiamondInit.sol";
import {LibContext} from "@diamond/libraries/LibContext.sol";
import {Script} from "forge-std/Script.sol";

/// @title DeployDiamond
/// @notice Deployment script for an EIP-2535 Diamond proxy contract with core facets and ERC165 initialization
Expand All @@ -28,14 +29,7 @@ contract DeployDiamond is Script, GetSelectors {
OwnableRolesFacet ownableRolesFacet = new OwnableRolesFacet();

// Deploy ERC165 initializer contract
ERC165Init erc165Init = new ERC165Init();

// Prepare DiamondArgs: owner and init data
DiamondArgs memory args = DiamondArgs({
owner: msg.sender,
init: address(erc165Init),
initData: abi.encodeWithSignature("initErc165()")
});
address diamondInit = address(new DiamondInit());

// Create an array of FacetCut entries for standard facets
FacetCut[] memory cut = new FacetCut[](3);
Expand All @@ -62,7 +56,8 @@ contract DeployDiamond is Script, GetSelectors {
});

// Deploy the Diamond contract with the facets and initialization args
Diamond diamond = new Diamond(cut, args);
MockDiamond diamond =
new MockDiamond(cut, diamondInit, abi.encodeWithSignature("initDiamond(address)", LibContext._msgSender()));
diamond_ = address(diamond);
vm.stopBroadcast();
}
Expand Down
100 changes: 56 additions & 44 deletions src/Diamond.sol
Original file line number Diff line number Diff line change
@@ -1,71 +1,74 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
pragma solidity ^0.8.20;

import {FacetCut} from "@diamond-storage/DiamondStorage.sol";
import {LibDiamond} from "@diamond/libraries/LibDiamond.sol";
import {LibOwnableRoles} from "@diamond/libraries/LibOwnableRoles.sol";
import {DiamondArgs, FacetCut} from "@diamond-storage/DiamondStorage.sol";
import {FunctionDoesNotExist} from "@diamond-errors/DiamondErrors.sol";

/*
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣤⡤⣶⣾⠟⠋⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠛⠛⠓⠶⠤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⢠⣴⠶⠛⠿⢿⣶⣿⡋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠙⠓⠲⢦⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢀⣴⡾⠋⠀⠀⢀⣴⠟⠁⠈⠛⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠛⠲⢶⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⣠⣶⡿⠋⠀⠀⠀⣠⠟⠁⠀⠀⠀⣀⣨⣿⣶⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⣷⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⣰⣾⡿⠋⠀⠀⣀⣤⣾⣥⠶⠒⠚⠋⠉⠉⠁⠀⠘⣧⠈⠉⠛⠒⠶⣤⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣝⠷⣤⡀⠀⠀⠀⠀⠀⠀⠀
⣿⡿⠒⠛⠋⢉⡽⠋⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣧⠀⠀⠀⠀⠀⠀⠉⠉⠛⠒⢶⣤⣤⣤⣤⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⠶⠛⠙⣟⠚⠻⢶⣄⠀⠀⠀⠀⠀
⢻⣷⡀⢀⣴⠏⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⡆⠀⠀⠀⣀⣤⣤⠴⠖⠚⠋⠉⠛⢦⣄⡀⠀⠉⠉⠉⠉⠉⠉⠉⠉⣹⡿⠿⣥⡀⠀⠀⠀⠹⣆⠀⠀⠹⣧⡀⠀⠀⠀
⠈⢿⡹⣿⡁⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣤⡴⣿⣶⠛⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⢦⣄⠀⠀⠀⠀⠀⢀⡾⠋⠀⠀⠈⠙⠳⣦⡀⠀⢻⡄⠀⠀⠹⣷⡀⠀⠀
⠀⠈⣷⣬⣿⣦⣄⠀⣿⠀⣀⣠⣤⡴⠖⠚⠋⠉⠁⠀⠀⡏⠈⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻⣦⡀⢀⣴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠉⠳⢦⣷⡀⠀⠀⠹⣿⡄
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣤⡤⣶⣾⠟⠋⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠛⠛⠓⠶⠤⣤⣀⡀
⠀⠀⠀⠀⠀⠀⠀⢠⣴⠶⠛⠿⢿⣶⣿⡋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠙⠓⠲⢦⣤⣀⣀
⠀⠀⠀⠀⢀⣴⡾⠋⠀⠀⢀⣴⠟⠁⠈⠛⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠛⠲⢶⣄
⠀⠀⣠⣶⡿⠋⠀⠀⠀⣠⠟⠁⠀⠀⠀⣀⣨⣿⣶⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⣷⣦⡀
⣰⣾⡿⠋⠀⠀⣀⣤⣾⣥⠶⠒⠚⠋⠉⠉⠁⠀⠘⣧⠈⠉⠛⠒⠶⣤⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣝⠷⣤⡀
⣿⡿⠒⠛⠋⢉⡽⠋⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣧⠀⠀⠀⠀⠀⠀⠉⠉⠛⠒⢶⣤⣤⣤⣤⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⠶⠛⠙⣟⠚⠻⢶⣄
⢻⣷⡀⢀⣴⠏⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⡆⠀⠀⠀⣀⣤⣤⠴⠖⠚⠋⠉⠛⢦⣄⡀⠀⠉⠉⠉⠉⠉⠉⠉⠉⣹⡿⠿⣥⡀⠀⠀⠀⠹⣆⠀⠀⠹⣧⡀
⠈⢿⡹⣿⡁⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣤⡴⣿⣶⠛⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⢦⣄⠀⠀⠀⠀⠀⢀⡾⠋⠀⠀⠈⠙⠳⣦⡀⠀⢻⡄⠀⠀⠹⣷⡀
⠀⠈⣷⣬⣿⣦⣄⠀⣿⠀⣀⣠⣤⡴⠖⠚⠋⠉⠁⠀⠀⡏⠈⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻⣦⡀⢀⣴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠉⠳⢦⣷⡀⠀⠀⠹⣿⡄
⠀⠀⠈⠻⣆⠉⠙⣿⡙⠻⢯⣀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠃⠀⠀⠙⢷⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⡿⡿⣧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡟⢿⢦⣄⠀⠹⣿⣆
⠀⠀⠀⠀⠈⢷⣄⠀⠙⢷⣄⣉⡻⣶⣄⣀⠀⠀⠀⢀⣿⠀⠀⠀⠀⠀⠻⣦⡀⠀⠀⠀⠀⠀⠀⢀⣠⡴⠞⠉⠀⢸⡇⠀⠙⠳⣦⡀⠀⠀⠀⠀⠀⠀⠀⣾⠀⠈⣧⠈⠙⢦⣽⣼
⠀⠀⠀⠀⠀⠀⠙⢧⡄⠀⠻⣯⡉⠉⠉⠛⢿⣍⡉⠉⠙⠷⣤⣀⠀⠀⠀⠈⠻⣦⠀⠀⣀⣤⠶⠋⠁⠀⠀⠀⠀⢸⠃⠀⠀⠀⠀⠙⠷⣤⡀⠀⠀⠀⣼⠃⠀⠀⠘⣦⠀⢀⣬⡿
⠀⠀⠀⠀⠀⠀⠀⠀⠻⣦⡀⢹⣷⣄⠀⠀⠀⠈⠙⢶⡶⠶⠶⠯⣭⣛⣓⡲⠶⠾⠷⠿⣭⣀⣀⠀⠀⠀⠀⠀⣀⣾⠀⠀⠀⠀⠀⠀⠀⠈⠛⢶⣄⣰⠏⠀⠀⢀⣠⡿⢟⡿⠋
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣄⢻⣟⢷⡄⠀⠀⠀⠈⢷⠀⠀⠀⠀⠀⠈⠉⠓⢶⣦⠴⠶⠾⠭⣭⣍⣉⣉⠉⠉⠉⠙⠳⢶⣤⣄⣤⡴⠶⠖⠛⠋⣙⣿⠷⠿⠿⣧⣶⠟⠁⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢷⣽⣆⠻⣦⡀⠀⠀⠘⣇⠀⠀⠀⠀⠀⠀⠀⣼⣷⠀⠀⠀⠀⠀⠀⠈⠉⢛⣶⠶⠛⠉⠉⠁⠀⠉⠙⣳⣶⠞⠋⠉⠀⣀⡶⠾⠋⠁⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣎⠌⢳⣄⠀⠀⢹⣆⠀⠀⠀⠀⠀⣼⠃⣿⠀⠀⠀⠀⠀⠀⠀⣠⠟⠁⠀⠀⠀⠀⠀⣠⣴⡿⠛⠁⢀⣤⠶⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠙⣧⡀⠀⢻⡄⠀⠀⠀⣸⠇⠀⣿⠀⠀⠀⠀⠀⢠⡾⠃⠀⠀⠀⢀⣤⠾⣫⡿⢋⣀⡴⠞⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⣆⠈⠻⣆⠈⣷⠀⠀⣰⡏⠀⠀⢻⠀⠀⠀⢀⣴⠏⠀⠀⣀⣴⠞⠋⣠⣾⣿⠾⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢷⣄⠘⢷⡼⣇⢀⡟⠀⠀⠀⢸⠀⠀⣠⠟⠁⣠⡴⠞⠉⢀⣠⡾⠟⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⣦⡀⠹⣿⡾⠁⠀⠀⠀⢸⣀⣾⣣⠶⠛⠁⣀⣤⠾⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣄⠈⢿⡀⠀⠀⢀⣼⠟⠋⢀⣠⠴⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠷⣜⣧⠀⣠⠟⣁⣴⠞⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣾⠿⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠻⣦⡀⢹⣷⣄⠀⠀⠀⠈⠙⢶⡶⠶⠶⠯⣭⣛⣓⡲⠶⠾⠷⠿⣭⣀⣀⠀⠀⠀⠀⠀⣀⣾⠀⠀⠀⠀⠀⠀⠀⠈⠛⢶⣄⣰⠏⠀⠀⢀⣠⡿⢟⡿⠋
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣄⢻⣟⢷⡄⠀⠀⠀⠈⢷⠀⠀⠀⠀⠀⠈⠉⠓⢶⣦⠴⠶⠾⠭⣭⣍⣉⣉⠉⠉⠉⠙⠳⢶⣤⣄⣤⡴⠶⠖⠛⠋⣙⣿⠷⠿⠿⣧⣶⠟⠁
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢷⣽⣆⠻⣦⡀⠀⠀⠘⣇⠀⠀⠀⠀⠀⠀⠀⣼⣷⠀⠀⠀⠀⠀⠀⠈⠉⢛⣶⠶⠛⠉⠉⠁⠀⠉⠙⣳⣶⠞⠋⠉⠀⣀⡶⠾⠋⠁
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣎⠌⢳⣄⠀⠀⢹⣆⠀⠀⠀⠀⠀⣼⠃⣿⠀⠀⠀⠀⠀⠀⠀⣠⠟⠁⠀⠀⠀⠀⠀⣠⣴⡿⠛⠁⢀⣤⠶⠛⠉
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠙⣧⡀⠀⢻⡄⠀⠀⠀⣸⠇⠀⣿⠀⠀⠀⠀⠀⢠⡾⠃⠀⠀⠀⢀⣤⠾⣫⡿⢋⣀⡴⠞⠉
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⣆⠈⠻⣆⠈⣷⠀⠀⣰⡏⠀⠀⢻⠀⠀⠀⢀⣴⠏⠀⠀⣀⣴⠞⠋⣠⣾⣿⠾⠛⠁
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢷⣄⠘⢷⡼⣇⢀⡟⠀⠀⠀⢸⠀⠀⣠⠟⠁⣠⡴⠞⠉⢀⣠⡾⠟⠋
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⣦⡀⠹⣿⡾⠁⠀⠀⠀⢸⣀⣾⣣⠶⠛⠁⣀⣤⠾⠋⠁
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣄⠈⢿⡀⠀⠀⢀⣼⠟⠋⢀⣠⠴⠛⠉
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠷⣜⣧⠀⣠⠟⣁⣴⠞⠋⠁
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣾⠿⠛⠉
*/

/// @title Diamond
/// @notice Implements EIP-2535 Diamond proxy pattern, allowing dynamic addition, replacement, and removal of facets
/// @author David Dada
/// @author Modified from Nick Mudge (https://github.com/mudgen/diamond-3-hardhat/blob/main/contracts/Diamond.sol)
/// @author Modified from Timo (https://github.com/FydeTreasury/Diamond-Foundry/blob/main/src/Diamond.sol)
///
/// @dev Uses LibDiamond for facet management and LibOwnableRoles for ownership initialization
contract Diamond {
/// @notice Implements ERC-2535 Diamond proxy pattern, allowing dynamic addition, replacement, and removal of facets
/// @author Nick Mudge (https://github.com/mudgen/diamond-3-hardhat/blob/main/contracts/Diamond.sol)
/// @author Modified by David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80)
abstract contract Diamond {
/// @notice Initializes the Diamond proxy with the provided facets and initialization parameters
/// @param _diamondCut Array of FacetCut structs defining facet addresses, corresponding function selectors, and actions (Add, Replace, Remove)
/// @param _args Struct containing the initial owner address, optional init contract address, and init calldata
constructor(FacetCut[] memory _diamondCut, DiamondArgs memory _args) payable {
LibOwnableRoles._initializeOwner(_args.owner);
LibDiamond._diamondCut(_diamondCut, _args.init, _args.initData);
/// @param _init Address of the initialization contract
/// @param _calldata Calldata to be passed to the initialization contract
constructor(FacetCut[] memory _facetCuts, address _init, bytes memory _calldata) payable {
_diamondCut(_facetCuts, _init, _calldata);
}

/// @notice Receive function to accept plain Ether transfers
/// @dev Allows contract to receive Ether without data
receive() external payable {}
receive() external payable virtual {}

/// @notice Fallback function that delegates calls to the appropriate facet based on function selector
/// @dev Reads the facet address from diamond storage and performs a delegatecall; reverts if selector is not found
fallback() external payable {
// Lookup facet for function selector
address facet = LibDiamond._diamondStorage().selectorToFacetAndPosition[msg.sig].facetAddress;
if (facet == address(0)) revert FunctionDoesNotExist(msg.sig);
fallback() external payable virtual {
_beforeDelegate();
_delegate(_implementation());
}

/// @notice Retrieves the implementation address for the current function call
/// @dev Implementation and Facet are synonyms in a Diamond Proxy
function _implementation() internal virtual returns (address) {
return LibDiamond._selectorToFacet(msg.sig);
}

/// @notice Internal function to perform a delegatecall to an implementation
/// @param _facet Address of the implementation to delegate to
function _delegate(address _facet) internal virtual {
assembly {
// Copy calldata to memory
calldatacopy(0, 0, calldatasize())

// Delegate call to facet
let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
// Delegate call to implementation
let result := delegatecall(gas(), _facet, 0, calldatasize(), 0, 0)

// Copy returned data
returndatacopy(0, 0, returndatasize())
Expand All @@ -76,4 +79,13 @@ contract Diamond {
default { return(0, returndatasize()) }
}
}

/// @notice Internal function to perform a diamond cut
function _diamondCut(FacetCut[] memory _facetCuts, address _init, bytes memory _calldata) internal virtual {
LibDiamond._diamondCut(_facetCuts, _init, _calldata);
}

/// @notice Internal hook function to run before a delegatecall to the facet
/// @dev This function can be replaced to perform additional logic before the delegatecall
function _beforeDelegate() internal virtual;
}
6 changes: 3 additions & 3 deletions src/facets/DiamondCutFacet.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
pragma solidity ^0.8.20;

import {FacetCut} from "@diamond-storage/DiamondStorage.sol";
import {IDiamondCut} from "@diamond/interfaces/IDiamondCut.sol";
import {LibDiamond} from "@diamond/libraries/LibDiamond.sol";
import {LibOwnableRoles} from "@diamond/libraries/LibOwnableRoles.sol";
import {FacetCut} from "@diamond-storage/DiamondStorage.sol";

/// @title DiamondCutFacet
/// @notice Simple single owner and multiroles authorization mixin.
Expand All @@ -26,6 +26,6 @@ contract DiamondCutFacet is IDiamondCut {
// Check that the caller is the owner
LibOwnableRoles._checkOwner();
// Call the diamond cut function from the library
LibDiamond._diamondCut(_diamondCut, _init, _calldata);
LibDiamond._diamondCutCalldata(_diamondCut, _init, _calldata);
}
}
6 changes: 3 additions & 3 deletions src/facets/DiamondLoupeFacet.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
pragma solidity ^0.8.20;

import {DiamondStorage, LibDiamond} from "@diamond/libraries/LibDiamond.sol";
import {IDiamondLoupe} from "@diamond/interfaces/IDiamondLoupe.sol";
import {Facet} from "@diamond-storage/DiamondStorage.sol";
import {IDiamondLoupe} from "@diamond/interfaces/IDiamondLoupe.sol";
import {DiamondStorage, LibDiamond} from "@diamond/libraries/LibDiamond.sol";

/// @title DiamondLoupeFacet
/// @notice Provides read-only functions to inspect the state of a Diamond proxy, including facets, function selectors, and supported interfaces
Expand Down
31 changes: 11 additions & 20 deletions src/facets/OwnableRolesFacet.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
pragma solidity ^0.8.20;

import {LibOwnableRoles} from "@diamond/libraries/LibOwnableRoles.sol";

Expand Down Expand Up @@ -72,18 +72,18 @@ contract OwnableRolesFacet {
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/// @dev Returns the owner of the contract.
function owner() public view returns (address result_) {
result_ = LibOwnableRoles._owner();
function owner() public view returns (address) {
return LibOwnableRoles._owner();
}

/// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
function ownershipHandoverExpiresAt(address _pendingOwner) public view returns (uint256 result_) {
result_ = _pendingOwner._ownershipHandoverExpiresAt();
function ownershipHandoverExpiresAt(address _pendingOwner) public view returns (uint256) {
return _pendingOwner._ownershipHandoverExpiresAt();
}

/// @dev Returns the roles of `user`.
function rolesOf(address _user) public view returns (uint256 roles_) {
roles_ = _user._rolesOf();
function rolesOf(address _user) public view returns (uint256) {
return _user._rolesOf();
}

/// @dev Returns whether `user` has any of `roles`.
Expand All @@ -99,24 +99,15 @@ contract OwnableRolesFacet {
/// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`.
/// This is meant for frontends like Etherscan, and is therefore not fully optimized.
/// Not recommended to be called on-chain.
function rolesFromOrdinals(uint8[] memory ordinals) external pure returns (uint256 roles_) {
roles_ = ordinals._rolesFromOrdinals();
function rolesFromOrdinals(uint8[] memory ordinals) external pure returns (uint256) {
return ordinals._rolesFromOrdinals();
}

/// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap.
/// This is meant for frontends like Etherscan, and is therefore not fully optimized.
/// Not recommended to be called on-chain.
function ordinalsFromRoles(uint256 roles) external pure returns (uint8[] memory ordinals_) {
ordinals_ = roles._ordinalsFromRoles();
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/// @dev This override returns true to make `_initializeOwner` prevent double-initialization.
function _guardInitializeOwner() internal pure returns (bool guard) {
return true;
function ordinalsFromRoles(uint256 roles) external pure returns (uint8[] memory) {
return roles._ordinalsFromRoles();
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
Expand Down
Loading