github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/test/universal/StandardBridge.t.sol (about) 1 // SPDX-License-Identifier: MIT 2 pragma solidity 0.8.15; 3 4 import { StandardBridge } from "src/universal/StandardBridge.sol"; 5 import { CommonTest } from "test/setup/CommonTest.sol"; 6 import { OptimismMintableERC20, ILegacyMintableERC20 } from "src/universal/OptimismMintableERC20.sol"; 7 import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 8 9 /// @title StandardBridgeTester 10 /// @notice Simple wrapper around the StandardBridge contract that exposes 11 /// internal functions so they can be more easily tested directly. 12 contract StandardBridgeTester is StandardBridge { 13 constructor() StandardBridge() { } 14 15 function isOptimismMintableERC20(address _token) external view returns (bool) { 16 return _isOptimismMintableERC20(_token); 17 } 18 19 function isCorrectTokenPair(address _mintableToken, address _otherToken) external view returns (bool) { 20 return _isCorrectTokenPair(_mintableToken, _otherToken); 21 } 22 23 receive() external payable override { } 24 } 25 26 /// @title LegacyMintable 27 /// @notice Simple implementation of the legacy OptimismMintableERC20. 28 contract LegacyMintable is ERC20, ILegacyMintableERC20 { 29 constructor(string memory _name, string memory _ticker) ERC20(_name, _ticker) { } 30 31 function l1Token() external pure returns (address) { 32 return address(0); 33 } 34 35 function mint(address _to, uint256 _amount) external pure { } 36 37 function burn(address _from, uint256 _amount) external pure { } 38 39 /// @notice Implements ERC165. This implementation should not be changed as 40 /// it is how the actual legacy optimism mintable token does the 41 /// check. Allows for testing against code that is has been deployed, 42 /// assuming different compiler version is no problem. 43 function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { 44 bytes4 firstSupportedInterface = bytes4(keccak256("supportsInterface(bytes4)")); // ERC165 45 bytes4 secondSupportedInterface = ILegacyMintableERC20.l1Token.selector ^ ILegacyMintableERC20.mint.selector 46 ^ ILegacyMintableERC20.burn.selector; 47 return _interfaceId == firstSupportedInterface || _interfaceId == secondSupportedInterface; 48 } 49 } 50 51 /// @title StandardBridge_Stateless_Test 52 /// @notice Tests internal functions that require no existing state or contract 53 /// interactions with the messenger. 54 contract StandardBridge_Stateless_Test is CommonTest { 55 StandardBridgeTester internal bridge; 56 OptimismMintableERC20 internal mintable; 57 ERC20 internal erc20; 58 LegacyMintable internal legacy; 59 60 function setUp() public override { 61 super.setUp(); 62 63 bridge = new StandardBridgeTester(); 64 65 mintable = new OptimismMintableERC20({ 66 _bridge: address(0), 67 _remoteToken: address(0), 68 _name: "Stonks", 69 _symbol: "STONK", 70 _decimals: 18 71 }); 72 73 erc20 = new ERC20("Altcoin", "ALT"); 74 legacy = new LegacyMintable("Legacy", "LEG"); 75 } 76 77 /// @notice Test coverage for identifying OptimismMintableERC20 tokens. 78 /// This function should return true for both modern and legacy 79 /// OptimismMintableERC20 tokens and false for any accounts that 80 /// do not implement the interface. 81 function test_isOptimismMintableERC20_succeeds() external { 82 // Both the modern and legacy mintable tokens should return true 83 assertTrue(bridge.isOptimismMintableERC20(address(mintable))); 84 assertTrue(bridge.isOptimismMintableERC20(address(legacy))); 85 // A regular ERC20 should return false 86 assertFalse(bridge.isOptimismMintableERC20(address(erc20))); 87 // Non existent contracts should return false and not revert 88 assertEq(address(0x20).code.length, 0); 89 assertFalse(bridge.isOptimismMintableERC20(address(0x20))); 90 } 91 92 /// @notice Test coverage of isCorrectTokenPair under different types of 93 /// tokens. 94 function test_isCorrectTokenPair_succeeds() external { 95 // Modern + known to be correct remote token 96 assertTrue(bridge.isCorrectTokenPair(address(mintable), mintable.remoteToken())); 97 // Modern + known to be correct l1Token (legacy interface) 98 assertTrue(bridge.isCorrectTokenPair(address(mintable), mintable.l1Token())); 99 // Modern + known to be incorrect remote token 100 assertTrue(mintable.remoteToken() != address(0x20)); 101 assertFalse(bridge.isCorrectTokenPair(address(mintable), address(0x20))); 102 // Legacy + known to be correct l1Token 103 assertTrue(bridge.isCorrectTokenPair(address(legacy), legacy.l1Token())); 104 // Legacy + known to be incorrect l1Token 105 assertTrue(legacy.l1Token() != address(0x20)); 106 assertFalse(bridge.isCorrectTokenPair(address(legacy), address(0x20))); 107 // A token that doesn't support either modern or legacy interface 108 // will revert 109 vm.expectRevert(bytes("")); 110 bridge.isCorrectTokenPair(address(erc20), address(1)); 111 } 112 113 /// @notice The bridge by default should be unpaused. 114 function test_paused_succeeds() external { 115 assertFalse(bridge.paused()); 116 } 117 }