Skip to content
This repository has been archived by the owner on Jan 11, 2024. It is now read-only.

Diamond registry #153

Merged
merged 36 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
48 changes: 41 additions & 7 deletions scripts/deploy-registry.template
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import hre, { ethers } from 'hardhat';
import { getTransactionFees } from './util';
import { ethers } from 'hardhat';
import { deployContractWithDeployer, getTransactionFees } from './util';

const { getSelectors } = require('./js/diamond.js')

async function main() {
try {

await hre.run('compile');

const [deployer] = await ethers.getSigners();
const balance = await deployer.getBalance();

Expand All @@ -15,8 +14,43 @@ async function main() {
const txArgs = await getTransactionFees();

// deploy
const registry = await ethers.getContractFactory('SubnetRegistry', { signer: deployer, libraries: LIBMAP });
const contract = await registry.deploy(gatewayAddress, txArgs);
const getterFacet = await deployContractWithDeployer(
deployer,
"SubnetActorGetterFacet",
{},
txArgs
);
const getterSelectors = getSelectors(getterFacet);
console.log("getter address:", getterFacet.address);

const managerFacet = await deployContractWithDeployer(
deployer,
"SubnetActorManagerFacet",
{
AccountHelper: LIBMAP['AccountHelper'],
CheckpointHelper: LIBMAP['CheckpointHelper'],
EpochVoteSubmissionHelper: LIBMAP['EpochVoteSubmissionHelper'],
ExecutableQueueHelper: LIBMAP['ExecutableQueueHelper'],
SubnetIDHelper: LIBMAP['SubnetIDHelper'],
CrossMsgHelper: LIBMAP['CrossMsgHelper'],
},
txArgs
);
const managerSelectors = getSelectors(managerFacet);
console.log("manager address:", managerFacet.address);

const registry = await ethers.getContractFactory('SubnetRegistry', { signer: deployer, libraries: {
"SubnetIDHelper": LIBMAP["SubnetIDHelper"]
}});

const contract = await registry.deploy(
gatewayAddress,
getterFacet.address,
managerFacet.address,
getterSelectors,
managerSelectors,
txArgs
);

// FEVM:
console.log(`registry contract deployed to: ${contract.address}`);
Expand Down
75 changes: 58 additions & 17 deletions src/SubnetRegistry.sol
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;

import {SubnetActor} from "./SubnetActor.sol";
import {SubnetID} from "./structs/Subnet.sol";
import {SubnetIDHelper} from "./lib/SubnetIDHelper.sol";
import {SubnetActorDiamond} from "./SubnetActorDiamond.sol";
import {IDiamond} from "./interfaces/IDiamond.sol";

contract SubnetRegistry {
using SubnetIDHelper for SubnetID;
address public immutable gateway;

/// The getter and manager facet shared by diamond
address public getterFacet;
address public managerFacet;

/// The subnet getter facet functions selectors
bytes4[] public subnetGetterSelectors;
/// The subnet manager facet functions selectors
bytes4[] public subnetManagerSelectors;

/// @notice Mapping that tracks the deployed subnet actors per user.
/// Key is the hash of Subnet ID, values are addresses.
Expand All @@ -18,28 +26,55 @@ contract SubnetRegistry {
/// owner => nonce
mapping(address => uint64) public userNonces;

address public immutable gateway;

/// @notice Event emitted when a new subnet is deployed.
event SubnetDeployed(address subnetAddr);

error WrongGateway();
error ZeroGatewayAddress();
error CannotFindSubnet();
error UnknownSubnet();

constructor(address _gateway) {
if (_gateway == address(0)) {
revert ZeroGatewayAddress();
}
constructor(
address _gateway,
address _getterFacet,
address _managerFacet,
bytes4[] memory _subnetGetterSelectors,
bytes4[] memory _subnetManagerSelectors
) {
gateway = _gateway;

getterFacet = _getterFacet;
managerFacet = _managerFacet;

subnetGetterSelectors = _subnetGetterSelectors;
subnetManagerSelectors = _subnetManagerSelectors;
}

function newSubnetActor(SubnetActor.ConstructParams calldata params) external returns (address subnetAddr) {
if (params.ipcGatewayAddr != gateway) {
/// @notice Deploys a new subnet actor.
/// @param _params The constructor params for Subnet Actor Diamond.
function newSubnetActor(
SubnetActorDiamond.ConstructorParams calldata _params
) external returns (address subnetAddr) {
if (_params.ipcGatewayAddr != gateway) {
revert WrongGateway();
}

subnetAddr = address(new SubnetActor(params));
IDiamond.FacetCut[] memory diamondCut = new IDiamond.FacetCut[](2);

// set the diamond cut for subnet getter
diamondCut[0] = IDiamond.FacetCut({
facetAddress: getterFacet,
action: IDiamond.FacetCutAction.Add,
functionSelectors: subnetGetterSelectors
});

// set the diamond cut for subnet manager
diamondCut[1] = IDiamond.FacetCut({
facetAddress: managerFacet,
action: IDiamond.FacetCutAction.Add,
functionSelectors: subnetManagerSelectors
});

subnetAddr = address(new SubnetActorDiamond(diamondCut, _params));

subnets[msg.sender][userNonces[msg.sender]] = subnetAddr;
++userNonces[msg.sender];
Expand All @@ -50,9 +85,15 @@ contract SubnetRegistry {
/// @notice Returns the address of the latest subnet actor
/// deployed by a user
function latestSubnetDeployed(address owner) external view returns (address subnet) {
subnet = subnets[owner][userNonces[owner] - 1];
uint64 nonce = userNonces[owner];
// need unchecked when nonce == 0 or else will underflow
unchecked {
nonce -= 1;
}

subnet = subnets[owner][nonce];
if (subnet == address(0)) {
revert ZeroGatewayAddress();
revert CannotFindSubnet();
}
}

Expand All @@ -61,7 +102,7 @@ contract SubnetRegistry {
function getSubnetDeployedByNonce(address owner, uint64 nonce) external view returns (address subnet) {
subnet = subnets[owner][nonce];
if (subnet == address(0)) {
revert ZeroGatewayAddress();
revert CannotFindSubnet();
}
}
}
18 changes: 16 additions & 2 deletions test/SubnetRegistry.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import "forge-std/console.sol";

import "../src/SubnetRegistry.sol";

import "../src/subnet/SubnetActorGetterFacet.sol";
import "../src/subnet/SubnetActorManagerFacet.sol";

import "../src/lib/SubnetIDHelper.sol";

contract SubnetRegistryTest is Test {
using SubnetIDHelper for SubnetID;

Expand All @@ -26,7 +31,16 @@ contract SubnetRegistryTest is Test {
SubnetRegistry sr;

function setUp() public {
sr = new SubnetRegistry(DEFAULT_IPC_GATEWAY_ADDR);
bytes4[] memory mockedSelectors = new bytes4[](1);
mockedSelectors[0] = 0x6cb2ecee;

bytes4[] memory mockedSelectors2 = new bytes4[](1);
mockedSelectors2[0] = 0x133f74ea;

address getter = address(new SubnetActorGetterFacet());
address manager = address(new SubnetActorManagerFacet());

sr = new SubnetRegistry(DEFAULT_IPC_GATEWAY_ADDR, getter, manager, mockedSelectors, mockedSelectors2);
}

function test_Registry_Deployment_Works() public {
Expand All @@ -53,7 +67,7 @@ contract SubnetRegistryTest is Test {
uint8 _majorityPercentage
) public {
vm.startPrank(DEFAULT_SENDER);
SubnetActor.ConstructParams memory params = SubnetActor.ConstructParams({
SubnetActorDiamond.ConstructorParams memory params = SubnetActorDiamond.ConstructorParams({
parentId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}),
name: _name,
ipcGatewayAddr: _ipcGatewayAddr,
Expand Down