- Start date27 Oct 2025
- End date11 Nov 2025
- Total awards$20,000 in USDC
- Duration15 days
- Details
Reflector audit details
- Total Prize Pool: $20,000 in USDC
- HM awards: up to $17,280 in USDC
- If no valid Highs or Mediums are found, the HM pool is $0
- QA awards: $720 in USDC
- Judge awards: $1,500 in USDC
- Scout awards: $500 in USDC
- HM awards: up to $17,280 in USDC
- Read our guidelines for more details
- Starts October 27, 2025 20:00 UTC
- Ends November 11, 2025 20:00 UTC
❗ Important notes for wardens
- Judging phase risk adjustments (upgrades/downgrades):
- High- or Medium-risk submissions downgraded by the judge to Low-risk (QA) will be ineligible for awards.
- Upgrading a Low-risk finding from a QA report to a Medium- or High-risk finding is not supported.
- As such, wardens are encouraged to select the appropriate risk level carefully during the submission phase.
Publicly known issues
Anything included in this section is considered a publicly known issue and is therefore ineligible for awards.
Administrator Mistakes
Contract admin can potentially invoke admin-level contract functions with some inconsistent/malformed arguments that may result in an unexpected internal contract state. Such an action would require explicit approval from >50% of Reflector DAO members, and thus cannot simply be done by mistake. As such, the contract code does not employ very strict validation rules in such functions.
Oracle Data Staleness
By design, it's normal to have a situation where an oracle does not have price data for a certain period in the past or reports "stale" data (updated more than 5 minutes ago). Reflector prioritizes safety over liveness. Consumer contracts must always check "timestamp" response field to decide whether the data is fresh enough.
Overview
The Reflector oracle protocol is a combination of specialized smart contracts and peer-to-peer consensus of data provider
nodes maintained by trusted Stellar ecosystem organizations that serve as intermediaries between Stellar smart contracts
and external price feed data sources.
How It Works
Oracle contracts are controlled by the multisig-protected consensus of reputable organizations. The smart contract admin
account always has all node public keys as co-signers with >50% multisig threshold, so more than half of the oracle
backing nodes have to agree on a transaction in order to store price feed data or modify the contract state.
Each node independently calculates values of quoted prices using deterministic idempotent algorithms to ensure
consistency, generates an update transaction, signs it with node's private key, and then shares it with other peers via
WebSocket protocol. If for some reason (ledger access delay, failing connection, version incompatibility, adversary
attack) any given node quotes a token/asset price different from other nodes, the transaction hash will not match the
hash generated by the majority and such transaction will be discarded by the ledger. This way Reflector utilizes Stellar
protocol underlying security to implement an uncomplicated yet robust consensus, which guarantees reliability, fault
tolerance and regular price feed updates.
For on-chain Stellar assets price feed data retrieval Reflector relies on a quorum of nodes connected to Stellar RPC
nodes. Each node independently fetches trades and state information from the Stellar ledger. Price feeds for generic
tokens get updated in a similar fashion, but nodes have to agree on the data pulled from external sources (CEX/DEX API,
banks, forex venues, price aggregators, stock exchanges, derivative platforms, etc.) All historical price feed data is
stored in the oracle contract and becomes immutable once it is written to the contract storage.
Reflector offers two data access models for Stellar on-chain oracles:
- ReflectorPulse oracles with a uniform 5 minutes update interval provide free access to published price feeds
- ReflectorBeam oracles allow flexible oracle provisioning and feature faster price updates in return for a small
XRF invocation fee
Both contract implementation are compatible with
SEP-40 ecosystem standard.
Check the standard for general info and public consumer interface documentation.
Cluster nodes report price feeds for all assets denominated in the base asset of the contract using the uniform
precision specified in decimals(). Prices get encoded as i128 numbers where last N digits designate the fractional
part of the given oracle feed. So the actual price can be calculated as price/10^decimals.
An oracle feed receives regular updates with a pre-defined resolution. Timestamps from trades and other price sources
are normalized as floor(unix_now()/resolution)*resolution during the aggregation phase. It is important for consumer
contracts to check the timestamp field of the returned values against the current ledger timestamp to make sure that
reported quotes are not stale.
Other contracts interact with oracle contracts, retrieving data stored earlier by Reflector consensus.
Consumers can fetch historical ranges, use cross-price calculation, utilize TWAP averaging, or simply pull the most
recent token price depending on the use-case.
Links
- Previous audits:
- Documentation: https://github.com/reflector-network/reflector-contract/tree/v3
- Website: https://reflector.network/
- X/Twitter: https://x.com/in_reflector
Scope
Files in scope
Note: The nSLoC counts in the following table have been automatically generated and may differ depending on the definition of what a "significant" line of code represents. As such, they should be considered indicative rather than absolute representations of the lines involved in each contract.
For a machine-readable version, see scope.txt
Files out of scope
For a machine-readable version, see out_of_scope.txt
Additional context
Areas of concern (where to focus for bugs)
- Data caching system for the last several rounds
- Protocol upgrade transition (v1 stored data in individual temporary entries with the <asset,timestamp> key, v2 protocol stores all updates with the same timestamp in a single entry)
- Bit masks that store information whether a certain feed has been updated at a given period in the past
Main invariants
General
- ReflectorPulse contract follows SEP-40 standard (https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0040.md), ReflectorBeam contract extends it with invocation sponsor
- All public functions never panic, and the ReflectorBeam may panic only if the invocation commission charge fails
Administrative
- Only admin account can change contract settings, upgrade it, and publish prices
- The admin account always has all cluster public keys as co-signers with >50% multisig threshold, meaning that any crucial state change requires DAO majority
Configurational
- A contract instance can only be initialized once
- Oracle base asset, decimals, and timeframe can never be changed after initialization
- Each asset is unique, and can be added only once
- Each oracle contract can support up to 256 assets and retain up to 256 historical update records
Price Feed Expiration Management
- Each price feed (quoted asset) has an expiration time; it stops receiving updates from the Reflector cluster after the expiration
- Anyone can bump a price feed's expiration time, paying for it with XRF tokens
- Update timestamp can never be greater than current ledger timestamp
Price Feed Data
- Every price update emits a corresponding event
- Price updates older than 256 periods can't be accessed through the contract, but can be loaded from the indexer by fetching update events
- An oracle contract may have no price data for a certain period in the past or report "stale" data (updated more than 1 period ago) if there were no price movements during that time or cluster nodes failed to reach quorum
- ReflectorBeam oracle caller address must have sufficient balance to pay for the invocation
All trusted roles in the protocol
admin Account
This account has permission to publish updates, change configurations, and upgrade the contracts. Always represented by an M-of-N configured multisig (signers - Reflector DAO members) with >50% of signers required to execute any action.
Running tests
Prerequisites
The codebase is composed of smart contracts written in Rust around the Stellar framework. As such, the following toolkits must be installed before attempting to compile the codebase:
The codebase was successfully compiled with the following tool versions:
rustc: 1.90.0rustup: 1.28.2cargo: 1.90.0stellar: 23.1.4stellar-xdr: 23.0.0
Compilation
Before we compile our contracts, we need to add the following rustup target if it is missing from our machine:
rustup target add wasm32v1-none
Afterward, the following Stellar CLI command can be run to build the contracts:
stellar contract build
Testing
Tests must be run through the cargo toolkit instead of the stellar CLI and are executed as follows:
cargo test
Miscellaneous
Employees of Reflector and Stellar Development Foundation and employees' family members are ineligible to participate in this audit.
Code4rena's rules cannot be overridden by the contents of this README. In case of doubt, please check with C4 staff.