Closed code423n4 closed 1 year ago
Picodes changed the severity to QA (Quality Assurance)
This previously downgraded issue has been upgraded by Picodes
This previously downgraded issue has been upgraded by Picodes
Picodes marked the issue as duplicate of #25
Picodes marked the issue as satisfactory
Picodes changed the severity to 3 (High Risk)
Lines of code
https://github.com/code-423n4/2023-03-mute/blob/4d8b13add2907b17ac14627cfa04e0c3cc9a2bed/contracts/bonds/MuteBond.sol#L153-L200
Vulnerability details
Impact
The
MuteBond.deposit
function allows the user to purchase a bond with LP tokens and receiveMUTE
tokens in return.The
bondPrice
increases linearly over time (which I should mention means the bond gets cheaper; the naming is a bit confusing). There is another mechanic that changes thebondPrice
: Whenever a bond is purchased thebondPrice
decreases (making the bond more expensive; meaning the user gets lessMUTE
for the LP tokens he provides).The user may also provide a
max_buy=true
parameter which means he will purchase the remainingMUTE
such that a new epoch is entered.There are several scenarios possible that lead to unexpected unintended outcomes for the user (Essentially a loss of funds). I decided to put all of this into a single report since all scenarios come down to this:
When the user calls the
deposit
function he cannot specify how manyMUTE
tokens he wants to get out at a minimum. The user cannot know if and how much thebondPrice
changes in between the time he creates the transaction and the time the transaction is processed. ThebondPrice
can also be changed by theowner
by settingstartPrice
,maxPrice
orepochDuration
within an ongoing epoch.Also if he sets
max_buy=true
and a new epoch is entered by the time the transaction is processed or theowner
has increasedmaxPayout
, the user ends up paying a lot more of his LP tokens than intended. Sure he may only approve a certain number. But many users will just approve the maximum amount.I think the first set of scenarios where the
bondPrice
changes is more severe because even a user that does not make the "mistake" of approvingtype(uint256).max
is prone to it.So I focus on this first set of scenarios in my proof of concept. I provide a solution for both of these problems in the recommendations section.
Proof of Concept
Add the following test to the
bonds.ts
test file.Due to the other transactions executing before the user's, the
bondPrice
drops which means the user gets lessMUTE
than expected. Essentially purchasingMUTE
at a worse price than expected which is a loss of funds. The user might be better off by just keeping his LP tokens.Tools Used
VSCode
Recommended Mitigation Steps
How can the first set of scenarios be mitigated?
The user should be able to provide a
minPayout
parameter that specifies how manyMUTE
tokens he wants to receive at a minimum. Thereby if thebondPrice
changes and he would receive lessMUTE
than intended, he is protected.For the second set of scenarios (where
max_buy=true
) I propose that the already existingvalue
parameter should specify amaxValue
, i.e. how many LP tokens the user is willing to pay at a maximum.Both fixes together then look like this: