Skip to content

Commit

Permalink
DEMO predict an (optimism) L2 token address when deployed by factory
Browse files Browse the repository at this point in the history
Signed-off-by: stadolf <[email protected]>
  • Loading branch information
elmariachi111 committed Jul 12, 2024
1 parent b115841 commit 92a82ea
Show file tree
Hide file tree
Showing 4 changed files with 222 additions and 0 deletions.
31 changes: 31 additions & 0 deletions src/Optimism/IOptimismMintableERC20.sol
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;
}
116 changes: 116 additions & 0 deletions src/Optimism/OptimismMintableERC20.sol
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;
}
}
32 changes: 32 additions & 0 deletions src/Optimism/Semver.sol
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)));
}
}
43 changes: 43 additions & 0 deletions test/DeterministicTokenL2.t.sol
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);
}
}

0 comments on commit 92a82ea

Please sign in to comment.