Skip to content
Open
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
78 changes: 65 additions & 13 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 @@ -33,6 +34,7 @@ const data = await response.json()
const targetFeeds = [
"AAVE/USD-RefPrice-DF-Ethereum-001",
"BTC/USD-RefPrice-DF-Ethereum-001",
"COMP/USD-RefPrice-DF-Ethereum-001",
"ETH/USD-RefPrice-DF-Ethereum-001",
"LINK/USD-RefPrice-DF-Ethereum-001",
"USDC/USD-RefPrice-DF-Ethereum-001",
Expand All @@ -44,13 +46,33 @@ const data = await response.json()
feed.secondaryProxyAddress && feed.docs?.clicProductName && targetFeeds.includes(feed.docs.clicProductName)
)

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,
canonicalAddress: null
}
}

if (isAaveSVR(feed)) {
feedGroups[baseName].aaveAddress = feed.contractAddress
} else if (isSharedSVR(feed)) {
feedGroups[baseName].canonicalAddress = 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 @@ -136,6 +158,22 @@ 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 currently available in two variants: [Canonical SVR Feeds](#canonical-svr-feeds) and [Aave SVR Feeds](#aave-svr-feeds).

### Canonical SVR Feeds

Canonical SVR feeds are designed to be used by any protocol.

{/* [More info] */}

### Aave SVR Feeds

Aave SVR feeds are specifically tailored for the Aave protocol.

{/* [More info] */}

## How Protocols Can Utilize SVR Feeds

### 1. Identify the SVR Feed Address
Expand Down Expand Up @@ -293,30 +331,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>Aave Dedicated SVR Feed</th>
<th>Canonical 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.aaveAddress ? (
<CopyText text={feed.aaveAddress} code />
) : (
<span style={{ color: "#888" }}>Not available</span>
)}
</td>
<td>
<CopyText text={feed.address} code />
{feed.canonicalAddress ? (
<CopyText text={feed.canonicalAddress} 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 @@ -393,7 +445,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
50 changes: 37 additions & 13 deletions src/features/feeds/components/Tables.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import { CheckHeartbeat } from "./pause-notice/CheckHeartbeat.tsx"
import { monitoredFeeds, FeedDataItem } from "~/features/data/index.ts"
import { StreamsNetworksData, type NetworkData } from "../data/StreamsNetworksData.ts"
import { type Docs } from "~/features/data/api/index.ts"
import { isSharedSVR, isAaveSVR } from "~/features/feeds/utils/svrDetection.ts"

const feedItems = monitoredFeeds.mainnet
const feedCategories = {
Expand Down Expand Up @@ -210,12 +210,24 @@
{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#canonical-svr-feeds"
: "/data-feeds/svr-feeds"
}
target="_blank"
className={tableStyles.feedVariantBadge}
title="SVR-enabled Feed"
title={
isAaveSVR(metadata)
? "Aave Dedicated SVR Feed"
: isSharedSVR(metadata)
? "Canonical SVR Feed"
: "SVR-enabled Feed"
}
>
SVR
{isAaveSVR(metadata) ? "Aave SVR" : isSharedSVR(metadata) ? "Canonical SVR" : "SVR"}
</a>
</div>
)}
Expand Down Expand Up @@ -304,7 +316,7 @@
<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 @@ -331,14 +343,26 @@
</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>🔗 Canonical SVR Feed:</strong> This SVR proxy feed is usable by any protocol. Learn more
about{" "}
<a href="/data-feeds/svr-feeds#canonical-svr-feeds" target="_blank">
Canonical SVR Feeds
</a>
.
</div>
)}
</>
)}
</dl>
Expand Down Expand Up @@ -1095,7 +1119,7 @@
lastAddr = 1000,
addrPerPage = 8,
currentPage = 1,
paginate = (_page: number) => {

Check warning on line 1122 in src/features/feeds/components/Tables.tsx

View workflow job for this annotation

GitHub Actions / eslint

'_page' is defined but never used

Check warning on line 1122 in src/features/feeds/components/Tables.tsx

View workflow job for this annotation

GitHub Actions / eslint

'_page' is defined but never used
/* Default no-op function */
},
searchValue = "",
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 (Canonical) SVR feed based on its path
* @param metadata - The feed metadata object
* @returns true if the feed is a shared/canonical 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