Integating Canary Nest Oracle (PUSH Based)

PriceOracle Technical Specification

Overview

The PriceOracle contract is a Chainlink-compatible price oracle implementation that provides secure price data management with built-in deviation controls and curator oversight. It implements the AggregatorV3Interface standard while adding additional security mechanisms for price validation and approval workflows.

Contract Information

  • License: MIT

  • Solidity Version: 0.8.25

  • Contract Type: Upgradeable proxy pattern

  • Version: 1

Architecture

Inheritance Structure

PriceOracle
β”œβ”€β”€ AggregatorV3Interface (Chainlink standard)
β”œβ”€β”€ Initializable (OpenZeppelin upgradeable)
└── AccessControlEnumerableUpgradeable (OpenZeppelin role-based access)

Access Control Roles

Role
Constant
Responsibilities

Default Admin

DEFAULT_ADMIN_ROLE

Manages other roles, overall contract administration

Curator

CURATOR_ROLE

Approves/rejects pending prices, configures parameters

Updater

UPDATER_ROLE

Submits new price data

Data Structures

RoundData

Stores confirmed price round information:

PendingRoundData

Stores price data awaiting curator approval:

State Variables

Variable
Type
Description

VERSION

uint8

Contract version (constant: 1)

pendingRoundData

PendingRoundData

Current pending price data

s_description

string

Oracle description

s_decimals

uint8

Price decimal places

rounds

mapping(uint80 => RoundData)

Historical round data

latestRoundId

uint80

Most recent round identifier

maxPriceDeviation

uint256

Maximum allowed price change

timestampBuffer

uint256

Timestamp validation buffer (ms)

Core Functions

Initialisation

initialize(address defaultAdmin, address curator, address updater, uint256 _maxPriceDeviation, uint256 _timestampBuffer, uint8 _decimals, string memory _description)

Initialises the upgradeable contract with initial parameters and role assignments.

Parameters:

  • defaultAdmin: Address receiving admin privileges

  • curator: Address receiving curator privileges

  • updater: Address receiving updater privileges

  • _maxPriceDeviation: Maximum allowed price deviation between rounds

  • _timestampBuffer: Timestamp validation buffer in milliseconds

  • _decimals: Number of decimal places for prices

  • _description: Human-readable oracle description

Requirements:

  • All addresses must be non-zero

  • Description must be non-empty

  • Decimals must be greater than zero

Price Management

addRoundData(uint256 recordedOffchainAt, int192 price, bytes32 sourceHash)

Submits new price data for validation and storage.

Access Control: UPDATER_ROLE

Parameters:

  • recordedOffchainAt: Offchain recording timestamp (milliseconds)

  • price: Price value (must be non-zero)

  • sourceHash: Source identification hash (must be non-zero)

Validation Rules:

  • Price must be non-zero

  • Source hash must be non-zero

  • No pending price data can exist

  • Timestamp must not be too far in the future (respects timestampBuffer)

  • Timestamp must be newer than the latest round

  • Price deviation from last round determines approval workflow

Behavior:

  • If price deviation ≀ maxPriceDeviation: Automatically approved and stored

  • If price deviation > maxPriceDeviation: Stored as pending, requires curator approval

resolvePendingPrice(bool isApproved)

Curator function to approve or reject pending price data.

Access Control: CURATOR_ROLE

Parameters:

  • isApproved: true to approve and store the pending price, false to reject

Requirements:

  • Pending price data must exist

Behavior:

  • If approved: Moves pending data to confirmed rounds

  • Always clears pending data regardless of approval decision

Configuration Management

setMaxPriceDeviation(uint256 _maxPriceDeviation)

Updates the maximum allowed price deviation threshold.

Access Control: CURATOR_ROLE

Parameters:

  • _maxPriceDeviation: New deviation threshold (must be non-zero and different from current)

setTimestampBuffer(uint256 _timestampBuffer)

Updates the timestamp validation buffer.

Access Control: CURATOR_ROLE

Parameters:

  • _timestampBuffer: New buffer duration in milliseconds (can be zero)

