-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathERC20CrossChainModule.sol
More file actions
142 lines (127 loc) · 5.55 KB
/
ERC20CrossChainModule.sol
File metadata and controls
142 lines (127 loc) · 5.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// SPDX-License-Identifier: MPL-2.0
pragma solidity ^0.8.20;
/* ==== OpenZeppelin === */
import {ERC165Upgradeable, IERC165} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
/* ==== Module === */
import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
/* ==== Interfaces === */
import {IERC7802} from "../../../interfaces/technical/IERC7802.sol";
import {IBurnFromERC20} from "../../../interfaces/technical/IMintBurnToken.sol";
import {IERC20Allowance} from "../../../interfaces/technical/IERC20Allowance.sol";
import {ERC20BurnModule, ERC20BurnModuleInternal} from "../core/ERC20BurnModule.sol";
import {ERC20MintModule, ERC20MintModuleInternal} from "../core/ERC20MintModule.sol";
/**
* @title ERC20CrossChainModule (ERC-7802)
* @dev
*
* Contains all mint and burn functions, inherits from ERC-20
* Implements ERC-7802 for cross-chain burn and mint
*/
abstract contract ERC20CrossChainModule is ERC20MintModule, ERC20BurnModule, ERC165Upgradeable, IERC7802, IBurnFromERC20 {
/* ============ State Variables ============ */
bytes32 public constant BURNER_FROM_ROLE = keccak256("BURNER_FROM_ROLE");
bytes32 public constant BURNER_SELF_ROLE = keccak256("BURNER_SELF_ROLE");
bytes32 public constant CROSS_CHAIN_ROLE = keccak256("CROSS_CHAIN_ROLE");
/* ============ Modifier ============ */
/// @dev Modifier to restrict access to the token bridge.
/// Source: OpenZeppelin v5.4.0 - draft-ERC20Bridgeable.sol
modifier onlyTokenBridge() {
// Token bridge should never be impersonated using a relayer/forwarder. Using msg.sender is preferable to
// _msgSender() for security reasons.
_checkTokenBridge(msg.sender);
_;
}
/// @dev Modifier to restrict access to the burner functions
modifier onlyBurnerFrom() {
_authorizeBurnFrom();
_;
}
/// @dev Modifier to restrict access to the burner functions
modifier onlySelfBurn() {
_authorizeSelfBurn();
_;
}
/*//////////////////////////////////////////////////////////////
PUBLIC/EXTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @inheritdoc IERC7802
* @dev
* Don't emit the same event as configured in the ERC20MintModule
* @custom:access-control
* Protected by the modifier onlyTokenBridge.
*/
function crosschainMint(address to, uint256 value) public virtual override(IERC7802) onlyTokenBridge {
_mintOverride(to, value);
emit CrosschainMint(to, value,_msgSender());
}
/**
* @inheritdoc IERC7802
* @dev
* Don't emit the same event as configured in the ERC20BurnModule
* Don't require allowance to follow Optimism Superchain ERC20 and OpenZeppelin implementation
* @custom:access-control
* - Protected by the modifier onlyTokenBridge.
*/
function crosschainBurn(address from, uint256 value) public virtual override(IERC7802) onlyTokenBridge{
_burnOverride(from, value);
emit CrosschainBurn(from, value, _msgSender());
}
/**
* @inheritdoc IBurnFromERC20
* @custom:access-control
* - Protected by the modifier onlyBurnerFrom.
*/
function burnFrom(address account, uint256 value)
public virtual override(IBurnFromERC20) onlyBurnerFrom
{
address sender = _msgSender();
_burnFrom(sender, account, value);
}
/**
* @inheritdoc IBurnFromERC20
* @custom:access-control
* - Protected by the modifier onlyBurnerFrom
*/
function burn(
uint256 value
) public virtual override(IBurnFromERC20) onlySelfBurn{
// Don't emit Spend event because allowance is not used here
address sender = _msgSender();
// burn from itself
_burn(sender, sender, value);
}
/* ============ View functions ============ */
function supportsInterface(bytes4 _interfaceId) public view virtual override(ERC165Upgradeable, IERC165) returns (bool) {
return _interfaceId == type(IERC7802).interfaceId || ERC165Upgradeable.supportsInterface(_interfaceId);
}
/*//////////////////////////////////////////////////////////////
INTERNAL/PRIVATE FUNCTIONS
//////////////////////////////////////////////////////////////*/
function _burnFrom(address sender, address account, uint256 value) internal virtual{
// Allowance check and spend
ERC20Upgradeable._spendAllowance(account, sender, value );
// Specific event for the spend operation, same as transferFrom (ERC20BaseModule)
// Importing the event through inheritance will result in the following error: "Linearization of inheritance graph impossible"
emit IERC20Allowance.Spend(account, sender, value);
_burn(sender, account, value);
}
function _burn(
address sender, address account, uint256 value
) internal virtual{
// burn
_burnOverride(account, value);
// Specific event to burnFrom and self-burn (burn)
// Don't emit CrossChainBurn because this function burn is not part of the IERC7802 interface
emit BurnFrom(sender, account, sender, value);
}
/* ==== Access Control ==== */
/**
* @dev Checks if the caller is a trusted token bridge. MUST revert otherwise.
*
* Source: OpenZeppelin v5.4.0 - draft-ERC20Bridgeable.sol
*/
function _checkTokenBridge(address caller) internal virtual;
function _authorizeBurnFrom() internal virtual;
function _authorizeSelfBurn() internal virtual;
}