Platform: Code4rena
Start Date: 01/07/2022
Pot Size: $75,000 USDC
Total HM: 17
Participants: 105
Period: 7 days
Judge: Jack the Pug
Total Solo HM: 5
Id: 143
League: ETH
Rank: 11/105
Findings: 3
Award: $1,267.15
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xNineDec
Also found by: 0x1f8b, 0x29A, 0x52, 0xDjango, 0xdanial, 0xf15ers, Cheeezzyyyy, Chom, Franfran, GalloDaSballo, Green, IllIllI, Meera, Ruhum, bardamu, cccz, codexploder, defsec, hake, hansfriese, horsefacts, hubble, hyh, jonatascm, kebabsec, oyc_109, pashov, rbserver, simon135, tabish, tintin, zzzitron
14.8726 USDC - $14.87
There is no check if the value of _price returned by chainlink latestRoundData() is latest or stale. If stale price is returned, it may result in wrong calculation used further, and in JBPrices.sol
Contract : JBChainlinkV3PriceFeed.sol Line : 42
function currentPrice(uint256 _decimals) external view override returns (uint256) { // Get the latest round information. Only need the price is needed. (, int256 _price, , , ) = feed.latestRoundData(); // Get a reference to the number of decimals the feed uses. uint256 _feedDecimals = feed.decimals(); // Return the price, adjusted to the target decimals. return uint256(_price).adjustDecimals(_feedDecimals, _decimals); }
As per chainlink's documentation, add relevant checks as below for handling return values of latestRoundData().
(uint80 roundID, int256 answer, , uint256 timeStamp, uint80 answeredInRound) = AggregatorV3Interface(feed).latestRoundData(); require(answer > 0, "Chainlink price <= 0"); require(answeredInRound >= roundID, "Stale answer"); require(timeStamp != 0, "Round not complete");
#0 - drgorillamd
2022-07-12T18:28:23Z
Duplicate of #138
1157.7765 USDC - $1,157.78
https://github.com/jbx-protocol/juice-contracts-v2-code4rena/blob/828bf2f3e719873daa08081cfa0d0a6deaa5ace5/contracts/abstract/JBPayoutRedemptionPaymentTerminal.sol#L437-L448 https://github.com/jbx-protocol/juice-contracts-v2-code4rena/blob/828bf2f3e719873daa08081cfa0d0a6deaa5ace5/contracts/abstract/JBPayoutRedemptionPaymentTerminal.sol#L809
The function _distributePayoutsOf() has reentrancy vulnerability which is being called by the external function distributePayoutsOf() There are external calls in this function along with calls sending ETH
The contract JBPayoutRedemptionPaymentTerminal inherits ReentrancyGuard, however there is no use of nonReentrant modifier either in this abstract contract or the other contracts which are deriving this, viz., JBETHPaymentTerminal.sol or JBERC20PaymentTerminal.sol
Contract : JBPayoutRedemptionPaymentTerminal.sol Function : _distributePayoutsOf()
Add nonReentrant modifier in the external function distributePayoutsOf()
#0 - drgorillamd
2022-07-12T16:28:48Z
Duplicate of #35
🌟 Selected for report: IllIllI
Also found by: 0v3rf10w, 0x1f8b, 0x29A, 0xDjango, 0xNazgul, 0xNineDec, 0xdanial, 0xf15ers, Bnke0x0, Ch_301, Chandr, Chom, Funen, GimelSec, Hawkeye, JC, Kaiziron, Lambda, Meera, MiloTruck, Noah3o6, Picodes, ReyAdmirado, Rohan16, Sm4rty, TerrierLover, TomJ, Waze, _Adam, __141345__, asutorufos, aysha, berndartmueller, brgltd, cccz, codexploder, defsec, delfin454000, djxploit, durianSausage, fatherOfBlocks, hake, horsefacts, hubble, jayfromthe13th, joestakey, jonatascm, m_Rassska, oyc_109, pashov, rajatbeladiya, rbserver, robee, sach1r0, sahar, samruna, simon135, svskaushik, zzzitron
94.5013 USDC - $94.50
configureFor
function, when _mustStartAtOrAfter < block.timestampThe function _transferFrom is using transfer and transferFrom, and the return value is ignored. Failure to do so will cause silent failures of transfers and affect token accounting in contract. Also unsafe transfer might return false instead of reverting, in this case, ignoring return value leads to considering it successful.
Use safe versions of the transfer functions.
Contract : JBERC20PaymentTerminal.sol Function :
function _transferFrom( address _from, address payable _to, uint256 _amount ) internal override { _from == address(this) ? IERC20(token).transfer(_to, _amount) : IERC20(token).transferFrom(_from, _to, _amount); }
Use safeTransfer and safeTransferFrom functions for ERC20 transfers
nonReentrant modifier is applied in other functions like recordPaymentFrom(), recordRedemptionFor(), recordDistributionFor(), recordUsedAllowanceOf(), recordMigration(). This modifier is missing in this function recordAddedBalanceFor(). For consistency and to avoid cross function reentrancy issue add the modifier to all relevant external/public functions.
Contract : JBSingleTokenPaymentTerminalStore.sol Function : recordAddedBalanceFor()
Add nonReentrant modifier in this function also
configureFor
function, when _mustStartAtOrAfter < block.timestampAs per line 340, When _mustStartAtOrAfter is less than block's timestamp, the block's timestamp or the relevant start time is stored in the configuration properties.
As per line 366, The event emitted has _mustStartAtOrAfter
Instead, it should have block's timestamp or the relevant start time.
This would effect the state of any external integrating system, existing or future, like Indexing server.
Manual review
Get the startTime from _configureIntrinsicPropertiesFor, emit the relevant startTime