Platform: Code4rena
Start Date: 18/05/2023
Pot Size: $24,500 USDC
Total HM: 3
Participants: 72
Period: 4 days
Judge: LSDan
Id: 237
League: ETH
Rank: 25/72
Findings: 2
Award: $44.17
๐ Selected for report: 0
๐ Solo Findings: 0
๐ Selected for report: ABA
Also found by: 0x4non, 0xHati, 0xMosh, 0xSmartContract, 0xWaitress, 0xhacksmithh, 0xnev, 0xprinc, Arabadzhiev, BLACK-PANDA-REACH, Deekshith99, Dimagu, KKat7531, Kose, LosPollosHermanos, MohammedRizwan, QiuhaoLi, RaymondFam, Rickard, Rolezn, SAAJ, Sathish9098, Shubham, SmartGooofy, Tripathi, Udsen, V1235816, adriro, arpit, ayden, bigtone, codeVolcan, d3e4, dwward3n, fatherOfBlocks, favelanky, jovemjeune, kutugu, lfzkoala, lukris02, matrix_0wl, minhquanym, ni8mare, parsely, pxng0lin, radev_sw, ravikiranweb3, rbserver, sces60107, souilos, tnevler, turvy_fuzz, yellowBirdy
16.1907 USDC - $16.19
It's important to ensure that the beneficiary address is properly checked before minting tokens to maintain security and prevent unauthorized minting. Failure to validate the beneficiary address can result in potential security vulnerabilities and unauthorized token creation
FILE: 2023-05-juicebox/juice-buyback/contracts/JBXBuybackDelegate.sol 341: _beneficiary: _data.beneficiary,
Including sender information in events during token minting or burning is a good practice to provide transparency and track the origin of the token creation or destruction. It helps to maintain an audit trail and enables easy verification of token transactions
FILE: Breadcrumbs2023-05-juicebox/juice-buyback/contracts/JBXBuybackDelegate.sol 352: emit JBXBuybackDelegate_Mint(_data.projectId); 328: emit JBXBuybackDelegate_Swap(_data.projectId, _data.amount.value, _amountReceived);
Proper error handling should be implemented to handle potential exceptions and provide meaningful feedback to the user or handle the failure gracefully within the application
FILE: 2023-05-juicebox/juice-buyback/contracts/JBXBuybackDelegate.sol 153: (,, uint256 _quote, uint256 _slippage) = abi.decode(_data.metadata, (bytes32, bytes32, uint256, uint256)); 196: (,, uint256 _quote, uint256 _slippage) = abi.decode(_data.metadata, (bytes32, bytes32, uint256, uint256)); 221: (uint256 _minimumAmountReceived) = abi.decode(data, (uint256));
Recommended Mitigation:
Use try/catch blocks to handle potential exceptions
Decoding arbitrary data can introduce security risks, such as potential vulnerabilities from maliciously crafted or manipulated data
FILE: 2023-05-juicebox/juice-buyback/contracts/JBXBuybackDelegate.sol 153: (,, uint256 _quote, uint256 _slippage) = abi.decode(_data.metadata, (bytes32, bytes32, uint256, uint256)); 196: (,, uint256 _quote, uint256 _slippage) = abi.decode(_data.metadata, (bytes32, bytes32, uint256, uint256)); 221: (uint256 _minimumAmountReceived) = abi.decode(data, (uint256));
Recommended Mitigation:
Check the data,_data.metadata values before start decoding
.transfer will relay 2300 gas and .call will relay all the gas
FILE: 2023-05-juicebox/juice-buyback/contracts/JBXBuybackDelegate.sol - 232: weth.transfer(address(pool), _amountToSend); + 232: (bool success, bytes memory data) = address(weth).call(abi.encodeWithSignature("transfer(address,uint256)", address(pool), _amountToSend));
FILE: 2023-05-juicebox/juice-buyback/contracts/JBXBuybackDelegate.sol 216: function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external override { 334: function _mint(JBDidPayData calldata _data, uint256 _amount) internal {
It is advisable to follow the conventional order of operations, which is performing multiplication before division, to avoid unexpected results and maintain the expected mathematical behavior
The conventional order of operations, known as PEMDAS (Parentheses, Exponents, Multiplication and Division, and Addition and Subtraction), ensures that calculations are performed in a standardized and predictable manner
FILE: 2023-05-juicebox/juice-buyback/contracts/JBXBuybackDelegate.sol 197: uint256 _minimumReceivedFromSwap = _quote - (_quote * _slippage / SLIPPAGE_DENOMINATOR); 157: if (_tokenCount < _quote - (_quote * _slippage / SLIPPAGE_DENOMINATOR)) {
Recommended Mitigation:
_quote - ((_quote * _slippage) / SLIPPAGE_DENOMINATOR);
#0 - c4-judge
2023-06-02T10:56:13Z
dmvt marked the issue as grade-b
27.9811 USDC - $27.98
If needed, the values can be read from the verified contract source code, or if there are multiple values there can be a single getter function that returns a tuple of the values of all currently-public constants. Saves 3406-3606 gas in deployment gas due to the compiler not having to create non-payable getter functions for deployment calldata, not having to store the bytes of the value outside of where itโs used, and not adding another entry to the method ID table
FILE: Breadcrumbs2023-05-juicebox/juice-buyback/contracts/JBXBuybackDelegate.sol 79: IERC20 public immutable projectToken; 85: IUniswapV3Pool public immutable pool; 90: IJBPayoutRedemptionPaymentTerminal3_1 public immutable jbxTerminal; 95: IWETH9 public immutable weth;
jbxTerminal.directory() is an external call and the result can be determined at deployment time (i.e., it doesn't depend on any variable or dynamic state), you can consider saving the result in an immutable variable. This can potentially save gas by avoiding redundant external calls during contract execution.
At least this will save 2100 gas.
FILE: 2023-05-juicebox/juice-buyback/contracts/JBXBuybackDelegate.sol 290: IJBController controller = IJBController(jbxTerminal.directory().controllerOf(_data.projectId)); 335: IJBController controller = IJBController(jbxTerminal.directory().controllerOf(_data.projectId));
itโll save 2100 gas to not set it to that value again
(_tokenCount < _quote - (_quote * _slippage / SLIPPAGE_DENOMINATOR) if this condition is true then only mintedAmount, reservedRate values updated
if particular condition false then values remains to 1 .
FILE: 2023-05-juicebox/juice-buyback/contracts/JBXBuybackDelegate.sol 188: uint256 _tokenCount = mintedAmount; + 192: uint256 _reservedRate = reservedRate; + if(mintedAmount! =1) + { + 189: mintedAmount = 1; + } + if(reservedRate! =1) + { + 189: reservedRate = 1; + } // Retrieve the fc reserved rate and reset the mutex - 192: uint256 _reservedRate = reservedRate; -193: reservedRate = 1;
Solidity version 0.8+ comes with implicit overflow and underflow checks on unsigned integers. When an overflow or an underflow isnโt possible (as an example, when a comparison is made before the arithmetic operation), some gas can be saved by using an unchecked block
FILE: https://github.com/code-423n4/2023-05-juicebox/blob/9d0458282511ff269b3b35b5b082b56d5cc08663/juicebuyback/contracts/JBXBuybackDelegate.sol#L267 267: sqrtPriceLimitX96: _projectTokenIsZero ? TickMath.MAX_SQRT_RATIO - 1 : TickMath.MIN_SQRT_RATIO + 1,
Latest solidity version is 0.8.19
FILE: 2023-05-juicebox/juice-buyback/contracts/JBXBuybackDelegate.sol 2: pragma solidity ^0.8.16;
FILE: 2023-05-juicebox/juice-buyback/contracts/JBXBuybackDelegate.sol 144: function payParams(JBPayParamsData calldata _data) external override returns (uint256 weight, string memory memo, JBPayDelegateAllocation[] memory delegateAllocations) 258: function _swap(JBDidPayData calldata _data, uint256 _minimumReceivedFromSwap, uint256 _reservedRate) internal returns (uint256 _amountReceived)
Checking non-zero transfer values can avoid an expensive external call and save gas. While this is done at some places, itโs not consistently done in the solution. I suggest adding a non-zero-value check here:
FILE: 2023-05-juicebox/juice-buyback/contracts/JBXBuybackDelegate.sol 232: weth.transfer(address(pool), _amountToSend);
#0 - c4-pre-sort
2023-05-23T14:21:23Z
dmvt marked the issue as low quality report
#1 - c4-judge
2023-06-02T10:05:57Z
dmvt marked the issue as grade-c
#2 - sathishpic22
2023-06-03T11:49:31Z
@dmvt I hope this message finds you well. I wanted to reach out and kindly request a recheck of the bug findings. While I deeply respect the expertise and effort that went into the initial assessment. I feel the scout mistakenly marked report as low quality report. The presentation alone not define the reports quality.
I feel my findings are valid and already proven. I saw some of grade A reports they simple applying assembly for all possible places and reduces the gas cost. There is no point assembly for all areas this will affect code readability and quality of the code. Another grade A report even not save total of 500 gas
If I am wrong, please clarify what is incorrect so that I can rectify my mistakes for future contests.
Thank you this chance to express my views .
#3 - c4-judge
2023-06-06T08:55:05Z
dmvt marked the issue as grade-b
#4 - dmvt
2023-06-06T09:03:10Z
After re-evaluating, I'll give you a B for this, but it is on the fence.
For gas I look at several things:
Is the amount of gas saved stated? Does the issue link to the code in question? Does the issue have a mitigation and is it correct? Is the finding invalid due to other reasons, like being part of the bot race?
I give each issue points, tally them up, and then grade based on that result.
Issue 1, 2, and 3 are fine, which is why I'm upgrading to a B. Gas saved is not shown on 4, 5, 6, or 7. Issue 5 is more QA than gas in nature. Issue 6 is yelling at me (all caps) and has no description. Issue 7 is nonsense. Adding a zero check would increase gas for everyone.
#5 - dmvt
2023-06-06T09:03:44Z
Please also note that I was the lookout as well as the judge
#6 - sathishpic22
2023-06-06T09:51:36Z
@dmvt Issue 7 yes this will increase the gas cost little.
My point is ,
In the ERC-20 standard, the transfer function transfers a specified amount of tokens from the sender's address to the designated recipient. If the amount is zero, the function will simply return without performing any token transfers. It won't cause any error or exception as long as the function is implemented correctly and handles zero transfers gracefully. Even with zero amount transfers need to pay the gas cost.
The empty transfer function consumes large gas than amount of zero check . The gas consumption may be around 2000 gas or more. Still the caller need to pay large volume of gas even empty transfer functions.
Using zero check can avoid empty transfers.
If i am wrong please correct me .
Thank you