Amount of project token minted to beneficiary by JBXBuybackDelegate._mint
function is not checked against an expected minimum number of project tokens to be minted to such beneficiary
#247
Labels
2 (Med Risk)
Assets not at direct risk, but function/availability of the protocol could be impacted or leak value
bug
Something isn't working
duplicate-232
satisfactory
satisfies C4 submission criteria; eligible for awards
Lines of code
https://github.com/code-423n4/2023-05-juicebox/blob/main/juice-buyback/contracts/JBXBuybackDelegate.sol#L144-L171
https://github.com/code-423n4/2023-05-juicebox/blob/main/juice-buyback/contracts/JBXBuybackDelegate.sol#L183-L209
https://github.com/code-423n4/2023-05-juicebox/blob/main/juice-buyback/contracts/JBXBuybackDelegate.sol#L334-L353
Vulnerability details
Impact
Calling the following
JBPayoutRedemptionPaymentTerminal3_1._pay
function executes(_fundingCycle, _tokenCount, _delegateAllocations, _memo) = store.recordPaymentFrom(_payer, _bundledAmount, _projectId, baseWeightCurrency, _beneficiary, _memo, _metadata)
.Then, calling the following
JBSingleTokenPaymentTerminalStore3_1.recordPaymentFrom
function executes(_weight, memo, delegateAllocations) = IJBFundingCycleDataSource(fundingCycle.dataSource()).payParams(_data)
.If
_tokenCount < _quote - (_quote * _slippage / SLIPPAGE_DENOMINATOR)
is true, calling the followingJBXBuybackDelegate.payParams
function would return a 0weight
. When_weight == 0
is true in theJBSingleTokenPaymentTerminalStore3_1.recordPaymentFrom
function, it would return a 0tokenCount
. Back in theJBPayoutRedemptionPaymentTerminal3_1._pay
function, when_tokenCount
is 0,beneficiaryTokenCount
would remain 0 that is its default value, and executingif (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT()
can revert when the_minReturnedTokens
input is positive. Thus, in order ot make such transaction to go through, the user who calls theJBPayoutRedemptionPaymentTerminal3_1.pay
function that further calls theJBPayoutRedemptionPaymentTerminal3_1._pay
function must input_minReturnedTokens
as 0 in this situation.https://github.com/code-423n4/2023-05-juicebox/blob/main/juice-buyback/contracts/JBXBuybackDelegate.sol#L144-L171
Furthermore, when the
JBPayoutRedemptionPaymentTerminal3_1._pay
function executes_delegateAllocation.delegate.didPay{value: _payableValue}(_data)
, the followingJBXBuybackDelegate.didPay
function can execute_mint(_data, _tokenCount)
if the swap fails or_data.preferClaimedTokens
is false. However, when calling theJBXBuybackDelegate._mint
function below, the return value of thecontroller.mintTokensOf
function call is not used to check against a value that is similar to_minReturnedTokens
, which is unlikeif (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT()
, wherebeneficiaryTokenCount
is the return value of theIJBController(directory.controllerOf(_projectId)).mintTokensOf
function call, in theJBPayoutRedemptionPaymentTerminal3_1._pay
function. As a result, the amount of project token minted to the corresponding beneficiary is not checked against an expected minimum number of project tokens to be minted to such beneficiary. Because of such lack of slippage control, the actual amount of project token minted to the beneficiary can be lower than expected, such as whenreservedRate
is unexpectedly changed for the current funding cycle.https://github.com/code-423n4/2023-05-juicebox/blob/main/juice-buyback/contracts/JBXBuybackDelegate.sol#L183-L209
https://github.com/code-423n4/2023-05-juicebox/blob/main/juice-buyback/contracts/JBXBuybackDelegate.sol#L334-L353
Proof of Concept
The following steps can occur for the described scenario.
JBPayoutRedemptionPaymentTerminal3_1.pay
function, which further calls theJBPayoutRedemptionPaymentTerminal3_1._pay
function, to pay some ETH._tokenCount < _quote - (_quote * _slippage / SLIPPAGE_DENOMINATOR)
in theJBXBuybackDelegate.payParams
function would be true for her transaction, the swap pathway could be used._minReturnedTokens
input for theJBPayoutRedemptionPaymentTerminal3_1.pay
function call.JBXBuybackDelegate._mint
function is called._minReturnedTokens
input is 0 when calling theJBPayoutRedemptionPaymentTerminal3_1.pay
function and the amount of project token minted to her beneficiary by theJBXBuybackDelegate._mint
function is not checked against an expected minimum number of project tokens to be minted to such beneficiary, an unexpected change ofreservedRate
for the current funding cycle can cause the actual amount of project token minted to her beneficiary to be lower than expected.Tools Used
VSCode
Recommended Mitigation Steps
The
JBPayoutRedemptionPaymentTerminal3_1._pay
function can be updated to executeif (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT()
only when_tokenCount > 0
is true and pass_minReturnedTokens
to theJBXBuybackDelegate.didPay
function. Then, theJBXBuybackDelegate.didPay
andJBXBuybackDelegate._mint
functions can be updated to be able to receive_minReturnedTokens
. Moreover, theJBXBuybackDelegate._mint
function can be updated to revert if the return value of thecontroller.mintTokensOf
function call is less than_minReturnedTokens
.Assessed type
Invalid Validation
The text was updated successfully, but these errors were encountered: