Ajna Protocol - pontifex's results

A peer to peer, oracleless, permissionless lending protocol with no governance, accepting both fungible and non fungible tokens as collateral.

General Information

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

Ajna Protocol

Findings Distribution

Researcher Performance

Rank: 70/114

Findings: 2

Award: $58.52

QA:
grade-b
Gas:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Non Critical

N-1 PositionManager.sol#L54_Incorrect comment about positions mapping

It is obviously that the comment in the #L54 is incorrect. It should be replaced with correct information.

54:    /// @dev Mapping of `token id => ajna pool address` for which token was minted.
55:    mapping(uint256 => mapping(uint256 => Position)) internal positions;

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/PositionManager.sol#L54

N-2 PositionManager.sol_Incorrect comments with LiquidityNotRemoved() error

Lines L#166 and L#258 contain wrong information about handled errors. The code below the comments doesn't revert with the LiquidityNotRemoved() error. These comments should be replaced with correct information.

166:     *  @dev    positions token to burn has liquidity `LiquidityNotRemoved()`


258:     *  @dev    - positions token to burn has liquidity `LiquidityNotRemoved()`

N-3 PositionManager.sol_Typo in comments

The line L#348 contains wrong information about the RemoveLiquidityFailed() error. There aren't this type errors in the code. It is possible that it is just a typo.

348:     *  @dev    - position not tracked `RemoveLiquidityFailed()`


369:            if (position.depositTime == 0 || position.lps == 0) revert RemovePositionFailed();


375:            if (!positionIndex.remove(index)) revert RemovePositionFailed();

N-4 StandardFunding.sol#L619_Variable support need not be initialized to 1

The support variable can be initialized with a default value.

619:        uint8  support = 1;
620:        uint256 proposalId = proposal_.proposalId;
621:
622:        // determine if voter is voting for or against the proposal
623:        voteParams_.votesUsed < 0 ? support = 0 : support = 1;

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/StandardFunding.sol#LL619C1-L623C63

N-5 Variables need not be initialized to zero

The default value for variables is zero, so initializing them to zero is superfluous. There are 21 instances.

