From d08a3b9e771598d526a1276fa7f28e7b62c3e7a7 Mon Sep 17 00:00:00 2001 From: neokry Date: Wed, 27 Dec 2023 15:46:32 -0800 Subject: [PATCH] Add minimum metadata calls to migration deployer --- src/deployers/L2MigrationDeployer.sol | 54 ++++++++++++++++++++------- test/L2MigrationDeployer.t.sol | 50 +++++++++++++++++++++++-- 2 files changed, 87 insertions(+), 17 deletions(-) diff --git a/src/deployers/L2MigrationDeployer.sol b/src/deployers/L2MigrationDeployer.sol index ded126f..e2aa1e2 100644 --- a/src/deployers/L2MigrationDeployer.sol +++ b/src/deployers/L2MigrationDeployer.sol @@ -15,6 +15,20 @@ import { OPAddressAliasHelper } from "../lib/utils/OPAddressAliasHelper.sol"; /// @dev This contract is designed to be called from the OPStack L1CrossDomainMessenger or OptimismPortal /// @author @neokry contract L2MigrationDeployer { + /// /// + /// STRUCTS /// + /// /// + + /// @notice The migration configuration for a deployment + /// @param tokenAddress The address of the deployed token + /// @param minimumMetadataCalls The minimum number of metadata calls expected to be made + /// @param executedMetadataCalls The number of metadata calls that have been executed + struct MigrationConfig { + address tokenAddress; + uint256 minimumMetadataCalls; + uint256 executedMetadataCalls; + } + /// /// /// EVENTS /// /// /// @@ -44,6 +58,9 @@ contract L2MigrationDeployer { /// @dev Metadata call failed error METADATA_CALL_FAILED(); + /// @dev Metadata calls not executed + error METADATA_CALLS_NOT_EXECUTED(); + /// /// /// IMMUTABLES /// /// /// @@ -61,8 +78,8 @@ contract L2MigrationDeployer { /// STORAGE /// /// /// - /// @notice Mapping of L1 deployer => L2 deployed token - mapping(address => address) public crossDomainDeployerToToken; + /// @notice Mapping of L1 deployer => L2 migration config + mapping(address => MigrationConfig) public crossDomainDeployerToMigration; /// /// /// CONSTRUCTOR /// @@ -94,7 +111,8 @@ contract L2MigrationDeployer { IManager.TokenParams calldata _tokenParams, IManager.AuctionParams calldata _auctionParams, IManager.GovParams calldata _govParams, - MerkleReserveMinter.MerkleMinterSettings calldata _minterParams + MerkleReserveMinter.MerkleMinterSettings calldata _minterParams, + uint256 _minimumMetadataCalls ) external returns (address token) { if (_getTokenFromSender() != address(0)) { revert DAO_ALREADY_DEPLOYED(); @@ -113,8 +131,8 @@ contract L2MigrationDeployer { // Initilize minter with given params MerkleReserveMinter(merkleMinter).setMintSettings(_token, _minterParams); - // Set the deployer - address deployer = _setTokenDeployer(_token); + // Set the migration config + address deployer = _setMigrationConfig(_token, _minimumMetadataCalls); // Emit deployer set event emit DeployerSet(_token, deployer); @@ -124,7 +142,7 @@ contract L2MigrationDeployer { ///@notice Resets the stored deployment if L1 DAO wants to redeploy function resetDeployment() external { - _resetTokenDeployer(); + _resetMigrationConfig(); } /// /// @@ -142,6 +160,9 @@ contract L2MigrationDeployer { function callMetadataRenderer(bytes memory _data) external { (, address metadata, , , ) = _getDAOAddressesFromSender(); + // Increment the number of metadata calls + crossDomainDeployerToMigration[_xMsgSender()].executedMetadataCalls++; + // Call the metadata renderer (bool success, ) = metadata.call(_data); @@ -168,6 +189,13 @@ contract L2MigrationDeployer { function renounceOwnership() external { (address token, , address auction, address treasury, ) = _getDAOAddressesFromSender(); + MigrationConfig storage migration = crossDomainDeployerToMigration[_xMsgSender()]; + + // Revert if the minimum amount of metadata calls have not been executed + if (migration.executedMetadataCalls < migration.minimumMetadataCalls) { + revert METADATA_CALLS_NOT_EXECUTED(); + } + // Transfer ownership of token contract Ownable(token).transferOwnership(treasury); @@ -190,22 +218,22 @@ contract L2MigrationDeployer { : OPAddressAliasHelper.undoL1ToL2Alias(msg.sender); } - function _setTokenDeployer(address token) private returns (address deployer) { + function _setMigrationConfig(address token, uint256 minimumMetadataCalls) private returns (address deployer) { deployer = _xMsgSender(); - // Set the deployer state so the xDomain caller can easily access in future calls - // Also prevents accidental re-deployment - crossDomainDeployerToToken[deployer] = token; + crossDomainDeployerToMigration[deployer].tokenAddress = token; + crossDomainDeployerToMigration[deployer].minimumMetadataCalls = minimumMetadataCalls; + crossDomainDeployerToMigration[deployer].executedMetadataCalls = 0; } - function _resetTokenDeployer() private { + function _resetMigrationConfig() private { // Reset the deployer state so the xDomain caller can redeploy - delete crossDomainDeployerToToken[_xMsgSender()]; + delete crossDomainDeployerToMigration[_xMsgSender()]; } function _getTokenFromSender() private view returns (address) { // Return the token address if it has been deployed by the xDomain caller - return crossDomainDeployerToToken[_xMsgSender()]; + return crossDomainDeployerToMigration[_xMsgSender()].tokenAddress; } function _getDAOAddressesFromSender() diff --git a/test/L2MigrationDeployer.t.sol b/test/L2MigrationDeployer.t.sol index bb1925e..6a70e89 100644 --- a/test/L2MigrationDeployer.t.sol +++ b/test/L2MigrationDeployer.t.sol @@ -38,7 +38,7 @@ contract L2MigrationDeployerTest is NounsBuilderTest { vm.startPrank(address(xDomainMessenger)); - address _token = deployer.deploy(foundersArr, tokenParams, auctionParams, govParams, minterParams); + address _token = deployer.deploy(foundersArr, tokenParams, auctionParams, govParams, minterParams, 1); addMetadataProperties(); @@ -61,6 +61,36 @@ contract L2MigrationDeployerTest is NounsBuilderTest { vm.label(address(governor), "GOVERNOR"); } + function deployAlt() internal { + setAltMockFounderParams(); + + setMockTokenParams(); + + setMockAuctionParams(); + + setMockGovParams(); + + vm.startPrank(address(xDomainMessenger)); + + address _token = deployer.deploy(foundersArr, tokenParams, auctionParams, govParams, minterParams, 1); + + vm.stopPrank(); + + (address _metadata, address _auction, address _treasury, address _governor) = manager.getAddresses(_token); + + token = Token(_token); + metadataRenderer = MetadataRenderer(_metadata); + auction = Auction(_auction); + treasury = Treasury(payable(_treasury)); + governor = Governor(_governor); + + vm.label(address(token), "TOKEN"); + vm.label(address(metadataRenderer), "METADATA_RENDERER"); + vm.label(address(auction), "AUCTION"); + vm.label(address(treasury), "TREASURY"); + vm.label(address(governor), "GOVERNOR"); + } + function setAltMockFounderParams() internal virtual { address[] memory wallets = new address[](3); uint256[] memory percents = new uint256[](3); @@ -107,6 +137,14 @@ contract L2MigrationDeployerTest is NounsBuilderTest { deploy(); } + function testRevert_DeployNoMetadata() external { + deployAlt(); + + vm.prank(address(xDomainMessenger)); + vm.expectRevert(abi.encodeWithSignature("METADATA_CALLS_NOT_EXECUTED()")); + deployer.renounceOwnership(); + } + function test_MinterIsSet() external { deploy(); @@ -148,12 +186,16 @@ contract L2MigrationDeployerTest is NounsBuilderTest { function test_ResetDeployment() external { deploy(); - assertEq(deployer.crossDomainDeployerToToken(xDomainMessenger.xDomainMessageSender()), address(token)); + (address token, , ) = deployer.crossDomainDeployerToMigration(xDomainMessenger.xDomainMessageSender()); + + assertEq(token, address(token)); vm.prank(address(xDomainMessenger)); deployer.resetDeployment(); - assertEq(deployer.crossDomainDeployerToToken(xDomainMessenger.xDomainMessageSender()), address(0)); + (address newToken, , ) = deployer.crossDomainDeployerToMigration(xDomainMessenger.xDomainMessageSender()); + + assertEq(newToken, address(0)); } function test_DepositToTreasury() external { @@ -184,6 +226,6 @@ contract L2MigrationDeployerTest is NounsBuilderTest { vm.prank(address(xDomainMessenger)); vm.expectRevert(abi.encodeWithSignature("DAO_ALREADY_DEPLOYED()")); - deployer.deploy(foundersArr, tokenParams, auctionParams, govParams, minterParams); + deployer.deploy(foundersArr, tokenParams, auctionParams, govParams, minterParams, 1); } }