diff --git a/public/changelog.json b/public/changelog.json index 5da8a17ac14..deea7092062 100644 --- a/public/changelog.json +++ b/public/changelog.json @@ -398,6 +398,13 @@ } }, "data": [ + { + "category": "release", + "date": "2026-03-20", + "description": "To give developers more choice in how certain asset classes are priced onchain, we have introduced Bounded Market Price Feeds, which include predefined bounds on reported values. This approach is intended to provide guardrails during edge cases where structural deviations can introduce higher risk. If your use case requires the use of a non-Bounded Market Price Feed and one does not exist, reach out and we’ll be happy to support. See the docs for how these feeds work and associated considerations: [Bounded Market Price Feeds](https://docs.chain.link/data-feeds/price-feeds/bounded-market-price-feeds).", + "title": "Bounded Market Price Feeds", + "topic": "Data Feeds" + }, { "category": "release", "date": "2026-03-17", @@ -806,6 +813,13 @@ "title": "Added support to Data Streams", "topic": "Data Streams" }, + { + "category": "deprecation", + "date": "2026-03-11", + "description": "We have announced the deprecation of select Data Feeds, scheduled for shutdown on March 25th, 2026. Check [the list of Deprecating Data Feeds to learn more](https://docs.chain.link/data-feeds/deprecating-feeds).", + "title": "Deprecating Data Feeds", + "topic": "Data Feeds" + }, { "category": "integration", "date": "2026-03-08", diff --git a/src/content/data-feeds/llms-full.txt b/src/content/data-feeds/llms-full.txt index 2bc6e82e150..d45ac895b53 100644 --- a/src/content/data-feeds/llms-full.txt +++ b/src/content/data-feeds/llms-full.txt @@ -3617,8 +3617,6 @@ For a summary of data sourcing models by asset type, see [Data Sources](/data-fe This categorization is put in place to inform users about the intended use cases of feeds and help highlight some of the inherent market integrity risks surrounding the data quality of these feeds. -Market price feeds incorporate three layers of aggregation at the data source, node operator, and oracle network layers, providing industry-standard security and reliability on the price data they reference. - Data feeds are grouped into the following categories based on the level of market pricing risk, based on multiple factors, from lowest to highest: - [🟢 Low Market Pricing Risk](#-low-market-pricing-risk-feeds) @@ -3631,9 +3629,24 @@ Data feeds are grouped into the following categories based on the level of marke +## Market Price Feeds + +Market Price Feeds incorporate three layers of aggregation at the data source, node operator, and oracle network layers. These feeds are designed to reflect observable market prices across [major venues](https://blog.chain.link/chainlink-price-feeds-secure-defi/). + +### Bounded Market Price Feeds + +Bounded Market Price Feeds are a specific category of Market Price Feeds that incorporate predefined bounds on reported values to mitigate specific asset class risks, following risk management best practices. + +For example, a Bounded Market Price Feed for a stablecoin would include an upper bound that caps the on-chain reported price at a pre-defined maximum (e.g., $1.05), even during edge cases like market dislocations where the stablecoin trades higher than the cap. In such cases, the price will not be reported on-chain. Instead, the most recently written on-chain price will be the value returned by calling [latestRoundData](https://docs.chain.link/data-feeds/api-reference#latestrounddata) on the feed’s [proxy address](https://docs.chain.link/data-feeds#single-value-feed-components). This helps prevent extreme or sustained premium pricing from being reported. These bounds are designed to provide guardrails for assets where structural deviations may introduce elevated risk for feed consumers. Note that a Bounded Market Price Feed for a stablecoin would not include a lower bound for the on-chain reported price. + +In rare circumstances, the fundamental value of an asset underlying a Bounded Market Price Feed, such as a stablecoin, may materially change. In such a case, the predefined bound(s) associated with a Bounded Market Price Feed may be adjusted or removed following advanced notice to consumers of such Bounded Market Price Feed. + +Users must be aware that Bounded Market Price Feeds have unique risk considerations. Developers remain responsible for ensuring that protocol risk parameters are configured appropriately and that the operation and performance of Bounded Market Price Feeds matches expectations. If your use case requires the use of a non-Bounded Market Price Feed and one does not exist, contact us at [chainlink_data_feeds@smartcontract.com](mailto:chainlink_data_feeds@smartcontract.com). + ### 🟢 Low Market Pricing Risk Feeds These are data feeds that follow a standardized data feeds workflow to report market prices for an asset pair. Chainlink node operators each query several sources for the market price and aggregate the estimates provided by those sources. @@ -3852,9 +3865,7 @@ To mitigate the risk associated with front running, users building highly latenc ## Exchange Rate Feeds -The architecture of exchange rate feeds differs from that of standard market rate Chainlink Price Feeds. - -**Market rate feeds** (e.g., Chainlink Price Feeds) deliver price updates based on the volume-based aggregated market price of a specific asset. Price data is [aggregated from across multiple sources](https://blog.chain.link/chainlink-price-feeds-secure-defi/), including centralized and decentralized exchanges, to provide an accurate representation of an asset's market-wide price. +The architecture of exchange rate feeds differs from that of [Market Price Feeds](#market-price-feeds). **Exchange rate feeds** are tied to specific protocols or ecosystems and report the internal redemption rates for an asset (i.e., the value/rate at which an asset can be redeemed or exchanged within that protocol's ecosystem). This data is sourced directly from a specified smart contract on a source chain and relayed to a destination chain. @@ -3865,10 +3876,10 @@ Exchange rate feeds are useful in circumstances such as: - **Improving liquidity pool performance for yield-bearing assets:** Exchange rate feeds can be utilized to programmatically adjust swap curves to maximize liquidity efficiency. ## ETF and Forex feeds diff --git a/src/content/data-feeds/selecting-data-feeds.mdx b/src/content/data-feeds/selecting-data-feeds.mdx index e450d19ebde..ca4ae89c087 100644 --- a/src/content/data-feeds/selecting-data-feeds.mdx +++ b/src/content/data-feeds/selecting-data-feeds.mdx @@ -16,8 +16,6 @@ For a summary of data sourcing models by asset type, see [Data Sources](/data-fe This categorization is put in place to inform users about the intended use cases of feeds and help highlight some of the inherent market integrity risks surrounding the data quality of these feeds. -Market price feeds incorporate three layers of aggregation at the data source, node operator, and oracle network layers, providing industry-standard security and reliability on the price data they reference. - Data feeds are grouped into the following categories based on the level of market pricing risk, based on multiple factors, from lowest to highest: - [🟢 Low Market Pricing Risk](#-low-market-pricing-risk-feeds) @@ -30,9 +28,24 @@ Data feeds are grouped into the following categories based on the level of marke +## Market Price Feeds + +Market Price Feeds incorporate three layers of aggregation at the data source, node operator, and oracle network layers. These feeds are designed to reflect observable market prices across [major venues](https://blog.chain.link/chainlink-price-feeds-secure-defi/). + +### Bounded Market Price Feeds + +Bounded Market Price Feeds are a specific category of Market Price Feeds that incorporate predefined bounds on reported values to mitigate specific asset class risks, following risk management best practices. + +For example, a Bounded Market Price Feed for a stablecoin would include an upper bound that caps the on-chain reported price at a pre-defined maximum (e.g., $1.05), even during edge cases like market dislocations where the stablecoin trades higher than the cap. In such cases, the price will not be reported on-chain. Instead, the most recently written on-chain price will be the value returned by calling [latestRoundData](https://docs.chain.link/data-feeds/api-reference#latestrounddata) on the feed’s [proxy address](https://docs.chain.link/data-feeds#single-value-feed-components). This helps prevent extreme or sustained premium pricing from being reported. These bounds are designed to provide guardrails for assets where structural deviations may introduce elevated risk for feed consumers. Note that a Bounded Market Price Feed for a stablecoin would not include a lower bound for the on-chain reported price. + +In rare circumstances, the fundamental value of an asset underlying a Bounded Market Price Feed, such as a stablecoin, may materially change. In such a case, the predefined bound(s) associated with a Bounded Market Price Feed may be adjusted or removed following advanced notice to consumers of such Bounded Market Price Feed. + +Users must be aware that Bounded Market Price Feeds have unique risk considerations. Developers remain responsible for ensuring that protocol risk parameters are configured appropriately and that the operation and performance of Bounded Market Price Feeds matches expectations. If your use case requires the use of a non-Bounded Market Price Feed and one does not exist, contact us at [chainlink_data_feeds@smartcontract.com](mailto:chainlink_data_feeds@smartcontract.com). + ### 🟢 Low Market Pricing Risk Feeds These are data feeds that follow a standardized data feeds workflow to report market prices for an asset pair. Chainlink node operators each query several sources for the market price and aggregate the estimates provided by those sources. @@ -250,9 +263,7 @@ To mitigate the risk associated with front running, users building highly latenc ## Exchange Rate Feeds -The architecture of exchange rate feeds differs from that of standard market rate Chainlink Price Feeds. - -**Market rate feeds** (e.g., Chainlink Price Feeds) deliver price updates based on the volume-based aggregated market price of a specific asset. Price data is [aggregated from across multiple sources](https://blog.chain.link/chainlink-price-feeds-secure-defi/), including centralized and decentralized exchanges, to provide an accurate representation of an asset's market-wide price. +The architecture of exchange rate feeds differs from that of [Market Price Feeds](#market-price-feeds). **Exchange rate feeds** are tied to specific protocols or ecosystems and report the internal redemption rates for an asset (i.e., the value/rate at which an asset can be redeemed or exchanged within that protocol's ecosystem). This data is sourced directly from a specified smart contract on a source chain and relayed to a destination chain. @@ -263,10 +274,10 @@ Exchange rate feeds are useful in circumstances such as: - **Improving liquidity pool performance for yield-bearing assets:** Exchange rate feeds can be utilized to programmatically adjust swap curves to maximize liquidity efficiency. ## ETF and Forex feeds diff --git a/src/features/data/api/backend.ts b/src/features/data/api/backend.ts index c4ee9a320bf..14ffc98fc0d 100644 --- a/src/features/data/api/backend.ts +++ b/src/features/data/api/backend.ts @@ -12,8 +12,8 @@ export const getServerSideChainMetadata = async ( const requests = chain.networks.map((nw) => nw?.rddUrl ? EleventyFetch(nw?.rddUrl, { - duration: skipCache ? "0s" : "1d", // No cache if skipCache is true - type: "json", // we'll parse JSON for you + duration: skipCache ? "0s" : "1d", + type: "json", }).then((metadata) => ({ ...nw, metadata: metadata.filter( diff --git a/src/features/data/api/index.ts b/src/features/data/api/index.ts index 01720a024ec..255aedb9995 100644 --- a/src/features/data/api/index.ts +++ b/src/features/data/api/index.ts @@ -53,6 +53,8 @@ export interface ChainMetadata { feedCategory: string feedType: string docs: Docs + decimals?: number + maxSubmissionValue?: string transmissionsAccount: null | string } diff --git a/src/features/feeds/components/Tables.module.css b/src/features/feeds/components/Tables.module.css index 2a9b96e74ae..9dd99998f28 100644 --- a/src/features/feeds/components/Tables.module.css +++ b/src/features/feeds/components/Tables.module.css @@ -855,3 +855,15 @@ tr.statusRow td { margin: 8px 0; line-height: 1.4; } + +.boundedNote { + display: inline-block; + font-size: 0.72rem; + padding: 2px 6px; + margin-top: 5px; + border-radius: 4px; + background: var(--color-background-info, #eff6ff); + color: var(--color-text-info, #1d4ed8); + font-weight: 500; + border: 1px solid var(--blue-200, #bfdbfe); +} diff --git a/src/features/feeds/components/Tables.tsx b/src/features/feeds/components/Tables.tsx index bdeadf83e5a..4d14753d8ef 100644 --- a/src/features/feeds/components/Tables.tsx +++ b/src/features/feeds/components/Tables.tsx @@ -17,6 +17,43 @@ import { isFeedVisible } from "~/features/feeds/utils/feedVisibility.ts" const feedItems = monitoredFeeds.mainnet +/** + * Decodes a raw maxSubmissionValue (BigInt string scaled by 10^decimals) into a + * human-readable USD price string. Returns null if the value is effectively unbounded + * (i.e. the contract's default max sentinel — all 0xff bytes) or otherwise too large + * to represent a real price cap. + * + * The raw value lives on-chain and is stored as a string to avoid JS number precision + * loss. We divide by 10^decimals to recover the actual price, then format it. + */ +const getMaxSubmissionValueBound = ( + maxSubmissionValue: string | undefined, + decimals: number | undefined +): string | null => { + if (!maxSubmissionValue || decimals == null || decimals < 0) return null + try { + const raw = BigInt(maxSubmissionValue) + const divisor = BigInt(10) ** BigInt(decimals) + const wholePart = raw / divisor + // Hide the badge if the decoded price exceeds $1,000,000 (1M). + // This filters out the all-0xff unbounded sentinel that contracts use by default + // (which decodes to ~9.578e44) while still accommodating any real-world price cap + // across USD, ETH, EUR, and other quote currencies — the highest plausible cap + // for any stablecoin or pegged asset is well below $1M. + if (wholePart > BigInt(1_000_000)) return null + const remainder = raw % divisor + const price = Number(wholePart) + Number(remainder) / Number(divisor) + return new Intl.NumberFormat("en-US", { + style: "currency", + currency: "USD", + minimumFractionDigits: 2, + maximumFractionDigits: 2, + }).format(price) + } catch { + return null + } +} + // Helper function to extract schema version from clicProductName // e.g., "HOOD/USD-Streams-RegularHoursEquityPrice-DS-Premium-Global-011" -> "v11" // e.g., "USD/SEK-Datalink-DeutscheBoerse-DS-Premium-Global-008" -> "v8" @@ -238,6 +275,12 @@ const DefaultTr = ({ network, metadata, showExtraDetails, batchedCategoryData, d // have its address hidden and show a contact email instead. const shouldHideAddress = metadata.docs?.productSubType === "calculatedPrice" + // Stablecoin price-bound note: only shown for stablecoin feeds with a meaningful cap + const isStablecoin = metadata.docs?.assetSubClass === "Stablecoin" + const stablecoinBound = isStablecoin + ? getMaxSubmissionValueBound(metadata.maxSubmissionValue, metadata.decimals) + : null + const label = isUSGovernmentMacroeconomicData ? "Category" : "Asset type" const value = isUSGovernmentMacroeconomicData ? metadata.docs.assetClass === "Macroeconomics" @@ -283,6 +326,18 @@ const DefaultTr = ({ network, metadata, showExtraDetails, batchedCategoryData, d )} + {stablecoinBound && ( +
+ + Bounded (Upper): {stablecoinBound} + +
+ )} {metadata.docs.shutdownDate && (
@@ -475,6 +530,12 @@ const SmartDataTr = ({ network, metadata, showExtraDetails, batchedCategoryData // (already includes deprecating status and Supabase risk tier) const finalTier = metadata.finalCategory || metadata.feedCategory + // Stablecoin price-bound note for Stablecoin Stability Assessment feeds + const isStablecoinAssessment = metadata.docs?.assetClass === "Stablecoin Stability Assessment" + const stablecoinBound = isStablecoinAssessment + ? getMaxSubmissionValueBound(metadata.maxSubmissionValue, metadata.decimals) + : null + return ( @@ -525,6 +586,18 @@ const SmartDataTr = ({ network, metadata, showExtraDetails, batchedCategoryData
)} + {stablecoinBound && ( +
+ + Bounded (Upper): {stablecoinBound} + +
+ )}