Skip to content

Commit

Permalink
Add zone manager role to ImmutableSignedZoneV2 (#210)
Browse files Browse the repository at this point in the history
  • Loading branch information
lfportal authored Apr 22, 2024
1 parent bcd3af9 commit f6dffe0
Show file tree
Hide file tree
Showing 8 changed files with 342 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
// solhint-disable-next-line compiler-version
pragma solidity ^0.8.20;

import {ZoneInterface} from "seaport/contracts/interfaces/ZoneInterface.sol";
import {ZoneParameters, Schema, ReceivedItem} from "seaport-types/src/lib/ConsiderationStructs.sol";
import {AccessControlEnumerable} from "openzeppelin-contracts-5.0.2/access/extensions/AccessControlEnumerable.sol";
import {ECDSA} from "openzeppelin-contracts-5.0.2/utils/cryptography/ECDSA.sol";
import {MessageHashUtils} from "openzeppelin-contracts-5.0.2/utils/cryptography/MessageHashUtils.sol";
import {ERC165} from "openzeppelin-contracts-5.0.2/utils/introspection/ERC165.sol";
import {Math} from "openzeppelin-contracts-5.0.2/utils/math/Math.sol";
import {ZoneInterface} from "seaport/contracts/interfaces/ZoneInterface.sol";
import {ZoneParameters, Schema, ReceivedItem} from "seaport-types/src/lib/ConsiderationStructs.sol";
import {ZoneAccessControl} from "./ZoneAccessControl.sol";
import {SIP5Interface} from "./interfaces/SIP5Interface.sol";
import {SIP6Interface} from "./interfaces/SIP6Interface.sol";
import {SIP7Interface} from "./interfaces/SIP7Interface.sol";
Expand All @@ -24,11 +25,11 @@ import {SIP7Interface} from "./interfaces/SIP7Interface.sol";
*/
contract ImmutableSignedZoneV2 is
ERC165,
ZoneAccessControl,
ZoneInterface,
SIP5Interface,
SIP6Interface,
SIP7Interface,
AccessControlEnumerable
SIP7Interface
{
/// @dev The EIP-712 domain type hash.
bytes32 private constant _EIP_712_DOMAIN_TYPEHASH = keccak256(
Expand Down Expand Up @@ -82,7 +83,9 @@ contract ImmutableSignedZoneV2 is
* @param owner The address of the owner of this contract. Specified in the
* constructor to be CREATE2 / CREATE3 compatible.
*/
constructor(string memory zoneName, string memory apiEndpoint, string memory documentationURI, address owner) {
constructor(string memory zoneName, string memory apiEndpoint, string memory documentationURI, address owner)
ZoneAccessControl(owner)
{
// Set the zone name.
_ZONE_NAME = zoneName;

Expand All @@ -100,17 +103,14 @@ contract ImmutableSignedZoneV2 is

// Emit an event to signal a SIP-5 contract has been deployed.
emit SeaportCompatibleContractDeployed();

// Grant admin role to the specified owner.
_grantRole(DEFAULT_ADMIN_ROLE, owner);
}

/**
* @notice Add a new signer to the zone.
*
* @param signer The new signer address to add.
*/
function addSigner(address signer) external override onlyRole(DEFAULT_ADMIN_ROLE) {
function addSigner(address signer) external override onlyRole(ZONE_MANAGER_ROLE) {
// Do not allow the zero address to be added as a signer.
if (signer == address(0)) {
revert SignerCannotBeZeroAddress();
Expand Down Expand Up @@ -140,7 +140,7 @@ contract ImmutableSignedZoneV2 is
*
* @param signer The signer address to remove.
*/
function removeSigner(address signer) external override onlyRole(DEFAULT_ADMIN_ROLE) {
function removeSigner(address signer) external override onlyRole(ZONE_MANAGER_ROLE) {
// Revert if the signer is not active.
if (!_signers[signer].active) {
revert SignerNotActive(signer);
Expand All @@ -158,7 +158,7 @@ contract ImmutableSignedZoneV2 is
*
* @param newApiEndpoint The new API endpoint.
*/
function updateAPIEndpoint(string calldata newApiEndpoint) external override onlyRole(DEFAULT_ADMIN_ROLE) {
function updateAPIEndpoint(string calldata newApiEndpoint) external override onlyRole(ZONE_MANAGER_ROLE) {
_apiEndpoint = newApiEndpoint;
}

Expand All @@ -170,7 +170,7 @@ contract ImmutableSignedZoneV2 is
function updateDocumentationURI(string calldata newDocumentationURI)
external
override
onlyRole(DEFAULT_ADMIN_ROLE)
onlyRole(ZONE_MANAGER_ROLE)
{
_documentationURI = newDocumentationURI;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,16 @@ flowchart LR
seaport -- 3a. transferFrom --> erc20[IERC20.sol]
seaport -- 3b. transferFrom --> erc721[IERC721.sol]
seaport -- 3c. safeTransferFrom --> erc1155[IERC1155.sol]
seaport -- 4. validateOrder --> zone[ImmutableSignedZoneV2.sol]
seaport -- 4. validateOrder --> Zone
subgraph Zone
direction TB
zone[ImmutableSignedZoneV2.sol] --> AccessControlEnumerable.sol
end
```

The sequence of events is as follows:

1. The client makes a HTTP `POST .../fulfillment-data` request to the Immutable Orderbook, which will construct signs and sign an `extraData` payload to return to the client
1. The client makes a HTTP `POST .../fulfillment-data` request to the Immutable Orderbook, which will construct and sign an `extraData` payload to return to the client
2. The client calls `fulfillAdvancedOrder` or `fulfillAvailableAdavancedOrders` on `ImmutableSeaport.sol` to fulfill an order
3. `ImmutableSeaport.sol` executes the fufilment by transferring items between parties
4. `ImmutableSeaport.sol` calls `validateOrder` on `ImmutableSignedZoneV2.sol`, passing it the fulfilment execution details as well as the `extraData` parameter
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) Immutable Pty Ltd 2018 - 2024
// SPDX-License-Identifier: Apache-2

// solhint-disable-next-line compiler-version
pragma solidity ^0.8.20;

import {AccessControl} from "openzeppelin-contracts-5.0.2/access/AccessControl.sol";
import {IAccessControl} from "openzeppelin-contracts-5.0.2/access/IAccessControl.sol";
import {AccessControlEnumerable} from "openzeppelin-contracts-5.0.2/access/extensions/AccessControlEnumerable.sol";
import {ZoneAccessControlEventsAndErrors} from
"../../../../../../contracts/trading/seaport/zones/immutable-signed-zone/v2/interfaces/ZoneAccessControlEventsAndErrors.sol";

/**
* @notice ZoneAccessControl encapsulates access control functionality for the zone.
*/
abstract contract ZoneAccessControl is AccessControlEnumerable, ZoneAccessControlEventsAndErrors {
/// @dev Zone manager manages the zone.
bytes32 public constant ZONE_MANAGER_ROLE = bytes32("ZONE_MANAGER");

/**
* @notice Constructor to setup initial default admin.
*
* @param owner The address to assign the DEFAULT_ADMIN_ROLE.
*/
constructor(address owner) {
// Grant admin role to the specified owner.
_grantRole(DEFAULT_ADMIN_ROLE, owner);
}

/**
* @inheritdoc AccessControl
*/
function revokeRole(bytes32 role, address account) public override(AccessControl, IAccessControl) onlyRole(getRoleAdmin(role)) {
super.revokeRole(role, account);

if (role == DEFAULT_ADMIN_ROLE && super.getRoleMemberCount(DEFAULT_ADMIN_ROLE) == 0) {
revert LastDefaultAdminRole(account);
}
}

/**
* @inheritdoc AccessControl
*/
function renounceRole(bytes32 role, address callerConfirmation) public override(AccessControl, IAccessControl) {
super.renounceRole(role, callerConfirmation);

if (role == DEFAULT_ADMIN_ROLE && super.getRoleMemberCount(DEFAULT_ADMIN_ROLE) == 0) {
revert LastDefaultAdminRole(callerConfirmation);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Immutable Pty Ltd 2018 - 2024
// SPDX-License-Identifier: Apache-2

// solhint-disable compiler-version
pragma solidity ^0.8.17;

/**
* @notice ZoneAccessControlEventsAndErrors contains errors and events
* related to zone access control.
*/
interface ZoneAccessControlEventsAndErrors {
/**
* @dev Revert with an error if revoking last DEFAULT_ADMIN_ROLE.
*/
error LastDefaultAdminRole(address account);
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ contract ImmutableSeaportSignedZoneV2IntegrationTest is Test, SigningTestHelper
"./foundry-out/ImmutableSignedZoneV2Harness.t.sol/ImmutableSignedZoneV2Harness.json";

address private immutable OWNER = makeAddr("owner");
address private immutable ZONE_MANAGER = makeAddr("zone_manager");
address private immutable SIGNER;
uint256 private immutable SIGNER_PRIVATE_KEY;
address private immutable FULFILLER = makeAddr("fulfiller");
Expand Down Expand Up @@ -98,6 +99,10 @@ contract ImmutableSeaportSignedZoneV2IntegrationTest is Test, SigningTestHelper
)
);
vm.prank(OWNER);
bytes32 managerRole = zone.ZONE_MANAGER_ROLE();
vm.prank(OWNER);
zone.grantRole(managerRole, ZONE_MANAGER);
vm.prank(ZONE_MANAGER);
zone.addSigner(SIGNER);

// seaport
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ import {SIP7Interface} from
// solhint-disable func-name-mixedcase

interface IImmutableSignedZoneV2Harness is ZoneInterface, SIP7Interface {
function grantRole(bytes32 role, address account) external;

function DEFAULT_ADMIN_ROLE() external view returns (bytes32);

function ZONE_MANAGER_ROLE() external view returns (bytes32);

function exposed_domainSeparator() external view returns (bytes32);

function exposed_deriveDomainSeparator() external view returns (bytes32 domainSeparator);
Expand Down
Loading

0 comments on commit f6dffe0

Please sign in to comment.