Quantum Audit Logo
Launch App

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

Is RAIN Safe?

Arbitrum
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 · 2 audits on record
SummaryAI Copilot

The audit of the Rain Token (implementation Rain) reveals significant architectural and design concerns.

Read the full analysis
What raised the score
  • Ownership not renounced — Multisig
  • Proxy contract
  • Top-10 concentration > 30%
  • 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%
  • 2 Critical finding(s) from audit
  • 1 Medium finding(s) from audit
  • 2 Low finding(s) from audit
Exact factors
  • Ownership NOT renounced — Multisig (2-of-4)
  • Proxy contract (upgradeable — admin can replace logic)
  • Top-10 concentration > 30% (86.2% total → 36.1% effective; 2.7% in EOAs, 83.6% in contracts — moderate)
  • 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, pool = 59% of DEX liquidity)
  • LP top3 unlocked holders = 100.0% (independent LP — depth risk, pool = 59% of DEX liquidity)
  • 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

Security Checklist

as of audit · Sep 42 of 5 checks passed
Contract verifiedVerified
OwnershipRetained
MintNo mint
Liquidity lockNot locked
UpgradeabilityUpgradeable

Holders

as of audit · Sep 4, 2026
83.6%Contracts2.7%13.8%Everyone else
83.6%Contracts13.8%Everyone else
ContractsWalletsEveryone elseBubble area = share of supply
86.2%of supply sits with the top 10 holders
  • Contractstreasury, vesting, bridge, staking83.6%
  • Walletsanonymous holders, free to sell2.7%
  • Everyone elsethe rest of the supply13.8%
Effective concentrationwhat the score reads36.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 4$2.80M across 3 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$1.66MShare of depth59.1%
Top-1 Unlocked Holder100.0%
Top-3 Unlocked100.0%
Unlocked LP held by
0x7706…53aa0x0963…3df6

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

Security Findings

2 Critical1 Medium2 Low2 Info
Critical

Architectural Flaw: Missing Chained Initialization Function

The Rain contract, despite inheriting from multiple OpenZeppelin upgradeable contracts (ERC20Upgradeable, Ownable2StepUpgradeable, etc.), lacks a primary initialize() function that explicitly calls the __<ContractName>_init() functions of its base contracts. While external deployment scripts might have called these _init functions directly on the proxy, the absence of this chained initialization in the contract's source code is an architectural flaw. It makes the contract's initialization process opaque, harder to audit, and prone to errors if not handled perfectly by external tooling. The initialize2() function, marked as a reinitializer(2), further complicates this, as it impl…C-01

Issue

The Rain contract, despite inheriting from multiple OpenZeppelin upgradeable contracts (ERC20Upgradeable, Ownable2StepUpgradeable, etc.), lacks a primary initialize() function that explicitly calls the __<ContractName>_init() functions of its base contracts. While external deployment scripts might have called these _init functions directly on the proxy, the absence of this chained initialization in the contract's source code is an architectural flaw. It makes the contract's initialization process opaque, harder to audit, and prone to errors if not handled perfectly by external tooling. The initialize2() function, marked as a reinitializer(2), further complicates this, as it impl…

Fix

Implement a comprehensive initialize() function in the Rain contract that explicitly calls all necessary __<ContractName>_init() functions from its inherited OpenZeppelin base contracts. Ensure proper chaining and versioning of initializers, and consider moving initialize2's logic into the primary initialize if it's intended for initial setup.

Status

Unresolved

Critical

Misleading/Unused Inflation Mechanism

The contract defines several state variables (DAILY_INFLATION_USD, oraclePriceFeed, deploymentTimestamp, LOCKUP_PERIOD) and custom errors (MintingNotAllowedYet, InvalidPrice, OraclePriceFeedNotSet) that strongly suggest a USD-pegged, time-locked inflation mechanism. However, the dailyMinting function, which is the sole minting mechanism, does not utilize any of this logic. Instead, it mints a fixed percentage (10%) of dailyBurned tokens. This significant discrepancy between declared intent/variables and actual implementation is highly misleading, indicates incomplete development or a major design change, and could lead to incorrect assumptions about the token's economic mo…C-02

Issue

The contract defines several state variables (DAILY_INFLATION_USD, oraclePriceFeed, deploymentTimestamp, LOCKUP_PERIOD) and custom errors (MintingNotAllowedYet, InvalidPrice, OraclePriceFeedNotSet) that strongly suggest a USD-pegged, time-locked inflation mechanism. However, the dailyMinting function, which is the sole minting mechanism, does not utilize any of this logic. Instead, it mints a fixed percentage (10%) of dailyBurned tokens. This significant discrepancy between declared intent/variables and actual implementation is highly misleading, indicates incomplete development or a major design change, and could lead to incorrect assumptions about the token's economic mo…

Fix

