SWEEP SUMMARY
0
CRITICAL
3
HIGH
3
MEDIUM
1
LOW
Primary attack surface: ChainlinkLikeWstethPriceFeed · GatedRedemptionQueueSharesWrapperLib · SharePriceThrottledAssetManagerLib · SingleAssetDepositQueueLib
Deep scan: subagent running · additional diamonds expected
GitHub issues mined: 100/~1065 total · Issue #1061 (state variable) confirmed LOW
Deep scan: subagent running · additional diamonds expected
GitHub issues mined: 100/~1065 total · Issue #1061 (state variable) confirmed LOW
DIAMONDS · V14 SWEEP
7 findings · click to expand
ENZYME-FIND-001
ChainlinkLikeWstethPriceFeed — Missing Round Completeness Check
HIGH
ContractChainlinkLikeWstethPriceFeed.sol
FunctionlatestRoundData()
γ₁ StratumT3 · 14.13s · oracle heartbeat mismatch
AdelicL1 · weight = γ₁/2 = 7.067
ImpactStale price from incomplete round used for fund NAV; arb on deposits/redemptions
// VULNERABLE — answeredInRound discarded
(, ethPerStethAnswer, startedAt_, updatedAt_,) =
STETH_ETH_CHAINLINK_AGGREGATOR.latestRoundData();
// No: require(answeredInRound >= roundId, "Stale price")
Joffe-MathTemporal Consistency Theorem — fund NAV must use temporally consistent oracle data
⚖ Adelic weight 7.067 · T3 stratum · KCF-SRCH-001
ENZYME-FIND-002
ChainlinkLikeWstethPriceFeed — No Heartbeat Staleness Validation
HIGH
ContractChainlinkLikeWstethPriceFeed.sol
FunctionlatestRoundData()
γ₁ StratumT5 · 11.09h · 24h staleness threshold
ImpactSplit-oracle: Lido rate fresh, Chainlink price stale → composite wstETH price incorrect
// MISSING: heartbeat check
// updatedAt_ passed through from stETH/ETH Chainlink feed
// stethPerWsteth is ALWAYS fresh (Lido on-chain)
// → composite answer_ = stale_eth_price × fresh_lido_rate
// updatedAt_ < block.timestamp - 86400 → STALE but unchecked
require(block.timestamp - updatedAt_ <= MAX_STALENESS, "Stale");
// ← this line is MISSING
ChainsEthereum mainnet (wstETH is primary)
⚖ Adelic weight 7.067 · T5 stratum · KCF-SRCH-001
ENZYME-FIND-003
GatedRedemptionQueue — Full Approval Deleted on Partial requestRedeem
MEDIUM
ContractGatedRedemptionQueueSharesWrapperLib.sol
FunctionrequestRedeem(uint256 _sharesAmount)
γ₁ StratumT1 · 1s · SOSTLE gate check
ImpactUser loses unspent redemption approval; must request new approval from manager; queue priority lost
if (redemptionApproval != type(uint256).max) {
require(_sharesAmount <= redemptionApproval, "...");
delete userToRedemptionApproval[msg.sender]; // ← FULL DELETE
// BUG: should be:
// userToRedemptionApproval[msg.sender] -= _sharesAmount;
}
⚖ Adelic weight 14.13 (L0) · T1 stratum · KCF-SRCH-003
ENZYME-FIND-004
GatedRedemptionQueue — depositMode Silent Default for Legacy Proxies
MEDIUM
ContractGatedRedemptionQueueSharesWrapperLib.sol
Functioninit() / deposit()
γ₁ StratumT1 · state machine gap
ImpactOperators who intend RequestAndApprove mode but pass _depositMode=0 get Direct mode silently — approval gate bypassed
// Base1 comment: "added after the 1st version: depositMode"
// For all proxies where init() called without _depositMode param,
// depositMode = DepositMode(0) = Direct
// deposit() works without RequestAndApprove gate
// → approval workflow intention bypassed silently
⚖ Adelic weight 7.067 · T1 stratum · KCF-SRCH-003
ENZYME-FIND-005
SharePriceThrottledAssetManager — N-Instance Throttle Multiplication
HIGH
ContractSharePriceThrottledAssetManagerLib.sol
FunctionexecuteCalls() / __validateAndUpdateThrottle()
γ₁ StratumT4 · 47min · proof cycle / throttle window
ImpactVault with N throttled managers can lose N × lossTolerance atomically — protocol assumes single manager per throttle instance
// Each instance has independent throttle.cumulativeLoss
// Contract designed to LIMIT loss to lossTolerance per period
// But N authorized instances = N × lossTolerance drainable
// Attack:
// 1. Attacker controls vault owner key
// 2. Vault has 5 authorized SharePriceThrottled managers
// 3. Each has lossTolerance=10%
// 4. Execute drain on all 5 simultaneously → 50% fund drained
// vs intended max of 10%
Joffe-MathAdditive Security Theorem — N independent throttles ≠ bounded by single tolerance
⚖ Adelic weight 2.83 (L3) · T4 stratum · KCF-SRCH-008 RISK
ENZYME-FIND-006
SingleAssetDepositQueue — Cancel in Same Block when minRequestTime=0
LOW
ContractSingleAssetDepositQueueLib.sol
FunctionaddDepositRequest() / cancelRequest()
γ₁ StratumT0 · 70.7ms · flash loan / same-block window
ImpactMEV: add request, observe manager tx, cancel before deposit executes. Gas grief on queue processors.
// canCancelTime = block.timestamp + minRequestTime
// If minRequestTime = 0:
// canCancelTime = block.timestamp ← can cancel immediately
// Same-block add + cancel = no-cost queue spam
⚖ Adelic weight 14.13 (L0) · T0 stratum · KCF-SRCH-003
ENZYME-FIND-007
GatedRedemptionQueue — Manager Can Skip Queue Entries (FIFO Not Enforced)
MEDIUM
ContractGatedRedemptionQueueSharesWrapperLib.sol
FunctionredeemFromQueue(startIndex, endIndex)
γ₁ StratumT4 · 47min · redemption window
ImpactManager can process later queue entries and skip earlier entrants within a window — principled FIFO violated
// Manager calls redeemFromQueue(50, 100) skipping users 0-49
// Users 0-49: NOT redeemed this window
// Users 50-100: redeemed
// Users 0-49 CANNOT cancel during window, CANNOT re-queue
// Trapped until next window (frequency-based delay)
NoteContract states: "Holders must fully trust vault owner" — may be acknowledged design
⚖ Adelic weight 7.067 · T4 stratum · KCF-SRCH-002
POC FORGE STATUS
POC-ENZYME-001
ChainlinkWsteth round completeness — fork mainnet
DRAFTING
POC-ENZYME-002
Staleness bypass — freeze Chainlink at block T
DRAFTING
POC-ENZYME-003
Approval wipe — unit test requestRedeem partial
READY
Foundry: forge 1.7.1 · Alchemy RPC: eth-mainnet.g.alchemy.com
Run:
Run:
cd bounty-hunting/poc-forge && forge test --match-contract EnzymeBlue
γ₁ STRATUM MAP
T0
70.7ms
FIND-006
T1
1.000s
FIND-003
FIND-004
T2
14.13s
MEV sandwich
T3
3.33min
FIND-001
T4
47.07min
FIND-005
FIND-007
T5
11.09h
FIND-002
T6
6.53d
long-range
ADELIC V14 BONIXER
| Finding | Layer | Weight |
|---|---|---|
| FIND-003 | L0 | 14.13 |
| FIND-001 | L1 | 7.07 |
| FIND-002 | L1 | 7.07 |
| FIND-007 | L1 | 7.07 |
| FIND-004 | L1 | 7.07 |
| FIND-006 | L0 | 14.13 |
| FIND-005 | L3 | 2.83 |
KCF SCAN RESULTS
KCF-SRCH-001Oracle staleness2 hits
KCF-SRCH-002Access control asymmetry1 hit
KCF-SRCH-003State machine gaps3 hits
KCF-SRCH-008Multi-instance risk1 hit
KCF-SRCH-013Math precision1 hit
KCF-SRCH-004Reentrancy0 hits
KCF-SRCH-005Flash loan0 hits
KCF-SRCH-009Integer overflow0 hits
SCOPE
CONTRACTS
~250
SOL FILES
361
CHAINS
ETH·ARB·BASE·POLY
GH ISSUES
1065
Primary repos: enzymefinance/protocol (dev branch) · 361 .sol files
Subagent deep scan: running · ETA 5-10min
Subagent deep scan: running · ETA 5-10min
SUBMISSION PIPELINE
FIND-001 roundId check
POC NEEDED
FIND-002 staleness
POC NEEDED
FIND-003 approval wipe
POC READY
FIND-005 multi-throttle
REVIEWING