# Oracles, Time and Randomness — Blockchain & Smart Contracts (Solidity)

Source: https://www.geekswithgeeks.com/en/solidity/i-oracles

> Bring off-chain data on chain safely and avoid insecure randomness.

## The oracle problem

Smart contracts cannot fetch web data; every node must compute the same result from on-chain data alone. **Oracles** bring external data, such as asset prices, weather or sports results, on chain. Decentralised oracle networks like **Chainlink** aggregate data from many independent nodes and publish it in **price feeds**; consumers should check that answers are **fresh** (compare `updatedAt` with the current time against a heartbeat) and positive, and handle feed decimals. Using a single **DEX spot price** as an oracle is dangerous: attackers can move it within one transaction using **flash loans** and exploit your contract, a pattern behind many large hacks; use time-weighted averages or robust oracle networks. **Randomness** is equally tricky: `block.timestamp`, `blockhash` and `block.prevrandao` are visible to, or partly influenced by, validators and other contracts, so they are unsafe for valuable lotteries. Use a **verifiable random function** (Chainlink VRF) or **commit-reveal** schemes. **Time**: `block.timestamp` is set by validators within protocol limits and suitable for durations of minutes or more, not precise seconds.

## Reading a price feed defensively

Check freshness, sign and decimals before using an oracle answer.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

interface AggregatorV3Interface {
    function decimals() external view returns (uint8);
    function latestRoundData()
        external
        view
        returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}

contract PriceConsumer {
    AggregatorV3Interface public immutable feed;     // e.g. an ETH/USD feed address for your network
    uint256 public immutable maxDelay;               // e.g. the feed heartbeat plus a margin

    error StalePrice(uint256 updatedAt);
    error InvalidPrice(int256 answer);

    constructor(AggregatorV3Interface feed_, uint256 maxDelay_) {
        feed = feed_;
        maxDelay = maxDelay_;
    }

    /// Returns the price scaled to 18 decimals
    function price18() public view returns (uint256) {
        (, int256 answer, , uint256 updatedAt, ) = feed.latestRoundData();
        if (answer <= 0) revert InvalidPrice(answer);
        if (block.timestamp - updatedAt > maxDelay) revert StalePrice(updatedAt);
        uint8 d = feed.decimals();                   // often 8 for USD feeds
        return d <= 18 ? uint256(answer) * 10 ** (18 - d) : uint256(answer) / 10 ** (d - 18);
    }

    function usdValue(uint256 ethAmountWei) external view returns (uint256) {
        return (ethAmountWei * price18()) / 1e18;     // USD with 18 decimals
    }
}
```

## Never use spot prices from one pool

If your protocol reads a price directly from a single AMM pool, an attacker can borrow a huge amount, distort the pool, call your contract and repay the loan in one transaction. Use robust oracles and sanity limits.

**Quiz:** Why is block.timestamp unsuitable as a source of randomness for a valuable lottery?

- [ ] It is always zero
- [ ] It cannot be read in Solidity
- [x] It is predictable and partly influenced by validators, so outcomes can be manipulated
- [ ] It changes every second

*Answer:* It is predictable and partly influenced by validators, so outcomes can be manipulated. On-chain values are public and influenceable; use VRF or commit-reveal.