Either fully implement the USD-pegged inflation mechanism using the declared variables and oracle, or remove all unused variables, errors, and comments related to it. Ensure the contract's code accurately reflects its intended economic model to avoid confusion and potential misinterpretations by users or integrators.

Status

Unresolved

Medium

Hardcoded Initial Burned Values in initialize2

The initialize2 function directly assigns large, specific values to lifetimeBurned and dailyBurned. While this might be intended for a specific initial state or migration, hardcoding such values in an initialization function reduces flexibility and makes the contract brittle. If the contract were to be redeployed or initialized under different circumstances, these hardcoded values might be inappropriate, leading to unexpected or incorrect minting behavior. (7.2 Code Security, 7.4 Economic, 7.8 Operations)M-01

Issue

The initialize2 function directly assigns large, specific values to lifetimeBurned and dailyBurned. While this might be intended for a specific initial state or migration, hardcoding such values in an initialization function reduces flexibility and makes the contract brittle. If the contract were to be redeployed or initialized under different circumstances, these hardcoded values might be inappropriate, leading to unexpected or incorrect minting behavior. (7.2 Code Security, 7.4 Economic, 7.8 Operations)

Fix

Consider making the initial values for lifetimeBurned and dailyBurned configurable parameters during initialization, or derive them dynamically based on the contract's actual state or a trusted external source. This improves flexibility and reduces the risk of incorrect initial states.

Status

Unresolved

Low

Unused INITIAL_SUPPLY Constant

The contract defines INITIAL_SUPPLY as a public constant with a value of 1_150_000_000_000 * WEI. However, there is no corresponding _mint call in any initialization function to actually create and distribute this initial supply. Without an explicit minting operation, the token will have a total supply of zero upon deployment (assuming the critical initialization flaw is fixed), rendering the INITIAL_SUPPLY constant effectively unused and misleading. (7.1 Architecture, 7.4 Economic)L-01

Issue

The contract defines INITIAL_SUPPLY as a public constant with a value of 1_150_000_000_000 * WEI. However, there is no corresponding _mint call in any initialization function to actually create and distribute this initial supply. Without an explicit minting operation, the token will have a total supply of zero upon deployment (assuming the critical initialization flaw is fixed), rendering the INITIAL_SUPPLY constant effectively unused and misleading. (7.1 Architecture, 7.4 Economic)

Fix

If an initial supply is intended, ensure that the initialize() function (or an appropriate setup function) includes a call to _mint(recipient, INITIAL_SUPPLY) to create and distribute the tokens. Otherwise, remove the INITIAL_SUPPLY constant if it is not meant to be used.

Status

Unresolved

Low

UUPS Upgrades Explicitly Disabled

The _authorizeUpgrade function, which is part of the UUPSUpgradeable pattern, is explicitly overridden to revert("UUPS upgrades disabled"). While this clearly signals immutability and prevents unauthorized upgrades, it contradicts the use of the UUPSUpgradeable base contract, which is designed for upgradeability. If future protocol changes require contract logic updates, a full redeployment of the token would be necessary, incurring significant operational overhead and potentially disrupting integrations. (7.7 Upgrades, 7.8 Operations)L-02

Issue

The _authorizeUpgrade function, which is part of the UUPSUpgradeable pattern, is explicitly overridden to revert("UUPS upgrades disabled"). While this clearly signals immutability and prevents unauthorized upgrades, it contradicts the use of the UUPSUpgradeable base contract, which is designed for upgradeability. If future protocol changes require contract logic updates, a full redeployment of the token would be necessary, incurring significant operational overhead and potentially disrupting integrations. (7.7 Upgrades, 7.8 Operations)

Fix

Confirm that the decision to disable upgrades is intentional and understood by all stakeholders. If future upgradeability is a possibility, reconsider this override. If immutability is the goal, ensure this is clearly documented and communicated to users and integrators.

Status

Unresolved

Info

Unused PriceFeed Interface and Related Logic

The PriceFeed interface is imported, and an oraclePriceFeed state variable is declared, along with a PriceFeedSet event. However, the oraclePriceFeed variable is never set (no setPriceFeed function) and its getPrice() method is never called within the contract's logic. This indicates dead code or an incomplete feature related to an external price oracle. (7.1 Architecture, 7.2 Code Security)I-01

Issue

The PriceFeed interface is imported, and an oraclePriceFeed state variable is declared, along with a PriceFeedSet event. However, the oraclePriceFeed variable is never set (no setPriceFeed function) and its getPrice() method is never called within the contract's logic. This indicates dead code or an incomplete feature related to an external price oracle. (7.1 Architecture, 7.2 Code Security)

Fix

Remove the unused PriceFeed interface, oraclePriceFeed variable, and related event/errors if the feature is not intended for implementation. If it is a planned feature, ensure it is fully implemented, including a function to set the oracle address and integrate its price data into relevant logic.

