From e091fd43062b2cd46115ba53447c72bddd4c3f43 Mon Sep 17 00:00:00 2001 From: toninorair Date: Tue, 25 Jun 2024 13:24:07 -0400 Subject: [PATCH 1/2] Add renames --- src/WrappedM.sol | 95 ++++++++++++++++++------------------ src/interfaces/IWrappedM.sol | 8 +-- test/Test.t.sol | 16 +++--- 3 files changed, 60 insertions(+), 59 deletions(-) diff --git a/src/WrappedM.sol b/src/WrappedM.sol index 4f2009c..2ac8a93 100644 --- a/src/WrappedM.sol +++ b/src/WrappedM.sol @@ -48,6 +48,22 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended { /* ============ Interactive Functions ============ */ + function wrap(address destination_, uint256 amount_) external { + emit Transfer(address(0), destination_, amount_); + + _mint(destination_, UIntMath.safe240(amount_)); + + IMTokenLike(mToken).transferFrom(msg.sender, address(this), amount_); + } + + function unwrap(address destination_, uint256 amount_) external { + emit Transfer(msg.sender, address(0), amount_); + + _burn(msg.sender, UIntMath.safe240(amount_)); + + IMTokenLike(mToken).transfer(destination_, amount_); + } + function claimFor(address account_) external returns (uint240 yield_) { return _claim(account_, currentIndex()); } @@ -58,14 +74,6 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended { IMTokenLike(mToken).transfer(vault, yield_); } - function deposit(address destination_, uint256 amount_) external { - emit Transfer(address(0), destination_, amount_); - - _addAmount(destination_, UIntMath.safe240(amount_)); - - IMTokenLike(mToken).transferFrom(msg.sender, address(this), amount_); - } - function startEarningFor(address account_) external { if (!_isApprovedEarner(account_)) revert NotApprovedEarner(); @@ -107,19 +115,12 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended { uint240 amount_ = IndexingMath.getPresentAmountRoundedDown(uint112(rawBalance_), index_); _setBalanceInfo(account_, false, 0, amount_); + totalNonEarningSupply += amount_; _subtractTotalEarningSupply(amount_, currentIndex_); } - function withdraw(address destination_, uint256 amount_) external { - emit Transfer(msg.sender, address(0), amount_); - - _subtractAmount(msg.sender, UIntMath.safe240(amount_)); - - IMTokenLike(mToken).transfer(destination_, amount_); - } - /* ============ View/Pure Functions ============ */ function accruedYieldOf(address account_) external view returns (uint240 yield_) { @@ -159,7 +160,7 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended { /* ============ Internal Interactive Functions ============ */ - function _addAmount(address recipient_, uint240 amount_) internal { + function _mint(address recipient_, uint240 amount_) internal { (bool isEarning_, , ) = _getBalanceInfo(recipient_); if (!isEarning_) return _addNonEarningAmount(recipient_, amount_); @@ -170,12 +171,29 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended { _addEarningAmount(recipient_, amount_, currentIndex_); } + function _burn(address account_, uint240 amount_) internal { + (bool isEarning_, , ) = _getBalanceInfo(account_); + + if (!isEarning_) return _subtractNonEarningAmount(account_, amount_); + + uint128 currentIndex_ = currentIndex(); + + _claim(account_, currentIndex_); + _subtractEarningAmount(account_, amount_, currentIndex_); + } + function _addNonEarningAmount(address recipient_, uint240 amount_) internal { (, , uint240 rawBalance_) = _getBalanceInfo(recipient_); _setBalanceInfo(recipient_, false, 0, rawBalance_ + amount_); totalNonEarningSupply += amount_; } + function _subtractNonEarningAmount(address account_, uint240 amount_) internal { + (, , uint240 rawBalance_) = _getBalanceInfo(account_); + _setBalanceInfo(account_, false, 0, rawBalance_ - amount_); + totalNonEarningSupply -= amount_; + } + function _addEarningAmount(address recipient_, uint240 amount_, uint128 currentIndex_) internal { (, , uint240 rawBalance_) = _getBalanceInfo(recipient_); @@ -189,6 +207,19 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended { _addTotalEarningSupply(amount_, currentIndex_); } + function _subtractEarningAmount(address account_, uint240 amount_, uint128 currentIndex_) internal { + (, , uint240 rawBalance_) = _getBalanceInfo(account_); + + _setBalanceInfo( + account_, + true, + currentIndex_, + rawBalance_ - IndexingMath.getPrincipalAmountRoundedUp(amount_, currentIndex_) + ); + + _subtractTotalEarningSupply(amount_, currentIndex_); + } + function _claim(address account_, uint128 currentIndex_) internal returns (uint240 yield_) { (bool isEarner_, uint128 index_, uint240 rawBalance_) = _getBalanceInfo(account_); @@ -219,36 +250,6 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended { : BalanceInfo.wrap(uint256(amount_)); } - function _subtractAmount(address account_, uint240 amount_) internal { - (bool isEarning_, , ) = _getBalanceInfo(account_); - - if (!isEarning_) return _subtractNonEarningAmount(account_, amount_); - - uint128 currentIndex_ = currentIndex(); - - _claim(account_, currentIndex_); - _subtractEarningAmount(account_, amount_, currentIndex_); - } - - function _subtractNonEarningAmount(address account_, uint240 amount_) internal { - (, , uint240 rawBalance_) = _getBalanceInfo(account_); - _setBalanceInfo(account_, false, 0, rawBalance_ - amount_); - totalNonEarningSupply -= amount_; - } - - function _subtractEarningAmount(address account_, uint240 amount_, uint128 currentIndex_) internal { - (, , uint240 rawBalance_) = _getBalanceInfo(account_); - - _setBalanceInfo( - account_, - true, - currentIndex_, - rawBalance_ - IndexingMath.getPrincipalAmountRoundedUp(amount_, currentIndex_) - ); - - _subtractTotalEarningSupply(amount_, currentIndex_); - } - function _transfer(address sender_, address recipient_, uint240 amount_, uint128 currentIndex_) internal { _claim(sender_, currentIndex_); _claim(recipient_, currentIndex_); diff --git a/src/interfaces/IWrappedM.sol b/src/interfaces/IWrappedM.sol index 5e91221..08484c9 100644 --- a/src/interfaces/IWrappedM.sol +++ b/src/interfaces/IWrappedM.sol @@ -27,18 +27,18 @@ interface IWrappedM is IMigratable, IERC20Extended { /* ============ Interactive Functions ============ */ + function wrap(address destination, uint256 amount) external; + + function unwrap(address destination, uint256 amount) external; + function claimFor(address account) external returns (uint240 yield); function claimExcess() external returns (uint240 yield); - function deposit(address destination, uint256 amount) external; - function startEarningFor(address account) external; function stopEarningFor(address account) external; - function withdraw(address destination, uint256 amount) external; - /* ============ View/Pure Functions ============ */ function accruedYieldOf(address account) external view returns (uint240 yield); diff --git a/test/Test.t.sol b/test/Test.t.sol index ad8b920..9df5c0a 100644 --- a/test/Test.t.sol +++ b/test/Test.t.sol @@ -124,7 +124,7 @@ contract Tests is Test { _wrappedM.startEarningFor(_bob); vm.prank(_alice); - _wrappedM.deposit(_alice, 100_000000); + _wrappedM.wrap(_alice, 100_000000); _mToken.setBalanceOf(address(_wrappedM), 100_000000); @@ -140,7 +140,7 @@ contract Tests is Test { assertEq(_wrappedM.excess(), 0); vm.prank(_carol); - _wrappedM.deposit(_carol, 100_000000); + _wrappedM.wrap(_carol, 100_000000); _mToken.setBalanceOf(address(_wrappedM), 200_000000); @@ -174,7 +174,7 @@ contract Tests is Test { assertEq(_wrappedM.excess(), 100_000000); vm.prank(_bob); - _wrappedM.deposit(_bob, 100_000000); + _wrappedM.wrap(_bob, 100_000000); _mToken.setBalanceOf(address(_wrappedM), 500_000000); @@ -191,7 +191,7 @@ contract Tests is Test { assertEq(_wrappedM.excess(), 100_000000); vm.prank(_dave); - _wrappedM.deposit(_dave, 100_000000); + _wrappedM.wrap(_dave, 100_000000); _mToken.setBalanceOf(address(_wrappedM), 600_000000); @@ -368,7 +368,7 @@ contract Tests is Test { assertEq(_wrappedM.excess(), 600_000001); vm.prank(_alice); - _wrappedM.withdraw(_alice, 266_666664); + _wrappedM.unwrap(_alice, 266_666664); _mToken.setBalanceOf(address(_wrappedM), 1_233_333336); @@ -384,7 +384,7 @@ contract Tests is Test { assertEq(_wrappedM.excess(), 600_000001); vm.prank(_bob); - _wrappedM.withdraw(_bob, 333_333330); + _wrappedM.unwrap(_bob, 333_333330); _mToken.setBalanceOf(address(_wrappedM), 900_000006); @@ -400,7 +400,7 @@ contract Tests is Test { assertEq(_wrappedM.excess(), 600_000001); vm.prank(_carol); - _wrappedM.withdraw(_carol, 250_000000); + _wrappedM.unwrap(_carol, 250_000000); _mToken.setBalanceOf(address(_wrappedM), 650_000006); @@ -416,7 +416,7 @@ contract Tests is Test { assertEq(_wrappedM.excess(), 600_000001); vm.prank(_dave); - _wrappedM.withdraw(_dave, 50_000000); + _wrappedM.unwrap(_dave, 50_000000); _mToken.setBalanceOf(address(_wrappedM), 600_000006); From da7d7645721ec3dc264a131dbcf33caced06aa83 Mon Sep 17 00:00:00 2001 From: toninorair Date: Wed, 26 Jun 2024 10:45:07 -0400 Subject: [PATCH 2/2] Add thoughts for possibility of start earning --- src/WrappedM.sol | 28 ++++++++++++++++++++++++---- src/interfaces/IMTokenLike.sol | 4 ++++ src/interfaces/IWrappedM.sol | 2 ++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/WrappedM.sol b/src/WrappedM.sol index 2ac8a93..99e84eb 100644 --- a/src/WrappedM.sol +++ b/src/WrappedM.sol @@ -37,6 +37,15 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended { mapping(address account => BalanceInfo balance) internal _balances; + bool public isEarner; + uint128 public lastIndexOfTotalEarningSupply; + + modifier onlyWhenEarner() { + if (isEarner == true) revert NotInEarnerState(); + + _; + } + /* ============ Constructor ============ */ constructor(address mToken_) ERC20Extended("WrappedM by M^0", "wM", 6) { @@ -48,7 +57,7 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended { /* ============ Interactive Functions ============ */ - function wrap(address destination_, uint256 amount_) external { + function wrap(address destination_, uint256 amount_) external onlyWhenEarner { emit Transfer(address(0), destination_, amount_); _mint(destination_, UIntMath.safe240(amount_)); @@ -74,7 +83,18 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended { IMTokenLike(mToken).transfer(vault, yield_); } - function startEarningFor(address account_) external { + function startEarningM() external { + isEarner = true; + IMTokenLike(mToken).startEarning(); + } + + function stopEarningM() external { + isEarner = false; + lastIndexOfTotalEarningSupply = currentIndex(); + IMTokenLike(mToken).stopEarning(); + } + + function startEarningFor(address account_) external onlyWhenEarner { if (!_isApprovedEarner(account_)) revert NotApprovedEarner(); (bool isEarning_, , uint240 rawBalance_) = _getBalanceInfo(account_); @@ -97,7 +117,7 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended { _addTotalEarningSupply(rawBalance_, currentIndex_); } - function stopEarningFor(address account_) external { + function stopEarningFor(address account_) external onlyWhenEarner { if (_isApprovedEarner(account_)) revert ApprovedEarner(); (bool isEarning_, , ) = _getBalanceInfo(account_); @@ -136,7 +156,7 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended { } function currentIndex() public view returns (uint128 index_) { - return IMTokenLike(mToken).currentIndex(); + return isEarner ? IMTokenLike(mToken).currentIndex() : lastIndexOfTotalEarningSupply; } function excess() public view returns (uint240 yield_) { diff --git a/src/interfaces/IMTokenLike.sol b/src/interfaces/IMTokenLike.sol index 40dd601..b01c911 100644 --- a/src/interfaces/IMTokenLike.sol +++ b/src/interfaces/IMTokenLike.sol @@ -9,6 +9,10 @@ interface IMTokenLike { function transferFrom(address sender, address recipient, uint256 amount) external returns (bool success); + function startEarning() external; + + function stopEarning() external; + /* ============ View/Pure Functions ============ */ function balanceOf(address account) external view returns (uint256 balance); diff --git a/src/interfaces/IWrappedM.sol b/src/interfaces/IWrappedM.sol index 08484c9..09450c4 100644 --- a/src/interfaces/IWrappedM.sol +++ b/src/interfaces/IWrappedM.sol @@ -25,6 +25,8 @@ interface IWrappedM is IMigratable, IERC20Extended { error ZeroMToken(); + error NotInEarnerState(); + /* ============ Interactive Functions ============ */ function wrap(address destination, uint256 amount) external;