Skip to content

Commit

Permalink
feat: setClaimRecipient
Browse files Browse the repository at this point in the history
  • Loading branch information
deluca-mike committed Jan 17, 2025
1 parent d25d55a commit dfb97c4
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 55 deletions.
35 changes: 23 additions & 12 deletions src/WrappedMToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,18 @@ contract WrappedMToken is IWrappedMToken, Migratable, ERC20Extended {

/**
* @dev Struct to represent an account's balance and yield earning details
* @param isEarning Whether the account is actively earning yield.
* @param balance The present amount of tokens held by the account.
* @param lastIndex The index of the last interaction for the account (0 for non-earning accounts).
* @param isEarning Whether the account is actively earning yield.
* @param balance The present amount of tokens held by the account.
* @param lastIndex The index of the last interaction for the account (0 for non-earning accounts).
* @param hasClaimRecipient Whether the account has an explicitly set claim recipient.
*/
struct Account {
// First Slot
bool isEarning;
uint240 balance;
// Second slot
uint128 lastIndex;
bool hasClaimRecipient;
}

/* ============ Variables ============ */
Expand Down Expand Up @@ -87,6 +89,8 @@ contract WrappedMToken is IWrappedMToken, Migratable, ERC20Extended {
/// @dev Array of indices at which earning was enabled or disabled.
uint128[] internal _enableDisableEarningIndices;

mapping(address account => address claimRecipient) internal _claimRecipients;

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

/**
Expand Down Expand Up @@ -190,6 +194,13 @@ contract WrappedMToken is IWrappedMToken, Migratable, ERC20Extended {
_stopEarningFor(account_, currentIndex());
}

/// @inheritdoc IWrappedMToken
function setClaimRecipient(address claimRecipient_) external {
_accounts[msg.sender].hasClaimRecipient = (_claimRecipients[msg.sender] = claimRecipient_) != address(0);

emit ClaimRecipientSet(msg.sender, claimRecipient_);
}

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

/// @inheritdoc IWrappedMToken
Expand Down Expand Up @@ -227,13 +238,14 @@ contract WrappedMToken is IWrappedMToken, Migratable, ERC20Extended {
}

/// @inheritdoc IWrappedMToken
function claimOverrideRecipientFor(address account_) public view returns (address recipient_) {
return
address(
uint160(
uint256(_getFromRegistrar(keccak256(abi.encode(CLAIM_OVERRIDE_RECIPIENT_KEY_PREFIX, account_))))
)
);
function claimRecipientFor(address account_) public view returns (address recipient_) {
if (_accounts[account_].hasClaimRecipient) return _claimRecipients[account_];

address claimOverrideRecipient_ = address(
uint160(uint256(_getFromRegistrar(keccak256(abi.encode(CLAIM_OVERRIDE_RECIPIENT_KEY_PREFIX, account_)))))
);

return claimOverrideRecipient_ == address(0) ? account_ : claimOverrideRecipient_;
}

/// @inheritdoc IWrappedMToken
Expand Down Expand Up @@ -428,8 +440,7 @@ contract WrappedMToken is IWrappedMToken, Migratable, ERC20Extended {
totalEarningSupply += yield_;
}

address claimOverrideRecipient_ = claimOverrideRecipientFor(account_);
address claimRecipient_ = claimOverrideRecipient_ == address(0) ? account_ : claimOverrideRecipient_;
address claimRecipient_ = claimRecipientFor(account_);

// Emit the appropriate `Claimed` and `Transfer` events, depending on the claim override recipient
emit Claimed(account_, claimRecipient_, yield_);
Expand Down
15 changes: 14 additions & 1 deletion src/interfaces/IWrappedMToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ interface IWrappedMToken is IMigratable, IERC20Extended {
*/
event Claimed(address indexed account, address indexed recipient, uint240 yield);

/**
* @notice Emitted when `account` set their yield claim recipient.
* @param account The account that set their yield claim recipient.
* @param claimRecipient The account that will receive the yield.
*/
event ClaimRecipientSet(address indexed account, address indexed claimRecipient);

/**
* @notice Emitted when Wrapped M earning is enabled.
* @param index The index at the moment earning is enabled.
Expand Down Expand Up @@ -159,6 +166,12 @@ interface IWrappedMToken is IMigratable, IERC20Extended {
*/
function stopEarningFor(address account) external;

/**
* @notice Explicitly sets the recipient of any yield claimed for the caller.
* @param claimRecipient The account that will receive the caller's yield.
*/
function setClaimRecipient(address claimRecipient) external;

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

/**
Expand Down Expand Up @@ -207,7 +220,7 @@ interface IWrappedMToken is IMigratable, IERC20Extended {
* @param account The account being queried.
* @return recipient The address of the recipient, if any, to override as the destination of claimed yield.
*/
function claimOverrideRecipientFor(address account) external view returns (address recipient);
function claimRecipientFor(address account) external view returns (address recipient);

/// @notice The current index of Wrapped M's earning mechanism.
function currentIndex() external view returns (uint128 index);
Expand Down
2 changes: 1 addition & 1 deletion test/integration/UniswapV3.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ contract UniswapV3IntegrationTests is TestBase {
_deployV2Components();
_migrate();

_poolClaimRecipient = _wrappedMToken.claimOverrideRecipientFor(_pool);
_poolClaimRecipient = _wrappedMToken.claimRecipientFor(_pool);

_wrapperBalanceOfM = _mToken.balanceOf(address(_wrappedMToken));
_poolBalanceOfUSDC = IERC20(_USDC).balanceOf(_pool);
Expand Down
Loading

0 comments on commit dfb97c4

Please sign in to comment.