Skip to content
This repository was archived by the owner on May 6, 2026. It is now read-only.

Add audit scorecard for Rajat staking submission#1

Merged
RolandDivine merged 1 commit into
mainfrom
codex/audit-rajat-s-staking-contract-submission-wljbt5
Mar 22, 2026
Merged

Add audit scorecard for Rajat staking submission#1
RolandDivine merged 1 commit into
mainfrom
codex/audit-rajat-s-staking-contract-submission-wljbt5

Conversation

@RolandDivine
Copy link
Copy Markdown
Member

Motivation

  • Provide a concise audit and scoring of the StakingPool submission against the original exercise requirements and document high-impact issues and recommended fixes.
  • Capture the review results as a repo artifact so the candidate and reviewers have a clear, reproducible record of findings and next steps.

Description

  • Add AUDIT.md containing a structured scorecard (79/100), a requirement-by-requirement assessment, a list of strengths, and prioritized issues with remediation suggestions.
  • The audit highlights implemented features (ERC-1363, 2-day cooldown, multisig flag, Yul math, CEI + mutex re-entrancy defenses), and calls out key gaps (unchecked uint256 -> uint128 narrowing casts, checkpoint-based oracle semantics vs per-block historical rates, and absence of a verified 100% coverage artifact).
  • Commit the audit into the repository for tracking as AUDIT.md and include the review rationale and commands used during the review (file inspections and grep/reading of tests and sources).

Testing

  • Attempted forge test -vv, forge coverage --report summary, and forge snapshot, but each command failed because the forge binary is not available in the execution environment, so unit/fuzz/invariant test runs could not be executed here.
  • Performed automated/static repository inspections using rg, sed, nl, and cat to enumerate and read relevant files (src/StakingPool.sol, test/StakingPool.t.sol, test/invariants/*, thoughts.md, GAS_REPORT.md) to validate claims and reproduce the reasoning in the audit.
  • Committed the AUDIT.md file to the repo (commit message: "Add audit scorecard for staking submission").

Codex Task

@RolandDivine RolandDivine merged commit d4e39f0 into main Mar 22, 2026
@RolandDivine RolandDivine deleted the codex/audit-rajat-s-staking-contract-submission-wljbt5 branch March 22, 2026 09:36
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9332cceb48

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread AUDIT.md
Comment on lines +60 to +65
Affected examples:
- `fundRewards()` does `rewardReserve += uint128(amount)` inside `unchecked`.
- `stake()` does `u.stakedAmount += uint128(amount)` and `totalStaked += uint128(amount)`.
- `onTransferReceived()` does the same for ERC-1363 staking.

Impact: if a caller supplies an amount above `type(uint128).max`, the token transfer can move the full amount while the pool only records the truncated lower 128 bits. That breaks reserve/accounting invariants and can strand or misaccount funds.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Cover requestWithdrawal in the truncation finding

The narrowing-cast section currently describes this as a large-token-amount problem, but requestWithdrawal() is exploitable with no large balances at all. In src/StakingPool.sol:301-325, both the sufficiency check and the stored request amount use uint128(amount), so calling requestWithdrawal(2**128) compares against zero and creates a zero-amount request even for an unstaked account, incrementing nextWithdrawalId and growing _userWithdrawalIds. Because the scorecard omits this path, it materially understates the reachability/severity of the accounting bug and makes the overall “Pass” recommendation too lenient.

Useful? React with 👍 / 👎.

Comment thread AUDIT.md
Comment on lines +106 to +107
### 6) Assembly/Yul used in withdrawal math with overflow handling
**Mostly pass.** Yul math helpers exist and have explicit overflow checks. But the contract still has unrelated narrowing-cast truncation risk elsewhere, so the overall overflow story is not perfect.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Do not credit the withdrawal Yul helpers as overflow-safe

Requirement 6 is graded as a “Mostly pass” because the Yul helpers supposedly provide overflow handling, but the withdrawal-path helper _add128 does not actually enforce a 128-bit upper bound. In src/StakingPool.sol:655-664, if lt(result, a) only detects 256-bit wraparound; type(uint128).max + 1 produces 2**128, which is then truncated when returned to Solidity. Since requestWithdrawal() relies on this helper for totalPendingWithdrawals, the submission does not meet the claimed overflow-handling bar in the withdrawal math itself.

Useful? React with 👍 / 👎.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant