The BobToken contract is an upgradeable ERC-20 token utilizing OpenZeppelin's UUPS, Ownable, ERC20Permit, ERC20Burnable, and AccessControl standards. The audit identified a High severity issue related to broken custom role management functions, which are unusable as implemented. Additionally, a Medium severity concern was noted regarding the centralized control over critical roles by the DEFAULT_ADMIN_ROLE, although mitigated by a multisig owner. Overall, the contract demonstrates good adherence to OpenZeppelin best practices for upgradeability and token functionality, but requires attention to the identified access control and role management issues.

On-chain security analysis — is it a scam or legit?
Is BOB Safe?
Not verified
This record has not gone through deep verification and is not being monitored. The score is a dated snapshot — the token’s risk can change at any time.Own this token? Put it under verification →The BobToken contract is an upgradeable ERC-20 token utilizing OpenZeppelin's UUPS, Ownable, ERC20Permit, ERC20Burnable, and AccessControl standards.
Read the full analysis- Ownership not renounced — Multisig
- Mintable supply — no cap found, dilution unbounded
- Proxy contract
- Top-10 concentration > 50%
- Liquidity not locked, but no owner/deployer address holds LP — market-depth risk, not rug risk
- LP top1 unlocked holder = 100.0%
- LP top3 unlocked holders = 100.0%
- 1 High finding(s) from audit
- 1 Medium finding(s) from audit
- 1 Low finding(s) from audit
Exact factors
- Ownership NOT renounced — Multisig (2-of-4)
- Mintable supply — no cap found, dilution unbounded
- Proxy contract (upgradeable — admin can replace logic)
- Top-10 concentration > 50% (94.9% total → 64.1% effective; 43.6% in EOAs, 51.3% in contracts — heavy)
- Liquidity not locked, but no owner/deployer address holds LP — market-depth risk, not rug risk
- LP top1 unlocked holder = 100.0% (independent LP — depth risk)
- LP top3 unlocked holders = 100.0% (independent LP — depth risk)
- 1 High finding(s) from audit
- 1 Medium finding(s) from audit
- 1 Low finding(s) from audit
Each factor is an on-chain fact recorded at the time of this analysis. The score is computed from them by a deterministic function, so the same contract returns the same score for anyone who runs the audit. How scores are computed
Security Checklist
as of audit · Sep 4Holders
as of audit · Sep 4, 2026- Contractstreasury, vesting, bridge, staking51.3%
- Walletsanonymous holders, free to sell43.6%
- Everyone elsethe rest of the supply5.1%
How holder types affect the score
Share held by contracts — treasury, vesting, bridge or staking — is discounted against share held by wallets when the score is computed: a contract cannot decide to sell the way an anonymous holder can, though it can still be drained or voted to sell. Effective concentration is the figure the risk score is actually calculated from.
Holder balances as recorded by the audit of Sep 4, 2026
Liquidity
as of audit · Sep 4The risk score reads depth across every pair.
The LP tokens of the analysed pool are not locked or burned, so whoever holds them can withdraw that liquidity.
0x9ead…ef92No privileged address appears among these holders: the unlocked liquidity sits with independent providers, not with the deployer.
Security Findings
HighBroken Role Management Functions (grantMintAndBurnRoles, revokeMintAndBurnRoles)
The grantMintAndBurnRoles and revokeMintAndBurnRoles functions are intended to manage MINTER_ROLE and BURNER_ROLE. However, they lack explicit access control (e.g., onlyRole(DEFAULT_ADMIN_ROLE)). When these functions are called, they internally invoke grantRole or revokeRole. Since grantRole and revokeRole are protected by onlyRole(getRoleAdmin(role)), and the msg.sender for the internal call is the contract itself (address(this)), which does not hold DEFAULT_ADMIN_ROLE, these functions will always revert. This renders the custom role management functions unusable, requiring DEFAULT_ADMIN_ROLE holders to directly interact with AccessControlUpgradeable's `grantR…H-01
grantMintAndBurnRoles, revokeMintAndBurnRoles)Issue
The grantMintAndBurnRoles and revokeMintAndBurnRoles functions are intended to manage MINTER_ROLE and BURNER_ROLE. However, they lack explicit access control (e.g., onlyRole(DEFAULT_ADMIN_ROLE)). When these functions are called, they internally invoke grantRole or revokeRole. Since grantRole and revokeRole are protected by onlyRole(getRoleAdmin(role)), and the msg.sender for the internal call is the contract itself (address(this)), which does not hold DEFAULT_ADMIN_ROLE, these functions will always revert. This renders the custom role management functions unusable, requiring DEFAULT_ADMIN_ROLE holders to directly interact with AccessControlUpgradeable's `grantR…
Fix
Add onlyRole(DEFAULT_ADMIN_ROLE) to both grantMintAndBurnRoles and revokeMintAndBurnRoles functions. This will ensure that only authorized administrators can call these functions, and the internal calls to grantRole/revokeRole will then be correctly executed with the msg.sender being the authorized administrator.
Status
Unresolved
MediumCentralized Control over Minting/Burning and CCIP Admin
The DEFAULT_ADMIN_ROLE holds significant power within the contract. This role can grant/revoke MINTER_ROLE and BURNER_ROLE, effectively controlling the token's supply dynamics (up to i_maxSupply), and can also set the s_ccipAdmin address. While the initialOwner (assigned DEFAULT_ADMIN_ROLE) is a multisig, this still represents a single point of control for these critical functions. A compromise of the multisig could lead to unauthorized token inflation or manipulation of the CCIP admin address.M-01
Issue
The DEFAULT_ADMIN_ROLE holds significant power within the contract. This role can grant/revoke MINTER_ROLE and BURNER_ROLE, effectively controlling the token's supply dynamics (up to i_maxSupply), and can also set the s_ccipAdmin address. While the initialOwner (assigned DEFAULT_ADMIN_ROLE) is a multisig, this still represents a single point of control for these critical functions. A compromise of the multisig could lead to unauthorized token inflation or manipulation of the CCIP admin address.
Fix
Consider implementing further decentralization or introducing a timelock mechanism for critical operations such as granting/revoking MINTER_ROLE or BURNER_ROLE, or changing the s_ccipAdmin. This would provide a delay for users to react to malicious actions and reduce the immediate impact of a multisig compromise.
Status
Unresolved
LowFixed Max Supply Value
The i_maxSupply is hardcoded in the initialize function to 10,000,000,000 * 10**decimals(). While this provides a clear and immutable supply cap, it means the maximum supply cannot be adjusted without a contract upgrade. If future protocol needs or market conditions require a different supply cap, an upgrade would be necessary, which might not always be desirable or feasible.L-01
Issue
The i_maxSupply is hardcoded in the initialize function to 10,000,000,000 * 10**decimals(). While this provides a clear and immutable supply cap, it means the maximum supply cannot be adjusted without a contract upgrade. If future protocol needs or market conditions require a different supply cap, an upgrade would be necessary, which might not always be desirable or feasible.
Fix
If flexibility in the maximum supply is desired, consider making i_maxSupply configurable by a privileged role (e.g., DEFAULT_ADMIN_ROLE) or through a governance mechanism. If the intention is for the maximum supply to be permanently fixed, no change is strictly necessary, but this design choice should be explicitly documented.
Status
Unresolved
InfoExternal useNonce Function Exposure
The useNonce() function is an external wrapper around _useNonce(msg.sender). While it doesn't pose a direct vulnerability, _useNonce is typically an internal function used by ERC20Permit's _permit and _approve functions to prevent replay attacks. Exposing this internal mechanism directly via an external function might lead to confusion or unintended usage if its purpose is not clearly understood or documented.I-01
useNonce Function ExposureIssue
The useNonce() function is an external wrapper around _useNonce(msg.sender). While it doesn't pose a direct vulnerability, _useNonce is typically an internal function used by ERC20Permit's _permit and _approve functions to prevent replay attacks. Exposing this internal mechanism directly via an external function might lead to confusion or unintended usage if its purpose is not clearly understood or documented.
Fix
Review if the useNonce() function is truly necessary for external calls. If its functionality is only required internally by the ERC20Permit mechanism, consider removing the external wrapper. If it serves a specific external purpose, ensure its functionality and intended use cases are thoroughly documented.
Status
Unresolved
Analysis
AI Copilotas of audit · Sep 4The contract leverages well-vetted OpenZeppelin upgradeable libraries for its ERC-20, burnable, permit, and access control functionalities (7.2 Code Security). The architecture is standard for an upgradeable token (7.1 Architecture). However, a significant issue was found in the custom grantMintAndBurnRoles and revokeMintAndBurnRoles functions, which are currently non-functional due to incorrect access control implementation, rendering them unusable (7.3 Access Control). This requires direct interaction with AccessControlUpgradeable functions for role management.
The economic model includes a fixed maximum supply (i_maxSupply) for the token, which provides predictability but limits flexibility without an upgrade (7.4 Economic). Governance relies on OwnableUpgradeable for upgrades and AccessControlUpgradeable for managing MINTER_ROLE, BURNER_ROLE, and s_ccipAdmin (7.5 Governance). The initialOwner (and thus DEFAULT_ADMIN_ROLE) holds significant power, though this is mitigated by the use of a multisig for the owner address (7.8 Operations).
The contract correctly implements the UUPS upgradeability pattern using OpenZeppelin's UUPSUpgradeable (7.7 Upgrades). The _authorizeUpgrade function is restricted to onlyOwner, ensuring that only the designated owner can initiate upgrades. The Initializable pattern is correctly used, and the constructor disables initializers to prevent re-initialization.
Prioritize resolving the High severity issue related to the broken role management functions to ensure proper control over minting and burning capabilities.
Carefully consider the implications of the centralized control held by the DEFAULT_ADMIN_ROLE and explore options for further decentralization or timelocks for critical operations if the project's roadmap requires it. Review the necessity and implications of the useNonce function's external exposure. Ensure comprehensive testing of all access control mechanisms and upgrade paths.
Contract & Record
Free for any token on the record. It links to this page and always shows the current score and the date it was checked.
- Aug 31, 202672High
Score changes are recorded as dated snapshots — history is append-only and cannot be edited.
Would You Like a More Detailed Audit of BOB?
Our AI-powered scanner gives you a deeper, real-time smart contract analysis — free, with every scoring factor shown.
Get Detailed Audit Is this your token? Publish your own audit on this page