Commit e4d687c3 authored by OptimismBot's avatar OptimismBot Committed by GitHub

Merge pull request #7182 from ethereum-optimism/08-09-feat_Add_decimals_to_tokenFactory

feat: configurable decimals to OptimismMintableERC20
parents 1f4eddf2 cbff7042
This diff is collapsed.
This diff is collapsed.
...@@ -292,7 +292,7 @@ LegacyERC20ETH_Test:test_burn_doesNotExist_reverts() (gas: 10637) ...@@ -292,7 +292,7 @@ LegacyERC20ETH_Test:test_burn_doesNotExist_reverts() (gas: 10637)
LegacyERC20ETH_Test:test_crossDomain_succeeds() (gas: 6341) LegacyERC20ETH_Test:test_crossDomain_succeeds() (gas: 6341)
LegacyERC20ETH_Test:test_decreaseAllowance_doesNotExist_reverts() (gas: 10724) LegacyERC20ETH_Test:test_decreaseAllowance_doesNotExist_reverts() (gas: 10724)
LegacyERC20ETH_Test:test_increaseAllowance_doesNotExist_reverts() (gas: 10690) LegacyERC20ETH_Test:test_increaseAllowance_doesNotExist_reverts() (gas: 10690)
LegacyERC20ETH_Test:test_metadata_succeeds() (gas: 15470) LegacyERC20ETH_Test:test_metadata_succeeds() (gas: 15476)
LegacyERC20ETH_Test:test_mint_doesNotExist_reverts() (gas: 10627) LegacyERC20ETH_Test:test_mint_doesNotExist_reverts() (gas: 10627)
LegacyERC20ETH_Test:test_transferFrom_doesNotExist_reverts() (gas: 12957) LegacyERC20ETH_Test:test_transferFrom_doesNotExist_reverts() (gas: 12957)
LegacyERC20ETH_Test:test_transfer_doesNotExist_reverts() (gas: 10755) LegacyERC20ETH_Test:test_transfer_doesNotExist_reverts() (gas: 10755)
...@@ -426,9 +426,10 @@ OptimismMintableERC721_Test:test_safeMint_succeeds() (gas: 140547) ...@@ -426,9 +426,10 @@ OptimismMintableERC721_Test:test_safeMint_succeeds() (gas: 140547)
OptimismMintableERC721_Test:test_supportsInterfaces_succeeds() (gas: 9005) OptimismMintableERC721_Test:test_supportsInterfaces_succeeds() (gas: 9005)
OptimismMintableERC721_Test:test_tokenURI_succeeds() (gas: 163441) OptimismMintableERC721_Test:test_tokenURI_succeeds() (gas: 163441)
OptimismMintableTokenFactory_Test:test_bridge_succeeds() (gas: 9760) OptimismMintableTokenFactory_Test:test_bridge_succeeds() (gas: 9760)
OptimismMintableTokenFactory_Test:test_createStandardL2Token_remoteIsZero_reverts() (gas: 9471) OptimismMintableTokenFactory_Test:test_createStandardL2TokenWithDecimals_succeeds() (gas: 1304000)
OptimismMintableTokenFactory_Test:test_createStandardL2Token_sameTwice_reverts() (gas: 8937393460516769105) OptimismMintableTokenFactory_Test:test_createStandardL2Token_remoteIsZero_reverts() (gas: 9570)
OptimismMintableTokenFactory_Test:test_createStandardL2Token_succeeds() (gas: 1295838) OptimismMintableTokenFactory_Test:test_createStandardL2Token_sameTwice_reverts() (gas: 8937393460516769330)
OptimismMintableTokenFactory_Test:test_createStandardL2Token_succeeds() (gas: 1303990)
OptimismPortalUpgradeable_Test:test_initialize_cannotInitImpl_reverts() (gas: 11178) OptimismPortalUpgradeable_Test:test_initialize_cannotInitImpl_reverts() (gas: 11178)
OptimismPortalUpgradeable_Test:test_initialize_cannotInitProxy_reverts() (gas: 16111) OptimismPortalUpgradeable_Test:test_initialize_cannotInitProxy_reverts() (gas: 16111)
OptimismPortalUpgradeable_Test:test_params_initValuesOnProxy_succeeds() (gas: 26781) OptimismPortalUpgradeable_Test:test_params_initValuesOnProxy_succeeds() (gas: 26781)
......
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
"src/periphery/op-nft/Optimist.sol": "0x38407f766aa9d394403e9da388dd0265b48901789f3e8a28af50014f9f5251d9", "src/periphery/op-nft/Optimist.sol": "0x38407f766aa9d394403e9da388dd0265b48901789f3e8a28af50014f9f5251d9",
"src/periphery/op-nft/OptimistAllowlist.sol": "0x53e9a9dfecbae036fd468e8f34c80c7d9c35bd8908c8a6483db44dbc5128ad69", "src/periphery/op-nft/OptimistAllowlist.sol": "0x53e9a9dfecbae036fd468e8f34c80c7d9c35bd8908c8a6483db44dbc5128ad69",
"src/periphery/op-nft/OptimistInviter.sol": "0xfdd5b9d45205ef9372ba37f7a6394724695e676d27a47cb154ee6e4148490013", "src/periphery/op-nft/OptimistInviter.sol": "0xfdd5b9d45205ef9372ba37f7a6394724695e676d27a47cb154ee6e4148490013",
"src/universal/OptimismMintableERC20.sol": "0xa0b4f168802d0f9eca9ddc54347ca66c34ad7aa0fd84b01e0d7e99a9f86f46d6", "src/universal/OptimismMintableERC20.sol": "0x17fe6e955dc7e9e480e57bc62c227206838b204dcb660b8cb8f6f217319a22ba",
"src/universal/OptimismMintableERC20Factory.sol": "0xf4beb7fed4defc3e70b2298831bf0024cceaa8f1cf55fd98c00f5998b8ab5589", "src/universal/OptimismMintableERC20Factory.sol": "0xa8b1781116fd296a2630b94e4e18724b64094a70e2e716cb4c5bf5a8dbe32889",
"src/universal/OptimismMintableERC721.sol": "0x49dc863caf3e002bf0c90b3af3873990fb282771f4c63735fd61a885b7873983", "src/universal/OptimismMintableERC721.sol": "0x49dc863caf3e002bf0c90b3af3873990fb282771f4c63735fd61a885b7873983",
"src/universal/OptimismMintableERC721Factory.sol": "0x502438b009bfaf0ab187914662468261f10446fd85d44a79b29cdaef7b4982ba" "src/universal/OptimismMintableERC721Factory.sol": "0x502438b009bfaf0ab187914662468261f10446fd85d44a79b29cdaef7b4982ba"
} }
\ No newline at end of file
...@@ -14,7 +14,7 @@ import { OptimismMintableERC20 } from "../universal/OptimismMintableERC20.sol"; ...@@ -14,7 +14,7 @@ import { OptimismMintableERC20 } from "../universal/OptimismMintableERC20.sol";
/// disabled as part of the EVM equivalence upgrade. /// disabled as part of the EVM equivalence upgrade.
contract LegacyERC20ETH is OptimismMintableERC20 { contract LegacyERC20ETH is OptimismMintableERC20 {
/// @notice Initializes the contract as an Optimism Mintable ERC20. /// @notice Initializes the contract as an Optimism Mintable ERC20.
constructor() OptimismMintableERC20(Predeploys.L2_STANDARD_BRIDGE, address(0), "Ether", "ETH") { } constructor() OptimismMintableERC20(Predeploys.L2_STANDARD_BRIDGE, address(0), "Ether", "ETH", 18) { }
/// @notice Returns the ETH balance of the target account. Overrides the base behavior of the /// @notice Returns the ETH balance of the target account. Overrides the base behavior of the
/// contract to preserve the invariant that the balance within this contract always /// contract to preserve the invariant that the balance within this contract always
......
...@@ -19,6 +19,9 @@ contract OptimismMintableERC20 is IOptimismMintableERC20, ILegacyMintableERC20, ...@@ -19,6 +19,9 @@ contract OptimismMintableERC20 is IOptimismMintableERC20, ILegacyMintableERC20,
/// @notice Address of the StandardBridge on this network. /// @notice Address of the StandardBridge on this network.
address public immutable BRIDGE; address public immutable BRIDGE;
/// @notice Decimals of the token
uint8 private immutable DECIMALS;
/// @notice Emitted whenever tokens are minted for an account. /// @notice Emitted whenever tokens are minted for an account.
/// @param account Address of the account tokens are being minted for. /// @param account Address of the account tokens are being minted for.
/// @param amount Amount of tokens minted. /// @param amount Amount of tokens minted.
...@@ -35,7 +38,7 @@ contract OptimismMintableERC20 is IOptimismMintableERC20, ILegacyMintableERC20, ...@@ -35,7 +38,7 @@ contract OptimismMintableERC20 is IOptimismMintableERC20, ILegacyMintableERC20,
_; _;
} }
/// @custom:semver 1.1.0 /// @custom:semver 1.2.0
/// @param _bridge Address of the L2 standard bridge. /// @param _bridge Address of the L2 standard bridge.
/// @param _remoteToken Address of the corresponding L1 token. /// @param _remoteToken Address of the corresponding L1 token.
/// @param _name ERC20 name. /// @param _name ERC20 name.
...@@ -44,13 +47,15 @@ contract OptimismMintableERC20 is IOptimismMintableERC20, ILegacyMintableERC20, ...@@ -44,13 +47,15 @@ contract OptimismMintableERC20 is IOptimismMintableERC20, ILegacyMintableERC20,
address _bridge, address _bridge,
address _remoteToken, address _remoteToken,
string memory _name, string memory _name,
string memory _symbol string memory _symbol,
uint8 _decimals
) )
ERC20(_name, _symbol) ERC20(_name, _symbol)
Semver(1, 1, 0) Semver(1, 2, 0)
{ {
REMOTE_TOKEN = _remoteToken; REMOTE_TOKEN = _remoteToken;
BRIDGE = _bridge; BRIDGE = _bridge;
DECIMALS = _decimals;
} }
/// @notice Allows the StandardBridge on this network to mint tokens. /// @notice Allows the StandardBridge on this network to mint tokens.
...@@ -120,4 +125,14 @@ contract OptimismMintableERC20 is IOptimismMintableERC20, ILegacyMintableERC20, ...@@ -120,4 +125,14 @@ contract OptimismMintableERC20 is IOptimismMintableERC20, ILegacyMintableERC20,
function bridge() public view returns (address) { function bridge() public view returns (address) {
return BRIDGE; 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;
}
} }
...@@ -30,11 +30,11 @@ contract OptimismMintableERC20Factory is Semver, Initializable { ...@@ -30,11 +30,11 @@ contract OptimismMintableERC20Factory is Semver, Initializable {
/// @param deployer Address of the account that deployed the token. /// @param deployer Address of the account that deployed the token.
event OptimismMintableERC20Created(address indexed localToken, address indexed remoteToken, address deployer); event OptimismMintableERC20Created(address indexed localToken, address indexed remoteToken, address deployer);
/// @custom:semver 1.3.0 /// @custom:semver 1.4.0
/// @notice The semver MUST be bumped any time that there is a change in /// @notice The semver MUST be bumped any time that there is a change in
/// the OptimismMintableERC20 token contract since this contract /// the OptimismMintableERC20 token contract since this contract
/// is responsible for deploying OptimismMintableERC20 contracts. /// is responsible for deploying OptimismMintableERC20 contracts.
constructor() Semver(1, 3, 0) { constructor() Semver(1, 4, 0) {
initialize({ _bridge: address(0) }); initialize({ _bridge: address(0) });
} }
...@@ -81,11 +81,30 @@ contract OptimismMintableERC20Factory is Semver, Initializable { ...@@ -81,11 +81,30 @@ contract OptimismMintableERC20Factory is Semver, Initializable {
) )
public public
returns (address) returns (address)
{
return createOptimismMintableERC20WithDecimals(_remoteToken, _name, _symbol, 18);
}
/// @notice Creates an instance of the OptimismMintableERC20 contract, with specified decimals.
/// @param _remoteToken Address of the token on the remote chain.
/// @param _name ERC20 name.
/// @param _symbol ERC20 symbol.
/// @param _decimals ERC20 decimals
/// @return Address of the newly created token.
function createOptimismMintableERC20WithDecimals(
address _remoteToken,
string memory _name,
string memory _symbol,
uint8 _decimals
)
public
returns (address)
{ {
require(_remoteToken != address(0), "OptimismMintableERC20Factory: must provide remote token address"); require(_remoteToken != address(0), "OptimismMintableERC20Factory: must provide remote token address");
bytes32 salt = keccak256(abi.encode(_remoteToken, _name, _symbol)); bytes32 salt = keccak256(abi.encode(_remoteToken, _name, _symbol));
address localToken = address(new OptimismMintableERC20{salt: salt}(bridge, _remoteToken, _name, _symbol)); address localToken =
address(new OptimismMintableERC20{salt: salt}(bridge, _remoteToken, _name, _symbol, _decimals));
// Emit the old event too for legacy support. // Emit the old event too for legacy support.
emit StandardL2TokenCreated(_remoteToken, localToken); emit StandardL2TokenCreated(_remoteToken, localToken);
......
...@@ -18,7 +18,9 @@ contract OptimismMintableTokenFactory_Test is Bridge_Initializer { ...@@ -18,7 +18,9 @@ contract OptimismMintableTokenFactory_Test is Bridge_Initializer {
function test_createStandardL2Token_succeeds() external { function test_createStandardL2Token_succeeds() external {
address remote = address(4); address remote = address(4);
address local = calculateTokenAddress(remote, "Beep", "BOOP");
// Defaults to 18 decimals
address local = calculateTokenAddress(remote, "Beep", "BOOP", 18);
vm.expectEmit(true, true, true, true); vm.expectEmit(true, true, true, true);
emit StandardL2TokenCreated(remote, local); emit StandardL2TokenCreated(remote, local);
...@@ -27,7 +29,26 @@ contract OptimismMintableTokenFactory_Test is Bridge_Initializer { ...@@ -27,7 +29,26 @@ contract OptimismMintableTokenFactory_Test is Bridge_Initializer {
emit OptimismMintableERC20Created(local, remote, alice); emit OptimismMintableERC20Created(local, remote, alice);
vm.prank(alice); vm.prank(alice);
L2TokenFactory.createStandardL2Token(remote, "Beep", "BOOP"); address addr = L2TokenFactory.createStandardL2Token(remote, "Beep", "BOOP");
assertTrue(addr == local);
assertTrue(OptimismMintableERC20(local).decimals() == 18);
}
function test_createStandardL2TokenWithDecimals_succeeds() external {
address remote = address(4);
address local = calculateTokenAddress(remote, "Beep", "BOOP", 6);
vm.expectEmit(true, true, true, true);
emit StandardL2TokenCreated(remote, local);
vm.expectEmit(true, true, true, true);
emit OptimismMintableERC20Created(local, remote, alice);
vm.prank(alice);
address addr = L2TokenFactory.createOptimismMintableERC20WithDecimals(remote, "Beep", "BOOP", 6);
assertTrue(addr == local);
assertTrue(OptimismMintableERC20(local).decimals() == 6);
} }
function test_createStandardL2Token_sameTwice_reverts() external { function test_createStandardL2Token_sameTwice_reverts() external {
...@@ -51,13 +72,14 @@ contract OptimismMintableTokenFactory_Test is Bridge_Initializer { ...@@ -51,13 +72,14 @@ contract OptimismMintableTokenFactory_Test is Bridge_Initializer {
function calculateTokenAddress( function calculateTokenAddress(
address _remote, address _remote,
string memory _name, string memory _name,
string memory _symbol string memory _symbol,
uint8 _decimals
) )
internal internal
view view
returns (address) returns (address)
{ {
bytes memory constructorArgs = abi.encode(address(L2Bridge), _remote, _name, _symbol); bytes memory constructorArgs = abi.encode(address(L2Bridge), _remote, _name, _symbol, _decimals);
bytes memory bytecode = abi.encodePacked(type(OptimismMintableERC20).creationCode, constructorArgs); bytes memory bytecode = abi.encodePacked(type(OptimismMintableERC20).creationCode, constructorArgs);
bytes32 salt = keccak256(abi.encode(_remote, _name, _symbol)); bytes32 salt = keccak256(abi.encode(_remote, _name, _symbol));
bytes32 hash = keccak256(abi.encodePacked(bytes1(0xff), address(L2TokenFactory), salt, keccak256(bytecode))); bytes32 hash = keccak256(abi.encodePacked(bytes1(0xff), address(L2TokenFactory), salt, keccak256(bytecode)));
......
...@@ -74,7 +74,8 @@ contract StandardBridge_Stateless_Test is CommonTest { ...@@ -74,7 +74,8 @@ contract StandardBridge_Stateless_Test is CommonTest {
_bridge: address(0), _bridge: address(0),
_remoteToken: address(0), _remoteToken: address(0),
_name: "Stonks", _name: "Stonks",
_symbol: "STONK" _symbol: "STONK",
_decimals: 18
}); });
erc20 = new ERC20("Altcoin", "ALT"); erc20 = new ERC20("Altcoin", "ALT");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment