Skip to content

Commit bf581dc

Browse files
committed
feat: port minter-burner role from v0.5.1
1 parent 68cfbd8 commit bf581dc

4 files changed

Lines changed: 53 additions & 31 deletions

File tree

src/etc/Versioned.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// SPDX-License-Identifier: LicenseRef-PolygonLabs-Source-Available
2-
// Vault Bridge (last updated v1.1.0) (etc/Versioned.sol)
2+
// Vault Bridge (last updated v1.1.1) (etc/Versioned.sol)
33

44
pragma solidity 0.8.29;
55

66
/// @author See https://github.com/agglayer/vault-bridge
77
abstract contract Versioned {
88
/// @notice The version of the contract.
99
function VAULT_BRIDGE_PROTOCOL() public pure returns (string memory) {
10-
return "1.1.0";
10+
return "1.1.1";
1111
}
1212
}

src/secondary-chain/CustomToken.sol

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: LicenseRef-PolygonLabs-Source-Available
2-
// Vault Bridge (last updated v1.1.0) (secondary-chain/CustomToken.sol)
2+
// Vault Bridge (last updated v1.1.1) (secondary-chain/CustomToken.sol)
33

44
pragma solidity 0.8.29;
55

@@ -38,6 +38,7 @@ abstract contract CustomToken is
3838
address bridge;
3939
address nativeConverter;
4040
uint256 _secondaryChainBalance;
41+
mapping(address => uint256) _netMintedByAdditionalMintersBurners;
4142
}
4243

4344
/// @dev The storage slot at which Custom Token storage starts, following the EIP-7201 standard.
@@ -48,6 +49,10 @@ abstract contract CustomToken is
4849
// Basic roles.
4950
// @remind Document.
5051
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
52+
bytes32 public constant MINTER_BURNER_ROLE = keccak256("MINTER_BURNER_ROLE");
53+
54+
// Events.
55+
event AlreadyMinted(uint256 indexed value);
5156

5257
// Errors.
5358
error Unauthorized();
@@ -60,6 +65,45 @@ abstract contract CustomToken is
6065
error NativeConverterAlreadySet();
6166
error FunctionNotSupportedWithThisBridgeProvider();
6267

68+
// -----================= ::: MODIFIERS ::: =================-----
69+
70+
/// @dev Checks if the sender is The Bridge or Native Converter or an additional minter-burner.
71+
/// @dev This modifier is used to restrict the minting of Custom Token.
72+
modifier mintController(address account, uint256 value) {
73+
CustomTokenStorage storage $ = _getCustomTokenStorage();
74+
75+
bool senderIsBridgeOrNativeConverter = msg.sender == $.bridge || msg.sender == $.nativeConverter;
76+
bool senderIsAdditionalMinterBurner = hasRole(MINTER_BURNER_ROLE, msg.sender);
77+
78+
// Only The Bridge and Native Converter and additional minter-burners can mint Custom Token.
79+
require(senderIsBridgeOrNativeConverter || senderIsAdditionalMinterBurner, Unauthorized());
80+
81+
_;
82+
83+
// If `account` is address zero, that means special logic will (or will not) be executed in the `mint` function.
84+
if (account != address(0) && senderIsAdditionalMinterBurner && !senderIsBridgeOrNativeConverter) {
85+
$._netMintedByAdditionalMintersBurners[msg.sender] += value;
86+
}
87+
}
88+
89+
/// @dev Checks if the sender is The Bridge or Native Converter or an additional minter-burner.
90+
/// @dev This modifier is used to restrict the burning of Custom Token.
91+
modifier burnController(uint256 value) {
92+
CustomTokenStorage storage $ = _getCustomTokenStorage();
93+
94+
bool senderIsBridgeOrNativeConverter = msg.sender == $.bridge || msg.sender == $.nativeConverter;
95+
bool senderIsAdditionalBurner = hasRole(MINTER_BURNER_ROLE, msg.sender);
96+
97+
// Only The Bridge and Native Converter and additional burners can burn Custom Token.
98+
require(senderIsBridgeOrNativeConverter || senderIsAdditionalBurner, Unauthorized());
99+
100+
if (senderIsAdditionalBurner && !senderIsBridgeOrNativeConverter) {
101+
$._netMintedByAdditionalMintersBurners[msg.sender] -= value;
102+
}
103+
104+
_;
105+
}
106+
63107
// -----================= ::: SETUP ::: =================-----
64108

