refactor: use custom error type instead of error strings (#18)

The `onlyBridge` modifier uses strings as error messages which are
expensive in gas.

This commit refactors this to use a custom error type instead and also
introduces some basic tests to ensure the errors are emitted properly.

It also adds some sanity tests for minting and burning bridge tokens.
This commit is contained in:
r4bbit 2023-10-06 08:37:32 +02:00 committed by GitHub
parent 2c0c825d60
commit fe1a4e96ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 66 additions and 3 deletions

View File

@ -1 +1,7 @@
OptmismMintableMiniMeTokenTest:testDeployment() (gas: 56870)
BurnTest:testDeployment() (gas: 56874)
BurnTest:test_Burn() (gas: 124436)
BurnTest:test_RevertWhen_SenderIsNotBridge() (gas: 10076)
MintTest:testDeployment() (gas: 56874)
MintTest:test_Mint() (gas: 110237)
MintTest:test_RevertWhen_SenderIsNotBridge() (gas: 10076)
OptmismMintableMiniMeTokenTest:testDeployment() (gas: 56874)

View File

@ -13,6 +13,9 @@ import { Semver } from "./Semver.sol";
/// Designed to be backwards compatible with the older StandardL2ERC20 token which was only
/// meant for use on L2.
contract OptimismMintableMiniMeToken is IOptimismMintableERC20, ILegacyMintableERC20, MiniMeBase, Semver {
/// @notice Error that is thrown if the sender is not the bridge.
error OptimismMintableMiniMeToken_SenderNotBridge();
/// @notice Address of the corresponding version of this token on the remote chain.
address public immutable REMOTE_TOKEN;
@ -31,7 +34,7 @@ contract OptimismMintableMiniMeToken is IOptimismMintableERC20, ILegacyMintableE
/// @notice A modifier that only allows the bridge to call
modifier onlyBridge() {
require(msg.sender == BRIDGE, "OptimismMintableMiniMeToken: only bridge can mint and burn");
if (msg.sender != BRIDGE) revert OptimismMintableMiniMeToken_SenderNotBridge();
_;
}

View File

@ -15,10 +15,12 @@ contract OptmismMintableMiniMeTokenTest is Test {
address internal deployer;
address internal bridgeAddress;
function setUp() public virtual {
DeployBridge deployment = new DeployBridge();
(deploymentConfig, bridgeToken, tokenController) = deployment.run();
(deployer,,,,,,,,) = deploymentConfig.activeNetworkConfig();
(deployer, bridgeAddress,,,,,,,) = deploymentConfig.activeNetworkConfig();
}
function testDeployment() public {
@ -48,3 +50,55 @@ contract OptmismMintableMiniMeTokenTest is Test {
assertEq(bridgeToken.transfersEnabled(), _transferEnabled);
}
}
contract MintTest is OptmismMintableMiniMeTokenTest {
event Mint(address indexed account, uint256 amount);
function setUp() public override {
OptmismMintableMiniMeTokenTest.setUp();
}
function test_RevertWhen_SenderIsNotBridge() public {
vm.expectRevert(OptimismMintableMiniMeToken.OptimismMintableMiniMeToken_SenderNotBridge.selector);
bridgeToken.mint(makeAddr("receiver"), 100);
}
function test_Mint() public {
address receiver = makeAddr("receiver");
vm.prank(bridgeAddress);
vm.expectEmit(true, true, true, true);
emit Mint(receiver, 100);
bridgeToken.mint(receiver, 100);
assertEq(bridgeToken.balanceOf(receiver), 100);
}
}
contract BurnTest is OptmismMintableMiniMeTokenTest {
event Burn(address indexed account, uint256 amount);
function setUp() public override {
OptmismMintableMiniMeTokenTest.setUp();
}
function test_RevertWhen_SenderIsNotBridge() public {
vm.expectRevert(OptimismMintableMiniMeToken.OptimismMintableMiniMeToken_SenderNotBridge.selector);
bridgeToken.burn(makeAddr("holder"), 100);
}
function test_Burn() public {
address holder = makeAddr("holder");
vm.prank(bridgeAddress);
bridgeToken.mint(holder, 100);
assertEq(bridgeToken.balanceOf(holder), 100);
vm.prank(bridgeAddress);
vm.expectEmit(true, true, true, true);
emit Burn(holder, 100);
bridgeToken.burn(holder, 100);
assertEq(bridgeToken.balanceOf(holder), 0);
}
}