Quantum Audit Logo
Launch App

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

Is Frax USD Safe?

FRXUSDEthereum
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 →
Last checked Sep 4, 2026 · 1 audit on record
SummaryAI Copilot

The audit of the FrxUSD token contract, an ERC-20 implementation utilizing a TransparentUpgradeableProxy, identified a critical vulnerability related to its constructor initialization.

Read the full analysis
What raised the score
  • Ownership not renounced — strong Multisig
  • Proxy contract
  • OZ ProxyAdmin -> Admin is unclassified 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 = 68.0%
  • LP top3 unlocked holders = 90.8%
  • 1 Critical finding(s) from audit
  • 1 High finding(s) from audit
  • 1 Medium finding(s) from audit
  • 1 Low finding(s) from audit
Exact factors
  • Ownership NOT renounced — strong Multisig (4-of-7)
  • Proxy contract (upgradeable — admin can replace logic)
  • OZ ProxyAdmin -> Admin is unclassified contract
  • Top-10 concentration > 50% (85.6% total → 60.8% effective; 44.3% in EOAs, 41.2% in contracts — heavy)
  • Liquidity not locked, but no owner/deployer address holds LP — market-depth risk, not rug risk
  • LP top1 unlocked holder = 68.0% (independent LP — depth risk, pool = 52% of DEX liquidity)
  • LP top3 unlocked holders = 90.8% (independent LP — depth risk, pool = 52% of DEX liquidity)
  • 1 Critical finding(s) from audit
  • 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 44 of 7 checks passed
Contract verifiedVerified
OwnershipRetained
MintNo mint
Liquidity lockNot locked
UpgradeabilityUpgradeable
HoneypotNone found
Buy / sell tax0% / 0%

Holders

as of audit · Sep 4, 2026
41.2%Contracts44.3%Wallets14.4%Everyone else
41.2%Contracts44.3%Wallets14.4%Everyone else
ContractsWalletsEveryone elseBubble area = share of supply
85.6%of supply sits with the top 10 holders
  • Contractstreasury, vesting, bridge, staking41.2%
  • Walletsanonymous holders, free to sell44.3%
  • Everyone elsethe rest of the supply14.4%
Effective concentrationwhat the score reads60.8%
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 4$28.45M across 13 pairs
LP tokensNot locked

The LP tokens of the analysed pool are not locked or burned, so whoever holds them can withdraw that liquidity.

Analysed pool$14.77MShare of depth51.9%
Top-1 Unlocked Holder68.0%
Top-3 Unlocked90.8%
Unlocked LP held by
0x5f07…832f0x3777…c2c80xc37a…88d30xf711…57930x83ee…26600xf5a5…9da30x714f…7f0a

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

Security Findings

1 Critical1 High1 Medium1 Low2 Info
Critical

Critical: Constructor Initialization in Upgradeable Contract Locks Out Owner

The FrxUSD3 contract, which serves as the implementation for a TransparentUpgradeableProxy, initializes its Ownable base contract via its constructor: constructor() FrxUSD2(address(1), "Frax USD", "frxUSD") {}. In an upgradeable proxy pattern, the constructor of the implementation contract is called only once when the implementation is deployed, not when the proxy is initialized. This means the owner state variable within the implementation contract is permanently set to address(1). Consequently, any function protected by the onlyOwner modifier will only be callable by address(1), rendering the legitimate proxy owner (e.g., the multisig `0xb898ad2976b4d8f2e21521c9db16b7497825e…C-01

Issue

The FrxUSD3 contract, which serves as the implementation for a TransparentUpgradeableProxy, initializes its Ownable base contract via its constructor: constructor() FrxUSD2(address(1), "Frax USD", "frxUSD") {}. In an upgradeable proxy pattern, the constructor of the implementation contract is called only once when the implementation is deployed, not when the proxy is initialized. This means the owner state variable within the implementation contract is permanently set to address(1). Consequently, any function protected by the onlyOwner modifier will only be callable by address(1), rendering the legitimate proxy owner (e.g., the multisig `0xb898ad2976b4d8f2e21521c9db16b7497825e…

Fix

For upgradeable contracts, avoid using constructors for state initialization. Instead, implement an initialize function (e.g., `function initialize(address _ownerAddress, string memory _name, string memory _symbol) public initializer`) that is called once by the proxy's admin after deployment. This function should set the owner and other initial parameters. Ensure the initialize function uses an initializer modifier (e.g., from OpenZeppelin's UUPSUpgradeable or Initializable) to preve…

Status

Unresolved

High

High: Extensive Centralized Control by Owner and Freezers

