Skip to content

code-423n4/2025-10-reflector

Repository files navigation

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
  • Read our guidelines for more details
  • Starts October 27, 2025 20:00 UTC
  • Ends November 11, 2025 20:00 UTC

❗ Important notes for wardens

  1. 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


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.

File nSLOC
beam-contract/src/cost.rs 71
beam-contract/src/lib.rs 143
oracle/src/assets.rs 145
oracle/src/auth.rs 19
oracle/src/events.rs 32
oracle/src/lib.rs 12
oracle/src/mapping.rs 45
oracle/src/price_oracle.rs 186
oracle/src/prices.rs 251
oracle/src/protocol.rs 37
oracle/src/settings.rs 84
pulse-contract/src/lib.rs 108
oracle/src/timestamps.rs 18
oracle/src/types.rs 50
Totals 1201

For a machine-readable version, see scope.txt

Files out of scope

File
beam-contract/src/tests.rs
oracle/src/tests/**.**
pulse-contract/src/tests/**.**
Totals: 7

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

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.0
  • rustup: 1.28.2
  • cargo: 1.90.0
  • stellar: 23.1.4
  • stellar-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.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages