Guardian's review of LCC Leveraged Fund Helper Review for 3Jane, published November 2026. The report records 3 findings, including 3 informational.
- Published
- Review window
- October 19 to 27, 2026
- Language
- Solidity
- Chains
- Ethereum
- Sector
- Lending
- 0 Critical
- 0 High
- 0 Medium
- 0 Low
- 3 Informational
Scope
2 files in scope · 677 nSLOC
| File | nSLOC | Lines |
|---|---|---|
src/lcc/interfaces/ILCCLeveragedFundHelper.sol | 101 | 343 |
src/lcc/LCCLeveragedFundHelper.sol | 576 | 840 |
Findings 3
-
I-01 Informational A skipped permit stays replayable until its deadline Documentation Resolved
Description
fundWithSignaturesdoes not submit the USDC permit when the contribution is zero, and does not submit the margin permit when no margin is used. The signature is still in the transaction.The notice says signatures the helper does not apply "are ignored and may be zeroed." That allows an empty signature. It does not say what a non-zero leftover does. The signature stays valid until its own deadline. Anyone can submit it once. That spends the nonce, so the same signature cannot be used again, and it sets the caller's allowance to the helper to the signed value. A later
approvecan raise it. Until the deadline, that old signature can still fire once and put the allowance back.The sentence about a third party submitting the same signature first is a different case. It covers a permit the helper does try to submit. If that permit was already applied and the allowance covers the pull, the helper tolerates the revert. A permit the helper never submits is not that case.
Recommendation
State that a non-zero signature the helper does not submit stays replayable until its deadline. The caller should zero that field or give it a short deadline. Do not submit every attached permit.
Resolution
3Jane Team: Acknowledged and fixed in documentation (a21efbc8). The
fundWithSignaturesnotice now states that a signature the call does not apply is not submitted and stays unused: anyone can submit a nonzero one once until its deadline, restoring the allowance or Morpho authorization it signs for the helper. This covers the USDC permit on a zero contribution, the margin permit without margin, and the Morpho authorization when the caller is already authorized. The helper pulls and borrows only formsg.sender, so this serves only the caller's own later calls; callers should zero an unneeded signature or give it a short deadline. The front-running sentence is now scoped to submitted signatures. -
I-02 Informational Consider an award-share burn cap for takeAuction margin recycling economic Resolved
Description
takeAuction withdraws the requested USDC from newly awarded margin shares without a caller-defined share-burn cap; minMarginAward protects the gross award, not the retained remainder. Unlike fund, it passes type(uint256).max as the withdrawal's maxShares. Both fork tests pass, demonstrating the API difference using a bespoke ERC4626 with explicit loss/recovery methods. They do not establish a reachable exploit against current intended margin assets. The behavior matches the documented interface, and conversion is fair value at execution.
Impact: No current supported-asset exploit, execution-time value loss or violated existing bound is established. With a future declining-rate USDC margin asset, callers could not independently bound shares sold for their fixed-USDC contribution. Burns remain bounded by the newly received award; the demonstrated opportunity cost additionally assumes subsequent recovery.
Recommendation
Document that marginAssets requests a fixed-USDC sale at the execution rate and minMarginAward is gross. Before supporting declining-rate USDC margin assets, consider a scaled maxMarginShares or minimum retained-award bound.
Resolution
3Jane Team: Acknowledged; documented in 4d7eaf79. The TakeParams docs now state that a nonzero marginAssets is a fixed-USDC withdrawal from the award at the margin asset's conversion rate at execution, with shares burned bounded only by the award received in that take (MarginSharesUnavailable) and no caller-set share bound, and that minMarginAward bounds the gross award, not the remainder forwarded to the caller. Margin sourcing requires a margin asset whose asset() is USDC (LCCLeveragedFundHelper.sol:899-907), which today is waEthUSDC only. Before admitting a USDC margin asset whose rate can decline, we will revisit a scaled maxMarginShares or retained-award bound.
-
I-03 Informational maxUnwindable can count a Morpho market the helper cannot unwind Documentation Resolved
Description
maxUnwindablereturns how many shares a user can unwind in a market. While the USD3l cooldown is on, that amount is the smaller of the user's Morpho collateral and the helper's matured cooldown shares for that market id. A market the helper never used has an empty book, so the result is zero.While the cooldown is waived, the read skips the book and returns the user's whole Morpho collateral for the id it was given. The waiver is a USD3l shutdown, or a cooldown length of zero. This deployment cannot set the length to zero. Shutdown is the switch, and only USD3l management or the emergency admin can turn it on.
unwindrejects a market whose loan token is not USDC or whose collateral token is not USD3l. The read does not make that check. After shutdown, an id where the user has some other Morpho position returns a positive number, andunwindof that market reverts.The notice calls the result a ceiling by the cooldown gate and live collateral. It says USD3's withdraw limit and Morpho's health check are not included. It does not promise that
unwindwill succeed, and it does not say the id must be a USDC/USD3l market. No cooldown credit is created, and the wrong market withdraws nothing.Recommendation
Document that
marketIdmust be a market on the pinned Morpho whose loan token is USDC and whose collateral token is USD3l. While the cooldown is waived, any other id can return that position's collateral even thoughunwindreverts. Alternatively, read the Morpho market data from the market id and return zero for any other pair.Resolution
3Jane Team: Acknowledged; documented in 4d7eaf79. The maxUnwindable notice now states that marketId is meant to be a market on the pinned Morpho lending USDC against USD3l (the markets unwind accepts), which the view does not check: while the USD3l cooldown is waived (shutdown or zero cooldownDuration) it returns the user's whole collateral for any market id, including one unwind rejects, and outside a waiver a market with no booked cooldowns returns zero. We kept the view unchanged rather than adding a Morpho market-params read, since an off-market result withdraws nothing and creates no cooldown credit.
No findings match.
More from 3Jane
Put your code through the same review.
This review started with a conversation about scope. Tell us what you are building and we will plan yours with you.