The contract grants significant centralized control to the owner and designated freezer roles. The owner has the power to add/remove minters, add/remove freezers, pause/unpause all transfers, and burn arbitrary amounts of tokens from any address, including burning an entire balance if _amount is zero. Freezers can freeze/thaw any user account. This high degree of centralization means that a compromise of the owner's or a freezer's private keys could lead to severe consequences, including censorship, denial of service, or arbitrary token destruction.H-01

Issue

The contract grants significant centralized control to the owner and designated freezer roles. The owner has the power to add/remove minters, add/remove freezers, pause/unpause all transfers, and burn arbitrary amounts of tokens from any address, including burning an entire balance if _amount is zero. Freezers can freeze/thaw any user account. This high degree of centralization means that a compromise of the owner's or a freezer's private keys could lead to severe consequences, including censorship, denial of service, or arbitrary token destruction.

Fix

While some centralization is inherent in stablecoin designs, consider implementing additional safeguards. For critical functions like burnMany, addMinter, removeMinter, addFreezer, removeFreezer, pause, and unpause, consider adding time-locks to allow users to react to pending changes. Implement multi-signature requirements for all sensitive administrative actions if not already enforced at the owner wallet level. Clearly document the responsibilities and security procedures for m…

Status

Unresolved

Medium

Medium: Owner Bypasses Pause and Freeze Checks

The _update internal function, which is called during token transfers, includes a conditional check: if (msg.sender != owner()) { ... }. This logic allows the contract owner to bypass the isPaused and isFrozen checks. While this might be intended for emergency recovery or specific administrative actions, it means the owner is not subject to the same restrictions as other users. This could be perceived as a backdoor, potentially allowing the owner to transfer tokens even when the contract is paused or to/from frozen accounts, undermining the intended universal application of these security mechanisms.M-01

Issue

The _update internal function, which is called during token transfers, includes a conditional check: if (msg.sender != owner()) { ... }. This logic allows the contract owner to bypass the isPaused and isFrozen checks. While this might be intended for emergency recovery or specific administrative actions, it means the owner is not subject to the same restrictions as other users. This could be perceived as a backdoor, potentially allowing the owner to transfer tokens even when the contract is paused or to/from frozen accounts, undermining the intended universal application of these security mechanisms.

Fix

Re-evaluate the necessity of the owner bypassing pause and freeze checks. If this functionality is critical for emergency scenarios, ensure it is clearly documented and understood. Consider implementing a separate, explicitly named emergency function for owner-initiated transfers that bypasses these checks, rather than embedding it within the general _update logic. This would make the intent clearer and reduce the risk of unintended use.

Status

Unresolved

Low

Low: Inefficient Minter Removal in minters_array

The removeMinter function iterates through the minters_array to find the target address and sets minters_array[i] = address(0). This approach does not actually remove the element from the array; it merely marks it as address(0). Over time, if many minters are added and removed, the minters_array will grow indefinitely with address(0) entries. This can lead to increased gas costs for any future function that iterates over this array, and could potentially hit block gas limits if the array becomes excessively large.L-01

Issue

The removeMinter function iterates through the minters_array to find the target address and sets minters_array[i] = address(0). This approach does not actually remove the element from the array; it merely marks it as address(0). Over time, if many minters are added and removed, the minters_array will grow indefinitely with address(0) entries. This can lead to increased gas costs for any future function that iterates over this array, and could potentially hit block gas limits if the array becomes excessively large.

Fix

To efficiently remove elements from a dynamic array, consider using a 'swap and pop' pattern. When an element is to be removed, swap it with the last element in the array and then pop() the last element. This maintains array contiguity and avoids address(0) entries. Alternatively, if the order of minters is not critical, a mapping(address => bool) for minters is sufficient for checking membership, and minters_array could be removed or rebuilt periodically if iteration is truly necessa…

Status

Unresolved

Info

Informational: Use of address(1) in Constructor

The constructor of FrxUSD3 initializes the Ownable contract with address(1) as the owner. While the primary issue is the use of a constructor for initialization in an upgradeable contract (C-01), the specific choice of address(1) is unusual. This address is a valid, but generally unused, Ethereum address. Its use here might be confusing or lead to misinterpretations if not clearly documented as a placeholder or a symptom of the upgradeability issue.I-01

Issue

The constructor of FrxUSD3 initializes the Ownable contract with address(1) as the owner. While the primary issue is the use of a constructor for initialization in an upgradeable contract (C-01), the specific choice of address(1) is unusual. This address is a valid, but generally unused, Ethereum address. Its use here might be confusing or lead to misinterpretations if not clearly documented as a placeholder or a symptom of the upgradeability issue.

