Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 58 additions & 24 deletions src/content/data-feeds/svr-feeds/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ whatsnext:
import { Aside, ClickToZoom, CodeSample, CopyText } from "@components"
import { Tabs } from "@components/Tabs"
import { CHAINS } from "@features/data/chains"
import { isSharedSVR, isAaveSVR } from "~/features/feeds/utils/svrDetection.ts"

export async function getFeeds() {
const ethereumMainnet = CHAINS.find((chain) => chain.page === "ethereum")?.networks.find(
Expand All @@ -30,27 +31,38 @@ try {
const response = await fetch(rddUrl)
const data = await response.json()

const targetFeeds = [
"AAVE/USD-RefPrice-DF-Ethereum-001",
"BTC/USD-RefPrice-DF-Ethereum-001",
"ETH/USD-RefPrice-DF-Ethereum-001",
"LINK/USD-RefPrice-DF-Ethereum-001",
"USDC/USD-RefPrice-DF-Ethereum-001",
"USDT/USD-RefPrice-DF-Ethereum-001",
]

// Find all feeds that have SVR variants (either Aave or Shared SVR) and are not hidden
const svrFeeds = data.filter(
(feed) =>
feed.secondaryProxyAddress && feed.docs?.clicProductName && targetFeeds.includes(feed.docs.clicProductName)
(feed) => feed.secondaryProxyAddress && !feed.docs?.hidden && (isAaveSVR(feed) || isSharedSVR(feed))
)

return svrFeeds
.map((feed) => ({
name: feed.name.replace(" / ", "/"),
address: feed.contractAddress,
}))
// Group feeds by their base name (e.g., "BTC/USD", "ETH/USD")
const feedGroups = {}

svrFeeds.forEach(feed => {
const baseName = feed.name.replace(" / ", "/")

if (!feedGroups[baseName]) {
feedGroups[baseName] = {
name: baseName,
aaveAddress: null,
svrAddress: null
}
}

if (isAaveSVR(feed)) {
feedGroups[baseName].aaveAddress = feed.contractAddress
} else if (isSharedSVR(feed)) {
feedGroups[baseName].svrAddress = feed.contractAddress
}
})

// Convert to array and sort
const combinedFeeds = Object.values(feedGroups)
.sort((a, b) => a.name.localeCompare(b.name))

return combinedFeeds

} catch (error) {
return []
}
Expand Down Expand Up @@ -132,6 +144,14 @@ Chainlink Smart Value Recapture (SVR) extends standard Chainlink Price Feeds wit
**Fail-Safe Fallback Mechanism**
If the **private route** fails or times out, the SVR feed automatically **reverts** to the **Standard Feed price** after a configurable delay. This delay can be set to any amount of seconds. This helps ensures the feed doesn't stall and that price data is accessible through the public route if the private channel is unavailable.

## SVR Feed Variants

Chainlink SVR Feeds are available as standard feeds for general use and specialized [Aave SVR Feeds](#aave-svr-feeds) for the Aave protocol. More specialized SVR feeds may be developed in the future for other protocols.

### Aave SVR Feeds

Aave SVR feeds are specifically tailored for the Aave protocol and are only intended for use by Aave.

## How Protocols Can Utilize SVR Feeds

### 1. Identify the SVR Feed Address
Expand Down Expand Up @@ -288,30 +308,44 @@ The following code samples demonstrate the complete decoding process, including
</Fragment>
</Tabs>

#### 4. Detect SVR-enabled Feeds for the Aave Protocol
#### 4. Detect SVR-enabled Feeds

When processing forward calls, verify that the `to` address from the code sample above (the destination of the forward call) matches one of these feed addresses. This tells you which SVR data feed the price update is for:

<table>
<thead>
<tr>
<th>Feed name</th>
<th>Address</th>
<th>Feed</th>
<th>SVR Feed</th>
<th>Aave Dedicated SVR Feed</th>
</tr>
</thead>
<tbody>
{feeds &&
feeds.map((feed) => (
<tr key={feed.address}>
<td>{feed.name}</td>
<tr key={feed.name}>
<td>
<strong>{feed.name}</strong>
</td>
<td>
{feed.svrAddress ? (
<CopyText text={feed.svrAddress} code />
) : (
<span style={{ color: "#888" }}>Not available</span>
)}
</td>
<td>
<CopyText text={feed.address} code />
{feed.aaveAddress ? (
<CopyText text={feed.aaveAddress} code />
) : (
<span style={{ color: "#888" }}>Not available</span>
)}
</td>
</tr>
))}
{(!feeds || feeds.length === 0) && (
<tr>
<td colSpan="2">No SVR feeds found.</td>
<td colSpan="3">No SVR feeds found.</td>
</tr>
)}
</tbody>
Expand Down Expand Up @@ -383,7 +417,7 @@ For gas management, simulations, and other advanced usage, see the official [Fla

3. **Stay Updated**
- Keep track of any updates to the SVR aggregator address, function signatures, or Flashbots MEV-Share changes.
- Monitor for changes in Aave liquidation parameters (e.g., new assets, different collateral thresholds).
- Monitor for changes in liquidation parameters (e.g., new assets, different collateral thresholds).

## Economics and Revenue Split

Expand Down
13 changes: 13 additions & 0 deletions src/features/feeds/components/Tables.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,19 @@
text-align: left;
}

.sharedCallout {
background-color: #e6f3ff;
border-radius: 4px;
padding: 10px 12px;
margin-top: 10px;
margin-bottom: 10px;
font-size: 0.9rem;
color: #0066cc;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
width: 100%;
text-align: left;
}

.feedVariantBadge {
display: inline-block;
font-size: 0.75rem;
Expand Down
44 changes: 32 additions & 12 deletions src/features/feeds/components/Tables.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import button from "@chainlink/design-system/button.module.css"
import { CheckHeartbeat } from "./pause-notice/CheckHeartbeat.tsx"
import { monitoredFeeds, FeedDataItem } from "~/features/data/index.ts"
import { StreamsNetworksData, type NetworkData } from "../data/StreamsNetworksData.ts"
import { isSharedSVR, isAaveSVR } from "~/features/feeds/utils/svrDetection.ts"

const feedItems = monitoredFeeds.mainnet
const feedCategories = {
Expand Down Expand Up @@ -228,12 +229,20 @@ const DefaultTr = ({ network, metadata, showExtraDetails, dataFeedType }) => {
{metadata.secondaryProxyAddress && (
<div style={{ marginTop: "5px" }}>
<a
href="/data-feeds/svr-feeds"
href={
isAaveSVR(metadata)
? "/data-feeds/svr-feeds#aave-svr-feeds"
: isSharedSVR(metadata)
? "/data-feeds/svr-feeds"
: "/data-feeds/svr-feeds"
}
target="_blank"
className={tableStyles.feedVariantBadge}
title="SVR-enabled Feed"
title={
isAaveSVR(metadata) ? "Aave Dedicated SVR Feed" : isSharedSVR(metadata) ? " SVR Feed" : "SVR Feed"
}
>
SVR
{isAaveSVR(metadata) ? "Aave SVR" : isSharedSVR(metadata) ? "SVR" : "SVR"}
</a>
</div>
)}
Expand Down Expand Up @@ -328,7 +337,7 @@ const DefaultTr = ({ network, metadata, showExtraDetails, dataFeedType }) => {
<div className={tableStyles.separator} />
<div className={tableStyles.assetAddress}>
<dt>
<span className="label">AAVE SVR Proxy:</span>
<span className="label">{isAaveSVR(metadata) ? "AAVE SVR Proxy:" : "SVR Proxy:"}</span>
</dt>
<dd>
<button
Expand All @@ -355,14 +364,25 @@ const DefaultTr = ({ network, metadata, showExtraDetails, dataFeedType }) => {
</a>
</dd>
</div>
<div className={clsx(tableStyles.aaveCallout)}>
<strong>⚠️ Aave Dedicated Feed:</strong> This SVR proxy feed is dedicated exclusively for use by the
Aave protocol. Learn more about{" "}
<a href="/data-feeds/svr-feeds" target="_blank">
SVR-enabled Feeds
</a>
.
</div>
{isAaveSVR(metadata) && (
<div className={clsx(tableStyles.aaveCallout)}>
<strong>⚠️ Aave Dedicated Feed:</strong> This SVR proxy feed is dedicated exclusively for use by the
Aave protocol. Learn more about{" "}
<a href="/data-feeds/svr-feeds#aave-svr-feeds" target="_blank">
Aave SVR Feeds
</a>
.
</div>
)}
{isSharedSVR(metadata) && (
<div className={clsx(tableStyles.sharedCallout)}>
<strong>🔗 SVR Feed:</strong> This SVR proxy feed is usable by any protocol. Learn more about{" "}
<a href="/data-feeds/svr-feeds" target="_blank">
SVR Feeds
</a>
.
</div>
)}
</>
)}
</dl>
Expand Down
23 changes: 23 additions & 0 deletions src/features/feeds/utils/svrDetection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { type ChainMetadata } from "~/features/data/api/index.ts"

// This file contains *temporary* functions to detect SVR feeds based on their metadata
// These functions are used to identify specific types of SVR feeds based on their metadata properties

/**
* Determines if a feed is a Shared SVR feed based on its path
* @param metadata - The feed metadata object
* @returns true if the feed is a shared SVR feed
*/
export const isSharedSVR = (metadata: ChainMetadata): boolean => {
// Check the path field for feeds ending with "-shared-svr"
return typeof metadata.path === "string" && /-shared-svr$/.test(metadata.path)
}

/**
* Determines if a feed is an Aave dedicated SVR feed
* @param metadata - The feed metadata object
* @returns true if the feed has a secondary proxy address but is not a shared SVR feed
*/
export const isAaveSVR = (metadata: ChainMetadata): boolean => {
return !!metadata?.secondaryProxyAddress && !isSharedSVR(metadata)
}
Loading