Bitano ($BITA) security report
Bitano ($BITA) was AI-scanned from verified source and ABI data. The review found no minting or proxy upgrade path, but identified high-risk centralized controls over launch, fees, transfer limits, exemptions, reward assets, and treasury swaps. GoPlus also flagged hidden ownership, pausable transfers, and modifiable slippage. Slither was not run.
The principal risks are centralized administrative controls rather than an identified permissionless theft exploit. The owner can keep trading disabled or remove transaction protections, while the immutable developer wallet can raise buy, sell, and transfer fees within hard caps, exempt selected accounts, change the reward asset, and alter swap behavior. GoPlus also reports hidden_owner, transfer_pausable, slippage_modifiable, anti-whale, and external-call signals. These controls create meaningful loss, restriction, and dividend-reliability risks. Slither was skipped.
Trust score: 58/100. Source verified: Yes. Chain: bsc. Contract: 0xb492432aa4557cf3d33e6c961985065150913a50.
This report was last modified on 2026-09-29 and contains 4 material findings.
high finding: Developer wallet retains powerful post-renouncement controls
The immutable DEV_WALLET can continue to modify economically significant behavior even if ownership is renounced. It can set buy fees up to 10%, sell fees up to 20%, wallet-transfer fees up to 15%, grant fee exemptions, change the reward asset, alter conversion settings, change swap slippage up to 20%, execute manual treasury swaps, and rescue unrelated assets.
Evidence: Bitano.sol defines onlyDev as msg.sender == DEV_WALLET. setFees, setConversionSettings, setAutoSwapSlippage, setFeeExempt, manualSwap, rescueBNB, and rescueForeignToken use this authority. renounceOwnership() only sets _owner to address(0); it does not disable DEV_WALLET. GoPlus reports hidden_owner=1, transfer_pausable=1, slippage_modifiable=1, and anti_whale_modifiable=1.
Recommendation: Disclose the developer wallet as a permanent privileged role, use a timelock or multisig, emit and monitor all privileged changes, and consider making fee, reward-asset, swap, and rescue powers renounceable or governance-controlled.
high finding: Owner can indefinitely prevent public trading or remove protections
Before trading is enabled, ordinary transfers and AMM buys are rejected unless one side is pre-authorized. The owner alone can enable trading or change the auto-launch threshold. While ownership remains, the owner can also disable all limits and later re-enable the global limit state, creating centralized control over transfer availability and transaction restrictions.
Evidence: _transfer() calls _enforcePreLaunch() while tradingEnabled is false, and _enforcePreLaunch() requires an allow-listed non-AMM address. enableTrading() and setAutoLaunchAfterBuyers() are onlyOwner. removeAllLimits() disables max-buy, max-wallet, and buy-window checks; setLimitsInEffect() can change the global state. GoPlus reports transfer_pausable=1 and anti_whale_modifiable=1.
Recommendation: Use a time-bounded launch mechanism or immutable launch deadline, publish the launch authority, place limit changes behind a timelock, and verify on-chain that trading is enabled before relying on the token for public transfers.
medium finding: Future dividend asset is centrally replaceable and not behaviorally validated
The owner or developer can replace the dividend asset for future generations with any contract that has a PancakeSwap V2 pair and nonzero reserves. The validation does not establish that the asset is standard, transferable, non-taxing, non-pausing, or honest. A hostile or incompatible reward token can cause dividend funding or claims to fail, while the automatic treasury path catches funding failures and leaves obligations pending.
Evidence: setRewardToken() is protected by onlyOwnerOrDev and calls _validateRewardAsset(). That validation checks code length, a PancakeSwap pair, and nonzero reserves, but does not inspect token transfer behavior or administrative controls. executeAutomaticFunding() catches failures and emits AutoSwapFailed("REWARD_PURCHASE"), allowing token sells to continue while dividend funding remains pending.
Recommendation: Restrict reward assets to an immutable allowlist or governance-approved list, validate transfer behavior on a fork before activation, add a timelock and veto period for changes, and publish recovery procedures for failed generations.
medium finding: Dividend balances arriving without active shares can become stranded across generations
DividendVault.syncDeposit() does not update accountedBalance when totalShares is zero. If an asset balance exists while there are no shares and the generation is then sealed, the old generation cannot later recognize that balance. The token and vault also prohibit rescuing historical dividend assets, so the balance can remain inaccessible unless the same asset is reused in a later generation, where attribution may instead occur under the new generation.
Evidence: DividendVault.syncDeposit() returns after emitting DividendsUnallocated when shares == 0, without updating accountedBalance. openGeneration() calls syncDeposit() before sealing the outgoing generation. rescueForeignToken() rejects every asset used by any generation, while finalizeGenerationRounding() only handles a sealed generation's recognized funded balance.
Recommendation: Define explicit handling for zero-share deposits before generation sealing, such as retaining per-generation unallocated balances, allowing a bounded recovery path, or preventing generation changes while unallocated balances exist.