Side Effects (SIDE) security report
Radar AI scanned the verified Side Effects contract on Base. Material findings include owner-controlled pool transfer blocking, configurable recipient balance limits, and implicit maximum Permit2 allowance.
Side Effects is not an unrestricted minting or blacklist token based on the verified source. However, the owner can block transfers to any configured pool address and later unlock it, which can interrupt pool-directed transfers. Initialization can also impose a balance cap on non-excluded recipients until expiration or controller disablement. Permit2 is granted an implicit maximum token allowance by design, subject to Permit2 authorization rules.
Trust score: 72/100. Source verified: Yes. Chain: base. Contract: 0x5d57596ecc2d891c3909e4f84f91a93862d6fee1.
This report was last modified on 2026-10-08 and contains 3 material findings.
medium finding: Owner can block transfers to the configured pool
The owner can designate any address as the pool and enable a lock that makes transfers to that address revert. If the configured address is a trading pool, this can interrupt transfers directed to the pool, including sell paths, until the owner unlocks it.
Evidence: DopplerERC20V1.lockPool(address pool_) is onlyOwner and sets pool = pool_ and isPoolLocked = true. In _beforeTokenTransfer, transfers with to == pool revert with PoolLocked() while isPoolLocked is true. unlockPool() is also onlyOwner.
Recommendation: Treat pool locking as a privileged operational control. Verify the configured pool address, monitor PoolLocked-related state changes, and use a timelocked or governed owner if this control is intended to remain available.
medium finding: Initialization can impose a recipient balance cap and restrict transfers
When configured, the balance limit rejects transfers or minting to non-excluded recipients whose resulting balance exceeds maxBalanceLimit. Incorrect exclusions or an unsuitable cap can prevent ordinary transfers to affected addresses until the limit expires or the controller disables it.
Evidence: initialize() activates isBalanceLimitActive when maxBalanceLimit_ or balanceLimitEnd_ is set, stores maxBalanceLimit and balanceLimitEnd, and marks only owner, recipient, and supplied excluded addresses as excluded. _beforeTokenTransfer reverts with BalanceLimitExceeded when a non-excluded recipient would exceed the cap before balanceLimitEnd. disableBalanceLimit() is callable only by controller.
Recommendation: Review initialization parameters and every excluded address before deployment. Use a trusted controller or omit the controller only when permanent duration-based enforcement is intended; test transfers involving pools, routers, migrators, and treasury addresses.
medium finding: Permit2 has implicit maximum token allowance
The token treats the canonical Permit2 address as having an infinite allowance for every token holder, without requiring a per-holder ERC20 approval transaction. This expands the trusted execution surface to Permit2 and any integration or authorization flow that permits Permit2 to transfer tokens.
Evidence: DopplerERC20V1 overrides _givePermit2InfiniteAllowance() to return true. ERC20.allowance() returns type(uint256).max for the Permit2 address, and ERC20.transferFrom() skips the token allowance check when msg.sender is Permit2.
Recommendation: Document the Permit2 dependency and ensure users understand that Permit2 is an implicit spender. Restrict integrations to the canonical verified Permit2 deployment and monitor changes in Permit2 authorization assumptions.