fix: cap endorsements to prevent endorsement-loop DoS#82
Conversation
WalkthroughThe changes implement a maximum endorsement limit by introducing a public constant Changes
Possibly related PRs
Suggested labels
Poem
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/IdentityToken.sol`:
- Line 15: Add a getter declaration for the MAX_ENDORSEMENTS constant to the
IIdentityToken interface so external callers compiled against the interface can
read the cap; specifically add a function signature matching the public constant
getter (function MAX_ENDORSEMENTS() external view returns (uint256)) to
IIdentityToken (referencing MAX_ENDORSEMENTS and IIdentityToken) and ensure the
interface compiles with that new declaration.
In `@test/IdentityToken.t.sol`:
- Around line 298-305: The test uses a hardcoded cap of 100 when filling
endorsements; replace that literal with the contract constant by querying
identityToken.MAX_ENDORSEMENTS() into a uint256 (e.g., max) and loop for
(uint256 i = 0; i < max; i++) calling identityToken.endorse(...), then expect
the revert when calling identityToken.endorse with index equal to max
(Errors.IndexOutOfBounds.selector). Update references to the hardcoded 100 to
use max and keep aliceId, bobId, identityToken.endorse, and
Errors.IndexOutOfBounds.selector intact.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 9ea1256f-b613-49a9-84aa-733e011e27ff
📒 Files selected for processing (2)
src/IdentityToken.soltest/IdentityToken.t.sol
| error NonTransferable(); | ||
|
|
||
| uint256 private _nextTokenId = 1; | ||
| uint256 public constant MAX_ENDORSEMENTS = 100; |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Expose the cap in IIdentityToken for typed integrators.
Consider adding the getter signature to the interface so clients compiled against IIdentityToken can discover the limit without implementation coupling.
♻️ Suggested interface addition
diff --git a/src/interfaces/IIdentityToken.sol b/src/interfaces/IIdentityToken.sol
@@
interface IIdentityToken is IERC721, IERC721Metadata {
+ function MAX_ENDORSEMENTS() external view returns (uint256);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/IdentityToken.sol` at line 15, Add a getter declaration for the
MAX_ENDORSEMENTS constant to the IIdentityToken interface so external callers
compiled against the interface can read the cap; specifically add a function
signature matching the public constant getter (function MAX_ENDORSEMENTS()
external view returns (uint256)) to IIdentityToken (referencing MAX_ENDORSEMENTS
and IIdentityToken) and ensure the interface compiles with that new declaration.
| for (uint256 i = 0; i < 100; i++) { | ||
| vm.prank(alice); | ||
| identityToken.endorse(aliceId, bobId, keccak256(abi.encodePacked("Connection", i)), 0); | ||
| } | ||
|
|
||
| vm.prank(alice); | ||
| vm.expectRevert(Errors.IndexOutOfBounds.selector); | ||
| identityToken.endorse(aliceId, bobId, keccak256(abi.encodePacked("Connection", uint256(100))), 0); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Avoid hardcoded cap values in the boundary test.
Use identityToken.MAX_ENDORSEMENTS() to keep the test aligned if the cap changes.
♻️ Suggested test update
- for (uint256 i = 0; i < 100; i++) {
+ uint256 maxEndorsements = identityToken.MAX_ENDORSEMENTS();
+ for (uint256 i = 0; i < maxEndorsements; i++) {
vm.prank(alice);
identityToken.endorse(aliceId, bobId, keccak256(abi.encodePacked("Connection", i)), 0);
}
vm.prank(alice);
vm.expectRevert(Errors.IndexOutOfBounds.selector);
- identityToken.endorse(aliceId, bobId, keccak256(abi.encodePacked("Connection", uint256(100))), 0);
+ identityToken.endorse(
+ aliceId,
+ bobId,
+ keccak256(abi.encodePacked("Connection", maxEndorsements)),
+ 0
+ );📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| for (uint256 i = 0; i < 100; i++) { | |
| vm.prank(alice); | |
| identityToken.endorse(aliceId, bobId, keccak256(abi.encodePacked("Connection", i)), 0); | |
| } | |
| vm.prank(alice); | |
| vm.expectRevert(Errors.IndexOutOfBounds.selector); | |
| identityToken.endorse(aliceId, bobId, keccak256(abi.encodePacked("Connection", uint256(100))), 0); | |
| uint256 maxEndorsements = identityToken.MAX_ENDORSEMENTS(); | |
| for (uint256 i = 0; i < maxEndorsements; i++) { | |
| vm.prank(alice); | |
| identityToken.endorse(aliceId, bobId, keccak256(abi.encodePacked("Connection", i)), 0); | |
| } | |
| vm.prank(alice); | |
| vm.expectRevert(Errors.IndexOutOfBounds.selector); | |
| identityToken.endorse( | |
| aliceId, | |
| bobId, | |
| keccak256(abi.encodePacked("Connection", maxEndorsements)), | |
| 0 | |
| ); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@test/IdentityToken.t.sol` around lines 298 - 305, The test uses a hardcoded
cap of 100 when filling endorsements; replace that literal with the contract
constant by querying identityToken.MAX_ENDORSEMENTS() into a uint256 (e.g., max)
and loop for (uint256 i = 0; i < max; i++) calling identityToken.endorse(...),
then expect the revert when calling identityToken.endorse with index equal to
max (Errors.IndexOutOfBounds.selector). Update references to the hardcoded 100
to use max and keep aliceId, bobId, identityToken.endorse, and
Errors.IndexOutOfBounds.selector intact.
Addressed Issues:
Fixes #68
MAX_ENDORSEMENTS = 100insrc/IdentityToken.sol.endorse()to revert withErrors.IndexOutOfBounds()when the cap is reached.test_RevertIf_MaxEndorsementsReached()intest/IdentityToken.t.solto verify the 101st endorsement reverts.Screenshots/Recordings:
TODO: If applicable, add screenshots or recordings that demonstrate the interface before and after the changes.
Additional Notes:
AI Usage Disclosure:
We encourage contributors to use AI tools responsibly when creating Pull Requests. While AI can be a valuable aid, it is essential to ensure that your contributions meet the task requirements, build successfully, include relevant tests, and pass all linters. Submissions that do not meet these standards may be closed without warning to maintain the quality and integrity of the project. Please take the time to understand the changes you are proposing and their impact. AI slop is strongly discouraged and may lead to banning and blocking. Do not spam our repos with AI slop.
Check one of the checkboxes below:
I have used the following AI models and tools: TODO
Checklist
Summary by CodeRabbit
Release Notes
New Features
Tests