diff --git a/src/WrappedMToken.sol b/src/WrappedMToken.sol index c70017a..22fbc5e 100644 --- a/src/WrappedMToken.sol +++ b/src/WrappedMToken.sol @@ -161,7 +161,7 @@ contract WrappedMToken is IWrappedMToken, Migratable, ERC20Extended { /// @inheritdoc IWrappedMToken function unwrap(address recipient_) external returns (uint240 unwrapped_) { - return _unwrap(msg.sender, recipient_, uint240(balanceWithYieldOf(msg.sender))); + return _unwrap(msg.sender, recipient_, uint240(balanceOf(msg.sender))); } /// @inheritdoc IWrappedMToken @@ -264,7 +264,7 @@ contract WrappedMToken is IWrappedMToken, Migratable, ERC20Extended { } /// @inheritdoc IWrappedMToken - function balanceWithYieldOf(address account_) public view returns (uint256 balance_) { + function balanceWithYieldOf(address account_) external view returns (uint256 balance_) { unchecked { return balanceOf(account_) + accruedYieldOf(account_); } @@ -356,12 +356,8 @@ contract WrappedMToken is IWrappedMToken, Migratable, ERC20Extended { _revertIfInvalidRecipient(recipient_); if (_accounts[recipient_].isEarning) { - uint128 currentIndex_ = currentIndex(); - - _claim(recipient_, currentIndex_); - // NOTE: Additional principal may end up being rounded to 0 and this will not `_revertIfInsufficientAmount`. - _addEarningAmount(recipient_, amount_, currentIndex_); + _addEarningAmount(recipient_, amount_, currentIndex()); } else { _addNonEarningAmount(recipient_, amount_); } @@ -378,12 +374,8 @@ contract WrappedMToken is IWrappedMToken, Migratable, ERC20Extended { _revertIfInsufficientAmount(amount_); if (_accounts[account_].isEarning) { - uint128 currentIndex_ = currentIndex(); - - _claim(account_, currentIndex_); - // NOTE: Subtracted principal may end up being rounded to 0 and this will not `_revertIfInsufficientAmount`. - _subtractEarningAmount(account_, amount_, currentIndex_); + _subtractEarningAmount(account_, amount_, currentIndex()); } else { _subtractNonEarningAmount(account_, amount_); } @@ -514,9 +506,6 @@ contract WrappedMToken is IWrappedMToken, Migratable, ERC20Extended { function _transfer(address sender_, address recipient_, uint240 amount_, uint128 currentIndex_) internal { _revertIfInvalidRecipient(recipient_); - _claim(sender_, currentIndex_); - _claim(recipient_, currentIndex_); - emit Transfer(sender_, recipient_, amount_); if (amount_ == 0) return; diff --git a/test/integration/MorphoBlue.t.sol b/test/integration/MorphoBlue.t.sol index 558d5e3..029ab2e 100644 --- a/test/integration/MorphoBlue.t.sol +++ b/test/integration/MorphoBlue.t.sol @@ -57,8 +57,8 @@ contract MorphoBlueTests is MorphoTestBase { // borrowing 0.90 USDC. _createMarket(_alice, _USDC); - // The market creation has triggered a wM transfer and the yield has been claimed for morpho. - assertEq(_wrappedMToken.accruedYieldOf(_MORPHO), _morphoAccruedYield -= _morphoAccruedYield); + // The market creation has triggered a wM transfer but the yield has not been claimed for morpho. + assertEq(_wrappedMToken.accruedYieldOf(_MORPHO), _morphoAccruedYield -= 1); assertEq(_wrappedMToken.balanceOf(_alice), _aliceBalanceOfWM -= 1e6); assertEq(_wrappedMToken.balanceOf(_MORPHO), _morphoBalanceOfWM += 1e6); @@ -95,7 +95,7 @@ contract MorphoBlueTests is MorphoTestBase { vm.warp(vm.getBlockTimestamp() + 365 days); assertEq(_wrappedMToken.balanceOf(_MORPHO), _morphoBalanceOfWM); - assertEq(_wrappedMToken.accruedYieldOf(_MORPHO), _morphoAccruedYield += 49_292100); + assertEq(_wrappedMToken.accruedYieldOf(_MORPHO), _morphoAccruedYield += 49_292110); // USDC balance is unchanged. assertEq(IERC20(_USDC).balanceOf(_MORPHO), _morphoBalanceOfUSDC); @@ -109,8 +109,8 @@ contract MorphoBlueTests is MorphoTestBase { _withdrawCollateral(_bob, address(_wrappedMToken), 1_000e6, _bob, _USDC); - // The collateral withdrawal has triggered a wM transfer and the yield has been claimed for morpho. - assertEq(_wrappedMToken.accruedYieldOf(_MORPHO), _morphoAccruedYield -= _morphoAccruedYield); + // The collateral withdrawal has triggered a wM transfer but the yield has not been claimed for morpho. + assertEq(_wrappedMToken.accruedYieldOf(_MORPHO), _morphoAccruedYield -= 1); assertEq(_wrappedMToken.balanceOf(_bob), _bobBalanceOfWM += 1_000e6); assertEq(_wrappedMToken.balanceOf(_MORPHO), _morphoBalanceOfWM -= 1_000e6); @@ -128,7 +128,7 @@ contract MorphoBlueTests is MorphoTestBase { vm.warp(vm.getBlockTimestamp() + 365 days); assertEq(_wrappedMToken.balanceOf(_MORPHO), _morphoBalanceOfWM); - assertEq(_wrappedMToken.accruedYieldOf(_MORPHO), _morphoAccruedYield += 121446); + assertEq(_wrappedMToken.accruedYieldOf(_MORPHO), _morphoAccruedYield += 2_545180); // USDC balance is unchanged. assertEq(IERC20(_USDC).balanceOf(_MORPHO), _morphoBalanceOfUSDC); @@ -149,8 +149,8 @@ contract MorphoBlueTests is MorphoTestBase { // borrowing 0.90 wM. _createMarket(_alice, address(_wrappedMToken)); - // The market creation has triggered a wM transfer and the yield has been claimed for morpho. - assertEq(_wrappedMToken.accruedYieldOf(_MORPHO), _morphoAccruedYield -= _morphoAccruedYield); + // The market creation has triggered a wM transfer but the yield has not been claimed for morpho. + assertEq(_wrappedMToken.accruedYieldOf(_MORPHO), _morphoAccruedYield -= 2); assertEq(_wrappedMToken.balanceOf(_alice), _aliceBalanceOfWM -= 100000); assertEq(_wrappedMToken.balanceOf(_MORPHO), _morphoBalanceOfWM += 100000); @@ -188,7 +188,7 @@ contract MorphoBlueTests is MorphoTestBase { // `startEarningFor` has been called so wM yield has accrued in the pool. assertEq(_wrappedMToken.balanceOf(_MORPHO), _morphoBalanceOfWM); - assertEq(_wrappedMToken.accruedYieldOf(_MORPHO), _morphoAccruedYield += 4_994256); + assertEq(_wrappedMToken.accruedYieldOf(_MORPHO), _morphoAccruedYield += 4_994266); // USDC balance is unchanged. assertEq(IERC20(_USDC).balanceOf(_MORPHO), _morphoBalanceOfUSDC); @@ -197,8 +197,8 @@ contract MorphoBlueTests is MorphoTestBase { _repay(_bob, address(_wrappedMToken), 900e6, _USDC); - // The repay has triggered a wM transfer and the yield has been claimed for morpho. - assertEq(_wrappedMToken.accruedYieldOf(_MORPHO), _morphoAccruedYield -= _morphoAccruedYield); + // The repay has triggered a wM transfer but the yield has not been claimed for morpho. + assertEq(_wrappedMToken.accruedYieldOf(_MORPHO), _morphoAccruedYield); assertEq(_wrappedMToken.balanceOf(_bob), _bobBalanceOfWM -= 900e6); assertEq(_wrappedMToken.balanceOf(_MORPHO), _morphoBalanceOfWM += 900e6); @@ -222,7 +222,7 @@ contract MorphoBlueTests is MorphoTestBase { // `startEarningFor` has been called so wM yield has accrued in the pool. assertEq(_wrappedMToken.balanceOf(_MORPHO), _morphoBalanceOfWM); - assertEq(_wrappedMToken.accruedYieldOf(_MORPHO), _morphoAccruedYield += 77192); + assertEq(_wrappedMToken.accruedYieldOf(_MORPHO), _morphoAccruedYield += 322772); // USDC balance is unchanged. assertEq(IERC20(_USDC).balanceOf(_MORPHO), _morphoBalanceOfUSDC); diff --git a/test/integration/Protocol.t.sol b/test/integration/Protocol.t.sol index c39d9e2..93cb894 100644 --- a/test/integration/Protocol.t.sol +++ b/test/integration/Protocol.t.sol @@ -333,19 +333,19 @@ contract ProtocolIntegrationTests is TestBase { // Alice transfers all her tokens and only keeps her accrued yield. _transferWM(_alice, _carol, 100_000000); - // Assert Alice (Earner) - assertEq(_wrappedMToken.balanceOf(_alice), _aliceBalance = _aliceBalance + 2_395361 - 100_000000); - assertEq(_wrappedMToken.accruedYieldOf(_alice), _aliceAccruedYield -= 2_395361); + // Assert Globals + assertEq(_wrappedMToken.totalEarningSupply(), _totalEarningSupply += _bobBalance - _aliceBalance); + assertEq(_wrappedMToken.totalNonEarningSupply(), _totalNonEarningSupply += _daveBalance + _aliceBalance); + assertEq(_wrappedMToken.totalAccruedYield(), _totalAccruedYield -= 1); + assertEq(_wrappedMToken.excess(), _excess += 1); // Assert Carol (Non-Earner) - assertEq(_wrappedMToken.balanceOf(_carol), _carolBalance += 100_000000); + assertEq(_wrappedMToken.balanceOf(_carol), _carolBalance += _aliceBalance); assertEq(_wrappedMToken.accruedYieldOf(_carol), 0); - // Assert Globals - assertEq(_wrappedMToken.totalEarningSupply(), _totalEarningSupply += _bobBalance + 2_395361 - 100_000000); - assertEq(_wrappedMToken.totalNonEarningSupply(), _totalNonEarningSupply += _daveBalance + 100_000000); - assertEq(_wrappedMToken.totalAccruedYield(), _totalAccruedYield -= 2_395361 + 1); - assertEq(_wrappedMToken.excess(), _excess += 1); + // Assert Alice (Earner) + assertEq(_wrappedMToken.balanceOf(_alice), _aliceBalance -= _aliceBalance); + assertEq(_wrappedMToken.accruedYieldOf(_alice), _aliceAccruedYield -= 1); assertGe( int256(_wrapperBalanceOfM), @@ -385,7 +385,7 @@ contract ProtocolIntegrationTests is TestBase { // Assert Alice (Earner) assertEq(_wrappedMToken.balanceOf(_alice), _aliceBalance); - assertEq(_wrappedMToken.accruedYieldOf(_alice), _aliceAccruedYield += 57377); + assertEq(_wrappedMToken.accruedYieldOf(_alice), _aliceAccruedYield += 57378); // Assert Bob (Earner) assertEq(_wrappedMToken.balanceOf(_bob), _bobBalance); @@ -550,38 +550,38 @@ contract ProtocolIntegrationTests is TestBase { int256(_totalEarningSupply + _totalNonEarningSupply + _totalAccruedYield) + _excess ); - // Accrued yield of Bob is claimed when unwrapping - _unwrap(_bob, _bob, _bobBalance + _bobAccruedYield); + // Accrued yield of Bob is not claimed when unwrapping + _unwrap(_bob, _bob, _bobBalance); // Assert Globals assertEq(_wrappedMToken.totalEarningSupply(), _totalEarningSupply -= _bobBalance); assertEq(_wrappedMToken.totalNonEarningSupply(), _totalNonEarningSupply); - assertEq(_wrappedMToken.totalAccruedYield(), _totalAccruedYield -= 3_614474); + assertEq(_wrappedMToken.totalAccruedYield(), _totalAccruedYield); assertEq(_wrappedMToken.excess(), _excess -= 2); // Assert Bob (Earner) - assertEq(_mToken.balanceOf(_bob), _bobBalance + _bobAccruedYield); - assertEq(_wrappedMToken.balanceOf(_bob), _bobBalance -= _bobBalance); - assertEq(_wrappedMToken.accruedYieldOf(_bob), _bobAccruedYield -= _bobAccruedYield); + assertEq(_mToken.balanceOf(_bob), _bobBalance); + assertEq(_wrappedMToken.balanceOf(_bob), _bobBalance -= 100_000000); + assertEq(_wrappedMToken.accruedYieldOf(_bob), _bobAccruedYield -= 1); assertGe( int256(_wrapperBalanceOfM), int256(_totalEarningSupply + _totalNonEarningSupply + _totalAccruedYield) + _excess ); - // Accrued yield of Carol is claimed when unwrapping - _unwrap(_carol, _carol, _carolBalance + _carolAccruedYield); + // Accrued yield of Carol is not claimed when unwrapping + _unwrap(_carol, _carol, _carolBalance); // Assert Globals assertEq(_wrappedMToken.totalEarningSupply(), _totalEarningSupply -= _carolBalance); assertEq(_wrappedMToken.totalNonEarningSupply(), _totalNonEarningSupply); - assertEq(_wrappedMToken.totalAccruedYield(), _totalAccruedYield -= _carolAccruedYield + 1); - assertEq(_wrappedMToken.excess(), _excess -= 1); + assertEq(_wrappedMToken.totalAccruedYield(), _totalAccruedYield -= 1); + assertEq(_wrappedMToken.excess(), _excess += 1); // Assert Carol (Earner) - assertEq(_mToken.balanceOf(_carol), _carolBalance + _carolAccruedYield); + assertEq(_mToken.balanceOf(_carol), _carolBalance); assertEq(_wrappedMToken.balanceOf(_carol), _carolBalance -= _carolBalance); - assertEq(_wrappedMToken.accruedYieldOf(_carol), _carolAccruedYield -= _carolAccruedYield); + assertEq(_wrappedMToken.accruedYieldOf(_carol), _carolAccruedYield); assertGe( int256(_wrapperBalanceOfM), @@ -594,7 +594,7 @@ contract ProtocolIntegrationTests is TestBase { assertEq(_wrappedMToken.totalEarningSupply(), _totalEarningSupply); assertEq(_wrappedMToken.totalNonEarningSupply(), _totalNonEarningSupply -= _daveBalance); assertEq(_wrappedMToken.totalAccruedYield(), _totalAccruedYield); - assertEq(_wrappedMToken.excess(), _excess); + assertEq(_wrappedMToken.excess(), _excess -= 2); // Assert Dave (Non-Earner) assertEq(_mToken.balanceOf(_dave), _daveBalance); diff --git a/test/integration/UniswapV3.t.sol b/test/integration/UniswapV3.t.sol index b2b5a0d..07a487a 100644 --- a/test/integration/UniswapV3.t.sol +++ b/test/integration/UniswapV3.t.sol @@ -88,10 +88,10 @@ contract UniswapV3IntegrationTests is TestBase { assertEq(_wrappedMToken.balanceOf(_alice), _aliceBalanceOfWM -= 999_930937); assertEq(_wrappedMToken.balanceOf(_pool), _poolBalanceOfWM += 999_930937); - // The mint has triggered a wM transfer and the yield has been claimed for the pool. - assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM += _poolAccruedYield); + // The mint has triggered a wM transfer but the yield has not been claimed for the pool. + assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield -= _poolAccruedYield); + assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield -= 1); assertEq(IERC20(_USDC).balanceOf(_alice), _aliceBalanceOfUSDC -= 1_000e6); assertEq(IERC20(_USDC).balanceOf(_pool), _poolBalanceOfUSDC += 1_000e6); @@ -103,7 +103,7 @@ contract UniswapV3IntegrationTests is TestBase { // `startEarningFor` has been called so wM yield has accrued in the pool. assertEq(_wrappedMToken.balanceOf(_pool), _poolBalanceOfWM); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield += 878_557_430309); + assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield += 878_576_252249); // USDC balance is unchanged. assertEq(IERC20(_USDC).balanceOf(_pool), _poolBalanceOfUSDC); @@ -121,11 +121,11 @@ contract UniswapV3IntegrationTests is TestBase { assertEq(IERC20(_USDC).balanceOf(_pool), _poolBalanceOfUSDC += 1_000e6); assertEq(_wrappedMToken.balanceOf(_bob), swapAmountOut_); - // The swap has triggered a wM transfer and the yield has been claimed for the pool. - assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM += _poolAccruedYield); + // The swap has triggered a wM transfer but the yield has not been claimed for the pool. + assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM); assertEq(_wrappedMToken.balanceOf(_pool), _poolBalanceOfWM -= swapAmountOut_); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield -= _poolAccruedYield); + assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield); /* ============ Second 1-Year Time Warp ============ */ @@ -134,7 +134,7 @@ contract UniswapV3IntegrationTests is TestBase { // `startEarningFor` has been called so wM yield has accrued in the pool. assertEq(_wrappedMToken.balanceOf(_pool), _poolBalanceOfWM); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield += 878_508_264721); + assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield += 921_727_256737); // USDC balance is unchanged. assertEq(IERC20(_USDC).balanceOf(_pool), _poolBalanceOfUSDC); @@ -154,11 +154,11 @@ contract UniswapV3IntegrationTests is TestBase { assertEq(IERC20(_USDC).balanceOf(_dave), _daveBalanceOfUSDC += swapAmountOut_); assertEq(IERC20(_USDC).balanceOf(_pool), _poolBalanceOfUSDC -= swapAmountOut_); - // The swap has triggered a wM transfer and the yield has been claimed for the pool. - assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM += _poolAccruedYield); + // The swap has triggered a wM transfer but the yield has not been claimed for the pool. + assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM); assertEq(_wrappedMToken.balanceOf(_pool), _poolBalanceOfWM += 1_000e6); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield -= _poolAccruedYield); + assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield += 1); } function testFuzz_uniswapV3_earning(uint256 aliceAmount_, uint256 bobUsdc_, uint256 daveWrappedM_) public { @@ -177,10 +177,8 @@ contract UniswapV3IntegrationTests is TestBase { assertEq(_wrappedMToken.balanceOf(_alice), _aliceBalanceOfWM -= amount0_); assertEq(_wrappedMToken.balanceOf(_pool), _poolBalanceOfWM += amount0_); - // The mint has triggered a wM transfer and the yield has been claimed for the pool. - assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM += _poolAccruedYield); - - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield -= _poolAccruedYield); + // The mint has triggered a wM transfer but the yield has not been claimed for the pool. + assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM); assertEq(IERC20(_USDC).balanceOf(_alice), _aliceBalanceOfUSDC -= amount1_); assertEq(IERC20(_USDC).balanceOf(_pool), _poolBalanceOfUSDC += amount1_); @@ -198,11 +196,13 @@ contract UniswapV3IntegrationTests is TestBase { assertEq(_wrappedMToken.balanceOf(_pool), _poolBalanceOfWM); assertApproxEqAbs( - _poolAccruedYield += _wrappedMToken.accruedYieldOf(_pool), - (_poolBalanceOfWM * newIndex_) / index_ - _poolBalanceOfWM, + _wrappedMToken.accruedYieldOf(_pool), + ((_poolBalanceOfWM + _poolAccruedYield) * newIndex_) / index_ - _poolBalanceOfWM, 10 ); + _poolAccruedYield = _wrappedMToken.accruedYieldOf(_pool); + // _USDC balance is unchanged since no swap has been performed. assertEq(IERC20(_USDC).balanceOf(_pool), _poolBalanceOfUSDC); @@ -217,11 +217,10 @@ contract UniswapV3IntegrationTests is TestBase { assertEq(IERC20(_USDC).balanceOf(_pool), _poolBalanceOfUSDC += bobUsdc_); assertEq(_wrappedMToken.balanceOf(_bob), swapOutWM_); - // The swap has triggered a wM transfer and the yield has been claimed for the pool. - assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM += _poolAccruedYield); + // The swap has triggered a wM transfer but the yield has not been claimed for the pool. + assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM); assertEq(_wrappedMToken.balanceOf(_pool), _poolBalanceOfWM -= swapOutWM_); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield -= _poolAccruedYield); /* ============ Second 1-Year Time Warp ============ */ @@ -236,11 +235,13 @@ contract UniswapV3IntegrationTests is TestBase { assertEq(_wrappedMToken.balanceOf(_pool), _poolBalanceOfWM); assertApproxEqAbs( - _poolAccruedYield += _wrappedMToken.accruedYieldOf(_pool), - (_poolBalanceOfWM * newIndex_) / index_ - _poolBalanceOfWM, + _wrappedMToken.accruedYieldOf(_pool), + ((_poolBalanceOfWM + _poolAccruedYield) * newIndex_) / index_ - _poolBalanceOfWM, 10 ); + _poolAccruedYield = _wrappedMToken.accruedYieldOf(_pool); + // USDC balance is unchanged since no swap has been performed. assertEq(IERC20(_USDC).balanceOf(_pool), _poolBalanceOfUSDC); @@ -257,11 +258,10 @@ contract UniswapV3IntegrationTests is TestBase { assertEq(IERC20(_USDC).balanceOf(_dave), swapOutUSDC_); assertEq(IERC20(_USDC).balanceOf(_pool), _poolBalanceOfUSDC -= swapOutUSDC_); - // The swap has triggered a wM transfer and the yield has been claimed for the pool. - assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM += _poolAccruedYield); + // The swap has triggered a wM transfer but the yield has not been claimed for the pool. + assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM); assertEq(_wrappedMToken.balanceOf(_pool), _poolBalanceOfWM += daveWrappedM_); - assertLe(_wrappedMToken.accruedYieldOf(_pool), 3); } function test_uniswapV3_exactInputOrOutputForEarnersAndNonEarners() public { @@ -280,10 +280,10 @@ contract UniswapV3IntegrationTests is TestBase { assertEq(_wrappedMToken.balanceOf(_alice), _aliceBalanceOfWM -= 999_930937); assertEq(_wrappedMToken.balanceOf(_pool), _poolBalanceOfWM += 999_930937); - // The mint has triggered a wM transfer and the yield has been claimed for the pool. - assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM += _poolAccruedYield); + // The mint has triggered a wM transfer but the yield has not been claimed for the pool. + assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield -= _poolAccruedYield); + assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield -= 1); assertEq(IERC20(_USDC).balanceOf(_alice), _aliceBalanceOfUSDC -= 1_000e6); assertEq(IERC20(_USDC).balanceOf(_pool), _poolBalanceOfUSDC += 1_000e6); @@ -293,7 +293,7 @@ contract UniswapV3IntegrationTests is TestBase { // Move 10 days forward and check that yield has accrued. vm.warp(vm.getBlockTimestamp() + 10 days); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield += 23_512_463128); + assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield += 23_512_966853); /* ============ 2 Non-Earners and 2 Earners are Initialized ============ */ @@ -314,17 +314,17 @@ contract UniswapV3IntegrationTests is TestBase { assertEq(_wrappedMToken.balanceOf(_pool), _poolBalanceOfWM += 1_000e6); - // The swap has triggered a wM transfer and the yield has been claimed for the pool. - assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM += _poolAccruedYield); + // The swap has triggered a wM transfer but the yield has not been claimed for the pool. + assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield -= _poolAccruedYield); + assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield); /* ============ 1-Day Time Warp ============ */ // Move 1 day forward and check that yield has accrued. vm.warp(vm.getBlockTimestamp() + 1 days); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield += 2_349_986661); + assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield += 2_353_129323); // Claim yield for the pool and check that carol received yield. _wrappedMToken.claimFor(_pool); @@ -346,17 +346,17 @@ contract UniswapV3IntegrationTests is TestBase { assertEq(_wrappedMToken.balanceOf(_pool), _poolBalanceOfWM += 1_000e6); - // The swap has triggered a wM transfer and the yield has been claimed for the pool. - assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM += _poolAccruedYield); + // The swap has triggered a wM transfer but the yield has not been claimed for the pool. + assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield -= _poolAccruedYield); + assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield); /* ============ 3-Day Time Warp ============ */ // Move 3 days forward and check that yield has accrued. vm.warp(vm.getBlockTimestamp() + 3 days); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield += 7_051_281773); + assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield += 7_055_919498); /* ============ Dave (Non-Earner) Swaps wM for Exact USDC ============ */ @@ -365,17 +365,17 @@ contract UniswapV3IntegrationTests is TestBase { assertEq(_wrappedMToken.balanceOf(_pool), _poolBalanceOfWM += daveOutput_); - // The swap has triggered a wM transfer and the yield has been claimed for the pool. - assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM += _poolAccruedYield); + // The swap has triggered a wM transfer but the yield has not been claimed for the pool. + assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield -= _poolAccruedYield); + assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield); /* ============ 7-Day Time Warp ============ */ // Move 7 day forward and check that yield has accrued. vm.warp(vm.getBlockTimestamp() + 7 days); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield += 16_458_240233); + assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield += 16_475_562741); /* ============ Frank (Earner) Swaps wM for Exact USDC ============ */ @@ -383,10 +383,10 @@ contract UniswapV3IntegrationTests is TestBase { assertEq(_wrappedMToken.balanceOf(_pool), _poolBalanceOfWM += frankOutput_); - // The swap has triggered a wM transfer and the yield has been claimed for the pool. - assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM += _poolAccruedYield); + // The swap has triggered a wM transfer but the yield has not been claimed for the pool. + assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield -= _poolAccruedYield); + assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield); } function test_uniswapV3_increaseDecreaseLiquidity() public { @@ -437,7 +437,7 @@ contract UniswapV3IntegrationTests is TestBase { vm.warp(vm.getBlockTimestamp() + 10 days); assertEq(_wrappedMToken.accruedYieldOf(_bob), _bobAccruedYield += 1_317340); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield += 23_130_990919); + assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield += 23_514_282695); /* ============ Dave (Non-Earner) Swaps Exact wM for USDC ============ */ @@ -451,10 +451,10 @@ contract UniswapV3IntegrationTests is TestBase { assertEq(_wrappedMToken.balanceOf(_pool), _poolBalanceOfWM += 1_000e6); - // The swap has triggered a wM transfer and the yield has been claimed for the pool. - assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM += _poolAccruedYield); + // The swap has triggered a wM transfer but the yield has not been claimed for the pool. + assertEq(_wrappedMToken.balanceOf(_poolClaimRecipient), _poolClaimRecipientBalanceOfWM); - assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield -= _poolAccruedYield); + assertEq(_wrappedMToken.accruedYieldOf(_pool), _poolAccruedYield); /* ============ Alice (Non-Earner) Decreases Liquidity And Bob (Earner) Increases Liquidity ============ */ diff --git a/test/unit/Stories.t.sol b/test/unit/Stories.t.sol index f9eaa71..d4d3b5c 100644 --- a/test/unit/Stories.t.sol +++ b/test/unit/Stories.t.sol @@ -183,48 +183,48 @@ contract StoryTests is Test { _wrappedMToken.transfer(_carol, 100_000000); // Assert Alice (Earner) - assertEq(_wrappedMToken.balanceOf(_alice), 200_000000); - assertEq(_wrappedMToken.accruedYieldOf(_alice), 0); + assertEq(_wrappedMToken.balanceOf(_alice), 100_000000); + assertEq(_wrappedMToken.accruedYieldOf(_alice), 99_999998); // Assert Carol (Non-Earner) assertEq(_wrappedMToken.balanceOf(_carol), 200_000000); assertEq(_wrappedMToken.accruedYieldOf(_carol), 0); // Assert Globals - assertEq(_wrappedMToken.totalEarningSupply(), 300_000000); + assertEq(_wrappedMToken.totalEarningSupply(), 200_000000); assertEq(_wrappedMToken.totalNonEarningSupply(), 300_000000); - assertEq(_wrappedMToken.totalSupply(), 600_000000); - assertEq(_wrappedMToken.totalAccruedYield(), 49_999998); - assertEq(_wrappedMToken.excess(), 250_000002); // TODO: fix rounding. + assertEq(_wrappedMToken.totalSupply(), 500_000000); + assertEq(_wrappedMToken.totalAccruedYield(), 149_999998); + assertEq(_wrappedMToken.excess(), 250_000002); vm.prank(_dave); _wrappedMToken.transfer(_bob, 50_000000); // Assert Bob (Earner) - assertEq(_wrappedMToken.balanceOf(_bob), 200_000000); - assertEq(_wrappedMToken.accruedYieldOf(_bob), 0); + assertEq(_wrappedMToken.balanceOf(_bob), 150_000000); + assertEq(_wrappedMToken.accruedYieldOf(_bob), 49_999998); // Assert Dave (Non-Earner) assertEq(_wrappedMToken.balanceOf(_dave), 50_000000); assertEq(_wrappedMToken.accruedYieldOf(_dave), 0); // Assert Globals - assertEq(_wrappedMToken.totalEarningSupply(), 400_000000); + assertEq(_wrappedMToken.totalEarningSupply(), 250_000000); assertEq(_wrappedMToken.totalNonEarningSupply(), 250_000000); - assertEq(_wrappedMToken.totalSupply(), 650_000000); - assertEq(_wrappedMToken.totalAccruedYield(), 0); - assertEq(_wrappedMToken.excess(), 250_000000); + assertEq(_wrappedMToken.totalSupply(), 500_000000); + assertEq(_wrappedMToken.totalAccruedYield(), 149_999996); + assertEq(_wrappedMToken.excess(), 250_000004); _mToken.setCurrentIndex(4 * _EXP_SCALED_ONE); _mToken.setBalanceOf(address(_wrappedMToken), 1_200_000000); // was 900 @ 3.0, so 1200 @ 4.0 // Assert Alice (Earner) - assertEq(_wrappedMToken.balanceOf(_alice), 200_000000); - assertEq(_wrappedMToken.accruedYieldOf(_alice), 66_666664); + assertEq(_wrappedMToken.balanceOf(_alice), 100_000000); + assertEq(_wrappedMToken.accruedYieldOf(_alice), 166_666664); // Assert Bob (Earner) - assertEq(_wrappedMToken.balanceOf(_bob), 200_000000); - assertEq(_wrappedMToken.accruedYieldOf(_bob), 66_666664); + assertEq(_wrappedMToken.balanceOf(_bob), 150_000000); + assertEq(_wrappedMToken.accruedYieldOf(_bob), 116_666664); // Assert Carol (Non-Earner) assertEq(_wrappedMToken.balanceOf(_carol), 200_000000); @@ -235,10 +235,10 @@ contract StoryTests is Test { assertEq(_wrappedMToken.accruedYieldOf(_dave), 0); // Assert Globals - assertEq(_wrappedMToken.totalEarningSupply(), 400_000000); + assertEq(_wrappedMToken.totalEarningSupply(), 250_000000); assertEq(_wrappedMToken.totalNonEarningSupply(), 250_000000); - assertEq(_wrappedMToken.totalSupply(), 650_000000); - assertEq(_wrappedMToken.totalAccruedYield(), 133_333328); + assertEq(_wrappedMToken.totalSupply(), 500_000000); + assertEq(_wrappedMToken.totalAccruedYield(), 283_333328); assertEq(_wrappedMToken.excess(), 416_666672); _registrar.setListContains(_EARNERS_LIST_NAME, _alice, false); @@ -250,10 +250,10 @@ contract StoryTests is Test { assertEq(_wrappedMToken.accruedYieldOf(_alice), 0); // Assert Globals - assertEq(_wrappedMToken.totalEarningSupply(), 200_000000); + assertEq(_wrappedMToken.totalEarningSupply(), 150_000000); assertEq(_wrappedMToken.totalNonEarningSupply(), 516_666664); - assertEq(_wrappedMToken.totalSupply(), 716_666664); - assertEq(_wrappedMToken.totalAccruedYield(), 66_666664); + assertEq(_wrappedMToken.totalSupply(), 666_666664); + assertEq(_wrappedMToken.totalAccruedYield(), 116_666664); assertEq(_wrappedMToken.excess(), 416_666672); _registrar.setListContains(_EARNERS_LIST_NAME, _carol, true); @@ -265,10 +265,10 @@ contract StoryTests is Test { assertEq(_wrappedMToken.accruedYieldOf(_carol), 0); // Assert Globals - assertEq(_wrappedMToken.totalEarningSupply(), 400_000000); + assertEq(_wrappedMToken.totalEarningSupply(), 350_000000); assertEq(_wrappedMToken.totalNonEarningSupply(), 316_666664); - assertEq(_wrappedMToken.totalSupply(), 716_666664); - assertEq(_wrappedMToken.totalAccruedYield(), 66_666664); + assertEq(_wrappedMToken.totalSupply(), 666_666664); + assertEq(_wrappedMToken.totalAccruedYield(), 116_666664); assertEq(_wrappedMToken.excess(), 416_666672); _mToken.setCurrentIndex(5 * _EXP_SCALED_ONE); @@ -279,8 +279,8 @@ contract StoryTests is Test { assertEq(_wrappedMToken.accruedYieldOf(_alice), 0); // Assert Bob (Earner) - assertEq(_wrappedMToken.balanceOf(_bob), 200_000000); - assertEq(_wrappedMToken.accruedYieldOf(_bob), 133_333330); + assertEq(_wrappedMToken.balanceOf(_bob), 150_000000); + assertEq(_wrappedMToken.accruedYieldOf(_bob), 183_333330); // Assert Carol (Earner) assertEq(_wrappedMToken.balanceOf(_carol), 200_000000); @@ -291,10 +291,10 @@ contract StoryTests is Test { assertEq(_wrappedMToken.accruedYieldOf(_dave), 0); // Assert Globals - assertEq(_wrappedMToken.totalEarningSupply(), 400_000000); + assertEq(_wrappedMToken.totalEarningSupply(), 350_000000); assertEq(_wrappedMToken.totalNonEarningSupply(), 316_666664); - assertEq(_wrappedMToken.totalSupply(), 716_666664); - assertEq(_wrappedMToken.totalAccruedYield(), 183_333330); + assertEq(_wrappedMToken.totalSupply(), 666_666664); + assertEq(_wrappedMToken.totalAccruedYield(), 233_333330); assertEq(_wrappedMToken.excess(), 600_000006); vm.prank(_alice); @@ -305,38 +305,38 @@ contract StoryTests is Test { assertEq(_wrappedMToken.accruedYieldOf(_alice), 0); // Assert Globals - assertEq(_wrappedMToken.totalEarningSupply(), 400_000000); + assertEq(_wrappedMToken.totalEarningSupply(), 350_000000); assertEq(_wrappedMToken.totalNonEarningSupply(), 50_000000); - assertEq(_wrappedMToken.totalSupply(), 450_000000); - assertEq(_wrappedMToken.totalAccruedYield(), 183_333330); + assertEq(_wrappedMToken.totalSupply(), 400_000000); + assertEq(_wrappedMToken.totalAccruedYield(), 233_333330); assertEq(_wrappedMToken.excess(), 600_000006); vm.prank(_bob); - _wrappedMToken.unwrap(_bob, 333_333330); + _wrappedMToken.unwrap(_bob, 150_000000); // Assert Bob (Earner) assertEq(_wrappedMToken.balanceOf(_bob), 0); - assertEq(_wrappedMToken.accruedYieldOf(_bob), 0); + assertEq(_wrappedMToken.accruedYieldOf(_bob), 183_333330); // Assert Globals assertEq(_wrappedMToken.totalEarningSupply(), 200_000000); assertEq(_wrappedMToken.totalNonEarningSupply(), 50_000000); assertEq(_wrappedMToken.totalSupply(), 250_000000); - assertEq(_wrappedMToken.totalAccruedYield(), 50_000000); + assertEq(_wrappedMToken.totalAccruedYield(), 233_333330); assertEq(_wrappedMToken.excess(), 600_000006); vm.prank(_carol); - _wrappedMToken.unwrap(_carol, 250_000000); + _wrappedMToken.unwrap(_carol, 200_000000); // Assert Carol (Earner) assertEq(_wrappedMToken.balanceOf(_carol), 0); - assertEq(_wrappedMToken.accruedYieldOf(_carol), 0); + assertEq(_wrappedMToken.accruedYieldOf(_carol), 50_000000); // Assert Globals assertEq(_wrappedMToken.totalEarningSupply(), 0); assertEq(_wrappedMToken.totalNonEarningSupply(), 50_000000); assertEq(_wrappedMToken.totalSupply(), 50_000000); - assertEq(_wrappedMToken.totalAccruedYield(), 0); + assertEq(_wrappedMToken.totalAccruedYield(), 233_333330); assertEq(_wrappedMToken.excess(), 600_000006); vm.prank(_dave); @@ -350,7 +350,7 @@ contract StoryTests is Test { assertEq(_wrappedMToken.totalEarningSupply(), 0); assertEq(_wrappedMToken.totalNonEarningSupply(), 0); assertEq(_wrappedMToken.totalSupply(), 0); - assertEq(_wrappedMToken.totalAccruedYield(), 0); + assertEq(_wrappedMToken.totalAccruedYield(), 233_333330); assertEq(_wrappedMToken.excess(), 600_000006); } diff --git a/test/unit/WrappedMToken.t.sol b/test/unit/WrappedMToken.t.sol index 2ca10f2..7035589 100644 --- a/test/unit/WrappedMToken.t.sol +++ b/test/unit/WrappedMToken.t.sol @@ -171,12 +171,12 @@ contract WrappedMTokenTests is Test { assertEq(_wrappedMToken.internalWrap(_alice, _alice, 999), 999); assertEq(_wrappedMToken.earningPrincipalOf(_alice), 1_000 + 908); - assertEq(_wrappedMToken.balanceOf(_alice), 1_000 + 100 + 999); - assertEq(_wrappedMToken.accruedYieldOf(_alice), 0); + assertEq(_wrappedMToken.balanceOf(_alice), 1_000 + 999); + assertEq(_wrappedMToken.accruedYieldOf(_alice), 99); assertEq(_wrappedMToken.totalNonEarningSupply(), 0); assertEq(_wrappedMToken.totalEarningPrincipal(), 1_000 + 908); - assertEq(_wrappedMToken.totalEarningSupply(), 1_000 + 100 + 999); - assertEq(_wrappedMToken.totalAccruedYield(), 0); + assertEq(_wrappedMToken.totalEarningSupply(), 1_000 + 999); + assertEq(_wrappedMToken.totalAccruedYield(), 100); vm.expectEmit(); emit IERC20.Transfer(address(0), _alice, 1); @@ -185,12 +185,12 @@ contract WrappedMTokenTests is Test { // No change due to principal round down on wrap. assertEq(_wrappedMToken.earningPrincipalOf(_alice), 1_000 + 908 + 0); - assertEq(_wrappedMToken.balanceOf(_alice), 1_000 + 100 + 999 + 1); - assertEq(_wrappedMToken.accruedYieldOf(_alice), 0); + assertEq(_wrappedMToken.balanceOf(_alice), 1_000 + 999 + 1); + assertEq(_wrappedMToken.accruedYieldOf(_alice), 98); assertEq(_wrappedMToken.totalNonEarningSupply(), 0); assertEq(_wrappedMToken.totalEarningPrincipal(), 1_000 + 908 + 0); - assertEq(_wrappedMToken.totalEarningSupply(), 1_000 + 100 + 999 + 1); - assertEq(_wrappedMToken.totalAccruedYield(), 0); + assertEq(_wrappedMToken.totalEarningSupply(), 1_000 + 999 + 1); + assertEq(_wrappedMToken.totalAccruedYield(), 99); vm.expectEmit(); emit IERC20.Transfer(address(0), _alice, 2); @@ -198,12 +198,12 @@ contract WrappedMTokenTests is Test { assertEq(_wrappedMToken.internalWrap(_alice, _alice, 2), 2); assertEq(_wrappedMToken.earningPrincipalOf(_alice), 1_000 + 908 + 0 + 1); - assertEq(_wrappedMToken.balanceOf(_alice), 1_000 + 100 + 999 + 1 + 2); - assertEq(_wrappedMToken.accruedYieldOf(_alice), 0); + assertEq(_wrappedMToken.balanceOf(_alice), 1_000 + 999 + 1 + 2); + assertEq(_wrappedMToken.accruedYieldOf(_alice), 97); assertEq(_wrappedMToken.totalNonEarningSupply(), 0); assertEq(_wrappedMToken.totalEarningPrincipal(), 1_000 + 908 + 0 + 1); - assertEq(_wrappedMToken.totalEarningSupply(), 1_000 + 100 + 999 + 1 + 2); - assertEq(_wrappedMToken.totalAccruedYield(), 0); + assertEq(_wrappedMToken.totalEarningSupply(), 1_000 + 999 + 1 + 2); + assertEq(_wrappedMToken.totalAccruedYield(), 98); } /* ============ wrap ============ */ @@ -238,8 +238,6 @@ contract WrappedMTokenTests is Test { _mToken.setBalanceOf(_alice, wrapAmount_); - uint240 accruedYield_ = _wrappedMToken.accruedYieldOf(_alice); - if (wrapAmount_ == 0) { vm.expectRevert(abi.encodeWithSelector(IERC20Extended.InsufficientAmount.selector, (0))); } else { @@ -252,7 +250,7 @@ contract WrappedMTokenTests is Test { if (wrapAmount_ == 0) return; - assertEq(_wrappedMToken.balanceOf(_alice), balance_ + accruedYield_ + wrapAmount_); + assertEq(_wrappedMToken.balanceOf(_alice), balance_ + wrapAmount_); assertEq( accountEarning_ ? _wrappedMToken.totalEarningSupply() : _wrappedMToken.totalNonEarningSupply(), @@ -294,8 +292,6 @@ contract WrappedMTokenTests is Test { _mToken.setBalanceOf(_alice, wrapAmount_); - uint240 accruedYield_ = _wrappedMToken.accruedYieldOf(_alice); - if (wrapAmount_ == 0) { vm.expectRevert(abi.encodeWithSelector(IERC20Extended.InsufficientAmount.selector, (0))); } else { @@ -308,7 +304,7 @@ contract WrappedMTokenTests is Test { if (wrapAmount_ == 0) return; - assertEq(_wrappedMToken.balanceOf(_alice), balance_ + accruedYield_ + wrapAmount_); + assertEq(_wrappedMToken.balanceOf(_alice), balance_ + wrapAmount_); assertEq( accountEarning_ ? _wrappedMToken.totalEarningSupply() : _wrappedMToken.totalNonEarningSupply(), @@ -348,8 +344,6 @@ contract WrappedMTokenTests is Test { _mToken.setBalanceOf(_alice, wrapAmount_); - uint240 accruedYield_ = _wrappedMToken.accruedYieldOf(_alice); - if (wrapAmount_ == 0) { vm.expectRevert(abi.encodeWithSelector(IERC20Extended.InsufficientAmount.selector, (0))); } else { @@ -362,7 +356,7 @@ contract WrappedMTokenTests is Test { if (wrapAmount_ == 0) return; - assertEq(_wrappedMToken.balanceOf(_alice), balance_ + accruedYield_ + wrapAmount_); + assertEq(_wrappedMToken.balanceOf(_alice), balance_ + wrapAmount_); assertEq( accountEarning_ ? _wrappedMToken.totalEarningSupply() : _wrappedMToken.totalNonEarningSupply(), @@ -402,8 +396,6 @@ contract WrappedMTokenTests is Test { _mToken.setBalanceOf(_alice, wrapAmount_); - uint240 accruedYield_ = _wrappedMToken.accruedYieldOf(_alice); - if (wrapAmount_ == 0) { vm.expectRevert(abi.encodeWithSelector(IERC20Extended.InsufficientAmount.selector, (0))); } else { @@ -416,7 +408,7 @@ contract WrappedMTokenTests is Test { if (wrapAmount_ == 0) return; - assertEq(_wrappedMToken.balanceOf(_alice), balance_ + accruedYield_ + wrapAmount_); + assertEq(_wrappedMToken.balanceOf(_alice), balance_ + wrapAmount_); assertEq( accountEarning_ ? _wrappedMToken.totalEarningSupply() : _wrappedMToken.totalNonEarningSupply(), @@ -514,18 +506,18 @@ contract WrappedMTokenTests is Test { _mToken.setBalanceOf(address(_wrappedMToken), 1_000); - _wrappedMToken.setTotalEarningPrincipal(909); - _wrappedMToken.setTotalEarningSupply(909); + _wrappedMToken.setTotalEarningPrincipal(1_000); + _wrappedMToken.setTotalEarningSupply(1_000); - _wrappedMToken.setAccountOf(_alice, 909, 909, false); // 999 balance with yield. + _wrappedMToken.setAccountOf(_alice, 1_000, 1_000, false); // 1_100 balance with yield. - assertEq(_wrappedMToken.earningPrincipalOf(_alice), 909); - assertEq(_wrappedMToken.balanceOf(_alice), 909); - assertEq(_wrappedMToken.accruedYieldOf(_alice), 90); + assertEq(_wrappedMToken.earningPrincipalOf(_alice), 1_000); + assertEq(_wrappedMToken.balanceOf(_alice), 1_000); + assertEq(_wrappedMToken.accruedYieldOf(_alice), 100); assertEq(_wrappedMToken.totalNonEarningSupply(), 0); - assertEq(_wrappedMToken.totalEarningPrincipal(), 909); - assertEq(_wrappedMToken.totalEarningSupply(), 909); - assertEq(_wrappedMToken.totalAccruedYield(), 91); + assertEq(_wrappedMToken.totalEarningPrincipal(), 1_000); + assertEq(_wrappedMToken.totalEarningSupply(), 1_000); + assertEq(_wrappedMToken.totalAccruedYield(), 100); vm.expectEmit(); emit IERC20.Transfer(_alice, address(0), 1); @@ -533,39 +525,39 @@ contract WrappedMTokenTests is Test { assertEq(_wrappedMToken.internalUnwrap(_alice, _alice, 1), 1); // Change due to principal round up on unwrap. - assertEq(_wrappedMToken.earningPrincipalOf(_alice), 909 - 1); - assertEq(_wrappedMToken.balanceOf(_alice), 999 - 1); - assertEq(_wrappedMToken.accruedYieldOf(_alice), 0); + assertEq(_wrappedMToken.earningPrincipalOf(_alice), 1_000 - 1); + assertEq(_wrappedMToken.balanceOf(_alice), 1_000 - 1); + assertEq(_wrappedMToken.accruedYieldOf(_alice), 99); assertEq(_wrappedMToken.totalNonEarningSupply(), 0); - assertEq(_wrappedMToken.totalEarningPrincipal(), 909 - 1); - assertEq(_wrappedMToken.totalEarningSupply(), 999 - 1); - assertEq(_wrappedMToken.totalAccruedYield(), 91 - 90); + assertEq(_wrappedMToken.totalEarningPrincipal(), 1_000 - 1); + assertEq(_wrappedMToken.totalEarningSupply(), 1_000 - 1); + assertEq(_wrappedMToken.totalAccruedYield(), 100); vm.expectEmit(); - emit IERC20.Transfer(_alice, address(0), 498); + emit IERC20.Transfer(_alice, address(0), 499); - assertEq(_wrappedMToken.internalUnwrap(_alice, _alice, 498), 498); + assertEq(_wrappedMToken.internalUnwrap(_alice, _alice, 499), 499); - assertEq(_wrappedMToken.earningPrincipalOf(_alice), 909 - 1 - 453); - assertEq(_wrappedMToken.balanceOf(_alice), 999 - 1 - 498); - assertEq(_wrappedMToken.accruedYieldOf(_alice), 0); + assertEq(_wrappedMToken.earningPrincipalOf(_alice), 1_000 - 1 - 454); + assertEq(_wrappedMToken.balanceOf(_alice), 1_000 - 1 - 499); + assertEq(_wrappedMToken.accruedYieldOf(_alice), 99); assertEq(_wrappedMToken.totalNonEarningSupply(), 0); - assertEq(_wrappedMToken.totalEarningPrincipal(), 909 - 1 - 453); - assertEq(_wrappedMToken.totalEarningSupply(), 999 - 1 - 498); - assertEq(_wrappedMToken.totalAccruedYield(), 91 - 90); + assertEq(_wrappedMToken.totalEarningPrincipal(), 1_000 - 1 - 454); + assertEq(_wrappedMToken.totalEarningSupply(), 1_000 - 1 - 499); + assertEq(_wrappedMToken.totalAccruedYield(), 100); vm.expectEmit(); emit IERC20.Transfer(_alice, address(0), 500); assertEq(_wrappedMToken.internalUnwrap(_alice, _alice, 500), 500); - assertEq(_wrappedMToken.earningPrincipalOf(_alice), 909 - 1 - 453 - 455); // 0 - assertEq(_wrappedMToken.balanceOf(_alice), 999 - 1 - 498 - 500); // 0 - assertEq(_wrappedMToken.accruedYieldOf(_alice), 0); + assertEq(_wrappedMToken.earningPrincipalOf(_alice), 1_000 - 1 - 454 - 455); // 0 + assertEq(_wrappedMToken.balanceOf(_alice), 1_000 - 1 - 499 - 500); // 0 + assertEq(_wrappedMToken.accruedYieldOf(_alice), 99); assertEq(_wrappedMToken.totalNonEarningSupply(), 0); - assertEq(_wrappedMToken.totalEarningPrincipal(), 909 - 1 - 453 - 455); // 0 - assertEq(_wrappedMToken.totalEarningSupply(), 999 - 1 - 498 - 500); // 0 - assertEq(_wrappedMToken.totalAccruedYield(), 91 - 90 - 1); // 0 + assertEq(_wrappedMToken.totalEarningPrincipal(), 1_000 - 1 - 454 - 455); // 0 + assertEq(_wrappedMToken.totalEarningSupply(), 1_000 - 1 - 499 - 500); // 0 + assertEq(_wrappedMToken.totalAccruedYield(), 99); } /* ============ unwrap ============ */ @@ -596,22 +588,15 @@ contract WrappedMTokenTests is Test { _setupAccount(_alice, accountEarning_, balanceWithYield_, balance_); - uint240 accruedYield_ = _wrappedMToken.accruedYieldOf(_alice); + _mToken.setBalanceOf(address(_wrappedMToken), balance_); - _mToken.setBalanceOf(address(_wrappedMToken), balance_ + accruedYield_); - - unwrapAmount_ = uint240(bound(unwrapAmount_, 0, (11 * (balance_ + accruedYield_)) / 10)); + unwrapAmount_ = uint240(bound(unwrapAmount_, 0, (11 * balance_) / 10)); if (unwrapAmount_ == 0) { vm.expectRevert(abi.encodeWithSelector(IERC20Extended.InsufficientAmount.selector, (0))); - } else if (unwrapAmount_ > balance_ + accruedYield_) { + } else if (unwrapAmount_ > balance_) { vm.expectRevert( - abi.encodeWithSelector( - IWrappedMToken.InsufficientBalance.selector, - _alice, - balance_ + accruedYield_, - unwrapAmount_ - ) + abi.encodeWithSelector(IWrappedMToken.InsufficientBalance.selector, _alice, balance_, unwrapAmount_) ); } else { vm.expectEmit(); @@ -621,9 +606,9 @@ contract WrappedMTokenTests is Test { vm.startPrank(_alice); _wrappedMToken.unwrap(_alice, unwrapAmount_); - if ((unwrapAmount_ == 0) || (unwrapAmount_ > balance_ + accruedYield_)) return; + if ((unwrapAmount_ == 0) || (unwrapAmount_ > balance_)) return; - assertEq(_wrappedMToken.balanceOf(_alice), balance_ + accruedYield_ - unwrapAmount_); + assertEq(_wrappedMToken.balanceOf(_alice), balance_ - unwrapAmount_); assertEq( accountEarning_ ? _wrappedMToken.totalEarningSupply() : _wrappedMToken.totalNonEarningSupply(), @@ -651,21 +636,19 @@ contract WrappedMTokenTests is Test { _setupAccount(_alice, accountEarning_, balanceWithYield_, balance_); - uint240 accruedYield_ = _wrappedMToken.accruedYieldOf(_alice); - - _mToken.setBalanceOf(address(_wrappedMToken), balance_ + accruedYield_); + _mToken.setBalanceOf(address(_wrappedMToken), balance_); - if (balance_ + accruedYield_ == 0) { + if (balance_ == 0) { vm.expectRevert(abi.encodeWithSelector(IERC20Extended.InsufficientAmount.selector, (0))); } else { vm.expectEmit(); - emit IERC20.Transfer(_alice, address(0), balance_ + accruedYield_); + emit IERC20.Transfer(_alice, address(0), balance_); } vm.startPrank(_alice); _wrappedMToken.unwrap(_alice); - if (balance_ + accruedYield_ == 0) return; + if (balance_ == 0) return; assertEq(_wrappedMToken.balanceOf(_alice), 0); @@ -881,11 +864,11 @@ contract WrappedMTokenTests is Test { _mToken.setCurrentIndex(1_100000000000); _wrappedMToken.pushEnableDisableEarningIndex(1_000000000000); - _wrappedMToken.setAccountOf(_alice, 909, 909, false); + _wrappedMToken.setAccountOf(_alice, 1_000, 1_000, false); // 1_100 balance with yield. - vm.expectRevert(abi.encodeWithSelector(IWrappedMToken.InsufficientBalance.selector, _alice, 999, 1_000)); + vm.expectRevert(abi.encodeWithSelector(IWrappedMToken.InsufficientBalance.selector, _alice, 1_000, 1_001)); vm.prank(_alice); - _wrappedMToken.transfer(_bob, 1_000); + _wrappedMToken.transfer(_bob, 1_001); } function test_transfer_fromNonEarner_toNonEarner() external { @@ -952,12 +935,6 @@ contract WrappedMTokenTests is Test { assertEq(_wrappedMToken.accruedYieldOf(_alice), 100); - vm.expectEmit(); - emit IWrappedMToken.Claimed(_alice, _alice, 100); - - vm.expectEmit(); - emit IERC20.Transfer(address(0), _alice, 100); - vm.expectEmit(); emit IERC20.Transfer(_alice, _bob, 500); @@ -965,15 +942,15 @@ contract WrappedMTokenTests is Test { _wrappedMToken.transfer(_bob, 500); assertEq(_wrappedMToken.earningPrincipalOf(_alice), 545); - assertEq(_wrappedMToken.balanceOf(_alice), 600); - assertEq(_wrappedMToken.accruedYieldOf(_alice), 0); + assertEq(_wrappedMToken.balanceOf(_alice), 500); + assertEq(_wrappedMToken.accruedYieldOf(_alice), 99); assertEq(_wrappedMToken.balanceOf(_bob), 1_000); assertEq(_wrappedMToken.totalNonEarningSupply(), 1_000); assertEq(_wrappedMToken.totalEarningPrincipal(), 545); - assertEq(_wrappedMToken.totalEarningSupply(), 600); - assertEq(_wrappedMToken.totalAccruedYield(), 0); + assertEq(_wrappedMToken.totalEarningSupply(), 500); + assertEq(_wrappedMToken.totalAccruedYield(), 100); vm.expectEmit(); emit IERC20.Transfer(_alice, _bob, 1); @@ -982,15 +959,15 @@ contract WrappedMTokenTests is Test { _wrappedMToken.transfer(_bob, 1); assertEq(_wrappedMToken.earningPrincipalOf(_alice), 544); - assertEq(_wrappedMToken.balanceOf(_alice), 599); - assertEq(_wrappedMToken.accruedYieldOf(_alice), 0); + assertEq(_wrappedMToken.balanceOf(_alice), 499); + assertEq(_wrappedMToken.accruedYieldOf(_alice), 99); assertEq(_wrappedMToken.balanceOf(_bob), 1_001); assertEq(_wrappedMToken.totalNonEarningSupply(), 1_001); assertEq(_wrappedMToken.totalEarningPrincipal(), 544); - assertEq(_wrappedMToken.totalEarningSupply(), 599); - assertEq(_wrappedMToken.totalAccruedYield(), 0); + assertEq(_wrappedMToken.totalEarningSupply(), 499); + assertEq(_wrappedMToken.totalAccruedYield(), 100); } function test_transfer_fromNonEarner_toEarner() external { @@ -1007,12 +984,6 @@ contract WrappedMTokenTests is Test { assertEq(_wrappedMToken.accruedYieldOf(_bob), 50); - vm.expectEmit(); - emit IWrappedMToken.Claimed(_bob, _bob, 50); - - vm.expectEmit(); - emit IERC20.Transfer(address(0), _bob, 50); - vm.expectEmit(); emit IERC20.Transfer(_alice, _bob, 500); @@ -1022,13 +993,13 @@ contract WrappedMTokenTests is Test { assertEq(_wrappedMToken.balanceOf(_alice), 500); assertEq(_wrappedMToken.earningPrincipalOf(_bob), 954); - assertEq(_wrappedMToken.balanceOf(_bob), 1_050); - assertEq(_wrappedMToken.accruedYieldOf(_bob), 0); + assertEq(_wrappedMToken.balanceOf(_bob), 1_000); + assertEq(_wrappedMToken.accruedYieldOf(_bob), 49); assertEq(_wrappedMToken.totalNonEarningSupply(), 500); assertEq(_wrappedMToken.totalEarningPrincipal(), 954); - assertEq(_wrappedMToken.totalEarningSupply(), 1_050); - assertEq(_wrappedMToken.totalAccruedYield(), 0); + assertEq(_wrappedMToken.totalEarningSupply(), 1_000); + assertEq(_wrappedMToken.totalAccruedYield(), 50); } function test_transfer_fromEarner_toEarner() external { @@ -1044,18 +1015,6 @@ contract WrappedMTokenTests is Test { assertEq(_wrappedMToken.accruedYieldOf(_alice), 100); assertEq(_wrappedMToken.accruedYieldOf(_bob), 50); - vm.expectEmit(); - emit IWrappedMToken.Claimed(_alice, _alice, 100); - - vm.expectEmit(); - emit IERC20.Transfer(address(0), _alice, 100); - - vm.expectEmit(); - emit IWrappedMToken.Claimed(_bob, _bob, 50); - - vm.expectEmit(); - emit IERC20.Transfer(address(0), _bob, 50); - vm.expectEmit(); emit IERC20.Transfer(_alice, _bob, 500); @@ -1063,17 +1022,17 @@ contract WrappedMTokenTests is Test { _wrappedMToken.transfer(_bob, 500); assertEq(_wrappedMToken.earningPrincipalOf(_alice), 545); - assertEq(_wrappedMToken.balanceOf(_alice), 600); - assertEq(_wrappedMToken.accruedYieldOf(_alice), 0); + assertEq(_wrappedMToken.balanceOf(_alice), 500); + assertEq(_wrappedMToken.accruedYieldOf(_alice), 99); assertEq(_wrappedMToken.earningPrincipalOf(_bob), 955); - assertEq(_wrappedMToken.balanceOf(_bob), 1_050); - assertEq(_wrappedMToken.accruedYieldOf(_bob), 0); + assertEq(_wrappedMToken.balanceOf(_bob), 1_000); + assertEq(_wrappedMToken.accruedYieldOf(_bob), 50); assertEq(_wrappedMToken.totalNonEarningSupply(), 0); assertEq(_wrappedMToken.totalEarningPrincipal(), 1_500); - assertEq(_wrappedMToken.totalEarningSupply(), 1_650); - assertEq(_wrappedMToken.totalAccruedYield(), 0); + assertEq(_wrappedMToken.totalEarningSupply(), 1_500); + assertEq(_wrappedMToken.totalAccruedYield(), 150); } function test_transfer_nonEarnerToSelf() external { @@ -1104,12 +1063,6 @@ contract WrappedMTokenTests is Test { assertEq(_wrappedMToken.balanceOf(_alice), 1_000); assertEq(_wrappedMToken.accruedYieldOf(_alice), 100); - vm.expectEmit(); - emit IWrappedMToken.Claimed(_alice, _alice, 100); - - vm.expectEmit(); - emit IERC20.Transfer(address(0), _alice, 100); - vm.expectEmit(); emit IERC20.Transfer(_alice, _alice, 500); @@ -1117,12 +1070,12 @@ contract WrappedMTokenTests is Test { _wrappedMToken.transfer(_alice, 500); assertEq(_wrappedMToken.earningPrincipalOf(_alice), 1_000); - assertEq(_wrappedMToken.balanceOf(_alice), 1_100); - assertEq(_wrappedMToken.accruedYieldOf(_alice), 0); + assertEq(_wrappedMToken.balanceOf(_alice), 1_000); + assertEq(_wrappedMToken.accruedYieldOf(_alice), 100); assertEq(_wrappedMToken.totalEarningPrincipal(), 1_000); - assertEq(_wrappedMToken.totalEarningSupply(), 1_100); - assertEq(_wrappedMToken.totalAccruedYield(), 0); + assertEq(_wrappedMToken.totalEarningSupply(), 1_000); + assertEq(_wrappedMToken.totalAccruedYield(), 100); } function testFuzz_transfer( @@ -1156,19 +1109,11 @@ contract WrappedMTokenTests is Test { _setupAccount(_bob, bobEarning_, bobBalanceWithYield_, bobBalance_); - uint240 aliceAccruedYield_ = _wrappedMToken.accruedYieldOf(_alice); - uint240 bobAccruedYield_ = _wrappedMToken.accruedYieldOf(_bob); + amount_ = uint240(bound(amount_, 0, (11 * aliceBalance_) / 10)); - amount_ = uint240(bound(amount_, 0, (11 * (aliceBalance_ + aliceAccruedYield_)) / 10)); - - if (amount_ > aliceBalance_ + aliceAccruedYield_) { + if (amount_ > aliceBalance_) { vm.expectRevert( - abi.encodeWithSelector( - IWrappedMToken.InsufficientBalance.selector, - _alice, - aliceBalance_ + aliceAccruedYield_, - amount_ - ) + abi.encodeWithSelector(IWrappedMToken.InsufficientBalance.selector, _alice, aliceBalance_, amount_) ); } else { vm.expectEmit(); @@ -1178,22 +1123,19 @@ contract WrappedMTokenTests is Test { vm.prank(_alice); _wrappedMToken.transfer(_bob, amount_); - if (amount_ > aliceBalance_ + aliceAccruedYield_) return; + if (amount_ > aliceBalance_) return; - assertEq(_wrappedMToken.balanceOf(_alice), aliceBalance_ + aliceAccruedYield_ - amount_); - assertEq(_wrappedMToken.balanceOf(_bob), bobBalance_ + bobAccruedYield_ + amount_); + assertEq(_wrappedMToken.balanceOf(_alice), aliceBalance_ - amount_); + assertEq(_wrappedMToken.balanceOf(_bob), bobBalance_ + amount_); if (aliceEarning_ && bobEarning_) { - assertEq( - _wrappedMToken.totalEarningSupply(), - aliceBalance_ + aliceAccruedYield_ + bobBalance_ + bobAccruedYield_ - ); + assertEq(_wrappedMToken.totalEarningSupply(), aliceBalance_ + bobBalance_); } else if (aliceEarning_) { - assertEq(_wrappedMToken.totalEarningSupply(), aliceBalance_ + aliceAccruedYield_ - amount_); + assertEq(_wrappedMToken.totalEarningSupply(), aliceBalance_ - amount_); assertEq(_wrappedMToken.totalNonEarningSupply(), bobBalance_ + amount_); } else if (bobEarning_) { assertEq(_wrappedMToken.totalNonEarningSupply(), aliceBalance_ - amount_); - assertEq(_wrappedMToken.totalEarningSupply(), bobBalance_ + bobAccruedYield_ + amount_); + assertEq(_wrappedMToken.totalEarningSupply(), bobBalance_ + amount_); } else { assertEq(_wrappedMToken.totalNonEarningSupply(), aliceBalance_ + bobBalance_); }