Platform: Code4rena
Start Date: 03/05/2023
Pot Size: $60,500 USDC
Total HM: 25
Participants: 114
Period: 8 days
Judge: Picodes
Total Solo HM: 6
Id: 234
League: ETH
Rank: 87/114
Findings: 1
Award: $36.24
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: rbserver
Also found by: 0xnev, ABAIKUNANBAEV, Audit_Avengers, Aymen0909, BGSecurity, BRONZEDISC, Bason, DadeKuma, GG_Security, Jerry0x, Jorgect, MohammedRizwan, REACH, Sathish9098, Shogoki, T1MOH, UniversalCrypto, aviggiano, ayden, berlin-101, bytes032, codeslide, descharre, fatherOfBlocks, hals, kaveyjoe, kodyvim, lfzkoala, lukris02, nadin, naman1778, patitonar, pontifex, sakshamguruji, squeaky_cactus, teawaterwire, wonjun, yjrwkk
36.2377 USDC - $36.24
Different Solidity compiler versions are used, the following contracts mix versions:
There are 2 files having compiler version 0.8.14 that is different from other files:
File: ajna-grants/src/grants/GrantFund.sol 3: pragma solidity 0.8.16; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/GrantFund.sol File: ajna-core/src/PositionManager.sol 3: pragma solidity 0.8.14; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/PositionManager.sol File: ajna-core/src/RewardsManager.sol 3: pragma solidity 0.8.14; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol File: ajna-grants/src/grants/base/Funding.sol 3: pragma solidity 0.8.16; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/Funding.sol File: ajna-grants/src/grants/base/ExtraordinaryFunding.sol 3: pragma solidity 0.8.16; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/ExtraordinaryFunding.sol File: ajna-grants/src/grants/base/StandardFunding.sol 3: pragma solidity 0.8.16; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/StandardFunding.sol File: ajna-grants/src/grants/libraries/Maths.sol 3: pragma solidity 0.8.16; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/libraries/Maths.sol File: ajna-grants/src/grants/interfaces/IGrantFund.sol 3: pragma solidity 0.8.16; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/interfaces/IGrantFund.sol File: ajna-grants/src/grants/interfaces/IFunding.sol 4: pragma solidity 0.8.16; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/interfaces/IFunding.sol File: ajna-grants/src/grants/interfaces/IExtraordinaryFunding.sol 4: pragma solidity 0.8.16; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/interfaces/IExtraordinaryFunding.sol File: ajna-grants/src/grants/interfaces/IStandardFunding.sol 4: pragma solidity 0.8.16; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/interfaces/IStandardFunding.sol
There are 6 instances of this issue in 4 files:
File: ajna-core/src/PositionManager.sol 55: mapping(uint256 => mapping(uint256 => Position)) internal positions; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/PositionManager.sol File: ajna-core/src/RewardsManager.sol 70: mapping(uint256 => mapping(uint256 => bool)) public override isEpochClaimed; 77: mapping(address => mapping(uint256 => mapping(uint256 => uint256))) internal bucketExchangeRates; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol File: ajna-grants/src/grants/base/ExtraordinaryFunding.sol 49: mapping(uint256 => mapping(address => bool)) public hasVotedExtraordinary; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/ExtraordinaryFunding.sol File: ajna-grants/src/grants/base/StandardFunding.sol 106: mapping(uint256 => mapping(address => bool)) public hasClaimedReward; 112: mapping(uint256 => mapping(address => uint256)) public screeningVotesCast; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/StandardFunding.sol
Consider using a modifier to implement access control instead of inlining the condition/requirement in the function’s body.
There are 4 instances of this issue in 1 file:
File: ajna-core/src/RewardsManager.sol 114: function claimRewards( 115: uint256 tokenId_, 116: uint256 epochToClaim_ 117: ) external override { 118: StakeInfo storage stakeInfo = stakes[tokenId_]; 119: 120: if (msg.sender != stakeInfo.owner) revert NotOwnerOfDeposit(); 135: function moveStakedLiquidity( 136: uint256 tokenId_, 137: uint256[] memory fromBuckets_, 138: uint256[] memory toBuckets_, 139: uint256 expiry_ 140: ) external nonReentrant override { 141: StakeInfo storage stakeInfo = stakes[tokenId_]; 142: 143: if (msg.sender != stakeInfo.owner) revert NotOwnerOfDeposit(); 207: function stake( 208: uint256 tokenId_ 209: ) external override { 210: address ajnaPool = PositionManager(address(positionManager)).poolKey(tokenId_); 211: 212: // check that msg.sender is owner of tokenId 213: if (IERC721(address(positionManager)).ownerOf(tokenId_) != msg.sender) revert NotOwnerOfDeposit(); 270: function unstake( 271: uint256 tokenId_ 272: ) external override { 273: StakeInfo storage stakeInfo = stakes[tokenId_]; 274: 275: if (msg.sender != stakeInfo.owner) revert NotOwnerOfDeposit(); https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol
Since this is a low level language that is more difficult to parse by readers, include extensive documentation, comments on the rationale behind its use, clearly explaining what each assembly instruction does.
This will make it easier for users to trust the code, for reviewers to validate the code, and for developers to build on or update the code.
Note that using Assembly removes several important security features of Solidity, which can make the code more insecure and more error-prone.
There are 3 instances of this issue in 2 files:
File: ajna-core/src/PositionManager.sol 483: // resize array 484: assembly { mstore(filteredIndexes_, filteredIndexesLength) } https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/PositionManager.sol File: ajna-grants/src/grants/base/Funding.sol 122: assembly { 123: selector := mload(add(selDataWithSig, 0x20)) 124: } 132: assembly { 133: tokensRequested := mload(add(tokenDataWithSig, 68)) 134: } https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/Funding.sol
If you use the constant first you support structures that veil programming errors. And one should only produce code either to add functionality, fix an programming error or trying to support structures to avoid programming errors (like design patterns).
https://www.moserware.com/2008/01/constants-on-left-are-better-but-this.html
There are 32 instances of this issue in 7 files:
File: ajna-grants/src/grants/GrantFund.sol 39: if (_standardFundingProposals[proposalId_].proposalId != 0) return FundingMechanism.Standard; 40: else if (_extraordinaryFundingProposals[proposalId_].proposalId != 0) return FundingMechanism.Extraordinary; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/GrantFund.sol File: ajna-core/src/PositionManager.sol 146: if (positionIndexes[params_.tokenId].length() != 0) revert LiquidityNotRemoved(); 193: if (position.depositTime != 0) { 369: if (position.depositTime == 0 || position.lps == 0) revert RemovePositionFailed(); https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/PositionManager.sol File: ajna-core/src/RewardsManager.sol 495: if (exchangeRate_ != 0) { 535: newRewards_ = totalInterestEarnedInPeriod == 0 ? 0 : Maths.wmul( 653: uint256 totalBurned = totalBurnedLatest != 0 ? totalBurnedLatest - totalBurnedAtBlock : totalBurnedAtBlock; 654: uint256 totalInterest = totalInterestLatest != 0 ? totalInterestLatest - totalInterestAtBlock : totalInterestAtBlock; 751: if (burnExchangeRate == 0) { 778: if (burnExchangeRate == 0) { 817: if (rewardsEarned_ != 0) { https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol File: ajna-grants/src/grants/base/Funding.sol 110: if (targets_.length == 0 || targets_.length != values_.length || targets_.length != calldatas_.length) revert InvalidProposal(); 115: if (targets_[i] != ajnaTokenAddress || values_[i] != 0) revert InvalidProposal(); https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/Funding.sol File: ajna-grants/src/grants/base/ExtraordinaryFunding.sol 97: if (newProposal.proposalId != 0) revert ProposalAlreadyExists(); 208: if (_fundedExtraordinaryProposals.length == 0) { 247: if (proposalId_ == 0) revert ExtraordinaryFundingProposalInactive(); https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/ExtraordinaryFunding.sol File: ajna-grants/src/grants/base/StandardFunding.sol 240: if(screeningVotesCast[distributionId_][msg.sender] == 0) revert DelegateRewardInvalid(); 282: if (votingPowerAllocatedByDelegatee == 0) return 0; 317: newTopSlate_ = currentSlateHash == 0 || 318: (currentSlateHash!= 0 && sum > _sumProposalFundingVotes(_fundedProposalSlates[currentSlateHash])); 377: if (newProposal.proposalId != 0) revert ProposalAlreadyExists(); 538: if (votingPower == 0) { 636: if (voteCastIndex != -1) { 641: if (support == 0 && existingVote.votesUsed > 0 || support == 1 && existingVote.votesUsed < 0) { 719: if (screenedProposalsLength < 10 && indexInArray == -1) { 727: if (indexInArray != -1) { 821: targetProposalId_ != 0 864: return _findProposalIndex(proposalId_, _fundedProposalSlates[_distributions[distributionId].fundedSlateHash]) != -1; 898: if (votingPower_ != 0) { https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/StandardFunding.sol File: ajna-grants/src/grants/libraries/Maths.sol 47: z = n % 2 != 0 ? x : 10**18; 52: if (n % 2 != 0) { https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/libraries/Maths.sol
An important feature of Custom Error is that values such as address, tokenID, msg.value can be written inside the () sign, this kind of approach provides a serious advantage in debugging and examining the revert details of dapps such as tenderly.
There are 16 instances of this issue in 3 files:
File: ajna-grants/src/grants/GrantFund.sol 41: else revert ProposalNotFound(); https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/GrantFund.sol File: ajna-core/src/PositionManager.sol 104: if (!_isApprovedOrOwner(msg.sender, tokenId_)) revert NoAuth(); 107: if (pool_ != poolKey[tokenId_]) revert WrongPool(); 146: if (positionIndexes[params_.tokenId].length() != 0) revert LiquidityNotRemoved(); 233: if (!_isAjnaPool(params_.pool, params_.poolSubsetHash)) revert NotAjnaPool(); 271: if (vars.depositTime == 0) revert RemovePositionFailed(); 285: if (vars.depositTime <= vars.bankruptcyTime) revert BucketBankrupt(); 300: if (!positionIndex.remove(params_.fromIndex)) revert RemovePositionFailed(); 369: if (position.depositTime == 0 || position.lps == 0) revert RemovePositionFailed(); 372: if (_bucketBankruptAfterDeposit(pool, index, position.depositTime)) revert BucketBankrupt(); 375: if (!positionIndex.remove(index)) revert RemovePositionFailed(); https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/PositionManager.sol File: ajna-core/src/RewardsManager.sol 96: if (ajnaToken_ == address(0)) revert DeployWithZeroAddress(); 120: if (msg.sender != stakeInfo.owner) revert NotOwnerOfDeposit(); 122: if (isEpochClaimed[tokenId_][epochToClaim_]) revert AlreadyClaimed(); 143: if (msg.sender != stakeInfo.owner) revert NotOwnerOfDeposit(); 147: if (fromBucketLength != toBuckets_.length) revert MoveStakedLiquidityInvalid(); https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol
The package.json configuration file says that the project is using 4.7.0 of OpenZeppelin which has a vulnerability.
Although there is no security vulnerability covering the project, it is recommended to use the latest version v4.8.3.
There is 1 instance of this issue in 1 file:
File: 2023-05-ajna/ajna-grants/lib/openzeppelin-contracts/package.json 1: { 2: "name": "openzeppelin-solidity", 3: "description": "Secure Smart Contract library for Solidity", 4: "version": "4.7.0",
There is occasions where certain number have been hardcoded, either in variable or in the code itself. Large numbers can become hard to read.
Consider using underscores for number literals to improve its readability.
There are 3 instances of this issue in 1 file:
File: ajna-grants/src/grants/base/StandardFunding.sol 34: uint256 internal constant CHALLENGE_PERIOD_LENGTH = 50400; 40: uint48 internal constant DISTRIBUTION_PERIOD_LENGTH = 648000; 46: uint256 internal constant FUNDING_PERIOD_LENGTH = 72000;
Use a solidity version of at least 0.8.18 to use named parameters in mappings (e.g. mapping(address account => uint256 balance)) to improve readability.
There are 4 instances of this issue in 4 files:
File: ajna-core/src/PositionManager.sol 3: pragma solidity 0.8.14; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/PositionManager.sol File: ajna-core/src/RewardsManager.sol 3: pragma solidity 0.8.14; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol File: ajna-grants/src/grants/base/ExtraordinaryFunding.sol 3: pragma solidity 0.8.16; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/ExtraordinaryFunding.sol File: ajna-grants/src/grants/base/StandardFunding.sol 3: pragma solidity 0.8.16; https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/StandardFunding.sol
There are 2 instances of this issue in 2 files:
File: ajna-grants/src/grants/libraries/Maths.sol 6: uint256 public constant WAD = 10**18; 30: z = z * 10**9;
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/libraries/Maths.sol
#0 - c4-judge
2023-05-18T18:29:12Z
Picodes marked the issue as grade-b