-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
DEMO predict an (optimism) L2 token address when deployed by factory
Signed-off-by: stadolf <[email protected]>
- Loading branch information
1 parent
b115841
commit 92a82ea
Showing
4 changed files
with
222 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; | ||
|
||
/// @title IOptimismMintableERC20 | ||
/// @notice This interface is available on the OptimismMintableERC20 contract. | ||
/// We declare it as a separate interface so that it can be used in | ||
/// custom implementations of OptimismMintableERC20. | ||
interface IOptimismMintableERC20 is IERC165 { | ||
function remoteToken() external view returns (address); | ||
|
||
function bridge() external returns (address); | ||
|
||
function mint(address _to, uint256 _amount) external; | ||
|
||
function burn(address _from, uint256 _amount) external; | ||
} | ||
|
||
/// @custom:legacy | ||
/// @title ILegacyMintableERC20 | ||
/// @notice This interface was available on the legacy L2StandardERC20 contract. | ||
/// It remains available on the OptimismMintableERC20 contract for | ||
/// backwards compatibility. | ||
interface ILegacyMintableERC20 is IERC165 { | ||
function l1Token() external view returns (address); | ||
|
||
function mint(address _to, uint256 _amount) external; | ||
|
||
function burn(address _from, uint256 _amount) external; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.15; | ||
|
||
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; | ||
import { ILegacyMintableERC20, IOptimismMintableERC20 } from "./IOptimismMintableERC20.sol"; | ||
import { Semver } from "./Semver.sol"; | ||
|
||
/// @title OptimismMintableERC20 | ||
/// @notice OptimismMintableERC20 is a standard extension of the base ERC20 token contract designed | ||
/// to allow the StandardBridge contracts to mint and burn tokens. This makes it possible to | ||
/// use an OptimismMintablERC20 as the L2 representation of an L1 token, or vice-versa. | ||
/// Designed to be backwards compatible with the older StandardL2ERC20 token which was only | ||
/// meant for use on L2. | ||
contract OptimismMintableERC20 is IOptimismMintableERC20, ILegacyMintableERC20, ERC20, Semver { | ||
/// @notice Address of the corresponding version of this token on the remote chain. | ||
address public immutable REMOTE_TOKEN; | ||
|
||
/// @notice Address of the StandardBridge on this network. | ||
address public immutable BRIDGE; | ||
|
||
/// @notice Decimals of the token | ||
uint8 private immutable DECIMALS; | ||
|
||
/// @notice Emitted whenever tokens are minted for an account. | ||
/// @param account Address of the account tokens are being minted for. | ||
/// @param amount Amount of tokens minted. | ||
event Mint(address indexed account, uint256 amount); | ||
|
||
/// @notice Emitted whenever tokens are burned from an account. | ||
/// @param account Address of the account tokens are being burned from. | ||
/// @param amount Amount of tokens burned. | ||
event Burn(address indexed account, uint256 amount); | ||
|
||
/// @notice A modifier that only allows the bridge to call | ||
modifier onlyBridge() { | ||
require(msg.sender == BRIDGE, "OptimismMintableERC20: only bridge can mint and burn"); | ||
_; | ||
} | ||
|
||
/// @custom:semver 1.2.0 | ||
/// @param _bridge Address of the L2 standard bridge. | ||
/// @param _remoteToken Address of the corresponding L1 token. | ||
/// @param _name ERC20 name. | ||
/// @param _symbol ERC20 symbol. | ||
constructor(address _bridge, address _remoteToken, string memory _name, string memory _symbol, uint8 _decimals) | ||
ERC20(_name, _symbol) | ||
Semver(1, 2, 0) | ||
{ | ||
REMOTE_TOKEN = _remoteToken; | ||
BRIDGE = _bridge; | ||
DECIMALS = _decimals; | ||
} | ||
|
||
/// @notice Allows the StandardBridge on this network to mint tokens. | ||
/// @param _to Address to mint tokens to. | ||
/// @param _amount Amount of tokens to mint. | ||
function mint(address _to, uint256 _amount) external virtual override(IOptimismMintableERC20, ILegacyMintableERC20) onlyBridge { | ||
_mint(_to, _amount); | ||
emit Mint(_to, _amount); | ||
} | ||
|
||
/// @notice Allows the StandardBridge on this network to burn tokens. | ||
/// @param _from Address to burn tokens from. | ||
/// @param _amount Amount of tokens to burn. | ||
function burn(address _from, uint256 _amount) external virtual override(IOptimismMintableERC20, ILegacyMintableERC20) onlyBridge { | ||
_burn(_from, _amount); | ||
emit Burn(_from, _amount); | ||
} | ||
|
||
/// @notice ERC165 interface check function. | ||
/// @param _interfaceId Interface ID to check. | ||
/// @return Whether or not the interface is supported by this contract. | ||
function supportsInterface(bytes4 _interfaceId) external pure virtual returns (bool) { | ||
bytes4 iface1 = type(IERC165).interfaceId; | ||
// Interface corresponding to the legacy L2StandardERC20. | ||
bytes4 iface2 = type(ILegacyMintableERC20).interfaceId; | ||
// Interface corresponding to the updated OptimismMintableERC20 (this contract). | ||
bytes4 iface3 = type(IOptimismMintableERC20).interfaceId; | ||
return _interfaceId == iface1 || _interfaceId == iface2 || _interfaceId == iface3; | ||
} | ||
|
||
/// @custom:legacy | ||
/// @notice Legacy getter for the remote token. Use REMOTE_TOKEN going forward. | ||
function l1Token() public view returns (address) { | ||
return REMOTE_TOKEN; | ||
} | ||
|
||
/// @custom:legacy | ||
/// @notice Legacy getter for the bridge. Use BRIDGE going forward. | ||
function l2Bridge() public view returns (address) { | ||
return BRIDGE; | ||
} | ||
|
||
/// @custom:legacy | ||
/// @notice Legacy getter for REMOTE_TOKEN. | ||
function remoteToken() public view returns (address) { | ||
return REMOTE_TOKEN; | ||
} | ||
|
||
/// @custom:legacy | ||
/// @notice Legacy getter for BRIDGE. | ||
function bridge() public view returns (address) { | ||
return BRIDGE; | ||
} | ||
|
||
/// @dev Returns the number of decimals used to get its user representation. | ||
/// For example, if `decimals` equals `2`, a balance of `505` tokens should | ||
/// be displayed to a user as `5.05` (`505 / 10 ** 2`). | ||
/// NOTE: This information is only used for _display_ purposes: it in | ||
/// no way affects any of the arithmetic of the contract, including | ||
/// {IERC20-balanceOf} and {IERC20-transfer}. | ||
function decimals() public view override returns (uint8) { | ||
return DECIMALS; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; | ||
|
||
/// @title Semver | ||
/// @notice Semver is a simple contract for managing contract versions. | ||
contract Semver { | ||
/// @notice Contract version number (major). | ||
uint256 private immutable MAJOR_VERSION; | ||
|
||
/// @notice Contract version number (minor). | ||
uint256 private immutable MINOR_VERSION; | ||
|
||
/// @notice Contract version number (patch). | ||
uint256 private immutable PATCH_VERSION; | ||
|
||
/// @param _major Version number (major). | ||
/// @param _minor Version number (minor). | ||
/// @param _patch Version number (patch). | ||
constructor(uint256 _major, uint256 _minor, uint256 _patch) { | ||
MAJOR_VERSION = _major; | ||
MINOR_VERSION = _minor; | ||
PATCH_VERSION = _patch; | ||
} | ||
|
||
/// @notice Returns the full semver contract version. | ||
/// @return Semver contract version as a string. | ||
function version() public view returns (string memory) { | ||
return string(abi.encodePacked(Strings.toString(MAJOR_VERSION), ".", Strings.toString(MINOR_VERSION), ".", Strings.toString(PATCH_VERSION))); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.18; | ||
|
||
import "forge-std/Test.sol"; | ||
import "forge-std/console.sol"; | ||
import { OptimismMintableERC20 } from "../src/Optimism/OptimismMintableERC20.sol"; | ||
|
||
contract DeterministicTokenL2 is Test { | ||
bytes creationCode = | ||
hex"6101406040523480156200001257600080fd5b506040516200144d3803806200144d833981016040819052620000359162000170565b600160026000858560036200004b8382620002ab565b5060046200005a8282620002ab565b50505060809290925260a05260c0526001600160a01b0393841660e0529390921661010052505060ff166101205262000377565b80516001600160a01b0381168114620000a657600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620000d357600080fd5b81516001600160401b0380821115620000f057620000f0620000ab565b604051601f8301601f19908116603f011681019082821181831017156200011b576200011b620000ab565b816040528381526020925086838588010111156200013857600080fd5b600091505b838210156200015c57858201830151818301840152908201906200013d565b600093810190920192909252949350505050565b600080600080600060a086880312156200018957600080fd5b62000194866200008e565b9450620001a4602087016200008e565b60408701519094506001600160401b0380821115620001c257600080fd5b620001d089838a01620000c1565b94506060880151915080821115620001e757600080fd5b50620001f688828901620000c1565b925050608086015160ff811681146200020e57600080fd5b809150509295509295909350565b600181811c908216806200023157607f821691505b6020821081036200025257634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620002a657600081815260208120601f850160051c81016020861015620002815750805b601f850160051c820191505b81811015620002a2578281556001016200028d565b5050505b505050565b81516001600160401b03811115620002c757620002c7620000ab565b620002df81620002d884546200021c565b8462000258565b602080601f831160018114620003175760008415620002fe5750858301515b600019600386901b1c1916600185901b178555620002a2565b600085815260208120601f198616915b82811015620003485788860151825594840194600190910190840162000327565b5085821015620003675787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e051610100516101205161106a620003e360003960006101f70152600081816102bd0152818161031f0152818161049c01526105f001526000818161016901526102e30152600061058c015260006105630152600061053a015261106a6000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c806370a08231116100b8578063ae1f6aaf1161007c578063ae1f6aaf146102bb578063c01e1bd6146102e1578063d6c0b2c4146102e1578063dd62ed3e14610307578063e78cea92146102bb578063ee9a31a21461031a57600080fd5b806370a082311461025157806395d89b411461027a5780639dc29fac14610282578063a457c2d714610295578063a9059cbb146102a857600080fd5b806323b872dd116100ff57806323b872dd146101dd578063313ce567146101f0578063395093511461022157806340c10f191461023457806354fd4d501461024957600080fd5b806301ffc9a71461013c578063033964be1461016457806306fdde03146101a3578063095ea7b3146101b857806318160ddd146101cb575b600080fd5b61014f61014a366004610dbd565b610341565b60405190151581526020015b60405180910390f35b61018b7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161015b565b6101ab61039f565b60405161015b9190610e12565b61014f6101c6366004610e61565b610431565b6002545b60405190815260200161015b565b61014f6101eb366004610e8b565b61044b565b60405160ff7f000000000000000000000000000000000000000000000000000000000000000016815260200161015b565b61014f61022f366004610e61565b61046f565b610247610242366004610e61565b610491565b005b6101ab610533565b6101cf61025f366004610ec7565b6001600160a01b031660009081526020819052604090205490565b6101ab6105d6565b610247610290366004610e61565b6105e5565b61014f6102a3366004610e61565b610672565b61014f6102b6366004610e61565b6106ed565b7f000000000000000000000000000000000000000000000000000000000000000061018b565b7f000000000000000000000000000000000000000000000000000000000000000061018b565b6101cf610315366004610ee2565b6106fb565b61018b7f000000000000000000000000000000000000000000000000000000000000000081565b60006301ffc9a760e01b631d1d8b6360e01b63ec4fc8e360e01b6001600160e01b0319851683148061037f57506001600160e01b0319858116908316145b8061039657506001600160e01b0319858116908216145b95945050505050565b6060600380546103ae90610f15565b80601f01602080910402602001604051908101604052809291908181526020018280546103da90610f15565b80156104275780601f106103fc57610100808354040283529160200191610427565b820191906000526020600020905b81548152906001019060200180831161040a57829003601f168201915b5050505050905090565b60003361043f818585610726565b60019150505b92915050565b60003361045985828561084b565b6104648585856108c5565b506001949350505050565b60003361043f81858561048283836106fb565b61048c9190610f4f565b610726565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146104e25760405162461bcd60e51b81526004016104d990610f70565b60405180910390fd5b6104ec8282610a69565b816001600160a01b03167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968858260405161052791815260200190565b60405180910390a25050565b606061055e7f0000000000000000000000000000000000000000000000000000000000000000610b28565b6105877f0000000000000000000000000000000000000000000000000000000000000000610b28565b6105b07f0000000000000000000000000000000000000000000000000000000000000000610b28565b6040516020016105c293929190610fc4565b604051602081830303815290604052905090565b6060600480546103ae90610f15565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461062d5760405162461bcd60e51b81526004016104d990610f70565b6106378282610bbb565b816001600160a01b03167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca58260405161052791815260200190565b6000338161068082866106fb565b9050838110156106e05760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016104d9565b6104648286868403610726565b60003361043f8185856108c5565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166107885760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016104d9565b6001600160a01b0382166107e95760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016104d9565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b600061085784846106fb565b905060001981146108bf57818110156108b25760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016104d9565b6108bf8484848403610726565b50505050565b6001600160a01b0383166109295760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016104d9565b6001600160a01b03821661098b5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016104d9565b6001600160a01b03831660009081526020819052604090205481811015610a035760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016104d9565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36108bf565b6001600160a01b038216610abf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016104d9565b8060026000828254610ad19190610f4f565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b60606000610b3583610ce5565b600101905060008167ffffffffffffffff811115610b5557610b5561101e565b6040519080825280601f01601f191660200182016040528015610b7f576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084610b8957509392505050565b6001600160a01b038216610c1b5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016104d9565b6001600160a01b03821660009081526020819052604090205481811015610c8f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016104d9565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910161083e565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310610d245772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310610d50576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310610d6e57662386f26fc10000830492506010015b6305f5e1008310610d86576305f5e100830492506008015b6127108310610d9a57612710830492506004015b60648310610dac576064830492506002015b600a83106104455760010192915050565b600060208284031215610dcf57600080fd5b81356001600160e01b031981168114610de757600080fd5b9392505050565b60005b83811015610e09578181015183820152602001610df1565b50506000910152565b6020815260008251806020840152610e31816040850160208701610dee565b601f01601f19169190910160400192915050565b80356001600160a01b0381168114610e5c57600080fd5b919050565b60008060408385031215610e7457600080fd5b610e7d83610e45565b946020939093013593505050565b600080600060608486031215610ea057600080fd5b610ea984610e45565b9250610eb760208501610e45565b9150604084013590509250925092565b600060208284031215610ed957600080fd5b610de782610e45565b60008060408385031215610ef557600080fd5b610efe83610e45565b9150610f0c60208401610e45565b90509250929050565b600181811c90821680610f2957607f821691505b602082108103610f4957634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561044557634e487b7160e01b600052601160045260246000fd5b60208082526034908201527f4f7074696d69736d4d696e7461626c6545524332303a206f6e6c79206272696460408201527333b29031b0b71036b4b73a1030b73210313ab93760611b606082015260800190565b60008451610fd6818460208901610dee565b8083019050601760f91b8082528551610ff6816001850160208a01610dee565b60019201918201528351611011816002840160208801610dee565b0160020195945050505050565b634e487b7160e01b600052604160045260246000fdfea2646970667358221220dfbd177392afbdbd8cbdcd64a92c69f67012b5bf0e778570c71cd97c362379c864736f6c63430008120033"; | ||
|
||
function setUp() public { } | ||
|
||
function testInitCode() public { | ||
address tokenFactory = 0x4200000000000000000000000000000000000012; | ||
address bridge = 0x4200000000000000000000000000000000000010; | ||
address remoteToken = 0xDa8Df672aCfa4Ee1be95FBC1c2e0FA97d49F7BDe; | ||
|
||
string memory name = "IP Tokens of IPNFT #42"; | ||
string memory symbol = "CYCL-01"; | ||
|
||
bytes32 salt = keccak256(abi.encode(remoteToken, name, symbol)); | ||
assertEq(creationCode, type(OptimismMintableERC20).creationCode); | ||
|
||
address predictedAddress = address( | ||
uint160( | ||
uint256( | ||
keccak256( | ||
abi.encodePacked( | ||
bytes1(0xff), | ||
tokenFactory, | ||
salt, | ||
keccak256(abi.encodePacked(type(OptimismMintableERC20).creationCode, abi.encode(bridge, remoteToken, name, symbol, 18))) | ||
) | ||
) | ||
) | ||
) | ||
); | ||
vm.startPrank(tokenFactory); | ||
OptimismMintableERC20 token = new OptimismMintableERC20{ salt: salt }(bridge, remoteToken, name, symbol, 18); | ||
assertEq(address(token), predictedAddress); | ||
} | ||
} |