hats-finance / Smooth-0x64bc275b37e62eec81a00ecaecd2b9567058f990

Dappnode's MEV Smoothing Pool
0 stars 2 forks source link

Validators don't receive their collateral when they unsubscribe #4

Open hats-bug-reporter[bot] opened 1 year ago

hats-bug-reporter[bot] commented 1 year ago

Github username: @0xDetermination Submission hash (on-chain): 0xdaafb805219e79cfca832079f3497e87547c741602099b0ada8f7ef82bc11d5f Severity: low

Description:

Impact

Validators don't receive their collateral upon unsubscribing, and they must trust and wait for the oracles to publish a root that allows them to claim their collateral in the form of a reward. If the oracles and/or rewardsRoot are somehow compromised, the validator's collateral may be permanently lost. Additionally, validators must pay more gas to retrieve their collateral using claimRewards().

PoC

A validator must send ether equal to subscriptionCollateral to join the protocol, but when they leave they don't receive that collateral back:

    function subscribeValidator(uint64 validatorID) external payable {
        // Check collateral
        require(
            msg.value == subscriptionCollateral,
            "DappnodeSmoothingPool::subscribeValidator: msg.value does not equal subscription collateral"
        );

        emit SubscribeValidator(
            msg.sender,
            subscriptionCollateral,
            validatorID
        );
    }
...
    function unsubscribeValidator(uint64 validatorID) external {
        emit UnsubscribeValidator(msg.sender, validatorID);
    }

Therefore, the only way for the validator to receive the collateral after unsubscribing is to wait for the collateral amount to be added as a reward for them in the rewards Merkle tree.

Relevant Code

https://github.com/hats-finance/Smooth-0x64bc275b37e62eec81a00ecaecd2b9567058f990/blob/main/contracts/DappnodeSmoothingPool.sol#L277-L289 https://github.com/hats-finance/Smooth-0x64bc275b37e62eec81a00ecaecd2b9567058f990/blob/main/contracts/DappnodeSmoothingPool.sol#L353-L355

Recommended Fix

unsubscribeValidator() should return the validator's collateral.

invocamanman commented 1 year ago

The collateral is returned as a reward, so it's added in the leaf of the validator inside the rewardsRoot and can be claimed calling claimRewards