Skip to content

Commit

Permalink
feat: No claim on wrap/unwrap/transfer
Browse files Browse the repository at this point in the history
  • Loading branch information
deluca-mike committed Feb 7, 2025
1 parent d824485 commit 5d25f34
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 285 deletions.
19 changes: 4 additions & 15 deletions src/WrappedMToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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_);
}
Expand Down Expand Up @@ -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_);
}
Expand All @@ -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_);
}
Expand Down Expand Up @@ -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;
Expand Down
24 changes: 12 additions & 12 deletions test/integration/MorphoBlue.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand Down
46 changes: 23 additions & 23 deletions test/integration/Protocol.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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),
Expand All @@ -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);
Expand Down
Loading

0 comments on commit 5d25f34

Please sign in to comment.