Quantum Audit Logo

Is EURC Safe?

On-chain security analysis — is it a scam or legit?

EURC EURC
0x60a3…db42
Base Not verifiedLast checked 3d ago 1 audit on record
Executive SummaryAI Copilot

This audit covers the FiatTokenV2_2 contract, which serves as the implementation logic for a USDC stablecoin proxy on the Base network. The contract implements ERC-20 functionalities, EIP-712 signed messages, and a custom blacklisting mechanism. The codebase is generally well-structured and follows established patterns for stablecoin operations, including upgradeability. Key findings highlight the inherent centralization risks typical for stablecoins and the complexity introduced by a non-standard blacklist storage method.

1 High1 Medium2 Low1 Informational
Volume 24h
$6.31M
Liquidity
$2.14M
Price
$1.1600
Token Age
1y
Top 10 Holders
47.8%

Security Findings

High

Centralized Control and Single Point of Failure

H-01The contract design, typical for a centralized stablecoin, grants significant power to a small set of privileged addresses (admin, owner, pauser, blacklister). These roles can pause transfers, blacklist accounts, and control contract upgrades. The proxy's admin is an EOA, representing a single point of failure for upgradeability and overall contract control. A compromise of this EOA could lead to unauthorized upgrades or manipulation of critical contract functions (7.3 Access Control, 7.5 Governance, 7.8 Operations).
IssueThe contract design, typical for a centralized stablecoin, grants significant power to a small set of privileged addresses (admin, owner, pauser, blacklister). These roles can pause transfers, blacklist accounts, and control contract upgrades. The proxy's admin is an EOA, representing a single point of failure for upgradeability and overall contract control. A compromise of this EOA could lead to unauthorized upgrades or manipulation of critical contract functions (7.3 Access Control, 7.5 Governance, 7.8 Operations).
FixWhile inherent to stablecoin design, consider implementing multi-signature wallets or a time-locked governance mechanism for critical administrative functions, especially the proxy admin, to reduce the risk associated with a single EOA compromise. This enhances operational security and resilience against key loss.
StatusUnresolved
Medium

Non-Standard Balance and Blacklist Storage Mechanism

M-01The contract employs a custom storage mechanism where `balanceAndBlacklistStates` uses a single `uint256` to store both an account's balance (lower 255 bits) and its blacklist status (most significant bit). While the implementation appears correct and includes checks like `_balance <= ((1 << 255) - 1)` to prevent overflow into the blacklist bit, this non-standard approach increases complexity and could be a source of subtle bugs or integration issues if not perfectly maintained or understood by external systems (7.1 Architecture, 7.2 Code Security).
IssueThe contract employs a custom storage mechanism where `balanceAndBlacklistStates` uses a single `uint256` to store both an account's balance (lower 255 bits) and its blacklist status (most significant bit). While the implementation appears correct and includes checks like `_balance <= ((1 << 255) - 1)` to prevent overflow into the blacklist bit, this non-standard approach increases complexity and could be a source of subtle bugs or integration issues if not perfectly maintained or understood by external systems (7.1 Architecture, 7.2 Code Security).
FixEnsure thorough internal documentation and testing for this custom storage logic. Future upgrades or integrations should exercise extreme caution when interacting with or modifying this specific storage pattern to prevent unintended side effects or data corruption.
StatusUnresolved
Low

Self-Blacklisting in `initializeV2_2`

L-01The `initializeV2_2` function explicitly blacklists the contract's own address (`_blacklist(address(this))`). While this might be intended to prevent tokens from being accidentally sent to and locked within the contract itself, it is an unusual pattern that could have unforeseen implications for future interactions or integrations if not fully understood by all parties (7.2 Code Security, 7.8 Operations).
IssueThe `initializeV2_2` function explicitly blacklists the contract's own address (`_blacklist(address(this))`). While this might be intended to prevent tokens from being accidentally sent to and locked within the contract itself, it is an unusual pattern that could have unforeseen implications for future interactions or integrations if not fully understood by all parties (7.2 Code Security, 7.8 Operations).
FixDocument the precise rationale behind blacklisting the contract address. Confirm that this action does not interfere with any expected contract functionalities, such as receiving tokens from other contracts, or future upgrade paths that might require the contract to hold tokens temporarily.
StatusUnresolved
Low

Reliance on `_chainId()` for EIP-712 Domain Separator

L-02The `_domainSeparator()` function uses `_chainId()` (which retrieves the chain ID via assembly) as part of the EIP-712 domain separator. While standard practice for EIP-712, if the contract were to be deployed on a chain with an unexpected chain ID, or if a chain's ID were to change (highly improbable for established networks), it would invalidate all existing EIP-712 signatures, requiring users to re-sign (7.2 Code Security, 7.6 External).
IssueThe `_domainSeparator()` function uses `_chainId()` (which retrieves the chain ID via assembly) as part of the EIP-712 domain separator. While standard practice for EIP-712, if the contract were to be deployed on a chain with an unexpected chain ID, or if a chain's ID were to change (highly improbable for established networks), it would invalidate all existing EIP-712 signatures, requiring users to re-sign (7.2 Code Security, 7.6 External).
FixThis is generally robust for stable chains like Base. No direct action is required, but it's a consideration for deployment on new or less stable networks, or if the contract were to be forked to a chain with a different ID, as it would necessitate re-issuing signatures.
StatusUnresolved
Info

