-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(contracts): add registry manager
- [x] Add RegistryManager contract - [x] Add EASRegistryManager contract - [x] Add Common contract with common errors - [x] Minor refactoring - [x] Add tests
- Loading branch information
Showing
15 changed files
with
946 additions
and
43 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,50 @@ | ||
name: Slither Analysis | ||
|
||
on: | ||
push: | ||
branches: [main] | ||
pull_request: | ||
|
||
concurrency: | ||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | ||
cancel-in-progress: true | ||
|
||
jobs: | ||
slither: | ||
runs-on: ubuntu-22.04 | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: pnpm/action-setup@v4 | ||
with: | ||
version: 9 | ||
|
||
- name: Use Node.js 20 | ||
uses: actions/setup-node@v4 | ||
with: | ||
node-version: 20 | ||
cache: "pnpm" | ||
|
||
- name: Install | ||
run: | | ||
pnpm install --frozen-lockfile --prefer-offline | ||
- name: Build | ||
run: | | ||
pnpm run build | ||
working-directory: packages/contracts | ||
|
||
- name: Run Slither | ||
uses: crytic/[email protected] | ||
continue-on-error: true | ||
id: slither | ||
with: | ||
sarif: results.sarif | ||
fail-on: none | ||
ignore-compile: true | ||
node-version: 20 | ||
target: "packages/contracts/" | ||
|
||
- name: Upload SARIF file | ||
uses: github/codeql-action/upload-sarif@v3 | ||
with: | ||
sarif_file: ${{ steps.slither.outputs.sarif }} |
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
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,12 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
/// @title ICommon | ||
/// @notice Interface that contains common things for all the contracts | ||
interface ICommon { | ||
/// @notice custom errors | ||
error InvalidAddress(); | ||
error InvalidInput(); | ||
error InvalidIndex(); | ||
error ValidationError(); | ||
} |
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
86 changes: 86 additions & 0 deletions
86
packages/contracts/contracts/interfaces/IRegistryManager.sol
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,86 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import { IRecipientRegistry } from "./IRecipientRegistry.sol"; | ||
|
||
/// @title IRegistryManager | ||
/// @notice An interface for a registry manager. Allows to manage requests for Registry. | ||
interface IRegistryManager { | ||
/// @notice Enum representing request type | ||
enum RequestType { | ||
Add, | ||
Change, | ||
Remove | ||
} | ||
|
||
/// @notice Enum representing request status | ||
enum Status { | ||
Pending, | ||
Approved, | ||
Rejected | ||
} | ||
|
||
/// @notice Request data | ||
struct Request { | ||
/// @notice index (optional) | ||
uint256 index; | ||
/// @notice registry address | ||
address registry; | ||
/// @notice request type | ||
RequestType requestType; | ||
/// @notice request status | ||
Status status; | ||
/// @notice recipient data | ||
IRecipientRegistry.Recipient recipient; | ||
} | ||
|
||
/// @notice Events | ||
event RequestSent( | ||
address indexed registry, | ||
RequestType indexed requestType, | ||
address indexed recipient, | ||
uint256 index, | ||
bytes32 id, | ||
bytes32 metadataUrl | ||
); | ||
event RequestApproved( | ||
address indexed registry, | ||
RequestType indexed requestType, | ||
address indexed recipient, | ||
uint256 index, | ||
bytes32 id, | ||
bytes32 metadataUrl | ||
); | ||
event RequestRejected( | ||
address indexed registry, | ||
RequestType indexed requestType, | ||
address indexed recipient, | ||
uint256 index, | ||
bytes32 id, | ||
bytes32 metadataUrl | ||
); | ||
|
||
/// @notice Custom errors | ||
error OperationError(); | ||
|
||
/// @notice Send the request to the Registry | ||
/// @param request user request | ||
function process(Request calldata request) external; | ||
|
||
/// @notice Approve the request and call registry function | ||
/// @param index The index of the request | ||
function approve(uint256 index) external; | ||
|
||
/// @notice Reject the request | ||
/// @param index The index of the request | ||
function reject(uint256 index) external; | ||
|
||
/// @notice Get a request | ||
/// @param index The index of the request | ||
/// @return request The request to the registry | ||
function getRequest(uint256 index) external view returns (Request memory request); | ||
|
||
/// @notice Get the number of requests | ||
/// @return The number of requests | ||
function requestCount() external view returns (uint256); | ||
} |
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,14 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import { BaseRegistry } from "../registry/BaseRegistry.sol"; | ||
|
||
/// @title MockRegistry | ||
/// @notice Mock registry contract | ||
contract MockRegistry is BaseRegistry { | ||
/// @notice Create a new instance of the registry contract | ||
/// @param max The maximum number of projects that can be registered | ||
/// @param url The metadata url | ||
/// @param ownerAddress The owner address | ||
constructor(uint256 max, bytes32 url, address ownerAddress) payable BaseRegistry(max, url, ownerAddress) {} | ||
} |
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 |
---|---|---|
@@ -1,11 +1,14 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; | ||
|
||
import { ICommon } from "../interfaces/ICommon.sol"; | ||
import { IRecipientRegistry } from "../interfaces/IRecipientRegistry.sol"; | ||
|
||
/// @title BaseRegistry | ||
/// @notice Base contract for a registry | ||
abstract contract BaseRegistry is IRecipientRegistry { | ||
abstract contract BaseRegistry is Ownable, IRecipientRegistry, ICommon { | ||
/// @notice The storage of recipients | ||
mapping(uint256 => Recipient) internal recipients; | ||
|
||
|
@@ -19,11 +22,12 @@ abstract contract BaseRegistry is IRecipientRegistry { | |
bytes32 public immutable metadataUrl; | ||
|
||
/// @notice Create a new instance of the registry contract | ||
/// @param _maxRecipients The maximum number of recipients that can be registered | ||
/// @param _metadataUrl The metadata url | ||
constructor(uint256 _maxRecipients, bytes32 _metadataUrl) payable { | ||
maxRecipients = _maxRecipients; | ||
metadataUrl = _metadataUrl; | ||
/// @param max The maximum number of recipients that can be registered | ||
/// @param url The metadata url | ||
/// @param ownerAddress The owner address | ||
constructor(uint256 max, bytes32 url, address ownerAddress) payable Ownable(ownerAddress) { | ||
maxRecipients = max; | ||
metadataUrl = url; | ||
} | ||
|
||
/// @inheritdoc IRecipientRegistry | ||
|
@@ -32,7 +36,7 @@ abstract contract BaseRegistry is IRecipientRegistry { | |
} | ||
|
||
/// @inheritdoc IRecipientRegistry | ||
function addRecipient(Recipient calldata recipient) public virtual override returns (uint256) { | ||
function addRecipient(Recipient calldata recipient) public virtual override onlyOwner returns (uint256) { | ||
uint256 index = recipientCount; | ||
|
||
if (index >= maxRecipients) { | ||
|
@@ -52,7 +56,7 @@ abstract contract BaseRegistry is IRecipientRegistry { | |
} | ||
Check warning Code scanning / Slither Costly operations inside a loop Warning
BaseRegistry.addRecipient(IRecipientRegistry.Recipient) has costly operations inside a loop:
- recipientCount ++ |
||
|
||
/// @inheritdoc IRecipientRegistry | ||
function removeRecipient(uint256 index) public virtual override { | ||
function removeRecipient(uint256 index) public virtual override onlyOwner { | ||
if (index >= recipientCount) { | ||
revert InvalidIndex(); | ||
} | ||
|
@@ -66,7 +70,7 @@ abstract contract BaseRegistry is IRecipientRegistry { | |
} | ||
|
||
/// @inheritdoc IRecipientRegistry | ||
function changeRecipient(uint256 index, Recipient calldata recipient) public virtual override { | ||
function changeRecipient(uint256 index, Recipient calldata recipient) public virtual override onlyOwner { | ||
if (index >= recipientCount) { | ||
revert InvalidIndex(); | ||
} | ||
|
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
49 changes: 49 additions & 0 deletions
49
packages/contracts/contracts/registryManager/EASRegistryManager.sol
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,49 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import { IEAS } from "../interfaces/IEAS.sol"; | ||
import { RegistryManager } from "./RegistryManager.sol"; | ||
|
||
/// @title EASRegistryManager | ||
/// @notice Contract that allows to use send, approve, reject requests to EASRegistry. | ||
contract EASRegistryManager is RegistryManager { | ||
/// @notice custom errors | ||
error NotYourAttestation(); | ||
|
||
/// @notice EAS | ||
IEAS public immutable eas; | ||
|
||
/// @notice Initialize EASRegistryManager | ||
/// @param easAddress EAS contract address | ||
constructor(address easAddress) payable { | ||
if (easAddress == address(0)) { | ||
revert InvalidAddress(); | ||
} | ||
|
||
eas = IEAS(easAddress); | ||
} | ||
|
||
/// @notice Check recipient has an EAS attestation | ||
/// @param request request to the registry | ||
modifier onlyWithAttestation(Request memory request) { | ||
if (request.requestType != RequestType.Change) { | ||
_; | ||
return; | ||
} | ||
|
||
IEAS.Attestation memory attestation = eas.getAttestation(request.recipient.id); | ||
|
||
if (attestation.recipient != request.recipient.recipient) { | ||
revert NotYourAttestation(); | ||
} | ||
|
||
_; | ||
} | ||
|
||
/// @inheritdoc RegistryManager | ||
function process( | ||
Request calldata request | ||
) public virtual override isValidRequest(request) onlyWithAttestation(request) { | ||
super.process(request); | ||
} | ||
} |
Oops, something went wrong.