New Tapout Protocol (BYTE) security report
Radar by SecureChain AI scanned New Tapout Protocol BYTE on BNB Smart Chain. Material findings include an uninitialized-proxy takeover condition, owner-controlled pool migration restrictions, and external tax and dividend callback dependencies.
The contract does not expose owner-controlled minting, blacklist controls, or a direct transfer-tax setter after initialization. However, deployment must atomically initialize any proxy, and the configured dividend and tax processor contracts are trusted dependencies. Owner-controlled migration can also restrict pool transfers until migration is completed.
Trust score: 55/100. Source verified: Yes. Chain: bsc. Contract: 0xe49875c417b865ed6e544ef1c55c13f26e867777.
This report was last modified on 2026-10-15 and contains 5 material findings.
high finding: Uninitialized proxy could be taken over through initialize
If a proxy instance is deployed without initialization in the same transaction or before initialization is otherwise secured, any caller can invoke initialize once, become the owner through __Ownable_init(), configure arbitrary external dependencies and pools, and receive the entire maxSupply mint.
Evidence: initialize(...) is external and protected only by the one-time initializer modifier. It calls __Ownable_init(), then executes _mint(msg.sender, maxSupply). The constructor disables initialization only on the implementation contract; it does not initialize proxy storage.
Recommendation: Deploy proxies with initializer calldata atomically, verify the proxy's Initialized event and owner immediately after deployment, and prevent any publicly reachable uninitialized deployment window.
medium finding: Configured dividend callback can block token transfers
When dividendContract is nonzero, ordinary transfers involving non-pool addresses synchronously call dividendContract.setShare(). Any revert from that external call reverts the entire token transfer, creating a transfer denial-of-service condition if the configured dividend contract is unavailable, incompatible, or deliberately reverting.
Evidence: _afterTokenTransfer calls IDividend(dividendContract).setShare(from, balanceOf(from)) and setShare(to, balanceOf(to)) without ignoring failures. Each failed call triggers DividendShareUpdateFailed and reverts the token transfer. dividendContract is supplied during initialize and has no setter in this contract.
Recommendation: Validate the dividend implementation during initialization, use a trusted immutable or governed dependency, and consider isolating share-accounting failures from ERC20 transfer success through a resilient update mechanism.
medium finding: Owner controls migration states that govern pool transfer restrictions
The owner can keep the token in BondingCurve, where transfers to or from every configured pool revert, or can choose when to transition through Migrating into tax-enforced operation. This creates centralized operational control over whether configured pool interactions are usable.
Evidence: _transfer requires !pools[from] && !pools[to] in BondingCurve state. startMigration() and finalizeMigration() are both onlyOwner and change the state from BondingCurve to Migrating and then TaxEnforcedAntiFarmer. No permissionless timeout or alternative transition exists.
Recommendation: Use a transparent, time-bounded migration mechanism, document the owner role, and consider immutable or governance-controlled transition conditions with publicly verifiable deployment procedures.
medium finding: Tax processing depends on arbitrary external contracts configured at initialization
The token grants the configured taxProcessor an unlimited allowance to pull tax tokens and delegates tax processing to it. A faulty or malicious processor can affect tax handling, return threshold-direction signals, or receive accumulated tax tokens through the failure fallback.
Evidence: _processTax sets allowance(address(this), taxProcessor) to type(uint256).max, then calls ITaxProcessor(taxProcessor).processTaxTokens(taxAmount). If that call fails, the catch block transfers the entire remaining token balance of the token contract to taxProcessor with _plainTransfer(address(this), taxProcessor, remainingBalance). taxProcessor is supplied by initialize and cannot be changed afterward.
Recommendation: Use a verified processor with tightly scoped authorization, avoid unlimited approvals where practical, validate the processor address and behavior before deployment, and make fallback handling transfer only the intended amount rather than the entire contract balance.
medium finding: External tax and dividend calls add reentrancy and composability risk to transfers
Token transfers invoke external contracts before completion of the overall transfer flow. Although the liquidation flag limits recursive liquidation, the external tax processor and dividend contract can execute arbitrary code during transfer processing and may cause unexpected reverts or state interactions.
Evidence: _liquidateTax can call ITaxProcessor(taxProcessor).processTaxTokens(taxAmount) from inside _transfer. _afterTokenTransfer then calls IDividend(dividendContract).setShare for sender and recipient. Neither external interaction is protected by a reentrancy guard.
Recommendation: Review the configured external contracts for reentrancy, apply checks-effects-interactions protections where possible, add explicit reentrancy tests for tax and dividend callbacks, and minimize external calls in the ERC20 transfer path.