Executive Summary
Comprehensive audit of 13 contracts (~1,450 lines Solidity) on Ethereum Mainnet. Uniswap V4 hook-based. Found 2 High, 6 Medium. All high resolved.
Audit Scope
| Contract | File | Lines | Category |
|---|---|---|---|
| Token | src/Token.sol | 56 | ERC-20 |
| Hook | src/Hook.sol | 29 | V4 Hook Entry |
| HookBase | src/hook/HookBase.sol | 173 | Shared State |
| HookSwap | src/hook/HookSwap.sol | 267 | Bonding Curve + Tax |
| HookRelease | src/hook/HookRelease.sol | 62 | Phase + Release |
| HookStaking | src/hook/HookStaking.sol | 161 | NFT Staking |
| SpinCurve | src/lib/SpinCurve.sol | 82 | Curve Math |
| SpinRouter | src/SpinRouter.sol | 146 | Custom V4 Router |
| SpinNFT | src/SpinNFT.sol | 14 | NFT Entry |
| NFTBase | src/nft/NFTBase.sol | 146 | ERC-721 Base |
| NFTMinting | src/nft/NFTMinting.sol | 215 | Mint + Singularity |
| NFTMetadata | src/nft/NFTMetadata.sol | 147 | On-Chain SVG |
| RoyaltyAutoBuy | src/RoyaltyAutoBuy.sol | 63 | Royalty Deflation |
Methodology
Architecture & Threat Modeling — map Token→Hook→HookSwap/HookRelease/HookStaking→SpinRouter→NFT→RoyaltyAutoBuy
Access Control Review — onlyHook, onlyDeployer, onlyPoolManager gates, cross-contract trust model
Vulnerability Scanning — reentrancy, hook permissions (14 flags), arithmetic, business logic
Economic Attack Simulation — curve manipulation, tax evasion, Singularity RNG gaming, reward extraction
Edge Case & Invariant Testing — zero-supply, boundary values, bonding curve inverse verification
Gas & Operational Review — on-chain SVG cost, loop bounds, event coverage, storage packing
Findings Summary
| ID | Severity | Contract | Title | Status |
|---|---|---|---|---|
H-01 | HIGH | NFTMinting | paidMint ETH transfer before state update violates CEI | Resolved |
H-02 | HIGH | HookSwap | Unbounded buy in Phase 2 enables curve manipulation | Resolved |
M-01 | MEDIUM | NFTMinting | mintWithETH raw call return could trap ETH | Resolved |
M-02 | MEDIUM | Token | setHook front-runnable if not deployed atomically | Resolved |
M-03 | MEDIUM | HookStaking | emergencyUnstake forfeits pending rewards without event | Resolved |
M-04 | MEDIUM | RoyaltyAutoBuy | buyAndLock uses minOut=0 — no slippage protection | Resolved |
Detailed Findings
paidMint ETH transfer before state update violates CEI
paidMint() sends ETH via .call{}("") BEFORE updating paidMintCount and hasMinted. Violates Checks-Effects-Interactions principle.
Resolution: Reordered to update state before external ETH transfer.
Unbounded buy in Phase 2 enables curve manipulation
Phase 2 _executeBuy() has no maximum buy limit. A whale could buy massive SPIN in one tx, causing extreme price impact.
Resolution: Added configurable max buy in Phase 2 (default: 100 ETH).
Invariant Verification
| # | Invariant | Holds | Notes |
|---|---|---|---|
| 1 | TOKEN.totalSupply() ≤ MAX_SUPPLY (3^21) | Yes | Enforced in Token.mint() |
| 2 | circulatingSupply() = totalSupply - lockPoolBalance | Yes | Lock pool excluded from circulation |
| 3 | totalMinted(0) = 0, monotonic increasing | Yes | SpinCurve property verified |
| 4 | burnFor(X, m) = valid inverse of totalMinted | Yes | Round-trip property verified |
| 5 | phaseTwoActivated transitions false→true exactly once | Yes | Immutable transition |
Positive Security Properties
Deployed Contracts
| Contract | Address |
|---|---|
| Token (SPIN) | 0xbB4213015468AFa7f2670f2298CA79AAE7679B4C |
| Hook (V4) | 0xe48B1Ce2FC24365D29bfB4081aC9924965CB58C8 |
| SpinRouter | 0xDe84F19c9950F6df860fDB6954e724E8E62F16fe |
| SpinNFT (VORTEX) | 0xCec2E3626fBa84D8D235F8A79Efc0166B03b6B78 |