★ Public initialize() without initializer modifier
Balancer (v2 + v3)'s assessment for RD-F-022 — scored green on the v1.7.0 rubric. The evidence below is the curator's reasoning for this score.
Evidence summary #
v2: ComposableStablePool uses struct-based constructor (not OZ Initializable proxy); Vault uses standard constructor (Solidity 0.7.1, Etherscan exact match confirmed). No public initialize() without initializer modifier found. v3: VaultExtension has an 'initialize' function for pool initialization but it is gated by 'onlyVaultDelegateCall' modifier — callable only via the Vault's delegatecall, not as a direct public call to the implementation address. This is not equivalent to the RD-F-022 pattern (which requires no protection). No one-tx exploit vector via unprotected initialize() found in either v2 or v3.
Sources #
- GitHubv3 VaultExtension: onlyVaultDelegateCall, hardcoded delegatecallhttps://github.com/balancer/balancer-v3-monorepo/blob/main/pkg/vault/contracts/VaultExtension.solretrieved 2026-05-05
- ComposableStablePool: struct-based constructor, no OZ Initializable proxyhttps://github.com/balancer/balancer-v2-monorepo/blob/master/pkg/pool-stable/contracts/ComposableStablePool.solretrieved 2026-05-05
- v2 Vault Etherscan: constructor-based, no proxyhttps://etherscan.io/address/0xBA12222222228d8Ba445958a75a0704d566BF2C8#coderetrieved 2026-05-05
Methodology #
Determine whether any implementation contract exposes `initialize(…)` without the OpenZeppelin `initializer` modifier or equivalent initialization lock.
See the full factor methodology and distribution across all protocols →