> For the complete documentation index, see [llms.txt](https://docs.chiliz.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.chiliz.com/ko/gaebal/goseup/on-chain-gaseukaemul-pidi/gagyeok-ilggi.md).

# 가격 읽기

## 1단계: 오라클 주소 찾기

주어진 쌍의 `PriceFeed` 컨트랙트 주소를 찾는 세 가지 방법:

* **Price Oracle Tracker** (개발 중 가장 간편): [price-oracle-tracker.vercel.app](https://price-oracle-tracker.vercel.app/?network=mainnet) — 배포된 모든 쌍, 실시간 가격, decimals, heartbeat, 주소를 표시합니다.
* **OracleFactory를 통한 온체인 조회**: `pairToOracle(string pair)` 호출. 쌍 심볼은 대문자로 전달해야 합니다(예: `"PSG/USDT"`) — 팩토리는 읽기 시 입력값을 정규화하지 않습니다.
* **OracleFactoryReader를 통한 대량 온체인 조회**: `getActiveOracles()`를 호출하여 모든 활성 쌍과 해당 주소를 한 번에 조회합니다.

```solidity
interface IOracleFactory {
    function pairToOracle(string memory pair) external view returns (address);
    function getOracleCount() external view returns (uint256);
}

function resolveFeed(address factory, string memory pair)
    external view returns (address)
{
    // Pair symbol must be passed in uppercase (e.g. "PSG/USDT").
    return IOracleFactory(factory).pairToOracle(pair);
}
```

## 2단계: 인터페이스로 연결하기

`PriceFeed` 컨트랙트는 표준 Chainlink `IAggregatorV3Interface`와 함께 상태 및 일시 정지 상태를 위한 Chiliz 전용 확장을 구현합니다.

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

interface IAggregatorV3Interface {
    function decimals() external view returns (uint8);
    function description() external view returns (string memory);
    function version() external view returns (uint256);

    function getRoundData(uint80 _roundId)
        external view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        );

    function latestRoundData()
        external view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        );
}

interface IChilizPriceFeed is IAggregatorV3Interface {
    function paused() external view returns (bool);
    function updateInterval() external view returns (uint256);
    function healthFactor() external view returns (uint80);
    function getHealthStatus()
        external view
        returns (
            uint256 lastUpdateTimestamp,
            uint256 totalRounds,
            uint256 timeSinceLastUpdate,
            bool isHealthy
        );
}
```

## 3단계: 가격 읽기

{% hint style="warning" %}
**피드는 오래되거나 일시 정지된 상태에서 revert하지 않습니다 — 이는 의도된 동작입니다.** `latestRoundData()`는 아직 round가 존재하지 않을 경우 `NoDataAvailable()`로 revert하지만, 피드가 일시 정지되었거나 오래된 상태인지 확인하지 않습니다. 이는 Chainlink AggregatorV3Interface 설계와 일치합니다: 소비자는 가격을 사용하기 전에 `paused()`와 `getHealthStatus()`를 확인할 책임이 있습니다. 참고: 스칼라 헬퍼(`latestAnswer()`, `latestTimestamp()`, `getAnswer()`, `getTimestamp()`)는 데이터가 없을 때 revert하는 대신 `0`을 반환합니다. 전체 검증 패턴은 [모범 사례](/ko/gaebal/goseup/on-chain-gaseukaemul-pidi/choeuseon-silmu.md)를 참고하세요.
{% endhint %}

기본 함수는 `latestRoundData()`로, 현재 가격을 round 및 타임스탬프 메타데이터와 함께 반환합니다.

```solidity
contract LendingOracleConsumer {
    IChilizPriceFeed public priceFeed;

    constructor(address _feed) {
        priceFeed = IChilizPriceFeed(_feed);
    }

    function getSafePrice() public view returns (uint256 price18) {
        // 1. Check feed is not paused
        require(!priceFeed.paused(), "Feed paused");

        // 2. Read latest data (reverts with NoDataAvailable() if no rounds exist)
        (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        ) = priceFeed.latestRoundData();

        // 3. Basic sanity checks
        require(answer > 0, "Invalid price");

        // 4. Optional: use explicit health check for staleness
        (, , , bool isHealthy) = priceFeed.getHealthStatus();
        require(isHealthy, "Stale price");

        // 5. Normalize to 18 decimals for internal math
        uint8 decimals_ = priceFeed.decimals();
        uint256 scale = 10 ** uint256(decimals_);
        price18 = uint256(answer) * 1e18 / scale; // This is the actual price of an asset
    }
}
```

프로토콜이 18 decimals로 정규화하지 않고 피드의 기본 decimals를 사용하는 경우:

```solidity
function getRawPriceWithMeta()
    external view
    returns (int256 price, uint8 decimals_, uint256 updatedAt)
{
    require(!priceFeed.paused(), "Feed paused");

    (, int256 answer, , uint256 _updatedAt, ) =
        priceFeed.latestRoundData();
    require(answer > 0, "Invalid price");

    (, , , bool isHealthy) = priceFeed.getHealthStatus();
    require(isHealthy, "Stale price");

    decimals_ = priceFeed.decimals();
    price = answer;
    updatedAt = _updatedAt;
}
```

## 과거 데이터

오라클은 모든 과거 round 데이터를 온체인에 저장합니다. 각 가격 업데이트는 증가하는 `roundId`와 함께 새로운 round를 생성합니다.

```solidity
(uint80 roundId, int256 answer, , uint256 updatedAt, ) =
    priceFeed.getRoundData(targetRoundId);
```

Chiliz 피드가 제공하는 추가 헬퍼 뷰:

| 함수                                 | 반환값                      |
| ---------------------------------- | ------------------------ |
| `latestAnswer()`                   | 최신 가격, 없으면 `0`           |
| `latestTimestamp()`                | 최신 `updatedAt`, 없으면 `0`  |
| `latestRound()`                    | 현재 round ID              |
| `getAnswer(uint80 roundId)`        | 특정 round의 가격, 없으면 `0`    |
| `getTimestamp(uint80 roundId)`     | 특정 round의 타임스탬프, 없으면 `0` |
| `getRoundsData(uint80[] roundIds)` | 대량 `RoundData` 배열        |
| `roundExists(uint80 roundId)`      | `updatedAt > 0`이면 `true` |

## 이벤트

각 `PriceFeed` 컨트랙트는 다음을 emit합니다:

* **`AnswerUpdated(int256 indexed current, uint80 indexed roundId, uint256 updatedAt)`**: 모든 가격 업데이트 시 emit됩니다. 가격 또는 round로 필터링할 수 있습니다.
* **`NewRound(uint80 indexed roundId, address indexed startedBy, uint256 startedAt)`**: 새 round 시작 시 emit됩니다. round 또는 시작한 주소로 필터링할 수 있습니다.

## 검색 함수 (OracleFactoryReader)

| 함수                                      | 설명                              |
| --------------------------------------- | ------------------------------- |
| `getActiveOracles()`                    | 모든 활성 쌍과 오라클 주소를 반환합니다          |
| `getAllOracles()`                       | 비활성 오라클을 포함한 모든 오라클을 반환합니다      |
| `getOraclesByPairs(string[] pairs)`     | 여러 쌍 이름을 한 번의 호출로 오라클 주소로 변환합니다 |
| `getOracleHealthStatus(address oracle)` | 단일 오라클의 상태를 반환합니다               |
| `getAllOracleHealthStatus()`            | 시스템의 모든 오라클 상태를 반환합니다           |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.chiliz.com/ko/gaebal/goseup/on-chain-gaseukaemul-pidi/gagyeok-ilggi.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
