Radar by SecureChain AI

Freedom of Money (货币自由) security report

Freedom of Money was AI scanned from verified source on BSC. Radar found no exposed mint, blacklist, pause, or selfdestruct path, but identified high owner concentration, owner-controlled migration, and medium risks tied to tax initialization and external dividend and tax-processing contracts. Slither was not run.

The contract does not show an obvious arbitrary mint, blacklist, selfdestruct, or owner-controlled tax setter. Trading and transfer behavior also depends on initialization parameters and external contracts that were not independently supplied for review.

Trust score: 48/100. Source verified: Yes. Chain: bsc. Contract: 0xced5a2ba24268407abda6790744d65b192897777.

This report was last modified on 2026-09-27 and contains 5 material findings.

high finding: Owner-controlled migration can keep pool trading restricted

The token starts in PoolState.BondingCurve, where transfers to or from any configured pool revert. Only the owner can call startMigration() and finalizeMigration(), and no permissionless fallback or deadline forces migration. If the owner does not complete both calls, pool trading remains restricted while ordinary wallet-to-wallet transfers can continue.

Evidence: initialize() sets poolState.state to PoolState.BondingCurve. _transfer() requires !pools[from] && !pools[to] in that state. startMigration() and finalizeMigration() are both external onlyOwner functions. GoPlus identifies owner_address as 0xe2ce6ab80874fa9fa2aae65d277dd6b8e65c9de0.

Recommendation: Use a permissionless or time-bounded migration path, publish the intended migration authority, and verify the live poolState before trading. Consider multisignature ownership and an emergency recovery process.

medium finding: Initialization permits tax rates above 100%, which can disable pool transfers

initialize() accepts buyTax and sellTax as uint16 values without requiring either rate to be at most 10000 basis points. If a configured rate exceeds 10000, _taxedTransfer() computes remainingAmount = amount - tax and reverts because tax exceeds amount. This can make buys or sells involving configured pools fail during the tax-enforced states. The supplied evidence does not include the deployed tax-rate values.

Evidence: initialize() directly stores params.buyTax and params.sellTax in poolState. _getTaxWithPoolState() calculates amount * rate / 10000, while _taxedTransfer() subtracts that tax from amount without a cap. Rates up to 65535 are accepted by uint16.

Recommendation: Enforce buyTax <= 10000 and sellTax <= 10000 during initialization, or explicitly cap tax at the transfer amount.

medium finding: External dividend callback can block ordinary token transfers

When dividendContract is nonzero, every transfer involving a non-excluded sender or recipient calls dividendContract.setShare(). Any revert from that external call is propagated as DividendShareUpdateFailed, causing the entire token transfer to revert. A broken, malicious, or incompatible dividend contract configured at initialization could therefore create a broad transfer lock for ordinary holders.

Evidence: _afterTokenTransfer() calls IDividend(dividendContract).setShare(from, balanceOf(from)) and setShare(to, balanceOf(to)) without a failure-tolerant fallback; caught failures are explicitly reverted. dividendContract is assigned from params.dividendContract during initialize() and has no setter in the contract.

Recommendation: Validate the dividend contract during initialization, consider isolating share-accounting failures from token transfers, and provide a controlled emergency disable or replacement mechanism governed by a multisignature.

medium finding: Tax liquidation delegates custody and failure handling to an immutable external processor

The contract approves taxProcessor for an effectively unlimited allowance and calls processTaxTokens(). If that call reverts, the catch branch transfers the entire token balance held by the token contract to taxProcessor. The processor address is set during initialization and cannot be changed through this contract, so a faulty or compromised processor can receive accumulated tax tokens or disrupt liquidation behavior.

Evidence: _processTax() sets allowance(address(this), taxProcessor) to type(uint256).max when needed. On catch, it executes _plainTransfer(address(this), taxProcessor, remainingBalance). taxProcessor is assigned once in initialize(), with only a nonzero-address check.

Recommendation: Use a rigorously verified processor, restrict approvals to the required amount where practical, define explicit recipient and accounting safeguards, and add governance-controlled recovery for processor failure.

medium finding: Tax parameters and pool configuration are immutable after initialization

The contract has no owner functions to change tax rates, configured pools, taxProcessor, dividendContract, router, or quoteToken after initialize(). Incorrect or malicious initialization values cannot be corrected through this token contract and may permanently alter trading, fee routing, or transfer behavior.

Evidence: initialize() writes buyTaxRate, sellTaxRate, pools, mainPool, taxProcessor, dividendContract, v2Router, and quoteToken. The ABI contains no setters for these values; only migration state is owner-controlled.

Recommendation: Use a vetted factory with strict parameter validation, publish the initialization transaction and all configured addresses, and verify external dependencies before launch.