Skip to content

Commit 0e9c53c

Browse files
authored
Merge pull request #31 from dadadave80/dev
release: merge dev into main (ERC-8153 exportSelectors + release-please)
2 parents 5233f95 + 95f0a0b commit 0e9c53c

20 files changed

Lines changed: 366 additions & 66 deletions
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: release-please
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
permissions:
9+
contents: write
10+
issues: write
11+
pull-requests: write
12+
13+
jobs:
14+
release-please:
15+
runs-on: ubuntu-latest
16+
steps:
17+
# Uses the default GITHUB_TOKEN. Note: releases/PRs it opens will NOT trigger
18+
# other workflows (e.g. CI on the release PR). Swap in a PAT secret if you need that.
19+
- uses: googleapis/release-please-action@v5
20+
with:
21+
token: ${{ secrets.GITHUB_TOKEN }}
22+
config-file: release-please-config.json
23+
manifest-file: .release-please-manifest.json

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
name: Foundry project
1717
runs-on: ubuntu-latest
1818
steps:
19-
- uses: actions/checkout@v4
19+
- uses: actions/checkout@v7
2020
with:
2121
submodules: recursive
2222

.release-please-manifest.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
".": "0.1.4"
3+
}

CONTRIBUTING.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,8 @@ forge build
1818

1919
## Running Tests
2020

21-
Tests use FFI for selector extraction, so the `--ffi` flag is required:
22-
2321
```sh
24-
forge test --ffi -vvv
22+
forge test -vvv
2523
```
2624

2725
## Making Changes
@@ -34,14 +32,15 @@ forge test --ffi -vvv
3432
- `src/initializers/` — Initializer contracts
3533
3. Add or update tests in `test/` to cover your changes.
3634
4. Run `forge fmt` to format your code.
37-
5. Ensure all tests pass with `forge test --ffi`.
35+
5. Ensure all tests pass with `forge test`.
3836
6. Open a pull request against `main`.
3937

4038
## Guidelines
4139

4240
- Keep gas efficiency in mind — this library is optimized for minimal overhead.
4341
- Follow existing code style and naming conventions.
4442
- One logical change per PR — avoid bundling unrelated changes.
43+
- Selectors are self-reported on-chain via ERC-8153 `exportSelectors()`. When you add an external/public function to a facet, you MUST also add its selector to that facet's `exportSelectors()`, extend the expected set in `test/ExportSelectorsTester.t.sol`, and exercise it through the diamond with a routed-call test. A function omitted from `exportSelectors()` will not be cut in or routed — and no test will fail unless you add one.
4544
- Include test cases for both success and failure paths.
4645

4746
## Reporting Issues

foundry.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ remappings = [
99
]
1010
optimizer_runs = 1_000_000
1111
via_ir = false
12-
ffi = true
12+
ffi = false
1313

1414
[profile.ci]
1515
optimizer_runs = 1_000_000

release-please-config.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
3+
"bump-minor-pre-major": true,
4+
"packages": {
5+
".": {
6+
"release-type": "simple"
7+
}
8+
}
9+
}

script/DeployDiamond.s.sol

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: MIT
22
pragma solidity ^0.8.20;
33