Single-Use Upgrade Initialization Function

I-01The `initializeV2_2` function includes a `require(_initializedVersion == 2);` check, ensuring it can only be called once and only when the previous version was correctly initialized. This is a standard and secure pattern for upgradeable contracts. However, if the initialization process were to fail mid-execution (e.g., due to an out-of-gas error or an unexpected revert within the `accountsToBlacklist` loop), the function could not be retried, potentially leaving the contract in an inconsistent state (7.7 Upgrades, 7.8 Operations).
IssueThe `initializeV2_2` function includes a `require(_initializedVersion == 2);` check, ensuring it can only be called once and only when the previous version was correctly initialized. This is a standard and secure pattern for upgradeable contracts. However, if the initialization process were to fail mid-execution (e.g., due to an out-of-gas error or an unexpected revert within the `accountsToBlacklist` loop), the function could not be retried, potentially leaving the contract in an inconsistent state (7.7 Upgrades, 7.8 Operations).
FixEnsure that the `accountsToBlacklist` array is processed efficiently and within gas limits, especially for large lists. Consider robust pre-deployment testing of the upgrade path on a testnet with realistic data to minimize the risk of failure during the single allowed execution.
StatusUnresolved

Category Ratings

TechnicalMedium6/10

The technical architecture (7.1) is robust, leveraging an upgradeable proxy pattern and EIP-712 for off-chain signed transactions. Code security (7.2) is generally strong, with appropriate checks for reentrancy and integer overflows, and a specific check in `receiveWithAuthorization` to prevent front-running. However, the custom bitmasking for balance and blacklist status in `_setBlacklistState` introduces complexity, which, while seemingly correct, is a non-standard pattern that requires careful management.

GovernanceHigh3/10

The economic model (7.4) is that of a centralized stablecoin, backed by fiat reserves, which inherently carries a high level of governance risk (7.5). Critical functions such as blacklisting, pausing, and upgrades are controlled by privileged addresses, typically EOAs or multi-signature wallets. This centralization, while expected for a stablecoin, means a compromise of these keys could lead to significant operational disruption or asset control issues. For example, the `initializeV2_2` function allows for symbol updates and migration of blacklisted accounts, controlled by an authorized entity.

UpgradesHigh1/10

The contract utilizes a ZeppelinOS legacy proxy pattern, allowing for seamless upgrades of the token logic (7.7). The `initializeV2_2` function is designed for a controlled, single-time execution during an upgrade, ensuring proper state migration and versioning. However, the proxy's admin address is an EOA, which represents a single point of failure for upgrade control. While the implementation contract itself is well-designed for upgrades, the security of the proxy admin is paramount.

Security Checklist

Contract VerifiedPass
Ownership RenouncedFail
No Mint FunctionFail
Liquidity LockedFail
Not a ProxyFail

Proxy Upgrade Controls

Proxy TypeZeppelin Os Legacy
AdminEOA (single key controls upgrades)
ImplementationVerified source
Upgrades (30d)0 · stable

Holder Composition

31.3% in wallets16.5% in contracts
Effective Concentration37.9%

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.

Liquidity Depth

Show 4 more pairsShow less

The 20 remaining pairs hold $151.0K between them and are not listed.

The risk score reads depth across every pair. The volume figure and the volume-to-liquidity ratio elsewhere on this page describe only the pair this audit analysed, so the two are not directly comparable.

LP Distribution

Top-1 Unlocked Holder34.0%
Top-3 Unlocked76.6%

Key Addresses

Deployer
0x71b7…3a78
Unlocked LP Held By
0x35f9…82cf0xa94f…6b2a0xd392…74700x7d27…fd550x6520…fd220xde40…d2580x8e0d…7b280x64d8…f6980x6fa3…1a490x1eec…2bcd

No privileged address appears among these holders: the unlocked liquidity sits with independent providers, not with the deployer.

What Raised This Score

  • Ownership NOT renounced — owner is an EOA (single private key)
  • Mintable supply — no cap found, dilution unbounded
  • Proxy contract (upgradeable — admin can replace logic)
  • Admin is EOA (single key controls upgrades)
  • Top-10 concentration > 30% (47.8% total → 37.9% effective; 31.3% in EOAs, 16.5% in contracts — moderate)
  • Liquidity not locked, but no owner/deployer address holds LP — market-depth risk, not rug risk
  • 1 High finding(s) from audit
  • 1 Medium finding(s) from audit
  • 2 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

Related Audits

Coinbase Wrapped BTC (CBBTC)High RiskDotHigh RiskSekuya (SKYA)High RiskRibbita by Virtuals (TIBBIR)High RiskPromptHigh RiskCoinbase Wrapped XRP (CBXRP)High Risk

Would You Like a More Detailed Audit of EURC?

Our AI-powered scanner gives you a deeper, real-time smart contract analysis — free, with every scoring factor shown.

Get Detailed Audit