Fix

Ensure that any placeholder addresses or unusual initialization values are thoroughly documented within the code or in external specifications to prevent confusion or misinterpretation by future auditors or developers.

Status

Unresolved

Info

Informational: OpenZeppelin Contracts Version 5.3.0

The contract utilizes OpenZeppelin Contracts version 5.3.0. This is a relatively recent version, indicating a commitment to using up-to-date and potentially more secure library components. However, newer versions can sometimes introduce subtle behavioral changes or require careful integration. It's important to ensure that the development team is fully aware of any breaking changes or new features introduced in this version compared to previous ones they might have used.I-02

Issue

The contract utilizes OpenZeppelin Contracts version 5.3.0. This is a relatively recent version, indicating a commitment to using up-to-date and potentially more secure library components. However, newer versions can sometimes introduce subtle behavioral changes or require careful integration. It's important to ensure that the development team is fully aware of any breaking changes or new features introduced in this version compared to previous ones they might have used.

Fix

Maintain a clear understanding of the OpenZeppelin Contracts changelog for version 5.3.0 and ensure all integrations are compatible. Regularly review OpenZeppelin's security advisories and consider upgrading to the latest stable version as new releases become available, after thorough testing.

Status

Unresolved

Analysis

AI Copilotas of audit · Sep 4
Executive SummaryWhat the contract is and what the review found

The audit of the FrxUSD token contract, an ERC-20 implementation utilizing a TransparentUpgradeableProxy, identified a critical vulnerability related to its constructor initialization. The implementation contract's owner is incorrectly set to address(1) due to constructor logic, rendering all owner-restricted functions inaccessible to the legitimate proxy owner. Additionally, the contract exhibits a high degree of centralization with extensive owner and freezer privileges, and the owner can bypass pause and freeze mechanisms. While the contract leverages well-vetted OpenZeppelin libraries for core functionality and EIP standards, the upgradeability and access control flaws pose significant risks.

Technical6/10Medium risk

The technical architecture benefits from inheriting battle-tested OpenZeppelin contracts (ERC20, ERC20Permit, Ownable2Step) and implementing EIP-3009 and EIP-2612 for enhanced token utility (7.1 Architecture). However, a critical flaw exists where the implementation contract's constructor initializes the owner to address(1), effectively locking out the actual proxy owner from all onlyOwner functions (7.3 Access Control). The removeMinter function also uses an inefficient soft-deletion mechanism, potentially leading to increased gas costs over time (7.2 Code Security).

Governance1/10High risk

The contract design grants significant centralized control to the owner and designated freezers (7.5 Governance). The owner can add/remove minters and freezers, pause/unpause transfers, and burn arbitrary amounts of tokens from any address, including full balances (7.4 Economic). Freezers can freeze/thaw accounts, which, combined with the owner's ability to bypass pause/freeze checks, creates a powerful and potentially exploitable control surface (7.3 Access Control). While the owner is a multisig, the extensive powers still represent a high risk if compromised.

Upgrades1/10High risk

The contract is deployed behind a TransparentUpgradeableProxy, but the implementation contract's constructor in FrxUSD3 initializes Ownable with address(1) (7.7 Upgrades). This is a critical anti-pattern for upgradeable contracts, as constructors are only called once upon implementation deployment, not during proxy initialization. Consequently, the owner() function in the implementation will always return address(1), making all onlyOwner functions inaccessible to the actual proxy owner, effectively bricking core administrative functionalities (7.3 Access Control).

Final RecommendationWhat to do about this score

Immediately address the critical constructor issue by deploying a new implementation contract that correctly initializes the Ownable role via an initialize function, rather than the constructor.

Review and potentially restrict the extensive centralized powers of the owner and freezer roles, considering multi-signature requirements for sensitive operations or time-locks. Improve the removeMinter function to efficiently remove elements from the minters_array to prevent unbounded growth and potential gas issues.

Contract & Record

1 audit on record
TypeTransparentUpgradeableProxy
NetworkEthereum
Token age1y
Contract0xcacd…6e29
Deployer0x5b35…9814
Proxy Upgrade Controls
Proxy TypeEip1967 Transparent
AdminOZ ProxyAdmin → Other-Contract
ImplementationVerified source
Upgrades (30d)0 · stable
Badge for your website
Frax USD security record badge

Free for any token on the record. It links to this page and always shows the current score and the date it was checked.

Audit History
  1. Sep 4, 202649Medium
  2. Sep 2, 202643Medium

Score changes are recorded as dated snapshots — history is append-only and cannot be edited.

Would You Like a More Detailed Audit of Frax USD?

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