181:        for (uint256 i = 0; i < indexesLength; ) {


364:        for (uint256 i = 0; i < indexesLength; ) {


474:        uint256 filteredIndexesLength = 0;


476:        for (uint256 i = 0; i < indexesLength; ) {

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/PositionManager.sol#L181

229:        for (uint256 i = 0; i < positionIndexes.length; ) {


290:        for (uint256 i = 0; i < positionIndexes.length; ) {


440:        for (uint256 i = 0; i < positionIndexes_.length; ) {


680:            for (uint256 i = 0; i < indexes_.length; ) {


704:                for (uint256 i = 0; i < indexes_.length; ) {

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/RewardsManager.sol#LL229C1-L229C60

62:        for (uint256 i = 0; i < targets_.length; ++i) {

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/Funding.sol#LL62C1-L62C56

208:        for (uint i = 0; i < numFundedProposals; ) {


324:            for (uint i = 0; i < numProposalsInSlate; ) {


431:        uint256 totalTokensRequested = 0;


434:        for (uint i = 0; i < numProposalsInSlate_; ) {


468:        for (uint i = 0; i < numProposals; ) {


491:        for (uint i = 0; i < proposalIdSubset_.length;) {


549:        for (uint256 i = 0; i < numVotesCast; ) {


582:        for (uint256 i = 0; i < numVotesCast; ) {


770:        for (int256 i = 0; i < arrayLength;) {


797:        for (int256 i = 0; i < numVotesCast; ) {


848:        for (uint256 i = 0; i < numVotesCast; ) {

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/StandardFunding.sol#LL208C1-L208C53

#0 - c4-judge

2023-05-18T18:29:46Z

Picodes marked the issue as grade-b

Awards

22.2767 USDC - $22.28

Labels

bug
G (Gas Optimization)
grade-b
G-02

External Links

GAS-1 Move if/validation statements to the top of the function when validating input parameters

There are 3 instances.

248:        if(hasClaimedReward[distributionId_][msg.sender]) revert RewardAlreadyClaimed();

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/StandardFunding.sol#LL248C22-L248C22

100:        if (block.number + MAX_EFM_PROPOSAL_LENGTH < endBlock_) revert InvalidProposal();

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/ExtraordinaryFunding.sol#LL100C1-L100C90

233:        if (!_isAjnaPool(params_.pool, params_.poolSubsetHash)) revert NotAjnaPool();

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/PositionManager.sol#L233

GAS-2 StandardFunding.sol#L743_Use distributionId caching variable instead proposal_.distributionId state variable

Using distributionId caching variable instead proposal_.distributionId in the line L#743 will save some gas.

703:        uint24 distributionId = proposal_.distributionId;
...
743:        screeningVotesCast[proposal_.distributionId][account_] += votes_;

GAS-3 StandardFunding.sol_Redundant type casting in the loop

Use type casting only once instead of using it in the loop. There are two instances.

-768:        int256 arrayLength = int256(array_.length);
+768:        uint256 arrayLength = array_.length;
 769:
-770:        for (int256 i = 0; i < arrayLength;) {
+770:        for (uint256 i; i < arrayLength;) {
 771:            //slither-disable-next-line incorrect-equality
-772:            if (array_[uint256(i)] == proposalId_) {
-773:                index_ = i;
+772:            if (array_[i] == proposalId_) {
-774:                index_ = int256(i);
 774:                break;
 775:            }

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/StandardFunding.sol#LL768C1-L775C14

-796:        int256 numVotesCast = int256(voteParams_.length);
-797:        for (int256 i = 0; i < numVotesCast; ) {
+796:        uint256 numVotesCast = voteParams_.length;
+797:        for (uint256 i; i < numVotesCast; ) {
 798:            //slither-disable-next-line incorrect-equality
-799:            if (voteParams_[uint256(i)].proposalId == proposalId_) {
-800:                index_ = i;
+799:            if (voteParams_[i].proposalId == proposalId_) {
+800:                index_ = int256(i);
 801:                break;
 802:            }

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/StandardFunding.sol#LL796C1-L802C14

GAS-4 Funding.sol#L130_Redundant caching variable

Use selDataWithSig twice instead of declaring a new variable tokenDataWithSig.

118:            bytes memory selDataWithSig = calldatas_[i];
...
122:            assembly {
123:                selector := mload(add(selDataWithSig, 0x20))
124:            }
...
130:            bytes memory tokenDataWithSig = calldatas_[i];
...
132:            assembly {
133:                tokensRequested := mload(add(tokenDataWithSig, 68))
134:            }

GAS-5 <x> += <y> / <x> -= <y> costs more gas than <x> = <x> + <y> / <x> = <x> - <y> for state variables

There are 11 instances.

62:        treasury += fundingAmount_;

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/GrantFund.sol#LL62C1-L62C36

320:        fromPosition.lps -= vars.lpbAmountFrom;
321:        toPosition.lps   += vars.lpbAmountTo;

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/PositionManager.sol#LL320C1-L321C46

 78:        treasury -= tokensRequested;

145:        proposal.votesReceived += SafeCast.toUint120(votesCast_);

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/ExtraordinaryFunding.sol#L78

157:        treasury -= gbc;

217:        treasury += (fundsAvailable - totalTokensRequested);

648:                existingVote.votesUsed += voteParams_.votesUsed;

673:        currentDistribution_.fundingVotePowerCast += incrementalVotingPowerUsed;

676:        proposal_.fundingVotesReceived += SafeCast.toInt128(voteParams_.votesUsed);

712:        proposal_.votesReceived += SafeCast.toUint128(votes_);

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/StandardFunding.sol#LL157C1-L157C25

#0 - c4-judge

2023-05-17T10:38:07Z

Picodes marked the issue as grade-b

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter