Quantum Audit Logo

Is Uniswap Safe?

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

Uniswap UNI
0xfa7f…f7f0
Arbitrum
Not verifiedThis 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.
Last checked today 1 audit on record
Executive SummaryAI Copilot

The audit of the StandardArbERC20 token implementation, deployed via a ClonableBeaconProxy, identified critical access control vulnerabilities related to its initialization process. Specifically, the `bridgeInit` function, which sets crucial operational parameters and the L2 gateway address, lacks proper access restrictions. This could allow an unauthorized entity to seize control of token minting and burning, or to disable core ERC20 metadata functions. Other findings include a potential limitation in string parsing and the inherent complexity of inline assembly, though these are of lower severity. The contract leverages OpenZeppelin standards and a modular architecture, but the identified critical flaws require immediate attention.

2 Critical1 Medium2 Low1 Informational
Volume 24h
$795.4K
Liquidity
$557.4K
Price
$10.2200
Token Age
1y
Top 10 Holders
54.8%

Security Findings

Critical

Unprotected Re-initialization of ERC20 Getters State

C-01The `bridgeInit` function, which sets the `availableGetters` struct, is `public` and lacks any access control or an `initializer` modifier. While `L2GatewayToken._initialize` prevents re-initialization of `l2Gateway` and `l1Address`, the `availableGetters` state variable can be modified multiple times by any external caller. An attacker could call `bridgeInit` with malformed `_data` to intentionally cause `BytesParser.toString` or `BytesParser.toUint8` to fail, thereby setting `ignoreName`, `ignoreSymbol`, or `ignoreDecimals` to `true`. This would cause the `name()`, `symbol()`, or `decimals()` functions to revert for all users, leading to a denial-of-service for basic ERC20 metadata retrie…
IssueThe `bridgeInit` function, which sets the `availableGetters` struct, is `public` and lacks any access control or an `initializer` modifier. While `L2GatewayToken._initialize` prevents re-initialization of `l2Gateway` and `l1Address`, the `availableGetters` state variable can be modified multiple times by any external caller. An attacker could call `bridgeInit` with malformed `_data` to intentionally cause `BytesParser.toString` or `BytesParser.toUint8` to fail, thereby setting `ignoreName`, `ignoreSymbol`, or `ignoreDecimals` to `true`. This would cause the `name()`, `symbol()`, or `decimals()` functions to revert for all users, leading to a denial-of-service for basic ERC20 metadata retrie…
FixImplement an `initializer` modifier (e.g., from OpenZeppelin's `Initializable` contract) on the `bridgeInit` function to ensure it can only be called once. Alternatively, add an `onlyOwner` or similar access control mechanism to restrict who can call this function and prevent unauthorized modification of `availableGetters`.
StatusUnresolved
Critical

Unprotected Initialization of L2 Gateway Address

C-02The `bridgeInit` function is `public` and lacks any access control. This function calls `L2GatewayToken._initialize`, passing `msg.sender` as the `l2Gateway_` parameter. The `l2Gateway` address is critical as it controls the `bridgeMint` and `bridgeBurn` functions, which directly affect the token's supply. Since `bridgeInit` can be called by anyone, the first caller can front-run the legitimate initialization and set the `l2Gateway` to an arbitrary address they control. This grants the attacker full control over the token's minting and burning capabilities, leading to a complete loss of funds or unauthorized supply manipulation.
IssueThe `bridgeInit` function is `public` and lacks any access control. This function calls `L2GatewayToken._initialize`, passing `msg.sender` as the `l2Gateway_` parameter. The `l2Gateway` address is critical as it controls the `bridgeMint` and `bridgeBurn` functions, which directly affect the token's supply. Since `bridgeInit` can be called by anyone, the first caller can front-run the legitimate initialization and set the `l2Gateway` to an arbitrary address they control. This grants the attacker full control over the token's minting and burning capabilities, leading to a complete loss of funds or unauthorized supply manipulation.
FixThe `bridgeInit` function must be protected by an `initializer` modifier (e.g., from OpenZeppelin's `Initializable` contract) to ensure it can only be called once. Additionally, the `initializer` should be callable only by a trusted deployer or governance mechanism to securely set the `l2Gateway` address.
StatusUnresolved
Medium

Ambiguous or Restrictive String Parsing in BytesParser.toString

M-01The `BytesParser.toString` library function has specific logic for handling 32-byte inputs. If `input.length == 32`, it explicitly checks if `input[31]` is `bytes1(0x00)`. If it's not null, the parsing fails (`return (false, res)`). This implies that 32-byte strings must be null-terminated to be successfully parsed by this branch. If an L1 token's name or symbol is exactly 32 bytes long and not null-terminated, it will fail to parse, potentially causing the `name()` or `symbol()` functions in `StandardArbERC20` to revert if `ignoreName` or `ignoreSymbol` is set to `true` (due to parsing failure during `bridgeInit`). This could lead to a denial-of-service for metadata retrieval for specific,…
IssueThe `BytesParser.toString` library function has specific logic for handling 32-byte inputs. If `input.length == 32`, it explicitly checks if `input[31]` is `bytes1(0x00)`. If it's not null, the parsing fails (`return (false, res)`). This implies that 32-byte strings must be null-terminated to be successfully parsed by this branch. If an L1 token's name or symbol is exactly 32 bytes long and not null-terminated, it will fail to parse, potentially causing the `name()` or `symbol()` functions in `StandardArbERC20` to revert if `ignoreName` or `ignoreSymbol` is set to `true` (due to parsing failure during `bridgeInit`). This could lead to a denial-of-service for metadata retrieval for specific,…
FixClarify the intended encoding standard for 32-byte strings within the Arbitrum bridge documentation. If non-null-terminated 32-byte strings are expected, adjust the `BytesParser.toString` logic to handle them correctly, possibly by using `abi.decode(input, (string))` for all string lengths, or by providing a more robust parsing mechanism. Ensure that the parsing logic is resilient to various valid string encodings to prevent unexpected reverts.
StatusUnresolved
Low

Reliance on Low-Level Assembly in BytesLib

L-01The `BytesLib` contract utilizes inline assembly (`mload`, `add`, `div`) for byte manipulation and type conversions (e.g., `toAddress`, `toUint8`, `toUint`). While the current implementation appears correct and includes bounds checks (`require(_bytes.length >= (_start + N))`), inline assembly is inherently more complex and error-prone than high-level Solidity. Any future modifications or incorrect usage could introduce subtle bugs that are difficult to detect and debug, potentially leading to incorrect data parsing or unexpected behavior.
IssueThe `BytesLib` contract utilizes inline assembly (`mload`, `add`, `div`) for byte manipulation and type conversions (e.g., `toAddress`, `toUint8`, `toUint`). While the current implementation appears correct and includes bounds checks (`require(_bytes.length >= (_start + N))`), inline assembly is inherently more complex and error-prone than high-level Solidity. Any future modifications or incorrect usage could introduce subtle bugs that are difficult to detect and debug, potentially leading to incorrect data parsing or unexpected behavior.
FixThoroughly document the assembly logic within `BytesLib` to explain its functionality and assumptions. Consider if `abi.decode` or other high-level Solidity constructs could achieve the same functionality with reduced complexity and improved readability, especially if performance is not a critical bottleneck. Ensure comprehensive unit tests cover all edge cases for these assembly functions.
StatusUnresolved
Low

Presence of safeSelfDestruct in Cloneable Contract

L-02The `Cloneable` base contract includes an `internal` function `safeSelfDestruct`. While it correctly prevents the master copy from being self-destructed via `require(!isMasterCopy, NOT_CLONE);`, the presence of a `selfdestruct` function, even if internal, introduces a powerful capability. If a derived contract were to expose this function externally, or if there was an unforeseen way to call it on a cloned instance, it could lead to the permanent disabling of a token instance. In the current `StandardArbERC20` contract, `safeSelfDestruct` is not called.
IssueThe `Cloneable` base contract includes an `internal` function `safeSelfDestruct`. While it correctly prevents the master copy from being self-destructed via `require(!isMasterCopy, NOT_CLONE);`, the presence of a `selfdestruct` function, even if internal, introduces a powerful capability. If a derived contract were to expose this function externally, or if there was an unforeseen way to call it on a cloned instance, it could lead to the permanent disabling of a token instance. In the current `StandardArbERC20` contract, `safeSelfDestruct` is not called.
FixEnsure that `safeSelfDestruct` is never exposed externally in any derived contract. If this functionality is not intended to be used by the token instances, consider removing the function entirely from the `Cloneable` contract to eliminate any potential for misuse or accidental invocation.
StatusUnresolved
Info

Design Choice for Conditional ERC20 Getters

I-01The `StandardArbERC20` contract implements `decimals()`, `name()`, and `symbol()` functions that conditionally revert based on the `ignoreDecimals`, `ignoreName`, and `ignoreSymbol` flags within the `availableGetters` struct. These flags are set during `bridgeInit` based on the success of parsing the L1 token's metadata. This design allows the token to function even if some metadata is unavailable or malformed, but it means that basic ERC20 getter functions might revert, which could be unexpected for users or integrations expecting standard ERC20 behavior.
IssueThe `StandardArbERC20` contract implements `decimals()`, `name()`, and `symbol()` functions that conditionally revert based on the `ignoreDecimals`, `ignoreName`, and `ignoreSymbol` flags within the `availableGetters` struct. These flags are set during `bridgeInit` based on the success of parsing the L1 token's metadata. This design allows the token to function even if some metadata is unavailable or malformed, but it means that basic ERC20 getter functions might revert, which could be unexpected for users or integrations expecting standard ERC20 behavior.
FixDocument this design choice clearly for users and integrators, explaining that `decimals()`, `name()`, or `symbol()` might revert under certain conditions. Ensure that the `bridgeInit` function is always called with valid and complete metadata by a trusted entity to minimize the chances of these flags being set to `true` in production.
StatusUnresolved

Category Ratings

TechnicalMedium5/10

The contract exhibits a modular architecture (7.1) by inheriting from `L2GatewayToken` and `Cloneable`, and utilizes OpenZeppelin standards for ERC20 functionality, which generally contributes to code security (7.2). However, critical access control flaws (7.3) were identified in the `bridgeInit` function, allowing unauthorized parties to set the L2 gateway or disable ERC20 metadata functions. The `BytesParser` library, while functional, has specific string parsing logic that could lead to unexpected reverts for non-conforming inputs (7.2). Inline assembly in `BytesLib` is used, which increases complexity but appears correct for its current use (7.2).

GovernanceHigh3/10

The economic model (7.4) relies on the `l2Gateway` address for controlling `bridgeMint` and `bridgeBurn` functions, which is a standard and secure approach when properly managed. However, the `bridgeInit` function, which sets this critical `l2Gateway` address, lacks any access control (7.5). This allows any caller to become the L2 gateway, gaining full control over the token's supply and potentially leading to unauthorized minting or burning. This represents a severe governance and economic risk, as the integrity of the token supply is compromised.

UpgradesHigh1/10

The contract is designed as an implementation for a `ClonableBeaconProxy` (7.7), indicating a standard and flexible upgrade mechanism. This pattern allows for efficient upgrades across multiple proxy instances by updating a single beacon contract. However, this also introduces a centralized point of control at the beacon, meaning a compromise of the beacon controller could lead to malicious upgrades affecting all associated token proxies. The `Cloneable` base contract correctly restricts `safeSelfDestruct` to non-master copies, preventing accidental destruction of the implementation.

Security Checklist

Contract VerifiedPass
Ownership Renounced?
No Mint FunctionPass
Liquidity LockedFail
Not a ProxyFail
HoneypotNoneBuy Tax0.0%Sell Tax0.0%

Proxy Upgrade Controls

Proxy TypeBeacon
ImplementationVerified source
Upgrades (30d)0 · stable

Holder Composition

6.2% in wallets48.5% in contracts
Effective Concentration25.6%

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 $1.3K 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 Holder20.2%
Top-3 Unlocked39.0%

Key Addresses

Deployer
0x3fe3…000f
Unlocked LP Held By
0xcad8…d7550x2db7…8a370xf15e…445b0x02b6…c5290x5e93…99f50x2832…9f4c0x9630…20200x38d8…9f3e0x3200…290d0xd84b…44a1

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

What Raised This Score

  • Ownership status UNKNOWN (owner could not be resolved)
  • Proxy contract (upgradeable — admin can replace logic)
  • Complex proxy pattern (BEACON)
  • Top-10 concentration > 20% (54.8% total → 25.6% effective; 6.2% in EOAs, 48.5% in contracts — mild)
  • Liquidity not locked, but no owner/deployer address holds LP — market-depth risk, not rug risk
  • 2 Critical 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

Espresso (ESP)High RiskLivepeer Token (LPT)High RiskOrderly Network (ORDER)High RiskGraph Token (GRT)High RiskCurve DAO Token (CRV)High RiskODYSHigh Risk

Would You Like a More Detailed Audit of Uniswap?

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

Get Detailed Audit