decimals() β†’ uint8

Returns the number of decimal places in price values.

description() β†’ string

Returns the human-readable oracle description.

version() β†’ uint256

Returns the contract version number.

getRoundData(uint80 _roundId) β†’ (uint80, int256, uint256, uint256, uint80)

Retrieves historical round data by round ID.

Returns:

  • roundId: The requested round ID

  • answer: Price value (converted to int256)

  • startedAt: Offchain recording timestamp

  • updatedAt: Onchain recording timestamp

  • answeredInRound: Same as roundId

Requirements:

  • Round ID must be valid (1 ≀ roundId ≀ latestRoundId)

latestRoundData() β†’ (uint80, int256, uint256, uint256, uint80)

Retrieves the most recent round data.

Returns: Same format as getRoundData

Requirements:

  • At least one round must exist

Events

RoundDataAdded(uint80 indexed roundId, uint256 recordedOffchainAt, uint256 recordedOnchainAt, int192 price, bytes32 indexed sourceHash)

Emitted when price data is confirmed and stored.

PendingRoundDataAdded(uint256 recordedOffchainAt, uint256 recordedOnchainAt, int192 pendingPrice, bytes32 indexed sourceHash)

Emitted when price data requires curator approval.

SetMaxPriceDeviation(uint256 oldMaxPriceDeviation, uint256 newMaxPriceDeviation)

Emitted when price deviation threshold is updated.

SetTimestampBuffer(uint256 oldTimestampBuffer, uint256 newTimestampBuffer)

Emitted when timestamp buffer is updated.

Error Conditions

Error
Trigger Condition

ZeroAddress()

Zero address provided in initialization

CantGeneratePrice()

No rounds available for latest data query

InvalidRoundId(uint80)

Round ID is zero or exceeds latest round

TimestampInvalid()

Timestamp validation failures

InvalidMaxPriceDeviation()

Invalid price deviation parameter

InvalidDescription()

Empty description in initialization

PriceZero()

Zero price value submitted

PriceNotPending()

No pending price to resolve

PriceAlreadyPending()

Attempting to add price when one is pending

InvalidDecimals()

Zero decimals in initialization

InvalidTimestampBuffer()

Invalid timestamp buffer parameter

InvalidSourceHash()

Zero source hash provided

Security Considerations

Price Validation

  1. Deviation Control: Prices exceeding maxPriceDeviation require curator approval

  2. Timestamp Validation: Prevents future timestamps and ensures chronological ordering

  3. Source Tracking: Each price includes a source hash for accountability

Access Control

  1. Role Separation: Clear separation between data submission and approval

  2. Upgradeable Pattern: Uses OpenZeppelin's secure upgrade pattern

  3. Administrative Controls: Curators can adjust system parameters

Economic Security

  1. Anti-Manipulation: Large price movements require human oversight

  2. Historical Integrity: Immutable round data once confirmed

  3. Operational Continuity: System continues operating during pending price periods

Integration Guidelines

For Consumers

Interface Requirements

Consumers must import and use the Chainlink AggregatorV3Interface to interact with the PriceOracle:

Reading Historical Price Data

Use getRoundData(uint80 _roundId) to retrieve specific historical rounds:

Essential Integration Patterns

  1. Always validate price data before using it in calculations

  2. Handle potential reversion when no data is available using try-catch blocks

  3. Validate data freshness using the updatedAt timestamp (in milliseconds)

  4. Account for decimal precision using priceFeed.decimals()

For Operators

  1. Updaters: Submit regular price updates with accurate timestamps and source hashes

  2. Curators: Monitor pending prices and validate large deviations promptly

  3. Administrators: Configure deviation thresholds and timestamp buffers appropriately

Deployment Considerations

  1. Proxy Pattern: Deploy using upgradeable proxy for future improvements

  2. Role Assignment: Carefully assign roles to appropriate addresses

  3. Parameter Tuning: Set maxPriceDeviation and timestampBuffer based on asset volatility

  4. Monitoring: Implement off-chain monitoring for pending prices and system health

Last updated