Radar by SecureChain AI

GrainFi (GrainFi) security report

GrainFi was AI scanned using verified Solidity source and GoPlus evidence. No confirmed minting, blacklist, proxy, selfdestruct, or honeypot signal was identified. Material risks include owner-controlled migration, an external tax processor with unlimited allowance, unbounded initialization tax rates that could lock trading if set above 100%, and an owner holding about 41.53% of supply. Slither was not run.

The supplied evidence does not show a confirmed honeypot, minting backdoor, blacklist, proxy, or selfdestruct capability. However, trading activation and tax behavior depend on owner and external tax-processor configuration. The largest observed risks are conditional launch/transfer control, external tax-processing trust, and a possible complete transfer lock if initialization uses tax rates above 10,000 basis points.

Trust score: 62/100. Source verified: Yes. Chain: bsc. Contract: 0x1d4189f1bf285759d5033cff2438bb4175247777.

This report was last modified on 2026-09-19 and contains 3 material findings.

high finding: Owner controls migration required for pool trading

While the token is in BondingCurve state, every transfer involving a configured pool reverts. Only the owner can call startMigration() and finalizeMigration(), which are required to move the token into a state where pool transfers are permitted. A non-cooperative or compromised owner can therefore prevent configured-pool trading from becoming operational.

Evidence: _transfer() requires !pools[from] && !pools[to] in PoolState.BondingCurve. startMigration() and finalizeMigration() are both external onlyOwner functions. The supplied GoPlus evidence reports transfer_pausable=0, but the source implements state-dependent pool restrictions that are not equivalent to a conventional pause flag.

Recommendation: Use a trust-minimized launcher or timelocked/ multisignature authority for migration, publish the expected migration state and deadlines, and verify on-chain that finalizeMigration() has executed before treating the token as freely tradable.

high finding: Initialization permits tax rates above 100%, potentially locking all pool trades

The initializer accepts uint16 buyTax and sellTax values without requiring either rate to be at most 10,000 basis points. If a rate above 10,000 is configured, the calculated tax exceeds the transfer amount and amount - tax reverts. Once tax enforcement applies to the relevant pool, affected buys or sells can become impossible, creating a complete trading lock for that direction or both directions.

Evidence: initialize() stores params.buyTax and params.sellTax directly into uint16 poolState fields with no upper-bound validation. _getTaxWithPoolState() calculates amount * rate / 10000, while _taxedTransfer() executes uint256 remainingAmount = amount - tax. The supplied ABI exposes the initializer but does not provide the deployed initialization values.

Recommendation: Enforce buyTax <= 10000 and sellTax <= 10000 in initialize(), preferably with a lower governance-approved maximum. Verify the deployed poolState tax rates and test representative buy and sell transfers before users trade.

medium finding: External tax processor receives unlimited allowance and controls tax handling

The token grants taxProcessor an effectively unlimited allowance over the token contract's balance. Tax liquidation then calls the external processor, which can pull the specified tax amount. If processing fails, the contract sends its entire remaining token balance to taxProcessor. A compromised, incorrect, or malicious processor can therefore capture accumulated tax tokens and influence liquidation behavior.

Evidence: _processTax() calls _approve(address(this), taxProcessor, type(uint256).max) and invokes ITaxProcessor(taxProcessor).processTaxTokens(taxAmount). In the catch path it calls _plainTransfer(address(this), taxProcessor, remainingBalance), transferring the full token-contract balance. taxProcessor is set during initialize() and is not changeable through the exposed ABI.

Recommendation: Use a narrowly scoped allowance equal to the current liquidation amount, validate the processor address and implementation, add recovery and governance controls, and avoid transferring the full residual balance on processing failure without an auditable, bounded fallback.