Flap pay (fPay) security report
SecureChain AI scanned the verified Flap pay source and reviewed GoPlus evidence. No public mint, blacklist, pause, proxy upgrade, or GoPlus honeypot signal was identified. Material risks include owner-controlled pool migration, initialization-configured taxes and dependencies, and a dividend callback that can revert transfers if the external contract fails. Slither was not run.
The contract does not expose an owner mint, blacklist, pause, or upgrade function, and GoPlus did not identify a honeypot. However, the owner controls migration from a state that blocks transfers to and from configured pools, while every non-pool transfer may depend on an external dividend contract. These are meaningful centralization and transfer-availability risks.
Trust score: 62/100. Source verified: Yes. Chain: bsc. Contract: 0x2259d0fc599a4cd2cf4861cae52c4f0d65537777.
This report was last modified on 2026-09-29 and contains 4 material findings.
high finding: External dividend callback can lock transfers and trading
After each transfer, the token calls dividendContract.setShare() for non-excluded sender and recipient addresses. Any revert from that external contract is propagated as DividendShareUpdateFailed, reverting the token transfer. A failing, incompatible, paused, or maliciously configured dividend contract can therefore prevent ordinary transfers and may also block buys or sells involving user addresses.
Evidence: In _afterTokenTransfer(), IDividend(dividendContract).setShare(from, balanceOf(from)) and setShare(to, balanceOf(to)) are called inside try/catch blocks; the catch handlers execute revert DividendShareUpdateFailed(...). dividendContract is assigned during initialize() and there is no fallback path when the callback fails.
Recommendation: Use a non-blocking dividend update pattern, such as recording failed updates for later repair, or add a carefully governed ability to disable or replace the dividend integration. Validate the dividend contract interface and behavior before initialization.
medium finding: Tax processing failure can redirect accumulated tax tokens to the processor
If TaxProcessor.processTaxTokens() reverts, the token catches the failure and transfers the entire token balance held by the token contract directly to taxProcessor. This bypasses the intended processing path and makes the configured processor a privileged recipient of accumulated tax tokens whenever processing fails.
Evidence: In _processTax(), the catch branch reads balanceOf(address(this)) and calls _plainTransfer(address(this), taxProcessor, remainingBalance). taxProcessor is configured during initialize() and is not replaced or independently validated afterward.
Recommendation: Do not transfer balances automatically on processing failure. Keep the tokens escrowed, emit a recoverable failure event, and allow a governed retry or recovery procedure with explicit recipient controls.
medium finding: Owner-controlled migration can keep configured pools unusable
While the token remains in BondingCurve state, every transfer involving an address marked in pools is rejected. The owner alone controls startMigration() and finalizeMigration(), so the owner can delay migration and keep pool-based trading restricted indefinitely. This creates a material launch and transfer-availability dependency on the owner.
Evidence: In _transfer(), PoolState.BondingCurve requires !pools[from] && !pools[to]. startMigration() and finalizeMigration() are both external onlyOwner functions, and no permissionless timeout or automatic transition exists.
Recommendation: Use an immutable or time-bounded launch schedule, multisignature or timelocked administration, and publish the migration conditions. Consider an automatic transition or a permissionless recovery path after a defined deadline.
medium finding: Initialization parameters give deployer broad tax and dependency control
The initializer sets buy and sell tax rates, taxProcessor, dividendContract, pool addresses, tax duration, anti-farmer duration, router, and quote token. Tax rates are uint16 basis-point values with no explicit upper-bound validation, so initialization can configure rates above 100% and can bind transfers to arbitrary external processor or dividend contracts. The current scan evidence does not provide the initialization transaction parameters needed to confirm the deployed values.
Evidence: initialize() directly stores params.buyTax and params.sellTax, requires only a nonzero taxProcessor, accepts dividendContract without interface validation, and marks every supplied params.pools address as a pool. _getTaxWithPoolState() divides by 10000, so a rate greater than 10000 can make taxed transfers underflow in _taxedTransfer().
Recommendation: Enforce buyTax and sellTax <= 10000, validate all external contract addresses, use a trusted factory with atomic initialization, and verify the deployed initialization calldata and resulting state before trading.