Introduction
We express our gratitude to the Zendex team for the collaborative engagement that enabled the execution of this Smart Contract Security Assessment.
Zendex is a privacy-preserving ZK-AMM, combining zero-knowledge asset management, private swaps, liquidity provisioning, and staking-based fee incentives into a unified DEX protocol.
Document | |
|---|---|
| Name | Smart Contract Code Review and Security Analysis Report for Zendex |
| Audited By | Olesia Bilenka, Georgi Krastenov |
| Approved By | Ivan Bondar |
| Website | https://www.zendex.fi/→ |
| Changelog | 01/05/2026 - Preliminary Report |
| 30/06/2026 - Retest Report | |
| 16/07/2026 - Second retest Report | |
| Platform | Base |
| Language | Solidity |
| Tags | Automated Market Maker; Order Book DEX; Staking; Fungible Token; Permit Token; Signatures; DEX; Vault; Liquidity Pool; Centralization |
| Methodology | https://docs.hacken.io/methodologies/smart-contracts→ |
Document
- Name
- Smart Contract Code Review and Security Analysis Report for Zendex
- Audited By
- Olesia Bilenka, Georgi Krastenov
- Approved By
- Ivan Bondar
- Website
- https://www.zendex.fi/→
- Changelog
- 01/05/2026 - Preliminary Report
- 30/06/2026 - Retest Report
- 16/07/2026 - Second retest Report
- Platform
- Base
- Language
- Solidity
- Tags
- Automated Market Maker; Order Book DEX; Staking; Fungible Token; Permit Token; Signatures; DEX; Vault; Liquidity Pool; Centralization
Review Scope | |
|---|---|
| Repository | https://github.com/lumos-codes-dev/zendex-sc-zk-amm/tree/v0.9.1/contracts→ |
| Commit | 683e89b |
| Retest commit | fb655e9 |
| Second retest commit | 0c53c21 |
Review Scope
- Commit
- 683e89b
- Retest commit
- fb655e9
- Second retest commit
- 0c53c21
Audit Summary
The system users should acknowledge all the risks summed up in the risks section of the report
Documentation quality
Functional requirements are partially documented.
The repository includes a README, deployment-related materials, and setup instructions, but the technical specification is incomplete. Detailed descriptions of the ZK circuits, trust model, role permissions, verifier assumptions, asset flow, upgrade process, and failure scenarios are missing or insufficient.
The documentation does not fully describe privacy guarantees, limitations, or expected off-chain backend responsibilities.
Code quality
The development environment is configured with Hardhat, TypeScript tests, Solidity coverage tooling, and deployment scripts.
The codebase is modular and separates AMM, vault, staking, rewards, verifier, and tree-management logic.
However, several components duplicate known implementations, including Uniswap V2-style AMM logic and custom ERC20 behavior, instead of relying directly on battle-tested libraries. T
Test coverage
Code coverage of the project is 43.27% (branch coverage).
The project includes tests for core flows such as staking, boost calculation, Merkle tree operations, vault deposits/withdrawals/split/join, AMM liquidity and swaps, and limit order creation.
Basic positive and some negative cases are covered. However, tests do not thoroughly cover complex multi-user interactions, adversarial execution ordering, backend failure modes, role abuse scenarios, and full integration flows across all protocol components.
System Overview
Zendex is a privacy-preserving ZK-AMM and DEX protocol with the following contracts:
BaseManager.sol — Abstract upgradeable contract providing shared functionality for all manager contracts, including proof verification via ZendexVerifierHub, nullifier validation, Merkle root validation, and commitment insertion through TreeOperator.
BoostManager.sol — Upgradeable contract that calculates fee boost percentages for users based on their staking positions; the boost formula uses linear interpolation between lock amount and duration to yield 5-25% boost in basis points.
RewardsEngine.sol — Upgradeable contract managing fee collection from the router, tracking per-user cashback and burn balances across multiple tokens, applying staking boosts at claim time, and auto-converting accumulated fees to native ZEN via swap through the router.
TreeOperator.sol — Non-upgradeable incremental Merkle tree implementation using Poseidon hashing (PoseidonT3 library) for commitment storage; manages historical roots by epoch, nullifier tracking, liquidity position tracking, and order book metadata for limit orders.
WZEN.sol — Standard ERC-20 wrapped native coin contract enabling deposit of native ZEN and minting of WZEN tokens, with withdrawal functionality to unwrap and receive native ZEN.
ZendexAmmManager.sol — Upgradeable manager contract for private AMM operations (
addLiquidity,removeLiquidity,swap) that verifies inclusion and action proofs, consumes nullifiers, inserts new commitments (liquidity or swap), and executes trades through ZendexRouter.ZendexERC20.sol — Custom ERC-20 implementation serving as the base for LP tokens, featuring EIP-2612 permit functionality with domain separator and typed data hashing for gasless approvals.
ZendexFactory.sol — Upgradeable factory contract for creating and registering ZendexPair liquidity pool contracts using CREATE2 deployment with deterministic addresses derived from sorted token pairs.
ZendexOrderBookManager.sol — Upgradeable manager contract for privacy-preserving limit orders; handles order creation with ZK proof verification (
createOrder), operator-triggered batch execution (executeOrders), cancellation requests (requestCancelOrder), and final cancellation settlement (cancelLimitOrder).ZendexPair.sol — Non-upgradeable Uniswap V2-style constant product AMM pair contract implementing
mint,burn, andswapfunctions with 0.18% LP fee; inherits from ZendexERC20 to serve as its own LP token with permit support.ZendexRouter.sol — Upgradeable router contract providing high-level functions for liquidity addition/removal and token swaps (exact input and exact output variants), handling fee extraction and distribution to RewardsEngine, and supporting both standard and fee-on-transfer tokens.
ZendexStaking.sol — Upgradeable staking contract where users lock tokens for 1-24 periods (minimum 1,000 tokens) to earn fee boosts; enforces that existing stakes can only have their duration extended, not decreased.
ZendexVault.sol — Non-upgradeable custody contract holding all deposited user assets (WZEN, USDT, USDC, DAI); exposes
releaseandapprovefunctions restricted to authorized manager roles for asset transfers during withdrawals and AMM operations.ZendexVaultManager.sol — Upgradeable manager contract for core vault operations (
deposit,withdraw,split,join) that verifies ZK proofs, manages commitment insertions, consumes nullifiers, and coordinates asset transfers with ZendexVault.ZendexVerifierHub.sol — Upgradeable central registry mapping verifier types (deposit, inclusion, withdrawal, split, join, add/remove liquidity, swap, create/cancel order) to their deployed Barretenberg verifier contract addresses; enables verifier upgrades without modifying manager contracts.
Math — provides basic math utilities used by AMM contracts, including minimum selection and square-root calculation for liquidity and fee logic.
UQ112x112 — provides fixed-point arithmetic helpers used by pair contracts for cumulative price calculations and reserve-based price encoding.
Privileged roles
The protocol uses several privileged roles across upgradeable and administrative contracts. Accounts holding DEFAULT_ADMIN_ROLE can upgrade UUPS contracts, manage verifier addresses, and assign or revoke roles depending on the contract. These permissions allow privileged actors to modify critical protocol logic and dependencies, including proof verification, routing, rewards, staking, and manager behavior.
BoostManagersol
DEFAULT_ADMIN_ROLE: Full administrative control over the contract.
Can call
_authorizeUpgradeto upgrade the contract implementation.Admin role for DEFAULT_ADMIN_ROLE; can grant and revoke it.
RewardsEngine.sol
DEFAULT_ADMIN_ROLE: Full administrative control over the contract.
Can call
_authorizeUpgradeto upgrade the contract implementation.Can call
withdrawTreasuryto withdraw accumulated treasury fees (swapped to native coins) to any recipient.Admin role for DEFAULT_ADMIN_ROLE and ROUTER_ROLE; can grant and revoke them.
ROUTER_ROLE: Authorized to deposit trading fees.
Can call
depositFeesto deposit treasury, cashback, and burn fees for users.
TreeOperator.sol
DEFAULT_ADMIN_ROLE: Full administrative control over the contract.
Admin role for DEFAULT_ADMIN_ROLE, VAULT_MANAGER_ROLE, AMM_MANAGER_ROLE, and ORDER_BOOK_MANAGER_ROLE; can grant and revoke them.
VAULT_MANAGER_ROLE: Authorized to manage Merkle tree state for vault operations.
Can call
insertto add commitments to the Merkle tree.Can call
consumeto mark nullifiers as used.
AMM_MANAGER_ROLE: Authorized to manage Merkle tree state and liquidity tracking.
Can call
insertto add commitments to the Merkle tree.Can call
consumeto mark nullifiers as used.Can call
trackPositionto record liquidity positions with LP amounts.Can call
removePositionto delete tracked liquidity positions.
ORDER_BOOK_MANAGER_ROLE: Authorized to manage Merkle tree state and order lifecycle.
Can call
insertto add commitments to the Merkle tree.Can call
consumeto mark nullifiers as used.Can call
openOrderto register new limit orders with execute and cancel commitments.Can call
updateOrderStatusto change order status (OPEN, CANCEL_REQUESTED, EXECUTED, CANCELED).Can call
setCancellationDeadlineto set cancellation deadlines for orders.
WZEN.sol
No privileged roles. All functions are permissionless.
ZendexAmmManager.sol
DEFAULT_ADMIN_ROLE (inherited from BaseManager): Full administrative control over the contract.
Can call
_authorizeUpgradeto upgrade the contract implementation.Admin role for DEFAULT_ADMIN_ROLE; can grant and revoke it.
ZendexERC20.sol
No privileged roles. Standard ERC-20 with permit functionality.
ZendexFactory.sol
DEFAULT_ADMIN_ROLE: Full administrative control over the contract.
Can call
_authorizeUpgradeto upgrade the contract implementation.Admin role for DEFAULT_ADMIN_ROLE; can grant and revoke it.
feeToSetter (address-based access control): Controls fee recipient configuration.
Can call
setFeeToto set the address that receives protocol fees from pairs.Can call
setFeeToSetterto transfer fee setter privileges to another address.
ZendexOrderBookManager.sol
DEFAULT_ADMIN_ROLE (inherited from BaseManager): Full administrative control over the contract.
Can call
_authorizeUpgradeto upgrade the contract implementation.Admin role for DEFAULT_ADMIN_ROLE and ORDER_BOOK_OPERATOR_ROLE; can grant and revoke them.
ORDER_BOOK_OPERATOR_ROLE: Authorized to execute and finalize order operations.
Can call
executeOrdersto execute multiple matched limit orders by inserting their execute commitments.Can call
cancelLimitOrderto finalize order cancellations by inserting cancel commitments.
ZendexPair.sol
factory (address-based access control, single-use): Initializes pair tokens.
Can call
initializeto set token0 and token1 addresses (callable only once at deployment).
ZendexRouter.sol
DEFAULT_ADMIN_ROLE: Full administrative control over the contract.
Can call
_authorizeUpgradeto upgrade the contract implementation.Admin role for DEFAULT_ADMIN_ROLE; can grant and revoke it.
ZendexStaking.sol
DEFAULT_ADMIN_ROLE: Full administrative control over the contract.
Can call
_authorizeUpgradeto upgrade the contract implementation.Admin role for DEFAULT_ADMIN_ROLE; can grant and revoke it.
ZendexVault.sol
DEFAULT_ADMIN_ROLE: Full administrative control over the contract.
Admin role for DEFAULT_ADMIN_ROLE and MANAGER_ROLE; can grant and revoke them.
MANAGER_ROLE: Authorized to manage vault assets.
Can call
releaseto transfer any token held by the vault to any recipient.Can call
approveto grant token spending allowances on behalf of the vault.
ZendexVaultManager.sol
DEFAULT_ADMIN_ROLE (inherited from BaseManager): Full administrative control over the contract.
Can call
_authorizeUpgradeto upgrade the contract implementation.Admin role for DEFAULT_ADMIN_ROLE; can grant and revoke it.
ZendexVerifierHub.sol
DEFAULT_ADMIN_ROLE: Full administrative control over the contract.
Can call
_authorizeUpgradeto upgrade the contract implementation.Can call
updateto change verifier addresses for any verifier type (DEPOSIT, INCLUSION, WITHDRAWAL, SPLIT, JOIN, ADDLIQUIDITY, REMOVELIQUIDITY, SWAP, CREATEORDER, REQUESTCANCEL_ORDER).Admin role for DEFAULT_ADMIN_ROLE; can grant and revoke it.
Potential Risks
Administrative Control Over Protocol Upgrades: The DEFAULT_ADMIN_ROLE holds unilateral authority to upgrade implementations of all UUPS-upgradeable contracts including ZendexAmmManager, ZendexOrderBookManager, ZendexVaultManager, ZendexFactory, ZendexRouter, ZendexStaking, ZendexVerifierHub, RewardsEngine, and BoostManager through their respective _authorizeUpgrade functions. A compromised or malicious admin can replace contract logic without user consent, potentially altering core protocol mechanics or extracting user funds.
Order Book Operator Exclusivity: The ZendexOrderBookManager contract designates an ORDER_BOOK_OPERATOR_ROLE with exclusive authority to call executeOrders and cancelLimitOrder. This centralized operator can selectively execute or delay order execution. While the cancellation deadline mechanism in TreeOperator tracks deadlines via cancellationDeadlines, the contract explicitly states this is view-only and not enforced on-chain. Users relying on limit orders are dependent on this single operator's availability and honesty.
Vault Asset Release Authority: The ZendexVault contract grants MANAGER_ROLE to three addresses (vaultManager, ammManager, tradeManager) at deployment, each able to invoke release to transfer arbitrary token amounts from the vault. If any manager contract or its admin is compromised, assets held in custody can be drained without requiring ZK proof validation at the vault level.
Fee Recipient Configuration: In ZendexFactory, the feeToSetter address can unilaterally change the feeTo address via setFeeTo without timelock or multi-signature requirements. Protocol fees accumulated from liquidity provision events can be redirected to any address at the fee setter's discretion.
Verifier Contract Substitution: The ZendexVerifierHub allows the DEFAULT_ADMIN_ROLE to update any verifier address through the update function. A malicious admin can replace legitimate ZK verifiers with contracts that accept invalid proofs, enabling unauthorized deposits, withdrawals, or trades without valid cryptographic attestation.
Immediate Upgrade Capability Without Timelock: All UUPS-upgradeable contracts including ZendexAmmManager, ZendexOrderBookManager, ZendexVaultManager, ZendexRouter, ZendexFactory, ZendexStaking, ZendexVerifierHub, RewardsEngine, and BoostManager can be upgraded immediately by the admin without a timelock delay. Users have no window to exit the protocol or withdraw funds before potentially harmful upgrades take effect.
Custom Storage Slot Management: The protocol employs custom storage slots (e.g., _BASE_MANAGER_STORAGE_SLOT, _AMM_MANAGER_STORAGE_SLOT, _VAULT_MANAGER_STORAGE_SLOT) computed via keccak256. Incorrect slot management during upgrades can cause storage collisions, leading to corrupted state variables or unintended behavior in upgraded implementations.
Poseidon Hash Function Library: The TreeOperator contract relies on the external PoseidonT3 library from poseidon-solidity for Merkle tree hash computation via _hashPair. Any vulnerability or unexpected behavior in this third-party cryptographic library would compromise the integrity of the commitment scheme and proof verification across all ZK operations.
Non-Standard Token Behavior: The protocol interacts with external ERC-20 tokens including USDT, USDC, and DAI configured in ZendexVault. While SafeERC20 and forceApprove are employed, tokens with fee-on-transfer mechanics, rebasing logic, or blocklist functionality may cause accounting discrepancies in vault balances or swap calculations in ZendexAmmManager and ZendexRouter.
Zero-Knowledge Proof Generation Infrastructure: All deposit, withdrawal, swap, liquidity, and limit order operations in ZendexVaultManager, ZendexAmmManager, and ZendexOrderBookManager require externally generated ZK proofs validated through ZendexVerifierHub. Users cannot interact with the protocol if the off-chain proof generation service is unavailable, censoring, or producing invalid proofs.
Order Book Operator Availability: The ZendexOrderBookManager requires the ORDER_BOOK_OPERATOR_ROLE to invoke executeOrders for order matching and cancelLimitOrder for cancellation finalization. If this off-chain operator becomes unavailable, all pending limit orders remain unexecutable, and users cannot complete order cancellations beyond requesting them via requestCancelOrder.
Merkle Tree State Synchronization: The TreeOperator maintains on-chain Merkle tree state in _levelHashes and historical snapshots in _epochLevelHashes, which must remain synchronized with off-chain commitment data. Users generating inclusion proofs off-chain must accurately reconstruct tree state from LeafInserted events, and any desynchronization prevents valid proof generation.
Public Commitment and Nullifier Registry: All commitments and nullifiers are stored in publicly readable mappings (commitments and nullifierUsed) within TreeOperator. While commitment values do not directly reveal deposit amounts or assets, on-chain observers can analyze commitment creation timing, nullifier consumption patterns, and transaction graph relationships to partially deanonymize user activity.
Visible Liquidity Position Amounts: The TreeOperator stores LP token amounts in the liquidityPositions mapping keyed by liquidity commitment. Observers can link liquidity commitments to specific LP amounts, enabling analysis of liquidity provider behavior and potentially correlating add/remove operations to specific users.
Order Metadata Exposure: The _orderBook mapping in TreeOperator publicly stores OrderMetadata including executeCommitment, cancelCommitment, and status for each spot commitment. Combined with OrderCreated and OrdersExecuted events that emit order parameters, observers can reconstruct order book activity and link orders to execution outcomes.
Findings
Code ― | Title | Status | Severity | |
|---|---|---|---|---|
| F-2026-1648 | Deterministic Commitment Construction Enables Full De-Anonymization of All Private Operations | fixed | Critical | |
| F-2026-1620 | Front-Running in swap and removeLiquidity Functions Leads to Theft of Released Assets | fixed | Critical | |
| F-2026-1619 | Front-Running in withdraw Function Leads to Theft of Withdrawn Funds | fixed | Critical | |
| F-2026-1657 | Incomplete Limit Order Implementation Results in Permanent Fund Lock Due to Missing On-Chain Execution and Cancellation Mechanisms | mitigated | Critical | |
| F-2026-1648 | Broken Fee-On-Transfer Swap Support in swapExactTokensForTokensSupportingFeeOnTransferTokens Causes Transaction Reverts | fixed | High | |
| F-2026-1621 | Missing Nullifier Validation in removeLiquidity Leads to Incomplete Replay Protection | fixed | High | |
| F-2026-1619 | Missing Slippage Protection in addLiquidity, removeLiquidity, and swap Leads to Value Extraction Through Price Manipulation | fixed | High | |
| F-2026-1660 | Unbounded Gas Growth in insert | accepted | High | |
| F-2026-1657 | Front-Running Vulnerability in createLimitOrder Enables Order Hijacking | mitigated | High | |
| F-2026-1655 | Broken Optimal-Swap Calculation | fixed | High |
Appendix 1. Definitions
Severities
When auditing smart contracts, Hacken is using a risk-based approach that considers Likelihood, Impact, Exploitability and Complexity metrics to evaluate findings and score severities.
Reference on how risk scoring is done is available through the repository in our Github organization:
Severity | Description |
|---|---|
Critical | Critical vulnerabilities are usually straightforward to exploit and can lead to the loss of user funds or contract state manipulation. |
High | High vulnerabilities are usually harder to exploit, requiring specific conditions, or have a more limited scope, but can still lead to the loss of user funds or contract state manipulation. |
Medium | Medium vulnerabilities are usually limited to state manipulations and, in most cases, cannot lead to asset loss. Contradictions and requirements violations. Major deviations from best practices are also in this category. |
Low | Major deviations from best practices or major Gas inefficiency. These issues will not have a significant impact on code execution. |
Severity
- Critical
Description
- Critical vulnerabilities are usually straightforward to exploit and can lead to the loss of user funds or contract state manipulation.
Severity
- High
Description
- High vulnerabilities are usually harder to exploit, requiring specific conditions, or have a more limited scope, but can still lead to the loss of user funds or contract state manipulation.
Severity
- Medium
Description
- Medium vulnerabilities are usually limited to state manipulations and, in most cases, cannot lead to asset loss. Contradictions and requirements violations. Major deviations from best practices are also in this category.
Severity
- Low
Description
- Major deviations from best practices or major Gas inefficiency. These issues will not have a significant impact on code execution.
Potential Risks
The "Potential Risks" section identifies issues that are not direct security vulnerabilities but could still affect the project’s performance, reliability, or user trust. These risks arise from design choices, architectural decisions, or operational practices that, while not immediately exploitable, may lead to problems under certain conditions. Additionally, potential risks can impact the quality of the audit itself, as they may involve external factors or components beyond the scope of the audit, leading to incomplete assessments or oversight of key areas. This section aims to provide a broader perspective on factors that could affect the project's long-term security, functionality, and the comprehensiveness of the audit findings.
Appendix 2. Scope
The scope of the project includes the following smart contracts from the provided repository:
Scope Details | |
|---|---|
| Repository | https://github.com/lumos-codes-dev/zendex-sc-zk-amm/tree/v0.9.1/contracts→ |
| Commit | 683e89b38bf6308072d9c6e5087509f01155f98a |
| Retest commit | fb655e97a47f1c1f2bb77b76091c492532fc4934 |
| Second retest commit | 0c53c2175a4941c43f74a8be788b53b92dedc2a5 |
| Whitepaper | - |
| Requirements | https://github.com/lumos-codes-dev/zendex-sc-zk-amm/tree/v0.9.1/contracts/docs→ |
| Technical Requirements | - |
Scope Details
- Commit
- 683e89b38bf6308072d9c6e5087509f01155f98a
- Retest commit
- fb655e97a47f1c1f2bb77b76091c492532fc4934
- Second retest commit
- 0c53c2175a4941c43f74a8be788b53b92dedc2a5
- Whitepaper
- -
- Technical Requirements
- -
Assets in Scope
Appendix 3. Additional Valuables
Additional Recommendations
The smart contracts in the scope of this audit could benefit from the introduction of automatic emergency actions for critical activities, such as unauthorized operations like ownership changes or proxy upgrades, as well as unexpected fund manipulations, including large withdrawals or minting events. Adding such mechanisms would enable the protocol to react automatically to unusual activity, ensuring that the contract remains secure and functions as intended.
To improve functionality, these emergency actions could be designed to trigger under specific conditions, such as:
Detecting changes to ownership or critical permissions.
Monitoring large or unexpected transactions and minting events.
Pausing operations when irregularities are identified.
These enhancements would provide an added layer of security, making the contract more robust and better equipped to handle unexpected situations while maintaining smooth operations.
Frameworks and Methodologies
This security assessment was conducted in alignment with recognised penetration testing standards, methodologies and guidelines, including the NIST SP 800-115 – Technical Guide to Information Security Testing and Assessment →, and the Penetration Testing Execution Standard (PTES) →, These assets provide a structured foundation for planning, executing, and documenting technical evaluations such as vulnerability assessments, exploitation activities, and security code reviews. Hacken’s internal penetration testing methodology extends these principles to Web2 and Web3 environments to ensure consistency, repeatability, and verifiable outcomes.