contracts

Oracles: Chainlink Price Consumers

Overview

BankX uses two Chainlink price feed consumer contracts: ChainlinkETHUSDPriceConsumer (ETH/USD) and ChainlinkXAGUSDPriceConsumer (XAG/USD silver). Both are thin wrappers around Chainlink's AggregatorV3Interface, implementing freshness validation via the answeredInRound >= roundID staleness check. Prices are pulled into XSDStablecoin and normalised to 1e6 precision.


ChainlinkETHUSDPriceConsumer

Purpose

Provides the ETH/USD price used throughout the protocol for:

  • Converting WETH collateral amounts to USD value in CollateralPool.
  • Computing pool-based BankX and XSD prices in PIDController.
  • ETH value calculations in RewardManager.

Contract Details

PropertyValue
Mainnet feed address (hardcoded)0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419
InterfaceAggregatorV3Interface
Freshness checkansweredInRound >= roundID

Functions

FunctionVisibilityReturnsDescription
getLatestPrice()public viewintReturns the latest ETH/USD price from Chainlink. Reverts if oracle is stale.
getDecimals()public viewuint8Returns the feed's decimal places (typically 8 for Chainlink USD feeds).

Usage in XSDStablecoin

function eth_usd_price() public view returns (uint256) {
    return (uint256(eth_usd_pricer.getLatestPrice()) * PRICE_PRECISION)
           / (uint256(10) ** eth_usd_pricer_decimals);
    // PRICE_PRECISION = 1e6
    // Result: ETH/USD in 1e6 precision
    // e.g. ETH = $3000 → returns 3000000000 (3000 * 1e6)
}

Feed Addresses by Network

NetworkAddress
Ethereum Mainnet0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419
Arbitrum0x639Fe6ab55C921f74e7fac1ee960C0B6293ba612
Polygon0xAB594600376Ec9fD91F8e885dADF0CE036862dE0
Optimism0x13e3Ee699D1909E989722E753853AE30b17e08c5
Avalanche0x0A77230d17318075983913bC2145DB16C7366156
Fantom0xf4766552D15AE4d256Ad41B6cf2933482B0680dc

:::note The constructor hardcodes the feed address at deploy time. Each network deployment uses a separate contract instance pointed at the correct Chainlink ETH/USD feed for that chain. See Deployments for deployed addresses. :::


ChainlinkXAGUSDPriceConsumer

Purpose

Provides the XAG/USD (silver) price — the fundamental peg reference for XSD. Used in:

  • XSDStablecoin.xag_usd_price() — the XSD target price feed.
  • PIDController.systemCalculations() — silver band computation for CR adjustment.
  • CollateralPoolLibrary.calcMintInterest() — interest accrual uses the silver gram price.

Oracle Migration: Pyth → Chainlink

When the protocol was first deployed on Base and Avalanche, Chainlink did not yet offer an XAG/USD (silver) price feed on those networks. To support the silver peg on those chains, the protocol initially integrated Pyth Network as the XAG/USD oracle source.

Chainlink has since launched XAG/USD feeds on both Base and Avalanche. The protocol has migrated to Chainlink on those networks. The Chainlink oracle contracts are already deployed — no redeployment is required.

:::note All currently active deployments use ChainlinkXAGUSDPriceConsumer. The Pyth integration is no longer in use. :::

Contract Details

PropertyValue
Mainnet feed address (hardcoded)0x379589227b15F1a12195D3f2d90bBc9F31f95235
InterfaceAggregatorV3Interface
Freshness checkansweredInRound >= roundID

Functions

FunctionVisibilityReturnsDescription
getLatestPrice()public viewintReturns the latest XAG/USD price from Chainlink. Reverts if oracle is stale.
getDecimals()public viewuint8Returns the feed's decimal places.

Usage in XSDStablecoin

function xag_usd_price() public view returns (uint256) {
    return (uint256(xag_usd_pricer.getLatestPrice()) * PRICE_PRECISION)
           / (uint256(10) ** xag_usd_pricer_decimals);
    // Result: XAG/USD in 1e6 precision
    // e.g. silver = $25/oz → returns 25000000 (25 * 1e6)
    // XSD target price = 25000000 / 1000 = 25000 ($0.025)
}

Feed Addresses by Network

NetworkAddress
Ethereum Mainnet0x379589227b15F1a12195D3f2d90bBc9F31f95235
Arbitrum0xC56765f04B248394CF1619D20dB8082Edbfa75b1
Polygon0x461c7B8D370a240DdB46B402748381C3210136b3
Optimism0x290dd71254874f0d4356443607cb8234958DEe49
Avalanche0x4305FB66699C3B2702D4d05CF36551390A4c69C6
BaseSee deployed contracts in Deployments

AggregatorV3Interface

Both consumers wrap Chainlink's standard AggregatorV3Interface:

interface AggregatorV3Interface {
    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
    );
}

The staleness check in both consumers:

(uint80 roundID, int price, , , uint80 answeredInRound) = priceFeed.latestRoundData();
require(answeredInRound >= roundID);
return price;

This check reverts if Chainlink has not answered the latest round, protecting the protocol from consuming stale data.