EVRGRoW SMART CONTRACT AUDIT
Summary. This is an eight-part review of the EVRGROW contract covering its published claims, the deployed bytecode, and automated analysis via Slither and Mythril. The deployed bytecode was independently reproduced from the published source byte for byte, so the code reviewed here is provably the code running on Base. No exploitable findings were identified: there are no hidden entry points, no mechanism to destroy the contract or execute outside code through it, and with ownership renounced the entire privileged function surface is permanently unreachable. One aspect of the design warrants attention regardless — the 1% burn and 1% LP tax apply only to trades against the main ETH Uniswap V2 pool, not to the other sixteen.
Verification that contract behavior matches all published claims
renounceOwnership() on Nov 18, 2025. Tx: 0xdcedf353...87cf. No party can ever call owner-only functions again.autoBurnFees set to [100, 100, 0]. Burns reduce totalSupply directly — not a burn wallet. This fires only on transfers where one side is the main ETH Uniswap V2 pool — the only pool registered in the AMMs mapping — see Part 5, Check 6 for detail on scope across the other 16 pools._liquidityPending; auto-injected into the Uniswap V2 ETH pool when the threshold is reached. Applies only to trades against the main pool — the same scope restriction as the burn fee, since both are governed by the same AMMs-mapping check.address(0xdead) inside _addLiquidity() — irrecoverable by design. Core initial LP separately locked via UNCX.swapThresholdRatio set to 50 (50/10000 = 0.5% of pool balance). Injection is automatic and permissionless.address(0) (burn) and the contract itself (LP). No team wallet, treasury, or marketing recipient anywhere in the code.AMMs mapping determines which transfers are treated as taxable buys/sells. Only the main ETH Uniswap V2 pool (0x2aa028...338e) is registered in this mapping. The 1% burn + 1% LP tax therefore fires only on transfers where one side is that main pool. The other 16 liquidity pools (Uniswap V3/V4, Aerodrome, SushiSwap, PancakeSwap, Curve, Balancer/CoW Swap, HydrexFi) are legitimate, tradeable EVRGROW pools, but trades confined to those pools — including multi-hop routes that never touch the main ETH V2 pool — do not trigger the tax. Practical consequence: buying or selling EVRGROW on any pool other than the main ETH V2 pair produces no burn and no LP contribution. Evidence basis: transaction 0xe9082639...d4fd1a3f, a multi-hop route through the BNKR and ETH/Aerodrome pools, moved 37,620 EVRGROW and emitted no AutoBurned or LiquidityAdded event — the fee events that appear in that transaction are Aerodrome's own 0.3% pool fee, a separate mechanism. See the methodology note at the end of this report for the verification status of the registration scope itself.Analysis performed on the deployed runtime bytecode, including independent reproduction of it from source
Most of this report reads the Solidity source published on BaseScan. That inherits one assumption: that the deployed bytecode actually corresponds to that source. Check 1 removes the assumption entirely by recompiling the source and comparing the result byte-for-byte against what is deployed. The remaining checks analyse the deployed bytecode directly and hold regardless of any source file.
0.8.25+commit.b61c2a91, optimizer enabled at 200 runs, EVM target paris — the exact settings recorded in the contract's own metadata — and the resulting runtime bytecode compared against the bytecode deployed on Base. Both are 8,485 bytes. Excluding the 53-byte CBOR metadata trailer, every one of the 8,432 executable bytes matches exactly. The metadata trailer differs only in its IPFS hash, which digests source file text; the dependency files were reconstructed from their behavior, so comments and whitespace differ while the compiled logic does not. This is the strongest available evidence that the source under review is the source that produced the contract running on Base — it no longer rests on the block explorer's verification label, and it is reproducible by anyone with the same compiler and settings.SELFDESTRUCT, DELEGATECALL, CALLCODE, CREATE and CREATE2 appear zero times. These absences are categorical rather than inferential: the contract cannot be self-destructed, cannot execute borrowed code from another address, cannot be converted into a proxy, and cannot deploy child contracts. Confirms SWC-106 and SWC-112 at the artifact level.autoBurnFeesSetup, liquidityFeesSetup, updateSwapThreshold, excludeFromFees, setAMM, transferOwnership and renounceOwnership. Both OwnableUnauthorizedAccount(address) revert sites (selector 0x118cdaa7) were located in the bytecode at PC 2967 and PC 4469, confirming every privileged entry point routes through the owner check. With owner permanently set to address(0), no caller can satisfy that check — the entire privileged surface is unreachable. Separately, afterConstructor is a one-shot initializer already consumed at deployment; the 'Initializable: contract is already initialized' revert string is present in the bytecode and any further call reverts. This converts several 'not exploitable because renounced' claims elsewhere in this report from argument into structural fact.CALL and 3 STATICCALL sites and zero DELEGATECALL. Every outbound selector resolves to a documented Uniswap V2 interface method: factory(), WETH(), createPair(address,address), swapExactTokensForETHSupportingFeeOnTransferTokens(...) and addLiquidityETH(...). No unexpected external callouts. Remaining PUSH4 constants are custom error selectors and Solidity panic codes, not call targets.| Check | Method | Result |
|---|---|---|
| Executable bytes vs. recompiled source | Byte-for-byte diff | 8,432 / 8,432 identical |
| SELFDESTRUCT / DELEGATECALL / CALLCODE | Opcode scan | 0 occurrences |
| CREATE / CREATE2 | Opcode scan | 0 occurrences |
| Selectors in bytecode vs. published ABI | Dispatcher extraction + keccak-256 | 33 / 33 match |
| Undocumented entry points | Set difference | 0 — none found |
| Selector collisions | Hash uniqueness | 0 — all distinct |
| Owner-gated functions reachable | Revert-site trace | 0 — all dead code |
| External call sites | Call-op inventory | 6, all documented |
| Embedded compiler version | CBOR metadata decode | 0.8.25 |
Scope note. Bytecode analysis examines code, not chain state. It confirms setAMM exists and is owner-gated, but cannot reveal which addresses were passed to it — that is storage, readable only via a live contract call. See the methodology note for the one open item this leaves.
Industry-standard static analysis and symbolic execution, run against the source and the deployed bytecode
Two of the three tools normally cited as the gap between a manual review and a formal audit — Slither and Mythril — were run for this report. Every finding either tool produced is reproduced below in full, including the ones labelled High, together with the specific reason each is not exploitable. Nothing is omitted: a tool finding shown and resolved is more useful to a reader than a clean summary with no working.
assembly block in the constructor, and the known no-op branch in _setAMM — all already described elsewhere in this report.SUB at PC 8009 is immediately followed by PUSH4 0x4e487b71 at PC 8014 — Solidity's Panic(uint256) selector. That is the compiler's own checked-arithmetic guard: if the subtraction would underflow, execution jumps into the panic handler and reverts. Mythril flagged the raw opcode without modelling the guard three instructions later. The path lies in solc's standard string handling reached via symbol(), not in EVRGROW's logic. No genuine finding.Disposition of every High and Medium finding
| Finding | Severity | Status | Why it is not exploitable |
|---|---|---|---|
arbitrary-send-eth |
High | Not exploitable | Slither flags addLiquidityETH{value: coinAmount} as sending ETH to an arbitrary recipient. The recipient is the hardcoded literal address(0xdead), written directly in the call and unchangeable — the detector fires on the pattern without evaluating that the destination is a compile-time constant burn address. There is no path by which any party can redirect this ETH. |
reentrancy-eth |
High | Mitigated by mutex | Flags balance writes in super._update() occurring after the external router calls inside _swapAndLiquify(). The _swapping boolean mutex guards exactly this: it is set true before the external calls and false after, and the swap block is gated on !_swapping. Slither's detector does not model boolean mutexes and so cannot see the guard. Re-entry would additionally have to originate from the Uniswap V2 router itself, which is the canonical immutable deployment. |
divide-before-multiply |
Medium | Known, bounded to 1 wei | Correctly identifies that fees * liquidityFees[txType] / totalFees[txType] operates on an already-divided fees value, losing precision. This is real but immaterial: the loss is bounded to 1 wei per transaction, accumulates in _liquidityPending rather than leaking from the system, and is included in the next LP injection. It is documented independently in the supplementary checks; the tool's finding corroborates that analysis rather than adding to it. |
On severity labels. Slither assigns severity by pattern, before context. A High label means the pattern is one that is often serious, not that this instance is. Each of the two High findings above resolves to a specific structural reason it cannot be exploited — a hardcoded burn address, and a mutex the detector cannot model. Readers are encouraged to verify both by reading _addLiquidity and the _swapping guard in the published source.
Line-by-line review of all 14 source files for hidden vulnerabilities, hidden privileges, and malicious logic
_mint() call is in the constructor, minting exactly 500,000,000 tokens to the deployer. _mint() is internal in OpenZeppelin ERC20 — cannot be called externally. No public mint() function exists.assembly guard in the constructor requires the deployer to be a contract — a standard factory-deployment pattern. Ownership flows cleanly through Ownable2Step with a single owner, now the zero address.afterConstructor() uses the initializer modifier from Initializable.sol, setting _initialized = true on first call and permanently reverting any subsequent call. The router cannot be replaced post-initialization.onlyOwner — permanently frozen with renouncement. Currently excluded addresses are the deployer wallet and the contract itself, both required for correct operation.onlyOwner, permanently frozen. Additional guard: if (AMM == pairV2 || AMM == address(routerV2)) revert InvalidAMM(AMM) prevents removal of the primary pair or router._swapAndLiquify() with LP destination hardcoded to address(0xdead). Cannot drain funds — only adds more permanent liquidity.routerV2 — any other sender triggers revert CannotDepositNativeCoins. ETH received is immediately consumed in _swapAndLiquify(). No ETH withdrawal function exists._beforeTokenUpdate and _afterTokenUpdate are completely empty stubs. No hidden logic, no callbacks, no exploitable behavior._updateRouterV2(), the contract approves the Uniswap router for type(uint256).max of its own accumulated fee balance — standard for LP injection. Holders' tokens are never approved to any third party.address(this) (the contract itself), not to any external wallet. Immediately consumed in _addLiquidity()._swapping boolean mutex prevents reentrant calls during LP injection. The guard if (!_swapping && from != pairV2 && from != address(routerV2) && canSwap) ensures the swap logic cannot be triggered recursively.uint16 values with an explicit 2500 bps revert cap. Arithmetic expands to uint256 before operations. unchecked blocks in ERC20 base are guarded by explicit balance checks immediately prior.Storage layout, event completeness, deployment verification, UNCX lock, arithmetic edge cases, pool address validation, and measured burn trajectory
_owner), Ownable2Step slot 1 (_pendingOwner), ERC20 slots 2–6 (_balances, _allowances, _totalSupply, _name, _symbol), Initializable slots 7–8 (_initialized, _initializing), and EVRGROW slots 9–18 (autoBurnFees through AMMs). Every contract declares storage in a distinct, non-overlapping range. No contract reads or writes a slot declared by another. C3 linearization order is correct and consistent with compiler resolution.autoBurnFeesSetup emits AutoBurnFeesUpdated; every auto-burn emits both AutoBurned and the standard ERC20 Transfer to address(0); LP injections emit LiquidityAdded; threshold changes emit SwapThresholdUpdated; fee exclusions emit ExcludeFromFees; router and AMM updates emit RouterV2Updated and AMMUpdated; Ownable2Step emits both OwnershipTransferStarted and OwnershipTransferred. One intentional omission: _liquidityPending accumulation is silent per-trade (gas optimization) but publicly readable via getAllPending(). Not a vulnerability.afterConstructor() was then called to create the Uniswap V2 pair, approve the router, and register initial AMMs — permanently locked by the initializer modifier. Additional AMMs were registered via setAMM(). Initial LP was seeded and locked on UNCX. Finally, ownership was renounced on Nov 18, 2025. The contract was fully configured and LP locked before renouncement — no window existed where it was live but unconfigured.0x2aa028...338e is locked, representing ~74.8M EVRGROW and 2.409 WETH. The lock was established Nov 18, 2025 and incrementally increased on Nov 25 and Dec 29, 2025. Note: the UNCX lock expiry is Nov 18, 2026 (one year). After that date the lock owner could withdraw the initial LP. However, all LP added by the auto-injection mechanism goes to address(0xdead) and is permanently irrecoverable regardless of the UNCX lock status. The 15.866% not in UNCX consists of LP tokens already burned on-chain via early auto-injections.amount * 200 at max realistic supply (~467M × 10¹⁸) ≈ 9.34 × 10²⁸, well within uint256 range of ~1.16 × 10⁷⁷. No overflow risk. Near-zero pool balance: getSwapThresholdAmount() returns 0, causing _swapAndLiquify to trigger with near-zero pending — a gas-wasting no-op but no security impact. Fee split rounding: with equal 100/200 split, autoBurnPortion is exactly 50% with no rounding loss at normal amounts.AMMs mapping — it is the sole pool whose trades trigger the 1% burn + 1% LP tax. The 16 auxiliary pools confirmed as legitimate live pairs — USDC on Uniswap V4 and HydrexFi; BTC (cbBTC) on Uniswap V3; ETH on Aerodrome and SushiSwap V2; OHM on Uniswap V2; Zora creator coin on PancakeSwap V2; AERO, PEAS, TOSHI, VEIL, MORPHO, and BNKR on Aerodrome; USDC via Balancer/CoW Swap; cbETH/DAI on Curve Finance; HYDX on HydrexFi — are all genuine, tradeable EVRGROW markets, but trades that stay within these pools (including multi-hop routes between them) do not trigger the tax. No pool address points to an unverified or suspicious contract; the distinction here is about tax scope, not pool legitimacy.totalSupply directly, the current supply reported by the contract is the original mint less every token ever burned. As of August 11, 2026, totalSupply() reads 462,423,454.63 EVRGROW (per BaseScan), giving a cumulative burn of 37,576,545.37 EVRGROW — 7.52% of the original supply over 266 days since deployment. That averages roughly 141,000 EVRGROW destroyed per day, or about 10.3% of original supply per year at the observed rate. This figure is a live measurement and will differ on any later reading; it is included as evidence the mechanism operates as coded in production, not as a forecast. Note that the observed burn rate is a function of trading volume through the main ETH V2 pool specifically (see Check 6) and should not be extrapolated as a fixed schedule.| Pool | Address | DEX | Depth | Verified | Tax Trigger |
|---|---|---|---|---|---|
| ETH Uniswap V2 (main) | 0x2aa028...338e | Uniswap V2 | Primary | ✓ UNCX locked | ✓ Yes |
| USDC Uniswap V4 1% | 0xaa3c7f...c2ca7 | Uniswap V4 | Secondary | ✓ Confirmed | No |
| BTC Uniswap V3 0.03% | 0xc2a517...cd1d | Uniswap V3 | Secondary | ✓ Confirmed | No |
| ETH Aerodrome 0.3% | 0x4cfac8...5504 | Aerodrome | Secondary | ✓ Confirmed | No |
| ETH SushiSwap V2 0.3% | 0xd863b8...fd7 | SushiSwap V2 | Secondary | ✓ Confirmed | No |
| OHM Uniswap V2 0.3% | 0x1343a4...414 | Uniswap V2 | Secondary | ✓ Confirmed | No |
| Zora PancakeSwap V2 | 0x38210...d0c | PancakeSwap V2 | Secondary | ✓ Confirmed | No |
| AERO Aerodrome 0.3% | 0x86459...2c4 | Aerodrome | Secondary | ✓ Confirmed | No |
| USDC HydrexFi 0.3% | 0x443d6...3a0 | HydrexFi | Secondary | ✓ Confirmed | No |
| PEAS Aerodrome 0.3% | 0x1c2b8...a10 | Aerodrome | Secondary | ✓ Confirmed | No |
| USDC Balancer/CoW | 0x10ae2...5d9 | Balancer/CoW | Secondary | ✓ Confirmed | No |
| TOSHI Aerodrome 0.3% | 0xb9ffc...c0 | Aerodrome | Secondary | ✓ Confirmed | No |
| cbETH/DAI Curve | 0x8b1eb...744 | Curve Finance | Secondary | ✓ Confirmed | No |
| HYDX HydrexFi 0.3% | 0x7c556...b87 | HydrexFi | Secondary | ✓ Confirmed | No |
| VEIL Aerodrome 0.3% | 0xfd3ed9...79fa | Aerodrome | Thin | ✓ Confirmed | No |
| MORPHO Aerodrome 0.3% | 0xbffa75...8af35 | Aerodrome | Thin | ✓ Confirmed | No |
| BNKR Aerodrome 0.3% | 0x4d60f2...cf45f49 | Aerodrome | Thin | ✓ Confirmed | No |
Depth key. Primary — the UNCX-locked main ETH V2 pair, the deepest pool and the only one that triggers the tax. Secondary — established pools with meaningful liquidity. Thin — pools created within the last several weeks holding under roughly $1,000 in pooled value at the time of review; these are genuine and functional, but their shallow depth means a single modest trade can move price substantially, and quoted prices there may diverge sharply from the main pair. Depth is a live figure and changes continuously. This column reflects market conditions, not contract security.
8 attack scenarios modeled against the contract mechanics and tokenomics
A bot observes the pending _swapAndLiquify() in the mempool, front-runs with a large ETH buy, lets the LP injection execute, then back-runs with a sell.
A front-running buy means the swap gets more ETH — benefiting the LP. LP tokens go to address(0xdead); no party suffers from unfavorable pricing. The attacker bears a 2% round-trip fee on both legs.
An adversary inflates the pool balance by adding large external liquidity, raising the threshold denominator and delaying LP injection indefinitely.
Adding liquidity benefits holders. The delay is temporary — fees continue accumulating in _liquidityPending. The public addLiquidityFromLeftoverTokens() provides a permissionless bypass path.
Use a flash loan to temporarily drain the EVRGROW/ETH pool, lowering the threshold and triggering LP injection at an artificially cheap level.
Draining the pool requires selling EVRGROW — triggering the 2% fee and burning supply. The flash loan must be repaid within the same transaction. The LP injection adds locked liquidity to address(0xdead). No value extraction path exists.
A fee-excluded address dumps large quantities of EVRGROW without incurring burn or LP fees, gaining a structural advantage over regular holders.
With ownership renounced, no new addresses can ever be fee-excluded. The two currently excluded addresses are the deployer wallet and the contract itself — both legitimate operational necessities.
A large LP holder removes liquidity from one of the 16 auxiliary pools, crashing price in that pool and creating extreme arbitrage pressure on the main pool.
The main Uniswap V2 pool's initial LP is locked via UNCX; all subsequent injections go to address(0xdead). Note: only trades that touch the main ETH V2 pool trigger the burn/LP tax — arbitrage confined to auxiliary pools does not. Arbitrage that routes back through the main pool still feeds the flywheel on that leg, but volume purely between auxiliary pools does not.
_addLiquidity() uses 0 for both amountTokenMin and amountETHMin. Heavy manipulation between the swap and the add could cause value leakage.
addLiquidityETH with amountMin = 0 accepts whatever ratio the pool offers, ensuring autonomous operation always succeeds. Per-transaction LP amount is ~0.5% of pool depth, making meaningful manipulation negligible.
_swapTokensForCoin() succeeds and ETH arrives in the contract, but _addLiquidity() fails, leaving ETH permanently stranded with no recovery path.
addLiquidityETH with 0 minimums will not revert on ratio grounds. Any router-level revert rolls back the entire transaction including the swap. Even if ETH were stranded, it would be consumed on the next LP injection trigger.
An attacker controls a low-liquidity auxiliary pool and manipulates it to generate artificial buy/sell volume, attempting to game the burn accumulation and LP injection mechanism.
Correction from earlier analysis: since only the main ETH V2 pool is registered to trigger the tax, volume confined to an auxiliary pool does not incur the 2% EVRGROW tax at all — no burn, no LP accumulation. The attacker pays only the DEX's own base trading fee (e.g., Aerodrome's 0.3%), which is small but real. This scenario cannot be used to "game" the burn mechanism, because auxiliary-pool volume simply doesn't touch it. The practical risk is limited to localized price manipulation within that specific pool, not any interaction with EVRGROW's tokenomics.
| Scenario | Attacker Profit | Protocol Impact |
|---|---|---|
| Sandwich LP swap | Negative (pays 2% fees) | Positive — LP deepens |
| Threshold griefing | Negative (adds liquidity) | Neutral / positive |
| Flash loan threshold | Negative (pays fees) | Positive — burns supply |
| Fee exclusion abuse | Not possible (renounced) | None |
| Liquidity removal | Temporary disruption only | Feeds the flywheel |
| Zero-slippage failure | Not a real failure mode | None |
| ETH stranding | Not possible | None |
| Multi-pool manipulation | Pays DEX fee only (~0.3%) | Neutral — no tax impact |
All 36 known Solidity vulnerability classes from the Smart Contract Weakness Classification registry, checked systematically against all 14 source files
| SWC ID | Vulnerability Class | Result | Notes |
|---|---|---|---|
| SWC-100 | Function Default Visibility | PASS | All functions have explicit visibility modifiers. No unintended public exposure. |
| SWC-101 | Integer Overflow and Underflow | PASS | Solidity 0.8.25 has built-in overflow protection. unchecked blocks are explicitly guarded by prior balance checks. |
| SWC-102 | Outdated Compiler Version | PASS | Uses Solidity 0.8.25 — most recent stable release at deployment. No known vulnerabilities in this version. |
| SWC-103 | Floating Pragma | PASS | Token.sol pinned at 0.8.25. OZ and Uniswap files use ^0.8.20 — acceptable for non-deployed library/interface files. |
| SWC-104 | Unchecked Call Return Value | PASS | All router calls are high-level Solidity calls that automatically revert on failure. No low-level .call() with unchecked return. |
| SWC-105 | Unprotected Ether Withdrawal | PASS | No ETH withdrawal function exists anywhere. All ETH is consumed immediately in LP injection. |
| SWC-106 | Unprotected SELFDESTRUCT | PASS | No selfdestruct instruction in any of the 14 files. |
| SWC-107 | Reentrancy | PASS | The _swapping boolean mutex prevents reentrant calls. Checks-effects-interactions pattern followed correctly. |
| SWC-108 | State Variable Default Visibility | PASS | All state variables have explicit visibility declared throughout all 14 files. |
| SWC-109 | Uninitialized Storage Pointer | PASS | No uninitialized storage pointers. All local variables are value types or explicitly initialized. |
| SWC-110 | Assert Violation | PASS | No assert() statements. Errors handled via revert with custom error types — the correct modern Solidity pattern. |
| SWC-111 | Use of Deprecated Solidity Functions | PASS | No use of suicide, throw, sha3, callcode, or other deprecated functions anywhere. |
| SWC-112 | Delegatecall to Untrusted Callee | PASS | No delegatecall anywhere in any of the 14 files. |
| SWC-113 | DoS with Failed Call | PASS | LP injection failure does not brick the contract. _swapping resets to false and operation continues normally. |
| SWC-114 | Transaction Order Dependence | INFO | LP swap is theoretically front-runnable but LP goes to address(0xdead) — no party suffers a loss. Sandwich attackers pay the 2% round-trip fee. Known and accepted trade-off in this class of auto-LP token. |
| SWC-115 | Authorization Through tx.origin | PASS | No use of tx.origin for authorization. All access control uses msg.sender via _msgSender(). |
| SWC-116 | Block Values as Proxy for Time | PASS | block.timestamp used only as deadline for Uniswap calls — standard DEX practice, not a security mechanism. |
| SWC-117 | Signature Malleability | PASS | No ECDSA signature verification in this contract. Not applicable. |
| SWC-118 | Incorrect Constructor Name | PASS | Uses the correct constructor() keyword. Legacy named-constructor vulnerability not applicable to 0.8.x. |
| SWC-119 | Shadowing State Variables | PASS | No state variable shadowing across the full inheritance chain: ERC20, ERC20Burnable, Ownable, Ownable2Step, Initializable. |
| SWC-120 | Weak Sources of Randomness | PASS | No randomness used anywhere in the contract. Not applicable. |
| SWC-121 | Missing Protection Against Signature Replay | PASS | No signature-based mechanisms in this contract. Not applicable. |
| SWC-122 | Lack of Proper Signature Verification | PASS | No signature verification in this contract. Not applicable. |
| SWC-123 | Requirement Violation | PASS | All revert conditions are logically sound and only reachable under genuinely invalid conditions. |
| SWC-124 | Write to Arbitrary Storage Location | PASS | No arbitrary storage writes. All storage access through named mappings and state variables. No pointer arithmetic. |
| SWC-125 | Incorrect Inheritance Order | PASS | Inheritance order is correct and non-conflicting. C3 linearization produces no ambiguous function resolution. |
| SWC-126 | Insufficient Gas Griefing | PASS | No relayed transactions or meta-transaction patterns that could be griefed via gas manipulation. |
| SWC-127 | Arbitrary Jump with Function Type Variable | PASS | No function type variables used anywhere in the contract. |
| SWC-128 | DoS With Block Gas Limit | PASS | No unbounded loops over dynamic arrays. All fee calculation loops are over fixed-size arrays of length 3. |
| SWC-129 | Typographical Error | PASS | Fee math reviewed carefully — no off-by-one errors, no misplaced operators. totalFees accounting is correctly structured. |
| SWC-130 | RTL-Override Control Character | PASS | Source code contains no hidden Unicode control characters or right-to-left override characters. |
| SWC-131 | Presence of Unused Variables | INFO | _beforeTokenUpdate and _afterTokenUpdate hooks are empty stubs with unused parameters. No security impact — informational only. |
| SWC-132 | Unexpected Ether Balance | PASS | Contract does not rely on address(this).balance being a specific value for any security-critical logic. |
| SWC-133 | Hash Collisions With Multiple Variable Length Args | PASS | No use of abi.encodePacked with multiple variable-length arguments. Not applicable. |
| SWC-134 | Message Call with Hardcoded Gas Amount | PASS | No .transfer() or .send() (which forward fixed 2300 gas). All ETH movement through the Uniswap router via high-level calls. |
| SWC-135 | Code With No Effects | INFO | Empty if (isAMM) { } branch inside _setAMM() is a no-op code generation artifact. No security implication. |
| SWC-136 | Unencrypted Private Data On-Chain | PASS | No sensitive data stored in private variables with any confidentiality expectation. All private state is operational. |
Compiler settings, ERC-20 compliance, public burn exposure, and integer precision documentation
v0.8.25+commit.b61c2a91, optimizer enabled at 200 runs, EVM target: paris. The 200-run setting balances deployment cost against runtime efficiency — correct for a frequently-called contract. Known optimizer risks (YulOptimizer, StackLimitEvader) apply to contracts with deep call stacks and many local variables; EVRGROW's functions are shallow with no nested internal calls beyond super._update(). EVM target paris is well-established and stable; EVRGROW uses neither DIFFICULTY nor PREVRANDAO so the paris/shanghai distinction is irrelevant. No known Solidity 0.8.25 compiler bugs affect any pattern used in this contract.totalSupply(), balanceOf(), transfer(), transferFrom(), approve(), allowance(). Both required events (Transfer, Approval) are correctly emitted. The Approval suppression on transferFrom allowance spend is the EIP-20 permitted optimization. Fee-on-transfer behavior is correctly implemented — the contract uses swapExactTokensForETHSupportingFeeOnTransferTokens rather than the standard swap function, which is the required Uniswap variant for fee-on-transfer tokens. All public functions return correct types; OpenZeppelin always returns true on success and reverts on failure — fully EIP-20 compliant.ERC20Burnable adds two public functions. burn(value): any holder can permanently destroy their own tokens. burnFrom(account, value): a spender with granted allowance can burn from a holder's balance. Neither triggers the fee mechanism — self-burns and allowance burns are deliberate holder actions, not AMM trades, so no 1% auto-burn or LP fee fires. Neither function can be called by any party other than the token holder themselves or an explicitly approved spender. No privileged actor can burn from arbitrary wallets. Standard DeFi hygiene applies: holders should only grant allowances to contracts they trust.halfAmount = tokenAmount / 2: odd tokenAmount rounds halfAmount down; otherHalf receives the extra wei — no compounding effect. (2) autoBurnPortion = fees * 100 / 200: exactly 50% for even fees; at odd fees rounds to 0, causing the full wei to accumulate in _liquidityPending instead. (3) _liquidityPending += fees * 100 / 200: identical — rounds down by at most 1 wei for odd fees. In all cases the remainder accumulates in _liquidityPending and is included in the next LP injection. No value leaks from the system. Rounding errors are bounded, self-correcting, and negligible in aggregate.Methodology & Verification Basis
Findings in this report come from four sources, and it is worth knowing which is which. Bytecode-level analysis — Part 2 — was performed on the deployed 8,485-byte runtime bytecode disassembled locally. Its first check recompiles the published source with the contract's own recorded compiler settings and finds all 8,432 executable bytes identical to what is deployed, which is what allows the source-level findings elsewhere to stand on more than a block explorer's label. Automated tool analysis — Part 3 — covers Slither 0.11.6 across all 16 compiled contracts and Mythril 0.24.8 symbolic execution against the deployed bytecode; every finding either tool produced is reproduced in that section with its disposition. Source-level analysis — Parts 1, 4, 6, 7 and 8, plus Part 5 checks 1, 2, 3 and 5 — was read directly from the verified Solidity source and ABI. On-chain observation covers the rest: the burn trajectory in Part 5 check 7 is computed from totalSupply() against the constructor's documented 500,000,000 mint; each pool in check 6 was confirmed live on its respective DEX or block explorer; and the finding that trades outside the main ETH V2 pool go untaxed is evidenced by transaction 0xe9082639...d4fd1a3f, in which EVRGROW moved between two non-main pools and emitted no AutoBurned or LiquidityAdded event.
One item remains open. The claim that only the main pool is registered in the AMMs mapping is consistent with everything observed here, but was not confirmed by calling AMMs(address) against each auxiliary pool or by reading the full AMMUpdated event history. This is a limit of scope rather than of evidence: bytecode analysis reads code, and the registration list is contract state, which requires a live contract call. Any reader can settle it in seconds via the Read Contract tab on BaseScan by calling AMMs() with each pool address.
Audit Scope & Disclosure
This audit was performed by Claude (Anthropic) on August 11, 2026 against the EVRGROW contract deployed at 0x8ea57c4d7a6a88c90bcf038d37939fae61305a88 on Base. It comprises eight parts: verification of contract behavior against every published claim, including the scope of the transfer tax; bytecode verification and source equivalence, covering byte-for-byte reproduction of the deployed code, dangerous-opcode absence, selector enumeration and collision analysis, a dead-code proof of the privileged surface, call site inventory and compiler metadata; automated analysis via Slither and Mythril with every finding disclosed and dispositioned; a full backdoor review across all 14 source files; advanced checks covering storage layout, deployment sequence, UNCX lock verification, arithmetic edge cases, validation of all 17 liquidity pool addresses and a measured burn trajectory since launch; adversarial economic modeling of 8 attack scenarios; systematic coverage of all 36 SWC vulnerability classes; and supplementary checks covering compiler settings, ERC-20 compliance, public burn exposure and integer precision behavior.
This does not constitute a formal professional security audit. What remains outside its scope is Echidna property-based fuzzing against a forked network, formal mathematical verification, and independent multi-auditor peer review. Two things narrow the gap. First, two of the three tools normally cited as that gap — Slither and Mythril — were actually run here, and the deployed bytecode was independently reproduced from source, which is a stronger guarantee of source authenticity than most reviews establish. Second, the contract's own design limits what is left to find: EVRGROW has no staking logic, no governance, no oracles, no upgradeable proxy pattern, and no complex multi-contract interactions of its own design, which are precisely the areas where formal audits most commonly uncover critical bugs. Ownership is renounced and the entire privileged function surface is demonstrably unreachable, so the contract's behavior is fixed. The attack surface is genuinely narrow, and the analysis performed here covers the substantial majority of meaningful risk for a contract of this architecture. It is not a guarantee, and it is not financial advice; readers should form their own judgement and verify the open item above independently.