{"id":1227,"date":"2025-12-10T12:05:16","date_gmt":"2025-12-10T10:05:16","guid":{"rendered":"https:\/\/ackee.xyz\/blog\/?p=1227"},"modified":"2026-03-20T16:35:29","modified_gmt":"2026-03-20T14:35:29","slug":"wake-arena-multi-agent-ai-audit-with-graph-driven-reasoning","status":"publish","type":"post","link":"https:\/\/ackee.xyz\/blog\/wake-arena-multi-agent-ai-audit-with-graph-driven-reasoning\/","title":{"rendered":"Wake Arena: Multi-Agent AI Audit with Graph-Driven Reasoning"},"content":{"rendered":"<h1><strong>Wake Arena: Multi-Agent AI Audit with Graph-Driven Reasoning<\/strong><\/h1>\n<p><strong>Benchmarked on audit competitions and production protocols<\/strong><\/p>\n<p>December 2025:<\/p>\n<p>Josef Gattermayer, Ph.D.<sup>1,2<\/sup><br \/>\nMichal P\u0159evr\u00e1til<sup>1<\/sup><br \/>\nMartin Vesel\u00fd<sup>1<\/sup><br \/>\nAndrei Shchapaniak<sup>1<br \/>\n<\/sup>Josef Bazal<sup>1<\/sup><\/p>\n<p><sup>1<\/sup><em>Ackee Blockchain<\/em><br \/>\n<sup>2<\/sup><em>Czech Technical University in Prague<\/em><\/p>\n<hr \/>\n<h2><strong>Executive Summary<\/strong><\/h2>\n<p>We present <a href=\"https:\/\/ackee.xyz\/wake\/arena\">Wake Arena<\/a>, a service for discovering vulnerabilities in Solidity smart contracts through multi-agent AI analysis with graph-driven reasoning.<\/p>\n<p>Wake Arena 3.1 discovered <strong>63 of 94 critical\/high-severity vulnerabilities<\/strong> in historical audit competitions, outperforming Zellic&#8217;s automated scanner V12 (41\/94), GPT-5.2 xhigh (41\/94), plain GPT-5 (24\/94), and plain Opus 4.5 (21\/94). When experimentally integrated into Ackee&#8217;s manual audit workflow in November 2025 for Lido, Printr, and Everstake, Wake Arena identified 26 findings.<\/p>\n<p>Specifically, Wake Arena discovered <strong>5 critical vulnerabilities and 5 unique findings beyond those discovered by human auditors during the <a href=\"https:\/\/github.com\/Ackee-Blockchain\/public-audit-reports\/blob\/master\/2025\/ackee-blockchain-printr-protocol-report.pdf\">Printr<\/a> audit<\/strong>.<\/p>\n<p>Additionally, LUKSO served as a design partner, providing valuable feedback during development. In a purely AI-driven audit, Wake Arena identified <strong>10 findings<\/strong> (2 High, 6 Medium, 1 Low, 1 Warning), with <strong>only two false positives<\/strong>. LUKSO&#8217;s responses and validation helped refine the service&#8217;s accuracy and user experience.<\/p>\n<p>Metrics across benchmarks and production audits:<\/p>\n<ul>\n<li>51.4% of all reported findings and 50%+ of critical findings discovered<\/li>\n<li>False positive rate below 30%<\/li>\n<li>True positive rate above 70%<\/li>\n<\/ul>\n<p>Unlike generic LLM wrappers, Wake Arena combines multi-agent AI reasoning, graph-driven analysis via Data Dependency and Control Flow graphs, and LLM-tailored static analysis from 200+ audits securing $180B+ in TVL.<\/p>\n<hr \/>\n<h2><strong>Background and Motivation<\/strong><\/h2>\n<p>Ackee Blockchain has conducted 200+ smart contract audits securing $180B+ in TVL (Lido, Aave, Axelar, Safe). As AI capabilities for code analysis have advanced, we built Wake Arena to leverage these capabilities while maintaining low false positive rates.<\/p>\n<p>Wake Arena is a multi-agent AI system combining our private detector library (87 from billion-dollar audits) with deep AI-driven security reasoning that navigates Data Dependency Graphs like a senior auditor. LLM-tailored static analysis feeds deep code insights into a full AI-driven audit pipeline with graph-driven reasoning and contextual understanding from years of auditing expertise.<\/p>\n<h3><strong>Problem statement<\/strong><\/h3>\n<p>Teams need a consistent, powerful security tool that reliably finds important vulnerabilities before premium audits, helping protocols arrive with cleaner code and use audit time for deep protocol logic review. We want to help teams reduce reliance on surface-level tools while recognizing that high-quality manual audits remain essential for critical systems.<\/p>\n<hr \/>\n<h2><strong>What Makes Wake Arena Different<\/strong><\/h2>\n<h3><strong>1. Multi-agent AI system<\/strong><\/h3>\n<p>A multi-step prompt pipeline combines:<\/p>\n<ul>\n<li>Advanced reasoning and validation with multi-agent cross-checking<\/li>\n<li>Deep contextual understanding from senior auditor expertise embedded in prompts<\/li>\n<li>Full AI-driven audit pipeline from compilation to report generation<\/li>\n<\/ul>\n<h3><strong>2. Graph-driven reasoning<\/strong><\/h3>\n<p>LLM-tailored Static Analysis with Data Dependency and Control Flow graphs navigates the code to find:<\/p>\n<ul>\n<li>Protocol-specific logical issues by tracing execution paths<\/li>\n<li>Mathematical vulnerabilities through value flow analysis<\/li>\n<li>Cross-function dependencies missed by pattern matching<\/li>\n<\/ul>\n<p><strong>Example:<\/strong> In the Lend protocol, Wake Arena traced how a deeply nested bug in <code class=\"codehl\">LendStorage.borrowWithInterest<\/code> affects <code class=\"codehl\">CoreRouter<\/code> and <code class=\"codehl\">CrossChainRouter<\/code> logic through <code class=\"codehl\">getHypotheticalAccountLiquidityCollateral<\/code> and other view functions, leading to denial-of-service reverts and incorrect accounting in the protocol. Tracing of the bug effects is what requires a deep graph-based reasoning.<\/p>\n<h3><strong>3. Battle-tested static analysis integrated into AI workflow<\/strong><\/h3>\n<p>LLM-tailored Static Analysis feeds deep insight about the analyzed code to the AI to:<\/p>\n<ul>\n<li>Provide additional information not available in the code as text<\/li>\n<li>Reference relevant code segments from different locations<\/li>\n<li>Let AI perform analysis with the same contextual information and tooling that human auditors have<\/li>\n<\/ul>\n<hr \/>\n<h2><strong>Evaluation Methodology<\/strong><\/h2>\n<p>We evaluated Wake Arena performance through two distinct approaches:<\/p>\n<ol>\n<li><strong>Audit competitions<\/strong> \u2014 comparing against industry-standard datasets<\/li>\n<li><b>Production audits<\/b> \u2014 integration into production security audits<\/li>\n<\/ol>\n<h3><strong>1. Audit competition performance<\/strong><\/h3>\n<p>We accepted the Zellic benchmark dataset as an industry standard: 14 protocols from historical audit competitions (Code4rena and Sherlock) with publicly available codebases and verified findings reviewed by multiple security researchers.<\/p>\n<p><strong>Reproducibility:<\/strong> All benchmark codebases and competition findings are public. Wake Arena reports with code references and exploit scenarios are linked in the table below.<\/p>\n<h3><strong>Benchmark Protocols<\/strong><\/h3>\n<p>The table displays the number of high-severity issues identified\u00b9.<\/p>\n<div style=\"overflow-x: auto;\">\n<table style=\"width: 100%; border-collapse: collapse;\">\n<thead>\n<tr>\n<th style=\"text-align: left; padding: 8px; border-bottom: 2px solid #ddd;\">Protocol<\/th>\n<th style=\"text-align: left; padding: 8px; border-bottom: 2px solid #ddd;\">Wake Arena 3.1<\/th>\n<th style=\"text-align: left; padding: 8px; border-bottom: 2px solid #ddd;\">Wake Arena 3.0<\/th>\n<th style=\"text-align: left; padding: 8px; border-bottom: 2px solid #ddd;\">Zellic V12<\/th>\n<th style=\"text-align: left; padding: 8px; border-bottom: 2px solid #ddd;\">Plain GPT-5<\/th>\n<th style=\"text-align: left; padding: 8px; border-bottom: 2px solid #ddd;\">Plain Opus 4.5<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><a href=\"https:\/\/code4rena.com\/reports\/2024-07-basin\">Basin<\/a><\/td>\n<td>2\/2<\/td>\n<td>2\/2<\/td>\n<td>2\/2<\/td>\n<td>2\/2<\/td>\n<td>2\/2<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/code4rena.com\/audits\/2025-05-blackhole\">Blackhole<\/a><\/td>\n<td>2\/2<\/td>\n<td>2\/2<\/td>\n<td>2\/2<\/td>\n<td>1\/2<\/td>\n<td>0\/2<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/audits.sherlock.xyz\/contests\/858\">Burve<\/a><\/td>\n<td>4\/9<\/td>\n<td>2\/9<\/td>\n<td>2\/9<\/td>\n<td>2\/9<\/td>\n<td>0\/9<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/audits.sherlock.xyz\/contests\/755\">Crestal<\/a><\/td>\n<td>1\/1<\/td>\n<td>1\/1<\/td>\n<td>1\/1<\/td>\n<td>1\/1<\/td>\n<td>1\/1<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/audits.sherlock.xyz\/contests\/991\">DODO<\/a><\/td>\n<td>4\/5<\/td>\n<td>2\/5<\/td>\n<td>2\/5<\/td>\n<td>1\/5<\/td>\n<td>4\/5<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/code4rena.com\/audits\/2024-12-lambowin\">Lambo.win<\/a><\/td>\n<td>2\/4<\/td>\n<td>2\/4<\/td>\n<td>2\/4<\/td>\n<td>2\/4<\/td>\n<td>1\/4<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/audits.sherlock.xyz\/contests\/908\">Lend<\/a><\/td>\n<td>20\/28<\/td>\n<td>13\/28<\/td>\n<td>10\/28<\/td>\n<td>4\/28<\/td>\n<td>6\/28<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/audits.sherlock.xyz\/contests\/964\">Mellow<\/a><\/td>\n<td>2\/6<\/td>\n<td>2\/6<\/td>\n<td>2\/6<\/td>\n<td>1\/6<\/td>\n<td>0\/6<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/code4rena.com\/reports\/2024-07-munchables\">Munchables<\/a><\/td>\n<td>5\/5<\/td>\n<td>4\/5<\/td>\n<td>4\/5<\/td>\n<td>2\/5<\/td>\n<td>3\/5<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/audits.sherlock.xyz\/contests\/1001\">Notional Exponent<\/a><\/td>\n<td>4\/11<\/td>\n<td>2\/11<\/td>\n<td>2\/11<\/td>\n<td>0\/11<\/td>\n<td>0\/11<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/code4rena.com\/reports\/2024-08-phi\">Phi<\/a><\/td>\n<td>6\/7<\/td>\n<td>4\/7<\/td>\n<td>6\/7<\/td>\n<td>3\/7<\/td>\n<td>3\/7<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/audits.sherlock.xyz\/contests\/968\">Superfluid<\/a><\/td>\n<td>1\/2<\/td>\n<td>1\/2<\/td>\n<td>1\/2<\/td>\n<td>1\/2<\/td>\n<td>0\/2<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/code4rena.com\/audits\/2024-07-traitforge\">TraitForge<\/a><\/td>\n<td>4\/6<\/td>\n<td>2\/6<\/td>\n<td>1\/6<\/td>\n<td>2\/6<\/td>\n<td>0\/6<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/code4rena.com\/audits\/2025-04-virtuals-protocol\">Virtuals<\/a><\/td>\n<td>6\/6<\/td>\n<td>4\/6<\/td>\n<td>4\/6<\/td>\n<td>2\/6<\/td>\n<td>1\/6<\/td>\n<\/tr>\n<tr>\n<td><strong>Total<\/strong><\/td>\n<td><strong>63\/94<\/strong><\/td>\n<td><strong>43\/94<\/strong><\/td>\n<td><strong>41\/94<\/strong><\/td>\n<td><strong>24\/94<\/strong><\/td>\n<td><strong>21\/94<\/strong><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p><strong>Notes:<\/strong><\/p>\n<p>\u00b9 We used the same historical audit competition dataset as Zellic. Plain GPT-5 was launched through the Code CLI tool, and plain Opus 4.5 was launched through the Claude Code CLI. We conducted the test with the prompt &#8220;perform extensive deep Solidity smart contract security analysis&#8221; from the repository root, no special guidance. Wake Arena scans ran with a standard configuration. Testing was conducted in November 2025 for v3.0 and in March 2026 for v3.1. 49 out of the 63 discovered issues were found by more than one agent. We took issue labeling from Code4rena &amp; Sherlock as-is, so some issues there may have been flagged incorrectly (with bad severity, for example), but we took their labeling for consistency. Also, we&#8217;re using models that may have already been trained on these projects.<\/p>\n<h3><strong>Performance comparison<\/strong><\/h3>\n<p>Wake Arena 3.1 detected 63 out of 94 high-severity vulnerabilities, achieving the highest detection rate:<\/p>\n<ul>\n<li><strong>Wake Arena 3.1: <\/strong>63\/94 (67.0%)<\/li>\n<li><strong>Wake Arena 3.0:<\/strong> 43\/94 (45.7%)<\/li>\n<li><strong>Zellic V12:<\/strong> 41\/94 (43.6%)<\/li>\n<li><strong>GPT-5.2 xhigh: <\/strong>41\/94 (43.6%)<\/li>\n<li><strong>Plain GPT-5:<\/strong> 24\/94 (25.5%)<\/li>\n<li data-stringify-indent=\"0\" data-stringify-border=\"0\"><b data-stringify-type=\"bold\">Plain Opus<\/b>: 21\/94 (22.3%)<\/li>\n<\/ul>\n<hr \/>\n<h3><strong>2. Production audits<\/strong><\/h3>\n<p>During November 2025, Wake Arena scans were integrated into Ackee Blockchain&#8217;s manual audit process for production protocols. Unlike isolated benchmark environments, production audits involve interconnected contracts, incomplete configurations, and the full severity spectrum from Critical to Informational.<\/p>\n<h3><strong>Production audit results<\/strong><\/h3>\n<div style=\"overflow-x: auto;\">\n<table style=\"border-collapse: collapse;\">\n<thead>\n<tr>\n<th style=\"text-align: left; padding: 12px 20px; border-bottom: 2px solid #ddd; white-space: nowrap;\">Client<\/th>\n<th style=\"text-align: left; padding: 12px 20px; border-bottom: 2px solid #ddd; white-space: nowrap;\">Project<\/th>\n<th style=\"text-align: left; padding: 12px 20px; border-bottom: 2px solid #ddd; white-space: nowrap;\">Delivery<\/th>\n<th style=\"text-align: center; padding: 12px 20px; border-bottom: 2px solid #ddd; white-space: nowrap;\">Days<\/th>\n<th style=\"text-align: center; padding: 12px 20px; border-bottom: 2px solid #ddd; white-space: nowrap;\">Found by AI \/ All Found<\/th>\n<th style=\"text-align: center; padding: 12px 20px; border-bottom: 2px solid #ddd; white-space: nowrap;\">Critical<\/th>\n<th style=\"text-align: center; padding: 12px 20px; border-bottom: 2px solid #ddd; white-space: nowrap;\">High<\/th>\n<th style=\"text-align: center; padding: 12px 20px; border-bottom: 2px solid #ddd; white-space: nowrap;\">Medium<\/th>\n<th style=\"text-align: center; padding: 12px 20px; border-bottom: 2px solid #ddd; white-space: nowrap;\">Low<\/th>\n<th style=\"text-align: center; padding: 12px 20px; border-bottom: 2px solid #ddd; white-space: nowrap;\">Warning<\/th>\n<th style=\"text-align: center; padding: 12px 20px; border-bottom: 2px solid #ddd; white-space: nowrap;\">Info<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"padding: 12px 20px; white-space: nowrap;\"><a href=\"https:\/\/github.com\/Ackee-Blockchain\/public-audit-reports\/blob\/master\/2025\/ackee-blockchain-lido-stonks-2.0-report.pdf\" target=\"_blank\" rel=\"noopener\">Lido<\/a><\/td>\n<td style=\"padding: 12px 20px; white-space: nowrap;\">Stonks 2.0<\/td>\n<td style=\"padding: 12px 20px; white-space: nowrap;\">Dec 2, 2025<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">15<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">4 \/ 17<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">0 \/ 0<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">0 \/ 0<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">1 \/ 1<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">1 \/ 2<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">1 \/ 5<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">1 \/ 9<\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 12px 20px; white-space: nowrap;\"><a href=\"https:\/\/github.com\/Ackee-Blockchain\/public-audit-reports\/blob\/master\/2025\/ackee-blockchain-everstake-eth2-batch-deposit-report.pdf\" target=\"_blank\" rel=\"noopener\">Everstake<\/a><\/td>\n<td style=\"padding: 12px 20px; white-space: nowrap;\">ETH2 Batch Deposit Contract<\/td>\n<td style=\"padding: 12px 20px; white-space: nowrap;\">Nov 14, 2025<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">2<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">1 \/ 2<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">0 \/ 0<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">0 \/ 0<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">0 \/ 0<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">0 \/ 0<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">0 \/ 0<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">1 \/ 2<\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 12px 20px; white-space: nowrap;\"><a href=\"https:\/\/github.com\/Ackee-Blockchain\/public-audit-reports\/blob\/master\/2025\/ackee-blockchain-printr-protocol-report.pdf\">Printr<\/a><\/td>\n<td style=\"padding: 12px 20px; white-space: nowrap;\">Protocol<\/td>\n<td style=\"padding: 12px 20px; white-space: nowrap;\">Oct 1, 2025<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">32<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">21 \/ 60<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">5 \/ 10<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">0 \/ 4<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">1 \/ 5<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">4 \/ 10<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">4 \/ 15<\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\">7 \/ 16<\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 12px 20px; white-space: nowrap;\"><strong>Total<\/strong><\/td>\n<td style=\"padding: 12px 20px; white-space: nowrap;\"><\/td>\n<td style=\"padding: 12px 20px; white-space: nowrap;\"><\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\"><strong>49<\/strong><\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\"><strong>26 \/ 79<\/strong><\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\"><strong>5 \/ 10<\/strong><\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\"><strong>0 \/ 4<\/strong><\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\"><strong>2 \/ 6<\/strong><\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\"><strong>5 \/ 12<\/strong><\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\"><strong>5 \/ 20<\/strong><\/td>\n<td style=\"padding: 12px 20px; text-align: center; white-space: nowrap;\"><strong>9 \/ 27<\/strong><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p><strong>Key insight:<\/strong> Wake Arena identified 26\/79 or 33% of all findings. Moreover, it discovered 5 critical and 5 unique vulnerabilities beyond those found by human auditors in the Printr audit.<\/p>\n<p><strong>Notes:<\/strong><\/p>\n<p>\u00b9 Check Appendix C of the report for details on the Wake Arena findings.<\/p>\n<h2><strong>Key Strengths<\/strong><\/h2>\n<h3><strong>1. Cross-chain vulnerabilities<\/strong><\/h3>\n<p>Wake Arena excels at finding complex cross-chain security issues through graph-driven reasoning:<\/p>\n<ul>\n<li><strong>Lend protocol:<\/strong> Cross-chain liquidation logic errors and multi-directional position handling<\/li>\n<li><strong>DODO:<\/strong> Cross-chain parameter validation and refund authorization issues<\/li>\n<\/ul>\n<h3><strong>2. Access control and authorization<\/strong><\/h3>\n<p>Deep contextual understanding identifies subtle permission bugs:<\/p>\n<ul>\n<li><strong>Crestal:<\/strong> Unauthenticated allowance drain<\/li>\n<li><strong>Virtuals:<\/strong> Permissionless validator registration<\/li>\n<li><strong>Mellow:<\/strong> Multisig threshold bypass via duplicate signers<\/li>\n<\/ul>\n<h3><strong>3. Accounting and state management<\/strong><\/h3>\n<p>Graph-driven analysis traces data dependencies through complex state updates:<\/p>\n<ul>\n<li><strong>Lend:<\/strong> Repeated reward claims due to missing state decrements<\/li>\n<li><strong>Notional:<\/strong> Incorrect netting logic causing accounting divergence<\/li>\n<li><strong>Mellow:<\/strong> Double-counting of staked vs. LP tokens<\/li>\n<\/ul>\n<h3><strong>4. Protocol-specific logic errors<\/strong><\/h3>\n<p>Multi-agent reasoning catches context-dependent vulnerabilities:<\/p>\n<ul>\n<li><strong>Munchables:<\/strong> Plot state management and dirty flag handling<\/li>\n<li><strong>TraitForge:<\/strong> Generation counter limits and airdrop attribution<\/li>\n<li><strong>Burve:<\/strong> Fee accrual checkpoint management across assets<\/li>\n<\/ul>\n<hr \/>\n<h2><strong>Limitations<\/strong><\/h2>\n<p>Wake Arena is a powerful tool for finding important vulnerabilities, but it has limitations:<\/p>\n<p><strong>What Wake Arena catches well:<\/strong><\/p>\n<ul>\n<li>Access control and authorization bugs<\/li>\n<li>State management and accounting errors<\/li>\n<li>Cross-chain and cross-contract logic issues<\/li>\n<li>Reentrancy and callback vulnerabilities<\/li>\n<li>Parameter validation and input handling<\/li>\n<\/ul>\n<p><strong>What Wake Arena may miss:<\/strong><\/p>\n<ul>\n<li>Novel cryptographic vulnerabilities requiring deep mathematical analysis<\/li>\n<li>Protocol design flaws requiring extensive economic modeling<\/li>\n<li>Extremely complex business logic spanning multiple contracts and off-chain systems<\/li>\n<li>Zero-day attack vectors with no similar historical patterns<\/li>\n<\/ul>\n<p><strong>Ideal use case:<\/strong><\/p>\n<p>Use Wake Arena before your premium audit to:<\/p>\n<ul>\n<li>Catch surface-level and mid-depth vulnerabilities early<\/li>\n<li>Arrive at manual audit with cleaner code<\/li>\n<li>Focus auditor time on deep protocol logic and design issues<\/li>\n<li>Reduce overall security costs through early detection<\/li>\n<\/ul>\n<p>Wake Arena complements, rather than replaces, high-quality manual audits of critical systems.<\/p>\n<hr \/>\n<h2><strong>How to Use Wake Arena<\/strong><\/h2>\n<p>Wake Arena is available now at <a href=\"http:\/\/ackee.xyz\/wake\/arena\"><strong>ackee.xyz\/wake\/arena<\/strong><\/a><\/p>\n<p>Once you get access, scan your protocol in 3 steps:<\/p>\n<ol>\n<li><strong>Upload codebase:<\/strong> Connect GitHub repository or upload files<\/li>\n<li><strong>AI-driven analysis:<\/strong> A multi-agent system analyzes with graph-driven reasoning<\/li>\n<li><strong>Receive report:<\/strong> Comprehensive PDF with findings, severity ratings, and remediation guidance<\/li>\n<\/ol>\n<p><strong>Pricing:<\/strong> Entry-level audit pricing with reports delivered in hours instead of months.<\/p>\n<p><strong>Foundation plans:<\/strong> Admin panels for grant programs to scan multiple projects under one subscription.<\/p>\n<hr \/>\n<h2><strong>Appendix<\/strong><\/h2>\n<h3><strong>Wake Arena Performance in Historical Audit Competitions<\/strong><\/h3>\n<p>All findings below were discovered independently by Wake Arena with no special prompting or human assistance. Each protocol scan ran through the full AI-driven audit pipeline: compilation, graph-driven analysis, multi-agent reasoning, and report generation.<\/p>\n<h3><a href=\"https:\/\/code4rena.com\/reports\/2024-07-basin\"><strong>Basin<\/strong><\/a> <strong>(Code4rena, July 2024)<\/strong><\/h3>\n<p>Wake Arena finds all 2 out of 2 high-severity issues reported by human researchers.<\/p>\n<p><strong>[H-01] Missing owner or role gating on upgrade endpoints enables permissionless upgrades<\/strong><\/p>\n<p>Functions <code class=\"codehl\">upgradeTo<\/code> and <code class=\"codehl\">upgradeToAndCall<\/code> rely solely on <code class=\"codehl\">_authorizeUpgrade<\/code> for gating, which enforces only environmental checks (delegatecall context, Aquifer mapping, and UUPS proxiableUUID) but does not restrict caller by owner or any role. Any external caller can invoke upgrade endpoints and change the implementation to any candidate that satisfies environment checks, bypassing governance.<\/p>\n<p><strong>[H-02] decodeWellData checks decimal0 twice, leaving decimal1 at 0 and mis-scaling token1 when 0 should default to 18<\/strong><\/p>\n<p>Function <code class=\"codehl\">decodeWellData<\/code> uses the same sentinel check twice for <code class=\"codehl\">decimal0<\/code> and never checks <code class=\"codehl\">decimal1<\/code> before defaulting to 18. When <code class=\"codehl\">decimal1<\/code> is encoded as 0 to signal &#8220;default to 18&#8221;, it remains 0. Downstream scaling in <code class=\"codehl\">getScaledReserves<\/code> then multiplies token 1 by <code class=\"codehl\">10 ** (18 - 0) = 10 ** 18<\/code>, mis-scaling reserves and corrupting pricing, reserve solves, and rate calculations.<\/p>\n<hr \/>\n<h3><a href=\"https:\/\/code4rena.com\/audits\/2025-05-blackhole\"><strong>Blackhole<\/strong><\/a> <strong>(May 2025)<\/strong><\/h3>\n<p>Wake Arena finds all 2 out of 2 high-severity issues reported by human researchers.<\/p>\n<p><strong>[H-01] setRouter inverts the zero-address check, only allowing router = address(0)<\/strong><\/p>\n<p>Function <code class=\"codehl\">setRouter<\/code> inverts the zero-address guard, requiring the new router to be the zero address (<code class=\"codehl\">require(_router == address(0), &quot;ZA&quot;)<\/code>). This prevents the owner from configuring any valid router. If router is ever zero, calls such as <code class=\"codehl\">IGenesisPool(_genesisPool).launch(router, MATURITY_TIME)<\/code> will use an invalid address, causing failures.<\/p>\n<p><strong>[H-02] createGauge permits untrusted _algebraEternalFarming, granting arbitrary ERC20 approval and enabling theft of factory-held reward tokens<\/strong><\/p>\n<p>Function <code class=\"codehl\">createGauge<\/code> is externally callable without modifiers and accepts caller-supplied <code class=\"codehl\">farmingParam.algebraEternalFarming<\/code>. It forwards this to the internal <code class=\"codehl\">createEternalFarming<\/code>, which unconditionally grants an ERC20 approval of 1e10 to the user-supplied <code class=\"codehl\">_algebraEternalFarming<\/code> before making an external call to it. Because <code class=\"codehl\">_algebraEternalFarming<\/code> is not validated against a trusted registry, any actor can point it to an arbitrary contract they control, allowing them to pull tokens from the factory via <code class=\"codehl\">transferFrom<\/code> using the granted allowance.<\/p>\n<hr \/>\n<h3><a href=\"https:\/\/audits.sherlock.xyz\/contests\/858\"><strong>Burve<\/strong><\/a> <strong>(Sherlock, April 2025)<\/strong><\/h3>\n<p>Wake Arena finds 4 out of 9 high-severity issues reported by human researchers.<\/p>\n<p><strong>[H-02] E4626ViewAdjustor inverts real\/nominal semantics vs IAdjustor, enabling mis-accounting and integration misuse<\/strong><\/p>\n<p><code class=\"codehl\">E4626ViewAdjustor<\/code> implements <code class=\"codehl\">toNominal<\/code> and <code class=\"codehl\">toReal<\/code> with the opposite semantics to those documented in <code class=\"codehl\">IAdjustor<\/code>: it maps real amounts to ERC4626 shares and nominal amounts to ERC4626 assets, where the interface expects normalization around 18 decimals. Callers following <code class=\"codehl\">IAdjustor<\/code> semantics receive silently wrong values, causing incorrect pricing, fee assessment, or token transfers when the adjustor is used generically across tokens.<\/p>\n<p><strong>[H-05] Permissionless compounding at spot price via mint(0) enables MEV extraction of fee balances<\/strong><\/p>\n<p><code class=\"codehl\">mint<\/code> and <code class=\"codehl\">burn<\/code> unconditionally call <code class=\"codehl\">compoundV3Ranges<\/code>, which uses the pool&#8217;s live <code class=\"codehl\">slot0<\/code> price to convert accumulated fee balances into new Uniswap V3 liquidity. Because <code class=\"codehl\">mint<\/code> accepts <code class=\"codehl\">mintNominalLiq == 0<\/code> after initialization, an attacker can trigger compounding for free, manipulate the spot price via flash or MEV, force the protocol to compound at the distorted price, and extract value from the resulting impermanent loss as the price reverts.<\/p>\n<p><strong>[H-06] Uninitialized return variable used as tax base in removeValueSingle results in zero fees<\/strong><\/p>\n<p><code class=\"codehl\">removeValueSingle<\/code> computes <code class=\"codehl\">realTax<\/code> from the return variable <code class=\"codehl\">removedBalance<\/code> before it is assigned. Because return variables in Solidity are zero-initialized, <code class=\"codehl\">realTax<\/code> is always 0. Users withdraw the full gross amount without paying the configured tax, the protocol accrues no fee revenue on this path, and the <code class=\"codehl\">minReceive<\/code> slippage guard evaluates against the gross rather than the net-of-tax amount.<\/p>\n<p><strong>[H-07] ERC4626 donation inflation lets NoopVault accept deposits that mint 0 shares, causing depositor asset loss<\/strong><\/p>\n<p><code class=\"codehl\">NoopVault<\/code> inherits OpenZeppelin&#8217;s <code class=\"codehl\">ERC4626<\/code> unchanged, so <code class=\"codehl\">totalAssets<\/code> reflects direct token donations. An attacker can seed the vault with dust shares, then donate tokens to inflate <code class=\"codehl\">totalAssets<\/code> while <code class=\"codehl\">totalSupply<\/code> stays minimal. Subsequent victim deposits compute <code class=\"codehl\">shares == 0<\/code> via floor rounding and still succeed, transferring assets in while minting nothing. The attacker later redeems their dust shares to withdraw a disproportionate fraction of the vault including all zero-share deposits.<\/p>\n<hr \/>\n<h3><a href=\"https:\/\/audits.sherlock.xyz\/contests\/755\"><strong>Crestal<\/strong><\/a> <strong>(Sherlock, March 2025)<\/strong><\/h3>\n<p>Wake Arena finds the only high-severity issue reported by human researchers.<\/p>\n<p><strong>[H-01] Unauthenticated allowance drain via public payWithERC20<\/strong><\/p>\n<p>Function <code class=\"codehl\">payWithERC20<\/code> in contract Payment is public and accepts arbitrary <code class=\"codehl\">fromAddress<\/code> and <code class=\"codehl\">toAddress<\/code>. It invokes <code class=\"codehl\">token.safeTransferFrom(fromAddress, toAddress, amount)<\/code> without authenticating the caller, binding <code class=\"codehl\">fromAddress<\/code> to <code class=\"codehl\">msg.sender<\/code>, or validating any signed authorization. Any user can trigger spending of any allowance that <code class=\"codehl\">fromAddress<\/code> has granted to this contract and redirect funds to an arbitrary <code class=\"codehl\">toAddress<\/code>.<\/p>\n<hr \/>\n<h3><a href=\"https:\/\/audits.sherlock.xyz\/contests\/991\"><strong>DODO Cross-Chain DEX<\/strong><\/a> <strong>(Sherlock, June 2025)<\/strong><\/h3>\n<p>Wake Arena finds 4 out of 5 high-severity issues reported by human researchers.<\/p>\n<p><strong>[H-01] Unvalidated message parameters in GatewayCrossChain onCall allow draining arbitrary ZRC20 balances<\/strong><\/p>\n<p><code class=\"codehl\">GatewayCrossChain.onCall<\/code> decodes <code class=\"codehl\">MixSwapParams<\/code> directly from the cross-chain message and passes them to <code class=\"codehl\">_doMixSwap<\/code> with no invariant binding <code class=\"codehl\">params.fromToken<\/code> to the received <code class=\"codehl\">zrc20<\/code> or <code class=\"codehl\">params.fromTokenAmount<\/code> to the post-fee <code class=\"codehl\">amount<\/code>. An attacker can craft a message pointing <code class=\"codehl\">params.fromToken<\/code> to any ZRC20 the contract already holds, set a large deposit in an unrelated token to inflate the approval, and route the DODO swap to drain the third-party balance.<\/p>\n<p><strong>[H-03] Approval vs. spend mismatch in GatewayCrossChain _doMixSwap strands allowances and enables griefing<\/strong><\/p>\n<p><code class=\"codehl\">_doMixSwap<\/code> in <code class=\"codehl\">GatewayCrossChain<\/code> grants <code class=\"codehl\">approve(DODOApprove, amount)<\/code> for <code class=\"codehl\">params.fromToken<\/code> but invokes <code class=\"codehl\">mixSwap<\/code> with <code class=\"codehl\">params.fromTokenAmount<\/code>. Since <code class=\"codehl\">amount<\/code> and <code class=\"codehl\">params.fromTokenAmount<\/code> are independent caller-supplied values, an attacker can set <code class=\"codehl\">params.fromTokenAmount &gt; amount<\/code> to cause a revert via insufficient allowance, or set it below <code class=\"codehl\">amount<\/code> to strand excess allowances and tokens in the contract for future abuse.<\/p>\n<p><strong>[H-04] Unbound params.fromToken in withdrawToNativeChain enables arbitrary token draining via DODO mixSwap<\/strong><\/p>\n<p><code class=\"codehl\">withdrawToNativeChain<\/code> in <code class=\"codehl\">GatewayTransferNative<\/code> approves <code class=\"codehl\">params.fromToken<\/code> for the full deposited <code class=\"codehl\">amount<\/code> before calling the DODO router, without enforcing that <code class=\"codehl\">params.fromToken<\/code> equals the <code class=\"codehl\">zrc20<\/code> transferred in. An attacker deposits a large amount of an unrelated token to set a correspondingly large approval on any target ZRC20 the contract holds, then routes the DODO swap to drain it.<\/p>\n<p><strong>[H-05] Non-EVM refund theft via authorization bypass in claimRefund<\/strong><\/p>\n<p><code class=\"codehl\">claimRefund<\/code> initializes <code class=\"codehl\">receiver = msg.sender<\/code> and only overwrites it when <code class=\"codehl\">refundInfo.walletAddress.length == 20<\/code>. For non-EVM recipients (Solana, Bitcoin), the wallet address is not 20 bytes, so <code class=\"codehl\">receiver<\/code> remains <code class=\"codehl\">msg.sender<\/code> and the check <code class=\"codehl\">require(bots[msg.sender] || msg.sender == receiver)<\/code> always passes for any caller. Any address can claim and redirect any stored non-EVM refund.<\/p>\n<hr \/>\n<h3><a href=\"https:\/\/code4rena.com\/audits\/2024-12-lambowin\"><strong>Lambo.win<\/strong><\/a> <strong>(Code4rena, December 2024)<\/strong><\/h3>\n<p>Wake Arena finds 2 out of 4 high-severity issues reported by human researchers.<\/p>\n<p><strong>[H-01] ERC20-mode cashIn mints by msg.value, enabling unbacked minting and zero-credit deposits<\/strong><\/p>\n<p>Function <code class=\"codehl\">cashIn<\/code> mints virtual tokens based on <code class=\"codehl\">msg.value<\/code> even when the underlying asset is an ERC20 token. In the ERC20 branch, the function transfers <code class=\"codehl\">amount<\/code> ERC20 tokens from the caller but mints <code class=\"codehl\">msg.value<\/code> virtual tokens, creating two failure modes: users depositing ERC20 with <code class=\"codehl\">msg.value == 0<\/code> receive 0 virtual tokens while their ERC20 is locked, and attackers can send ETH with <code class=\"codehl\">amount == 0<\/code> to receive unbacked virtual tokens they can <code class=\"codehl\">cashOut<\/code> to drain others&#8217; ERC20 deposits.<\/p>\n<p><strong>[H-02] Front-run DoS by pre-creating Uniswap pair (PAIR_EXISTS) due to predictable next clone address<\/strong><\/p>\n<p>Function <code class=\"codehl\">createLaunchPad<\/code> deploys a new quote token clone using <code class=\"codehl\">Clones.clone<\/code> (via CREATE), then immediately calls Uniswap V2 <code class=\"codehl\">createPair<\/code>. Because CREATE-based addresses are derived from the factory&#8217;s address and its nonce, an observer can predict the next clone address. An attacker can front-run and pre-create the pair for <code class=\"codehl\">(virtualLiquidityToken, predictedQuoteToken)<\/code>, causing the victim&#8217;s <code class=\"codehl\">createLaunchPad<\/code> to revert with <code class=\"codehl\">PAIR_EXISTS<\/code>.<\/p>\n<hr \/>\n<h3><a href=\"https:\/\/audits.sherlock.xyz\/contests\/908\"><strong>Lend<\/strong><\/a> <strong>(Sherlock, June 2025)<\/strong><\/h3>\n<p>Wake Arena finds 20 out of 28 high-severity issues reported by human researchers.<\/p>\n<p><strong>[H-01] claimLend fails to decrement lendAccrued after grant, allowing repeated reward claims and LEND drain<\/strong><\/p>\n<p>Function <code class=\"codehl\">claimLend<\/code> transfers accrued LEND but never reduces the recorded accrual in storage. After a successful transfer, <code class=\"codehl\">lendAccrued(account)<\/code> remains unchanged, allowing the same accrual to be claimed repeatedly whenever the router holds enough LEND. Storage-side distribution functions only ever increase <code class=\"codehl\">lendAccrued<\/code>; no path decrements or clears it after grants.<\/p>\n<p><strong>[H-03] borrowWithInterest reverts for legitimate multi-direction positions (both arrays populated)<\/strong><\/p>\n<p>Function <code class=\"codehl\">borrowWithInterest<\/code> enforces that only one of <code class=\"codehl\">crossChainBorrows<\/code> or <code class=\"codehl\">crossChainCollaterals<\/code> is populated for a given user and underlying on a chain. This invariant does not hold for legitimate multi-direction positions involving the same underlying in opposite directions across different remote chains, causing denial-of-service in repay and accounting flows.<\/p>\n<p><strong>[H-04] Collateral seized before repayment; LiquidationSuccess uses foreign lToken, bricking cross-chain liquidation<\/strong><\/p>\n<p>Collateral is seized on the collateral chain before repayment is secured, and the follow-up <code class=\"codehl\">LiquidationSuccess<\/code> handler repays using a foreign <code class=\"codehl\">lToken<\/code> address. On the debt chain, <code class=\"codehl\">liquidateCrossChain<\/code> computes seize tokens and sends <code class=\"codehl\">CrossChainLiquidationExecute<\/code> without first escrowing or pulling repayment funds from the liquidator. On the collateral chain, <code class=\"codehl\">_handleLiquidationExecute<\/code> immediately updates accounting and reduces the borrower&#8217;s collateral before any guarantee that repayment will succeed, breaking the cross-chain liquidation flow and permanently desynchronizing borrower state across chains.<\/p>\n<p><strong>[H-05] Cross-chain liquidation computes seize amount on debt chain and applies it verbatim on collateral chain, enabling over- or under-seizure<\/strong><\/p>\n<p><code class=\"codehl\">_executeLiquidationCore<\/code> calculates <code class=\"codehl\">seizeTokens<\/code> using the debt chain&#8217;s oracle prices, exchange rates, and liquidation parameters, then transmits this value to the collateral chain where <code class=\"codehl\">_handleLiquidationExecute<\/code> applies it without recomputation. If market parameters or oracle prices differ between chains, the collateral chain can seize too many tokens (harming the borrower) or too few (creating protocol bad debt).<\/p>\n<p><strong>[H-06] Cross-chain borrow capacity check forwards full sumCollateral instead of net liquidity, enabling multi-chain collateral double-counting<\/strong><\/p>\n<p><code class=\"codehl\">borrowCrossChain<\/code> snapshots and sends only the borrower&#8217;s gross <code class=\"codehl\">sumCollateral<\/code> in the payload, discarding the borrow side. Each destination chain validates the new borrow independently against this full collateral value without subtracting existing debt on other chains. A borrower can initiate simultaneous cross-chain borrows to multiple destinations, each of which passes the check, reusing the same collateral across chains and creating undercollateralized positions.<\/p>\n<p><strong>[H-07] Redeem underpays by using pre-accrual exchangeRateStored; surplus underlying stranded in router<\/strong><\/p>\n<p>Function <code class=\"codehl\">redeem<\/code> computes <code class=\"codehl\">expectedUnderlying<\/code> using <code class=\"codehl\">exchangeRateStored<\/code> read before calling the market&#8217;s <code class=\"codehl\">redeem<\/code>. The <code class=\"codehl\">redeem<\/code> call accrues interest and uses post-accrual rate, so the router receives more underlying than it forwards to the user. The difference remains stuck in the router and accumulates over time.<\/p>\n<p><strong>[H-08] borrowWithInterest excludes destination-chain collaterals, zeroing cross-chain debt and blocking liquidation<\/strong><\/p>\n<p>Function <code class=\"codehl\">borrowWithInterest<\/code> fails to include cross-chain debt on destination chains because the collaterals branch erroneously requires both <code class=\"codehl\">destEid == currentEid<\/code> and <code class=\"codehl\">srcEid == currentEid<\/code>. On genuine cross-chain borrows originating on Chain A with debt on Chain B, <code class=\"codehl\">destEid == currentEid<\/code> but <code class=\"codehl\">srcEid != currentEid<\/code>, so the condition is always false. This incorrect zero balance corrupts downstream logic including liquidity calculations and liquidation limits.<\/p>\n<p><strong>[H-09] Supply credits lTokens using stale exchangeRateStored, causing accounting drift and redeem DoS<\/strong><\/p>\n<p>Supply uses <code class=\"codehl\">exchangeRateStored<\/code> from before mint and then credits <code class=\"codehl\">mintTokens<\/code> using the stale rate. The subsequent mint call accrues interest and uses post-accrual exchange rate, so actual lTokens minted to the router are fewer than the credited amount. This creates persistent accounting surplus that eventually causes redemption reverts.<\/p>\n<p><strong>[H-10] Non-atomic cross-chain liquidation seizes collateral before collecting repayment, enabling unpaid seizures<\/strong><\/p>\n<p>The liquidation protocol seizes collateral on the collateral chain first, then attempts to collect repayment from the liquidator on the debt chain. There is no escrow of the liquidator&#8217;s tokens prior to seizure, so if the liquidator cannot or will not pay, repayment fails while collateral has already been redistributed.<\/p>\n<p><strong>[H-16] Cross-chain repay corrupts same-chain borrow state and shared userBorrowedAssets, hiding or double-counting debt<\/strong><\/p>\n<p><code class=\"codehl\">CoreRouter.repayBorrowInternal<\/code> always mutates the same-chain <code class=\"codehl\">borrowBalance<\/code> mapping and the shared <code class=\"codehl\">userBorrowedAssets<\/code> set regardless of whether the repayment is same-chain or cross-chain. Cross-chain repayment helpers similarly remove the lToken from <code class=\"codehl\">userBorrowedAssets<\/code> when the cross-chain portion reaches zero without checking whether same-chain debt remains. The result is either hidden debt (the asset disappears from risk enumeration while a balance remains) or double-counted debt (partial cross-chain repayments write a ghost entry into same-chain <code class=\"codehl\">borrowBalance<\/code>, which is then summed again alongside the actual cross-chain record in liquidity calculations).<\/p>\n<p><strong>[H-18] Cross-chain debt undercount and repay DoS on destination chain in borrowWithInterest<\/strong><\/p>\n<p>Cross-chain debt becomes invisible on the destination chain because the <code class=\"codehl\">borrowWithInterest<\/code> collaterals branch uses an unsatisfiable predicate requiring both <code class=\"codehl\">destEid<\/code> and <code class=\"codehl\">srcEid<\/code> to equal <code class=\"codehl\">currentEid<\/code>. On the destination chain, cross-chain collateral records have <code class=\"codehl\">destEid == currentEid<\/code> and <code class=\"codehl\">srcEid<\/code> set to the origin chain, so <code class=\"codehl\">srcEid == currentEid<\/code> is always false and the loop never adds any amount. This causes under-accounting of debt in helpers like <code class=\"codehl\">getHypotheticalAccountLiquidityCollateral<\/code> and repay path DoS where <code class=\"codehl\">CoreRouter.repayBorrowInternal<\/code> requires <code class=\"codehl\">borrowedAmount &gt; 0<\/code> but <code class=\"codehl\">borrowWithInterest<\/code> incorrectly returns 0.<\/p>\n<p><strong>[H-19] Liquidation repayment uses collateral seizeTokens instead of repayAmount<\/strong><\/p>\n<p>After seizing collateral, the <code class=\"codehl\">LiquidationSuccess<\/code> handler repays the borrower using <code class=\"codehl\">payload.amount<\/code>, but that field was set to <code class=\"codehl\">seizeTokens<\/code> (collateral lToken units) during <code class=\"codehl\">_executeLiquidationCore<\/code>. Repayment must be performed using the <code class=\"codehl\">repayAmount<\/code> in the borrowed asset&#8217;s underlying units, causing incorrect debt settlement.<\/p>\n<p><strong>[H-20] Stale unlocked collateral snapshot enables undercollateralized cross-chain borrowing via TOCTOU race<\/strong><\/p>\n<p><code class=\"codehl\">borrowCrossChain<\/code> snapshots the borrower&#8217;s collateral at call time and includes it unmodified in the LayerZero payload without locking or reserving the collateral. During the asynchronous window before the destination chain executes, the borrower can freely redeem or borrow against the same collateral on the source chain; the source records no in-flight debt. The destination validates against the stale snapshot and approves the borrow regardless, yielding an undercollateralized position once the source-chain withdrawal completes.<\/p>\n<p><strong>[H-21] Stale source-chain collateral snapshot enables undercollateralized cross-chain borrowing<\/strong><\/p>\n<p>The destination-chain borrow handler trusts a collateral value snapshotted on the source chain at send time. There is no lock on source-chain collateral while the message is in flight. The borrower can withdraw source-chain collateral after initiating cross-chain borrow but before destination execution, allowing undercollateralized or uncollateralized borrowing.<\/p>\n<p><strong>[H-22] Liquidation validity check uses wrong units and wrong action model, enabling seizure of healthy accounts<\/strong><\/p>\n<p>The liquidation validator <code class=\"codehl\">_checkLiquidationValid<\/code> models an additional borrow in the collateral market and passes <code class=\"codehl\">payload.amount<\/code> as the <code class=\"codehl\">borrowAmount<\/code>. In this flow, <code class=\"codehl\">payload.amount<\/code> is the number of lTokens to seize, not underlying-denominated borrow amount. This mixes units and incorrectly inflates the &#8220;borrowed&#8221; side of the solvency check, enabling liquidation of healthy accounts.<\/p>\n<p><strong>[H-23] borrowWithInterest EID predicate excludes valid destination-chain records, making cross-chain debt invisible<\/strong><\/p>\n<p>Records in <code class=\"codehl\">crossChainCollaterals<\/code> are stored with <code class=\"codehl\">srcEid<\/code> pointing to the remote source chain, but <code class=\"codehl\">borrowWithInterest<\/code> requires <code class=\"codehl\">collaterals[i].srcEid == currentEid<\/code> on the destination-chain branch, so legitimate records are never summed. Cross-chain debt is invisible on the destination chain, breaking repay paths, liquidation validation, and solvency checks in <code class=\"codehl\">getHypotheticalAccountLiquidityCollateral<\/code>.<\/p>\n<p><strong>[H-24] Cross-chain repayment removes lToken from shared userBorrowedAssets without checking outstanding same-chain debt<\/strong><\/p>\n<p>When a cross-chain repayment fully settles its portion, the repayment handlers unconditionally remove the lToken from the shared <code class=\"codehl\">userBorrowedAssets<\/code> enumeration set without verifying whether same-chain debt for that lToken remains. Because <code class=\"codehl\">getHypotheticalAccountLiquidityCollateral<\/code> iterates only <code class=\"codehl\">userBorrowedAssets<\/code>, any remaining same-chain balance becomes invisible to all risk and liquidation checks.<\/p>\n<p><strong>[H-25] LiquidationSuccess uses foreign lToken and wrong EIDs; repayment never executes after collateral seized<\/strong><\/p>\n<p>After seizing collateral on the collateral chain, the router sends a <code class=\"codehl\">LiquidationSuccess<\/code> message back to the debt chain. The receiving handler <code class=\"codehl\">_handleLiquidationSuccess<\/code> attempts to look up the borrow position and repay the debt using the collateral-chain <code class=\"codehl\">destlToken<\/code> and mismatched endpoint IDs. This causes the handler to fail to locate the record or revert when interacting with an unknown lToken, leaving repayment unexecuted while collateral has already been seized.<\/p>\n<p><strong>[H-27] First-time borrowers bypass per-user collateral checks in borrow due to zero borrowIndex path<\/strong><\/p>\n<p>In function <code class=\"codehl\">borrow<\/code>, the contract computes borrowed and collateral including the new amount, but then derives <code class=\"codehl\">borrowAmount<\/code> as zero when <code class=\"codehl\">currentBorrow.borrowIndex == 0<\/code> (first-time borrowers). The per-user collateral check <code class=\"codehl\">collateral &gt;= borrowAmount<\/code> becomes <code class=\"codehl\">collateral &gt;= 0<\/code>, always passing and enabling new users to borrow against other users&#8217; collateral held by the router.<\/p>\n<p><strong>[H-28] _handleValidBorrowRequest overwrites borrowIndex without accruing prior principal, erasing cross-chain interest on each new borrow<\/strong><\/p>\n<p>When a cross-chain borrow confirmation arrives at the source chain, <code class=\"codehl\">_handleValidBorrowRequest<\/code> adds the new amount to the existing principal and overwrites the stored <code class=\"codehl\">borrowIndex<\/code> without first scaling the prior principal to the new index. Because debt is computed as <code class=\"codehl\">principle * currentBorrowIndex \/ storedBorrowIndex<\/code>, the interest accrued since the last borrow is effectively forgiven each time the user borrows again. Source-chain liquidity checks undercount the borrower&#8217;s true debt, allowing excess collateral withdrawals and additional borrows.<\/p>\n<hr \/>\n<h3><a href=\"https:\/\/audits.sherlock.xyz\/contests\/964\"><strong>Mellow<\/strong><\/a> <strong>(Sherlock, July 2025)<\/strong><\/h3>\n<p>Wake Arena finds 2 out of 6 high-severity issues reported by human researchers.<\/p>\n<p><strong>[H-01] Threshold bypass: duplicate signer entries counted as distinct in checkSignatures<\/strong><\/p>\n<p>The Consensus multisig validator counts provided signatures against threshold but does not enforce that each signature is produced by a unique signer. The same signer can be repeated in the signatures array to satisfy any threshold, degrading a k-of-N policy to effectively 1-of-N as long as one registered signer is willing or compromised.<\/p>\n<p><strong>[H-04] Protocol fee double-accrual across non-base-asset reports because timestamp is only updated for base asset<\/strong><\/p>\n<p>A protocol-fee accrual checkpoint is stored per vault in <code class=\"codehl\">timestamps<\/code>. Function <code class=\"codehl\">calculateFee<\/code> unconditionally adds time-based protocol fees proportional to <code class=\"codehl\">block.timestamp - timestamps[vault]<\/code> for any asset, while function <code class=\"codehl\">updateState<\/code> advances the checkpoint only when <code class=\"codehl\">asset == baseAsset[vault]<\/code> and returns early otherwise. This allows the same elapsed period to be charged multiple times across different non-base-asset reports until a base-asset report finally updates the timestamp, systematically over-minting protocol fee shares.<\/p>\n<hr \/>\n<h3><a href=\"https:\/\/code4rena.com\/reports\/2024-07-munchables\"><strong>Munchables<\/strong><\/a> <strong>(Code4rena, July 2024)<\/strong><\/h3>\n<p>Wake Arena finds 5 out of 5 high-severity issues reported by human researchers.<\/p>\n<p><strong>[H-01] Missing plotId update on transfer causes stuck occupancy and event inconsistency<\/strong><\/p>\n<p>Function <code class=\"codehl\">transferToUnoccupiedPlot<\/code> updates occupancy bitmaps for the old and new plots but never updates the staked token&#8217;s <code class=\"codehl\">toilerState.plotId<\/code> field. As a result, the contract retains a stale plot id in storage while the <code class=\"codehl\">plotOccupied<\/code> mapping reflects the new plot. When the renter later calls <code class=\"codehl\">unstakeMunchable<\/code>, the function frees the old plot id (which is already empty), leaving the new plot permanently marked as occupied and preventing further rentals on that plot.<\/p>\n<p><strong>[H-02] Off-by-one in invalid-plot check allows farming on removed plots<\/strong><\/p>\n<p>The invalid plot detection in <code class=\"codehl\">_farmPlots<\/code> uses <code class=\"codehl\">_getNumPlots(landlord) &lt; _toiler.plotId<\/code> instead of the correct <code class=\"codehl\">&gt;=<\/code> comparison, missing the equality case. When a landlord reduces the number of plots, a toiler whose <code class=\"codehl\">plotId<\/code> equals the new plot count should be marked invalid, but the current code fails to detect it. As a result, staked tokens on the highest removed index continue farming as if the plot still existed, causing accounting errors for both renter and landlord.<\/p>\n<p><strong>[H-03] Signed bonus arithmetic in _farmPlots can produce negative schnibbles and revert, trapping NFTs<\/strong><\/p>\n<p><code class=\"codehl\">_farmPlots<\/code> computes <code class=\"codehl\">finalBonus<\/code> as the sum of a signed <code class=\"codehl\">REALM_BONUSES<\/code> entry and a <code class=\"codehl\">RARITY_BONUSES<\/code> entry cast through <code class=\"codehl\">uint8 \u2192 int8<\/code> (values \u2265 128 become negative). The adjusted schnibbles total is then computed as <code class=\"codehl\">uint256((int256(schnibblesTotal) + int256(schnibblesTotal) * finalBonus) \/ 100)<\/code>. Any <code class=\"codehl\">finalBonus<\/code> of \u22122 or below makes the numerator negative; casting a negative <code class=\"codehl\">int256<\/code> to <code class=\"codehl\">uint256<\/code> reverts in Solidity 0.8. Because <code class=\"codehl\">_farmPlots<\/code> runs via the <code class=\"codehl\">forceFarmPlots<\/code> modifier on every key user action, affected renters cannot farm, transfer to another plot, or unstake, leaving their NFTs permanently trapped until configuration is changed.<\/p>\n<p><strong>[H-04] Time-delta underflow in _farmPlots when using landlord lastUpdated on invalid plot causes revert and blocks user actions<\/strong><\/p>\n<p>When a staked token&#8217;s <code class=\"codehl\">plotId<\/code> exceeds the landlord&#8217;s available plots, <code class=\"codehl\">_farmPlots<\/code> substitutes <code class=\"codehl\">timestamp = plotMetadata[landlord].lastUpdated<\/code> and then computes the farming delta as <code class=\"codehl\">timestamp - _toiler.lastToilDate<\/code>. If <code class=\"codehl\">plotMetadata[landlord].lastUpdated<\/code> is zero (never initialized) or earlier than <code class=\"codehl\">_toiler.lastToilDate<\/code>, the subtraction underflows under Solidity 0.8 and reverts the entire transaction. Because <code class=\"codehl\">_farmPlots<\/code> is executed by the <code class=\"codehl\">forceFarmPlots<\/code> modifier on key functions (<code class=\"codehl\">stakeMunchable<\/code>, <code class=\"codehl\">unstakeMunchable<\/code>, <code class=\"codehl\">transferToUnoccupiedPlot<\/code>), this revert prevents users from farming, moving to a valid plot, or even unstaking\u2014effectively locking assets until metadata is updated.<\/p>\n<p><strong>[H-05] Dirty flag in _farmPlots is never cleared, permanently disabling farming for affected tokens<\/strong><\/p>\n<p>When a staked token&#8217;s <code class=\"codehl\">plotId<\/code> is no longer valid (available plots shrank), <code class=\"codehl\">_farmPlots<\/code> sets <code class=\"codehl\">toilerState[tokenId].dirty = true<\/code> to denote a one-time adjustment. On subsequent calls, the check <code class=\"codehl\">if (_toiler.dirty) continue;<\/code> skips farming entirely for that token. There is no code path that clears the dirty flag after the adjustment, including in <code class=\"codehl\">transferToUnoccupiedPlot<\/code>, so the token will never accrue schnibbles again unless the owner fully unstakes and restakes it.<\/p>\n<hr \/>\n<h3><a href=\"https:\/\/audits.sherlock.xyz\/contests\/1001\"><strong>Notional Exponent<\/strong><\/a> <strong>(Sherlock, July 2025)<\/strong><\/h3>\n<p>Wake Arena finds 4 out of 11 high-severity issues reported by human researchers.<\/p>\n<p><strong>[H-03] Overlapping Dinero withdraw requests redeem aggregated upxETH, enabling theft and DoS of other withdrawals<\/strong><\/p>\n<p><code class=\"codehl\">DineroWithdrawRequestManager<\/code> mints all <code class=\"codehl\">upxETH<\/code> redemptions to <code class=\"codehl\">address(this)<\/code>. When finalizing a request, <code class=\"codehl\">_finalizeWithdrawImpl<\/code> redeems the entire <code class=\"codehl\">upxETH.balanceOf(address(this), i)<\/code> for every batch id in the request&#8217;s <code class=\"codehl\">[initialBatchId, finalBatchId]<\/code> range and attributes the full redeemed WETH to that single <code class=\"codehl\">requestId<\/code>. Because requests are explicitly allowed to overlap on batch ids, whichever request is finalized first captures all <code class=\"codehl\">upxETH<\/code> across shared batches, including amounts that belong to other requests. Later finalizations see a zero balance and settle with <code class=\"codehl\">totalWithdraw = 0<\/code>.<\/p>\n<p><strong>[H-04] Borrowers calling Morpho directly bypass the account-aware oracle, enabling undercollateralized borrowing<\/strong><\/p>\n<p><code class=\"codehl\">MorphoLendingRouter<\/code> configures Morpho markets to use the vault itself as the oracle. The vault&#8217;s <code class=\"codehl\">IOracle.price()<\/code> calls <code class=\"codehl\">convertToAssets<\/code>, which in staking strategies returns a lower, withdraw-request-aware valuation when the transient <code class=\"codehl\">t_CurrentAccount<\/code> is set. The router sets this context only during its own authenticated flows. Because Morpho&#8217;s <code class=\"codehl\">borrow<\/code> is permissionless for self-managed positions, a borrower can call Morpho directly with <code class=\"codehl\">t_CurrentAccount<\/code> unset, receiving the higher default valuation and borrowing more than the router would permit. Router-driven liquidations subsequently use the lower per-account price, risking bad debt for lenders.<\/p>\n<p><strong>[H-06] Withdrawal initiation DoS after ~65k requests due to 16-bit nonce overflow in s_batchNonce<\/strong><\/p>\n<p>The withdraw request identifier packs a 16-bit <code class=\"codehl\">s_batchNonce<\/code> in the high bits and uses <code class=\"codehl\">++s_batchNonce<\/code> during initiation. In Solidity 0.8+, arithmetic on <code class=\"codehl\">uint16<\/code> is checked. Once the counter reaches 65535, the next increment reverts, permanently denying further withdrawal initiation through this manager.<\/p>\n<p><strong>[H-09] Curve V2 exits hardcode use_eth=true, causing ETH\/WETH mismatch and stranded native ETH on WETH pools<\/strong><\/p>\n<p><code class=\"codehl\">CurveConvexLib<\/code> exit paths unconditionally pass <code class=\"codehl\">use_eth = true<\/code> to Curve V2&#8217;s <code class=\"codehl\">remove_liquidity<\/code> and <code class=\"codehl\">remove_liquidity_one_coin<\/code>. For pools where the coin is ERC20 WETH rather than native ETH, this causes Curve to unwrap and return native ETH. The strategy measures exit proceeds via <code class=\"codehl\">TokenUtils.tokenBalance(asset)<\/code> which tracks ERC20 WETH balances, not native ETH, so the received ETH is invisible. <code class=\"codehl\">assetsWithdrawn<\/code> is undercounted (often zero) and native ETH accumulates stranded on the vault. Entry paths correctly toggle <code class=\"codehl\">use_eth<\/code> based on whether a coin is <code class=\"codehl\">ETH_ADDRESS<\/code>, making exit asymmetric with entry.<\/p>\n<hr \/>\n<h3><a href=\"https:\/\/code4rena.com\/reports\/2024-08-phi\"><strong>Phi<\/strong><\/a> <strong>(Code4rena, October 2024)<\/strong><\/h3>\n<p>Wake Arena finds 6 out of 7 high-severity issues reported by human researchers.<\/p>\n<p><strong>[H-01] Art creation signature lacks domain separation, enabling cross-chain replay<\/strong><\/p>\n<p>The <code class=\"codehl\">createArt<\/code> authorization flow verifies a personal-signature over <code class=\"codehl\">(uint256 expiresIn, string uri, bytes credData)<\/code> without binding to <code class=\"codehl\">block.chainid<\/code> or <code class=\"codehl\">address(this)<\/code>. A valid art-creation signature for Chain A can be replayed on Chain B if the same <code class=\"codehl\">phiSignerAddress<\/code> is configured, creating unintended duplicate art across chains and bypassing per-chain rollout policies.<\/p>\n<p><strong>[H-02] createArt signatures do not bind CreateConfig, allowing parameter hijack and revenue redirection<\/strong><\/p>\n<p>The factory signature only covers <code class=\"codehl\">(expiresIn, uri, credData)<\/code> and does not bind <code class=\"codehl\">CreateConfig<\/code> fields or the caller. Any party with a valid signed payload can front-run and submit <code class=\"codehl\">createArt<\/code> with arbitrary <code class=\"codehl\">artist<\/code>, <code class=\"codehl\">receiver<\/code>, <code class=\"codehl\">mintFee<\/code>, and timing parameters. The attacker gains persistent control via <code class=\"codehl\">onlyArtCreator<\/code> modifier and redirects revenue. The first creation also fixes the per-cred ERC1155 contract address permanently.<\/p>\n<p><strong>[H-03] Unbounded EnumerableMap keys in shareBalance enable gas-DoS of distribute, permanently locking curator rewards<\/strong><\/p>\n<p><code class=\"codehl\">_updateCuratorShareBalance<\/code> calls <code class=\"codehl\">EnumerableMap.set(sender_, 0)<\/code> when a curator sells to zero instead of <code class=\"codehl\">remove<\/code>, so the address remains as an enumerable key forever. <code class=\"codehl\">CuratorRewardsDistributor.distribute<\/code> always calls <code class=\"codehl\">getCuratorAddresses(credId, 0, 0)<\/code>, forcing a full scan over every historical key for that <code class=\"codehl\">credId<\/code>. An attacker can inflate the key count by briefly buying from many throwaway addresses and selling out; once the scan exceeds the block gas limit, <code class=\"codehl\">distribute<\/code> becomes permanently uncallable and the rewards locked in <code class=\"codehl\">balanceOf[credId]<\/code> are irrecoverable.<\/p>\n<p><strong>[H-05] Public position-bookkeeping mutators allow arbitrary state tampering and sell-to-zero DoS<\/strong><\/p>\n<p>Both <code class=\"codehl\">_addCredIdPerAddress<\/code> and <code class=\"codehl\">_removeCredIdPerAddress<\/code> are declared <code class=\"codehl\">public<\/code> and accept an arbitrary <code class=\"codehl\">sender_<\/code> address with no access control. An attacker can remove a victim&#8217;s position entry out of band, corrupting the index mapping. When the victim later sells their full balance, the internal call to <code class=\"codehl\">_removeCredIdPerAddress<\/code> reverts with <code class=\"codehl\">WrongCredId<\/code> or <code class=\"codehl\">IndexOutofBounds<\/code> because the mapping was already tampered with, permanently blocking the sell-to-zero path for that position. Callers can also inject arbitrary entries to bloat position arrays and increase gas costs.<\/p>\n<p><strong>[H-06] Reentrancy via refund in _handleTrade buy path allows sell-lock bypass<\/strong><\/p>\n<p>The single-trade flow updates <code class=\"codehl\">lastTradeTimestamp[credId_][curator_]<\/code> only after refunding <code class=\"codehl\">excessPayment<\/code> via external call. A malicious contract can reenter during the refund and immediately call <code class=\"codehl\">sellShareCred<\/code> before the timestamp is updated. The lock check uses the stale timestamp, allowing immediate sell after buy and bypassing the cooldown period. The function lacks <code class=\"codehl\">nonReentrant<\/code> guard.<\/p>\n<p><strong>[H-07] Uncapped royaltyBPS allows royalties to exceed sale price, breaking ERC-2981 integrations and DoSing secondary sales<\/strong><\/p>\n<p><code class=\"codehl\">CreatorRoyaltiesControl._updateRoyalties<\/code> accepts any <code class=\"codehl\">royaltyBPS<\/code> value without an upper bound. When <code class=\"codehl\">royaltyBPS &gt; 10_000<\/code>, <code class=\"codehl\">royaltyInfo<\/code> returns a <code class=\"codehl\">royaltyAmount<\/code> greater than <code class=\"codehl\">salePrice<\/code>. Marketplaces that compute seller proceeds as <code class=\"codehl\">salePrice \u2212 royaltyAmount<\/code> will revert under Solidity 0.8 checked arithmetic, making affected token listings permanently unfillable. The misconfiguration is reachable by any art creator via <code class=\"codehl\">updateRoyalties<\/code> or <code class=\"codehl\">PhiFactory.updateArtSettings<\/code>.<\/p>\n<hr \/>\n<h3><a href=\"https:\/\/audits.sherlock.xyz\/contests\/968\"><strong>Superfluid<\/strong><\/a> <strong>(Sherlock, June 2025)<\/strong><\/h3>\n<p>Wake Arena finds 1 out of 2 high-severity issues reported by human researchers.<\/p>\n<p><strong>[H-01] provideLiquidity can spend staked tokens (no available-balance check), causing double counting and accounting breakage<\/strong><\/p>\n<p>Function <code class=\"codehl\">provideLiquidity<\/code> does not enforce that <code class=\"codehl\">supAmount<\/code> is bounded by the locker&#8217;s available (non-staked) balance. Staking only updates internal <code class=\"codehl\">_stakedBalance<\/code> while tokens remain in this contract&#8217;s address, so Uniswap&#8217;s position manager can pull staked tokens when minting an LP position. This violates the invariant <code class=\"codehl\">FLUID.balanceOf(this) &gt;= _stakedBalance<\/code>, enables double counting (same tokens accrue staking and LP rewards), and can later break accounting and unlock flows.<\/p>\n<hr \/>\n<h3><a href=\"https:\/\/code4rena.com\/audits\/2024-07-traitforge\"><strong>TraitForge<\/strong><\/a> <strong>(Code4rena, July 2024)<\/strong><\/h3>\n<p>Wake Arena finds 4 out of 6 high-severity issues reported by human researchers.<\/p>\n<p><strong>[H-01] Batch mint loop uses global _tokenIds, blocking mintWithBudget after generation-1 cap<\/strong><\/p>\n<p>The <code class=\"codehl\">mintWithBudget<\/code> while-condition compares global token counter <code class=\"codehl\">_tokenIds<\/code> against per-generation limit <code class=\"codehl\">maxTokensPerGen<\/code>. Because <code class=\"codehl\">_tokenIds<\/code> is monotonically increasing across all generations, after the first generation mints <code class=\"codehl\">maxTokensPerGen<\/code> tokens, the condition <code class=\"codehl\">_tokenIds &lt; maxTokensPerGen<\/code> becomes false forever, preventing any further batch mints in subsequent generations.<\/p>\n<p><strong>[H-02] Burn before airdrop start lets current holder reduce the initial minter&#8217;s airdrop allocation<\/strong><\/p>\n<p>In <code class=\"codehl\">burn(uint256 tokenId)<\/code>, while the airdrop has not started, the contract subtracts entropy from <code class=\"codehl\">initialOwners[tokenId]<\/code>. <code class=\"codehl\">initialOwners<\/code> is set at mint time and never updated on transfer. Any current holder or approved operator can burn the token before airdrop starts and force a deduction from the original minter&#8217;s airdrop allocation.<\/p>\n<p><strong>[H-04] Pre-forging into future generations bypasses per-generation cap via count reset on rollover<\/strong><\/p>\n<p><code class=\"codehl\">forge<\/code> allows minting into <code class=\"codehl\">newGeneration = getTokenGeneration(parent1Id) + 1<\/code> without requiring that <code class=\"codehl\">newGeneration == currentGeneration<\/code>. Tokens can be created in a future generation before public minting advances <code class=\"codehl\">currentGeneration<\/code>, correctly incrementing <code class=\"codehl\">generationMintCounts[newGeneration]<\/code>. However, when the contract later rolls over, <code class=\"codehl\">_incrementGeneration<\/code> unconditionally sets <code class=\"codehl\">generationMintCounts[currentGeneration] = 0<\/code> for the newly entered generation, erasing any count pre-accumulated via forging. This re-opens the full <code class=\"codehl\">maxTokensPerGen<\/code> capacity, enabling supply beyond the intended cap and underpricing subsequent public mints.<\/p>\n<p><strong>[H-05] Public minting ignores maxGeneration, allowing unlimited generations<\/strong><\/p>\n<p><code class=\"codehl\">maxGeneration<\/code> is enforced in <code class=\"codehl\">forge<\/code> via <code class=\"codehl\">require(newGeneration &lt;= maxGeneration)<\/code> but is absent from the public mint rollover path. When a generation fills during public minting, <code class=\"codehl\">_mintInternal<\/code> calls <code class=\"codehl\">_incrementGeneration<\/code>, which unconditionally increments <code class=\"codehl\">currentGeneration<\/code> with no bound check. Once the last intended generation is filled, public mints continue into generation 11, 12, and beyond, breaking the intended total supply cap.<\/p>\n<hr \/>\n<h3><a href=\"https:\/\/code4rena.com\/audits\/2025-04-virtuals-protocol\"><strong>Virtuals<\/strong><\/a> <strong>(Code4rena, April 2025)<\/strong><\/h3>\n<p>Wake Arena finds 6 out of 6 high-severity issues reported by human researchers.<\/p>\n<p><strong>[H-01] Permissionless validator registration enables sybil set inflation, base score manipulation, and gas-based DoS<\/strong><\/p>\n<p>Function <code class=\"codehl\">addValidator<\/code> is publicly callable and lacks access control, allowing any account to register an arbitrary validator for any <code class=\"codehl\">virtualId<\/code>. On call, <code class=\"codehl\">addValidator<\/code> unconditionally invokes <code class=\"codehl\">_addValidator<\/code> and <code class=\"codehl\">_initValidatorScore<\/code>, which appends to the per-virtual validator array and assigns a non-zero base score tied to the DAO&#8217;s proposal count. This enables sybil inflation of the validator set, upward manipulation of aggregated validator scoring via the non-zero base score, and unbounded growth of the <code class=\"codehl\">_validators[virtualId]<\/code> array, increasing gas costs in consumer loops like <code class=\"codehl\">totalUptimeScore<\/code> with realistic out-of-gas reverts in downstream flows.<\/p>\n<p><strong>[H-02] Third-party stake call overwrites victim&#8217;s entire vote delegation<\/strong><\/p>\n<p><code class=\"codehl\">AgentVeToken.stake<\/code> accepts arbitrary <code class=\"codehl\">receiver<\/code> and <code class=\"codehl\">delegatee<\/code> arguments and unconditionally calls <code class=\"codehl\">_delegate(receiver, delegatee)<\/code> without requiring the caller to be the <code class=\"codehl\">receiver<\/code>. Because <code class=\"codehl\">_delegate<\/code> updates the delegation for the receiver&#8217;s entire voting power \u2014 not just the newly minted amount \u2014 any address can dust-stake 1 wei to a victim and silently redirect all of the victim&#8217;s votes to an attacker-controlled delegatee. The attack is repeatable for as long as staking is enabled, making re-delegation an unreliable defense.<\/p>\n<p><strong>[H-03] Unbound virtualId in updateImpact enables cross-persona impact and dataset score manipulation<\/strong><\/p>\n<p>Function <code class=\"codehl\">updateImpact<\/code> accepts caller-controlled <code class=\"codehl\">virtualId<\/code> and <code class=\"codehl\">proposalId<\/code> and computes the baseline service using <code class=\"codehl\">_coreServices[virtualId][_cores[proposalId]]<\/code>, with no binding between the two parameters. The contract does not persist any mapping from <code class=\"codehl\">proposalId<\/code> to its originating persona, so any caller can pair a victim <code class=\"codehl\">proposalId<\/code> with an unrelated <code class=\"codehl\">virtualId<\/code> to compare maturity against the wrong persona&#8217;s last service or against zero. This directly changes <code class=\"codehl\">_impacts[proposalId]<\/code> and, when the proposal has an associated dataset, also rewrites <code class=\"codehl\">_impacts[datasetId]<\/code> and <code class=\"codehl\">_maturities[datasetId]<\/code>, corrupting cross-persona scoring.<\/p>\n<p><strong>[H-04] Unchecked parentId enables cross-DAO lineage forgery and unbounded children growth<\/strong><\/p>\n<p>The mint function accepts an arbitrary <code class=\"codehl\">parentId<\/code> and only enforces <code class=\"codehl\">parentId != proposalId<\/code>, then writes the linkage and appends to the parent&#8217;s children without validating that the parent exists, belongs to the same virtual persona, or that the caller is authorized to modify the parent&#8217;s lineage. This allows any proposer to forge cross-DAO ancestry, attach children to nonexistent parents, and bloat <code class=\"codehl\">_children[parentId]<\/code> for griefing. An attacker can make a token from DAO A appear as a child of a token minted by DAO B, or spam a popular parent with thousands of children, breaking assumptions of downstream consumers and making <code class=\"codehl\">getChildren(parentId)<\/code> heavy for indexers.<\/p>\n<p><strong>[H-05] Base-score initialization inflates validatorScore beyond totalProposals, causing reward distribution underflow DoS<\/strong><\/p>\n<p><code class=\"codehl\">_initValidatorScore<\/code> seeds a newly registered validator&#8217;s base score to <code class=\"codehl\">totalProposals<\/code> at the moment of registration. If the validator address already has non-zero <code class=\"codehl\">scoreOf<\/code> (from prior governance votes), the effective <code class=\"codehl\">validatorScore = totalProposals + preExistingVotes &gt; totalProposals<\/code>. In <code class=\"codehl\">_distributeValidatorRewards<\/code>, the participation slice is computed as <code class=\"codehl\">validatorRewards * validatorScore \/ totalProposals<\/code>; when the ratio exceeds 1, the subsequent <code class=\"codehl\">validatorPoolRewards -= participationReward<\/code> underflows and reverts in Solidity 0.8, permanently bricking reward distribution for that persona. Because <code class=\"codehl\">addValidator<\/code> is permissionless and validators cannot be removed, registering a single pre-voted address is enough to permanently DoS all future distributions.<\/p>\n<p><strong>[H-06] promptMulti can transfer to zero address or stale TBA because prevAgentId is never updated<\/strong><\/p>\n<p>The <code class=\"codehl\">promptMulti<\/code> loop initializes <code class=\"codehl\">prevAgentId<\/code> to 0 and <code class=\"codehl\">agentTba<\/code> to <code class=\"codehl\">address(0)<\/code> but never updates <code class=\"codehl\">prevAgentId<\/code> inside the loop. The refresh condition <code class=\"codehl\">if (prevAgentId != agentId)<\/code> therefore fails when <code class=\"codehl\">agentId == 0<\/code>, leaving <code class=\"codehl\">agentTba<\/code> unchanged. For the first element where <code class=\"codehl\">agentId == 0<\/code>, <code class=\"codehl\">agentTba<\/code> remains <code class=\"codehl\">address(0)<\/code> and <code class=\"codehl\">token.safeTransferFrom(sender, agentTba, amounts[i])<\/code> attempts a transfer to the zero address, causing standard ERC20 tokens to revert. For any later element where <code class=\"codehl\">agentId == 0<\/code> follows a non-zero <code class=\"codehl\">agentId<\/code>, the stale <code class=\"codehl\">agentTba<\/code> from the previous agent is reused, misdirecting funds to the wrong recipient.<\/p>\n<hr \/>\n<h2><strong>Acknowledgments<\/strong><\/h2>\n<p>We thank Lido, Printr, Everstake, and LUKSO for participating in the production validation of Wake Arena.<\/p>\n<hr \/>\n<h2><strong>Access<\/strong><\/h2>\n<p>Wake Arena: <a href=\"http:\/\/ackee.xyz\/wake\/arena\"><strong>ackee.xyz\/wake\/arena<\/strong><\/a><\/p>\n<p><a href=\"https:\/\/forms.gle\/6ysoSkWpfWQkMdbv9\" target=\"_blank\" rel=\"noopener\">Request access<\/a><\/p>\n<hr \/>\n<p><em>Ackee Blockchain Security<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wake Arena: Multi-Agent AI Audit with Graph-Driven Reasoning Benchmarked on audit competitions and production protocols December 2025: Josef Gattermayer, Ph.D.1,2 Michal P\u0159evr\u00e1til1 Martin Vesel\u00fd1 Andrei Shchapaniak1 Josef Bazal1 1Ackee Blockchain 2Czech Technical University in Prague Executive Summary We present Wake Arena, a service for discovering vulnerabilities in Solidity smart contracts through multi-agent AI analysis with graph-driven reasoning. Wake Arena 3.1 discovered 63&hellip;<\/p>\n","protected":false},"author":30,"featured_media":1236,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[65,10,161],"tags":[24,64,162],"class_list":["post-1227","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-announcements","category-ethereum","category-wake-arena","tag-ethereum","tag-security","tag-wake-arena"],"aioseo_notices":[],"featured_image_src":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/12\/wa-cover-600x400.png","featured_image_src_square":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2025\/12\/wa-cover-600x600.png","author_info":{"display_name":"Tom\u00e1\u0161 Kova\u0159\u00edk","author_link":"https:\/\/ackee.xyz\/blog\/author\/tomas-kovarik\/"},"_links":{"self":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/1227","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/users\/30"}],"replies":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/comments?post=1227"}],"version-history":[{"count":0,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/1227\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media\/1236"}],"wp:attachment":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media?parent=1227"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/categories?post=1227"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/tags?post=1227"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}