Loading...

Loading
WalletGuard Audit: EVMBench: 2025-05-blackhole | Score: 3.0/10

medium(21)

low(9)
Code Quality Observations(1)
Gas Optimizations(2)

Decentralization

5 centralization points identified

*
AutoVotingEscrow.releaseLock approves msg.sender (manager), not the actual token owner

The unnecessary approve grants the manager persistent approval over released tokens, creating an elevated privilege surface. Exploitation requires a secondary compromise of the manager contract's logic.

releaseLock()
*
GaugeFactoryCL.setReferralFee has no upper bound

Duplicate of Finding 27 (FindingId 928e9e43) from a different agent perspective; same root cause and impact. Admin setting dibsPercentage at or above the denominator bricks fee collection.

setReferralFee()
*
BlackGovernor uses block.number - 1 for proposal threshold but timestamp-based voting weight_proposal()
*
GaugeCL.getReward is restricted to onlyDistribution but reward collection should be user-callable

The dependency on GaugeManager as the sole reward claim path means GaugeManager downtime or upgrade could temporarily freeze user reward access; this is a design risk without an immediate exploit path.

getReward()
*
GaugeFactoryCL.setReferralFee has no upper bound on dibsPercentage

An authorized admin setting dibsPercentage above the denominator would cause all fee claims to revert due to arithmetic underflow, effectively bricking fee collection; the risk is bounded by the access control of the setReferralFee function.

setReferralFee()

Attack Chain Analysis

Governance Takeover via Defeated Proposal Execution and Misconfigured Voting Weighthigh

Finding 5 (Governor execute() allows Defeated/Expired proposals) combines with Finding 16 (BlackGovernor uses block.number-1 as timestamp for proposal threshold). The misconfigured proposal threshold check may allow a proposer with minimal voting power to create proposals. Once a proposal is created and voted down by the community, the execute() logic error permits the attacker to execute it anyway. Together, the attacker can bypass both the proposal creation threshold and the voting outcome requirement to force arbitrary governance actions.

Governor execute() allows execution of Defeated and Expired proposalsBlackGovernor uses block.number - 1 for proposal threshold but timestamp-based voting weight
Unauthorized Gauge Creation Drains Factory Token Approvalshigh

Finding 9 (GaugeFactoryCL.createGauge has no access control) enables any attacker to call createGauge, which internally triggers createEternalFarming (Finding 11). createEternalFarming calls safeApprove for 1e10 reward tokens and transfers them to an attacker-controlled farming address if the farmingParam has been set to a malicious contract by a compromised GaugeAdmin (Finding 3). The attacker can repeatedly create gauges to drain the factory's token balance or any token allowance granted to the factory.

GaugeFactoryCL.createGauge() Missing Access Control - Anyone Can Create GaugesGaugeFactoryCL.createEternalFarming Sends 1e10 Tokens Without Authorization CheckGaugeFactoryCL.createEternalFarming sends real tokens to MockEternalFarming beneficiary via IERC20.safeApprove without validation
AutoVotingEscrow Lock Corruption via Incorrect Index Validationhigh

Finding 36 (AutoVotingEscrow.lockOwner returns wrong owner for unregistered tokens due to default index 0) combines with Finding 34 (releaseLock does not verify tokenId exists before using tokenIdIndex). An attacker or a logic bug in the manager can pass an unregistered tokenId to releaseLock, which defaults to index 0 and deletes the first registered lock. The corrupted lockOwner lookup then returns the wrong owner, potentially allowing unauthorized token release via disableAutoVoting in the manager.

AutoVotingEscrow.releaseLock does not verify tokenId exists before accessing tokenIdIndexAutoVotingEscrow.lockOwner has incorrect bounds check
Stale Reward Rate Compounded by Truncation Causes Total Reward Accounting Failurehigh

Finding 1 and Finding 17 both describe the same underlying rewardRate shadow variable bug in GaugeCL.notifyRewardAmount, causing the storage rewardRate to remain at 0. Finding 22 (uint256 to uint128 truncation) then silently truncates large reward values before passing them to the farming contract. Together, the accounting layer reports zero reward rate while simultaneously passing potentially truncated reward amounts to the farming pool, causing LP rewards to be calculated and distributed incorrectly across every epoch.

GaugeCL.notifyRewardAmount shadows state variable rewardRate with local return variableTruncation of reward/rewardRate from uint256 to uint128 in GaugeCL.notifyRewardAmount

Agent Coverage