Status

Unresolved

Info

constructor calls _disableInitializers() but initialize2 is reinitializer(2)

The constructor correctly calls _disableInitializers() for upgradeable contracts. However, the initialize2 function is marked as reinitializer(2). This implies that an initialize function (version 1) should have been called first. Given the critical initialization flaw (C-01) where the primary initialize is missing, the versioning for initialize2 is either incorrectly applied or part of the larger initialization issue. (7.1 Architecture, 7.2 Code Security)I-02

Issue

The constructor correctly calls _disableInitializers() for upgradeable contracts. However, the initialize2 function is marked as reinitializer(2). This implies that an initialize function (version 1) should have been called first. Given the critical initialization flaw (C-01) where the primary initialize is missing, the versioning for initialize2 is either incorrectly applied or part of the larger initialization issue. (7.1 Architecture, 7.2 Code Security)

Fix

Ensure that the initialization versioning is correctly implemented. If initialize2 is intended as the first or only initialization, adjust its modifier accordingly (e.g., initializer). If it is truly a reinitializer, ensure that initialize (version 1) is properly defined and called first.

Status

Unresolved

Analysis

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

The audit of the Rain Token (implementation Rain) reveals significant architectural and design concerns. A critical initialization flaw means the contract's core functionalities (ERC20, ownership) are not explicitly initialized within the provided source code, relying on opaque external calls. Furthermore, the contract includes extensive unused variables and errors suggesting a USD-pegged inflation mechanism, which is entirely absent from the actual dailyMinting logic, leading to a misleading economic model. Other findings include hardcoded initial values, an unused initial supply constant, and explicitly disabled UUPS upgrades.

Technical5/10Medium risk

The technical architecture leverages OpenZeppelin's upgradeable contracts, including ERC20, Ownable2Step, and UUPS. However, a critical architectural flaw exists where the contract lacks a primary initialize() function to properly chain the initialization of these base contracts (7.1 Architecture, 7.2 Code Security). This makes the contract's operational state dependent on external, non-auditable setup. The dailyMinting function is properly access-controlled by onlyOwner and includes a MINT_COOLDOWN_PERIOD (7.3 Access Control). UUPS upgrades are explicitly disabled, providing immutability but limiting future flexibility (7.7 Upgrades).

Governance2/10High risk

The economic model for token minting is based on a percentage of burned tokens, controlled by the owner (7.4 Economic). However, the contract contains extensive declarations for a USD-pegged inflation mechanism with an oracle and lockup periods, which are entirely unused in the dailyMinting logic. This discrepancy is highly misleading and creates ambiguity regarding the token's intended economic behavior (7.4 Economic). Initial burned values are hardcoded in initialize2, which could lead to unexpected behavior if not carefully managed (7.8 Operations). The owner is a 2/4 multisig, providing a degree of decentralized control over critical functions like dailyMinting and updateTreasury (7.5 Governance).

Upgrades1/10High risk

The contract utilizes the UUPSUpgradeable pattern but explicitly disables upgrades by reverting in _authorizeUpgrade (7.7 Upgrades). This design choice ensures immutability of the contract logic, preventing any future on-chain upgrades. While this provides a clear and immutable state, it means any future protocol changes requiring contract modifications would necessitate a full redeployment, incurring significant operational overhead and potential disruption to integrations (7.8 Operations). The initialize2 function is a reinitializer(2), implying a versioning strategy that is not fully supported by the contract's missing primary initialize function.

Final RecommendationWhat to do about this score

Address the critical initialization flaw by implementing a comprehensive initialize() function that properly chains all inherited OpenZeppelin _init() functions.

Clarify and align the contract's economic model by either implementing the USD-pegged inflation logic or removing the unused variables and comments to prevent misleading expectations. Review the hardcoded initial burned values and consider making them configurable or derived dynamically for better flexibility and robustness.

Contract & Record

2 audits on record
TypeERC1967Proxy
NetworkArbitrum
Token age1mo
Contract0x2511…099d
Deployer0xbd80…c331
Proxy Upgrade Controls
Proxy TypeEip1967 Uups
ImplementationVerified source
Upgrades (30d)0 · stable
Badge for your website
RAIN 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, 202643Medium
  2. Jul 27, 202640Medium
  3. Jul 27, 202666High

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

Frequently Asked Questions

Is RAIN a scam?

Based on automated analysis, RAIN scores 66/100 (High Risk) on our risk scale. No honeypot was detected, but always verify independently before investing.

Is RAIN safe to buy?

Our scanner flagged a risk score of 66/100. Ownership has not been renounced, which is a risk factor. DYOR before purchasing any token.

Has RAIN been audited?

The contract has not been verified on-chain. Verification is not the same as a full security audit. Use Quantum Audit's free tool to run a deeper analysis of the contract code.

Would You Like a More Detailed Audit of RAIN?

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