Introduction
We express our gratitude to the vAPI Network team for the collaborative engagement that enabled the execution of this Smart Contract Security Assessment.
A fixed-supply ERC-20 and a Uniswap V4 swap-fee hook are deployed on Base. Swaps on allowlisted token-pair pools are taxed up to 3%, with fees collected in the project token and forwarded to a treasury.
Document | |
|---|---|
| Name | Smart Contract Code Review and Security Analysis Report for vAPI Network |
| Audited By | Ivan Bondar |
| Approved By | Kornel Światłowski |
| Website | https://vapinetwork.ai→ |
| Changelog | 05/08/2026 - Preliminary Report |
| 20/08/2026 - Final Report | |
| Platform | Base |
| Language | Solidity |
| Tags | Fungible Token; Permit Token; Signatures; Automated Market Maker (AMM); ERC20 |
| Methodology | https://docs.hacken.io/methodologies/smart-contracts→ |
Document
- Name
- Smart Contract Code Review and Security Analysis Report for vAPI Network
- Audited By
- Ivan Bondar
- Approved By
- Kornel Światłowski
- Website
- https://vapinetwork.ai→
- Changelog
- 05/08/2026 - Preliminary Report
- 20/08/2026 - Final Report
- Platform
- Base
- Language
- Solidity
- Tags
- Fungible Token; Permit Token; Signatures; Automated Market Maker (AMM); ERC20
Review Scope | |
|---|---|
| Repository | https://github.com/vAPI-Network/token→ |
| Initial Commit | 281ba94 |
| Remediation Commit (fee in project token) | 372514c (audit/hacken-remediation) |
| Remediation Commit (fee in pair currency, ETH) | f3f051d (explore/eth-fee-redesign) |
Review Scope
- Repository
- https://github.com/vAPI-Network/token→
- Initial Commit
- 281ba94
- Remediation Commit (fee in project token)
- 372514c (
audit/hacken-remediation) - Remediation Commit (fee in pair currency, ETH)
- f3f051d (
explore/eth-fee-redesign)
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 covered in the repository README and contract-level NatSpec.
No dedicated external specification describes system architecture, operational procedures, or Uniswap V4 integration assumptions.
Technical description of FeeHook fee-direction handling, registry gating, and launch-guard behavior is provided via extensive NatSpec.
NatSpec comments are present and generally complete for public, owner-only, and complex internal hook functions.
Code quality
Standard OpenZeppelin patterns (
ERC20,ERC20Burnable,ERC20Permit,Ownable2Step) are utilized.Uniswap V4
BaseHookinheritance andPoolManagercallback patterns are utilized for fee collection.Contracts are non-upgradeable; proxy and storage-gap patterns are not used.
The development environment is configured (Foundry, pinned dependencies, deployment scripts, and CI).
Test coverage
Code coverage of the project is 95.24% (branch coverage).
Deployment and basic user interactions are covered with tests.
Negative cases and edge conditions are covered across unit, fuzz, invariant, and Base fork suites.
Multi-user scenarios (token transfers, ownership handoff, launch-guard stress) are covered, though some complex concurrent cross-role sequences remain limited to the fork suite.
System Overview
The system comprises two non-upgradeable contracts with no proxy pattern. Token is a standalone ERC-20 with a single mint at construction to a designated recipient and no privileged surface afterward. Supply is fixed at TOTAL_SUPPLY and may only decrease through burns. EIP-2612 permits are supported for gasless approvals. Ordinary transfers and off-pool integrations are not taxed by the token itself.
FeeHook is a Uniswap V4 BaseHook that attaches to pools formed by exactly one allowlisted project token and one allowlisted pair currency. Fees are always taken in the pool's token side and transferred to the treasury via poolManager.take. Charging occurs in _beforeSwap when the token is the specified currency and in _afterSwap when it is unspecified, covering exact-in and exact-out paths. Owner-managed registries (allowedTokens, allowedPairs) gate pool initialization through _beforeInitialize; accepted pools record poolFeeToken, so later delisting only blocks new initializations. lockLists freezes both lists permanently. Per-token feeThreshold accounting can auto-disable fees once cumulative collection reaches the threshold. feeExempt exempts designated caller contracts (V4 routers), and a one-time launch guard per token restricts early swaps by priority fee range and caller allowlist until a buy budget is exhausted or the guard is ended. Ownership uses Ownable2Step; renounceOwnership is disabled.
During remediation the fee leg was split into two alternative implementations of FeeHook, each delivered as a separate commit and each collecting the fee on one side of the pool. The token-side variant keeps charging on the pool's project-token side; the pair-side variant charges in the pool's counterpart currency, typically native ETH, and keys the fee accumulator and its shutoff threshold by both project token and fee currency rather than by token alone. Both variants also replace the callback-time poolManager.take described above with poolManager.mint, crediting the fee to the treasury as an ERC-6909 claim that the treasury redeems separately. Registry, launch-guard, and ownership surfaces are identical in both, and one variant is intended for deployment.
Files in Scope
Token.sol — Fixed-supply ERC-20 implementing OpenZeppelin
ERC20,ERC20Burnable, andERC20Permit. The constructor mintsTOTAL_SUPPLYto a non-zerorecipient; holders and approved spenders may reduce supply viaburnandburnFrom.FeeHook.sol — Uniswap V4 hook that charges configurable swap fees (capped at
MAX_FEE) on allowlisted token-pair pools, routes proceeds to the treasury, and exposes owner controls for registries, fees, exemptions, launch guard, and two-step ownership transfer.
Privileged roles
Token.sol
No privileged roles exist after deployment. The constructor mints the fixed supply to a recipient address, which is an initial token holder only and not an on-chain admin role.
FeeHook.sol
owner (inherited from Ownable2Step / Ownable): Controls registry, fee configuration, launch-guard settings, and two-step ownership transfer. Ownership renunciation is permanently disabled.
Can call
setTokenAllowedto allow or disallow project tokens (reverts when lists are locked).Can call
setPairAllowedto allow or disallow pair currencies, includingaddress(0)for ETH (reverts when lists are locked).Can call
lockListsto permanently freeze both allowlists.Can call
setFeeto updatefeeBps(bounded byMAX_FEEof 300).Can call
setFeeThresholdto set a per-token auto-disable collection threshold.Can call
setTreasuryto update the validated fee recipient.Can call
setFeeExemptto exempt or un-exempt caller contracts from the fee.Can call
setLaunchGuardto arm a token's launch guard once before its first pool.Can call
setFeeRangeto set the launch-guard priority fee range.Can call
setLaunchCallerAllowedto manage the launch-guard caller allowlist.Can call
endLaunchGuardto end a token's launch guard early (one-way).Can call
transferOwnershipto nominate a new owner (two-step handoff).Can call
acceptOwnership(as pending owner) to accept ownership (two-step handoff).Can call
renounceOwnership, which always reverts withRenounceDisabled.
Potential Risks
Treasury and fee redemption outside the boundary: treasury is an owner-set address, validated only against the zero address, the hook itself, the PoolManager, and registry members. Because remediation credits fees as ERC-6909 claims on the PoolManager, realising them requires the treasury to burn those claims inside a PoolManager unlock, which an EOA or Safe can only do by authorising a redeemer contract through IERC6909Claims.setOperator. Neither the treasury account nor any redeemer contract is part of this review, so whether collected fees can be withdrawn, and in which currency the treasury is able to hold them, rests on configuration outside the audited boundary.
Uniswap V4 BaseHook and PoolManager dependency: FeeHook inherits BaseHook from v4-periphery, binds to IPoolManager from v4-core, and routes fees exclusively through poolManager.take inside _collectFee, which remediation replaced with poolManager.mint in both variants. Pool acceptance, swap deltas, and fee extraction rely on that external callback framework (getHookPermissions, _beforeInitialize, _beforeSwap, _afterSwap). Defects, unavailability, or currency-accounting changes in the Uniswap V4 hook or PoolManager path would directly affect fee charging, launch-guard enforcement, and delivery to treasury.
Coupling to Uniswap V4 swap lifecycle: Swap fees and launch-guard checks execute only inside Uniswap V4 pool callbacks for pools that pass _beforeInitialize registry checks (allowedTokens, allowedPairs, poolFeeToken). Ordinary ERC-20 transfers of Token are untaxed; all fee and antisnipe behavior is inseparable from V4 pool initialization and PoolManager.swap caller semantics (sender is the router contract, not the end-user EOA).
Fixed total supply determined at construction: Token defines TOTAL_SUPPLY as the constant 100_000_000e18 and mints that entire amount once in the constructor to the recipient parameter, with no subsequent mint path. Name, symbol, and initial holder are constructor inputs; after deployment, circulating supply can only decrease through ERC20Burnable burns. Misallocation of the initial recipient or incorrect name/symbol at deploy time is permanent for the minted supply distribution.
Owner-managed fee and launch caller allowlists: FeeHook maintains feeExempt and launchCallerAllowed, both writable only by the owner via setFeeExempt and setLaunchCallerAllowed. feeExempt causes an early return at the top of _beforeSwap (and skips fee charging in _afterSwap), so an exempt V4 sender pays no fee and is also never launch-gated. A non-empty launchCallerAllowed registry (launchAllowedCallers != 0) restricts buys while launchGuardActive is true; an empty registry disables only that caller gate, while any configured priority-fee floor or cap still applies. Incorrect exemption of a public router enables fee-free and guard-free swaps for all users of that router.
Immediate owner control without on-chain delay: The FeeHook owner can call setFee, setTreasury, setFeeThreshold, setFeeExempt, setTokenAllowed, setPairAllowed, setFeeRange, setLaunchCallerAllowed, endLaunchGuard, and lockLists in the same transaction that invokes each setter, with no on-chain timelock. setLaunchGuard is likewise immediate when callable, but only before the token's first accepted pool and only once. Fee rate (up to MAX_FEE), treasury destination, per-token shutoff thresholds, registry membership until lock, and global priority-fee bounds therefore take effect with no mandatory notice window. After launch, mid-flight reshaping of gating is limited to setFeeRange, setLaunchCallerAllowed, and one-way endLaunchGuard, not re-arming the buy budget.
Multi-sig recommended but not enforced: Constructor NatSpec for FeeHook recommends a Safe multisig as _owner, yet the contract accepts any non-zero address and performs no on-chain multi-signature or threshold check. Deployment may therefore leave fee, treasury, registry, and launch-guard powers under a single EOA. Off-chain custody choices cannot be verified from the in-scope bytecode alone.
Single administrative point of failure on FeeHook: Operational control of allowed tokens and pairs, fee rate, treasury, fee exemptions, launch-guard budgets, launch callers, and priority-fee range concentrates in the FeeHook owner. Loss, coercion, or compromise of that key or controlling contract can halt intended administration or force adversarial reconfiguration of all listed pools' fee and launch behavior. Token itself exposes no post-deployment admin surface.
Owner key liveness as ongoing dependency: renounceOwnership on FeeHook is overridden to revert with RenounceDisabled, so ownership cannot be burned away. Continued correct operation of fee updates, treasury rotation, and optional early endLaunchGuard therefore requires the owner key or owner contract to remain available and uncompromised for the lifetime of mutable configuration.
Count-based antisnipe budget can be burned by dust buys: Each token's launch guard is armed once via setLaunchGuard with a fixed launchGuardBuys budget; successful non-exempt buys that pass _checkLaunchBuy increment launchBuyCount until the budget is exhausted or endLaunchGuard ends it. Rejected buys revert and do not consume budget, but successful minimal buys through an allowed caller permanently advance the counter. A determined actor can exhaust the guard at gas, tip, and dust cost, after which priority-fee and caller checks permanently cease for that token.
One-way freezes and permanent guard termination: lockLists permanently sets listsLocked, after which setTokenAllowed and setPairAllowed always revert with ListsFrozen. endLaunchGuard sets launchGuardEnded for a token and cannot be undone; setLaunchGuard is set-once and unavailable after tokenHasPool is true. Premature locking freezes the registry against future tokens or pairs, and premature guard termination removes antisnipe protections with no re-arm path.
Partial fills rejected on the fee-specified swap path: When the fee currency is the swap's specified currency, _beforeSwap charges fee on the full requested amountSpecified, and _afterSwap reverts PartialFillNotSupported unless the realised specified-side delta matches that amount plus the fee. A fill an unmodified V4 pool would truncate is therefore rejected outright, which is protective rather than a defect, since V4 applies an _afterSwap return delta to the unspecified currency and the pre-charge cannot be refunded. The protected cells follow the fee side, so the pair-side variant moves the rejection onto exact-input buys, the ordinary retail path, where a buy exceeding pool depth reverts even under the canonical router's unbounded price limit. The contract NatSpec documents the behavior, the retail-path consequence included.
Findings
Code ― | Title | Status | Severity | |
|---|---|---|---|---|
| F-2026-1880 | Callback-Time Fee Withdrawal Blocks Token Sells When PoolManager Inventory Is Thin | fixed | Medium | |
| F-2026-1880 | Launch-Guard Budget Can Be Exhausted by Zero-Fee Dust Buys in a Single Transaction | accepted | Medium | |
| F-2026-1880 | Permissionless Initialization Permanently Blocks Arming of a Token's Launch Guard | fixed | Medium | |
| F-2026-1880 | Third Parties Can Advance the Token-Wide Fee Threshold and Disable Fees on Intended Pools | mitigated | Low | |
| F-2026-1898 | Missing Key Validation In Fee Threshold Setter Prevents Fee Shutoff | accepted | Low | |
| F-2026-1881 | Exact-Output Trades Pay a Lower Effective Fee Than Exact-Input Trades | fixed | Observation | |
| F-2026-1881 | Canonical Pool Initialization Can Be Front-Run | fixed | Observation | |
| F-2026-1881 | Registry Documentation Overstates Pool-Level Admission | fixed | Observation | |
| F-2026-1881 | Dynamic-Fee Pools Can Attach and Remain at Zero LP Fee | fixed | Observation | |
| F-2026-1880 | Router Allowlisting Cannot Enforce the Documented Front-End-Only Access Rule | fixed | Observation |
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/vAPI-Network/token→ |
| Initial Commit | 281ba94dad1c8d00e1f807bb931c22381cc5f756 |
| Remediation Commit (fee in project token) | 372514ca99250590764c9cb9f101ca90181de2bf (audit/hacken-remediation) |
| Remediation Commit (fee in pair currency, ETH) | f3f051d05eeddd5943eb2c2e419c1ec2ac7a68f2 (explore/eth-fee-redesign) |
| Whitepaper | N/A |
| Requirements | README.md; NatSpec |
| Technical Requirements | README.md; NatSpec |
Scope Details
- Repository
- https://github.com/vAPI-Network/token→
- Initial Commit
- 281ba94dad1c8d00e1f807bb931c22381cc5f756
- Remediation Commit (fee in project token)
- 372514ca99250590764c9cb9f101ca90181de2bf (
audit/hacken-remediation) - Remediation Commit (fee in pair currency, ETH)
- f3f051d05eeddd5943eb2c2e419c1ec2ac7a68f2 (
explore/eth-fee-redesign) - Whitepaper
- N/A
- Requirements
- README.md; NatSpec
- Technical Requirements
- README.md; NatSpec
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.