AgentStatusFindingsSeverityConfidenceDurationCoverage
reentrancysuccess8
2H2M
79%1.6mCross-function reentrancy in GaugeCL deposit/withdraw/getReward/notifyRewardAmount/claimFees, Cross-function reentrancy in GaugeV2 deposit/withdraw/getReward/notifyRewardAmount, ERC-777 callback reentrancy via token transfers in GaugeCL and GaugeV2, Bribe contract reentrancy via notifyRewardAmount callbacks, AutoVotingEscrow lock management reentrancy, GaugeManager distribute functions for reentrancy, GaugeFactoryCL createGauge and createEternalFarming for reentrancy and logic errors, BlackClaims claimAndStakeReward for reentrancy and accounting errors, ReentrancyGuard usage verification across all contracts, CEI pattern compliance, Shadow variable analysis in GaugeCL.notifyRewardAmount, Governor execute state checks, GenesisPoolManager router update logic, VoterV3 vote/reset cross-function reentrancy, Pair.swap callback-based flash loan reentrancy (uses custom lock modifier), AutoVotingEscrowManager enableAutoVoting/disableAutoVoting reentrancy, RewardsDistributor claim reentrancy
access controlsuccess10
1H3M1L
74%1.5mAccess control on all public/external state-changing functions across all contracts, Initializer protection for upgradeable contracts (GaugeFactoryCL, AlgebraPoolAPIStorage, GaugeManager, AutoVotingEscrowManager, MinterUpgradeable), Ownership and role patterns including two-step transfers and self-grant risks, Signature verification in Pair.permit() and VotingEscrow.delegateBySig(), ecrecover return value checks, Governance execute() logic in Governor.sol and BlackGovernor.sol, Fee distribution access control in GaugeCL and GaugeV2, AutoVotingEscrow lock/release mechanics, Genesis pool manager logic including router setter, Bribe contract access control, ERC20 transfer patterns and reentrancy guards
economicsuccess11
2H2M1L
76%2.2mFlash loan attack vectors on gauge deposit/withdraw functions, Oracle manipulation - no direct price feed oracles found; Algebra pool slot0 used only for quote computation in API helpers, not for liquidation, Governance attack vectors - BlackGovernor proposal/execute flow, voting weight mechanics, quorum calculation, Flash loan governance capture - veNFT-based voting using getPastVotes with timestamp snapshots, Reward manipulation in GaugeCL and GaugeV2 - rewardRate state variable shadowing, MEV exposure in RouterV2 swap functions, Sandwich attack vectors on epoch distributions, BlackClaims reward calculation math, GenesisPoolManager logic errors including setRouter zero-address check inversion, AutoVotingEscrow manager AVM flow and lock management, MinterUpgradeable emission calculation and nudge() logic, Bribe contract reward accumulation and checkpoint logic, GaugeFactoryCL createEternalFarming seed reward sourcing, BlackGovernor execute() state machine allowing defeated/expired proposal execution, VotingEscrow delegation and balance calculation
logic validationsuccess14
3H6M2L
85%2.0mInput validation on all public/external functions, Integer overflow/underflow including unchecked blocks, State machine integrity for GenesisPool, BlackClaims seasons, governance proposals, Governance execute() state checks across both Governor implementations, Arithmetic precision in reward rate calculations, Array bounds checking in API helper contracts, Access control modifiers and role-based permissions, EIP-712 domain separator usage in VotingEscrow.delegateBySig, abi.encodePacked hash collision risks, Timestamp dependence in epoch calculations, Unbounded loops in distribution and API functions, Truncation from uint256 to uint128 in reward calculations, Router zero-address validation logic
code qualitysuccess16
1L
83%2.3mERC-20 compliance (Black token), ERC-721 compliance (VotingEscrow, Thenian), Access control on all external/public functions, Integer overflow and unsafe downcasts, Reentrancy vulnerabilities, Governance logic (BlackGovernor, L2Governor), Fee distribution logic (GaugeManager, GaugeCL, GaugeV2), Genesis pool lifecycle logic, AutoVotingEscrow lock management, Router and swap logic, Reward distribution (RewardsDistributor, Bribes), Loop bounds and array bounds, Zero address checks, Token transfer safety, Epoch and time-based logic, Proxy/upgrade safety (OwnableUpgradeable, Initializable), Cross-contract interaction patterns
compiler bugssuccess4
1H2M
81%59.6sGaugeCL deposit/withdraw/getReward/notifyRewardAmount access control and logic, GaugeFactoryCL createGauge and createEternalFarming incentive key construction, GaugeManager distribution, fee distribution, and claimRewards access control, GenesisPoolManager router setter zero-address check, Bribe deposit/withdraw/getReward/notifyRewardAmount logic, VoterV3 vote/reset/poke access control and epoch gating, MinterUpgradeable nudge and update_period logic, AutoVotingEscrowManager enableAutoVoting/disableAutoVoting token custody, BlackClaims season finalization and claim logic, RewardsDistributor claim and checkpoint_token logic, Variable shadowing in GaugeCL.notifyRewardAmount (rewardRate), Compiler bug patterns (pragma 0.8.13 - not in any known affected range for listed bugs), Integer overflow/underflow in unchecked blocks, Reentrancy guard coverage across all state-mutating functions, Emergency mode activation/deactivation consistency
assembly safetysuccess12
1H2M2L
81%2.1mAll assembly{} blocks scanned - Base64.sol contains assembly for base64 encoding (standard pattern, no issues), VotingEscrow.sol safeTransferFrom contains assembly revert (standard OZ pattern), no other assembly blocks found, Full codepoint-by-codepoint scan for non-ASCII characters in identifiers, comments, and string literals - no non-ASCII characters found, Invisible character attacks (RTLO U+202E, zero-width joiners U+200D/200B/200C, Cyrillic homoglyphs) - none detected, Keyword obfuscation (lookalike assembly/selfdestruct/delegatecall identifiers) - none detected, Governance logic in BlackGovernor and L2Governor execute() state checks, GaugeCL reward distribution and notifyRewardAmount logic, GaugeFactoryCL access control and createEternalFarming, AutoVotingEscrow lock management and releaseLock, GenesisPoolManager router setter, BlackClaims reward claiming math, GaugeV2 withdrawal and balance deduction logic, Bribe reward claiming access patterns, Integer truncation in uint128 casts, Zero-address guard correctness across all setter functions, Reentrancy patterns across all nonReentrant-guarded functions, Storage variable shadowing in return parameters
l2 specificsuccess13
2H4M2L
84%2.0mGovernor.sol execute() and propose() flow for proposal state logic, GaugeCL.sol notifyRewardAmount for variable shadowing, GaugeFactoryCL.sol access control on createGauge, GaugeV2.sol and GaugeCL.sol for access control, fee logic, and input validation, BlackClaims.sol for reward accounting logic, AutoVotingEscrow.sol and AutoVotingEscrowManager.sol for ownership tracking, GenesisPoolManager.sol for router setter logic, MinterUpgradeable.sol for emission calculation and nudge logic, VoterV3.sol for voting window and AVM checks, TradeHelper.sol for loop bounds and integer underflow, BlackTimeLibrary.sol for epoch duration configuration, GaugeFactoryCL.sol for fee bounds checking, RewardsDistributor.sol for claim logic and balance accounting, Bribes.sol for deposit/withdraw and reward distribution logic, VotingEscrow.sol for lock mechanics and delegation, PairFactory.sol and Pair.sol for AMM safety, RouterV2.sol for swap routing and access control, GaugeManager.sol for distribution logic and governance

