Skip to content

Commit

Permalink
Merge branch 'main' into feat/simple-start-stop-earning
Browse files Browse the repository at this point in the history
  • Loading branch information
toninorair authored Jul 3, 2024
2 parents e9cbaf4 + 1fbabd5 commit 9e472be
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 15 deletions.
27 changes: 18 additions & 9 deletions src/Migratable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,7 @@ abstract contract Migratable is IMigratable {
/* ============ Interactive Functions ============ */

function migrate() external {
address migrator_ = _getMigrator();

if (migrator_ == address(0)) revert ZeroMigrator();

address oldImplementation_ = implementation();

migrator_.delegatecall("");

emit Migrate(migrator_, oldImplementation_, implementation());
_migrate(_getMigrator());
}

/* ============ View/Pure Functions ============ */
Expand All @@ -35,6 +27,23 @@ abstract contract Migratable is IMigratable {
}
}

/* ============ Internal Interactive Functions ============ */

function _migrate(address migrator_) internal {
if (migrator_ == address(0)) revert ZeroMigrator();

if (migrator_.code.length == 0) revert InvalidMigrator();

address oldImplementation_ = implementation();

migrator_.delegatecall("");

address newImplementation_ = implementation();

emit Migrated(migrator_, oldImplementation_, newImplementation_);
emit Upgraded(newImplementation_);
}

/* ============ Internal View/Pure Functions ============ */

