From 9f8ea6e952806e383db61da3f918b9e44a52af3d Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 4 Dec 2024 09:46:20 -0800 Subject: [PATCH 01/49] feat: inherit from AccessControl and update accordingly --- l2-contracts/src/ZkCappedMinterV2.sol | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/l2-contracts/src/ZkCappedMinterV2.sol b/l2-contracts/src/ZkCappedMinterV2.sol index 7d01758..ee4e198 100644 --- a/l2-contracts/src/ZkCappedMinterV2.sol +++ b/l2-contracts/src/ZkCappedMinterV2.sol @@ -1,19 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.24; +import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; import {IMintableAndDelegatable} from "src/interfaces/IMintableAndDelegatable.sol"; /// @title ZkCappedMinterV2 /// @author [ScopeLift](https://scopelift.co) /// @notice A contract to allow a permissioned entity to mint ZK tokens up to a given amount (the cap). /// @custom:security-contact security@zksync.io -contract ZkCappedMinterV2 { +contract ZkCappedMinterV2 is AccessControl { /// @notice The contract where the tokens will be minted by an authorized minter. IMintableAndDelegatable public immutable TOKEN; - /// @notice The address that is allowed to mint tokens. - address public immutable ADMIN; - /// @notice The maximum number of tokens that may be minted by the ZkCappedMinter. uint256 public immutable CAP; @@ -23,17 +21,18 @@ contract ZkCappedMinterV2 { /// @notice Error for when the cap is exceeded. error ZkCappedMinterV2__CapExceeded(address minter, uint256 amount); - /// @notice Error for when the caller is not the admin. + /// @notice Error for when the account is unauthorized. error ZkCappedMinterV2__Unauthorized(address account); /// @notice Constructor for a new ZkCappedMinter contract /// @param _token The token contract where tokens will be minted. - /// @param _admin The address that is allowed to mint tokens. + /// @param _admin The address that will be granted the admin role. /// @param _cap The maximum number of tokens that may be minted by the ZkCappedMinter. constructor(IMintableAndDelegatable _token, address _admin, uint256 _cap) { TOKEN = _token; - ADMIN = _admin; CAP = _cap; + + _grantRole(DEFAULT_ADMIN_ROLE, _admin); } /// @notice Mints a given amount of tokens to a given address, so long as the cap is not exceeded. @@ -46,9 +45,9 @@ contract ZkCappedMinterV2 { TOKEN.mint(_to, _amount); } - /// @notice Reverts if msg.sender is not the contract admin. + /// @notice Reverts if the account is unauthorized. function _revertIfUnauthorized() internal view { - if (msg.sender != ADMIN) { + if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) { revert ZkCappedMinterV2__Unauthorized(msg.sender); } } From 2aecdcec8d559f6b407ffffb9b3f89df42fcae9d Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 4 Dec 2024 09:46:20 -0800 Subject: [PATCH 02/49] feat: update tests to handle new auth functionality --- l2-contracts/test/ZkCappedMinterV2.t.sol | 53 ++++++++++++++----- .../test/ZkCappedMinterV2Factory.t.sol | 2 +- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 91aa90e..1e86c48 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -26,7 +26,7 @@ contract Constructor is ZkCappedMinterV2Test { _cap = bound(_cap, 0, MAX_MINT_SUPPLY); ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); assertEq(address(cappedMinter.TOKEN()), address(token)); - assertEq(cappedMinter.ADMIN(), _cappedMinterAdmin); + assertEq(cappedMinter.hasRole(DEFAULT_ADMIN_ROLE, _cappedMinterAdmin), true); assertEq(cappedMinter.CAP(), _cap); } } @@ -34,6 +34,7 @@ contract Constructor is ZkCappedMinterV2Test { contract Mint is ZkCappedMinterV2Test { function testFuzz_MintsNewTokensWhenTheAmountRequestedIsBelowTheCap( address _cappedMinterAdmin, + address _minter, address _receiver, uint256 _cap, uint256 _amount @@ -42,14 +43,21 @@ contract Mint is ZkCappedMinterV2Test { _amount = bound(_amount, 1, MAX_MINT_SUPPLY); vm.assume(_cap > _amount); vm.assume(_receiver != address(0) && _receiver != initMintReceiver); + vm.assume(_minter != address(0)); + ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); + vm.prank(_cappedMinterAdmin); + cappedMinter.grantRole(MINTER_ROLE, _minter); + + vm.prank(_minter); cappedMinter.mint(_receiver, _amount); assertEq(token.balanceOf(_receiver), _amount); } function testFuzz_MintsNewTokensInSuccessionToDifferentAccountsWhileRemainingBelowCap( address _cappedMinterAdmin, + address _minter, address _receiver1, address _receiver2, uint256 _cap, @@ -63,38 +71,57 @@ contract Mint is ZkCappedMinterV2Test { vm.assume(_receiver1 != address(0) && _receiver1 != initMintReceiver); vm.assume(_receiver2 != address(0) && _receiver2 != initMintReceiver); vm.assume(_receiver1 != _receiver2); + vm.assume(_minter != address(0)); + ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); - vm.startPrank(_cappedMinterAdmin); + + vm.prank(_cappedMinterAdmin); + cappedMinter.grantRole(MINTER_ROLE, _minter); + + vm.startPrank(_minter); cappedMinter.mint(_receiver1, _amount1); cappedMinter.mint(_receiver2, _amount2); vm.stopPrank(); + assertEq(token.balanceOf(_receiver1), _amount1); assertEq(token.balanceOf(_receiver2), _amount2); } - function testFuzz_RevertIf_MintAttemptedByNonAdmin(address _cappedMinterAdmin, uint256 _cap, address _nonAdmin) + function testFuzz_RevertIf_MintAttemptedByNonMinter(address _cappedMinterAdmin, address _nonMinter, uint256 _cap) public { _cap = bound(_cap, 0, MAX_MINT_SUPPLY); - vm.assume(_nonAdmin != _cappedMinterAdmin); - ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); - vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__Unauthorized.selector, _nonAdmin)); - vm.startPrank(_nonAdmin); - cappedMinter.mint(_nonAdmin, _cap); + + vm.assume(_nonMinter != address(0)); + vm.assume(!cappedMinter.hasRole(MINTER_ROLE, _nonMinter)); + + vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__Unauthorized.selector, _nonMinter)); + vm.prank(_nonMinter); + cappedMinter.mint(_nonMinter, _cap); } - function testFuzz_RevertIf_CapExceededOnMint(address _cappedMinterAdmin, address _receiver, uint256 _cap) public { + function testFuzz_RevertIf_CapExceededOnMint( + address _cappedMinterAdmin, + address _minter, + address _receiver, + uint256 _cap + ) public { _cap = bound(_cap, 4, MAX_MINT_SUPPLY); vm.assume(_receiver != address(0) && _receiver != initMintReceiver); + vm.assume(_minter != address(0)); + ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); + vm.prank(_cappedMinterAdmin); + cappedMinter.grantRole(MINTER_ROLE, _minter); + + vm.prank(_minter); cappedMinter.mint(_receiver, _cap); assertEq(token.balanceOf(_receiver), _cap); - vm.expectRevert( - abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__CapExceeded.selector, _cappedMinterAdmin, _cap) - ); - vm.prank(_cappedMinterAdmin); + + vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__CapExceeded.selector, _minter, _cap)); + vm.prank(_minter); cappedMinter.mint(_receiver, _cap); } } diff --git a/l2-contracts/test/ZkCappedMinterV2Factory.t.sol b/l2-contracts/test/ZkCappedMinterV2Factory.t.sol index d111e82..5a87ff9 100644 --- a/l2-contracts/test/ZkCappedMinterV2Factory.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2Factory.t.sol @@ -44,7 +44,7 @@ contract CreateCappedMinter is ZkCappedMinterV2FactoryTest { ZkCappedMinterV2 minter = ZkCappedMinterV2(minterAddress); assertEq(address(minter.TOKEN()), address(token)); - assertEq(minter.ADMIN(), _cappedMinterAdmin); + assertEq(minter.hasRole(DEFAULT_ADMIN_ROLE, _cappedMinterAdmin), true); assertEq(minter.CAP(), _cap); } From e293e2dba2e3ccaf944979d3ba8f7d9890d6c7a4 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 4 Dec 2024 09:46:20 -0800 Subject: [PATCH 03/49] feat: add minter role --- l2-contracts/src/ZkCappedMinterV2.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/l2-contracts/src/ZkCappedMinterV2.sol b/l2-contracts/src/ZkCappedMinterV2.sol index ee4e198..a6d7386 100644 --- a/l2-contracts/src/ZkCappedMinterV2.sol +++ b/l2-contracts/src/ZkCappedMinterV2.sol @@ -24,6 +24,8 @@ contract ZkCappedMinterV2 is AccessControl { /// @notice Error for when the account is unauthorized. error ZkCappedMinterV2__Unauthorized(address account); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + /// @notice Constructor for a new ZkCappedMinter contract /// @param _token The token contract where tokens will be minted. /// @param _admin The address that will be granted the admin role. @@ -47,7 +49,7 @@ contract ZkCappedMinterV2 is AccessControl { /// @notice Reverts if the account is unauthorized. function _revertIfUnauthorized() internal view { - if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) { + if (!hasRole(MINTER_ROLE, msg.sender)) { revert ZkCappedMinterV2__Unauthorized(msg.sender); } } From b7f42229ddf3f7a3b5df13c0fcaf612f4ae52a9e Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 4 Dec 2024 09:46:20 -0800 Subject: [PATCH 04/49] feat: test admin can't mint by default --- l2-contracts/test/ZkCappedMinterV2.t.sol | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 1e86c48..76ede2a 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -124,4 +124,17 @@ contract Mint is ZkCappedMinterV2Test { vm.prank(_minter); cappedMinter.mint(_receiver, _cap); } + + function testFuzz_AdminCannotMintByDefault(address _admin, address _receiver, uint256 _cap, uint256 _amount) public { + _cap = bound(_cap, 0, MAX_MINT_SUPPLY); + _amount = bound(_amount, 1, _cap); + vm.assume(_admin != address(0)); + vm.assume(_receiver != address(0) && _receiver != initMintReceiver); + + ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); + + vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__Unauthorized.selector, _admin)); + vm.prank(_admin); + cappedMinter.mint(_receiver, _amount); + } } From 726d0bf014f4a17f01f758ff0f22c92f55589c6d Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 4 Dec 2024 09:46:21 -0800 Subject: [PATCH 05/49] fix: name --- l2-contracts/test/ZkCappedMinterV2.t.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 76ede2a..f028d66 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -125,7 +125,9 @@ contract Mint is ZkCappedMinterV2Test { cappedMinter.mint(_receiver, _cap); } - function testFuzz_AdminCannotMintByDefault(address _admin, address _receiver, uint256 _cap, uint256 _amount) public { + function testFuzz_RevertIf_AdminMintsByDefault(address _admin, address _receiver, uint256 _cap, uint256 _amount) + public + { _cap = bound(_cap, 0, MAX_MINT_SUPPLY); _amount = bound(_amount, 1, _cap); vm.assume(_admin != address(0)); From 31d626f361e4173fd19b13ca80b46e6a59490c85 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 4 Dec 2024 15:01:45 -0800 Subject: [PATCH 06/49] fix: structure --- l2-contracts/src/ZkCappedMinterV2.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/l2-contracts/src/ZkCappedMinterV2.sol b/l2-contracts/src/ZkCappedMinterV2.sol index a6d7386..233de89 100644 --- a/l2-contracts/src/ZkCappedMinterV2.sol +++ b/l2-contracts/src/ZkCappedMinterV2.sol @@ -18,14 +18,14 @@ contract ZkCappedMinterV2 is AccessControl { /// @notice The cumulative number of tokens that have been minted by the ZkCappedMinter. uint256 public minted = 0; + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + /// @notice Error for when the cap is exceeded. error ZkCappedMinterV2__CapExceeded(address minter, uint256 amount); /// @notice Error for when the account is unauthorized. error ZkCappedMinterV2__Unauthorized(address account); - bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); - /// @notice Constructor for a new ZkCappedMinter contract /// @param _token The token contract where tokens will be minted. /// @param _admin The address that will be granted the admin role. From fb8864838d4f848c41b86ad03c295467debb8aec Mon Sep 17 00:00:00 2001 From: marcomariscal Date: Tue, 3 Dec 2024 14:05:04 -0800 Subject: [PATCH 07/49] feat: basic pause functionality --- l2-contracts/src/ZkCappedMinterV2.sol | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/l2-contracts/src/ZkCappedMinterV2.sol b/l2-contracts/src/ZkCappedMinterV2.sol index 233de89..8d4d1d1 100644 --- a/l2-contracts/src/ZkCappedMinterV2.sol +++ b/l2-contracts/src/ZkCappedMinterV2.sol @@ -2,13 +2,14 @@ pragma solidity 0.8.24; import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; +import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol"; import {IMintableAndDelegatable} from "src/interfaces/IMintableAndDelegatable.sol"; /// @title ZkCappedMinterV2 /// @author [ScopeLift](https://scopelift.co) /// @notice A contract to allow a permissioned entity to mint ZK tokens up to a given amount (the cap). /// @custom:security-contact security@zksync.io -contract ZkCappedMinterV2 is AccessControl { +contract ZkCappedMinterV2 is AccessControl, Pausable { /// @notice The contract where the tokens will be minted by an authorized minter. IMintableAndDelegatable public immutable TOKEN; @@ -19,6 +20,7 @@ contract ZkCappedMinterV2 is AccessControl { uint256 public minted = 0; bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); /// @notice Error for when the cap is exceeded. error ZkCappedMinterV2__CapExceeded(address minter, uint256 amount); @@ -35,12 +37,30 @@ contract ZkCappedMinterV2 is AccessControl { CAP = _cap; _grantRole(DEFAULT_ADMIN_ROLE, _admin); + _grantRole(PAUSER_ROLE, _admin); + } + + /// @notice Pauses token minting + function pause() external { + if (!hasRole(PAUSER_ROLE, msg.sender)) { + revert ZkCappedMinterV2__Unauthorized(msg.sender); + } + _pause(); + } + + /// @notice Unpauses token minting + function unpause() external { + if (!hasRole(PAUSER_ROLE, msg.sender)) { + revert ZkCappedMinterV2__Unauthorized(msg.sender); + } + _unpause(); } /// @notice Mints a given amount of tokens to a given address, so long as the cap is not exceeded. /// @param _to The address that will receive the new tokens. /// @param _amount The quantity of tokens, in raw decimals, that will be created. function mint(address _to, uint256 _amount) external { + _requireNotPaused(); _revertIfUnauthorized(); _revertIfCapExceeded(_amount); minted += _amount; From 946dc79b326467d3006055e50267826dbd9f8571 Mon Sep 17 00:00:00 2001 From: marcomariscal Date: Tue, 3 Dec 2024 14:43:11 -0800 Subject: [PATCH 08/49] feat: pause/unpause tests --- l2-contracts/test/ZkCappedMinterV2.t.sol | 94 ++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index f028d66..ba7d1f1 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -140,3 +140,97 @@ contract Mint is ZkCappedMinterV2Test { cappedMinter.mint(_receiver, _amount); } } + +contract Pause is ZkCappedMinterV2Test { + function testFuzz_CorrectlyPreventsNewMintsWhenPaused( + address _admin, + address _minter, + address _receiver, + uint256 _cap, + uint256 _amount + ) public { + _cap = bound(_cap, 0, MAX_MINT_SUPPLY); + vm.assume(_cap > 0); + _amount = bound(_amount, 1, _cap); + vm.assume(_admin != address(0)); + vm.assume(_minter != address(0) && _minter != _admin); + vm.assume(_receiver != address(0) && _receiver != initMintReceiver); + + ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); + + // Grant minter role and verify minting works + vm.prank(_admin); + cappedMinter.grantRole(MINTER_ROLE, _minter); + + vm.prank(_minter); + cappedMinter.mint(_receiver, _amount); + assertEq(token.balanceOf(_receiver), _amount); + + // Pause and verify minting fails + vm.prank(_admin); + cappedMinter.pause(); + + vm.expectRevert("Pausable: paused"); + vm.prank(_minter); + cappedMinter.mint(_receiver, _amount); + } + + function testFuzz_RevertIf_NonAdminAttemptsToPause(address _admin, address _nonAdmin, uint256 _cap) public { + _cap = bound(_cap, 0, MAX_MINT_SUPPLY); + vm.assume(_admin != address(0)); + vm.assume(_nonAdmin != address(0) && _nonAdmin != _admin); + + ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); + + vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__Unauthorized.selector, _nonAdmin)); + vm.prank(_nonAdmin); + cappedMinter.pause(); + } +} + +contract Unpause is ZkCappedMinterV2Test { + function testFuzz_CorrectlyAllowsNewMintsWhenUnpaused( + address _admin, + address _minter, + address _receiver, + uint256 _cap, + uint256 _amount + ) public { + _cap = bound(_cap, 0, MAX_MINT_SUPPLY); + vm.assume(_cap > 0); + _amount = bound(_amount, 1, _cap); + vm.assume(_admin != address(0)); + vm.assume(_minter != address(0) && _minter != _admin); + vm.assume(_receiver != address(0) && _receiver != initMintReceiver); + + ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); + + vm.prank(_admin); + cappedMinter.grantRole(MINTER_ROLE, _minter); + + vm.prank(_admin); + cappedMinter.pause(); + + vm.prank(_admin); + cappedMinter.unpause(); + + vm.prank(_minter); + cappedMinter.mint(_receiver, _amount); + assertEq(token.balanceOf(_receiver), _amount); + } + + function testFuzz_RevertIf_NonAdminAttemptsToUnpause(address _admin, address _nonAdmin, uint256 _cap) public { + _cap = bound(_cap, 1, MAX_MINT_SUPPLY); + vm.assume(_admin != address(0)); + vm.assume(_nonAdmin != address(0) && _nonAdmin != _admin); + + ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); + + vm.prank(_admin); + cappedMinter.pause(); + + vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__Unauthorized.selector, _nonAdmin)); + vm.prank(_nonAdmin); + cappedMinter.unpause(); + } +} From d9b3dba392ac5dcf3300a8aaa50b3b9103595ce6 Mon Sep 17 00:00:00 2001 From: marcomariscal Date: Tue, 3 Dec 2024 14:46:53 -0800 Subject: [PATCH 09/49] fix: assume cap is not zero --- l2-contracts/test/ZkCappedMinterV2.t.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index ba7d1f1..8724c6f 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -40,6 +40,7 @@ contract Mint is ZkCappedMinterV2Test { uint256 _amount ) public { _cap = bound(_cap, 0, MAX_MINT_SUPPLY); + vm.assume(_cap > 0); _amount = bound(_amount, 1, MAX_MINT_SUPPLY); vm.assume(_cap > _amount); vm.assume(_receiver != address(0) && _receiver != initMintReceiver); @@ -65,6 +66,7 @@ contract Mint is ZkCappedMinterV2Test { uint256 _amount2 ) public { _cap = bound(_cap, 0, MAX_MINT_SUPPLY); + vm.assume(_cap > 0); vm.assume(_amount1 < MAX_MINT_SUPPLY / 2); vm.assume(_amount2 < MAX_MINT_SUPPLY / 2); vm.assume(_amount1 + _amount2 < _cap); @@ -129,6 +131,7 @@ contract Mint is ZkCappedMinterV2Test { public { _cap = bound(_cap, 0, MAX_MINT_SUPPLY); + vm.assume(_cap > 0); _amount = bound(_amount, 1, _cap); vm.assume(_admin != address(0)); vm.assume(_receiver != address(0) && _receiver != initMintReceiver); From 1cfbef7f9b2e8e07acaa35833e14d97f688b2090 Mon Sep 17 00:00:00 2001 From: marcomariscal Date: Tue, 3 Dec 2024 14:53:32 -0800 Subject: [PATCH 10/49] fix: check for pauser role --- l2-contracts/test/ZkCappedMinterV2.t.sol | 25 +++++++++++++++--------- l2-contracts/test/utils/ZkTokenTest.sol | 1 + 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 8724c6f..b621906 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -178,15 +178,18 @@ contract Pause is ZkCappedMinterV2Test { cappedMinter.mint(_receiver, _amount); } - function testFuzz_RevertIf_NonAdminAttemptsToPause(address _admin, address _nonAdmin, uint256 _cap) public { + function testFuzz_RevertIf_NotPauserRole(address _admin, uint256 _cap) public { _cap = bound(_cap, 0, MAX_MINT_SUPPLY); vm.assume(_admin != address(0)); - vm.assume(_nonAdmin != address(0) && _nonAdmin != _admin); ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); - vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__Unauthorized.selector, _nonAdmin)); - vm.prank(_nonAdmin); + // Remove PAUSER_ROLE from admin + vm.prank(_admin); + cappedMinter.revokeRole(PAUSER_ROLE, _admin); + + vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__Unauthorized.selector, _admin)); + vm.prank(_admin); cappedMinter.pause(); } } @@ -222,18 +225,22 @@ contract Unpause is ZkCappedMinterV2Test { assertEq(token.balanceOf(_receiver), _amount); } - function testFuzz_RevertIf_NonAdminAttemptsToUnpause(address _admin, address _nonAdmin, uint256 _cap) public { - _cap = bound(_cap, 1, MAX_MINT_SUPPLY); + function testFuzz_RevertIf_NotPauserRole(address _admin, uint256 _cap) public { + _cap = bound(_cap, 0, MAX_MINT_SUPPLY); vm.assume(_admin != address(0)); - vm.assume(_nonAdmin != address(0) && _nonAdmin != _admin); ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); + // Pause first (while admin still has PAUSER_ROLE) vm.prank(_admin); cappedMinter.pause(); - vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__Unauthorized.selector, _nonAdmin)); - vm.prank(_nonAdmin); + // Remove PAUSER_ROLE from admin + vm.prank(_admin); + cappedMinter.revokeRole(PAUSER_ROLE, _admin); + + vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__Unauthorized.selector, _admin)); + vm.prank(_admin); cappedMinter.unpause(); } } diff --git a/l2-contracts/test/utils/ZkTokenTest.sol b/l2-contracts/test/utils/ZkTokenTest.sol index 54913c6..9f057c4 100644 --- a/l2-contracts/test/utils/ZkTokenTest.sol +++ b/l2-contracts/test/utils/ZkTokenTest.sol @@ -15,6 +15,7 @@ contract ZkTokenTest is Test { // Placed here for convenience in tests. Must match the constants in the implementation. bytes32 public DEFAULT_ADMIN_ROLE = 0x00; bytes32 public MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public PAUSER_ROLE = keccak256("PAUSER_ROLE"); bytes32 public BURNER_ROLE = keccak256("BURNER_ROLE"); bytes32 public MINTER_ADMIN_ROLE = keccak256("MINTER_ADMIN_ROLE"); bytes32 public BURNER_ADMIN_ROLE = keccak256("BURNER_ADMIN_ROLE"); From 33798528d7704594e05d710c2028d9e864a385bf Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 4 Dec 2024 08:50:57 -0800 Subject: [PATCH 11/49] fix: separate role errors --- l2-contracts/src/ZkCappedMinterV2.sol | 21 +++++++++------- l2-contracts/test/ZkCappedMinterV2.t.sol | 31 ++++++++++++------------ 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/l2-contracts/src/ZkCappedMinterV2.sol b/l2-contracts/src/ZkCappedMinterV2.sol index 8d4d1d1..3eab0b3 100644 --- a/l2-contracts/src/ZkCappedMinterV2.sol +++ b/l2-contracts/src/ZkCappedMinterV2.sol @@ -25,8 +25,11 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { /// @notice Error for when the cap is exceeded. error ZkCappedMinterV2__CapExceeded(address minter, uint256 amount); - /// @notice Error for when the account is unauthorized. - error ZkCappedMinterV2__Unauthorized(address account); + /// @notice Error for when the account does not have minter role. + error ZkCappedMinterV2__NotMinter(address account); + + /// @notice Error for when the account does not have pauser role. + error ZkCappedMinterV2__NotPauser(address account); /// @notice Constructor for a new ZkCappedMinter contract /// @param _token The token contract where tokens will be minted. @@ -43,7 +46,7 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { /// @notice Pauses token minting function pause() external { if (!hasRole(PAUSER_ROLE, msg.sender)) { - revert ZkCappedMinterV2__Unauthorized(msg.sender); + revert ZkCappedMinterV2__NotPauser(msg.sender); } _pause(); } @@ -51,7 +54,7 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { /// @notice Unpauses token minting function unpause() external { if (!hasRole(PAUSER_ROLE, msg.sender)) { - revert ZkCappedMinterV2__Unauthorized(msg.sender); + revert ZkCappedMinterV2__NotPauser(msg.sender); } _unpause(); } @@ -61,16 +64,16 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { /// @param _amount The quantity of tokens, in raw decimals, that will be created. function mint(address _to, uint256 _amount) external { _requireNotPaused(); - _revertIfUnauthorized(); + _revertIfNotMinter(msg.sender); _revertIfCapExceeded(_amount); minted += _amount; TOKEN.mint(_to, _amount); } - /// @notice Reverts if the account is unauthorized. - function _revertIfUnauthorized() internal view { - if (!hasRole(MINTER_ROLE, msg.sender)) { - revert ZkCappedMinterV2__Unauthorized(msg.sender); + /// @notice Reverts if the account does not have minter role. + function _revertIfNotMinter(address account) internal view { + if (!hasRole(MINTER_ROLE, account)) { + revert ZkCappedMinterV2__NotMinter(account); } } diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index b621906..6454b85 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -89,16 +89,14 @@ contract Mint is ZkCappedMinterV2Test { assertEq(token.balanceOf(_receiver2), _amount2); } - function testFuzz_RevertIf_MintAttemptedByNonMinter(address _cappedMinterAdmin, address _nonMinter, uint256 _cap) - public - { + function testFuzz_RevertIf_MintAttemptedByNonMinter(address _admin, address _nonMinter, uint256 _cap) public { _cap = bound(_cap, 0, MAX_MINT_SUPPLY); - ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); + vm.assume(_admin != address(0)); + vm.assume(_nonMinter != address(0) && _nonMinter != _admin); - vm.assume(_nonMinter != address(0)); - vm.assume(!cappedMinter.hasRole(MINTER_ROLE, _nonMinter)); + ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); - vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__Unauthorized.selector, _nonMinter)); + vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__NotMinter.selector, _nonMinter)); vm.prank(_nonMinter); cappedMinter.mint(_nonMinter, _cap); } @@ -127,9 +125,12 @@ contract Mint is ZkCappedMinterV2Test { cappedMinter.mint(_receiver, _cap); } - function testFuzz_RevertIf_AdminMintsByDefault(address _admin, address _receiver, uint256 _cap, uint256 _amount) - public - { + function testFuzz_RevertIf_AdminAttemptsToMintByDefault( + address _admin, + address _receiver, + uint256 _cap, + uint256 _amount + ) public { _cap = bound(_cap, 0, MAX_MINT_SUPPLY); vm.assume(_cap > 0); _amount = bound(_amount, 1, _cap); @@ -138,7 +139,7 @@ contract Mint is ZkCappedMinterV2Test { ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); - vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__Unauthorized.selector, _admin)); + vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__NotMinter.selector, _admin)); vm.prank(_admin); cappedMinter.mint(_receiver, _amount); } @@ -178,7 +179,7 @@ contract Pause is ZkCappedMinterV2Test { cappedMinter.mint(_receiver, _amount); } - function testFuzz_RevertIf_NotPauserRole(address _admin, uint256 _cap) public { + function testFuzz_RevertIf_NotPauserRolePauses(address _admin, uint256 _cap) public { _cap = bound(_cap, 0, MAX_MINT_SUPPLY); vm.assume(_admin != address(0)); @@ -188,7 +189,7 @@ contract Pause is ZkCappedMinterV2Test { vm.prank(_admin); cappedMinter.revokeRole(PAUSER_ROLE, _admin); - vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__Unauthorized.selector, _admin)); + vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__NotPauser.selector, _admin)); vm.prank(_admin); cappedMinter.pause(); } @@ -225,7 +226,7 @@ contract Unpause is ZkCappedMinterV2Test { assertEq(token.balanceOf(_receiver), _amount); } - function testFuzz_RevertIf_NotPauserRole(address _admin, uint256 _cap) public { + function testFuzz_RevertIf_NotPauserRoleUnpauses(address _admin, uint256 _cap) public { _cap = bound(_cap, 0, MAX_MINT_SUPPLY); vm.assume(_admin != address(0)); @@ -239,7 +240,7 @@ contract Unpause is ZkCappedMinterV2Test { vm.prank(_admin); cappedMinter.revokeRole(PAUSER_ROLE, _admin); - vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__Unauthorized.selector, _admin)); + vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__NotPauser.selector, _admin)); vm.prank(_admin); cappedMinter.unpause(); } From 004c789177deb977ded2aa436cbfd3249fba4b76 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 4 Dec 2024 10:01:56 -0800 Subject: [PATCH 12/49] feat: _revertIfNotPauser --- l2-contracts/src/ZkCappedMinterV2.sol | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/l2-contracts/src/ZkCappedMinterV2.sol b/l2-contracts/src/ZkCappedMinterV2.sol index 3eab0b3..75ad256 100644 --- a/l2-contracts/src/ZkCappedMinterV2.sol +++ b/l2-contracts/src/ZkCappedMinterV2.sol @@ -45,17 +45,13 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { /// @notice Pauses token minting function pause() external { - if (!hasRole(PAUSER_ROLE, msg.sender)) { - revert ZkCappedMinterV2__NotPauser(msg.sender); - } + _revertIfNotPauser(msg.sender); _pause(); } /// @notice Unpauses token minting function unpause() external { - if (!hasRole(PAUSER_ROLE, msg.sender)) { - revert ZkCappedMinterV2__NotPauser(msg.sender); - } + _revertIfNotPauser(msg.sender); _unpause(); } @@ -77,6 +73,13 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { } } + /// @notice Reverts if the account does not have pauser role. + function _revertIfNotPauser(address account) internal view { + if (!hasRole(PAUSER_ROLE, account)) { + revert ZkCappedMinterV2__NotPauser(account); + } + } + /// @notice Reverts if the amount of new tokens will increase the minted tokens beyond the mint cap. /// @param _amount The quantity of tokens, in raw decimals, that will checked against the cap. function _revertIfCapExceeded(uint256 _amount) internal view { From 4f29f5c334a4066811f41fcaca37f112fc1c42de Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 4 Dec 2024 09:59:56 -0800 Subject: [PATCH 13/49] feat: close with tests --- l2-contracts/src/ZkCappedMinterV2.sol | 21 ++++++++++++ l2-contracts/test/ZkCappedMinterV2.t.sol | 41 ++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/l2-contracts/src/ZkCappedMinterV2.sol b/l2-contracts/src/ZkCappedMinterV2.sol index 75ad256..0bb7e6c 100644 --- a/l2-contracts/src/ZkCappedMinterV2.sol +++ b/l2-contracts/src/ZkCappedMinterV2.sol @@ -22,6 +22,9 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + /// @notice Whether the contract has been permanently closed. + bool public closed; + /// @notice Error for when the cap is exceeded. error ZkCappedMinterV2__CapExceeded(address minter, uint256 amount); @@ -31,6 +34,9 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { /// @notice Error for when the account does not have pauser role. error ZkCappedMinterV2__NotPauser(address account); + /// @notice Error for when the contract is closed. + error ZkCappedMinterV2__ContractClosed(); + /// @notice Constructor for a new ZkCappedMinter contract /// @param _token The token contract where tokens will be minted. /// @param _admin The address that will be granted the admin role. @@ -52,6 +58,9 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { /// @notice Unpauses token minting function unpause() external { _revertIfNotPauser(msg.sender); + if (closed) { + revert ZkCappedMinterV2__ContractClosed(); + } _unpause(); } @@ -59,6 +68,9 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { /// @param _to The address that will receive the new tokens. /// @param _amount The quantity of tokens, in raw decimals, that will be created. function mint(address _to, uint256 _amount) external { + if (closed) { + revert ZkCappedMinterV2__ContractClosed(); + } _requireNotPaused(); _revertIfNotMinter(msg.sender); _revertIfCapExceeded(_amount); @@ -87,4 +99,13 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { revert ZkCappedMinterV2__CapExceeded(msg.sender, _amount); } } + + /// @notice Permanently closes the contract, preventing any future minting. + function close() external { + if (!hasRole(PAUSER_ROLE, msg.sender)) { + revert ZkCappedMinterV2__NotPauser(msg.sender); + } + closed = true; + _pause(); + } } diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 6454b85..df1285e 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -245,3 +245,44 @@ contract Unpause is ZkCappedMinterV2Test { cappedMinter.unpause(); } } + +contract Close is ZkCappedMinterV2Test { + function testFuzz_CorrectlyPermanentlyBlocksMinting( + address _cappedMinterAdmin, + address _minter, + address _receiver, + uint256 _cap, + uint256 _amount + ) public { + _cap = bound(_cap, 0, MAX_MINT_SUPPLY); + vm.assume(_cap > 0); + _amount = bound(_amount, 1, _cap); + vm.assume(_receiver != address(0) && _receiver != initMintReceiver); + + ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); + vm.prank(_cappedMinterAdmin); + cappedMinter.grantRole(MINTER_ROLE, _minter); + + vm.prank(_cappedMinterAdmin); + cappedMinter.close(); + + vm.expectRevert(ZkCappedMinterV2.ZkCappedMinterV2__ContractClosed.selector); + vm.prank(_minter); + cappedMinter.mint(_receiver, _amount); + + // Try to unpause (should fail) + vm.expectRevert(ZkCappedMinterV2.ZkCappedMinterV2__ContractClosed.selector); + vm.prank(_cappedMinterAdmin); + cappedMinter.unpause(); + } + + function testFuzz_RevertIf_NotPauserRoleCloses(address _cappedMinterAdmin, address _nonPauser, uint256 _cap) public { + vm.assume(_nonPauser != _cappedMinterAdmin); + _cap = bound(_cap, 0, MAX_MINT_SUPPLY); + + ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); + vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__NotPauser.selector, _nonPauser)); + vm.prank(_nonPauser); + cappedMinter.close(); + } +} From edf05f63c57eed48f2da3f8bf0c3ddbe5b916949 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 4 Dec 2024 10:05:06 -0800 Subject: [PATCH 14/49] fix: use _revertIfNotPauser --- l2-contracts/src/ZkCappedMinterV2.sol | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/l2-contracts/src/ZkCappedMinterV2.sol b/l2-contracts/src/ZkCappedMinterV2.sol index 0bb7e6c..9276a10 100644 --- a/l2-contracts/src/ZkCappedMinterV2.sol +++ b/l2-contracts/src/ZkCappedMinterV2.sol @@ -102,9 +102,7 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { /// @notice Permanently closes the contract, preventing any future minting. function close() external { - if (!hasRole(PAUSER_ROLE, msg.sender)) { - revert ZkCappedMinterV2__NotPauser(msg.sender); - } + _revertIfNotPauser(msg.sender); closed = true; _pause(); } From bceb0f77397805e244f91ee32680583191f37ba6 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 4 Dec 2024 10:08:26 -0800 Subject: [PATCH 15/49] chore: better comment for `close` --- l2-contracts/src/ZkCappedMinterV2.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/l2-contracts/src/ZkCappedMinterV2.sol b/l2-contracts/src/ZkCappedMinterV2.sol index 9276a10..3a092bb 100644 --- a/l2-contracts/src/ZkCappedMinterV2.sol +++ b/l2-contracts/src/ZkCappedMinterV2.sol @@ -101,6 +101,8 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { } /// @notice Permanently closes the contract, preventing any future minting. + /// @dev Once closed, the contract cannot be reopened and all minting operations will be permanently blocked. + /// @dev Only callable by accounts with the PAUSER_ROLE. function close() external { _revertIfNotPauser(msg.sender); closed = true; From e680c31224dad3f6bf1f6e27a0ca5c7089615b08 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Mon, 9 Dec 2024 16:25:25 -0800 Subject: [PATCH 16/49] chore: comment --- l2-contracts/src/ZkCappedMinterV2.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l2-contracts/src/ZkCappedMinterV2.sol b/l2-contracts/src/ZkCappedMinterV2.sol index 233de89..2252b22 100644 --- a/l2-contracts/src/ZkCappedMinterV2.sol +++ b/l2-contracts/src/ZkCappedMinterV2.sol @@ -26,7 +26,7 @@ contract ZkCappedMinterV2 is AccessControl { /// @notice Error for when the account is unauthorized. error ZkCappedMinterV2__Unauthorized(address account); - /// @notice Constructor for a new ZkCappedMinter contract + /// @notice Constructor for a new ZkCappedMinterV2 contract /// @param _token The token contract where tokens will be minted. /// @param _admin The address that will be granted the admin role. /// @param _cap The maximum number of tokens that may be minted by the ZkCappedMinter. From 6ee3fb120966b14f9b33f8224a926a88fc2dae21 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Mon, 9 Dec 2024 16:34:18 -0800 Subject: [PATCH 17/49] feat: _grantMinterRole helper --- l2-contracts/test/ZkCappedMinterV2.t.sol | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index f028d66..f618e3b 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -17,6 +17,11 @@ contract ZkCappedMinterV2Test is ZkTokenTest { token.grantRole(MINTER_ROLE, address(cappedMinter)); return cappedMinter; } + + function _grantMinterRole(ZkCappedMinterV2 _cappedMinter, address _cappedMinterAdmin, address _minter) internal { + vm.prank(_cappedMinterAdmin); + _cappedMinter.grantRole(MINTER_ROLE, _minter); + } } contract Constructor is ZkCappedMinterV2Test { @@ -47,8 +52,7 @@ contract Mint is ZkCappedMinterV2Test { ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); - vm.prank(_cappedMinterAdmin); - cappedMinter.grantRole(MINTER_ROLE, _minter); + _grantMinterRole(cappedMinter, _cappedMinterAdmin, _minter); vm.prank(_minter); cappedMinter.mint(_receiver, _amount); @@ -75,8 +79,7 @@ contract Mint is ZkCappedMinterV2Test { ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); - vm.prank(_cappedMinterAdmin); - cappedMinter.grantRole(MINTER_ROLE, _minter); + _grantMinterRole(cappedMinter, _cappedMinterAdmin, _minter); vm.startPrank(_minter); cappedMinter.mint(_receiver1, _amount1); @@ -113,8 +116,7 @@ contract Mint is ZkCappedMinterV2Test { ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); - vm.prank(_cappedMinterAdmin); - cappedMinter.grantRole(MINTER_ROLE, _minter); + _grantMinterRole(cappedMinter, _cappedMinterAdmin, _minter); vm.prank(_minter); cappedMinter.mint(_receiver, _cap); From 72ef93c12a0535d82f7ad289ae4abb14024ff755 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Mon, 9 Dec 2024 16:48:59 -0800 Subject: [PATCH 18/49] fix: use _checkRole and remove unused unauth error --- l2-contracts/src/ZkCappedMinterV2.sol | 12 +----------- l2-contracts/test/ZkCappedMinterV2.t.sol | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/l2-contracts/src/ZkCappedMinterV2.sol b/l2-contracts/src/ZkCappedMinterV2.sol index 2252b22..ce082c5 100644 --- a/l2-contracts/src/ZkCappedMinterV2.sol +++ b/l2-contracts/src/ZkCappedMinterV2.sol @@ -23,9 +23,6 @@ contract ZkCappedMinterV2 is AccessControl { /// @notice Error for when the cap is exceeded. error ZkCappedMinterV2__CapExceeded(address minter, uint256 amount); - /// @notice Error for when the account is unauthorized. - error ZkCappedMinterV2__Unauthorized(address account); - /// @notice Constructor for a new ZkCappedMinterV2 contract /// @param _token The token contract where tokens will be minted. /// @param _admin The address that will be granted the admin role. @@ -41,19 +38,12 @@ contract ZkCappedMinterV2 is AccessControl { /// @param _to The address that will receive the new tokens. /// @param _amount The quantity of tokens, in raw decimals, that will be created. function mint(address _to, uint256 _amount) external { - _revertIfUnauthorized(); + _checkRole(MINTER_ROLE, msg.sender); _revertIfCapExceeded(_amount); minted += _amount; TOKEN.mint(_to, _amount); } - /// @notice Reverts if the account is unauthorized. - function _revertIfUnauthorized() internal view { - if (!hasRole(MINTER_ROLE, msg.sender)) { - revert ZkCappedMinterV2__Unauthorized(msg.sender); - } - } - /// @notice Reverts if the amount of new tokens will increase the minted tokens beyond the mint cap. /// @param _amount The quantity of tokens, in raw decimals, that will checked against the cap. function _revertIfCapExceeded(uint256 _amount) internal view { diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index f618e3b..30d2c96 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -5,6 +5,7 @@ import {ZkTokenTest} from "test/utils/ZkTokenTest.sol"; import {IMintableAndDelegatable} from "src/interfaces/IMintableAndDelegatable.sol"; import {ZkCappedMinterV2} from "src/ZkCappedMinterV2.sol"; import {console2} from "forge-std/Test.sol"; +import {Strings} from "lib/openzeppelin-contracts/contracts/utils/Strings.sol"; contract ZkCappedMinterV2Test is ZkTokenTest { function setUp() public virtual override { @@ -99,7 +100,16 @@ contract Mint is ZkCappedMinterV2Test { vm.assume(_nonMinter != address(0)); vm.assume(!cappedMinter.hasRole(MINTER_ROLE, _nonMinter)); - vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__Unauthorized.selector, _nonMinter)); + vm.expectRevert( + bytes( + string.concat( + "AccessControl: account ", + Strings.toHexString(uint160(_nonMinter), 20), + " is missing role ", + Strings.toHexString(uint256(MINTER_ROLE)) + ) + ) + ); vm.prank(_nonMinter); cappedMinter.mint(_nonMinter, _cap); } @@ -137,7 +147,16 @@ contract Mint is ZkCappedMinterV2Test { ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); - vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__Unauthorized.selector, _admin)); + vm.expectRevert( + bytes( + string.concat( + "AccessControl: account ", + Strings.toHexString(uint160(_admin), 20), + " is missing role ", + Strings.toHexString(uint256(MINTER_ROLE)) + ) + ) + ); vm.prank(_admin); cappedMinter.mint(_receiver, _amount); } From dd15cace8bf1d08603279e51e3d3b9fb9abc43ef Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Mon, 9 Dec 2024 16:58:35 -0800 Subject: [PATCH 19/49] fix: assume cap --- l2-contracts/test/ZkCappedMinterV2.t.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 30d2c96..5154dfc 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -141,6 +141,7 @@ contract Mint is ZkCappedMinterV2Test { public { _cap = bound(_cap, 0, MAX_MINT_SUPPLY); + vm.assume(_cap > 0); _amount = bound(_amount, 1, _cap); vm.assume(_admin != address(0)); vm.assume(_receiver != address(0) && _receiver != initMintReceiver); From 61e72470c0ea526e8092cec812d2527513c16d6f Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Mon, 9 Dec 2024 16:59:06 -0800 Subject: [PATCH 20/49] fix: toml --- l2-contracts/foundry.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/l2-contracts/foundry.toml b/l2-contracts/foundry.toml index 409177e..6b07ee5 100644 --- a/l2-contracts/foundry.toml +++ b/l2-contracts/foundry.toml @@ -8,6 +8,7 @@ "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/", "@murky/=lib/murky/", + "src/=src/" ] solc_version = "0.8.24" verbosity = 3 From 1295f88e6160cb9e7146e61059cb6bfc59122e7c Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Mon, 9 Dec 2024 17:00:41 -0800 Subject: [PATCH 21/49] chore: format --- l2-contracts/foundry.toml | 4 ++-- l2-contracts/test/ZkCappedMinterFactory.t.sol | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/l2-contracts/foundry.toml b/l2-contracts/foundry.toml index 6b07ee5..6934b43 100644 --- a/l2-contracts/foundry.toml +++ b/l2-contracts/foundry.toml @@ -1,5 +1,6 @@ [profile.default] evm_version = "paris" + fs_permissions = [{ access = "read", path = "./zkout" }] fuzz = { runs = 50 } optimizer = true optimizer_runs = 10_000_000 @@ -8,11 +9,10 @@ "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/", "@murky/=lib/murky/", - "src/=src/" + "src/=src/", ] solc_version = "0.8.24" verbosity = 3 - fs_permissions = [{ access = "read", path = "./zkout" }] [profile.ci] fuzz = { runs = 5000 } diff --git a/l2-contracts/test/ZkCappedMinterFactory.t.sol b/l2-contracts/test/ZkCappedMinterFactory.t.sol index dc1845a..f82b7c3 100644 --- a/l2-contracts/test/ZkCappedMinterFactory.t.sol +++ b/l2-contracts/test/ZkCappedMinterFactory.t.sol @@ -15,7 +15,7 @@ contract ZkCappedMinterFactoryTest is ZkTokenTest { function setUp() public virtual override { super.setUp(); - + // Read the bytecode hash from the JSON file string memory root = vm.projectRoot(); string memory path = string.concat(root, "/zkout/ZkCappedMinter.sol/ZkCappedMinter.json"); From 54315f5633dc75305a8d7d37d311fb50d8984edd Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Tue, 10 Dec 2024 10:51:15 -0800 Subject: [PATCH 22/49] fix: import --- l2-contracts/test/ZkCappedMinterV2.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 5154dfc..dee6aef 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -2,10 +2,10 @@ pragma solidity 0.8.24; import {ZkTokenTest} from "test/utils/ZkTokenTest.sol"; +import {Strings} from "@openzeppelin-contracts/contracts/utils/Strings.sol"; import {IMintableAndDelegatable} from "src/interfaces/IMintableAndDelegatable.sol"; import {ZkCappedMinterV2} from "src/ZkCappedMinterV2.sol"; import {console2} from "forge-std/Test.sol"; -import {Strings} from "lib/openzeppelin-contracts/contracts/utils/Strings.sol"; contract ZkCappedMinterV2Test is ZkTokenTest { function setUp() public virtual override { From 25582499b8646c76c3201cbf5b2faecd7f507bd1 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Tue, 10 Dec 2024 10:56:11 -0800 Subject: [PATCH 23/49] fix: compile --- l2-contracts/.github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/l2-contracts/.github/workflows/ci.yml b/l2-contracts/.github/workflows/ci.yml index ac624bf..2edb8be 100644 --- a/l2-contracts/.github/workflows/ci.yml +++ b/l2-contracts/.github/workflows/ci.yml @@ -36,6 +36,9 @@ jobs: - name: Install the dependencies run: npm install + - name: Compile + run: npm run compile + - name: Run tests run: forge test --no-match-path .integration.t.sol From 857ebc634c10ee2e3d3d5d506c28631ed51c67f7 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Tue, 10 Dec 2024 10:57:29 -0800 Subject: [PATCH 24/49] chore: name --- l2-contracts/.github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l2-contracts/.github/workflows/ci.yml b/l2-contracts/.github/workflows/ci.yml index 2edb8be..a676634 100644 --- a/l2-contracts/.github/workflows/ci.yml +++ b/l2-contracts/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: - name: Install the dependencies run: npm install - - name: Compile + - name: Buld contracts run: npm run compile - name: Run tests From 479ef77632c412e0ecf1fc737b57f0cb860db795 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:18:08 -0800 Subject: [PATCH 25/49] fix: import --- l2-contracts/test/ZkCappedMinterV2.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index dee6aef..b8cd237 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.24; import {ZkTokenTest} from "test/utils/ZkTokenTest.sol"; -import {Strings} from "@openzeppelin-contracts/contracts/utils/Strings.sol"; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {IMintableAndDelegatable} from "src/interfaces/IMintableAndDelegatable.sol"; import {ZkCappedMinterV2} from "src/ZkCappedMinterV2.sol"; import {console2} from "forge-std/Test.sol"; From 007784bc37152fb9cd058080e6059af6a0505461 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:18:24 -0800 Subject: [PATCH 26/49] fix: remove unnecessary --- l2-contracts/.github/workflows/ci.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/l2-contracts/.github/workflows/ci.yml b/l2-contracts/.github/workflows/ci.yml index a676634..ac624bf 100644 --- a/l2-contracts/.github/workflows/ci.yml +++ b/l2-contracts/.github/workflows/ci.yml @@ -36,9 +36,6 @@ jobs: - name: Install the dependencies run: npm install - - name: Buld contracts - run: npm run compile - - name: Run tests run: forge test --no-match-path .integration.t.sol From bfbac0e2045d5e1317a75dcc7023e72f6e26656a Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:18:04 -0800 Subject: [PATCH 27/49] feat: _revertIfClosed --- l2-contracts/src/ZkCappedMinterV2.sol | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/l2-contracts/src/ZkCappedMinterV2.sol b/l2-contracts/src/ZkCappedMinterV2.sol index 3a092bb..3e654a8 100644 --- a/l2-contracts/src/ZkCappedMinterV2.sol +++ b/l2-contracts/src/ZkCappedMinterV2.sol @@ -58,9 +58,7 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { /// @notice Unpauses token minting function unpause() external { _revertIfNotPauser(msg.sender); - if (closed) { - revert ZkCappedMinterV2__ContractClosed(); - } + _revertIfClosed(); _unpause(); } @@ -68,9 +66,7 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { /// @param _to The address that will receive the new tokens. /// @param _amount The quantity of tokens, in raw decimals, that will be created. function mint(address _to, uint256 _amount) external { - if (closed) { - revert ZkCappedMinterV2__ContractClosed(); - } + _revertIfClosed(); _requireNotPaused(); _revertIfNotMinter(msg.sender); _revertIfCapExceeded(_amount); @@ -100,6 +96,13 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { } } + /// @notice Reverts if the contract is closed. + function _revertIfClosed() internal view { + if (closed) { + revert ZkCappedMinterV2__ContractClosed(); + } + } + /// @notice Permanently closes the contract, preventing any future minting. /// @dev Once closed, the contract cannot be reopened and all minting operations will be permanently blocked. /// @dev Only callable by accounts with the PAUSER_ROLE. From 493c1a67377aee3cb2c3308412d1cbda310f5f34 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:33:11 -0800 Subject: [PATCH 28/49] feat: _formatAccessControlError --- l2-contracts/test/ZkCappedMinterV2.t.sol | 55 +++++++----------------- 1 file changed, 15 insertions(+), 40 deletions(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 624de59..3e633ec 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -23,6 +23,17 @@ contract ZkCappedMinterV2Test is ZkTokenTest { vm.prank(_cappedMinterAdmin); _cappedMinter.grantRole(MINTER_ROLE, _minter); } + + function _formatAccessControlError(address account, bytes32 role) internal pure returns (bytes memory) { + return bytes( + string.concat( + "AccessControl: account ", + Strings.toHexString(uint160(account), 20), + " is missing role ", + Strings.toHexString(uint256(role)) + ) + ); + } } contract Constructor is ZkCappedMinterV2Test { @@ -100,16 +111,7 @@ contract Mint is ZkCappedMinterV2Test { ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); - vm.expectRevert( - bytes( - string.concat( - "AccessControl: account ", - Strings.toHexString(uint160(_nonMinter), 20), - " is missing role ", - Strings.toHexString(uint256(MINTER_ROLE)) - ) - ) - ); + vm.expectRevert(_formatAccessControlError(_nonMinter, MINTER_ROLE)); vm.prank(_nonMinter); cappedMinter.mint(_nonMinter, _cap); } @@ -151,16 +153,7 @@ contract Mint is ZkCappedMinterV2Test { ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); - vm.expectRevert( - bytes( - string.concat( - "AccessControl: account ", - Strings.toHexString(uint160(_admin), 20), - " is missing role ", - Strings.toHexString(uint256(MINTER_ROLE)) - ) - ) - ); + vm.expectRevert(_formatAccessControlError(_admin, MINTER_ROLE)); vm.prank(_admin); cappedMinter.mint(_receiver, _amount); } @@ -210,16 +203,7 @@ contract Pause is ZkCappedMinterV2Test { vm.prank(_admin); cappedMinter.revokeRole(PAUSER_ROLE, _admin); - vm.expectRevert( - bytes( - string.concat( - "AccessControl: account ", - Strings.toHexString(uint160(_admin), 20), - " is missing role ", - Strings.toHexString(uint256(PAUSER_ROLE)) - ) - ) - ); + vm.expectRevert(_formatAccessControlError(_admin, PAUSER_ROLE)); vm.prank(_admin); cappedMinter.pause(); } @@ -270,16 +254,7 @@ contract Unpause is ZkCappedMinterV2Test { vm.prank(_admin); cappedMinter.revokeRole(PAUSER_ROLE, _admin); - vm.expectRevert( - bytes( - string.concat( - "AccessControl: account ", - Strings.toHexString(uint160(_admin), 20), - " is missing role ", - Strings.toHexString(uint256(PAUSER_ROLE)) - ) - ) - ); + vm.expectRevert(_formatAccessControlError(_admin, PAUSER_ROLE)); vm.prank(_admin); cappedMinter.unpause(); } From 6bb7d1a138a17990a21270d2d756e68ce9125c6a Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:37:49 -0800 Subject: [PATCH 29/49] fix: formatted error --- l2-contracts/test/ZkCappedMinterV2.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 01b0566..cad13bd 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -295,7 +295,7 @@ contract Close is ZkCappedMinterV2Test { _cap = bound(_cap, 0, MAX_MINT_SUPPLY); ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); - vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__NotPauser.selector, _nonPauser)); + vm.expectRevert(_formatAccessControlError(_nonPauser, PAUSER_ROLE)); vm.prank(_nonPauser); cappedMinter.close(); } From fca3ffba6fb3208590a96ba42abc2f24cede4186 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:08:10 -0800 Subject: [PATCH 30/49] fix: remove assume cap greater than 0 in favor of bound --- l2-contracts/test/ZkCappedMinterV2.t.sol | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 3e633ec..b036537 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -56,8 +56,7 @@ contract Mint is ZkCappedMinterV2Test { uint256 _cap, uint256 _amount ) public { - _cap = bound(_cap, 0, MAX_MINT_SUPPLY); - vm.assume(_cap > 0); + _cap = bound(_cap, 1, MAX_MINT_SUPPLY); _amount = bound(_amount, 1, MAX_MINT_SUPPLY); vm.assume(_cap > _amount); vm.assume(_receiver != address(0) && _receiver != initMintReceiver); @@ -81,8 +80,7 @@ contract Mint is ZkCappedMinterV2Test { uint256 _amount1, uint256 _amount2 ) public { - _cap = bound(_cap, 0, MAX_MINT_SUPPLY); - vm.assume(_cap > 0); + _cap = bound(_cap, 1, MAX_MINT_SUPPLY); vm.assume(_amount1 < MAX_MINT_SUPPLY / 2); vm.assume(_amount2 < MAX_MINT_SUPPLY / 2); vm.assume(_amount1 + _amount2 < _cap); @@ -105,7 +103,7 @@ contract Mint is ZkCappedMinterV2Test { } function testFuzz_RevertIf_MintAttemptedByNonMinter(address _admin, address _nonMinter, uint256 _cap) public { - _cap = bound(_cap, 0, MAX_MINT_SUPPLY); + _cap = bound(_cap, 1, MAX_MINT_SUPPLY); vm.assume(_admin != address(0)); vm.assume(_nonMinter != address(0) && _nonMinter != _admin); @@ -145,8 +143,7 @@ contract Mint is ZkCappedMinterV2Test { uint256 _cap, uint256 _amount ) public { - _cap = bound(_cap, 0, MAX_MINT_SUPPLY); - vm.assume(_cap > 0); + _cap = bound(_cap, 1, MAX_MINT_SUPPLY); _amount = bound(_amount, 1, _cap); vm.assume(_admin != address(0)); vm.assume(_receiver != address(0) && _receiver != initMintReceiver); @@ -167,8 +164,7 @@ contract Pause is ZkCappedMinterV2Test { uint256 _cap, uint256 _amount ) public { - _cap = bound(_cap, 0, MAX_MINT_SUPPLY); - vm.assume(_cap > 0); + _cap = bound(_cap, 1, MAX_MINT_SUPPLY); _amount = bound(_amount, 1, _cap); vm.assume(_admin != address(0)); vm.assume(_minter != address(0) && _minter != _admin); @@ -194,7 +190,7 @@ contract Pause is ZkCappedMinterV2Test { } function testFuzz_RevertIf_NotPauserRolePauses(address _admin, uint256 _cap) public { - _cap = bound(_cap, 0, MAX_MINT_SUPPLY); + _cap = bound(_cap, 1, MAX_MINT_SUPPLY); vm.assume(_admin != address(0)); ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); @@ -217,8 +213,7 @@ contract Unpause is ZkCappedMinterV2Test { uint256 _cap, uint256 _amount ) public { - _cap = bound(_cap, 0, MAX_MINT_SUPPLY); - vm.assume(_cap > 0); + _cap = bound(_cap, 1, MAX_MINT_SUPPLY); _amount = bound(_amount, 1, _cap); vm.assume(_admin != address(0)); vm.assume(_minter != address(0) && _minter != _admin); @@ -241,7 +236,7 @@ contract Unpause is ZkCappedMinterV2Test { } function testFuzz_RevertIf_NotPauserRoleUnpauses(address _admin, uint256 _cap) public { - _cap = bound(_cap, 0, MAX_MINT_SUPPLY); + _cap = bound(_cap, 1, MAX_MINT_SUPPLY); vm.assume(_admin != address(0)); ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); From 93e4af339e07acc26fc5961be644ea05d46ef466 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:22:40 -0800 Subject: [PATCH 31/49] fix: remove unnecessary assumptions --- l2-contracts/test/ZkCappedMinterV2.t.sol | 25 ++++++------------------ 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index b036537..d08aac8 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -59,8 +59,7 @@ contract Mint is ZkCappedMinterV2Test { _cap = bound(_cap, 1, MAX_MINT_SUPPLY); _amount = bound(_amount, 1, MAX_MINT_SUPPLY); vm.assume(_cap > _amount); - vm.assume(_receiver != address(0) && _receiver != initMintReceiver); - vm.assume(_minter != address(0)); + vm.assume(_receiver != address(0)); ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); @@ -84,10 +83,8 @@ contract Mint is ZkCappedMinterV2Test { vm.assume(_amount1 < MAX_MINT_SUPPLY / 2); vm.assume(_amount2 < MAX_MINT_SUPPLY / 2); vm.assume(_amount1 + _amount2 < _cap); - vm.assume(_receiver1 != address(0) && _receiver1 != initMintReceiver); - vm.assume(_receiver2 != address(0) && _receiver2 != initMintReceiver); + vm.assume(_receiver1 != address(0) && _receiver2 != address(0)); vm.assume(_receiver1 != _receiver2); - vm.assume(_minter != address(0)); ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); @@ -104,8 +101,6 @@ contract Mint is ZkCappedMinterV2Test { function testFuzz_RevertIf_MintAttemptedByNonMinter(address _admin, address _nonMinter, uint256 _cap) public { _cap = bound(_cap, 1, MAX_MINT_SUPPLY); - vm.assume(_admin != address(0)); - vm.assume(_nonMinter != address(0) && _nonMinter != _admin); ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); @@ -121,8 +116,7 @@ contract Mint is ZkCappedMinterV2Test { uint256 _cap ) public { _cap = bound(_cap, 4, MAX_MINT_SUPPLY); - vm.assume(_receiver != address(0) && _receiver != initMintReceiver); - vm.assume(_minter != address(0)); + vm.assume(_receiver != address(0)); ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); @@ -145,8 +139,7 @@ contract Mint is ZkCappedMinterV2Test { ) public { _cap = bound(_cap, 1, MAX_MINT_SUPPLY); _amount = bound(_amount, 1, _cap); - vm.assume(_admin != address(0)); - vm.assume(_receiver != address(0) && _receiver != initMintReceiver); + vm.assume(_receiver != address(0)); ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); @@ -166,9 +159,7 @@ contract Pause is ZkCappedMinterV2Test { ) public { _cap = bound(_cap, 1, MAX_MINT_SUPPLY); _amount = bound(_amount, 1, _cap); - vm.assume(_admin != address(0)); - vm.assume(_minter != address(0) && _minter != _admin); - vm.assume(_receiver != address(0) && _receiver != initMintReceiver); + vm.assume(_receiver != address(0)); ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); @@ -191,7 +182,6 @@ contract Pause is ZkCappedMinterV2Test { function testFuzz_RevertIf_NotPauserRolePauses(address _admin, uint256 _cap) public { _cap = bound(_cap, 1, MAX_MINT_SUPPLY); - vm.assume(_admin != address(0)); ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); @@ -215,9 +205,7 @@ contract Unpause is ZkCappedMinterV2Test { ) public { _cap = bound(_cap, 1, MAX_MINT_SUPPLY); _amount = bound(_amount, 1, _cap); - vm.assume(_admin != address(0)); - vm.assume(_minter != address(0) && _minter != _admin); - vm.assume(_receiver != address(0) && _receiver != initMintReceiver); + vm.assume(_receiver != address(0)); ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); @@ -237,7 +225,6 @@ contract Unpause is ZkCappedMinterV2Test { function testFuzz_RevertIf_NotPauserRoleUnpauses(address _admin, uint256 _cap) public { _cap = bound(_cap, 1, MAX_MINT_SUPPLY); - vm.assume(_admin != address(0)); ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); From 225ba92eb6efa385c51ac560a81ccb77e1090d1f Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:26:00 -0800 Subject: [PATCH 32/49] fix: use grant minter role --- l2-contracts/test/ZkCappedMinterV2.t.sol | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index d08aac8..4bf70f1 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -164,8 +164,7 @@ contract Pause is ZkCappedMinterV2Test { ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); // Grant minter role and verify minting works - vm.prank(_admin); - cappedMinter.grantRole(MINTER_ROLE, _minter); + _grantMinterRole(cappedMinter, _admin, _minter); vm.prank(_minter); cappedMinter.mint(_receiver, _amount); @@ -209,8 +208,7 @@ contract Unpause is ZkCappedMinterV2Test { ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); - vm.prank(_admin); - cappedMinter.grantRole(MINTER_ROLE, _minter); + _grantMinterRole(cappedMinter, _admin, _minter); vm.prank(_admin); cappedMinter.pause(); From 1942a64eab59368ef6ba1e7f34bf518562b4b0ba Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:27:12 -0800 Subject: [PATCH 33/49] fix: remove redundant balance check --- l2-contracts/test/ZkCappedMinterV2.t.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 4bf70f1..e9ac1d1 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -218,7 +218,6 @@ contract Unpause is ZkCappedMinterV2Test { vm.prank(_minter); cappedMinter.mint(_receiver, _amount); - assertEq(token.balanceOf(_receiver), _amount); } function testFuzz_RevertIf_NotPauserRoleUnpauses(address _admin, uint256 _cap) public { From 77acf62b91c53e15a4844a9e343839f76e43d139 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 11 Dec 2024 11:33:10 -0800 Subject: [PATCH 34/49] feat: refactor to set up capped minter in setup func --- l2-contracts/test/ZkCappedMinterV2.t.sol | 151 ++++++++--------------- 1 file changed, 51 insertions(+), 100 deletions(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index e9ac1d1..858c955 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -8,15 +8,21 @@ import {ZkCappedMinterV2} from "src/ZkCappedMinterV2.sol"; import {console2} from "forge-std/Test.sol"; contract ZkCappedMinterV2Test is ZkTokenTest { + ZkCappedMinterV2 public cappedMinter; + uint256 constant DEFAULT_CAP = 1000e18; + address cappedMinterAdmin = makeAddr("cappedMinterAdmin"); + function setUp() public virtual override { super.setUp(); - } - function createCappedMinter(address _admin, uint256 _cap) internal returns (ZkCappedMinterV2) { - ZkCappedMinterV2 cappedMinter = new ZkCappedMinterV2(IMintableAndDelegatable(address(token)), _admin, _cap); + cappedMinter = _createCappedMinter(cappedMinterAdmin, DEFAULT_CAP); + vm.prank(admin); token.grantRole(MINTER_ROLE, address(cappedMinter)); - return cappedMinter; + } + + function _createCappedMinter(address _admin, uint256 _cap) internal returns (ZkCappedMinterV2) { + return new ZkCappedMinterV2(IMintableAndDelegatable(address(token)), _admin, _cap); } function _grantMinterRole(ZkCappedMinterV2 _cappedMinter, address _cappedMinterAdmin, address _minter) internal { @@ -41,7 +47,7 @@ contract Constructor is ZkCappedMinterV2Test { public { _cap = bound(_cap, 0, MAX_MINT_SUPPLY); - ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); + ZkCappedMinterV2 cappedMinter = _createCappedMinter(_cappedMinterAdmin, _cap); assertEq(address(cappedMinter.TOKEN()), address(token)); assertEq(cappedMinter.hasRole(DEFAULT_ADMIN_ROLE, _cappedMinterAdmin), true); assertEq(cappedMinter.CAP(), _cap); @@ -50,20 +56,13 @@ contract Constructor is ZkCappedMinterV2Test { contract Mint is ZkCappedMinterV2Test { function testFuzz_MintsNewTokensWhenTheAmountRequestedIsBelowTheCap( - address _cappedMinterAdmin, address _minter, address _receiver, - uint256 _cap, uint256 _amount ) public { - _cap = bound(_cap, 1, MAX_MINT_SUPPLY); - _amount = bound(_amount, 1, MAX_MINT_SUPPLY); - vm.assume(_cap > _amount); - vm.assume(_receiver != address(0)); + _amount = bound(_amount, 1, DEFAULT_CAP); - ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); - - _grantMinterRole(cappedMinter, _cappedMinterAdmin, _minter); + _grantMinterRole(cappedMinter, cappedMinterAdmin, _minter); vm.prank(_minter); cappedMinter.mint(_receiver, _amount); @@ -71,24 +70,19 @@ contract Mint is ZkCappedMinterV2Test { } function testFuzz_MintsNewTokensInSuccessionToDifferentAccountsWhileRemainingBelowCap( - address _cappedMinterAdmin, address _minter, address _receiver1, address _receiver2, - uint256 _cap, uint256 _amount1, uint256 _amount2 ) public { - _cap = bound(_cap, 1, MAX_MINT_SUPPLY); - vm.assume(_amount1 < MAX_MINT_SUPPLY / 2); - vm.assume(_amount2 < MAX_MINT_SUPPLY / 2); - vm.assume(_amount1 + _amount2 < _cap); + _amount1 = bound(_amount1, 1, DEFAULT_CAP / 2); + _amount2 = bound(_amount2, 1, DEFAULT_CAP / 2); + vm.assume(_amount1 + _amount2 < DEFAULT_CAP); vm.assume(_receiver1 != address(0) && _receiver2 != address(0)); vm.assume(_receiver1 != _receiver2); - ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); - - _grantMinterRole(cappedMinter, _cappedMinterAdmin, _minter); + _grantMinterRole(cappedMinter, cappedMinterAdmin, _minter); vm.startPrank(_minter); cappedMinter.mint(_receiver1, _amount1); @@ -99,79 +93,49 @@ contract Mint is ZkCappedMinterV2Test { assertEq(token.balanceOf(_receiver2), _amount2); } - function testFuzz_RevertIf_MintAttemptedByNonMinter(address _admin, address _nonMinter, uint256 _cap) public { - _cap = bound(_cap, 1, MAX_MINT_SUPPLY); - - ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); + function testFuzz_RevertIf_MintAttemptedByNonMinter(address _nonMinter, uint256 _amount) public { + _amount = bound(_amount, 1, DEFAULT_CAP); vm.expectRevert(_formatAccessControlError(_nonMinter, MINTER_ROLE)); vm.prank(_nonMinter); - cappedMinter.mint(_nonMinter, _cap); + cappedMinter.mint(_nonMinter, _amount); } - function testFuzz_RevertIf_CapExceededOnMint( - address _cappedMinterAdmin, - address _minter, - address _receiver, - uint256 _cap - ) public { - _cap = bound(_cap, 4, MAX_MINT_SUPPLY); + function testFuzz_RevertIf_CapExceededOnMint(address _minter, address _receiver, uint256 _amount) public { + _amount = bound(_amount, DEFAULT_CAP + 1, type(uint256).max); vm.assume(_receiver != address(0)); - ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); + _grantMinterRole(cappedMinter, cappedMinterAdmin, _minter); - _grantMinterRole(cappedMinter, _cappedMinterAdmin, _minter); - - vm.prank(_minter); - cappedMinter.mint(_receiver, _cap); - assertEq(token.balanceOf(_receiver), _cap); - - vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__CapExceeded.selector, _minter, _cap)); + vm.expectRevert(abi.encodeWithSelector(ZkCappedMinterV2.ZkCappedMinterV2__CapExceeded.selector, _minter, _amount)); vm.prank(_minter); - cappedMinter.mint(_receiver, _cap); + cappedMinter.mint(_receiver, _amount); } - function testFuzz_RevertIf_AdminAttemptsToMintByDefault( - address _admin, - address _receiver, - uint256 _cap, - uint256 _amount - ) public { - _cap = bound(_cap, 1, MAX_MINT_SUPPLY); - _amount = bound(_amount, 1, _cap); + function testFuzz_RevertIf_AdminAttemptsToMintByDefault(address _receiver, uint256 _amount) public { + _amount = bound(_amount, 1, DEFAULT_CAP); vm.assume(_receiver != address(0)); - ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); - - vm.expectRevert(_formatAccessControlError(_admin, MINTER_ROLE)); - vm.prank(_admin); + vm.expectRevert(_formatAccessControlError(cappedMinterAdmin, MINTER_ROLE)); + vm.prank(cappedMinterAdmin); cappedMinter.mint(_receiver, _amount); } } contract Pause is ZkCappedMinterV2Test { - function testFuzz_CorrectlyPreventsNewMintsWhenPaused( - address _admin, - address _minter, - address _receiver, - uint256 _cap, - uint256 _amount - ) public { - _cap = bound(_cap, 1, MAX_MINT_SUPPLY); - _amount = bound(_amount, 1, _cap); + function testFuzz_CorrectlyPreventsNewMintsWhenPaused(address _minter, address _receiver, uint256 _amount) public { + _amount = bound(_amount, 1, DEFAULT_CAP); vm.assume(_receiver != address(0)); - ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); - // Grant minter role and verify minting works - _grantMinterRole(cappedMinter, _admin, _minter); + _grantMinterRole(cappedMinter, cappedMinterAdmin, _minter); vm.prank(_minter); cappedMinter.mint(_receiver, _amount); assertEq(token.balanceOf(_receiver), _amount); // Pause and verify minting fails - vm.prank(_admin); + vm.prank(cappedMinterAdmin); cappedMinter.pause(); vm.expectRevert("Pausable: paused"); @@ -179,62 +143,49 @@ contract Pause is ZkCappedMinterV2Test { cappedMinter.mint(_receiver, _amount); } - function testFuzz_RevertIf_NotPauserRolePauses(address _admin, uint256 _cap) public { - _cap = bound(_cap, 1, MAX_MINT_SUPPLY); - - ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); + function testFuzz_RevertIf_NotPauserRolePauses(uint256 _amount) public { + _amount = bound(_amount, 1, DEFAULT_CAP); // Remove PAUSER_ROLE from admin - vm.prank(_admin); - cappedMinter.revokeRole(PAUSER_ROLE, _admin); + vm.prank(cappedMinterAdmin); + cappedMinter.revokeRole(PAUSER_ROLE, cappedMinterAdmin); - vm.expectRevert(_formatAccessControlError(_admin, PAUSER_ROLE)); - vm.prank(_admin); + vm.expectRevert(_formatAccessControlError(cappedMinterAdmin, PAUSER_ROLE)); + vm.prank(cappedMinterAdmin); cappedMinter.pause(); } } contract Unpause is ZkCappedMinterV2Test { - function testFuzz_CorrectlyAllowsNewMintsWhenUnpaused( - address _admin, - address _minter, - address _receiver, - uint256 _cap, - uint256 _amount - ) public { - _cap = bound(_cap, 1, MAX_MINT_SUPPLY); - _amount = bound(_amount, 1, _cap); + function testFuzz_CorrectlyAllowsNewMintsWhenUnpaused(address _minter, address _receiver, uint256 _amount) public { + _amount = bound(_amount, 1, DEFAULT_CAP); vm.assume(_receiver != address(0)); - ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); + _grantMinterRole(cappedMinter, cappedMinterAdmin, _minter); - _grantMinterRole(cappedMinter, _admin, _minter); - - vm.prank(_admin); + vm.prank(cappedMinterAdmin); cappedMinter.pause(); - vm.prank(_admin); + vm.prank(cappedMinterAdmin); cappedMinter.unpause(); vm.prank(_minter); cappedMinter.mint(_receiver, _amount); } - function testFuzz_RevertIf_NotPauserRoleUnpauses(address _admin, uint256 _cap) public { - _cap = bound(_cap, 1, MAX_MINT_SUPPLY); - - ZkCappedMinterV2 cappedMinter = createCappedMinter(_admin, _cap); + function testFuzz_RevertIf_NotPauserRoleUnpauses(uint256 _amount) public { + _amount = bound(_amount, 1, DEFAULT_CAP); // Pause first (while admin still has PAUSER_ROLE) - vm.prank(_admin); + vm.prank(cappedMinterAdmin); cappedMinter.pause(); // Remove PAUSER_ROLE from admin - vm.prank(_admin); - cappedMinter.revokeRole(PAUSER_ROLE, _admin); + vm.prank(cappedMinterAdmin); + cappedMinter.revokeRole(PAUSER_ROLE, cappedMinterAdmin); - vm.expectRevert(_formatAccessControlError(_admin, PAUSER_ROLE)); - vm.prank(_admin); + vm.expectRevert(_formatAccessControlError(cappedMinterAdmin, PAUSER_ROLE)); + vm.prank(cappedMinterAdmin); cappedMinter.unpause(); } } From ecb275db99127a20a4b0d8d8afbe4ffaf867b9ad Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 11 Dec 2024 11:37:59 -0800 Subject: [PATCH 35/49] feat: testFuzz_CorrectlyPausesMintsWhenTogglingPause --- l2-contracts/test/ZkCappedMinterV2.t.sol | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 858c955..7afdae4 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -173,6 +173,23 @@ contract Unpause is ZkCappedMinterV2Test { cappedMinter.mint(_receiver, _amount); } + function testFuzz_CorrectlyPausesMintsWhenTogglingPause(address _minter, address _receiver, uint256 _amount) public { + _amount = bound(_amount, 1, DEFAULT_CAP); + vm.assume(_receiver != address(0)); + + _grantMinterRole(cappedMinter, cappedMinterAdmin, _minter); + + vm.startPrank(cappedMinterAdmin); + cappedMinter.pause(); + cappedMinter.unpause(); + cappedMinter.pause(); + vm.stopPrank(); + + vm.expectRevert("Pausable: paused"); + vm.prank(_minter); + cappedMinter.mint(_receiver, _amount); + } + function testFuzz_RevertIf_NotPauserRoleUnpauses(uint256 _amount) public { _amount = bound(_amount, 1, DEFAULT_CAP); From 43fa666d17e9c8a90a8b8917c805d816c0c6bfb5 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Wed, 11 Dec 2024 11:38:41 -0800 Subject: [PATCH 36/49] fix: move func --- l2-contracts/test/ZkCappedMinterV2.t.sol | 34 ++++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 7afdae4..ed55155 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -143,6 +143,23 @@ contract Pause is ZkCappedMinterV2Test { cappedMinter.mint(_receiver, _amount); } + function testFuzz_CorrectlyPausesMintsWhenTogglingPause(address _minter, address _receiver, uint256 _amount) public { + _amount = bound(_amount, 1, DEFAULT_CAP); + vm.assume(_receiver != address(0)); + + _grantMinterRole(cappedMinter, cappedMinterAdmin, _minter); + + vm.startPrank(cappedMinterAdmin); + cappedMinter.pause(); + cappedMinter.unpause(); + cappedMinter.pause(); + vm.stopPrank(); + + vm.expectRevert("Pausable: paused"); + vm.prank(_minter); + cappedMinter.mint(_receiver, _amount); + } + function testFuzz_RevertIf_NotPauserRolePauses(uint256 _amount) public { _amount = bound(_amount, 1, DEFAULT_CAP); @@ -173,23 +190,6 @@ contract Unpause is ZkCappedMinterV2Test { cappedMinter.mint(_receiver, _amount); } - function testFuzz_CorrectlyPausesMintsWhenTogglingPause(address _minter, address _receiver, uint256 _amount) public { - _amount = bound(_amount, 1, DEFAULT_CAP); - vm.assume(_receiver != address(0)); - - _grantMinterRole(cappedMinter, cappedMinterAdmin, _minter); - - vm.startPrank(cappedMinterAdmin); - cappedMinter.pause(); - cappedMinter.unpause(); - cappedMinter.pause(); - vm.stopPrank(); - - vm.expectRevert("Pausable: paused"); - vm.prank(_minter); - cappedMinter.mint(_receiver, _amount); - } - function testFuzz_RevertIf_NotPauserRoleUnpauses(uint256 _amount) public { _amount = bound(_amount, 1, DEFAULT_CAP); From 57e1f4ff929718d0787606b4d988dee1ea262024 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Thu, 12 Dec 2024 13:20:23 -0800 Subject: [PATCH 37/49] fix: only admin can close, fix mint to zero addr receiver, and formatting default admin string error --- l2-contracts/src/ZkCappedMinterV2.sol | 4 ++-- l2-contracts/test/ZkCappedMinterV2.t.sol | 15 ++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/l2-contracts/src/ZkCappedMinterV2.sol b/l2-contracts/src/ZkCappedMinterV2.sol index 7462432..b17ca77 100644 --- a/l2-contracts/src/ZkCappedMinterV2.sol +++ b/l2-contracts/src/ZkCappedMinterV2.sol @@ -85,9 +85,9 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { /// @notice Permanently closes the contract, preventing any future minting. /// @dev Once closed, the contract cannot be reopened and all minting operations will be permanently blocked. - /// @dev Only callable by accounts with the PAUSER_ROLE. + /// @dev Only callable by the admin. function close() external { - _checkRole(PAUSER_ROLE, msg.sender); + _checkRole(DEFAULT_ADMIN_ROLE, msg.sender); closed = true; _pause(); } diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 3b6d594..e25228f 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -36,7 +36,7 @@ contract ZkCappedMinterV2Test is ZkTokenTest { "AccessControl: account ", Strings.toHexString(uint160(account), 20), " is missing role ", - Strings.toHexString(uint256(role)) + Strings.toHexString(uint256(role), 32) ) ); } @@ -60,6 +60,7 @@ contract Mint is ZkCappedMinterV2Test { address _receiver, uint256 _amount ) public { + vm.assume(_receiver != address(0)); _amount = bound(_amount, 1, DEFAULT_CAP); _grantMinterRole(cappedMinter, cappedMinterAdmin, _minter); @@ -220,7 +221,7 @@ contract Close is ZkCappedMinterV2Test { _amount = bound(_amount, 1, _cap); vm.assume(_receiver != address(0) && _receiver != initMintReceiver); - ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); + ZkCappedMinterV2 cappedMinter = _createCappedMinter(_cappedMinterAdmin, _cap); vm.prank(_cappedMinterAdmin); cappedMinter.grantRole(MINTER_ROLE, _minter); @@ -237,13 +238,13 @@ contract Close is ZkCappedMinterV2Test { cappedMinter.unpause(); } - function testFuzz_RevertIf_NotPauserRoleCloses(address _cappedMinterAdmin, address _nonPauser, uint256 _cap) public { - vm.assume(_nonPauser != _cappedMinterAdmin); + function testFuzz_RevertIf_NotAdminCloses(address _cappedMinterAdmin, address _nonAdmin, uint256 _cap) public { + vm.assume(_nonAdmin != _cappedMinterAdmin); _cap = bound(_cap, 0, MAX_MINT_SUPPLY); - ZkCappedMinterV2 cappedMinter = createCappedMinter(_cappedMinterAdmin, _cap); - vm.expectRevert(_formatAccessControlError(_nonPauser, PAUSER_ROLE)); - vm.prank(_nonPauser); + ZkCappedMinterV2 cappedMinter = _createCappedMinter(_cappedMinterAdmin, _cap); + vm.expectRevert(_formatAccessControlError(_nonAdmin, DEFAULT_ADMIN_ROLE)); + vm.prank(_nonAdmin); cappedMinter.close(); } } From ef8ca9616beb4aaba4bc18e52ca51bad922527aa Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Thu, 12 Dec 2024 13:25:40 -0800 Subject: [PATCH 38/49] fix: remove unnecessary revert if closed when unpausing --- l2-contracts/src/ZkCappedMinterV2.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/l2-contracts/src/ZkCappedMinterV2.sol b/l2-contracts/src/ZkCappedMinterV2.sol index b17ca77..b8910c0 100644 --- a/l2-contracts/src/ZkCappedMinterV2.sol +++ b/l2-contracts/src/ZkCappedMinterV2.sol @@ -51,7 +51,6 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { /// @notice Unpauses token minting function unpause() external { - _revertIfClosed(); _checkRole(PAUSER_ROLE, msg.sender); _unpause(); } From 3fc7d3a441e8684416068793e7df181dff6df111 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Thu, 12 Dec 2024 13:26:29 -0800 Subject: [PATCH 39/49] Update l2-contracts/src/ZkCappedMinterV2.sol Co-authored-by: Alexander Keating --- l2-contracts/src/ZkCappedMinterV2.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l2-contracts/src/ZkCappedMinterV2.sol b/l2-contracts/src/ZkCappedMinterV2.sol index b8910c0..b7ddce1 100644 --- a/l2-contracts/src/ZkCappedMinterV2.sol +++ b/l2-contracts/src/ZkCappedMinterV2.sol @@ -28,7 +28,7 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { /// @notice Error for when the cap is exceeded. error ZkCappedMinterV2__CapExceeded(address minter, uint256 amount); - /// @notice Error for when the contract is closed. + /// @notice Thrown when a mint action is taken while the contract is closed. error ZkCappedMinterV2__ContractClosed(); /// @notice Constructor for a new ZkCappedMinterV2 contract From bb6854b4de08f1726c78381c3c8d87c2fb7c14fb Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Thu, 12 Dec 2024 13:26:51 -0800 Subject: [PATCH 40/49] fix: test --- l2-contracts/test/ZkCappedMinterV2.t.sol | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index e25228f..9fe685a 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -232,10 +232,14 @@ contract Close is ZkCappedMinterV2Test { vm.prank(_minter); cappedMinter.mint(_receiver, _amount); - // Try to unpause (should fail) - vm.expectRevert(ZkCappedMinterV2.ZkCappedMinterV2__ContractClosed.selector); + // Try to unpause (should succeed but minting still blocked) vm.prank(_cappedMinterAdmin); cappedMinter.unpause(); + + // Verify minting is still blocked even after unpausing + vm.expectRevert(ZkCappedMinterV2.ZkCappedMinterV2__ContractClosed.selector); + vm.prank(_minter); + cappedMinter.mint(_receiver, _amount); } function testFuzz_RevertIf_NotAdminCloses(address _cappedMinterAdmin, address _nonAdmin, uint256 _cap) public { From 0b17e887dfd99b3be389359209498921a6a9f58f Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Thu, 12 Dec 2024 13:30:10 -0800 Subject: [PATCH 41/49] fix: remove unnecessary pause from close --- l2-contracts/src/ZkCappedMinterV2.sol | 1 - l2-contracts/test/ZkCappedMinterV2.t.sol | 9 --------- 2 files changed, 10 deletions(-) diff --git a/l2-contracts/src/ZkCappedMinterV2.sol b/l2-contracts/src/ZkCappedMinterV2.sol index b7ddce1..b9a11b8 100644 --- a/l2-contracts/src/ZkCappedMinterV2.sol +++ b/l2-contracts/src/ZkCappedMinterV2.sol @@ -88,6 +88,5 @@ contract ZkCappedMinterV2 is AccessControl, Pausable { function close() external { _checkRole(DEFAULT_ADMIN_ROLE, msg.sender); closed = true; - _pause(); } } diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 9fe685a..69135ad 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -231,15 +231,6 @@ contract Close is ZkCappedMinterV2Test { vm.expectRevert(ZkCappedMinterV2.ZkCappedMinterV2__ContractClosed.selector); vm.prank(_minter); cappedMinter.mint(_receiver, _amount); - - // Try to unpause (should succeed but minting still blocked) - vm.prank(_cappedMinterAdmin); - cappedMinter.unpause(); - - // Verify minting is still blocked even after unpausing - vm.expectRevert(ZkCappedMinterV2.ZkCappedMinterV2__ContractClosed.selector); - vm.prank(_minter); - cappedMinter.mint(_receiver, _amount); } function testFuzz_RevertIf_NotAdminCloses(address _cappedMinterAdmin, address _nonAdmin, uint256 _cap) public { From 7631a2965182d2e588fbdfcbff07ee2c85c7468c Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Thu, 12 Dec 2024 13:33:41 -0800 Subject: [PATCH 42/49] fix: use global minter --- l2-contracts/test/ZkCappedMinterV2.t.sol | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 69135ad..3d18a04 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -209,23 +209,14 @@ contract Unpause is ZkCappedMinterV2Test { } contract Close is ZkCappedMinterV2Test { - function testFuzz_CorrectlyPermanentlyBlocksMinting( - address _cappedMinterAdmin, - address _minter, - address _receiver, - uint256 _cap, - uint256 _amount - ) public { - _cap = bound(_cap, 0, MAX_MINT_SUPPLY); - vm.assume(_cap > 0); - _amount = bound(_amount, 1, _cap); + function testFuzz_CorrectlyPermanentlyBlocksMinting(address _minter, address _receiver, uint256 _amount) public { + _amount = bound(_amount, 1, DEFAULT_CAP); vm.assume(_receiver != address(0) && _receiver != initMintReceiver); - ZkCappedMinterV2 cappedMinter = _createCappedMinter(_cappedMinterAdmin, _cap); - vm.prank(_cappedMinterAdmin); + vm.prank(cappedMinterAdmin); cappedMinter.grantRole(MINTER_ROLE, _minter); - vm.prank(_cappedMinterAdmin); + vm.prank(cappedMinterAdmin); cappedMinter.close(); vm.expectRevert(ZkCappedMinterV2.ZkCappedMinterV2__ContractClosed.selector); @@ -233,11 +224,8 @@ contract Close is ZkCappedMinterV2Test { cappedMinter.mint(_receiver, _amount); } - function testFuzz_RevertIf_NotAdminCloses(address _cappedMinterAdmin, address _nonAdmin, uint256 _cap) public { - vm.assume(_nonAdmin != _cappedMinterAdmin); - _cap = bound(_cap, 0, MAX_MINT_SUPPLY); - - ZkCappedMinterV2 cappedMinter = _createCappedMinter(_cappedMinterAdmin, _cap); + function testFuzz_RevertIf_NotAdminCloses(address _nonAdmin, uint256 _amount) public { + _amount = bound(_amount, 1, DEFAULT_CAP); vm.expectRevert(_formatAccessControlError(_nonAdmin, DEFAULT_ADMIN_ROLE)); vm.prank(_nonAdmin); cappedMinter.close(); From 246efdc0d9a8b4e5af2f20141e2a1c8f12924fed Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Mon, 16 Dec 2024 10:23:02 -0800 Subject: [PATCH 43/49] feat: test_CorrectlyChangesClosedVarWhenCalledByAdmin --- l2-contracts/test/ZkCappedMinterV2.t.sol | 28 +++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 3d18a04..6951e4d 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -121,6 +121,21 @@ contract Mint is ZkCappedMinterV2Test { vm.prank(cappedMinterAdmin); cappedMinter.mint(_receiver, _amount); } + + function testFuzz_CorrectlyPermanentlyBlocksMinting(address _minter, address _receiver, uint256 _amount) public { + _amount = bound(_amount, 1, DEFAULT_CAP); + vm.assume(_receiver != address(0) && _receiver != initMintReceiver); + + vm.prank(cappedMinterAdmin); + cappedMinter.grantRole(MINTER_ROLE, _minter); + + vm.prank(cappedMinterAdmin); + cappedMinter.close(); + + vm.expectRevert(ZkCappedMinterV2.ZkCappedMinterV2__ContractClosed.selector); + vm.prank(_minter); + cappedMinter.mint(_receiver, _amount); + } } contract Pause is ZkCappedMinterV2Test { @@ -209,19 +224,12 @@ contract Unpause is ZkCappedMinterV2Test { } contract Close is ZkCappedMinterV2Test { - function testFuzz_CorrectlyPermanentlyBlocksMinting(address _minter, address _receiver, uint256 _amount) public { - _amount = bound(_amount, 1, DEFAULT_CAP); - vm.assume(_receiver != address(0) && _receiver != initMintReceiver); - - vm.prank(cappedMinterAdmin); - cappedMinter.grantRole(MINTER_ROLE, _minter); + function test_CorrectlyChangesClosedVarWhenCalledByAdmin() public { + assertEq(cappedMinter.closed(), false); vm.prank(cappedMinterAdmin); cappedMinter.close(); - - vm.expectRevert(ZkCappedMinterV2.ZkCappedMinterV2__ContractClosed.selector); - vm.prank(_minter); - cappedMinter.mint(_receiver, _amount); + assertEq(cappedMinter.closed(), true); } function testFuzz_RevertIf_NotAdminCloses(address _nonAdmin, uint256 _amount) public { From 91c0ca87438338aba9c38a66f8f78d86827a598c Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:56:39 -0800 Subject: [PATCH 44/49] fix: foundry toml revert --- l2-contracts/foundry.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/l2-contracts/foundry.toml b/l2-contracts/foundry.toml index 6934b43..99eb898 100644 --- a/l2-contracts/foundry.toml +++ b/l2-contracts/foundry.toml @@ -9,14 +9,13 @@ "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/", "@murky/=lib/murky/", - "src/=src/", ] solc_version = "0.8.24" verbosity = 3 [profile.ci] - fuzz = { runs = 5000 } - invariant = { runs = 1000 } + fuzz = { runs = 1000 } + invariant = { runs = 500 } [profile.lite] fuzz = { runs = 50 } From 48c9ca6f6ed54c0fe0c98369838a7c576845b395 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:55:25 -0800 Subject: [PATCH 45/49] fix: handle check balances before and after --- l2-contracts/test/ZkCappedMinterV2.t.sol | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index b6b2f19..9b5c995 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -66,9 +66,11 @@ contract Mint is ZkCappedMinterV2Test { _grantMinterRole(cappedMinter, cappedMinterAdmin, _minter); + uint256 amountBefore = token.balanceOf(_receiver); + vm.prank(_minter); cappedMinter.mint(_receiver, _amount); - assertEq(token.balanceOf(_receiver), _amount); + assertEq(token.balanceOf(_receiver), amountBefore + _amount); } function testFuzz_MintsNewTokensInSuccessionToDifferentAccountsWhileRemainingBelowCap( @@ -86,13 +88,16 @@ contract Mint is ZkCappedMinterV2Test { _grantMinterRole(cappedMinter, cappedMinterAdmin, _minter); + uint256 amountBefore1 = token.balanceOf(_receiver1); + uint256 amountBefore2 = token.balanceOf(_receiver2); + vm.startPrank(_minter); cappedMinter.mint(_receiver1, _amount1); cappedMinter.mint(_receiver2, _amount2); vm.stopPrank(); - assertEq(token.balanceOf(_receiver1), _amount1); - assertEq(token.balanceOf(_receiver2), _amount2); + assertEq(token.balanceOf(_receiver1), amountBefore1 + _amount1); + assertEq(token.balanceOf(_receiver2), amountBefore2 + _amount2); } function testFuzz_RevertIf_MintAttemptedByNonMinter(address _nonMinter, uint256 _amount) public { From fe1cac7cc969b0e86cb0eeac4ce9c1710be9d9f0 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:57:30 -0800 Subject: [PATCH 46/49] fix: assume not capped minter admin --- l2-contracts/test/ZkCappedMinterV2.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 9b5c995..4af1109 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -239,7 +239,7 @@ contract Close is ZkCappedMinterV2Test { } function testFuzz_RevertIf_NotAdminCloses(address _nonAdmin, uint256 _amount) public { - _amount = bound(_amount, 1, DEFAULT_CAP); + vm.assume(_nonAdmin != cappedMinterAdmin); vm.expectRevert(_formatAccessControlError(_nonAdmin, DEFAULT_ADMIN_ROLE)); vm.prank(_nonAdmin); cappedMinter.close(); From c7bef58cf0e4f3742571151dcf5f697f857fcc95 Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:00:11 -0800 Subject: [PATCH 47/49] fix: handle balance check before in test --- l2-contracts/test/ZkCappedMinterV2.t.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 4af1109..56673f1 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -152,9 +152,11 @@ contract Pause is ZkCappedMinterV2Test { // Grant minter role and verify minting works _grantMinterRole(cappedMinter, cappedMinterAdmin, _minter); + uint256 amountBefore = token.balanceOf(_receiver); + vm.prank(_minter); cappedMinter.mint(_receiver, _amount); - assertEq(token.balanceOf(_receiver), _amount); + assertEq(token.balanceOf(_receiver), amountBefore + _amount); // Pause and verify minting fails vm.prank(cappedMinterAdmin); From 010e4c59e002a8ba05323c726825f67ae42e0eaf Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:01:20 -0800 Subject: [PATCH 48/49] fix: rename --- l2-contracts/test/ZkCappedMinterV2.t.sol | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 56673f1..3738dbe 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -66,11 +66,11 @@ contract Mint is ZkCappedMinterV2Test { _grantMinterRole(cappedMinter, cappedMinterAdmin, _minter); - uint256 amountBefore = token.balanceOf(_receiver); + uint256 balanceBefore = token.balanceOf(_receiver); vm.prank(_minter); cappedMinter.mint(_receiver, _amount); - assertEq(token.balanceOf(_receiver), amountBefore + _amount); + assertEq(token.balanceOf(_receiver), balanceBefore + _amount); } function testFuzz_MintsNewTokensInSuccessionToDifferentAccountsWhileRemainingBelowCap( @@ -88,16 +88,16 @@ contract Mint is ZkCappedMinterV2Test { _grantMinterRole(cappedMinter, cappedMinterAdmin, _minter); - uint256 amountBefore1 = token.balanceOf(_receiver1); - uint256 amountBefore2 = token.balanceOf(_receiver2); + uint256 balanceBefore1 = token.balanceOf(_receiver1); + uint256 balanceBefore2 = token.balanceOf(_receiver2); vm.startPrank(_minter); cappedMinter.mint(_receiver1, _amount1); cappedMinter.mint(_receiver2, _amount2); vm.stopPrank(); - assertEq(token.balanceOf(_receiver1), amountBefore1 + _amount1); - assertEq(token.balanceOf(_receiver2), amountBefore2 + _amount2); + assertEq(token.balanceOf(_receiver1), balanceBefore1 + _amount1); + assertEq(token.balanceOf(_receiver2), balanceBefore2 + _amount2); } function testFuzz_RevertIf_MintAttemptedByNonMinter(address _nonMinter, uint256 _amount) public { @@ -152,11 +152,11 @@ contract Pause is ZkCappedMinterV2Test { // Grant minter role and verify minting works _grantMinterRole(cappedMinter, cappedMinterAdmin, _minter); - uint256 amountBefore = token.balanceOf(_receiver); + uint256 balanceBefore = token.balanceOf(_receiver); vm.prank(_minter); cappedMinter.mint(_receiver, _amount); - assertEq(token.balanceOf(_receiver), amountBefore + _amount); + assertEq(token.balanceOf(_receiver), balanceBefore + _amount); // Pause and verify minting fails vm.prank(cappedMinterAdmin); From 960a751fcc122cf0e05d94a255e309a56a9256dd Mon Sep 17 00:00:00 2001 From: marcomariscal <42938673+marcomariscal@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:01:56 -0800 Subject: [PATCH 49/49] chore: remove unused --- l2-contracts/test/ZkCappedMinterV2.t.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/l2-contracts/test/ZkCappedMinterV2.t.sol b/l2-contracts/test/ZkCappedMinterV2.t.sol index 3738dbe..ee8860a 100644 --- a/l2-contracts/test/ZkCappedMinterV2.t.sol +++ b/l2-contracts/test/ZkCappedMinterV2.t.sol @@ -56,7 +56,6 @@ contract Constructor is ZkCappedMinterV2Test { contract Mint is ZkCappedMinterV2Test { function testFuzz_MintsNewTokensWhenTheAmountRequestedIsBelowTheCap( - address _cappedMinterAdmin, address _minter, address _receiver, uint256 _amount @@ -240,7 +239,7 @@ contract Close is ZkCappedMinterV2Test { assertEq(cappedMinter.closed(), true); } - function testFuzz_RevertIf_NotAdminCloses(address _nonAdmin, uint256 _amount) public { + function testFuzz_RevertIf_NotAdminCloses(address _nonAdmin) public { vm.assume(_nonAdmin != cappedMinterAdmin); vm.expectRevert(_formatAccessControlError(_nonAdmin, DEFAULT_ADMIN_ROLE)); vm.prank(_nonAdmin);