From 2ab98e2c222155f1048f32ee99c73e1bd058e41b Mon Sep 17 00:00:00 2001 From: Pano Skylakis Date: Thu, 13 Jun 2024 11:11:29 +1200 Subject: [PATCH 1/6] WIP: add session activity factory --- contracts/games/session-activity/README.md | 0 .../session-activity/SessionActivity.sol | 67 ++++++++++++++ .../SessionActivityDeployer.sol | 90 +++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 contracts/games/session-activity/README.md create mode 100644 contracts/games/session-activity/SessionActivity.sol create mode 100644 contracts/games/session-activity/SessionActivityDeployer.sol diff --git a/contracts/games/session-activity/README.md b/contracts/games/session-activity/README.md new file mode 100644 index 00000000..e69de29b diff --git a/contracts/games/session-activity/SessionActivity.sol b/contracts/games/session-activity/SessionActivity.sol new file mode 100644 index 00000000..96453d46 --- /dev/null +++ b/contracts/games/session-activity/SessionActivity.sol @@ -0,0 +1,67 @@ +// Copyright (c) Immutable Pty Ltd 2018 - 2024 +// SPDX-License-Identifier: Apache 2 +// solhint-disable not-rely-on-time + +pragma solidity ^0.8.19; + +import {AccessControlEnumerable} from "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; +import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol"; + +error Unauthorized(); +error ContractPaused(); + +/** + * @title SessionActivity - A simple contract that emits an event for the purpose of recording session activity on-chain + * @author Immutable + * @dev The SessionActivity contract is not designed to be upgradeable or extended. + */ +contract SessionActivity is AccessControlEnumerable, Pausable { + /// @notice Indicates that session activity has been recorded for an account + event SessionActivityRecorded(address indexed account, uint256 timestamp); + + /// @notice The name of the contract + string public name; + + /// @notice Role to allow pausing the contract + bytes32 private constant _PAUSE = keccak256("PAUSE"); + + /// @notice Role to allow unpausing the contract + bytes32 private constant _UNPAUSE = keccak256("UNPAUSE"); + + /** + * @notice Sets the DEFAULT_ADMIN, PAUSE and UNPAUSE roles + * @param _admin The address for the admin role + * @param _pauser The address for the pauser role + * @param _unpauser The address for the unpauser role + */ + constructor(address _admin, address _pauser, address _unpauser, string memory _name) { + _grantRole(DEFAULT_ADMIN_ROLE, _admin); + _grantRole(_PAUSE, _pauser); + _grantRole(_UNPAUSE, _unpauser); + name = _name; + } + + /** + * @notice Pauses the contract + */ + function pause() external { + if (!hasRole(_PAUSE, msg.sender)) revert Unauthorized(); + _pause(); + } + + /** + * @notice Unpauses the contract + */ + function unpause() external { + if (!hasRole(_UNPAUSE, msg.sender)) revert Unauthorized(); + _unpause(); + } + + /** + * @notice Function that emits a `SessionActivityRecorded` event + */ + function recordSessionActivity() external { + if (paused()) revert ContractPaused(); + emit SessionActivityRecorded(msg.sender, block.timestamp); + } +} diff --git a/contracts/games/session-activity/SessionActivityDeployer.sol b/contracts/games/session-activity/SessionActivityDeployer.sol new file mode 100644 index 00000000..155df989 --- /dev/null +++ b/contracts/games/session-activity/SessionActivityDeployer.sol @@ -0,0 +1,90 @@ +// Copyright (c) Immutable Pty Ltd 2018 - 2024 +// SPDX-License-Identifier: Apache 2 +// solhint-disable not-rely-on-time + +pragma solidity ^0.8.19; + +import {AccessControlEnumerable} from "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; +import {SessionActivity} from "./SessionActivity.sol"; + +error Unauthorized(); +error NameAlreadyRegistered(); + +/** + * @title SessionActivityDeployer - A factory contract that deploys SessionActivity contracts and tracks their addresses and names + * @author Immutable + * @dev The SessionActivityDeployer contract is not designed to be upgradeable or extended. + */ +contract SessionActivityDeployer is AccessControlEnumerable { + /// @notice Indicates that an account has registered session activity + event SessionActivityDeployed(address indexed account, string indexed name); + + /// @notice Mapping of deployed SessionActivity contract addresses to their names + /// @dev To get a list of all deployed contract names, iterate over the deployedContracts array and use this mapping + mapping(address deployedContract => string name) public sessionActivityNames; + + /// @notice Mapping of SessionActivity contract names to their addresses + /// @dev To get a list of all deployed contract addresses, iterate over the names array and use this mapping + mapping(string name => address deployedContract) public sessionActivityContracts; + + /// @notice Array of deployed SessionActivity contracts + address[] public deployedContracts; + + /// @notice Array of deployed SessionActivity contract names + string[] public names; + + /// @notice Role to allow deploying SessionActivity contracts + bytes32 private constant _DEPLOYER_ROLE = keccak256("DEPLOYER"); + + /// @notice The address for the pauser role on the SessionActivity contract + address private _pauser; + + /// @notice The address for the unpauser role on the SessionActivity contract + address private _unpauser; + + /** + * @notice Sets the DEFAULT_ADMIN, PAUSE and UNPAUSE roles + * @param admin The address for the admin role + * @param deployer The address for the deployer role + * @param pauser The address for the pauser role on the SessionActivity contract + * @param unpauser The address for the unpauser role on the SessionActivity contract + */ + constructor(address admin, address deployer, address pauser, address unpauser) { + _grantRole(DEFAULT_ADMIN_ROLE, admin); + _grantRole(_DEPLOYER_ROLE, deployer); + _pauser = pauser; + _unpauser = unpauser; + } + + /** + * @notice Deploys a new SessionActivity contract + * @param name The name of the SessionActivity contract + * @dev Only accounts granted the _DEPLOYER_ROLE can call this function + */ + function deploy(string memory name) public { + // Ensure the caller has the deployer role + if (!hasRole(_DEPLOYER_ROLE, msg.sender)) revert Unauthorized(); + + // Loop through names and ensure the provided name is unique + for (uint256 i = 0; i < names.length; i++) { + if (keccak256(abi.encodePacked(names[i])) == keccak256(abi.encodePacked(name))) { + revert NameAlreadyRegistered(); + } + } + + // Get the existing admin role + address admin = getRoleMember(DEFAULT_ADMIN_ROLE, 0); + + // Deploy the session activity contract + SessionActivity sessionActivityContract = new SessionActivity(admin, _pauser, _unpauser, name); + + // Register the contract address and name + sessionActivityNames[address(sessionActivityContract)] = name; + deployedContracts.push(address(sessionActivityContract)); + + sessionActivityContracts[name] = address(sessionActivityContract); + names.push(name); + + emit SessionActivityDeployed(msg.sender, name); + } +} From 385010362db6b45445777c95166653e71f6acbc2 Mon Sep 17 00:00:00 2001 From: Pano Skylakis Date: Wed, 19 Jun 2024 13:49:15 +1200 Subject: [PATCH 2/6] Refactor: remove mappings --- .../SessionActivityDeployer.sol | 33 ++----------------- 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/contracts/games/session-activity/SessionActivityDeployer.sol b/contracts/games/session-activity/SessionActivityDeployer.sol index 155df989..5603efa9 100644 --- a/contracts/games/session-activity/SessionActivityDeployer.sol +++ b/contracts/games/session-activity/SessionActivityDeployer.sol @@ -17,21 +17,7 @@ error NameAlreadyRegistered(); */ contract SessionActivityDeployer is AccessControlEnumerable { /// @notice Indicates that an account has registered session activity - event SessionActivityDeployed(address indexed account, string indexed name); - - /// @notice Mapping of deployed SessionActivity contract addresses to their names - /// @dev To get a list of all deployed contract names, iterate over the deployedContracts array and use this mapping - mapping(address deployedContract => string name) public sessionActivityNames; - - /// @notice Mapping of SessionActivity contract names to their addresses - /// @dev To get a list of all deployed contract addresses, iterate over the names array and use this mapping - mapping(string name => address deployedContract) public sessionActivityContracts; - - /// @notice Array of deployed SessionActivity contracts - address[] public deployedContracts; - - /// @notice Array of deployed SessionActivity contract names - string[] public names; + event SessionActivityDeployed(address indexed account, address indexed deployedContract, string indexed name); /// @notice Role to allow deploying SessionActivity contracts bytes32 private constant _DEPLOYER_ROLE = keccak256("DEPLOYER"); @@ -65,26 +51,11 @@ contract SessionActivityDeployer is AccessControlEnumerable { // Ensure the caller has the deployer role if (!hasRole(_DEPLOYER_ROLE, msg.sender)) revert Unauthorized(); - // Loop through names and ensure the provided name is unique - for (uint256 i = 0; i < names.length; i++) { - if (keccak256(abi.encodePacked(names[i])) == keccak256(abi.encodePacked(name))) { - revert NameAlreadyRegistered(); - } - } - // Get the existing admin role address admin = getRoleMember(DEFAULT_ADMIN_ROLE, 0); // Deploy the session activity contract SessionActivity sessionActivityContract = new SessionActivity(admin, _pauser, _unpauser, name); - - // Register the contract address and name - sessionActivityNames[address(sessionActivityContract)] = name; - deployedContracts.push(address(sessionActivityContract)); - - sessionActivityContracts[name] = address(sessionActivityContract); - names.push(name); - - emit SessionActivityDeployed(msg.sender, name); + emit SessionActivityDeployed(msg.sender, address(sessionActivityContract), name); } } From d0d9c15fddfe9c2ddf6d1baf58b6c10deb6cd398 Mon Sep 17 00:00:00 2001 From: Pano Skylakis Date: Wed, 19 Jun 2024 15:59:41 +1200 Subject: [PATCH 3/6] Add deployment test --- .../SessionActivityDeployer.sol | 6 +- .../DeploySessionActivityDeployer.sol | 161 ++++++++++++++++++ 2 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 script/games/session-activity/DeploySessionActivityDeployer.sol diff --git a/contracts/games/session-activity/SessionActivityDeployer.sol b/contracts/games/session-activity/SessionActivityDeployer.sol index 5603efa9..ff0d1e40 100644 --- a/contracts/games/session-activity/SessionActivityDeployer.sol +++ b/contracts/games/session-activity/SessionActivityDeployer.sol @@ -11,7 +11,7 @@ error Unauthorized(); error NameAlreadyRegistered(); /** - * @title SessionActivityDeployer - A factory contract that deploys SessionActivity contracts and tracks their addresses and names + * @title SessionActivityDeployer - A factory contract that deploys SessionActivity contracts * @author Immutable * @dev The SessionActivityDeployer contract is not designed to be upgradeable or extended. */ @@ -47,7 +47,7 @@ contract SessionActivityDeployer is AccessControlEnumerable { * @param name The name of the SessionActivity contract * @dev Only accounts granted the _DEPLOYER_ROLE can call this function */ - function deploy(string memory name) public { + function deploy(string memory name) public returns (SessionActivity) { // Ensure the caller has the deployer role if (!hasRole(_DEPLOYER_ROLE, msg.sender)) revert Unauthorized(); @@ -57,5 +57,7 @@ contract SessionActivityDeployer is AccessControlEnumerable { // Deploy the session activity contract SessionActivity sessionActivityContract = new SessionActivity(admin, _pauser, _unpauser, name); emit SessionActivityDeployed(msg.sender, address(sessionActivityContract), name); + + return sessionActivityContract; } } diff --git a/script/games/session-activity/DeploySessionActivityDeployer.sol b/script/games/session-activity/DeploySessionActivityDeployer.sol new file mode 100644 index 00000000..ae70a606 --- /dev/null +++ b/script/games/session-activity/DeploySessionActivityDeployer.sol @@ -0,0 +1,161 @@ +// Copyright (c) Immutable Pty Ltd 2018 - 2023 +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.20; + +import "forge-std/Test.sol"; +import {SessionActivity} from "../../../contracts/games/session-activity/SessionActivity.sol"; +import { + SessionActivityDeployer, + Unauthorized +} from "../../../contracts/games/session-activity/SessionActivityDeployer.sol"; + +/** + * @title IDeployer Interface + * @notice This interface defines the contract responsible for deploying and optionally initializing new contracts + * via a specified deployment method. + * @dev Credit to axelarnetwork https://github.com/axelarnetwork/axelar-gmp-sdk-solidity/blob/main/contracts/interfaces/IDeployer.sol + */ +interface IDeployer { + function deploy(bytes memory bytecode, bytes32 salt) external payable returns (address deployedAddress_); + function deployAndInit(bytes memory bytecode, bytes32 salt, bytes calldata init) + external + payable + returns (address deployedAddress_); + function deployedAddress(bytes calldata bytecode, address sender, bytes32 salt) + external + view + returns (address deployedAddress_); +} + +struct DeploymentArgs { + address signer; + address factory; + string salt; +} + +struct SessionActivityContractArgs { + address defaultAdmin; + address pauser; + address unpauser; + string name; +} + +struct SessionActivityDeployerArgs { + address admin; + address deployer; + address pauser; + address unpauser; +} + +contract DeploySessionActivityDeployer is Test { + event SessionActivityRecorded(address indexed account, uint256 timestamp); + event SessionActivityDeployed(address indexed account, address indexed deployedContract, string indexed name); + + function testDeploy() external { + /// @dev Fork the Immutable zkEVM testnet for this test + string memory rpcURL = "https://rpc.testnet.immutable.com"; + vm.createSelectFork(rpcURL); + + /// @dev These are Immutable zkEVM testnet values where necessary + DeploymentArgs memory deploymentArgs = DeploymentArgs({ + signer: 0xdDA0d9448Ebe3eA43aFecE5Fa6401F5795c19333, + factory: 0x37a59A845Bb6eD2034098af8738fbFFB9D589610, + salt: "salty" + }); + + SessionActivityDeployerArgs memory sessionActivityDeployerArgs = SessionActivityDeployerArgs({ + pauser: makeAddr("pause"), + unpauser: makeAddr("unpause"), + admin: makeAddr("admin"), + deployer: makeAddr("deployer") + }); + + // Run deployment against forked testnet + SessionActivityDeployer deployerContract = _deploy(deploymentArgs, sessionActivityDeployerArgs); + + // Assert roles are assigned correctly + assertEq(true, deployerContract.hasRole(keccak256("DEPLOYER"), sessionActivityDeployerArgs.deployer)); + assertEq( + true, deployerContract.hasRole(deployerContract.DEFAULT_ADMIN_ROLE(), sessionActivityDeployerArgs.admin) + ); + + // The DEFAULT_ADMIN_ROLE should be revoked from the deployer account and the factory contract address + assertEq(false, deployerContract.hasRole(deployerContract.DEFAULT_ADMIN_ROLE(), deploymentArgs.signer)); + assertEq(false, deployerContract.hasRole(deployerContract.DEFAULT_ADMIN_ROLE(), deploymentArgs.factory)); + + // Try to deploy a contract without the deployer role expecting a revert + vm.prank(makeAddr("notdeployer")); + vm.expectRevert(Unauthorized.selector); + deployerContract.deploy("SessionActivity"); + + // Deploy a contract with the deployer role + vm.prank(sessionActivityDeployerArgs.deployer); + vm.expectEmit(true, false, true, false); + emit SessionActivityDeployed(sessionActivityDeployerArgs.deployer, address(0), "MyCoolGame"); + SessionActivity deployedSessionActivityContract = deployerContract.deploy("MyCoolGame"); + + // Asset roles are assigned correctly on the child contract + assertEq(true, deployedSessionActivityContract.hasRole(keccak256("PAUSE"), sessionActivityDeployerArgs.pauser)); + assertEq( + true, deployedSessionActivityContract.hasRole(keccak256("UNPAUSE"), sessionActivityDeployerArgs.unpauser) + ); + assertEq( + true, + deployedSessionActivityContract.hasRole( + deployedSessionActivityContract.DEFAULT_ADMIN_ROLE(), sessionActivityDeployerArgs.admin + ) + ); + + // Record a session activity + vm.expectEmit(true, true, true, false); + emit SessionActivityRecorded(address(0), block.timestamp); + deployedSessionActivityContract.recordSessionActivity(); + } + + function deploy() external { + address signer = vm.envAddress("SIGNER_ADDRESS"); + address factory = vm.envAddress("OWNABLE_CREATE3_FACTORY_ADDRESS"); + string memory salt = vm.envString("SESSION_ACTIVITY_DEPLOYER_SALT"); + + DeploymentArgs memory deploymentArgs = DeploymentArgs({signer: signer, factory: factory, salt: salt}); + + address defaultAdmin = vm.envAddress("DEFAULT_ADMIN"); + address deployer = vm.envAddress("DEPLOYER"); + address pauser = vm.envAddress("PAUSER"); + address unpauser = vm.envAddress("UNPAUSER"); + + SessionActivityDeployerArgs memory sessionActivityDeployerArgs = + SessionActivityDeployerArgs({admin: defaultAdmin, deployer: deployer, pauser: pauser, unpauser: unpauser}); + + _deploy(deploymentArgs, sessionActivityDeployerArgs); + } + + function _deploy( + DeploymentArgs memory deploymentArgs, + SessionActivityDeployerArgs memory sessionActivityDeployerArgs + ) internal returns (SessionActivityDeployer sessionActivityDeployerContract) { + IDeployer ownableCreate3 = IDeployer(deploymentArgs.factory); + + // Create deployment bytecode and encode constructor args + bytes memory deploymentBytecode = abi.encodePacked( + type(SessionActivityDeployer).creationCode, + abi.encode( + sessionActivityDeployerArgs.admin, + sessionActivityDeployerArgs.deployer, + sessionActivityDeployerArgs.pauser, + sessionActivityDeployerArgs.unpauser + ) + ); + + bytes32 saltBytes = keccak256(abi.encode(deploymentArgs.salt)); + + /// @dev Deploy the contract via the Ownable CREATE3 factory + vm.startBroadcast(deploymentArgs.signer); + + address sessionActivityDeployerAddress = ownableCreate3.deploy(deploymentBytecode, saltBytes); + sessionActivityDeployerContract = SessionActivityDeployer(sessionActivityDeployerAddress); + + vm.stopBroadcast(); + } +} From fd289349d82cd10ce66c9b6d0c2275f79c350ce5 Mon Sep 17 00:00:00 2001 From: Pano Skylakis Date: Wed, 19 Jun 2024 17:17:16 +1200 Subject: [PATCH 4/6] Fix test --- script/games/session-activity/DeploySessionActivityDeployer.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/games/session-activity/DeploySessionActivityDeployer.sol b/script/games/session-activity/DeploySessionActivityDeployer.sol index ae70a606..ec73d582 100644 --- a/script/games/session-activity/DeploySessionActivityDeployer.sol +++ b/script/games/session-activity/DeploySessionActivityDeployer.sol @@ -109,7 +109,7 @@ contract DeploySessionActivityDeployer is Test { // Record a session activity vm.expectEmit(true, true, true, false); - emit SessionActivityRecorded(address(0), block.timestamp); + emit SessionActivityRecorded(address(this), block.timestamp); deployedSessionActivityContract.recordSessionActivity(); } From 69120d8a1d50a329a310117c15dd668452d7b027 Mon Sep 17 00:00:00 2001 From: Pano Skylakis Date: Wed, 19 Jun 2024 17:25:24 +1200 Subject: [PATCH 5/6] temp: use proxy deployer --- .../DeploySessionActivityDeployer.sol | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/script/games/session-activity/DeploySessionActivityDeployer.sol b/script/games/session-activity/DeploySessionActivityDeployer.sol index ec73d582..fdd1335e 100644 --- a/script/games/session-activity/DeploySessionActivityDeployer.sol +++ b/script/games/session-activity/DeploySessionActivityDeployer.sol @@ -28,9 +28,14 @@ interface IDeployer { returns (address deployedAddress_); } +interface INewDeployer { + function deploy(IDeployer deployer, bytes memory bytecode, bytes32 salt) external payable returns (address); +} + struct DeploymentArgs { address signer; address factory; + address actualDeployer; string salt; } @@ -59,8 +64,9 @@ contract DeploySessionActivityDeployer is Test { /// @dev These are Immutable zkEVM testnet values where necessary DeploymentArgs memory deploymentArgs = DeploymentArgs({ - signer: 0xdDA0d9448Ebe3eA43aFecE5Fa6401F5795c19333, - factory: 0x37a59A845Bb6eD2034098af8738fbFFB9D589610, + signer: 0xE4D45C0277762CaD4EC40bE69406068DAE74E17d, + factory: 0xFB1Ecc73c3f3F505d66C055A3571362DE001D9C0, + actualDeployer: 0x0B5B1d92259b13D516cCd5a6E63d7D94Ea2A4836, salt: "salty" }); @@ -116,9 +122,11 @@ contract DeploySessionActivityDeployer is Test { function deploy() external { address signer = vm.envAddress("SIGNER_ADDRESS"); address factory = vm.envAddress("OWNABLE_CREATE3_FACTORY_ADDRESS"); + address actualDeployer = vm.envAddress("ACTUAL_DEPLOYER_ADDRESS"); string memory salt = vm.envString("SESSION_ACTIVITY_DEPLOYER_SALT"); - DeploymentArgs memory deploymentArgs = DeploymentArgs({signer: signer, factory: factory, salt: salt}); + DeploymentArgs memory deploymentArgs = + DeploymentArgs({signer: signer, factory: factory, salt: salt, actualDeployer: actualDeployer}); address defaultAdmin = vm.envAddress("DEFAULT_ADMIN"); address deployer = vm.envAddress("DEPLOYER"); @@ -135,6 +143,7 @@ contract DeploySessionActivityDeployer is Test { DeploymentArgs memory deploymentArgs, SessionActivityDeployerArgs memory sessionActivityDeployerArgs ) internal returns (SessionActivityDeployer sessionActivityDeployerContract) { + INewDeployer actualDeployer = INewDeployer(deploymentArgs.actualDeployer); IDeployer ownableCreate3 = IDeployer(deploymentArgs.factory); // Create deployment bytecode and encode constructor args @@ -153,7 +162,7 @@ contract DeploySessionActivityDeployer is Test { /// @dev Deploy the contract via the Ownable CREATE3 factory vm.startBroadcast(deploymentArgs.signer); - address sessionActivityDeployerAddress = ownableCreate3.deploy(deploymentBytecode, saltBytes); + address sessionActivityDeployerAddress = actualDeployer.deploy(ownableCreate3, deploymentBytecode, saltBytes); sessionActivityDeployerContract = SessionActivityDeployer(sessionActivityDeployerAddress); vm.stopBroadcast(); From dfbd0002f67b152b48cdf7adcbb2224ea62c21a6 Mon Sep 17 00:00:00 2001 From: Pano Skylakis Date: Thu, 20 Jun 2024 10:44:02 +1200 Subject: [PATCH 6/6] Update test to use access controlled factory --- .../DeploySessionActivityDeployer.sol | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/script/games/session-activity/DeploySessionActivityDeployer.sol b/script/games/session-activity/DeploySessionActivityDeployer.sol index fdd1335e..be30b63b 100644 --- a/script/games/session-activity/DeploySessionActivityDeployer.sol +++ b/script/games/session-activity/DeploySessionActivityDeployer.sol @@ -28,24 +28,17 @@ interface IDeployer { returns (address deployedAddress_); } -interface INewDeployer { +interface IAccessControlledDeployer { function deploy(IDeployer deployer, bytes memory bytecode, bytes32 salt) external payable returns (address); } struct DeploymentArgs { address signer; - address factory; - address actualDeployer; + address create3Factory; + address accessControlledDeployer; string salt; } -struct SessionActivityContractArgs { - address defaultAdmin; - address pauser; - address unpauser; - string name; -} - struct SessionActivityDeployerArgs { address admin; address deployer; @@ -65,8 +58,8 @@ contract DeploySessionActivityDeployer is Test { /// @dev These are Immutable zkEVM testnet values where necessary DeploymentArgs memory deploymentArgs = DeploymentArgs({ signer: 0xE4D45C0277762CaD4EC40bE69406068DAE74E17d, - factory: 0xFB1Ecc73c3f3F505d66C055A3571362DE001D9C0, - actualDeployer: 0x0B5B1d92259b13D516cCd5a6E63d7D94Ea2A4836, + create3Factory: 0xFB1Ecc73c3f3F505d66C055A3571362DE001D9C0, + accessControlledDeployer: 0x0B5B1d92259b13D516cCd5a6E63d7D94Ea2A4836, salt: "salty" }); @@ -88,18 +81,18 @@ contract DeploySessionActivityDeployer is Test { // The DEFAULT_ADMIN_ROLE should be revoked from the deployer account and the factory contract address assertEq(false, deployerContract.hasRole(deployerContract.DEFAULT_ADMIN_ROLE(), deploymentArgs.signer)); - assertEq(false, deployerContract.hasRole(deployerContract.DEFAULT_ADMIN_ROLE(), deploymentArgs.factory)); + assertEq(false, deployerContract.hasRole(deployerContract.DEFAULT_ADMIN_ROLE(), deploymentArgs.create3Factory)); // Try to deploy a contract without the deployer role expecting a revert vm.prank(makeAddr("notdeployer")); vm.expectRevert(Unauthorized.selector); - deployerContract.deploy("SessionActivity"); + deployerContract.deploy("atestname"); // Deploy a contract with the deployer role vm.prank(sessionActivityDeployerArgs.deployer); vm.expectEmit(true, false, true, false); - emit SessionActivityDeployed(sessionActivityDeployerArgs.deployer, address(0), "MyCoolGame"); - SessionActivity deployedSessionActivityContract = deployerContract.deploy("MyCoolGame"); + emit SessionActivityDeployed(sessionActivityDeployerArgs.deployer, address(0), "atestname"); + SessionActivity deployedSessionActivityContract = deployerContract.deploy("atestname"); // Asset roles are assigned correctly on the child contract assertEq(true, deployedSessionActivityContract.hasRole(keccak256("PAUSE"), sessionActivityDeployerArgs.pauser)); @@ -121,12 +114,16 @@ contract DeploySessionActivityDeployer is Test { function deploy() external { address signer = vm.envAddress("SIGNER_ADDRESS"); - address factory = vm.envAddress("OWNABLE_CREATE3_FACTORY_ADDRESS"); - address actualDeployer = vm.envAddress("ACTUAL_DEPLOYER_ADDRESS"); + address create3Factory = vm.envAddress("OWNABLE_CREATE3_FACTORY_ADDRESS"); + address accessControlledDeployer = vm.envAddress("ACCESS_CONTROLLED_DEPLOYER_ADDRESS"); string memory salt = vm.envString("SESSION_ACTIVITY_DEPLOYER_SALT"); - DeploymentArgs memory deploymentArgs = - DeploymentArgs({signer: signer, factory: factory, salt: salt, actualDeployer: actualDeployer}); + DeploymentArgs memory deploymentArgs = DeploymentArgs({ + signer: signer, + create3Factory: create3Factory, + salt: salt, + accessControlledDeployer: accessControlledDeployer + }); address defaultAdmin = vm.envAddress("DEFAULT_ADMIN"); address deployer = vm.envAddress("DEPLOYER"); @@ -143,8 +140,9 @@ contract DeploySessionActivityDeployer is Test { DeploymentArgs memory deploymentArgs, SessionActivityDeployerArgs memory sessionActivityDeployerArgs ) internal returns (SessionActivityDeployer sessionActivityDeployerContract) { - INewDeployer actualDeployer = INewDeployer(deploymentArgs.actualDeployer); - IDeployer ownableCreate3 = IDeployer(deploymentArgs.factory); + IAccessControlledDeployer accessControlledDeployer = + IAccessControlledDeployer(deploymentArgs.accessControlledDeployer); + IDeployer create3Factory = IDeployer(deploymentArgs.create3Factory); // Create deployment bytecode and encode constructor args bytes memory deploymentBytecode = abi.encodePacked( @@ -162,7 +160,8 @@ contract DeploySessionActivityDeployer is Test { /// @dev Deploy the contract via the Ownable CREATE3 factory vm.startBroadcast(deploymentArgs.signer); - address sessionActivityDeployerAddress = actualDeployer.deploy(ownableCreate3, deploymentBytecode, saltBytes); + address sessionActivityDeployerAddress = + accessControlledDeployer.deploy(create3Factory, deploymentBytecode, saltBytes); sessionActivityDeployerContract = SessionActivityDeployer(sessionActivityDeployerAddress); vm.stopBroadcast();