65109
/// @dev Preserves the `name` and `symbol` of the bridged vbToken.

src/secondary-chain/agglayer/CustomTokenAgglayer.sol

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: LicenseRef-PolygonLabs-Source-Available
2-
// Vault Bridge (last updated v1.0.0) (secondary-chain/agglayer/CustomTokenAgglayer.sol)
2+
// Vault Bridge (last updated v1.1.1) (secondary-chain/agglayer/CustomTokenAgglayer.sol)
33

44
pragma solidity 0.8.29;
55

@@ -12,26 +12,10 @@ import {NativeConverter} from "../NativeConverter.sol";
1212
// @remind Document.
1313
/// @author See https://github.com/agglayer/vault-bridge
1414
abstract contract CustomTokenAgglayer is CustomToken {
15-
// Events.
16-
event AlreadyMinted(uint256 indexed value);
17-
18-
// -----================= ::: MODIFIERS ::: =================-----
19-
20-
/// @dev Checks if the sender is Agglayer Bridge or Native Converter.
21-
/// @dev This modifier is used to restrict minting and burning of Custom Token.
22-
modifier onlyAgglayerBridgeAndNativeConverter() {
23-
// Only Agglayer Bridge and Native Converter can mint and burn Custom Token.
24-
require(msg.sender == bridge() || msg.sender == nativeConverter(), Unauthorized());
25-
_;
26-
}
27-
2815
// -----================= ::: CUSTOM TOKEN ::: =================-----
2916

30-
// @remind Redocument (the entire function).
31-
/// @notice Mints Custom Tokens to the recipient.
32-
/// @notice This function can be called by Agglayer Bridge and Native Converter only.
33-
/// @param account @note CAUTION! Minting to `address(0)` will result in no tokens minted! This is to enable vbToken on Primary Chain to bridge tokens to address zero on Secondary Chain at the end of the process of migrating backing from Native Converter to Primary Chain. Please refer to `NativeConverter.sol` for more information.
34-
function mint(address account, uint256 value) external onlyAgglayerBridgeAndNativeConverter nonReentrant {
17+
/// @notice This function can be called by Agglayer Bridge, Native Converter, and additional minter-burners only.
18+
function mint(address account, uint256 value) external whenNotPaused mintController(account, value) nonReentrant {
3519
if (msg.sender == bridge() && account == address(0)) {
3620
NativeConverter(nativeConverter()).removeMigrationInProgress(value);
3721

@@ -42,18 +26,12 @@ abstract contract CustomTokenAgglayer is CustomToken {
4226

4327
_requireNotPaused();
4428

45-
// Mint.
4629
_mint(account, value);
4730
}
4831

4932
/// @notice Burns Custom Tokens from a holder.
50-
/// @notice This function can be called by Agglayer Bridge and Native Converter only.
51-
function burn(address account, uint256 value)
52-
external
53-
whenNotPaused
54-
onlyAgglayerBridgeAndNativeConverter
55-
nonReentrant
56-
{
33+
/// @notice This function can be called by Agglayer Bridge, Native Converter, and additional minter-burners only.
34+
function burn(address account, uint256 value) external whenNotPaused burnController(value) nonReentrant {
5735
_burn(account, value);
5836
}
5937

test/unit/secondary-chain/agglayer/GenericCustomTokenAgglayer.t.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ contract GenericCustomTokenAgglayerTest is GenericCustomTokenAgglayerTestBase {
5050
uint256 amount = 1000e18;
5151

5252
vm.expectEmit(true, true, true, true);
53-
emit CustomTokenAgglayer.AlreadyMinted(amount);
53+
emit CustomToken.AlreadyMinted(amount);
5454

5555
vm.prank(address(mockAgglayerBridge));
5656
genericCustomTokenAgglayer.mint(address(0), amount);

0 commit comments

Comments
 (0)