Closed code423n4 closed 1 year ago
dmvt marked the issue as primary issue
2 things:
_minReturnedToken
is not really used currently in the protocol, as it's rather for future-proof (for the day where we have terminals with various currencies, where a slippage might appear) - screenshot of the latest pay(..) for instance:
in this setting, the delegate doesn't receive this arg (hence the use of the "free" metadata arg, to pass the quote/min received)
The scenario of "the transaction is pending then current fc rolls over and the beneficiary receive less token" looks a bit super edge case (esp for a med risk)...
Agreed it should be more documented tho, as it might be confusing rn
drgorillamd marked the issue as disagree with severity
dmvt marked issue #232 as primary and marked this issue as a duplicate of 232
I'm going to leave this in place as a medium. The code functions in unexpected ways based on external factors and it's actual function is very different than a user could reasonably expect. If the variable should always be zero, consider removing it. I don't agree with the assertion that including dead arguments which may be used in the future is future-proof.
Also, see here wrt protecting users from themselves.
dmvt marked the issue as satisfactory
Lines of code
https://github.com/code-423n4/2023-05-juicebox/blob/9d0458282511ff269b3b35b5b082b56d5cc08663/juice-buyback/contracts/JBXBuybackDelegate.sol#L166 https://github.com/jbx-protocol/juice-contracts-v3/blob/12d852f28d372dd44987586f8009c56b0fe247a9/contracts/JBSingleTokenPaymentTerminalStore.sol#L409 https://github.com/jbx-protocol/juice-contracts-v3/blob/12d852f28d372dd44987586f8009c56b0fe247a9/contracts/abstract/JBPayoutRedemptionPaymentTerminal.sol#L1385 https://github.com/code-423n4/2023-05-juicebox/blob/9d0458282511ff269b3b35b5b082b56d5cc08663/juice-buyback/contracts/test/DelegateUnit.t.sol#L193
Vulnerability details
Impact
Why does
_minReturnedTokens = 0
:There is a check in the
_pay()
function of JBPayoutRedemptionPaymentTerminal.sol, that requiresbeneficiaryTokenCount
to be higher or equal than_minReturnedTokens
(https://github.com/jbx-protocol/juice-contracts-v3/blob/12d852f28d372dd44987586f8009c56b0fe247a9/contracts/abstract/JBPayoutRedemptionPaymentTerminal.sol#L1373-L1385C11).JuiceBoxBuybackDelegate can return
weight = 0
inpayParams()
if the swap path is chosen over the minting.If using it as a delegate and data source, when
weight = 0
thenrecordPaymentFrom()
will returntokenCount = 0
which will then causebeneficiaryTokenCount
to be 0.See: https://github.com/code-423n4/2023-05-juicebox/blob/9d0458282511ff269b3b35b5b082b56d5cc08663/juice-buyback/contracts/JBXBuybackDelegate.sol#L166 and https://github.com/jbx-protocol/juice-contracts-v3/blob/12d852f28d372dd44987586f8009c56b0fe247a9/contracts/JBSingleTokenPaymentTerminalStore.sol#L409.
Because of that the only way to pass this check is to use
_minReturnedTokens = 0
This is validated by the tests files (https://github.com/code-423n4/2023-05-juicebox/blob/9d0458282511ff269b3b35b5b082b56d5cc08663/juice-buyback/contracts/test/DelegateUnit.t.sol#L193).
Why is it an issue :
_minReturnedTokens
is here to make sure the user will always get a minimum return when callingpay()
.Because the returns on user's investement are determined by the cycle params, if these params where to change while the user transaction is in the MEM pool, the returns would get impacted.
Fortunately it seems like cycle's params are fixed for the cycle duration, protecting the user in most cases.
But if a cycle was to end and a new one to start while the transaction is being mined, the returns for the user could change if the new cycle's params are different.
Proof of Concept
Tools Used
Manual review
Recommended Mitigation Steps
A
_minReturnedTokensDelegate
variable could be passed in themetadata
variable and then be checked in the JuiceBoxBuybackDelegate contract and revert iftokenCount
is inferior.Assessed type
Timing