Scope and Methodology

Target0xaaa8d96a31fea8e3aeec964815abebe30491e2da
ChainEthereum
Complexitycomplex
Standards DetectedERC20, ERC721, ERC721Metadata
Analysis ModelClaude Sonnet 4.6
Specialist Agents9
Agent Types
reentrancyaccess controleconomiclogic validationcode qualitycompiler bugsassembly safetyl2 specific
Scope TemplateNFT/Marketplace (auto-selected)
MethodologyAutomated multi-agent analysis. Each specialist agent independently reviews the contract source code for vulnerabilities in its domain. Findings are deduplicated, scored, and synthesized into this report.
Findings are gated by demonstrated exploit feasibility against the analyzed contract. Observations that describe accepted blockchain behavior, consensus-layer issues, or infeasible preconditions are excluded from scored findings. See scope policy.

Severity Classification

CriticalDirect loss of funds or complete protocol compromise. Exploitable with high likelihood. Requires immediate remediation.
HighSignificant risk to funds or protocol integrity. Conditionally exploitable or requires specific circumstances. Should be fixed before deployment.
MediumLimited or conditional impact. May require unlikely conditions to exploit. Should be addressed but not blocking.
LowMinor impact. Best practice deviations, minor inefficiencies. Fix when convenient.
InformationalNo direct security impact. Code quality observations, gas optimizations, style recommendations.

Limitations

This automated audit has inherent limitations. The following areas are not covered.

Disclaimer

This report is an automated point-in-time assessment and does not guarantee protection against all possible attacks. It does not cover off-chain components, economic modeling, or business logic correctness unless explicitly noted. Changes to the contract after the audit commit are not reviewed. This is not financial or legal advice. WalletGuard, powered by Gestalt Labs, provides this analysis as-is with no warranty of completeness.

Embed Badge
WalletGuard Audit Badge
Markdown
[![WalletGuard Audit](https://walletguard.ai/api/badge/cc944a7f-4a16-4eb6-bc87-3e29f8c74f68)](https://walletguard.ai/audit/cc944a7f-4a16-4eb6-bc87-3e29f8c74f68)
HTML
<a href="https://walletguard.ai/audit/cc944a7f-4a16-4eb6-bc87-3e29f8c74f68">
  <img src="https://walletguard.ai/api/badge/cc944a7f-4a16-4eb6-bc87-3e29f8c74f68" alt="WalletGuard Audit Badge" />
</a>
WalletGuardSecured by WalletGuard
How We AuditView all reports for this contractUID: 0x8aaaebe4...101850This report was produced by generic vulnerability pattern matching.
Modelsonnet
Duration6.3m
CostN/A
Tokens- in / - out
Source verified via Etherscan