4-
import {GetSelectors} from "@diamond-test/helpers/GetSelectors.sol";
4+
import {Selectors} from "@diamond-test/helpers/Selectors.sol";
55
import {MockDiamond} from "@diamond-test/mocks/MockDiamond.sol";
66
import {DiamondCutFacet} from "@diamond/facets/DiamondCutFacet.sol";
77
import {DiamondLoupeFacet} from "@diamond/facets/DiamondLoupeFacet.sol";
@@ -11,6 +11,7 @@ import {DiamondInit} from "@diamond/initializers/DiamondInit.sol";
1111
import {ERC165Init} from "@diamond/initializers/ERC165Init.sol";
1212
import {MultiInit} from "@diamond/initializers/MultiInit.sol";
1313
import {OwnableInit} from "@diamond/initializers/OwnableInit.sol";
14+
import {IFacet} from "@diamond/interfaces/IFacet.sol";
1415
import {ContextLib} from "@diamond/libraries/ContextLib.sol";
1516
import {FacetCut, FacetCutAction} from "@diamond/libraries/DiamondLib.sol";
1617
import {Script} from "forge-std/Script.sol";
@@ -20,7 +21,7 @@ import {Script} from "forge-std/Script.sol";
2021
/// @author David Dada
2122
///
2223
/// @dev Uses Foundry's `Script` and a helper contract to deploy and wire up DiamondCutFacet, DiamondLoupeFacet, and OwnableFacet
23-
contract DeployDiamond is Script, GetSelectors {
24+
contract DeployDiamond is Script {
2425
/// @notice Executes the deployment of the Diamond contract with the initial facets and ERC165 interface setup
2526
/// @dev Broadcasts transactions using Foundry's scripting environment (`vm.startBroadcast()` and `vm.stopBroadcast()`).
2627
/// Deploys three core facets, sets up DiamondArgs, encodes an initializer call, and constructs the Diamond.
@@ -39,32 +40,32 @@ contract DeployDiamond is Script, GetSelectors {
3940
// Create an array of FacetCut entries for standard facets
4041
FacetCut[] memory cut = new FacetCut[](4);
4142

42-
// Add DiamondCutFacet to the cut list
43+
// Add DiamondCutFacet to the cut list (selectors read on-chain via ERC-8153 exportSelectors)
4344
cut[0] = FacetCut({
4445
facetAddress: address(diamondCutFacet),
4546
action: FacetCutAction.Add,
46-
functionSelectors: _getSelectors("DiamondCutFacet")
47+
functionSelectors: Selectors.decode(IFacet(address(diamondCutFacet)).exportSelectors())
4748
});
4849

4950
// Add DiamondLoupeFacet to the cut list
5051
cut[1] = FacetCut({
5152
facetAddress: address(diamondLoupeFacet),
5253
action: FacetCutAction.Add,
53-
functionSelectors: _getSelectors("DiamondLoupeFacet")
54+
functionSelectors: Selectors.decode(IFacet(address(diamondLoupeFacet)).exportSelectors())
5455
});
5556

5657
// Add ERC165Facet to the cut list
5758
cut[2] = FacetCut({
5859
facetAddress: address(erc165Facet),
5960
action: FacetCutAction.Add,
60-
functionSelectors: _getSelectors("ERC165Facet")
61+
functionSelectors: Selectors.decode(IFacet(address(erc165Facet)).exportSelectors())
6162
});
6263

6364
// Add OwnableFacet to the cut list
6465
cut[3] = FacetCut({
6566
facetAddress: address(ownableFacet),
6667
action: FacetCutAction.Add,
67-
functionSelectors: _getSelectors("OwnableFacet")
68+
functionSelectors: Selectors.decode(IFacet(address(ownableFacet)).exportSelectors())
6869
});
6970

7071
// Deploy the Diamond contract with the facets and initialization args

src/facets/DiamondCutFacet.sol

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
pragma solidity ^0.8.20;
33

44
import {IDiamondCut} from "@diamond/interfaces/IDiamondCut.sol";
5+
import {IFacet} from "@diamond/interfaces/IFacet.sol";
56
import {DiamondLib, FacetCut} from "@diamond/libraries/DiamondLib.sol";
67
import {OwnableLib} from "@diamond/libraries/OwnableLib.sol";
78

@@ -13,7 +14,7 @@ import {OwnableLib} from "@diamond/libraries/OwnableLib.sol";
1314
/// @dev Note:
1415
/// Remember to add the loupe functions from DiamondLoupeFacet to the diamond.
1516
/// The loupe functions are required by the EIP2535 Diamonds standard.
16-
contract DiamondCutFacet is IDiamondCut {
17+
contract DiamondCutFacet is IDiamondCut, IFacet {
1718
/// @notice Add/replace/remove any number of functions and optionally execute
1819
/// a function with delegatecall
1920
/// @param _diamondCut Contains the facet addresses and function selectors
@@ -26,4 +27,9 @@ contract DiamondCutFacet is IDiamondCut {
2627
// Call the diamond cut function from the library
2728
DiamondLib.diamondCut(_diamondCut, _init, _calldata);
2829
}
30+
31+
/// @inheritdoc IFacet
32+
function exportSelectors() external pure returns (bytes memory selectors_) {
33+
selectors_ = abi.encodePacked(this.diamondCut.selector);
34+
}
2935
}

src/facets/DiamondLoupeFacet.sol

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
pragma solidity ^0.8.20;
33

44
import {IDiamondLoupe} from "@diamond/interfaces/IDiamondLoupe.sol";
5+
import {IFacet} from "@diamond/interfaces/IFacet.sol";
56
import {DiamondLib, DiamondStorage, Facet} from "@diamond/libraries/DiamondLib.sol";
67

78
/// @title DiamondLoupeFacet
@@ -10,7 +11,7 @@ import {DiamondLib, DiamondStorage, Facet} from "@diamond/libraries/DiamondLib.s
1011
/// @author Modified by David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80)
1112
///
1213
/// @dev Implements the IDiamondLoupe interface as defined in EIP-2535
13-
contract DiamondLoupeFacet is IDiamondLoupe {
14+
contract DiamondLoupeFacet is IDiamondLoupe, IFacet {
1415
/// @notice Gets all facet addresses and their function selectors.
1516
/// @return facets_ Facet
1617
function facets() external view returns (Facet[] memory facets_) {
@@ -44,4 +45,14 @@ contract DiamondLoupeFacet is IDiamondLoupe {
4445
function facetAddress(bytes4 _functionSelector) external view override returns (address) {
4546
return DiamondLib.diamondStorage().selectorToFacetAndPosition[_functionSelector].facetAddress;
4647
}
48+
49+
/// @inheritdoc IFacet
50+
function exportSelectors() external pure returns (bytes memory selectors_) {
51+
selectors_ = abi.encodePacked(
52+
this.facets.selector,
53+
this.facetFunctionSelectors.selector,
54+
this.facetAddresses.selector,
55+
this.facetAddress.selector
56+
);
57+
}
4758
}

src/facets/ERC165Facet.sol

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
// SPDX-License-Identifier: MIT
22
pragma solidity ^0.8.20;
33

4+
import {IFacet} from "@diamond/interfaces/IFacet.sol";
45
import {ERC165Lib} from "@diamond/libraries/ERC165Lib.sol";
56

67
/// @title ERC165Facet
78
/// @notice Diamond facet that implements the ERC-165 standard interface detection
89
/// @author David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80)
910
/// @dev Delegates to ERC165Lib which hardcodes support for ERC-165, ERC-173, IDiamondCut, and IDiamondLoupe
10-
contract ERC165Facet {
11+
contract ERC165Facet is IFacet {
1112
/// @notice Query if a contract implements an interface
1213
/// @param _interfaceId The interface identifier, as specified in ERC-165
1314
/// @dev Interface identification is specified in ERC-165. This function
@@ -17,4 +18,9 @@ contract ERC165Facet {
1718
function supportsInterface(bytes4 _interfaceId) external view returns (bool) {
1819
return ERC165Lib.supportsInterface(_interfaceId);
1920
}
21+
22+
/// @inheritdoc IFacet
23+
function exportSelectors() external pure returns (bytes memory selectors_) {
24+
selectors_ = abi.encodePacked(this.supportsInterface.selector);
25+
}
2026
}

0 commit comments

Comments
 (0)