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: 38/72
Findings: 1
Award: $16.19
🌟 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
Issue | |
---|---|
NC-1 | ADD TO INDEXED PARAMETER FOR COUNTABLE EVENTS |
NC-2 | FUNCTIONS, PARAMETERS AND VARIABLES IN SNAKE CASE |
NC-3 | LARGE MULTIPLES OF TEN SHOULD USE SCIENTIFIC NOTATION |
NC-4 | NO SAME VALUE INPUT CONTROL |
NC-5 | ADD PARAMETER TO EVENT-EMIT |
NC-6 | USE A MORE RECENT VERSION OF SOLIDITY |
NC-7 | FOR FUNCTIONS AND VARIABLES FOLLOW SOLIDITY STANDARD NAMING CONVENTIONS |
NC-8 | USE UNDERSCORES FOR NUMBER LITERALS |
Add to indexed parameter for countable Events.
File: juice-buyback/contracts/JBXBuybackDelegate.sol 54: event JBXBuybackDelegate_Mint(uint256 projectId); 352: emit JBXBuybackDelegate_Mint(_data.projectId);
Use camel case for all functions, parameters and variables and snake case for constants.
File: juice-buyback/contracts/JBXBuybackDelegate.sol 197: uint256 _minimumReceivedFromSwap = _quote - (_quote * _slippage / SLIPPAGE_DENOMINATOR);
Use (e.g. 1e5) rather than decimal literals (e.g. 10000), for better code readability.
File: juice-buyback/contracts/JBXBuybackDelegate.sol 68: uint256 private constant SLIPPAGE_DENOMINATOR = 10000;
File: juice-buyback/contracts/JBXBuybackDelegate.sol 124: projectToken = _projectToken; 125: pool = _pool; 126: jbxTerminal = _jbxTerminal; 128: weth = _weth;
Some event-emit description hasn’t parameter. Add to parameter for front-end website or client app , they can has that something has happened on the blockchain.
File: juice-buyback/contracts/JBXBuybackDelegate.sol 352: emit JBXBuybackDelegate_Mint(_data.projectId);
For security, it is best practice to use the latest Solidity version. For the security fix list in the versions; https://github.com/ethereum/solidity/blob/develop/Changelog.md
File: juice-buyback/contracts/JBXBuybackDelegate.sol 2: pragma solidity ^0.8.16;
Solidity’s standard naming convention for internal and private functions and variables (apart from constants): the mixedCase format starting with an underscore (_mixedCase starting with an underscore)
Solidity’s standard naming convention for internal and private constants variables: the snake_case format starting with an underscore (_mixedCase starting with an underscore) and use ALL_CAPS for naming them.
File: juice-buyback/contracts/JBXBuybackDelegate.sol 68: uint256 private constant SLIPPAGE_DENOMINATOR = 10000; 106: uint256 private mintedAmount = 1; 113: uint256 private reservedRate = 1; 334: function _mint(JBDidPayData calldata _data, uint256 _amount) internal {
Consider using underscores for number literals to improve its readability.
File: juice-buyback/contracts/JBXBuybackDelegate.sol 68: uint256 private constant SLIPPAGE_DENOMINATOR = 10000;
Issue | |
---|---|
L-1 | AVOID TRANSFER() /SEND() AS REENTRANCY MITIGATIONS |
L-2 | Empty Function Body - Consider commenting why |
L-3 | LOSS OF PRECISION DUE TO ROUNDING |
L-4 | OWNER CAN RENOUNCE OWNERSHIP |
L-5 | Unsafe ERC20 operation(s) |
L-6 | USE _SAFEMINT INSTEAD OF _MINT |
L-7 | USE SAFETRANSFER INSTEAD OF TRANSFER |
TRANSFER()
/SEND()
AS REENTRANCY MITIGATIONSAlthough transfer()
and send()
have been recommended as a security best-practice to prevent reentrancy attacks because they only forward 2300 gas, the gas repricing of opcodes may break deployed contracts. Use call()
instead, without hardcoded gas limits along with checks-effects-interactions pattern or reentrancy guards for reentrancy protection.
https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/
https://swcregistry.io/docs/SWC-134
File: juice-buyback/contracts/JBXBuybackDelegate.sol 232: weth.transfer(address(pool), _amountToSend); 286: if (_nonReservedToken != 0) projectToken.transfer(_data.beneficiary, _nonReservedToken);
Using low-level call.value(amount)
with the corresponding result check or using the OpenZeppelin Address.sendValue
is advised:https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol#L60
Code contains empty block
Empty blocks should be removed or emit something - The code should be refactored such that they no longer exist, or the block should do something useful, such as emitting an event or reverting. If the contract is meant to be extended, the contract should be abstract
and the function signatures be added without any default implementation. If the block is an empty if
-statement block to avoid doing subsequent checks in the else-if/else conditions, the else-if/else conditions should be nested under the negation of the if-statement, because they involve different classes of checks, which may lead to the introduction of errors when the code is later modified (if(x){}else if(y){...}else{...}
=> if(!x){if(y){...}else{...}}
). Empty receive()
/fallback()
payable functions that are not used, can be removed to save deployment gas.
File: juice-buyback/contracts/JBXBuybackDelegate.sol 239: {}
The code should be refactored such that they no longer exist, or the block should do something useful, such as emitting an event or reverting.
File: juice-buyback/contracts/JBXBuybackDelegate.sol 156: if (_tokenCount < _quote - (_quote * _slippage / SLIPPAGE_DENOMINATOR)) { 197: uint256 _minimumReceivedFromSwap = _quote - (_quote * _slippage / SLIPPAGE_DENOMINATOR);
Typically, the contract’s owner is the account that deploys the contract. As a result, the owner is able to perform certain privileged activities.
The Openzeppelin’s Ownable used in this project contract implements renounceOwnership
. This can represent a certain risk if the ownership is renounced for any other reason than by design. Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.
File: juice-buyback/contracts/JBXBuybackDelegate.sol 39: contract JBXBuybackDelegate is IJBFundingCycleDataSource, IJBPayDelegate, IUniswapV3SwapCallback, Ownable {
We recommend to either reimplement the function to disable it or to clearly specify if it is part of the contract design.`
File: juice-buyback/contracts/JBXBuybackDelegate.sol 232: weth.transfer(address(pool), _amountToSend); 286: if (_nonReservedToken != 0) projectToken.transfer(_data.beneficiary, _nonReservedToken);
_SAFEMINT
INSTEAD OF _MINT
According to openzepplin’s ERC721, the use of _mint
is discouraged, use safeMint
whenever possible.
https://docs.openzeppelin.com/contracts/3.x/api/token/erc721#ERC721-mint-address-uint256-
File: juice-buyback/contracts/JBXBuybackDelegate.sol 205: if (_amountReceived == 0) _mint(_data, _tokenCount); 207: _mint(_data, _tokenCount); 334: function _mint(JBDidPayData calldata _data, uint256 _amount) internal {
Use _safeMint
whenever possible instead of _mint
SAFETRANSFER
INSTEAD OF TRANSFER
It is good to add a require()
statement that checks the return value of token transfers or to use something like OpenZeppelin’s safeTransfer
/safeTransferFrom
unless one is sure the given token reverts in case of a failure. Failure to do so will cause silent failures of transfers and affect token accounting in contract.
For example, Some tokens do not implement the ERC20 standard properly but are still accepted by most code that accepts ERC20 tokens. For example Tether (USDT)‘s transfer() and transferFrom() functions do not return booleans as the specification requires, and instead have no return value. When these sorts of tokens are cast to IERC20, their function signatures do not match and therefore the calls made, revert.
File: juice-buyback/contracts/JBXBuybackDelegate.sol 232: weth.transfer(address(pool), _amountToSend); 286: if (_nonReservedToken != 0) projectToken.transfer(_data.beneficiary, _nonReservedToken);
Consider using safeTransfer
/safeTransferFrom
or require()
consistently.
#0 - c4-judge
2023-06-02T10:54:48Z
dmvt marked the issue as grade-b