diff --git a/script/DeployBase.sol b/script/DeployBase.sol index 5f73575a..367bba0b 100644 --- a/script/DeployBase.sol +++ b/script/DeployBase.sol @@ -17,7 +17,7 @@ contract DeployBase { */ function deploy(address registrar_, address migrationAdmin_) public virtual returns (address implementation_, address proxy_) { implementation_ = address(new MToken(registrar_, migrationAdmin_)); - proxy_ = address(new ERC1967Proxy(implementation_, abi.encodeCall(MToken.initialize, ()))); + proxy_ = address(new ERC1967Proxy(implementation_, abi.encodeCall(MToken.initialize, ("M by M0", "M")))); } function _getExpectedMTokenImplementation( diff --git a/src/MToken.sol b/src/MToken.sol index a2ca6f54..00ac29c6 100644 --- a/src/MToken.sol +++ b/src/MToken.sol @@ -5,6 +5,7 @@ pragma solidity 0.8.26; import { ERC20Extended } from "../lib/common/src/ERC20Extended.sol"; import { UIntMath } from "../lib/common/src/libs/UIntMath.sol"; import { Migratable } from "../lib/common/src/Migratable.sol"; +import { Bytes32String } from "../lib/common/src/libs/Bytes32String.sol"; import { IERC20 } from "../lib/common/src/interfaces/IERC20.sol"; @@ -16,12 +17,29 @@ import { IMToken } from "./interfaces/IMToken.sol"; import { ContinuousIndexing } from "./abstract/ContinuousIndexing.sol"; import { ContinuousIndexingMath } from "./libs/ContinuousIndexingMath.sol"; +abstract contract MTokenStorageLayout { + /// @custom:storage-location erc7201:m0.storage.MToken + struct MTokenStorage { + bytes32 name; + bytes32 symbol; + } + + // keccak256(abi.encode(uint256(keccak256("m0.storage.MToken")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant _M_TOKEN_STORAGE_SLOT = 0xeb521740570240fc3b71275bd090460409d92adf7cec95ba2df10066ee73c700; + + function _getMTokenStorage() internal pure returns (MTokenStorage storage $) { + assembly { + $.slot := _M_TOKEN_STORAGE_SLOT + } + } +} + /** * @title MToken - * @author M^0 Labs + * @author M0 Labs * @notice ERC20 M Token living on other chains. */ -contract MToken is IMToken, ContinuousIndexing, ERC20Extended, Migratable { +contract MToken is IMToken, ContinuousIndexing, ERC20Extended, Migratable, MTokenStorageLayout { /* ============ Structs ============ */ /** @@ -70,9 +88,9 @@ contract MToken is IMToken, ContinuousIndexing, ERC20Extended, Migratable { * @param registrar_ The address of the Registrar contract. * @param migrationAdmin_ The address of a migration admin. */ - constructor(address registrar_, address migrationAdmin_) ContinuousIndexing() ERC20Extended("M by M^0", "M", 6) { + constructor(address registrar_, address migrationAdmin_) ContinuousIndexing() ERC20Extended("M by M0", "M", 6) { _disableInitializers(); - + if ((registrar = registrar_) == address(0)) revert ZeroRegistrar(); if ((portal = RegistrarReader.getPortal(registrar_)) == address(0)) revert ZeroPortal(); if ((migrationAdmin = migrationAdmin_) == address(0)) revert ZeroMigrationAdmin(); @@ -81,8 +99,13 @@ contract MToken is IMToken, ContinuousIndexing, ERC20Extended, Migratable { /* ============ Initializer ============ */ /// @inheritdoc IMToken - function initialize() external initializer { + function initialize(string memory name_, string memory symbol_) external initializer { _initialize(); + + MTokenStorage storage $ = _getMTokenStorage(); + + $.name = Bytes32String.toBytes32(name_); + $.symbol = Bytes32String.toBytes32(symbol_); } /* ============ Interactive Functions ============ */ @@ -138,6 +161,15 @@ contract MToken is IMToken, ContinuousIndexing, ERC20Extended, Migratable { } /* ============ View/Pure Functions ============ */ + /// @inheritdoc IERC20 + function name() external view override(IERC20, ERC20Extended) returns (string memory name_) { + return Bytes32String.toString(_getMTokenStorage().name); + } + + /// @inheritdoc IERC20 + function symbol() external view override(IERC20, ERC20Extended) returns (string memory symbol_) { + return Bytes32String.toString(_getMTokenStorage().symbol); + } /// @inheritdoc IMToken function totalEarningSupply() public view returns (uint240 totalEarningSupply_) { diff --git a/src/interfaces/IMToken.sol b/src/interfaces/IMToken.sol index eaccee32..eabfa9f3 100644 --- a/src/interfaces/IMToken.sol +++ b/src/interfaces/IMToken.sol @@ -108,8 +108,12 @@ interface IMToken is IContinuousIndexing, IERC20Extended { */ function stopEarning(address account) external; - /// @notice Initializes the Proxy's storage. - function initialize() external; + /** + * @notice Initializes the Proxy's storage. + * @param name The name of the token. + * @param symbol The symbol of the token. + */ + function initialize(string memory name, string memory symbol) external; /** * @notice Performs an arbitrarily defined migration. diff --git a/test/MToken.t.sol b/test/MToken.t.sol index 892e0aaa..df218bab 100644 --- a/test/MToken.t.sol +++ b/test/MToken.t.sol @@ -44,7 +44,7 @@ contract MTokenTests is TestUtils { _registrar.setPortal(_portal); _implementation = new MTokenHarness(address(_registrar), _migrationAdmin); - _mToken = MTokenHarness(address(new ERC1967Proxy(address(_implementation), abi.encodeCall(IMToken.initialize, ())))); + _mToken = MTokenHarness(address(new ERC1967Proxy(address(_implementation), abi.encodeCall(IMToken.initialize, ("M by M0", "M"))))); _mToken.setLatestIndex(_expectedCurrentIndex = 1_100000068703); } diff --git a/test/Migrate.t.sol b/test/Migrate.t.sol index 9b2929a1..fd42e0f1 100644 --- a/test/Migrate.t.sol +++ b/test/Migrate.t.sol @@ -54,7 +54,7 @@ contract MigrationTests is Test { ); _implementation = new MToken(_registrar, _migrationAdmin); - _mToken = MToken(address(new ERC1967Proxy(address(_implementation), abi.encodeCall(IMToken.initialize, ())))); + _mToken = MToken(address(new ERC1967Proxy(address(_implementation), abi.encodeCall(IMToken.initialize, ("M by M0", "M"))))); } function test_migration() external {