-
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
14 changed files
with
772 additions
and
13 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
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 Common | ||
/// @notice Contract that contains common things for all the contracts | ||
contract Common { | ||
/// @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
84 changes: 84 additions & 0 deletions
84
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,84 @@ | ||
// 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 | ||
} | ||
|
||
/// @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 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 send(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 with index and data | ||
/// @return status The request status | ||
function getRequest(uint256 index) external view returns (Request memory request, Status status); | ||
|
||
/// @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,13 @@ | ||
// 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 maxRecipients The maximum number of projects that can be registered | ||
/// @param metadataUrl The metadata url | ||
constructor(uint256 maxRecipients, bytes32 metadataUrl) payable BaseRegistry(maxRecipients, metadataUrl) {} | ||
} |
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
50 changes: 50 additions & 0 deletions
50
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,50 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import { IEAS } from "../interfaces/IEAS.sol"; | ||
import { IRecipientRegistry } from "../interfaces/IRecipientRegistry.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 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 send( | ||
Request calldata request | ||
) public virtual override isValidRequest(request) onlyWithAttestation(request) { | ||
super.send(request); | ||
} | ||
} |
122 changes: 122 additions & 0 deletions
122
packages/contracts/contracts/registryManager/RegistryManager.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,122 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; | ||
|
||
import { Common } from "../common/Common.sol"; | ||
import { IRecipientRegistry } from "../interfaces/IRecipientRegistry.sol"; | ||
import { IRegistryManager } from "../interfaces/IRegistryManager.sol"; | ||
|
||
/// @title RegistryManager | ||
/// @notice Contract that allows to use send, approve, reject requests to RecipientRegistry. | ||
contract RegistryManager is Ownable, IRegistryManager, Common { | ||
/// @notice requests | ||
mapping(uint256 => Request) internal requests; | ||
|
||
/// @notice request statuses | ||
mapping(uint256 => Status) internal statuses; | ||
|
||
/// @inheritdoc IRegistryManager | ||
uint256 public requestCount; | ||
|
||
/// @notice Initialize registry manager | ||
constructor() payable Ownable(msg.sender) {} | ||
|
||
/// @notice Check if request is valid | ||
modifier isValidRequest(Request calldata request) { | ||
if (request.registry == address(0)) { | ||
revert ValidationError(); | ||
} | ||
|
||
if (request.recipient.recipient == address(0)) { | ||
revert ValidationError(); | ||
} | ||
|
||
uint256 count = IRecipientRegistry(request.registry).recipientCount(); | ||
|
||
if (request.index >= count && request.requestType == RequestType.Change) { | ||
revert ValidationError(); | ||
} | ||
|
||
_; | ||
} | ||
|
||
/// @notice Check if request is pending and exists | ||
/// @param index Request index | ||
modifier isPending(uint256 index) { | ||
if (index >= requestCount || statuses[index] != Status.Pending) { | ||
revert OperationError(); | ||
} | ||
_; | ||
} | ||
|
||
/// @inheritdoc IRegistryManager | ||
function send(Request calldata request) public virtual override isValidRequest(request) { | ||
requests[requestCount] = request; | ||
statuses[requestCount] = Status.Pending; | ||
|
||
unchecked { | ||
requestCount++; | ||
} | ||
|
||
emit RequestSent( | ||
request.registry, | ||
request.requestType, | ||
request.recipient.recipient, | ||
request.index, | ||
request.recipient.id, | ||
request.recipient.metadataUrl | ||
); | ||
} | ||
|
||
/// @inheritdoc IRegistryManager | ||
function approve(uint256 index) public virtual override onlyOwner isPending(index) { | ||
Request memory request = requests[index]; | ||
IRecipientRegistry registry = IRecipientRegistry(request.registry); | ||
|
||
if (request.requestType == RequestType.Change) { | ||
approveRequest(index, request); | ||
registry.changeRecipient(request.index, request.recipient); | ||
} else { | ||
approveRequest(index, request); | ||
registry.addRecipient(request.recipient); | ||
} | ||
} | ||
|
||
/// @notice Internal approve request with state change | ||
/// @param index Index of the request (optional) | ||
/// @param request Request to the registry | ||
function approveRequest(uint256 index, Request memory request) internal { | ||
statuses[index] = Status.Approved; | ||
|
||
emit RequestApproved( | ||
request.registry, | ||
request.requestType, | ||
request.recipient.recipient, | ||
request.index, | ||
request.recipient.id, | ||
request.recipient.metadataUrl | ||
); | ||
} | ||
|
||
/// @inheritdoc IRegistryManager | ||
function reject(uint256 index) public virtual override onlyOwner isPending(index) { | ||
Request memory request = requests[index]; | ||
statuses[index] = Status.Rejected; | ||
|
||
emit RequestRejected( | ||
request.registry, | ||
request.requestType, | ||
request.recipient.recipient, | ||
request.index, | ||
request.recipient.id, | ||
request.recipient.metadataUrl | ||
); | ||
} | ||
|
||
/// @inheritdoc IRegistryManager | ||
function getRequest(uint256 index) public view virtual override returns (Request memory request, Status status) { | ||
request = requests[index]; | ||
status = statuses[index]; | ||
} | ||
} |
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
Oops, something went wrong.