Lucene search

K
code423n4Code4renaCODE423N4:2023-03-MUTE-FINDINGS-ISSUES-36
HistoryApr 03, 2023 - 12:00 a.m.

A user can 'borrow' dMute balance for a single block to increase their amplifier APY

2023-04-0300:00:00
Code4rena
github.com
2
dmute balance
amplifier apy
delegation balance
exploitation
rewards incentivization

Lines of code

Vulnerability details

The amplifier’s APY is calculated based on the user’s dMute balance (delegation balance to be more accurate) - the more dMute the user holds the higher APY they get.
However, the contract only checks the user’s dMute balance at staking, the user doesn’t have to hold that balance at any time but at the staking block.

This let’s the user to bribe somebody to delegate them their dMute for a single block and stake at the same time.

Since the balance checked is the delegation balance (getPriorVotes) this even makes it easier - since the ‘lender’ doesn’t even need to trust the ‘borrower’ to return the funds, all the ‘lender’ can cancel the delegation on their own on the next block.

The lender can also create a smart contract to automate and decentralize this ‘service’.

Impact

Users can get a share of the rewards that are supposed to incentivize them to hold dMute without actually holding them.
In other words, the same dMute tokens can be used to increase simultaneous staking of different users.

Proof of Concept

The following code shows that only a single block is being checked to calculate the accountDTokenValue at calculateMultiplier():

        if(staked_block != 0 && enforce)
          accountDTokenValue = IDMute(dToken).getPriorVotes(account, staked_block);
        else
          accountDTokenValue = IDMute(dToken).getPriorVotes(account, block.number - 1);

The block checked when rewarding is the staked block, since enforce is true when applying reward:

        reward = lpTokenOut.mul(_totalWeight.sub(_userWeighted[account])).div(calculateMultiplier(account, true));

Recommended Mitigation Steps

Make sure that the user holds the dMute for a longer time, one way to do it might be to sample a few random blocks between staking and current blocks and use the minimum balance as the user’s balance.


The text was updated successfully, but these errors were encountered:

All reactions