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: 75/114
Findings: 2
Award: $51.82
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: aviggiano
Also found by: 0xSmartContract, 0xTheC0der, 0xcm, ABAIKUNANBAEV, Audinarey, Audit_Avengers, BGSecurity, Bauchibred, Dug, Evo, Haipls, Jerry0x, TS, bytes032, devscrooge, kenta, ladboy233, mrvincere, patitonar, sakshamguruji, tsvetanovv
15.5756 USDC - $15.58
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol#L815
Likelihood:
Medium, because it requires rewardsEarned_ > ajnaBalance
Impact:
Medium, because accounting might be wrong, which may lead to loss of funds for the ajnaToken or for the user, and unnecessary actions to perform _updateBucketExchangeRates
and _updateBucketExchangeRateAndCalculateRewards
would be executed anyways
Such implementation is in contrast with programming best practices and it'll force unnecessary additional actions to execute _updateBucketExchangeRates
and _updateBucketExchangeRateAndCalculateRewards
and can even lead to loss of funds in edge case scenarios.
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol#L815
Manual Review
The first choice is to redesign the logic to store the currently up-to-date users' rewards in the storage variable and perform calculations on it. Then if rewardsEarned_ > ajnaBalance
check is true, you can subtract the user rewards with ajnaBalance in storage and execute the transfer.
The second choice is to simply revert the transaction in case rewardsEarned_ > ajnaBalance
, to prevent unexpected behavior.
Invalid Validation
#0 - c4-judge
2023-05-18T16:14:51Z
Picodes marked the issue as duplicate of #361
#1 - c4-judge
2023-05-29T20:55:44Z
Picodes changed the severity to 3 (High Risk)
#2 - c4-judge
2023-05-29T21:00:41Z
Picodes marked the issue as satisfactory
🌟 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
Ajna QA report was done by martin and anonresercher, with a main focus on the low severity and non-critical security aspects of the implementaion and logic of the project.
The following issues were found, categorized by their severity:
ID | Title | Severity |
---|---|---|
[L-01] | Hardcoded Ajna token address | Low |
[L-02] | Function logic is misleadingly documented | Low |
[L-03] | Redundant parameter reason in IFunding.VoteCast event | Low |
[NC-01] | emit function called early | Non-Critical |
[NC-02] | Bad formatting | Non-Critical |
In case the addresses change due to reasons such as updating their versions in the future, addresses coded as constants cannot be updated. You can have a immutable
variable containing the token address. And this variable can be set from a constructor.
So you can effectively pass the value from an environment variable to the contract constructor, to the contract storage.
21: address public immutable ajnaTokenAddress = 0x9a96ec9B57Fb64FbC60B423d1f4da7691Bd35079;
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/Funding.sol
The Nat Spec dev description assures that the function will iterate through maximum of 10 proposals, but actually it iterates through all of them in a nested loop.
458: * @dev Only iterates through a maximum of 10 proposals that made it through the screening round.
reason
in IFunding.VoteCast
eventThe reason
parameter is set value as an empty string everywhere where event IFunding.VoteCast
is emitted and should therefore be removed, because there is no use for it
/ajna-grants/src/grants/interfaces/IFunding.sol 69: event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason);
There are 3 instances of set reason
value as an empty string:
emit
function called earlyThe event is actually emitted before the action, event emits should be moved after the action. Otherwise, it might cause an incorrectly emitted event.
59: emit ProposalExecuted(proposalId_);
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/Funding.sol
In case safeTransfer
fails the DelegateRewardClaimed
event would still be called.
In case safeTransferFrom
fails the FundTreasury
event would still be called.
https://github.com/code-423n4/2023-05-ajna/blob/ main/ajna-grants/src/grants/GrantFund.sol#L64
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol#L299
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol#L585
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/Funding.sol
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/StandardFunding.sol
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/GrantFund.sol
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/PositionManager.sol
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol
#0 - c4-judge
2023-05-18T18:59:16Z
Picodes marked the issue as grade-b