forked from ethereum-optimism/optimism
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStandardBridge.t.sol
120 lines (103 loc) · 5.15 KB
/
StandardBridge.t.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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { StandardBridge } from "../src/universal/StandardBridge.sol";
import { CommonTest } from "./CommonTest.t.sol";
import { OptimismMintableERC20, ILegacyMintableERC20 } from "../src/universal/OptimismMintableERC20.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
/// @title StandardBridgeTester
/// @notice Simple wrapper around the StandardBridge contract that exposes
/// internal functions so they can be more easily tested directly.
contract StandardBridgeTester is StandardBridge {
constructor(
address payable _messenger,
address payable _otherBridge
)
StandardBridge(StandardBridge(_otherBridge))
{ }
function isOptimismMintableERC20(address _token) external view returns (bool) {
return _isOptimismMintableERC20(_token);
}
function isCorrectTokenPair(address _mintableToken, address _otherToken) external view returns (bool) {
return _isCorrectTokenPair(_mintableToken, _otherToken);
}
receive() external payable override { }
}
/// @title LegacyMintable
/// @notice Simple implementation of the legacy OptimismMintableERC20.
contract LegacyMintable is ERC20, ILegacyMintableERC20 {
constructor(string memory _name, string memory _ticker) ERC20(_name, _ticker) { }
function l1Token() external pure returns (address) {
return address(0);
}
function mint(address _to, uint256 _amount) external pure { }
function burn(address _from, uint256 _amount) external pure { }
/// @notice Implements ERC165. This implementation should not be changed as
/// it is how the actual legacy optimism mintable token does the
/// check. Allows for testing against code that is has been deployed,
/// assuming different compiler version is no problem.
function supportsInterface(bytes4 _interfaceId) external pure returns (bool) {
bytes4 firstSupportedInterface = bytes4(keccak256("supportsInterface(bytes4)")); // ERC165
bytes4 secondSupportedInterface = ILegacyMintableERC20.l1Token.selector ^ ILegacyMintableERC20.mint.selector
^ ILegacyMintableERC20.burn.selector;
return _interfaceId == firstSupportedInterface || _interfaceId == secondSupportedInterface;
}
}
/// @title StandardBridge_Stateless_Test
/// @notice Tests internal functions that require no existing state or contract
/// interactions with the messenger.
contract StandardBridge_Stateless_Test is CommonTest {
StandardBridgeTester internal bridge;
OptimismMintableERC20 internal mintable;
ERC20 internal erc20;
LegacyMintable internal legacy;
function setUp() public override {
super.setUp();
bridge = new StandardBridgeTester({
_messenger: payable(address(0)),
_otherBridge: payable(address(0))
});
mintable = new OptimismMintableERC20({
_bridge: address(0),
_remoteToken: address(0),
_name: "Stonks",
_symbol: "STONK",
_decimals: 18
});
erc20 = new ERC20("Altcoin", "ALT");
legacy = new LegacyMintable("Legacy", "LEG");
}
/// @notice Test coverage for identifying OptimismMintableERC20 tokens.
/// This function should return true for both modern and legacy
/// OptimismMintableERC20 tokens and false for any accounts that
/// do not implement the interface.
function test_isOptimismMintableERC20_succeeds() external {
// Both the modern and legacy mintable tokens should return true
assertTrue(bridge.isOptimismMintableERC20(address(mintable)));
assertTrue(bridge.isOptimismMintableERC20(address(legacy)));
// A regular ERC20 should return false
assertFalse(bridge.isOptimismMintableERC20(address(erc20)));
// Non existent contracts should return false and not revert
assertEq(address(0x20).code.length, 0);
assertFalse(bridge.isOptimismMintableERC20(address(0x20)));
}
/// @notice Test coverage of isCorrectTokenPair under different types of
/// tokens.
function test_isCorrectTokenPair_succeeds() external {
// Modern + known to be correct remote token
assertTrue(bridge.isCorrectTokenPair(address(mintable), mintable.remoteToken()));
// Modern + known to be correct l1Token (legacy interface)
assertTrue(bridge.isCorrectTokenPair(address(mintable), mintable.l1Token()));
// Modern + known to be incorrect remote token
assertTrue(mintable.remoteToken() != address(0x20));
assertFalse(bridge.isCorrectTokenPair(address(mintable), address(0x20)));
// Legacy + known to be correct l1Token
assertTrue(bridge.isCorrectTokenPair(address(legacy), legacy.l1Token()));
// Legacy + known to be incorrect l1Token
assertTrue(legacy.l1Token() != address(0x20));
assertFalse(bridge.isCorrectTokenPair(address(legacy), address(0x20)));
// A token that doesn't support either modern or legacy interface
// will revert
vm.expectRevert();
bridge.isCorrectTokenPair(address(erc20), address(1));
}
}