/
ScrollStandardERC20.sol
96 lines (81 loc) · 3.15 KB
/
ScrollStandardERC20.sol
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
// SPDX-License-Identifier: MIT
pragma solidity =0.8.16;
import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol";
import {IScrollERC20Upgradeable} from "./IScrollERC20Upgradeable.sol";
import {IERC677Receiver} from "../callbacks/IERC677Receiver.sol";
/// @notice The `ScrollStandardERC20` is the ERC20 token contract created by
/// `L2StandardERC20Gateway` when the first time the L1 ERC20 is bridged via
/// `L1StandardERC20Gateway`.
/// @dev The reason that `ScrollStandardERC20` inherits `IScrollERC20Upgradeable` is because we need
/// to use the `initialize` function from the `ERC20PermitUpgradeable` to initialize the ERC20
/// token. However, the token contract is NOT upgradable afterwards because
/// `ScrollStandardERC20Factory` uses `Clones` to deploy the `ScrollStandardERC20` contract.
contract ScrollStandardERC20 is ERC20PermitUpgradeable, IScrollERC20Upgradeable {
/// @inheritdoc IScrollERC20Upgradeable
address public override gateway;
/// @inheritdoc IScrollERC20Upgradeable
address public override counterpart;
uint8 private decimals_;
modifier onlyGateway() {
require(gateway == msg.sender, "Only Gateway");
_;
}
constructor() {
_disableInitializers();
}
function initialize(
string memory _name,
string memory _symbol,
uint8 _decimals,
address _gateway,
address _counterpart
) external initializer {
__ERC20Permit_init(_name);
__ERC20_init(_name, _symbol);
decimals_ = _decimals;
gateway = _gateway;
counterpart = _counterpart;
}
function decimals() public view override returns (uint8) {
return decimals_;
}
/// @dev ERC677 Standard, see https://github.com/ethereum/EIPs/issues/677
/// Defi can use this method to transfer L1/L2 token to L2/L1,
/// and deposit to L2/L1 contract in one transaction
function transferAndCall(
address receiver,
uint256 amount,
bytes calldata data
) external returns (bool success) {
ERC20Upgradeable.transfer(receiver, amount);
if (isContract(receiver)) {
contractFallback(receiver, amount, data);
}
return true;
}
function contractFallback(
address to,
uint256 value,
bytes memory data
) private {
IERC677Receiver receiver = IERC677Receiver(to);
receiver.onTokenTransfer(msg.sender, value, data);
}
function isContract(address _addr) private view returns (bool hasCode) {
uint256 length;
// solhint-disable-next-line no-inline-assembly
assembly {
length := extcodesize(_addr)
}
return length > 0;
}
/// @inheritdoc IScrollERC20Upgradeable
function mint(address _to, uint256 _amount) external onlyGateway {
_mint(_to, _amount);
}
/// @inheritdoc IScrollERC20Upgradeable
function burn(address _from, uint256 _amount) external onlyGateway {
_burn(_from, _amount);
}
}