Vividpad (VIVID) security report
Radar AI scanned Vividpad VIVID on BNB Smart Chain from verified source. Material findings include owner-controlled pool migration, dividend callback transfer failures, and tax-processor trust risks.
The source does not expose an unrestricted mint function or blacklist function, and GoPlus reported no minting, blacklist, proxy, or honeypot signal. However, the owner controls migration from a state that blocks pool transfers, while configured external contracts can freeze transfers or receive accumulated tax tokens under failure handling. These are material control and operational risks.
Trust score: 54/100. Source verified: Yes. Chain: bsc. Contract: 0x0a9fb6535d0b50f4994c21a4444e4e91f4e67777.
This report was last modified on 2026-10-07 and contains 4 material findings.
medium finding: Owner-controlled migration can keep pool trading restricted
While the token is in BondingCurve state, every transfer involving an address marked in pools reverts. Only the owner can call startMigration and finalizeMigration, so the owner controls when pool transfers become possible and when tax-enforced trading begins. Failure to complete migration can keep trading through configured pools unavailable.
Evidence: In _transfer, PoolState.BondingCurve requires !pools[from] && !pools[to], reverting with "Transfers to/from pools are restricted in BondingCurve state". startMigration() and finalizeMigration() are both protected by onlyOwner.
Recommendation: Use an independently verifiable migration condition or timelock, publish the configured pool addresses and migration procedure, and avoid relying on an unrestricted owner-controlled transition for enabling pool transfers.
medium finding: Dividend callback can halt token transfers
When dividendContract is configured, token transfers invoke setShare for the sender and recipient. Any revert from the dividend contract is rethrown as DividendShareUpdateFailed, so a failing, paused, incompatible, or malicious dividend contract can make ordinary transfers revert for affected accounts and potentially prevent broad token movement.
Evidence: _afterTokenTransfer calls IDividend(dividendContract).setShare(from, balanceOf(from)) and setShare(to, balanceOf(to)) without suppressing failure. Each failed call executes revert DividendShareUpdateFailed(...). dividendContract is assigned during initialize and has no setter in FlapTaxTokenV3.
Recommendation: Decouple balance transfers from dividend bookkeeping, or use failure isolation and recovery controls. Validate the dividend implementation during initialization and provide a safe way to disable or replace it if callbacks fail.
medium finding: Tax processor receives unlimited allowance and failed-tax balances
The configured taxProcessor is approved for an unlimited allowance over the token contract's tax balance. If processTaxTokens reverts, the contract catches the error and transfers its remaining token balance directly to taxProcessor. A compromised or incorrectly configured processor could therefore control or obtain accumulated tax tokens.
Evidence: _processTax sets _approve(address(this), taxProcessor, type(uint256).max) when allowance is insufficient. In the catch branch, it calls _plainTransfer(address(this), taxProcessor, remainingBalance). taxProcessor is supplied during initialize and cannot be changed by a public setter.
Recommendation: Use exact, limited approvals, verify the processor implementation and address before initialization, avoid transferring all remaining balances on failure, and add governed recovery or processor replacement controls.
medium finding: Initialization caller receives the entire fixed supply
Initialization mints maxSupply directly to msg.sender. The contract does not distribute or escrow this supply itself, so the deployment or factory path must correctly identify and control the recipient. A wrong initializer caller or misconfigured deployment can place the entire supply under an unintended account.
Evidence: initialize() executes _mint(msg.sender, maxSupply), where maxSupply is defined as 1e9 ether. initialize is externally callable once through the initializer modifier and does not validate the intended recipient separately from msg.sender.
Recommendation: Initialize atomically through a trusted factory, explicitly document the recipient, verify the initializer transaction before enabling trading, and consider minting to a dedicated treasury or distribution contract.