
Loading...
Loading
Loading...
LoadingLoading audit report...

WalletGuard.ai, powered by Gestalt Labs
Forge fork-validation ran but no findings met the threshold for PoC inclusion. See the per-finding "Forge validated" badges in the report below for individual results.
FeeAMM is a custom automated market maker designed to facilitate fee token exchanges between stablecoins for validators on the Tempo payment protocol. The analysis identified 3 critical, 8 high, 7 medium, 1 low, and 2 informational findings, plus 2 adversarial findings escalated during synthesis. The single most dangerous pattern is the pool initialization vulnerability in mint(), which accepts only one token during pool creation, enabling a complete donation-attack drain of all subsequent LP funds via reserve inflation. Overall, this contract is unsafe for production deployment: it contains multiple independently exploitable critical vulnerabilities including an inverted fee formula in rebalanceSwap(), a donation-based pool drain, and a zero-burn griefing path that destroys total supply without removing reserves.
When a new pool is created, the contract only requires one type of token to be deposited. An attacker can create a pool with 1 wei of one token, then send a large amount of the other token directly to the contract (bypassing the deposit function), and then mint LP shares at an artificially favorable rate. When they withdraw, they collect both tokens and profit at the expense of every other liquidity provider. This can drain 100% of pool funds.
The formula used in rebalanceSwap() to calculate how much a user must pay is mathematically inverted. Instead of charging a fee on top of the token value, the formula divides by the fee rate, meaning users pay less than the fair value of the tokens they receive. Anyone can repeatedly call this function to extract validatorTokens at a discount, draining the protocol's reserves over time.
An attacker holding any LP tokens can repeatedly call the burn function with a tiny amount of LP shares and receive zero tokens back, while still reducing the total supply count. If done millions of times, the total supply drops to near zero while all pool reserves remain. The next person to add liquidity receives an astronomically large share count, allowing them to immediately withdraw nearly all reserves from the pool.
The two swap functions charge different fee rates, and combining them creates a profitable arbitrage loop. A trader can swap tokens through executeFeeSwap in one direction and then swap back through rebalanceSwap, ending up with more tokens than they started with. This cycle can be repeated indefinitely, systematically draining the pool's reserves with each round trip.
An attacker first calls mint() with only validatorToken, creating a pool with zero reserveUserToken (Finding 1). Because the contract accepts single-token initialization, no userToken is locked. The attacker then directly transfers a large amount of userToken to the contract address, inflating pool.reserveUserToken without issuing proportional liquidity shares. On the next mint() call, the weighted liquidity formula uses the inflated reserveUserToken in the denominator but only the attacker's small new validatorToken deposit in the numerator, yielding disproportionate LP shares. The attacker burns these shares via burn() (Finding 4) to extract both tokens. The zero-amount burn griefing path (Finding 15) further enables the attacker to manipulate the totalSupply/reserve ratio before executing the drain, maximizing extraction. Combined severity is critical because each step reinforces the next.
The inverted fee formula in rebalanceSwap() (Finding 6) means users pay less than fair value for userToken. An attacker can amplify this by first calling executeFeeSwap with identical token addresses (Finding 5/25) to inject tokens into a self-referential pool, manipulating the reserve ratios. The attacker then calls rebalanceSwap on the manipulated pool to extract validatorToken at the discounted rate. Because reserveUserToken is artificially inflated by the identical-token swap, the pool has more apparent liquidity, and the inverted fee formula allows the attacker to drain it faster than the fee revenue can compensate.
An attacker holding minimal LP tokens (as few as 1 wei, obtainable via the single-token mint vulnerability in Finding 1) can repeatedly call burn() with liquidity=1. If pool.reserveUserToken or reserveValidatorToken is small relative to totalSupply, _calculateBurnAmounts() returns (0, 0) (Finding 15, Finding 24). The burn succeeds, decrementing totalSupply and liquidityBalances[attacker] by 1 each call, while reserves remain unchanged. This asymmetric decay is compounded by the mint() formula (Finding 13) which divides by totalSupply: once totalSupply approaches zero, any subsequent mint() call either reverts on division by zero or mints an astronomically large share, allowing the attacker to claim the entire reserve in one final burn.
All transfer() and transferFrom() calls lack return value checks (Finding 16). If a token's transfer fails silently (returns false instead of reverting), the pool's reserve counters are decremented as if the transfer succeeded. Combined with the fee formula asymmetry (Findings 2, 6, 7), an attacker can repeatedly trigger silent transfer failures during outbound transfers in executeFeeSwap(), accumulating reserve decrements without actual token outflows. The resulting reserve undercount makes the pool appear less liquid than it is, suppressing the prices computed by the mint() weighted formula and allowing subsequent LPs to mint shares cheaply. These cheaply-minted shares can then be burned to claim the real (underdecremented) token balance.
Step 1: Attacker calls mint() with 1 wei validatorToken to initialize a pool (exploiting the single-token init flaw). The pool has reserveUserToken=0 and tiny reserveValidatorToken. Step 2: Attacker directly transfers a large amount of userToken to the contract address, inflating the pool's effective userToken balance without updating reserveUserToken (the reserve only updates on mint/swap calls). Step 3: Attacker calls mint() again with minimal validatorToken; the weighted-denominator formula assigns disproportionately large liquidity shares because the reserve ratio is skewed. Step 4: Attacker calls burn() to extract both tokens, draining the pool. If other LPs have deposited in the interim, they lose everything. As an alternative attack vector, attacker calls burn(1) repeatedly to drain totalSupply toward zero without removing reserves, causing future mint() pricing to break catastrophically.
The inverted fee formula in rebalanceSwap() (Finding 6) means users pay less than fair value for every userToken received. Combined with the fee asymmetry between executeFeeSwap (0.3% fee) and rebalanceSwap (effectively a discount), an attacker can: (1) Call executeFeeSwap to convert 10,000 userToken into 9,970 validatorToken, paying 30 units as fee. (2) Call rebalanceSwap requesting 9,970 userToken output; the inverted formula computes amountIn = (9970 * 9985) / 10000 + 1 = 9,956 validatorToken. Attacker pays 9,956 and receives 9,970 userToken. (3) Net result after round trip: started with 10,000 userToken, now has 9,970 + 14 = net position showing 14 validatorToken profit. Repeated at scale, this drains all validatorToken reserves. The protocol's own fee structure enables the attack with no special privileges required.
executeFeeSwap and rebalanceSwap lack the userToken != validatorToken check present in mint/burn. An attacker calls executeFeeSwap(TOKEN_A, TOKEN_A, X): the contract takes X TOKEN_A from the caller, adds X to reserveUserToken, subtracts 0.997X from reserveValidatorToken, and sends 0.997X TOKEN_A back. Net: attacker spent 0.003X tokens, pool's reserveUserToken increased by X while reserveValidatorToken decreased by 0.997X. Repeating this skews the reserve ratio arbitrarily. Once the reserve ratio is sufficiently distorted, the attacker calls mint() with minimal validatorToken, receiving inflated liquidity shares due to the skewed denominator in the weighted formula. Finally, burn() drains the pool at the artificially inflated ratio, stealing from all honest LPs.
An attacker who holds any LP tokens calls burn(1) repeatedly. Each call burns 1 unit of liquidity and (due to rounding in _calculateBurnAmounts) returns 0 tokens to the attacker. The pool's totalSupply and the attacker's liquidityBalance both decrease by 1 each call. If the attacker has 10^6 LP tokens, they can reduce totalSupply by 10^6 with no token cost beyond gas. When totalSupply reaches 0 while reserves remain non-zero, subsequent mint() calls in the non-initial branch compute liquidity = (amountValidatorToken * 0) / denom = 0, then hit the require(liquidity != 0) check and revert. The pool becomes permanently bricked: burn() requires liquidity > 0 and liquidityBalance >= liquidity, but if the attacker drained all LP tokens, no one can burn. The reserves are permanently locked.
The contract does not use SafeERC20 and does not check return values from transfer/transferFrom. If a token's transfer() returns false (e.g., USDC with OFAC blacklisting, or a paused token), the reserve update still executes. For example, in executeFeeSwap: transferFrom(sender, contract, amountIn) fails silently -> pool.reserveUserToken += amountIn (pool believes it received tokens it did not). On the validatorToken transfer: IERC20(validatorToken).transfer(sender, amountOut) fails silently -> pool.reserveValidatorToken -= amountOut (pool believes it sent tokens it did not). The pool now tracks phantom reserves. Combined with the fee asymmetry, an attacker can exploit the phantom reserves by calling rebalanceSwap against the inflated userToken reserve, receiving real validatorToken while paying nothing. This causes direct fund loss for all honest LPs.
In Solidity 0.7.6 (which this contract uses), arithmetic does not have implicit overflow protection. In executeFeeSwap, amountOut is computed as (amountIn * M) / SCALE before _requireU128(amountIn) is called. If a user supplies amountIn close to type(uint256).max / M (approximately 1.16e73), the multiplication amountIn * M silently overflows uint256 and wraps to a small value. After division by SCALE, amountOut is tiny. The user's transferFrom succeeds for the huge amountIn, pool.reserveUserToken is incremented by the huge value (which also overflows uint128 unless _requireU128 catches it), and the user receives nearly nothing. The overflow check sequence is: compute amountOut (may overflow), then check _requireU128(amountIn) and _requireU128(amountOut). Since amountOut wraps to a small number, it passes the uint128 check, but the user already transferred a massive amount. Combined with the identical-token-address bug, an attacker can construct overflow scenarios that corrupt both reserves simultaneously.
The pool does not enforce a constant-product or any other invariant across swaps. executeFeeSwap and rebalanceSwap use flat fee percentages regardless of reserve ratios, meaning an attacker can push the reserve ratio arbitrarily far from equilibrium at the cost of the fee alone. After skewing reserves via repeated swaps, the attacker calls mint() with validatorToken; the weighted-denominator formula (N*reserveUserToken/SCALE + reserveValidatorToken) becomes heavily biased, minting far more or far fewer shares than fair value depending on which reserve was inflated. The attacker then burns to extract disproportionate reserves, net-extracting from honest LPs who cannot exit without loss.
An attacker exploits the zero-amount burn vulnerability (Finding 15) to systematically reduce totalSupply[poolId] to near-zero without withdrawing any reserves. Once totalSupply approaches zero, the attacker calls mint() with a small amountValidatorToken. With a near-zero totalSupply, the mint formula computes an astronomically large liquidity share for the attacker. The attacker then calls burn() with those shares, extracting essentially all remaining reserves. Combined with the inverted rebalanceSwap fee formula (Finding 6) that undercharges callers, the attacker can also pre-drain validator token reserves before executing the share collapse, maximizing the value stolen.
An attacker first exploits the missing userToken != validatorToken check in executeFeeSwap (Finding 5/25) to create a same-token pool entry with an inflated reserveUserToken. They then call the one-sided mint() (Finding 1) with the validatorToken corresponding to the inflated userToken pool, triggering the weighted denominator formula that misprices liquidity shares because reserveUserToken is now corrupted. The attacker receives outsized liquidity shares relative to their deposit, then burns to extract both tokens from the pool, draining honest LPs.
The inverted rebalanceSwap formula (Finding 6) charges users less than fair value on every call. Combined with the executeFeeSwap fee direction mismatch (Finding 7) and the division rounding that systematically favors callers (Findings 4, 11, 12), a sophisticated attacker can construct a cyclic call sequence: executeFeeSwap followed by rebalanceSwap. Each cycle extracts a small net positive value due to the fee rate mismatch (0.3% vs 0.15%) and the inverted formula in rebalanceSwap. Repeated with flash-loan-scale capital, this drains pool reserves continuously without any capital at risk.
The missing ERC20 return value check (Finding 16) allows a transfer-out to silently fail while reserve accounting proceeds as normal. If the validatorToken is a token that returns false on transfer (rather than reverting), executeFeeSwap decrements pool.reserveValidatorToken without the corresponding tokens actually leaving the contract. An attacker can pair this with the zero-burn vulnerability (Finding 15): after the reserve accounting is corrupted, burning LP shares against the now-incorrect reserve values allows the attacker to withdraw more tokens than their actual proportional share, draining honest LP funds.
| Agent | Status | Findings | Severity | Confidence | Duration | Coverage |
|---|---|---|---|---|---|---|
| reentrancy | success | 25 | 85% | 3.8m | Cross-function reentrancy via external token transfers, K-invariant AMM formula correctness in mint and burn, Fee asymmetry between executeFeeSwap and rebalanceSwap, Rounding and precision loss in arithmetic operations, Input validation on token addresses, Unsafe down-casts from uint256 to uint128, Pool initialization with single token type, Donation attack patterns via liquidity seeding, Division before multiplication precision issues, Reciprocal swap formula consistency, Cross-function reentrancy via external calls, K-invariant violations in AMM formulas, Fee asymmetry and arbitrage opportunities, Unsafe downcasts and overflow/underflow, Rounding and precision loss in division-before-multiplication, Fee-on-transfer token handling, Return value checks on ERC20 transfers, Slippage protection and frontrunning vectors, Initial pool creation and donation attacks, Liquidity share calculation formulas, Division-before-multiplication precision loss in all arithmetic operations, Rounding direction in fee calculations (executeFeeSwap, rebalanceSwap), AMM K-invariant maintenance across swaps and liquidity operations, LP token mint/burn symmetry and share calculation, Pool reserve state consistency and bounds checking, Round-trip symmetry in reciprocal swap functions, Unsafe uint128 casts on user-controlled inputs, Missing userToken deposit in mint function, Rebalance swap offset asymmetry | |
| access control | success | 28 | 84% | 3.9m | Access control on all state-modifying functions (mint, burn, executeFeeSwap, rebalanceSwap), Reserve overflow/underflow in pool state updates, Fee asymmetry between executeFeeSwap (uses M) vs rebalanceSwap (uses N), Liquidity calculation in mint() for initial vs subsequent mints, Burn amount validation and zero-value transfers, Pool initialization logic and imbalanced reserve handling, Div-by-zero conditions in mint() when totalSupply is zero, Cast safety and bounds checking on uint128 operations, Access control and authorization (mint, burn, executeFeeSwap, rebalanceSwap), Liquidity pool initialization and invariant maintenance, Fee calculation and asymmetry between two swap paths, Rounding direction in division-before-multiplication patterns, Unsafe uint256 to uint128 downcasts and overflow checks, Reserve state corruption and pool balance tracking, Input validation on address parameters and amounts, Share accounting and LP withdrawal calculations, Mathematical consistency between related functions, Precision loss in repeated operations, Access control and authorization (all functions public/external, no onlyOwner guards), Rounding direction in all divisions (executeFeeSwap, rebalanceSwap, mint, _calculateBurnAmounts), Integer overflow/underflow via unsafe casts (uint128 casts in mint, burn, executeFeeSwap, rebalanceSwap), DEX invariant correctness (K-invariant assumptions, fee asymmetry between swap directions), LP token math (mint/burn parity, initial liquidity handling, MIN_LIQUIDITY cliff), Cross-function consistency (swap fees, reserve updates, total supply accounting), Reserve sufficiency checks (before and after transfers), Asymmetric pool initialization (zero-reserve cases), Division-before-multiplication precision loss across all arithmetic paths | |
| economic | success | 27 | 82% | 3.9m | Fee swap path (executeFeeSwap) for fee asymmetry and rounding loss, Rebalance swap path (rebalanceSwap) for overflow and underflow conditions, Liquidity provision (mint) for proper reserve initialization and LP share calculation, Liquidity withdrawal (burn) for rounding loss in share redemption, Pool invariant maintenance across all state-mutating functions, Cross-function flow analysis for state consistency, Input validation and bounds checking (uint128 overflow protections), Token transfer order and reentrancy patterns, Asymmetric fee structure between executeFeeSwap and rebalanceSwap, Initial liquidity calculation and first-minter donation attack in mint(), Division-before-multiplication precision loss in mint() and burn(), Unsafe uint256 to uint128 downcasts and overflow checks, Missing K-invariant enforcement and pricing constraints, Fee-on-transfer token handling in executeFeeSwap(), Slippage protection and MEV exposure, Input validation on token addresses and parameters, Liquidity balance management in burn(), Hardcoded offsets and rounding asymmetries across functions, Rounding direction in swap and fee calculations (executeFeeSwap, rebalanceSwap), Precision loss in division operations (_calculateBurnAmounts, mint, burn), MEV and sandwich attack vectors (missing slippage protection, missing deadline), Fee-on-transfer token handling (balance delta verification), Integer overflow in arithmetic (Solidity 0.7.6 context), LP token inflation attacks (first-depositor attack, disproportionate contributions), Race conditions in burn and concurrent operations, Token transfer return value validation, Pool invariant maintenance across mint/burn/swap operations, Cross-function consistency in reserve accounting | |
| logic validation | success | 28 | 77% | 4.1m | Input validation on all external functions (mint, burn, executeFeeSwap, rebalanceSwap), Arithmetic safety: division-before-multiplication patterns, rounding direction, overflow in uint128 conversions, Pool state consistency: reserve updates vs. totalSupply, liquidity tracking, Fee calculation paths: executeFeeSwap vs rebalanceSwap formula asymmetry, ERC-20 integration: fee-on-transfer token handling, transfer ordering, Slippage protection and frontrunning vectors, Pool initialization and minimum liquidity logic, Arithmetic overflow/underflow in Solidity 0.7.6 (no built-in overflow protection) with uint256 multiplication in executeFeeSwap and rebalanceSwap, Unsafe downcasts from uint256 to uint128 in pool reserve updates, Precision loss from division-before-multiplication in mint(), _calculateBurnAmounts(), and rebalanceSwap(), Asymmetric fee structure between executeFeeSwap (M=9970) and rebalanceSwap (N=9985), Pool initialization asymmetry in mint() accepting only validatorToken, Zero-amount burn bypass allowing reserve ratio inflation without reserve removal, Rounding direction inconsistencies in swap and liquidity calculations, Pool state imbalance created by asymmetric initialization, Liquidity calculation weighting formula using fee constants instead of proportional reserves, Rounding direction in all division operations (executeFeeSwap, rebalanceSwap, mint, burn, _calculateBurnAmounts), LP token minting/burning mechanics and liquidity share calculation, AMM invariant enforcement (lack thereof in rebalanceSwap), Fee structure parity between executeFeeSwap (0.3%) and rebalanceSwap (0.15%), Pool reserve state transitions across all functions, Cross-function consistency: mint/burn, executeFeeSwap/rebalanceSwap round-trip behavior, MIN_LIQUIDITY burn application and asymmetry between first and subsequent deposits, Precision loss accumulation in repeated burns and swaps | |
| code quality | success | 27 | 86% | 4.7m | ERC-20 transfer/transferFrom return value handling, Fee calculation asymmetry between executeFeeSwap and rebalanceSwap, Liquidity minting formula and its weighting of token reserves, First-depositor pool initialization logic, Rounding direction in division operations (amountOut calculations), Unsafe uint256 to uint128 downcasts, Off-by-one errors in arithmetic (none found), Access control (none present, contract allows open liquidity operations), ERC-20 transfer/transferFrom compliance and return value handling, Fee calculation asymmetry between executeFeeSwap (M=9970) and rebalanceSwap (N=9985), Unsafe uint256 to uint128 downcasts in rebalanceSwap and executeFeeSwap, Division-before-multiplication precision loss in mint and burn, Initial pool liquidity calculation and inflation attack vectors, Rounding direction errors and favor asymmetry in swap pricing, Pool reserve state corruption via self-referential tokens, Liquidity share calculation formulas for fairness and MEV, Slippage protection and frontrunning vulnerability, Authorization checks on burn and mint operations, Accumulation of rounding errors across multiple transactions, ERC-20 transfer safety and return value handling, Unsafe downcasts from uint256 to uint128 without prior bounds checking, Rounding direction in division operations (burn amounts, rebalance fees), Fee asymmetry between executeFeeSwap and rebalanceSwap directional swaps, Fee-on-transfer token compatibility in pool reserve accounting, Liquidity mining and burn mechanics for share price calculations, AMM K-invariant preservation across swap operations, Sandwich attack vectors and slippage protection, Mint function first-depositor inflation defense (MIN_LIQUIDITY burn), Pool initialization and imbalanced reserve scenarios, Rounding errors in small-amount swaps (fee granularity), Cross-function consistency in reserve updates | |
| compiler bugs | success | 11 | 75% | 2.3m | Fee path asymmetry between swap functions (patterns #1 high), Rounding direction and division-before-multiplication (patterns #4, #6), Unsafe down-cast from uint256 to uint128 on user input (pattern #8), K-invariant and AMM pool arithmetic, Liquidity minting/burning and inflation attacks (patterns #9, #10), Cross-function reentrancy via IERC20 transfers, Input validation on all public functions, Pool initialization and liquidity minting in mint() function - found critical donation-attack flaw, Fee asymmetry between executeFeeSwap and rebalanceSwap - found critical fee-direction mismatch, Overflow and underflow in state mutations - verified most checks are correctly placed, no overflow bypass found, burn() function for LP withdrawal - found zero-amount transfer vulnerability, Input validation across all swap and LP functions - found missing userToken != validatorToken check in mint(), Rounding direction in swap calculations - found +1 overpayment in rebalanceSwap, Decimal conversion and scaling - contract assumes all tokens have same decimal handling (no cross-decimal math found), Reentrancy and CEI violations - contract uses transferFrom before state update in most cases, but executeFeeSwap has CEI issue, TWAP and oracle dependencies - no oracle calls found, only reserve-based AMM pricing, Rounding direction in mint() liquidity calculation (division-before-multiplication), Fee asymmetry between executeFeeSwap (M=9970) and rebalanceSwap (N=9985), Round-trip swap symmetry and arbitrage paths, LP token issuance and redemption parity, Precision loss from repeated integer division in _calculateBurnAmounts, Pool invariant maintenance (reserves consistency), Cross-function consistency in fee calculations | |
| assembly safety | success | 15 | 78% | 4.6m | Inline assembly blocks and unsafe operations, Non-ASCII and homoglyph characters in identifiers and strings, Fee path asymmetry between executeFeeSwap and rebalanceSwap, AMM K-invariant and pricing constraints, Precision loss in division-before-multiplication arithmetic, Overflow and underflow in uint128 reserves, Pool initialization and liquidity calculations, Input validation on user-supplied addresses and amounts, Rounding direction in all arithmetic operations (mint, burn, executeFeeSwap, rebalanceSwap), Fee structure consistency across executeFeeSwap (M=9970) vs rebalanceSwap (N=9985) vs mint (N=9985) formulas, Division-before-multiplication precision loss in _calculateBurnAmounts, Unsafe down-casts to uint128 in executeFeeSwap and rebalanceSwap, Initial liquidity lock-up behavior in mint with MIN_LIQUIDITY, Consistency of fee rates between different swap functions, Input validation for zero-amount swaps, Cross-function invariants (round-trip symmetry, fee consistency), Pool invariant maintenance (reserve balance tracking), Liquidity provider share calculations for initial and subsequent deposits | |
| l2 specific | success | 25 | 84% | 4.4m | Fee asymmetry between executeFeeSwap and rebalanceSwap swap directions, Division-before-multiplication rounding in mint, burn, and swap calculations, Integer overflow and unsafe uint128 downcasts in executeFeeSwap and rebalanceSwap, Liquidity share price precision across mint/burn lifecycle, Initial pool creation (mint) logic for dead-share handling, Reserve accounting and state transitions in all swap functions, Chainlink oracle and price feed usage (none present, N/A), Fee asymmetry between executeFeeSwap and rebalanceSwap - verified M vs N constants and pricing formulas, Initial pool initialization in mint() - identified missing userToken reserve setup and liquidity formula flaws, Division-before-multiplication rounding patterns - checked mint and burn calculation orders, Overflow and underflow in uint128 casts - examined _requireU128 checks and reserve updates, Burn amount validation - confirmed missing zero-amount checks in calculated transfers, rebalanceSwap +1 offset - verified hardcoded rounding implementation, Pool reserve manipulation via zero-value transfers - traced burn path with zero amounts, Two-token AMM invariant enforcement - checked if K-invariant or pricing constraints exist, Cross-function state consistency - verified reserve updates across executeFeeSwap, rebalanceSwap, mint, burn, Input validation completeness - reviewed all require statements and missing validations, Rounding direction in division operations (burn, mint, swap), Unsafe uint128 casts and overflow checks in pool reserve updates, Cross-function consistency between swap fee rates and pricing models, AMM invariant correctness (K-invariant, weighted invariants), Precision loss in accumulated arithmetic (division before multiplication), Input validation for token address distinctness across all swap functions, Liquidity check boundary conditions and MEV vectors, Edge cases in LP token calculations (zero-amount burns, rounding-to-zero scenarios), First-LP mint behavior and MIN_LIQUIDITY handling | |
| math verification | success | 17 | 72% | 4.4m | mint() initial liquidity calculation with division-before-subtraction precision loss, mint() non-initial liquidity calculation asymmetric formula, mint() one-sided liquidity provision vulnerability, executeFeeSwap() fee calculation and rounding direction, rebalanceSwap() amountIn calculation and overflow checks, burn() share verification and proportional redemption, Liquidity balance tracking and totalSupply invariant, Pool reserve management across all functions, Cross-function consistency (mint-burn-swap state transitions), Fee calculation asymmetry between executeFeeSwap (M=9970) and rebalanceSwap (N=9985), mint() function initial liquidity calculation and single-token deposit vulnerability, burn() function rounding direction and precision loss in withdraw calculations, rebalanceSwap() amountIn calculation and +1 offset correctness, Unsafe uint128 down-cast patterns and overflow checks, Cross-function state consistency between mint and burn, Pool K-invariant enforcement and economic incentives, Liquidity calculation precision loss in mint(), Rounding direction in burn() / _calculateBurnAmounts() - systematic under-payout to LPs, Fee asymmetry between executeFeeSwap (M=9970) and rebalanceSwap (N=9985) - round-trip imbalance, Arbitrary recipient in rebalanceSwap() - forced fund transfer vulnerability, Pool initialization via MIN_LIQUIDITY dead shares - intentional design, Pool existence checks in burn() - implicit guard via liquidityBalance, Division-before-multiplication in entire contract, Cross-function consistency between mint/burn/swap operations, Unsafe down-cast validation via _requireU128(), Overflow checks in pool reserve updates |
Zod validation failed: findings.3.affectedFile: Invalid input: expected string, received null; findings.3.affectedLines: Invalid input: expected string, received null; findings.3.codeSnippet: Invalid input: expected string, received null; findings.3.impact: Invalid input: expected string, received null; findings.3.remediation: Invalid input: expected string, received null; findings.6.affectedFile: Invalid input: expected string, received null; findings.6.affectedLines: Invalid input: expected string, received null; findings.6.codeSnippet: Invalid input: expected string, received null; findings.6.impact: Invalid input: expected string, received null; findings.6.remediation: Invalid input: expected string, received null; findings.8.affectedFile: Invalid input: expected string, received null; findings.8.affectedLines: Invalid input: expected string, received null; findings.8.codeSnippet: Invalid input: expected string, received null; findings.8.impact: Invalid input: expected string, received null; findings.8.remediation: Invalid input: expected string, received null
How this affects your report: findings normally surfaced by this specialist are missing; overlapping coverage from other agents still applies.
This automated audit has inherent limitations. The following areas are not covered.
This report is an automated point-in-time assessment and does not guarantee protection against all possible attacks. It does not cover off-chain components, economic modeling, or business logic correctness unless explicitly noted. Changes to the contract after the audit commit are not reviewed. This is not financial or legal advice. WalletGuard, powered by Gestalt Labs, provides this analysis as-is with no warranty of completeness.
[](https://walletguard.ai/audit/16ae9122-dd85-42ae-9c23-679c1ee0df1c)
<a href="https://walletguard.ai/audit/16ae9122-dd85-42ae-9c23-679c1ee0df1c"> <img src="https://walletguard.ai/api/badge/16ae9122-dd85-42ae-9c23-679c1ee0df1c" alt="WalletGuard Audit Badge" /> </a>