- High: 1
- Medium: 0
- Low: 0
H-01. Multisig participants will lose their rewards, because target address on destination chain is not owner by them
If a participant in staking is a multisig wallet and tries to claim rewards, a mint message would be sent to Arbutrim chain with the address of the multisig wallet. However multisigs are contracts deployed on chains and that's why destination chain address, which corresponds to source chain address won't be owned by the same person/s
In common case rewards would be sent to some random user who may don't want to refund them. In the worst case expoiter can deploy contract on the following address and claim MOR tokens. See Wintermute
Lost rewards for participants, who use multisig wallets. This is more ofter practice. Also the problem could occur in other account abstraction scenarios.
Manual Review
Make claim
function callable only by the owner and let him pass receiver
address for the destination chain:
- function claim(uint256 poolId_, address user_) external payable poolExists(poolId_) {
+ function claim(uint256 poolId_, address receiverAddress ) external payable poolExists(poolId_) {
Pool storage pool = pools[poolId_];
PoolData storage poolData = poolsData[poolId_];
- UserData storage userData = usersData[user][poolId_];
+ UserData storage userData = usersData[msg.sender][poolId_];
require(block.timestamp > pool.payoutStart + pool.claimLockPeriod, "DS: pool claim is locked");
uint256 currentPoolRate_ = _getCurrentPoolRate(poolId_);
uint256 pendingRewards_ = _getCurrentUserReward(currentPoolRate_, userData);
require(pendingRewards_ > 0, "DS: nothing to claim");
// Update pool data
poolData.lastUpdate = uint128(block.timestamp);
poolData.rate = currentPoolRate_;
// Update user data
userData.rate = currentPoolRate_;
userData.pendingRewards = 0;
// @audit if user is multisig wallet, rewards would be lost
// @audit also if the caller of the message is multisig, surplus gass would be lost
// Transfer rewards
+ L1Sender(l1Sender).sendMintMessage{value: msg.value}(receiverAddress, pendingRewards_, _msgSender());
emit UserClaimed(poolId_, user_, pendingRewards_);
}