function _getMigrator() internal view virtual returns (address migrator_);
Expand Down
13 changes: 12 additions & 1 deletion src/WrappedMToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ contract WrappedMToken is IWrappedMToken, Migratable, ERC20Extended {
bytes32 internal constant _CLAIM_OVERRIDE_RECIPIENT_PREFIX = "wm_claim_override_recipient";
bytes32 internal constant _MIGRATOR_V1_PREFIX = "wm_migrator_v1";

address public immutable migrationAdmin;
address public immutable mToken;
address public immutable registrar;
address public immutable vault;
Expand All @@ -47,11 +48,13 @@ contract WrappedMToken is IWrappedMToken, Migratable, ERC20Extended {

/* ============ Constructor ============ */

constructor(address mToken_) ERC20Extended("WrappedM by M^0", "wM", 6) {
constructor(address mToken_, address migrationAdmin_) ERC20Extended("WrappedM by M^0", "wM", 6) {
if ((mToken = mToken_) == address(0)) revert ZeroMToken();

registrar = IMTokenLike(mToken_).ttgRegistrar();
vault = IRegistrarLike(registrar).vault();

if ((migrationAdmin = migrationAdmin_) == address(0)) revert ZeroMigrationAdmin();
}

/* ============ Interactive Functions ============ */
Expand Down Expand Up @@ -130,6 +133,14 @@ contract WrappedMToken is IWrappedMToken, Migratable, ERC20Extended {
}
}

/* ============ Temporary Admin Migration ============ */

function migrate(address migrator_) external {
if (msg.sender != migrationAdmin) revert UnauthorizedMigration();

_migrate(migrator_);
}

/* ============ View/Pure Functions ============ */

function accruedYieldOf(address account_) external view returns (uint240 yield_) {
Expand Down
6 changes: 5 additions & 1 deletion src/interfaces/IMigratable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
pragma solidity 0.8.23;

interface IMigratable {
event Migrate(address indexed migrator, address indexed oldImplementation, address indexed newImplementation);
event Migrated(address indexed migrator, address indexed oldImplementation, address indexed newImplementation);

event Upgraded(address indexed implementation);

error InvalidMigrator();

error ZeroMigrator();

Expand Down
10 changes: 10 additions & 0 deletions src/interfaces/IWrappedMToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,15 @@ interface IWrappedMToken is IMigratable, IERC20Extended {
/// @notice Emitted when calling `startEarningFor` if Wrapped M is not in earning state.
error NotInEarningState();

/// @notice Emitted when the non-governance migrate function is called by a account other than the migration admin.
error UnauthorizedMigration();

/// @notice Emitted in constructor if M Token is 0x0.
error ZeroMToken();

/// @notice Emitted in constructor if Migration Admin is 0x0.
error ZeroMigrationAdmin();

/* ============ Interactive Functions ============ */

function wrap(address recipient, uint256 amount) external;
Expand All @@ -68,6 +74,10 @@ interface IWrappedMToken is IMigratable, IERC20Extended {

function stopEarningFor(address account) external;

/* ============ Temporary Admin Migration ============ */

function migrate(address migrator_) external;

/* ============ View/Pure Functions ============ */

function accruedYieldOf(address account) external view returns (uint240 yield);
Expand Down
17 changes: 16 additions & 1 deletion test/Test.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ contract Tests is Test {
address internal _carol = makeAddr("carol");
address internal _dave = makeAddr("dave");

address internal _migrationAdmin = makeAddr("migrationAdmin");

address internal _vault = makeAddr("vault");

MockM internal _mToken;
Expand All @@ -63,7 +65,7 @@ contract Tests is Test {
_mToken.setCurrentIndex(_EXP_SCALED_ONE);
_mToken.setTtgRegistrar(address(_registrar));

_implementation = new WrappedMToken(address(_mToken));
_implementation = new WrappedMToken(address(_mToken), _migrationAdmin);

_wrappedMToken = IWrappedMToken(address(new Proxy(address(_implementation))));
}
Expand Down Expand Up @@ -414,4 +416,17 @@ contract Tests is Test {

assertEq(WrappedMTokenV2(address(_wrappedMToken)).foo(), 1);
}

function test_migration_fromAdmin() external {
WrappedMTokenV2 implementationV2_ = new WrappedMTokenV2();
address migrator_ = address(new WrappedMTokenMigratorV1(address(implementationV2_)));

vm.expectRevert();
WrappedMTokenV2(address(_wrappedMToken)).foo();

vm.prank(_migrationAdmin);
_wrappedMToken.migrate(migrator_);

assertEq(WrappedMTokenV2(address(_wrappedMToken)).foo(), 1);
}
}
11 changes: 9 additions & 2 deletions test/WrappedMToken.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ contract WrappedMTokenTests is Test {
address internal _charlie = makeAddr("charlie");
address internal _david = makeAddr("david");

address internal _migrationAdmin = makeAddr("migrationAdmin");

address[] internal _accounts = [_alice, _bob, _charlie, _david];

address internal _vault = makeAddr("vault");
Expand All @@ -49,7 +51,7 @@ contract WrappedMTokenTests is Test {
_mToken.setCurrentIndex(_EXP_SCALED_ONE);
_mToken.setTtgRegistrar(address(_registrar));

_implementation = new WrappedMTokenHarness(address(_mToken));
_implementation = new WrappedMTokenHarness(address(_mToken), _migrationAdmin);

_wrappedMToken = WrappedMTokenHarness(address(new Proxy(address(_implementation))));

Expand All @@ -69,7 +71,12 @@ contract WrappedMTokenTests is Test {

function test_constructor_zeroMToken() external {
vm.expectRevert(IWrappedMToken.ZeroMToken.selector);
new WrappedMTokenHarness(address(0));
new WrappedMTokenHarness(address(0), address(0));
}

function test_constructor_zeroMigrationAdmin() external {
vm.expectRevert(IWrappedMToken.ZeroMigrationAdmin.selector);
new WrappedMTokenHarness(address(_mToken), address(0));
}

/* ============ wrap ============ */
Expand Down
2 changes: 1 addition & 1 deletion test/utils/WrappedMTokenHarness.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pragma solidity 0.8.23;
import { WrappedMToken } from "../../src/WrappedMToken.sol";

contract WrappedMTokenHarness is WrappedMToken {
constructor(address mToken_) WrappedMToken(mToken_) {}
constructor(address mToken_, address migrationAdmin_) WrappedMToken(mToken_, migrationAdmin_) {}

function setIsEarningOf(address account_, bool isEarning_) external {
(, uint128 index_, , uint240 balance_) = _getBalanceInfo(account_);
Expand Down

0 comments on commit 9e472be

Please sign in to comment.