Executive Summary
Hashlock was engaged to perform a comprehensive security audit of the Clutch.AMM smart contract suite — a permissionless NFT liquidity protocol deployed on ApeChain (Chain ID 33139). The audit covered all 14 Solidity source files comprising 2,779 lines of code across the factory, market, vault, governance, router, and library modules.
The protocol enables users to create NFT-backed token markets with automated market making, NFT-collateralized lending, NFT staking for fee rewards, and on-chain governance for fee parameter adjustments. All contracts compile under Solidity 0.8.26 with the Cancun EVM target and via-IR optimization.
Finding Summary
Key Security Properties Verified
- Global solvency invariant holds under all tested scenarios (sell, buy, borrow, repay, liquidate)
- Bucket-gated token releases prevent over-issuance from any single path
- No reentrancy vulnerabilities — all external calls protected by ReentrancyGuard
- Access control correctly enforced via RBAC with least-privilege principle
- Token conservation law verified across 10 live market parameter sets
- Fee arithmetic decomposition identity holds for all fee configurations
- Liquidation incentive drain analysis confirms AMM bucket cannot be exhausted
- Interest calculations are bounded — never exceeds principal even at max APY and max duration
Audit Scope
The following table enumerates every source file included in this audit. All contracts reside undercontracts/src/ and compile with Solidity 0.8.26 (via-ir, optimizer 200 runs) targeting the Cancun EVM.
Additionally, 8 interface files under interfaces/ were reviewed for correctness. The total audited surface encompasses 2,779 SLOC of production Solidity plus 1,852 lines of test code across arithmetic audit, perpetual audit, and exploit scenario test suites.
Dependencies
Methodology
The audit followed a multi-phase approach combining automated analysis with deep manual review:
Phase 1 — Automated Analysis
- Static analysis with Slither for common vulnerability patterns (reentrancy, uninitialized storage, unchecked returns)
- Compilation verification under strict settings (via-ir, optimizer enabled, Cancun EVM)
- Dependency audit of OpenZeppelin library usage for known CVEs
- Gas optimization analysis across all state-mutating functions
Phase 2 — Manual Code Review
- Line-by-line review of all 14 source contracts and 8 interfaces
- Access control role mapping and privilege escalation analysis
- Reentrancy vector identification on all external call sites
- Arithmetic overflow/underflow analysis (Solidity 0.8+ native checks verified)
- Business logic validation against protocol specification
- Cross-contract interaction analysis (factory → deployers → vaults → escrow)
- Governance attack surface analysis (flash loan voting, proposal manipulation)
Phase 3 — Scenario Testing & Formal Verification
- Protocol arithmetic audit: 16 test categories across 6 collection sizes (5–1,000 NFTs)
- Perpetual arithmetic audit: 11 test categories replicating all 10 live ApeChain market parameters
- Exploit scenario testing: inventory poisoning, FIFO ordering correctness, double-ingest prevention
- Liquidation drain analysis: mathematical proof that AMM bucket cannot be exhausted by liquidation incentives
- Token conservation law verification after heavy mixed operations (sell, buy, borrow, stake)
Architecture Review
The Clutch.AMM protocol follows a factory-deployed market architecture. Each market deploys an isolated set of contracts sharing a single ERC-20 token and escrow reserve. The design is sound and follows established DeFi patterns.
Contract Dependency Graph
AMMFactory ├── CollectionToken (ERC20 + Permit + Burnable) ├── TokenEscrowReserve (Bucketed token release) │ ├── AMM Bucket → NFTAMMVault / ERC1155AMMVault │ ├── LOAN Bucket → LoanVault │ └── REWARD Bucket → NFTStakingVault ├── NFTAMMVault (ERC-721 swap vault) │ ├── Reads: escrow, collection, token, stakingVault │ └── Roles: PAUSER, GOVERNOR, INGEST ├── ERC1155AMMVault (ERC-1155 swap vault) ├── LoanVault (NFT-collateralized lending) │ ├── Reads: escrow, ammVault, stakingVault │ └── Calls: escrow.rebalanceBuckets, ammVault.ingestNFT ├── NFTStakingVault (Synthetix-style reward distribution) │ └── Reads: loanVault (collateral check) ├── MarketGovernor (Token-staked voting) │ └── Calls: ammVault.setFees (via governed contract) └── BatchRouter (Multi-NFT batch operations)
Architecture Strengths
- Strict separation of concerns — each vault handles exactly one function (AMM, lending, staking)
- Immutable core parameters (tokensPerNFT, totalSupply, bucketCaps, borrowAPY) prevent post-deployment tampering
- Factory deploys and immediately transfers admin to protocol admin, then renounces factory privileges
- One-time vault initialization via
vaultsInitializedflag prevents re-registration - Per-vault immutable treasury address — factory treasury changes do not retroactively affect deployed markets
- CollectionToken has no owner, no admin, no mint, no pause, no blacklist — a clean token by design
Findings & Severity Classification
Findings are classified according to the standard severity scale used in professional smart contract audits:
Access Control Analysis
All privileged operations are protected by OpenZeppelin's AccessControl with role-based separation. The following role map documents every privilege across the protocol:
Verified Properties
- Factory renounces DEFAULT_ADMIN_ROLE on all deployed contracts after transferring to protocolAdmin
- GOVERNOR_ROLE is only granted to the MarketGovernor contract (if governance enabled)
- INGEST_ROLE is only granted to the LoanVault for liquidation NFT ingestion
- Vault initialization is one-time —
vaultsInitializedflag prevents re-registration of authorized vaults - Escrow only releases tokens to addresses registered as authorized vaults — admin cannot drain
- Fee caps are enforced at the contract level (MAX_FEE_BPS = 1500, immutable) — governance cannot exceed
Reentrancy Analysis
Every state-mutating external function across all vault contracts uses OpenZeppelin's nonReentrant modifier. The following analysis covers all external call sites:
Arithmetic Safety
All contracts compile under Solidity 0.8.26 which provides native overflow/underflow protection on all arithmetic operations. The following additional arithmetic properties were verified:
Fee Decomposition Identity
// For all fee configurations: netPayout + stakerFee + protocolFee == grossPayout (sell) baseCost + stakerFee + protocolFee == totalCost (buy) // Verified across 10 live market configurations with fees ranging // from 1% to 15% and tokensPerNFT from 100e18 to 5000e18.
Interest Bounds
// For all APY and duration combinations: upfrontInterest = (principal * borrowAPYBps * duration) / (365 days * 10_000) // At maximum values (APY=50%, duration=365 days): // interest = principal * 5000 * 365d / (365d * 10000) = principal * 0.5 // → Interest never exceeds principal. Verified mathematically and via test.
Bucket Capacity Stress Test Results
Escrow Invariant Verification
The TokenEscrowReserve enforces a global solvency invariant on every token release and return:
escrow.balanceOf(escrow) + totalReleased >= totalSupply
This invariant prevents token creation from thin air. If violated, the transaction reverts withInvariantViolation. The invariant was verified to hold under all of the following scenarios:
- Market deployment (all tokens start in escrow)
- Sequential sells up to bucket cap exhaustion
- Sequential buys returning tokens to escrow
- Borrow → repay cycles (principal leaves and returns via LOAN bucket)
- Borrow → liquidate flow (LOAN bucket rebalanced to AMM bucket)
- 50-cycle perpetual sell-buy loops across all 10 live market configs
- Mixed operations: sell + buy + borrow + stake + claim in sequence
- Concurrent multi-user interactions (Alice sells, Bob buys, Charlie borrows)
Bucket Isolation
Each bucket (AMM, LOAN, REWARD) maintains independent cap and used tracking. If one bucket reaches its cap, other paths continue to function normally. The REWARD bucket cap is enforced at 0 at deployment time — all staking rewards are funded exclusively from accumulated swap fees.
Governance Security
The MarketGovernor implements token-staked voting for fee parameter adjustments. The following attack vectors were analyzed:
Flash Loan Governance Attack
Mitigated. Voting power is determined by checkpoint-based stake snapshots taken atblock.number - 1 at proposal creation time. A flash loan stake within the same block produces zero voting power since the checkpoint won't exist at the snapshot block. Additionally, a 3-day VOTE_LOCK_PERIOD prevents unstaking after voting, making borrowed-token attacks economically infeasible.
Proposal Spam
Mitigated. Three independent controls: (1) proposalFee charges tokens to the treasury, (2) 30-day PROPOSAL_COOLDOWN per proposer, (3) MAX_ACTIVE_PROPOSALS = 3 cap across the entire governor.
Fee Manipulation via Governance
Bounded. The governor can only call setFees(uint16, uint16) on the governed vault. The vault enforces MAX_FEE_BPS = 1500 (15%) as an immutable constant. Even a successful governance attack cannot set fees above 15%. The calldata is validated to exactly match the setFees selector and parameter size.
Timelock & Execution Window
Proposals require a 3-day voting period + 1-day timelock before execution, with a 7-day execution window after the timelock expires. Proposals that are not executed within the window are automatically marked as EXPIRED. This gives the community time to react to malicious proposals and the admin time to cancel via CANCELLER_ROLE.
Test Coverage & Verification
The protocol includes extensive test suites that go beyond standard unit tests into formal arithmetic verification and exploit scenario reproduction:
Key Test Categories
- Bucket allocation arithmetic — caps match BPS exactly for 6 collection sizes
- Sell fee decomposition — netPayout + stakerFee + protocolFee = grossPayout
- Buy fee decomposition — baseCost + stakerFee + protocolFee = totalCost
- Sell→Buy round-trip token conservation — all tokens accounted for
- Loan interest precision — disbursement + interest = principal exactly
- Late fee accumulation — correct calculation at grace deadline
- Liquidation incentive drain analysis — AMM bucket cannot be exhausted
- Staking reward rate precision over 7-day horizons
- Full lifecycle test (deploy → sell → buy → borrow → repay → liquidate)
- Token conservation law — sum of all balances = totalSupply after mixed ops
- Perpetual sell-buy cycles (50 iterations per market × 10 markets)
- ERC-721 inventory poisoning prevention (duplicate ingestNFT)
- ERC-1155 FIFO buy ordering correctness
Conclusion
The Clutch.AMM smart contract suite demonstrates strong security engineering across its 14-contract architecture. The protocol employs defense-in-depth with multiple overlapping safety mechanisms including a global solvency invariant, bucket-gated token releases, reentrancy guards on all state-mutating functions, immutable core parameters, and bounded fee governance.
The codebase is well-organized with clean separation of concerns, consistent coding patterns, and comprehensive test coverage including arithmetic verification across 10 live market parameter sets. The use of battle-tested OpenZeppelin libraries for access control, token standards, and security primitives further strengthens the protocol's security posture.