Introduction
We express our gratitude to the RAIN team for the collaborative engagement that enabled the execution of this Smart Contract Security Assessment.
RAIN V2 is a decentralized prediction-market protocol deployed on Arbitrum One, enabling users to create binary-option markets (each subdivided into multiple independent options) and trade outcome shares via either an internal Constant Product Market Maker (CPMM) or a fully on-chain order book, with post-resolution fund distribution and a two-tier AI-plus-oracle dispute system.
Document | |
|---|---|
| Name | Smart Contract Code Review and Security Analysis Report for RAIN |
| Audited By | Ivan Bondar; Atanas Dimulski |
| Approved By | Olesia Bilenka |
| Website | https://www.rain.one→ |
| Changelog | 01/06/2026 - Preliminary Report |
| 05/06/2026 - Final Report | |
| 18/06/2026 - Retest Report | |
| Platform | Arbitrum |
| Language | Solidity |
| Tags | Prediction Market; Automated Market Maker (AMM); Oracle; Factory; Claims |
| Methodology | https://docs.hacken.io/methodologies/smart-contracts→ |
Document
- Name
- Smart Contract Code Review and Security Analysis Report for RAIN
- Audited By
- Ivan Bondar; Atanas Dimulski
- Approved By
- Olesia Bilenka
- Website
- https://www.rain.one→
- Changelog
- 01/06/2026 - Preliminary Report
- 05/06/2026 - Final Report
- 18/06/2026 - Retest Report
- Platform
- Arbitrum
- Language
- Solidity
- Tags
- Prediction Market; Automated Market Maker (AMM); Oracle; Factory; Claims
Review Scope | |
|---|---|
| Repository | https://github.com/rain1-labs/rain-contracts/→ |
| Initial Commit | 6e17125 |
| Final Commit | a91bdb3 |
| Retest Commit | 77eb85c |
Review Scope
- Initial Commit
- 6e17125
- Final Commit
- a91bdb3
- Retest Commit
- 77eb85c
Audit Summary
The system users should acknowledge all the risks summed up in the risks section of the report
Documentation quality
Functional requirements are detailed.
Project overview is detailed
All roles in the system are described.
Use cases are described and detailed.
For each contract, all futures are described.
All interactions are described.
Technical description is detailed.
Run instructions are provided.
Technical specification is provided.
The NatSpec documentation is sufficient.
Code quality
The development environment is configured.
Test coverage
Code coverage of the project is 43.22% (branch coverage).
Deployment and basic user interactions are covered with tests.
Negative cases coverage is partially missed.
Interactions by several users are tested.
System Overview
The protocol is organized around three deployment-time layers. The first layer is RainDeployer, a UUPS-upgradeable singleton that holds all protocol configuration—fee parameters, oracle factory address, platform address, and the implementation addresses of all eleven diamond facets. When a pool creator calls createPool, RainDeployer assembles a FacetCut[] array and delegates to RainDiamondFactory, which deploys a new RainPoolDiamond instance. The deployer then transfers the oracle-fixed-fee and initial liquidity from the creator into the newly deployed pool. Every deployed RainPoolDiamond records RainDeployer as its FACTORY address, granting it the sole authority to invoke diamondCut on the pool.
Each RainPoolDiamond is an EIP-2535 Diamond proxy. Its constructor calls LibDiamond.initializeDiamond to write pool parameters into the shared DiamondStorage struct, then calls LibDiamond.diamondCut to install all eleven facets. Because diamondCut sets isInitialized = true permanently, individual pools are immutable after deployment; only future pools created by the deployer reflect updated facet addresses. All protocol state—AMM reserves, LP shares, order book linked lists, resolution outcomes, dispute records, and fee accumulators—lives in the single DiamondStorage struct managed by LibDiamond.
Trading and resolution are handled by facets that delegate-call into this shared storage. TradingFacet supports two trading models per pool: an AMM phase using constant-product math on per-option YES/NO reserves, and an order-book phase backed by doubly-linked price queues managed by LinkedListLogic. ResolutionFacet allows anyone to finalize an option after its end time by posting a resolver bond; the designated per-option resolver then calls chooseWinner to confirm the outcome. Disputed outcomes trigger DisputeFacet: the initial openDispute call collects a computed dispute fee in base tokens and reassigns the resolver to the protocol's dispute resolver, entering the Disputed state. If the resolution is subsequently contested again, a second openDispute call enters the Appealed state—swapping the resolver-fee share to USDT via LibUtils, calling createOracle on the deployer to provision an external oracle, and commencing a second appeal cycle. Once resolution is complete and the dispute window has elapsed, ClaimFacet distributes payouts and routes fee shares—including a swap-and-burn path for the RAIN token.
Files in Scope
RainDeployer.sol — UUPS-upgradeable protocol coordinator; stores all fee parameters and eleven facet implementation addresses; exposes
createPoolfor permissionless market creation and a suite ofonlyOwnerconfiguration setters; transfers initial liquidity and oracle fees from pool creators; restrictscreateOracleto pools it has deployed.RainDiamondFactory.sol — Thin factory contract; deploys a new RainPoolDiamond with the provided
FacetCut[]array and pool parameters, returning its address to the caller.RainPoolDiamond.sol — EIP-2535 Diamond proxy entry point; constructor applies initial facet cuts via LibDiamond (permanently setting
isInitialized = true); fallback delegates every unknown function selector to the corresponding facet address stored inDiamondStorage.DiamondCutFacet.sol — Exposes the EIP-2535
diamondCutfunction gated to the deployer factory; in practice immutable becauseisInitializedis set during construction.DiamondLoupeFacet.sol — Read-only EIP-2535 loupe implementation; exposes
facets,facetFunctionSelectors,facetAddresses,facetAddress, andsupportsInterface.TradingFacet.sol — Core trading facet; implements AMM-phase
enterOption,enterLiquidity,enterLiquidityBatch, andremoveLiquidityusing constant-product math, and order-book-phaseplaceSellOrderandplaceBuyOrderwith linked-list order matching and fee routing.CancelOrderFacet.sol — Implements
cancelSellOrdersandcancelBuyOrders, allowing order makers to cancel their resting orders in batch; buy-order cancellations refund escrowed base tokens.SplitMergeFacet.sol — Implements
split(collateral → equal YES+NO share accounting, bypassing AMM reserves) andmerge(symmetric YES+NO shares → collateral refund); available during AMM and order-book phases while the option is not finalized.DisputeFacet.sol — Implements permissionless
openDispute, which serves two phases: in the initial dispute phase it collects a computed fee in base tokens and reassigns the per-option resolver to the protocol's dispute resolver; in the appeal phase it additionally swaps the resolver-fee share to USDT via LibUtils and callscreateOracleon the deployer factory to provision an external oracle. Also implementsunlockCallbackfor Uniswap V4PoolManagercallbacks during V4 swap execution.ClaimFacet.sol — Implements permissionless
claim; on the first invocation per option distributes platform fees via swap-and-burn, creator and referrer shares, resolver bond, and dispute fees; on every invocation transfers the caller's proportional payout of LP fees and winning pool share.ResolutionFacet.sol — Manages option lifecycle closure;
closePool(AI path) andclosePoolwith a proposed winner (human path) are permissionless but require a resolver bond from non-owner/resolver callers;chooseWinnerandtooEarlyare restricted to the per-option resolver address.OracleFeeFacet.sol — Exposes a permissionless fee-quote helper (
calculateBaseTokenOracleFixedFee) and a factory-only sweep function (swapOracleFixedFee) that converts the pool's accumulated base-token balance to USDT via LibUtils, transferring the output to the designated platform or oracle-fee recipient.InfoFacet.sol — Read-oriented query façade providing simulated share-entry quotes, LP-return previews, order-book sizing helpers, and dispute-fee and resolver-bond calculators;
getDisputeAppealFeeandgetResolverBondAmountare non-view because they invoke Uniswap quoter contracts.GetterFacet.sol — Pure view getter façade exposing all
DiamondStoragefields: protocol constants, address configuration, AMM reserves, LP state, order-book linked-list metadata, and resolution and dispute records.LibDiamond.sol — Core library defining the
DiamondStoragestruct stored at a deterministic slot; implements pool initialization with parameter validation, the EIP-2535 cut/add/replace/remove mechanics, and all per-option phase and trading-mode guard functions.LibUtils.sol — Swap utility library; implements
swapAndBurn(base token → WETH via the token's configured V2/V3/V4 pool, then WETH → RAIN via Uniswap V3 at the hardcoded router address, thenIRainToken.burnwith a platform-transfer fallback),referrerCreatorClaim(creator-fee split), and Uniswap V2/V3/V4 quoting and swap helpers for base-token ↔ USDT/WETH routing.PathKey.sol — Local copy of the Uniswap V4
PathKeystruct andPathKeyLibrary.getPoolAndSwapDirection; used by LibUtils for V4 multi-hop swap construction.Types.sol — Shared type definitions:
PoolStateenum (NotDisputed, Disputed, Appealed, Refunded) andTradingModelenum (None, AMM, OrderBook).LinkedList.sol —
LinkedListLogiclibrary implementing a doubly-linked list for order-book queues; supports initialize, append, insert, remove, pop-FIFO, and traversal operations.UniswapV2Library.sol — Local copy of Uniswap V2 pair math helpers:
pairFor,getReserves,quote,getAmountOut,getAmountIn,getAmountsOut,getAmountsIn; used by LibUtils for V2 routing.SafeMath.sol — Overflow-safe arithmetic library (
add,sub,mul) used by UniswapV2Library.Constants.sol — File-level constants specifying Arbitrum One addresses: USDT, WETH, RAINTOKEN, Uniswap V4 `POOLMANAGER
,MINSQRTPRICE,MAXSQRTPRICE, andRAINWETHFEE`; referenced throughout LibUtils and DisputeFacet.Globals.sol — Provides the assembly-based
_revert(bytes4 selector)helper used protocol-wide to revert with a four-byte custom-error selector.
Privileged roles
Owner (inherited from OwnableUpgradeable): Holds complete administrative authority over the protocol's configuration and upgrade path.
Can call
setDiamondFactoryto update the factory address used for future pool deployments.Can call
setResolverAIto update the default AI resolver address assigned to new pools.Can call
setOracleFactoryAddressto replace the external oracle factory used for dispute resolution.Can call
setBaseTokento change the default base-token address for new pools.Can call
setOracleFixedFeeto modify the fixed oracle fee charged at pool creation.Can call
setCreatorFeeto adjust the creator fee rate applied to trading activity.Can call
setClosingFeeto adjust the fee deducted at option closure.Can call
setResultResolverFeeto adjust the fee share allocated to result resolvers.Can call
setPlatformAddressto redirect the platform fee recipient.Can call
setLiquidityFeeto modify the fee rate charged on LP operations.Can call
setPlatformFeeto adjust the platform fee share of trading revenue.Can call
setDisputeResolverAIto change the AI address used for dispute resolution.Can call
setNewDiamondCutFacet,setNewDiamondLoupeFacet,setNewDiamondTradingFacet,setNewDiamondResolutionFacet,setNewDiamondDisputeFacet,setNewDiamondClaimFacet,setNewDiamondCancelOrderFacet,setNewDiamondInfoFacet,setNewDiamondGetterFacet,setNewOracleFeeFacet, andsetNewSplitMergeFacetto update the implementation addresses and function selectors for each of the eleven diamond facets used in all future pool deployments.Can call
allowNewTokento whitelist a new ERC-20 token as an accepted pool base token.Can call
disallowExistingTokento remove an ERC-20 token from the accepted base-token list.Can call
_authorizeUpgrade(invoked internally by the UUPS mechanism) to authorize replacement of the RainDeployer proxy implementation with a new logic contract.
Created Pool (runtime check:
createdPools[msg.sender] true): Granted only to RainPoolDiamond instances deployed throughcreatePool.Can call
createOracleto provision an external resolution oracle; the call transfers base tokens from the pool to the deployer and onwards to the oracle factory.
DiamondCutFacet.sol
Factory (runtime check via
LibDiamond.enforceIsFactory:msg.sender ds.FACTORY): Restricted to the RainDeployer address recorded inDiamondStorageat pool initialization.Can call
diamondCutto add, replace, or remove facet function selectors; in practice this path is unreachable for existing pools becauseisInitializedis set totrueduring construction.
CancelOrderFacet.sol
Order Maker (runtime check:
msg.sender order.makerper order): Restricted to the address that placed each individual order.Can call
cancelSellOrdersto cancel one or more of their own resting sell orders, releasing the corresponding share escrow.Can call
cancelBuyOrdersto cancel one or more of their own resting buy orders and receive a refund of the escrowed base tokens.
DisputeFacet.sol
Pool Manager (runtime check:
msg.sender POOL_MANAGER): Restricted to the hardcoded Uniswap V4PoolManageraddress defined inConstants.sol.Can call
unlockCallbackto execute Uniswap V4 swap settlement steps (swap, sync, settle, take) during V4 swap execution initiated by the protocol's fee-routing paths.
ResolutionFacet.sol
Per-option Resolver (runtime check:
msg.sender ds.optionResolver[option]): A per-option address recorded inDiamondStorageat pool initialization; this address is reassigned to the dispute resolver upon a successfulopenDisputecall.Can call
chooseWinnerto designate the winning outcome side for a finalized option, computing the fee split between platform and winning-share pools.Can call
tooEarlyto roll back an option's finalization, transferring the escrowed resolver bond to the calling resolver and, if the option was in a Disputed state, refunding the dispute fee to the original disputer; effectively reopens the option for further resolution attempts.
OracleFeeFacet.sol
Factory (runtime check via
LibDiamond.enforceIsFactory:msg.sender ds.FACTORY): Restricted to the RainDeployer address.Can call
swapOracleFixedFeeto sweep the pool's entire base-token balance and convert it to USDT via LibUtils, transferring the output to the designated platform or oracle-fee recipient.
Potential Risks
Dependency on External Resolution Logic: The claim and dispute flows in ClaimFacet and DisputeFacet invoke IQuestion.winnerFinalized, IQuestion.winnerOption, IQuestion.timeExtended, IQuestion.calculateWinnerReadOnly, IQuestion.getExternalSource, and IQuestion.refund on an oracle question contract provisioned at appeal time. The logic and security guarantees of this external contract are outside the audit scope; unexpected behavior—such as incorrect winner reporting or a revert in refund—could permanently block resolution or misdirect payouts.
System Reliance on External Contracts: Core protocol operations depend on three external systems not in scope: the oracle factory (referenced via oracleFactoryAddress in RainDeployer) is required for appeal-phase oracle provisioning; Uniswap V2/V3/V4 is required for all fee routing, including the swapAndBurn path in LibUtils and the dispute-fee swap in the appeal phase of DisputeFacet; and the RAIN token (IRainToken.burn) is required for fee burning. Unavailability or compromise of any of these systems blocks the corresponding protocol paths.
Interactions with External DeFi Protocols: LibUtils integrates three versions of Uniswap—V2 (via UniswapV2Library and IUniswapV2Router01), V3 (via ISwapRouter at hardcoded address 0xE592427A0AEce92De3Edee1F18E0157C05861564 and IQuoter at 0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6, used for the WETH → RAIN burn path), and V4 (via IPoolManager at the address in Constants.POOL_MANAGER)—for oracle fee conversions, platform fee burns, and dispute fee routing. The security and liveness of these paths inherits from each Uniswap version's own correctness, liquidity availability, and pool existence on Arbitrum One.
Unbounded Array Iteration in Batch Operations: enterLiquidityBatch in TradingFacet iterates over a caller-supplied percentages[] array without an enforced length cap; similarly, cancelSellOrders and cancelBuyOrders in CancelOrderFacet iterate caller-supplied order-ID arrays. Sufficiently large arrays could cause transactions to exceed the transaction gas limit, permanently preventing batch operations from completing.
External Calls Within Order-Matching Loops: The private helpers _executeSellOrder and _executeBuyOrder in TradingFacet iterate over the linked-list order book, executing IERC20.safeTransfer per matched order and optionally calling LibUtils.swapAndBurn and LibUtils.referrerCreatorClaim—both of which contain Uniswap external calls—for each executed trade. As the number of resting orders grows, the cumulative gas cost of a single placeBuyOrder or placeSellOrder call rises proportionally, with the risk of gas exhaustion or prohibitively expensive transactions under active order-book conditions.
Arbitrary Oracle Factory Replacement: The setOracleFactoryAddress function in RainDeployer allows the owner to replace the oracle factory address without any timelock, validation, or bounds check. A malicious or erroneously set address would cause all subsequent appeal-phase openDispute calls—which route resolver-fee shares to the deployer and invoke IOracle.createExternalSource via createOracle—to fail or interact with an unintended contract.
Unrestricted Fee Parameter Modification: The owner of RainDeployer can modify all six fee parameters—oracleFixedFee, creatorFee, closingFee, resultResolverFee, liquidityFee, and platformFee—through dedicated set* functions with no upper-bound enforcement and no timelock. Changes take effect immediately on the next createPool call, allowing fee rates to be set to economically harmful values without advance notice to users.
Absence of Timelock on Critical Operations: All twenty-four-plus onlyOwner functions in RainDeployer—including fee setters, facet address updates, oracle factory replacement, and the UUPS _authorizeUpgrade path—execute immediately upon owner invocation with no mandatory delay. There is no on-chain mechanism that grants users or other stakeholders time to review and react to parameter changes before they take effect.
Insufficient Multi-Signature Controls: The owner role in RainDeployer is controlled by a single address (enforced by OwnableUpgradeable), with no multi-signature or governance contract required for any operation. A single compromised owner key grants unrestricted access to all fee parameters, all facet implementation addresses for future pools, the oracle factory and platform address, and the UUPS upgrade mechanism.
Single Point of Control Over Protocol Configuration: The Owner role in RainDeployer holds sweeping authority over the entire protocol: it can simultaneously alter all fee parameters, replace any of the eleven diamond facet implementations used by future pools, redirect the platform fee destination, change the oracle factory, update the base-token allowlist, and upgrade the deployer contract itself. The safety of the protocol is therefore directly tied to the security of this single private key.
Single Entity Upgrade Authority: The _authorizeUpgrade function in RainDeployer is gated exclusively by onlyOwner, granting the same address that controls fee and configuration parameters the authority to replace the deployer's entire logic contract. No governance vote, multi-signature approval, or timelock delay constrains this upgrade path, meaning a malicious or compromised upgrade could alter the behavior of all future pool deployments without prior notice.
Resolution Dependent on External Oracle Availability: For AI-resolved pools (resolverIsAI = true), the winner determination in ClaimFacet depends on calling IQuestion.winnerFinalized and IQuestion.winnerOption on an externally provisioned question contract. If the oracle service is unavailable, the external question contract fails to finalize, or the IQuestion interface is not implemented correctly by the provisioned contract, the corresponding option cannot progress to its claim phase and user funds remain locked in the pool indefinitely.
Silent Failure on Cross-Chain Deployment or Address Migration: Constants.sol embeds the Arbitrum One addresses for USDT (0xFd086bC7…), WETH (0x82aF49A…), RAINTOKEN, and the Uniswap V4 `POOLMANAGER, while **LibUtils** additionally hardcodes the Uniswap V3 router (0xE592427A…) and quoter (0xb27308f9…) for the WETH → RAIN burn path. If the protocol is deployed to a different network, or if Uniswap redeploys its contracts at new addresses, all fee-routing paths—including swapAndBurn, swapTokensForUSDT, getQuoteOut, getQuoteIn`, and the appeal-phase dispute-fee swap in DisputeFacet—would silently fail or interact with incorrect contracts, potentially locking fee flows or corrupting dispute resolution.
Allowlist Restricted to Standard Non-Hooking ERC-20s: The base-token allowlist managed by allowNewToken and disallowExistingToken in RainDeployer is intended (per protocol team confirmation) to be limited to standard ERC-20 tokens such as USDT, USDC, and DAI; hookable or callback-enabled tokens—ERC-777, ERC-1363, tokens with transfer hooks or pre/post-transfer callbacks, fee-on-transfer tokens, and rebasing tokens—are explicitly out of scope. Trading, liquidity, escrow, and fee-routing flows across TradingFacet, CancelOrderFacet, SplitMergeFacet, ClaimFacet, DisputeFacet, and OracleFeeFacet rely on direct IERC20.safeTransfer and safeTransferFrom calls with no reentrancy guards around the transfer-then-update sequence and assume that the amount transferred equals the amount specified. Whitelisting a hookable, fee-on-transfer, or rebasing token would invalidate these assumptions and could enable reentrancy through ERC-777 tokensReceived callbacks, balance-accounting drift from fee-on-transfer deductions, or share/reserve mismatches from rebases, leading to fund loss or stuck collateral; correctness therefore depends entirely on the Owner of RainDeployer never allowlisting a non-standard token.
Findings
Code ― | Title | Status | Severity | |
|---|---|---|---|---|
| F-2026-1707 | Inverted Arguments in _swapTokenForWETHV2 Bypass RAIN Burn and Block Settlements Across All V2 Non-WETH Markets | fixed | High | |
| F-2026-1753 | Push Transfer to OB Maker Blocks Book on Blacklist | accepted | High | |
| F-2026-1727 | swapAndBurn Catch Drains Pooled Reserves and Strands WETH | fixed | High | |
| F-2026-1715 | enterOption AMM Path Lacks minSharesOut and deadline, Exposing Users to Ordering-Driven Slippage | fixed | Medium | |
| F-2026-1718 | AI-Resolved Pool Funds Lock If chooseWinner Never Called | accepted | Medium | |
| F-2026-1754 | On-chain Quoter Calls in swapAndBurn Cause enterOption to Exhaust Gas on Large OB Orders | fixed | Medium | |
| F-2026-1746 | calculateWinnerReadOnly Return Value Ignored, Permanently Blocking claim | fixed | Medium | |
| F-2026-1739 | Permissionless Pool Creation Allows Blacklisted poolOwner or referrer to Lock All Pool Funds | accepted | Medium | |
| F-2026-1739 | getEntryShares Preview Diverges From enterOption On Multi-Tick Orders | fixed | Medium | |
| F-2026-1739 | Uniswap Reverts in openDispute Trap Pool in Disputed State | accepted | Medium |
Appendix 1. Definitions
Severities
When auditing smart contracts, Hacken is using a risk-based approach that considers Likelihood, Impact, Exploitability and Complexity metrics to evaluate findings and score severities.
Reference on how risk scoring is done is available through the repository in our Github organization:
Severity | Description |
|---|---|
Critical | Critical vulnerabilities are usually straightforward to exploit and can lead to the loss of user funds or contract state manipulation. |
High | High vulnerabilities are usually harder to exploit, requiring specific conditions, or have a more limited scope, but can still lead to the loss of user funds or contract state manipulation. |
Medium | Medium vulnerabilities are usually limited to state manipulations and, in most cases, cannot lead to asset loss. Contradictions and requirements violations. Major deviations from best practices are also in this category. |
Low | Major deviations from best practices or major Gas inefficiency. These issues will not have a significant impact on code execution. |
Severity
- Critical
Description
- Critical vulnerabilities are usually straightforward to exploit and can lead to the loss of user funds or contract state manipulation.
Severity
- High
Description
- High vulnerabilities are usually harder to exploit, requiring specific conditions, or have a more limited scope, but can still lead to the loss of user funds or contract state manipulation.
Severity
- Medium
Description
- Medium vulnerabilities are usually limited to state manipulations and, in most cases, cannot lead to asset loss. Contradictions and requirements violations. Major deviations from best practices are also in this category.
Severity
- Low
Description
- Major deviations from best practices or major Gas inefficiency. These issues will not have a significant impact on code execution.
Potential Risks
The "Potential Risks" section identifies issues that are not direct security vulnerabilities but could still affect the project’s performance, reliability, or user trust. These risks arise from design choices, architectural decisions, or operational practices that, while not immediately exploitable, may lead to problems under certain conditions. Additionally, potential risks can impact the quality of the audit itself, as they may involve external factors or components beyond the scope of the audit, leading to incomplete assessments or oversight of key areas. This section aims to provide a broader perspective on factors that could affect the project's long-term security, functionality, and the comprehensiveness of the audit findings.
Appendix 2. Scope
The scope of the project includes the following smart contracts from the provided repository:
Scope Details | |
|---|---|
| Repository | https://github.com/rain1-labs/rain-contracts/→ |
| Initial Commit | 6e1712556ae6a40fb7bc5e9ae81a018fc836d9b0 |
| Final Commit | a91bdb3e23724759d4160322066bb16f343d578d |
| Retest Commit | 77eb85c01d57e904cbc9d16387d7afc66e477f82 |
| Whitepaper | N/A |
| Requirements | https://github.com/rain1-labs/rain-contracts/blob/audit/hacken/CLAUDE.md→ |
| Technical Requirements | https://github.com/rain1-labs/rain-contracts/blob/audit/hacken/README.md→ |
Scope Details
- Initial Commit
- 6e1712556ae6a40fb7bc5e9ae81a018fc836d9b0
- Final Commit
- a91bdb3e23724759d4160322066bb16f343d578d
- Retest Commit
- 77eb85c01d57e904cbc9d16387d7afc66e477f82
- Whitepaper
- N/A
- Technical Requirements
- https://github.com/rain1-labs/rain-contracts/blob/audit/hacken/README.md→
Assets in Scope
Appendix 3. Additional Valuables
Additional Recommendations
The smart contracts in the scope of this audit could benefit from the introduction of automatic emergency actions for critical activities, such as unauthorized operations like ownership changes or proxy upgrades, as well as unexpected fund manipulations, including large withdrawals or minting events. Adding such mechanisms would enable the protocol to react automatically to unusual activity, ensuring that the contract remains secure and functions as intended.
To improve functionality, these emergency actions could be designed to trigger under specific conditions, such as:
Detecting changes to ownership or critical permissions.
Monitoring large or unexpected transactions and minting events.
Pausing operations when irregularities are identified.
These enhancements would provide an added layer of security, making the contract more robust and better equipped to handle unexpected situations while maintaining smooth operations.
Frameworks and Methodologies
This security assessment was conducted in alignment with recognised penetration testing standards, methodologies and guidelines, including the NIST SP 800-115 – Technical Guide to Information Security Testing and Assessment →, and the Penetration Testing Execution Standard (PTES) →, These assets provide a structured foundation for planning, executing, and documenting technical evaluations such as vulnerability assessments, exploitation activities, and security code reviews. Hacken’s internal penetration testing methodology extends these principles to Web2 and Web3 environments to ensure consistency, repeatability, and verifiable outcomes.