diff --git a/src/config/sidebar.ts b/src/config/sidebar.ts index 4736b8cb8ea..a4d1cce5647 100644 --- a/src/config/sidebar.ts +++ b/src/config/sidebar.ts @@ -369,6 +369,10 @@ export const SIDEBAR: Partial> = { { section: "Streams & Report Schemas", contents: [ + { + title: "Overview", + url: "data-streams/reference/report-schema-overview", + }, { title: "Cryptocurrency Streams", url: "data-streams/crypto-streams", @@ -428,25 +432,13 @@ export const SIDEBAR: Partial> = { }, { title: "Fetch and decode reports", - url: "data-streams/tutorials/api-go", - highlightAsCurrent: [ - "data-streams/tutorials/api-rust", - "data-streams/tutorials/api-rwa-go", - "data-streams/tutorials/api-rwa-rust", - "data-streams/tutorials/api-nav-rust", - "data-streams/tutorials/api-nav-go", - ], + url: "data-streams/tutorials/go-sdk-fetch", + highlightAsCurrent: ["data-streams/tutorials/rust-sdk-fetch"], }, { title: "Stream and decode reports (WebSocket)", - url: "data-streams/tutorials/ws-go", - highlightAsCurrent: [ - "data-streams/tutorials/ws-rust", - "data-streams/tutorials/ws-rwa-go", - "data-streams/tutorials/ws-rwa-rust", - "data-streams/tutorials/ws-nav-go", - "data-streams/tutorials/ws-nav-rust", - ], + url: "data-streams/tutorials/go-sdk-stream", + highlightAsCurrent: ["data-streams/tutorials/rust-sdk-stream"], }, { title: "Verify report data (EVM)", diff --git a/src/content/data-streams/architecture.mdx b/src/content/data-streams/architecture.mdx index 231f03df117..498dac84714 100644 --- a/src/content/data-streams/architecture.mdx +++ b/src/content/data-streams/architecture.mdx @@ -7,7 +7,7 @@ metadata: keywords: ["Data Streams", "Architecture", "Oracle Network", "DON", "Verification", "API", "Streams Trade"] whatsnext: { - "Learn more about the Standard API Implementation": "/data-streams/tutorials/api-go", + "Learn more about the Standard API Implementation": "/data-streams/tutorials/go-sdk-fetch", "Learn more about the Streams Trade Implementation": "/data-streams/streams-trade", "Find the list of available Stream IDs": "/data-streams/crypto-streams", "Find the schema of data to expect from Data Streams reports: Crypto": "/data-streams/reference/report-schema-v3", diff --git a/src/content/data-streams/developer-responsibilities.mdx b/src/content/data-streams/developer-responsibilities.mdx index 2ccb68ee2b2..9d3cc2a2b6e 100644 --- a/src/content/data-streams/developer-responsibilities.mdx +++ b/src/content/data-streams/developer-responsibilities.mdx @@ -11,7 +11,7 @@ whatsnext: "Find the schema of data to expect from Data Streams reports: Crypto": "/data-streams/reference/report-schema-v3", "Find the schema of data to expect from Data Streams reports: RWA": "/data-streams/reference/report-schema-v8", "Learn the basics about how to retrieve Data Streams reports using the Streams Trade implementation": "/data-streams/getting-started", - "Learn how to fetch and decode Data Streams reports using the Data Streams API": "/data-streams/tutorials/api-go", + "Learn how to fetch and decode Data Streams reports using the Data Streams API": "/data-streams/tutorials/go-sdk-fetch", } --- diff --git a/src/content/data-streams/index.mdx b/src/content/data-streams/index.mdx index f126bd2b511..2cf5d1d24db 100644 --- a/src/content/data-streams/index.mdx +++ b/src/content/data-streams/index.mdx @@ -8,7 +8,7 @@ metadata: keywords: ["Chainlink", "Data Streams", "Oracle", "DeFi", "Market Data", "Low Latency", "High Frequency"] whatsnext: { - "Learn how to fetch and decode Data Streams reports with the API": "/data-streams/tutorials/api-go", + "Learn how to fetch and decode Data Streams reports with the API": "/data-streams/tutorials/go-sdk-fetch", "Find the list of available Stream IDs": "/data-streams/crypto-streams", "Find the schema of data to expect from Data Streams reports: Crypto": "/data-streams/reference/report-schema-v3", "Find the schema of data to expect from Data Streams reports: RWA": "/data-streams/reference/report-schema-v8", @@ -24,6 +24,8 @@ Chainlink Data Streams delivers low-latency market data offchain, which you can Traditional push-based oracles update onchain data at set intervals or when certain price thresholds are met. In contrast, Chainlink Data Streams uses a pull-based design that preserves trust-minimization with onchain verification. +Data Streams are offered in [several report formats](/data-streams/reference/report-schema-overview), each designed for distinct asset classes. + ## Sub-Second Data and Commit-and-Reveal Chainlink Data Streams supports sub-second data resolution for latency-sensitive use cases by retrieving data only when needed. You can combine the data with any transaction in near real time. A "commit-and-reveal" approach mitigates frontrunning by making trade data and stream data visible atomically onchain. @@ -86,9 +88,9 @@ Access data directly through REST APIs or WebSocket connections using our SDKs: 1. Understand the Architecture: Review the [system components and data flow](/data-streams/architecture) to understand how Data Streams works. -1. Explore Available Data: Browse [available Stream IDs](/data-streams/crypto-streams) and [report schemas](/data-streams/reference/report-schema-v3) to see what data is available. +1. Explore Available Data: Browse [available reports and associated schemas](/data-streams/reference/report-schema-overview) to see what data is available. -1. Try the API: Follow our [hands-on tutorial](/data-streams/tutorials/api-go) to fetch and decode your first report. +1. Try the API: Follow our [hands-on tutorial](/data-streams/tutorials/go-sdk-fetch) to fetch and decode your first report. 1. Implement Verification: Add [onchain verification](/data-streams/reference/data-streams-api/onchain-verification) to ensure data authenticity in your smart contracts. diff --git a/src/content/data-streams/reference/data-streams-api/go-sdk.mdx b/src/content/data-streams/reference/data-streams-api/go-sdk.mdx index 9cdadc65606..3351ca9de70 100644 --- a/src/content/data-streams/reference/data-streams-api/go-sdk.mdx +++ b/src/content/data-streams/reference/data-streams-api/go-sdk.mdx @@ -8,8 +8,8 @@ metadata: keywords: ["Go SDK", "Golang", "Data Streams", "Integration", "API Client", "WebSocket Client", "Report Decoding"] whatsnext: { - "Learn how to fetch and decode Data Streams reports using the Data Streams SDK": "/data-streams/tutorials/api-go", - "Learn how to stream and decode reports via a WebSocket connection using the Data Streams SDK": "/data-streams/tutorials/ws-go", + "Learn how to fetch and decode Data Streams reports using the Data Streams SDK": "/data-streams/tutorials/go-sdk-fetch", + "Learn how to stream and decode reports via a WebSocket connection using the Data Streams SDK": "/data-streams/tutorials/go-sdk-stream", } --- diff --git a/src/content/data-streams/reference/data-streams-api/rust-sdk.mdx b/src/content/data-streams/reference/data-streams-api/rust-sdk.mdx index d19845cc3bb..64bfbc758f8 100644 --- a/src/content/data-streams/reference/data-streams-api/rust-sdk.mdx +++ b/src/content/data-streams/reference/data-streams-api/rust-sdk.mdx @@ -8,8 +8,8 @@ metadata: keywords: ["Rust SDK", "Data Streams", "Integration", "API Client", "WebSocket Client", "Report Decoding"] whatsnext: { - "Learn how to fetch and decode Data Streams reports using the Data Streams SDK": "/data-streams/tutorials/api-rust", - "Learn how to stream and decode reports via a WebSocket connection using the Data Streams SDK": "/data-streams/tutorials/ws-rust", + "Learn how to fetch and decode Data Streams reports using the Data Streams SDK": "/data-streams/tutorials/rust-sdk-fetch", + "Learn how to stream and decode reports via a WebSocket connection using the Data Streams SDK": "/data-streams/tutorials/rust-sdk-stream", } --- @@ -217,8 +217,8 @@ match client.get_latest_report(feed_id).await { ### Step-by-Step Guides -- [Fetch and decode reports using the REST API](/data-streams/tutorials/api-rust) -- [Stream and decode reports via WebSocket](/data-streams/tutorials/ws-rust) +- [Fetch and decode reports using the REST API](/data-streams/tutorials/rust-sdk-fetch) +- [Stream and decode reports via WebSocket](/data-streams/tutorials/rust-sdk-stream) ### More Examples diff --git a/src/content/data-streams/reference/report-schema-overview.mdx b/src/content/data-streams/reference/report-schema-overview.mdx new file mode 100644 index 00000000000..fb783a3da7a --- /dev/null +++ b/src/content/data-streams/reference/report-schema-overview.mdx @@ -0,0 +1,85 @@ +--- +section: dataStreams +date: Last Modified +title: "Overview" +--- + +import DataStreams from "@features/data-streams/common/DataStreams.astro" +import { PageTabs } from "@components" + + + + + +## Available Report Schemas + +Below is a summary of all available Data Streams report schemas, their main use cases, and key fields. + +| Report Schema | Version | Use Case / Purpose | Key Fields | +| :------------------------------------------------------------ | :----------------------------------------- | :---------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | +| [Cryptocurrency](#cryptocurrency-report-schema) | [View schema (v3)](./report-schema-v3) | Crypto price streams | `price`, `bid`, `ask` | +| [DEX State Price](#dex-state-price-report-schema) | [View schema (v3)](./report-schema-v3-dex) | DEX state crypto price streams | `price`, `bid`, `ask` (All fields equal; [details](../concepts/dex-state-price-streams#how-to-use-dex-state-price-streams)) | +| [Real World Asset (RWA)](#real-world-asset-rwa-report-schema) | [View schema (v8)](./report-schema-v8) | Real World Asset (RWA) price streams | `midPrice`, `marketStatus`, `lastUpdateTimestamp` | +| [Net Asset Value (NAV)](#net-asset-value-nav-report-schema) | [View schema (v9)](./report-schema-v9) | Net Asset Value (NAV) streams | `aum`, `navPerShare`, `navDate`, `ripcord` | +| [Backed xStock](#backed-xstock-report-schema) | [View schema (v10)](./report-schema-v10) | Tokenized stocks and backed asset streams | `price`, `tokenizedPrice`, `marketStatus`, `currentMultiplier`, `newMultiplier` | + +## Cryptocurrency Report Schema + +[Chainlink Cryptocurrency Reports](./report-schema-v3) provide market data for digital assets, supporting high-frequency, onchain use cases. Each report includes a consensus mid price (`price`), as well as simulated bid (`bid`) and ask (`ask`) prices that estimate the impact of buying or selling at a specified liquidity depth. These values help protocols and applications understand current market conditions and potential slippage for larger trades. + +For a deeper explanation of how liquidity-weighted bid and ask prices work, see [Liquidity-Weighted Bid-Ask Prices (LWBA)](../concepts/liquidity-weighted-prices). + +## DEX State Price Report Schema + +[Chainlink DEX State Price Reports](./report-schema-v3-dex) are designed for assets that derive most or all of their liquidity from decentralized exchanges (DEXs). Unlike standard crypto price streams, these reports use onchain market data to reflect the unique conditions of AMM pools and DEX-dominant tokens. In this report, the `price`, `bid`, and `ask` fields are all equal, representing the execution price a trader would receive based on the current state of onchain liquidity pools, rather than order-book mechanics. This approach enables accurate, real-time pricing, even for long-tail or newly launched tokens in low-volume environments. + +[The DEX State Price methodology](/data-streams/concepts/dex-state-price-streams#high-level-outline-of-the-dex-state-price-methodology) aggregates data from multiple DEX pools, applies volume and TVL-based weighting, and uses filters to reduce manipulation and smooth volatility. Users should be aware of the specific risks inherent to DeFi, such as smart contract vulnerabilities, bridge dependencies, and external price manipulation. It is important to review [risk mitigation guidance](/data-streams/concepts/dex-state-price-streams#risk-mitigation) and adjust protocol parameters accordingly when integrating DEX State Price Reports. + +For more details on the methodology and risk considerations, see [DEX State Price Streams](../concepts/dex-state-price-streams). + +## Real World Asset (RWA) Report Schema + +[Chainlink RWA Data Streams](./report-schema-v8) provide fresh, reliable, and accurate financial market data for real-world assets, enabling DeFi users to gain onchain exposure to physical assets. Each report includes a staleness measure (`lastUpdateTimestamp`), consensus median price (`midPrice`) and market status (`marketStatus`). + +RWA assets trade on traditional exchanges during [market hours](../market-hours). These market hours vary by asset class and can be subject to unexpected halts, pauses and other behaviors affecting traditional markets. For this reason, this class of Data Streams contains a market hours flag and a staleness measure to equip our users to handle these events correctly. It is critical that users implement correct safeguards on their end to pause markets, add more conservative risk caps, or do whatever else is appropriate for their application. + +## Net Asset Value (NAV) Report Schema + +[Chainlink NAV Data Streams](./report-schema-v9) provide real-time, tamper-proof access to the Net Asset Value (`navPerShare`) of tokenized assets, funds, or portfolios, delivered over the low latency, high frequency Chainlink Data Streams infrastructure. Each report includes NAV per share (`navPerShare`), NAV date (`navDate`), assets under management (`aum`), and ripcord status (`ripcord`). The ripcord is set to true (`1`) by the asset issuer when the consumer should ignore the value being sent (for cases such as maintenance, upstream data source outages, etc). The feed data will remain stale until the ripcord returns false (`0`). + +NAV is a fundamental financial metric that represents the value of an investment vehicle such as a mutual fund or ETF and is calculated as the total assets minus the total liabilities. + +Data Streams ensures that any NAV update, whenever it occurs, is captured and made available immediately and at low latency, allowing for seamless integration with onchain applications alongside other real-time data streams. Although the NAV value may not change frequently, Data Streams provides the most recent NAV as soon as it is published by the source. + +## Backed xStock Report Schema + +[Chainlink Backed xStock Data Streams](./report-schema-v10) provide fresh, reliable, and accurate financial market data for Tokenized Equities such as [xStock](https://xstocks.com/us) assets, enabling DeFi users to gain onchain exposure to tokenized stocks. These Streams are a unique product provided by Chainlink Labs for partners such as xStocks. They combine data from our US equity Data Streams with data from the tokenization service, which enables users to correctly handle corporate actions affecting the underlying equities. Each report includes the staleness measure (`lastUpdateTimestamp`), consensus mid price (`price`), market status (`marketStatus`), current multiplier (`currentMultiplier`, the number of underlying shares each xStock is redeemable for), new multiplier (`newMultiplier`, the future number of shares after a scheduled corporate action), activation date/time of the corporate action (`activationDateTime`) and the tokenized price if available on primary or secondary markets (`tokenizedPrice`). + +The underlying US equities trade on traditional exchanges during [market hours](../market-hours). These market hours depend per asset class and can be subject to unexpected halts, pauses and other behaviors affecting traditional markets. For this reason, this class of Data Streams contains a market hours flag and a staleness measure to equip our users to handle these events correctly. It is critical that users implement correct safeguards on their end to pause markets, add more conservative risk caps, or implement other measures appropriate for their application. + +[The schema](./report-schema-v10) is designed specifically for tokenized equities such as xStocks and contains data from the Chainlink US equities streams, combined with data provided by the tokenizer to properly handle corporate actions. With this enhanced data users are able to handle expected and unexpected market events such as pauses, halts and market off hours. The tokenization provider layers in data around the `currentMultiplier`, the `newMultiplier` and the `activationDateTime` of the new multiplier to handle corporate actions. diff --git a/src/content/data-streams/reference/report-schema-v10.mdx b/src/content/data-streams/reference/report-schema-v10.mdx index ac6fdbe46b4..250d3ee53bd 100644 --- a/src/content/data-streams/reference/report-schema-v10.mdx +++ b/src/content/data-streams/reference/report-schema-v10.mdx @@ -64,6 +64,7 @@ Chainlink Backed xStock Data Streams adhere to the report schema outlined below. **Notes:** +- Future Backed xStock streams may use different report schemas. - `price` updates in real time during market open, but may become stale during market closed periods. - `tokenizedPrice` will be available in an upcoming release of Backed xStock Data Streams. Currently, it will always return `0`. - `currentMultiplier` reflects all past corporate actions and is updated only when a new action is activated. diff --git a/src/content/data-streams/reference/report-schema-v8.mdx b/src/content/data-streams/reference/report-schema-v8.mdx index 9015d8a73a7..2b53dcf005b 100644 --- a/src/content/data-streams/reference/report-schema-v8.mdx +++ b/src/content/data-streams/reference/report-schema-v8.mdx @@ -57,3 +57,7 @@ RWA streams adhere to the report schema outlined below. | `lastUpdateTimestamp` | `uint64` | Timestamp of the last valid price update (nanoseconds) | | `midPrice` | `int192` | DON's consensus median price | | `marketStatus` | `uint32` | [Market status](/data-streams/market-hours). Possible values: `0` (`Unknown`), `1` (`Closed`), `2` (`Open`) | + +**Notes**: + +- Future RWA streams may use different report schemas. diff --git a/src/content/data-streams/reference/report-schema-v9.mdx b/src/content/data-streams/reference/report-schema-v9.mdx index 34ba9aa4a91..aa340eccf51 100644 --- a/src/content/data-streams/reference/report-schema-v9.mdx +++ b/src/content/data-streams/reference/report-schema-v9.mdx @@ -61,6 +61,8 @@ Chainlink NAV Data Streams streams adhere to the report schema outlined below. **Notes:** +- Future NAV streams may use different report schemas. + ##### `ripcord` Status - 0 (false) - **Data Provider is OK**. This indicates that the Fund’s data provider and data accuracy is reporting as expected. diff --git a/src/content/data-streams/tutorials/api-nav-go.mdx b/src/content/data-streams/tutorials/api-nav-go.mdx deleted file mode 100644 index 159b9a8db94..00000000000 --- a/src/content/data-streams/tutorials/api-nav-go.mdx +++ /dev/null @@ -1,618 +0,0 @@ ---- -section: dataStreams -date: Last Modified -title: "Fetch and decode V9 reports using the Go SDK" -metadata: - title: "Fetch and Decode Net Asset Value Data with Go SDK | Chainlink Data Streams" - description: "Learn how to use the Go SDK to fetch and decode Net Asset Value (NAV) market data reports with V9 schema from Chainlink Data Streams." - keywords: ["Go SDK", "Golang", "NAV", "Net Asset Value", "V9 Reports", "API Tutorial", "Data Streams"] -whatsnext: - { - "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/ws-nav-go", - "Learn how to verify your data onchain": "/data-streams/reference/onchain-verification", - "Find the list of available Stream IDs": "/data-streams/nav-streams", - } ---- - -import { CopyText, PageTabs } from "@components" -import DataStreams from "@features/data-streams/common/DataStreams.astro" - - - - - -In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/reference/go-sdk) for Go to fetch and decode [V9 reports](/data-streams/reference/report-schema-v9) for [Net Asset Value (NAV) streams](/data-streams/nav-streams) from the Data Streams Aggregation Network. You'll set up your Go project, retrieve reports, decode them, and log their attributes. - - - -## Requirements - -- **Git**: Make sure you have Git installed. You can check your current version by running in your terminal and download the latest version from the official [Git website](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) if necessary. -- **Go Version**: Make sure you have Go version 1.21 or higher. You can check your current version by running `go version` in your terminal and download the latest version from the official [Go website](https://go.dev/) if necessary. -- **API Credentials**: Access to Data Streams requires API credentials. If you haven't already, [contact us](https://chainlinkcommunity.typeform.com/datastreams?typeform-source=docs.chain.link#ref_id=docs) to request mainnet or testnet access. - -## Tutorial - -You'll start with the set up of your Go project. Next, you'll fetch and decode reports for both single and multiple [NAV streams](/data-streams/nav-streams), and log their attributes to your terminal. - -### Set up your Go project - -1. Create a new directory for your project and navigate to it: - - ```bash - mkdir my-data-streams-project - cd my-data-streams-project - ``` - -1. Initialize a new Go module: - - ```bash - go mod init my-data-streams-project - ``` - -1. Install the Data Streams SDK: - - ```bash - go get github.com/smartcontractkit/data-streams-sdk/go - ``` - -### Fetch and decode a report with a single stream - -1. Create a new Go file, `single-stream.go`, in your project directory: - - ```bash - touch single-stream.go - ``` - -1. Insert the following code example and save your `single-stream.go` file: - - ```go - package main - - import ( - "context" - "fmt" - "os" - "time" - - streams "github.com/smartcontractkit/data-streams-sdk/go" - feed "github.com/smartcontractkit/data-streams-sdk/go/feed" - report "github.com/smartcontractkit/data-streams-sdk/go/report" - v9 "github.com/smartcontractkit/data-streams-sdk/go/report/v9" // Import the v9 report schema for NAV streams - ) - - func main() { - // Validate command-line arguments - if len(os.Args) < 2 { - fmt.Printf("Usage: go run main.go [FeedID]\nExample: go run main.go [FEED_ID]\n") - os.Exit(1) - } - feedIDInput := os.Args[1] - - // Get API credentials from environment variables - apiKey := os.Getenv("API_KEY") - apiSecret := os.Getenv("API_SECRET") - if apiKey == "" || apiSecret == "" { - fmt.Printf("API_KEY and API_SECRET environment variables must be set\n") - os.Exit(1) - } - - // Define the configuration for the SDK client - cfg := streams.Config{ - ApiKey: apiKey, - ApiSecret: apiSecret, - RestURL: "https://api.testnet-dataengine.chain.link", - Logger: streams.LogPrintf, - } - - // Initialize the SDK client - client, err := streams.New(cfg) - if err != nil { - cfg.Logger("Failed to create client: %v\n", err) - os.Exit(1) - } - - // Create context with timeout - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - // Parse the feed ID - var feedID feed.ID - if err := feedID.FromString(feedIDInput); err != nil { - cfg.Logger("Invalid feed ID format '%s': %v\n", feedIDInput, err) - os.Exit(1) - } - - // Fetch the latest report - reportResponse, err := client.GetLatestReport(ctx, feedID) - if err != nil { - cfg.Logger("Failed to get latest report: %v\n", err) - os.Exit(1) - } - - // Log the raw report data - cfg.Logger("Raw report data: %+v\n", reportResponse) - - // Decode the report - decodedReport, err := report.Decode[v9.Data](reportResponse.FullReport) - if err != nil { - cfg.Logger("Failed to decode report: %v\n", err) - os.Exit(1) - } - - // Format and display the decoded report - fmt.Printf( - "\nDecoded Report for Stream ID %s:\n"+ - "------------------------------------------\n"+ - "Observations Timestamp : %d\n"+ - "Valid From Timestamp : %d\n"+ - "Expires At : %d\n"+ - "NAV Per Share : %s\n"+ - "NAV Date : %d\n"+ - "AUM : %s\n"+ - "Ripcord : %d\n"+ - "Link Fee (wei) : %s\n"+ - "Native Fee (wei) : %s\n"+ - "------------------------------------------\n", - feedIDInput, - decodedReport.Data.ObservationsTimestamp, - decodedReport.Data.ValidFromTimestamp, - decodedReport.Data.ExpiresAt, - decodedReport.Data.NavPerShare.String(), - decodedReport.Data.NavDate, - decodedReport.Data.Aum.String(), - decodedReport.Data.Ripcord, - decodedReport.Data.LinkFee.String(), - decodedReport.Data.NativeFee.String(), - ) - } - - ``` - -1. Download the required dependencies and update the `go.mod` and `go.sum` files: - - ```bash - go mod tidy - ``` - -1. Set up the SDK client configuration within `single-stream.go` with your API credentials and the REST endpoint: - - ```go - cfg := streams.Config{ - ApiKey: os.Getenv("API_KEY"), - ApiSecret: os.Getenv("API_SECRET"), - RestURL: "https://api.testnet-dataengine.chain.link", - Logger: streams.LogPrintf, - } - ``` - - - Set your API credentials as environment variables: - - ```bash - export API_KEY="" - export API_SECRET="" - ``` - - Replace `` and `` with your API credentials. - - - `RestURL` is the REST endpoint to poll for specific reports. See the [Data Streams Interface](/data-streams/reference/data-streams-api/interface-api#domains) page for more information. - - See the [SDK Reference](/data-streams/reference/data-streams-api/go-sdk#config-struct) page for more configuration options. - -1. For this example, you will read from a NAV stream. See the [Data Streams NAV streams](/data-streams/nav-streams) page for a complete list of available Net Asset Value streams. - - Execute your application. Replace `[STREAM_ID]` with your stream ID. - - ```bash - go run single-stream.go [STREAM_ID] - ``` - - Expect output similar to the following in your terminal: - - ```bash - 2025-07-26T12:44:54-05:00 Raw report data: {"fullReport":"0x...","feedID":"[STREAM_ID]","validFromTimestamp":1753551893,"observationsTimestamp":1753551893} - - 2025-07-26T12:44:54-05:00 - Decoded Report for Stream ID [STREAM_ID]: - ------------------------------------------ - Observations Timestamp : 1753551893 - Valid From Timestamp : 1753551893 - Expires At : 1756143893 - NAV Per Share : 1234500000000000000000 - NAV Date : 1753551893 - AUM : 12345000000000000000000000 - Ripcord : 0 - Link Fee (wei) : 17515847021884305 - Native Fee (wei) : 85879244037647 - ------------------------------------------ - ``` - -#### Decoded report details - -The decoded report includes: - -| Attribute | Value | Description | -| ------------------------ | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `Stream ID` | `[STREAM_ID]` | The unique identifier for the stream. | -| `Observations Timestamp` | `1753551893` | The timestamp indicating when the data was captured. | -| `Valid From Timestamp` | `1753551893` | The start validity timestamp for the report, indicating when the data becomes relevant. | -| `Expires At` | `1756143893` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. | -| `NAV Per Share` | `1234500000000000000000` | DON's consensus NAV Per Share value as reported by the Fund Manager (18 decimal precision). For readability: `1234.5`. | -| `NAV Date` | `1753551893` | Timestamp for the date the NAV Report was published by the Fund Manager. | -| `AUM` | `12345000000000000000000000` | DON's consensus for the total USD value of Assets Under Management (18 decimal precision). For readability: `12345000.0`. | -| `Ripcord` | `0` | Whether the API provider initiated a "pause" to the NAV reporting due to underlying data source issues. Possible values: `0` (normal state), `1` (paused state). | -| `Link Fee` | `17515847021884305` | The fee to pay in LINK tokens for onchain verification of the report data. | -| `Native Fee` | `85879244037647` | The fee to pay in the native blockchain token (e.g., ETH) for onchain verification. | - -**Important**: Always validate the ripcord status before consuming NAV data. When ripcord=1, do not consume any NAV data. - -#### Payload for onchain verification - -In this tutorial, you log and decode the `fullReport` payload to extract the report data. In a -production environment, you should verify the data to ensure its integrity and authenticity. Refer to the -[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) tutorial. - -### Fetch and decode reports for multiple streams - -1. Create a new Go file, `multiple-streams.go`, in your project directory: - - ```bash - touch multiple-streams.go - ``` - -1. Insert the following code example in your `multiple-streams.go` file: - - ```go - package main - - import ( - "context" - "fmt" - "os" - "time" - - streams "github.com/smartcontractkit/data-streams-sdk/go" - feed "github.com/smartcontractkit/data-streams-sdk/go/feed" - report "github.com/smartcontractkit/data-streams-sdk/go/report" - v9 "github.com/smartcontractkit/data-streams-sdk/go/report/v9" // Import the v9 report schema for NAV streams - ) - - func main() { - // Validate command-line arguments - if len(os.Args) < 3 { - fmt.Printf("Usage: go run multiple-streams.go [StreamID1] [StreamID2] ...\n"+ - "Example: go run multiple-streams.go [STREAM_ID_1] [STREAM_ID_2]\n") - os.Exit(1) - } - - // Get API credentials from environment variables - apiKey := os.Getenv("API_KEY") - apiSecret := os.Getenv("API_SECRET") - if apiKey == "" || apiSecret == "" { - fmt.Printf("API_KEY and API_SECRET environment variables must be set\n") - os.Exit(1) - } - - // Define the configuration for the SDK client - cfg := streams.Config{ - ApiKey: apiKey, - ApiSecret: apiSecret, - RestURL: "https://api.testnet-dataengine.chain.link", - Logger: streams.LogPrintf, - } - - // Initialize the SDK client - client, err := streams.New(cfg) - if err != nil { - cfg.Logger("Failed to create client: %v\n", err) - os.Exit(1) - } - - // Create context with timeout - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - // Parse Feed IDs - var ids []feed.ID - for _, arg := range os.Args[1:] { - var fid feed.ID - if err := fid.FromString(arg); err != nil { - cfg.Logger("Invalid feed ID format '%s': %v\n", arg, err) - continue - } - ids = append(ids, fid) - } - - - if len(ids) == 0 { - cfg.Logger("No valid feed IDs provided\n") - os.Exit(1) - } - - // Fetch reports for all streams - timestamp := uint64(time.Now().Unix()) - reportResponses, err := client.GetReports(ctx, ids, timestamp) - if err != nil { - cfg.Logger("Failed to get reports: %v\n", err) - os.Exit(1) - } - - // Process reports - for _, reportResponse := range reportResponses { - // Log the raw report data - cfg.Logger("Raw report data for Stream ID %s: %+v\n", - reportResponse.FeedID.String(), reportResponse) - - // Decode the report - decodedReport, err := report.Decode[v9.Data](reportResponse.FullReport) - if err != nil { - cfg.Logger("Failed to decode report for Stream ID %s: %v\n", - reportResponse.FeedID.String(), err) - continue // Skip to next report if decoding fails - } - - // Format and display the decoded report - fmt.Printf( - "\nDecoded Report for Stream ID %s:\n"+ - "------------------------------------------\n"+ - "Observations Timestamp : %d\n"+ - "Valid From Timestamp : %d\n"+ - "Expires At : %d\n"+ - "NAV Per Share : %s\n"+ - "NAV Date : %d\n"+ - "AUM : %s\n"+ - "Ripcord : %d\n"+ - "Link Fee (wei) : %s\n"+ - "Native Fee (wei) : %s\n"+ - "------------------------------------------\n", - reportResponse.FeedID.String(), - decodedReport.Data.ObservationsTimestamp, - decodedReport.Data.ValidFromTimestamp, - decodedReport.Data.ExpiresAt, - decodedReport.Data.NavPerShare.String(), - decodedReport.Data.NavDate, - decodedReport.Data.Aum.String(), - decodedReport.Data.Ripcord, - decodedReport.Data.LinkFee.String(), - decodedReport.Data.NativeFee.String(), - ) - } - } - ``` - -1. Before running the example, verify that your API credentials are still set in your current terminal session: - - ```bash - echo $API_KEY - echo $API_SECRET - ``` - - If the commands above don't show your credentials, set them again: - - ```bash - export API_KEY="" - export API_SECRET="" - ``` - -1. For this example, you will read from two NAV streams. Run your application. Replace `[STREAM_ID_1]` and `[STREAM_ID_2]` with your stream IDs. - - ```bash - go run multiple-streams.go [STREAM_ID_1] [STREAM_ID_2] - ``` - - Expect to see output similar to the following in your terminal: - - ```bash - 2024-12-14T17:53:30-05:00 Raw report data for Stream ID [STREAM_ID_1]: {"fullReport":"0x...","feedID":"[STREAM_ID_1]","validFromTimestamp":1734216809,"observationsTimestamp":1734216809} - - - Decoded Report for Stream ID [STREAM_ID_1]: - ------------------------------------------ - Observations Timestamp : 1753551893 - Valid From Timestamp : 1753551893 - Expires At : 1756143893 - NAV Per Share : 1234500000000000000000 - NAV Date : 1753551893 - AUM : 12345000000000000000000000 - Ripcord : 0 - Link Fee (wei) : 17515847021884305 - Native Fee (wei) : 85879244037647 - ------------------------------------------ - 2024-12-14T17:53:30-05:00 Raw report data for Stream ID [STREAM_ID_2]: {"fullReport":"0x...","feedID":"[STREAM_ID_2]","validFromTimestamp":1734216809,"observationsTimestamp":1734216809} - - - Decoded Report for Stream ID [STREAM_ID_2]: - ------------------------------------------ - Observations Timestamp : 1753551893 - Valid From Timestamp : 1753551893 - Expires At : 1756143893 - NAV Per Share : 987600000000000000000 - NAV Date : 1753551893 - AUM : 9876000000000000000000000 - Ripcord : 0 - Link Fee (wei) : 17515847021884305 - Native Fee (wei) : 85879244037647 - ------------------------------------------ - ``` - - Your application has successfully fetched and decoded data for both streams. - -#### Payload for onchain verification - -In this guide, you log and decode the `fullReport` payloads to extract the report data. In a -production environment, you should verify the data to ensure its integrity and authenticity. Refer to the -[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) guide. - -## Explanation - -### Initializing the client and configuration - -The Data Streams client is initialized in two steps: - -1. Configure the client with [`streams.Config`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/config.go#L10): - - ```go - cfg := streams.Config{ - ApiKey: os.Getenv("API_KEY"), - ApiSecret: os.Getenv("API_SECRET"), - RestURL: "https://api.testnet-dataengine.chain.link", - Logger: streams.LogPrintf, - } - ``` - - The configuration requires: - - - `ApiKey` and `ApiSecret` for authentication (required) - - `RestURL` for the API endpoint (required) - - `Logger` for debugging and error tracking (optional, defaults to `streams.LogPrintf`) - -2. Create the client with [`streams.New`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L56): - ```go - client, err := streams.New(cfg) - ``` - The client handles: - - Authentication with HMAC signatures - - Connection management and timeouts - - Error handling and retries - -### Fetching reports - -The SDK provides two main methods to fetch reports: - -1. Latest report for a single stream with [`GetLatestReport`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L130): - - ```go - reportResponse, err := client.GetLatestReport(ctx, feedID) - ``` - - - Takes a context and feed ID - - Returns a single `ReportResponse` with the most recent data - - No timestamp parameter needed - - Useful for real-time NAV monitoring - -2. Latest reports for multiple streams with [`GetReports`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L208): - - ```go - reportResponses, err := client.GetReports(ctx, ids, timestamp) - ``` - - - Takes context, feed IDs array, and Unix timestamp - - Returns array of `ReportResponse`, one per feed ID - - Timestamp determines the point in time for the reports - - Efficient for monitoring multiple NAV assets simultaneously - -Each API request automatically: - -- Handles authentication with API credentials -- Manages request timeouts via context -- Processes responses into structured types - -### Decoding reports - -Reports are decoded in two steps: - -1. Report decoding with [`report.Decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/report/report.go#L30): - - ```go - decodedReport, err := report.Decode[v9.Data](reportResponse.FullReport) - ``` - - This step: - - - Takes the raw `FullReport` bytes from the response - - Uses `v9.Data` schema for NAV streams - - Validates the format and decodes using Go generics - - Returns a structured report with typed data - -2. Data access: - ```go - data := decodedReport.Data - navPerShare := data.NavPerShare.String() // Convert big number to string - navDate := data.NavDate // Unix timestamp - aum := data.Aum.String() // Convert big number to string - ripcord := data.Ripcord // Ripcord flag (0: normal, 1: paused) - validFrom := data.ValidFromTimestamp // Unix timestamp - expiresAt := data.ExpiresAt // Unix timestamp - ``` - Provides access to: - - NAV per share value (as big number) - - NAV date timestamp - - Assets under management total (as big number) - - Ripcord safety flag - - Fee information (LINK and native token fees) - - Timestamp data (validity period) - - All numeric values require `.String()` for display - -### Error handling - -The SDK uses Go's standard error handling patterns with some enhancements: - -1. Context management: - - ```go - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - ``` - - - Sets request timeouts for API calls - - `defer cancel()` ensures cleanup of resources - - Same context pattern for both single and multiple reports - -2. Error checking: - - ```go - if err != nil { - cfg.Logger("Failed to decode report: %v\n", err) - os.Exit(1) // Fatal errors: exit the program - // or - continue // Non-fatal errors: skip this report - } - ``` - - - Fatal errors (client creation, no valid feeds) use `os.Exit(1)` - - Non-fatal errors (single report decode) use `continue` - - All errors are logged before handling - -3. SDK logging: - ```go - cfg.Logger("Raw report data: %+v\n", reportResponse) - ``` - - Uses configured logger for SDK operations - - `fmt.Printf` for user-facing output - - Debug information includes raw report data - - Structured error messages with context - -The decoded data can be used for further processing or display in your application. For production environments, you must verify the data onchain using the provided `fullReport` payload and always validate the ripcord status before consuming NAV data. diff --git a/src/content/data-streams/tutorials/api-nav-rust.mdx b/src/content/data-streams/tutorials/api-nav-rust.mdx deleted file mode 100644 index dcd185a1059..00000000000 --- a/src/content/data-streams/tutorials/api-nav-rust.mdx +++ /dev/null @@ -1,308 +0,0 @@ ---- -section: dataStreams -date: Last Modified -title: "Fetch and decode V9 reports using the Rust SDK" -metadata: - title: "Fetch and Decode Net Asset Value Data with Rust SDK | Chainlink Data Streams" - description: "Learn how to use the Rust SDK to fetch and decode Net Asset Value (NAV) market data reports with V9 schema from Chainlink Data Streams." - keywords: ["Rust SDK", "NAV", "Net Asset Value", "V9 Reports", "API Tutorial", "Data Streams", "Fund Management"] -whatsnext: - { - "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/ws-nav-rust", - "Learn how to verify your data onchain": "/data-streams/reference/onchain-verification", - "Find the list of available Stream IDs": "/data-streams/nav-streams", - } ---- - -import { CopyText, PageTabs } from "@components" -import DataStreams from "@features/data-streams/common/DataStreams.astro" - - - - - -In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/reference/rust-sdk) for Rust to fetch and decode [V9 reports](/data-streams/reference/report-schema-v9) for [Net Asset Value (NAV) streams](/data-streams/nav-streams) from the Data Streams Aggregation Network. You'll set up your Rust project, retrieve reports, decode them, and log their attributes. - - - -## Requirements - -- **Rust**: Make sure you have Rust installed. You can install Rust by following the instructions on the official [Rust website](https://www.rust-lang.org/tools/install). -- **API Credentials**: Access to Data Streams requires API credentials. If you haven't already, [contact us](https://chainlinkcommunity.typeform.com/datastreams?typeform-source=docs.chain.link#ref_id=docs) to request mainnet or testnet access. - -## Tutorial - -You'll start with the set up of your Rust project. Next, you'll fetch and decode reports for NAV streams and log their attributes to your terminal. - -### Set up your Rust project - -1. Create a new directory for your project and navigate to it: - - ```bash - mkdir my-data-streams-project && cd my-data-streams-project - ``` - -1. Initialize a new Rust project: - - ```bash - cargo init - ``` - -1. Add the following dependencies to your `Cargo.toml` file: - - ```toml - [dependencies] - chainlink-data-streams-sdk = "1.0.3" - chainlink-data-streams-report = "1.0.3" - tokio = { version = "1.4", features = ["full"] } - hex = "0.4" - ``` - -### Fetch and decode a report with a single stream - -1. Replace the contents of `src/main.rs` with the following code: - - ```rust - use chainlink_data_streams_report::feed_id::ID; - use chainlink_data_streams_report::report::{ decode_full_report, v9::ReportDataV9 }; - use chainlink_data_streams_sdk::client::Client; - use chainlink_data_streams_sdk::config::Config; - use std::env; - use std::error::Error; - - #[tokio::main] - async fn main() -> Result<(), Box> { - // Get feed ID from command line arguments - let args: Vec = env::args().collect(); - if args.len() < 2 { - eprintln!("Usage: cargo run [FeedID]"); - std::process::exit(1); - } - let feed_id_input = &args[1]; - - // Get API credentials from environment variables - let api_key = env::var("API_KEY").expect("API_KEY must be set"); - let api_secret = env::var("API_SECRET").expect("API_SECRET must be set"); - - // Initialize the configuration - let config = Config::new( - api_key, - api_secret, - "https://api.testnet-dataengine.chain.link".to_string(), - "wss://api.testnet-dataengine.chain.link/ws".to_string() - ).build()?; - - // Initialize the client - let client = Client::new(config)?; - - // Parse the feed ID - let feed_id = ID::from_hex_str(feed_id_input)?; - - // Fetch the latest report - let response = client.get_latest_report(feed_id).await?; - println!("\nRaw report data: {:?}\n", response.report); - - // Decode the report - let full_report = hex::decode(&response.report.full_report[2..])?; - let (_report_context, report_blob) = decode_full_report(&full_report)?; - let report_data = ReportDataV9::decode(&report_blob)?; - - // Print decoded report details - println!("\nDecoded Report for Stream ID {}:", feed_id_input); - println!("------------------------------------------"); - println!("Valid From Timestamp : {}", response.report.valid_from_timestamp); - println!("Observations Timestamp: {}", response.report.observations_timestamp); - println!("Expires At : {}", report_data.expires_at); - println!("NAV Per Share : {}", report_data.nav_per_share); - println!("NAV Date : {}", report_data.nav_date); - println!("AUM : {}", report_data.aum); - println!("Ripcord : {}", report_data.ripcord); - println!("Link Fee : {}", report_data.link_fee); - println!("Native Fee : {}", report_data.native_fee); - println!("------------------------------------------"); - - Ok(()) - } - - ``` - -1. Set up your API credentials as environment variables: - - ```bash - export API_KEY="" - export API_SECRET="" - ``` - - Replace `` and `` with your API credentials. - -1. For this example, you will read from a NAV stream. See the [Data Streams NAV streams](/data-streams/nav-streams) page for a complete list of available Net Asset Value streams. - - Build and run your application. Replace `[STREAM_ID]` with your stream ID. - - ```bash - cargo run -- [STREAM_ID] - ``` - - Expect output similar to the following in your terminal: - - ```bash - Raw report data: Report { feed_id: [STREAM_ID], valid_from_timestamp: 1734125487, observations_timestamp: 1734125487, full_report: "0x..." } - - - Decoded Report for Stream ID [STREAM_ID]: - ------------------------------------------ - Valid From Timestamp : 1753554142 - Observations Timestamp: 1753554142 - Expires At : 1756146142 - NAV Per Share : 1234500000000000000000 - NAV Date : 1753554142 - AUM : 12345000000000000000000000 - Ripcord : 0 - Link Fee : 17474419425934927 - Native Fee : 85926694786199 - ------------------------------------------ - ``` - -#### Decoded report details - -The decoded report details include: - -| Attribute | Value | Description | -| ------------------------ | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `Stream ID` | `[STREAM_ID]` | The unique identifier for the stream. | -| `Valid From Timestamp` | `1753554142` | The start validity timestamp for the report, indicating when the data becomes relevant. | -| `Observations Timestamp` | `1753554142` | The timestamp indicating when the data was captured. | -| `Expires At` | `1756146142` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. | -| `NAV Per Share` | `1234500000000000000000` | DON's consensus NAV Per Share value as reported by the Fund Manager (18 decimal precision). For readability: `1234.5`. | -| `NAV Date` | `1753554142` | Timestamp for the date the NAV Report was published by the Fund Manager. | -| `AUM` | `12345000000000000000000000` | DON's consensus for the total USD value of Assets Under Management (18 decimal precision). For readability: `12345000.0`. | -| `Ripcord` | `0` | Whether the API provider initiated a "pause" to the NAV reporting due to underlying data source issues. Possible values: `0` (normal state), `1` (paused state). | -| `Link Fee` | `17474419425934927` | The fee to pay in LINK tokens for onchain verification of the report data. | -| `Native Fee` | `85926694786199` | The fee to pay in the native blockchain token (e.g., ETH) for onchain verification. | - -**Important**: Always validate the ripcord status before consuming NAV data. When ripcord=1, do not consume any NAV data. - -#### Payload for onchain verification - -In this tutorial, you log and decode the `full_report` payload to extract the report data. In a -production environment, you should verify the data to ensure its integrity and authenticity. Refer to the -[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) tutorial. - -## Explanation - -### Initializing the API client and configuration - -The API client is initialized in two steps: - -1. [`Config::new`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/config.rs#L131) creates a configuration with your API credentials and endpoints. This function: - - - Validates your API key and secret - - Sets up the REST API endpoint for data retrieval - - Configures optional settings like TLS verification - -2. [`Client::new`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/client.rs#L131) creates the HTTP client with your configuration. This client: - - Handles authentication automatically - - Manages HTTP connections efficiently - - Implements retry logic for failed requests - -### Fetching reports - -The SDK provides several methods to fetch reports through the REST API: - -1. Latest report: [`get_latest_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/client.rs#L165) retrieves the most recent report for a feed: - - - Takes a feed ID as input - - Returns a single report with the latest timestamp - - Useful for applications that need the most current data - -2. Historical report: [`get_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/client.rs#L242) fetches a report at a specific timestamp: - - Takes both feed ID and timestamp - - Returns the report closest to the requested timestamp - - Helpful for historical analysis or verification - -Each API request automatically: - -- Generates HMAC authentication headers -- Includes proper timestamps -- Handles HTTP response status codes -- Deserializes the JSON response into Rust structures - -### Decoding reports - -Reports are decoded in three stages: - -1. Hex decoding: The `full_report` field comes as a hex string prefixed with "0x": - - ```rust - let full_report = hex::decode(&response.report.full_report[2..])?; - ``` - -2. Report separation: [`decode_full_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report.rs#L77) splits the binary data: - - - Extracts the report context (metadata) - - Isolates the report blob (actual data) - - Validates the report format - -3. Data extraction: [`ReportDataV9::decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report/v9.rs#L60) parses the report blob into structured data: - - NAV per share value - - NAV date timestamp - - Assets under management total - - Ripcord safety flag - - Fee information for onchain verification - - Timestamp information - -### Error handling - -The example demonstrates Rust's robust error handling: - -1. Type-safe errors: - - - Uses custom error types for different failure scenarios - - Implements the `Error` trait for proper error propagation - - Provides detailed error messages for debugging - -2. Error propagation: - - - Uses the `?` operator for clean error handling - - Converts errors between types when needed - - Bubbles up errors to the main function - -3. Input validation: - - Checks command-line arguments - - Validates environment variables - - Verifies feed ID format - -The decoded data can be used for further processing, analysis, or display in your application. For production environments, you must verify the data onchain using the provided `full_report` payload and always validate the ripcord status before consuming NAV data. diff --git a/src/content/data-streams/tutorials/api-rwa-go.mdx b/src/content/data-streams/tutorials/api-rwa-go.mdx deleted file mode 100644 index cc6a4d8316e..00000000000 --- a/src/content/data-streams/tutorials/api-rwa-go.mdx +++ /dev/null @@ -1,603 +0,0 @@ ---- -section: dataStreams -date: Last Modified -title: "Fetch and decode V8 reports using the Go SDK" -metadata: - title: "Fetch and Decode Real World Asset Data with Go SDK | Chainlink Data Streams" - description: "Learn how to use the Go SDK to fetch and decode Real World Asset (RWA) market data reports with V8 schema from Chainlink Data Streams." - keywords: ["Go SDK", "Golang", "RWA", "Real World Assets", "V8 Reports", "API Tutorial", "Data Streams"] -whatsnext: - { - "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/ws-rwa-go", - "Learn how to verify your data onchain": "/data-streams/reference/data-streams-api/onchain-verification", - "Find the list of available Stream IDs": "/data-streams/rwa-streams", - } ---- - -import { CopyText, PageTabs } from "@components" -import DataStreams from "@features/data-streams/common/DataStreams.astro" - - - - - -In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/reference/data-streams-api/go-sdk) for Go to fetch and decode [V8 reports](/data-streams/reference/report-schema-v8) for [Real World Assets (RWAs) streams](/data-streams/rwa-streams) from the Data Streams Aggregation Network. You'll set up your Go project, retrieve reports, decode them, and log their attributes. - - - -## Requirements - -- **Git**: Make sure you have Git installed. You can check your current version by running in your terminal and download the latest version from the official [Git website](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) if necessary. -- **Go Version**: Make sure you have Go version 1.21 or higher. You can check your current version by running `go version` in your terminal and download the latest version from the official [Go website](https://go.dev/) if necessary. -- **API Credentials**: Access to Data Streams requires API credentials. If you haven't already, [contact us](https://chainlinkcommunity.typeform.com/datastreams?typeform-source=docs.chain.link#ref_id=docs) to request mainnet or testnet access. - -## Tutorial - -You'll start with the set up of your Go project. Next, you'll fetch and decode reports for both single and multiple [RWA streams](/data-streams/rwa-streams), and log their attributes to your terminal. - -### Set up your Go project - -1. Create a new directory for your project and navigate to it: - - ```bash - mkdir my-data-streams-project - cd my-data-streams-project - ``` - -1. Initialize a new Go module: - - ```bash - go mod init my-data-streams-project - ``` - -1. Install the Data Streams SDK: - - ```bash - go get github.com/smartcontractkit/data-streams-sdk/go - ``` - -### Fetch and decode a report with a single stream - -1. Create a new Go file, `single-stream.go`, in your project directory: - - ```bash - touch single-stream.go - ``` - -1. Insert the following code example and save your `single-stream.go` file: - - ```go - package main - - import ( - "context" - "fmt" - "os" - "time" - - streams "github.com/smartcontractkit/data-streams-sdk/go" - feed "github.com/smartcontractkit/data-streams-sdk/go/feed" - report "github.com/smartcontractkit/data-streams-sdk/go/report" - v8 "github.com/smartcontractkit/data-streams-sdk/go/report/v8" // Import the v8 report schema for RWA streams. For Crypto streams, use the v3 schema. - ) - - func main() { - // Validate command-line arguments - if len(os.Args) < 2 { - fmt.Printf("Usage: go run main.go [FeedID]\nExample: go run main.go [FEED_ID]\n") - os.Exit(1) - } - feedIDInput := os.Args[1] - - // Get API credentials from environment variables - apiKey := os.Getenv("API_KEY") - apiSecret := os.Getenv("API_SECRET") - if apiKey == "" || apiSecret == "" { - fmt.Printf("API_KEY and API_SECRET environment variables must be set\n") - os.Exit(1) - } - - // Define the configuration for the SDK client - cfg := streams.Config{ - ApiKey: apiKey, - ApiSecret: apiSecret, - RestURL: "https://api.testnet-dataengine.chain.link", - Logger: streams.LogPrintf, - } - - // Initialize the SDK client - client, err := streams.New(cfg) - if err != nil { - cfg.Logger("Failed to create client: %v\n", err) - os.Exit(1) - } - - // Create context with timeout - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - // Parse the feed ID - var feedID feed.ID - if err := feedID.FromString(feedIDInput); err != nil { - cfg.Logger("Invalid feed ID format '%s': %v\n", feedIDInput, err) - os.Exit(1) - } - - // Fetch the latest report - reportResponse, err := client.GetLatestReport(ctx, feedID) - if err != nil { - cfg.Logger("Failed to get latest report: %v\n", err) - os.Exit(1) - } - - // Log the raw report data - cfg.Logger("Raw report data: %+v\n", reportResponse) - - // Decode the report - decodedReport, err := report.Decode[v8.Data](reportResponse.FullReport) - if err != nil { - cfg.Logger("Failed to decode report: %v\n", err) - os.Exit(1) - } - - // Format and display the decoded report - fmt.Printf( - "\nDecoded Report for Stream ID %s:\n"+ - "------------------------------------------\n"+ - "Observations Timestamp : %d\n"+ - "Valid From Timestamp : %d\n"+ - "Last Update Timestamp : %d\n"+ - "Expires At : %d\n"+ - "Mid Price : %s\n"+ - "Market Status : %d\n"+ - "Link Fee (wei) : %s\n"+ - "Native Fee (wei) : %s\n"+ - "------------------------------------------\n", - feedIDInput, - decodedReport.Data.ObservationsTimestamp, - decodedReport.Data.ValidFromTimestamp, - decodedReport.Data.LastUpdateTimestamp, - decodedReport.Data.ExpiresAt, - decodedReport.Data.MidPrice.String(), - decodedReport.Data.MarketStatus, - decodedReport.Data.LinkFee.String(), - decodedReport.Data.NativeFee.String(), - ) - } - - ``` - -1. Download the required dependencies and update the `go.mod` and `go.sum` files: - - ```bash - go mod tidy - ``` - -1. Set up the SDK client configuration within `single-stream.go` with your API credentials and the REST endpoint: - - ```go - cfg := streams.Config{ - ApiKey: os.Getenv("API_KEY"), - ApiSecret: os.Getenv("API_SECRET"), - RestURL: "https://api.testnet-dataengine.chain.link", - Logger: streams.LogPrintf, - } - ``` - - - Set your API credentials as environment variables: - - ```bash - export API_KEY="" - export API_SECRET="" - ``` - - Replace `` and `` with your API credentials. - - - `RestURL` is the REST endpoint to poll for specific reports. See the [Data Streams Interface](/data-streams/reference/data-streams-api/interface-api#domains) page for more information. - - See the [SDK Reference](/data-streams/reference/data-streams-api/go-sdk#config-struct) page for more configuration options. - -1. For this example, you will read from an RWA stream. See the [Data Streams RWA streams](/data-streams/rwa-streams) page for a complete list of available Real World Assets. - - Execute your application. Replace `[STREAM_ID]` with your stream ID. - - ```bash - go run single-stream.go [STREAM_ID] - ``` - - Expect output similar to the following in your terminal: - - ```bash - 2025-07-26T12:44:54-05:00 Raw report data: {"fullReport":"0x...","feedID":"[STREAM_ID]","validFromTimestamp":1753551893,"observationsTimestamp":1753551893} - - 2025-07-26T12:44:54-05:00 - Decoded Report for Stream ID [STREAM_ID]: - ------------------------------------------ - Observations Timestamp : 1753551893 - Valid From Timestamp : 1753551893 - Last Update Timestamp : 1753476931520000000 - Expires At : 1756143893 - Mid Price : 213940000000000000000 - Market Status : 1 - Link Fee (wei) : 17515847021884305 - Native Fee (wei) : 85879244037647 - ------------------------------------------ - ``` - -#### Decoded report details - -The decoded report includes: - -| Attribute | Value | Description | -| ------------------------ | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -| `Stream ID` | `[STREAM_ID]` | The unique identifier for the stream. | -| `Observations Timestamp` | `1753551893` | The timestamp indicating when the data was captured. | -| `Valid From Timestamp` | `1753551893` | The start validity timestamp for the report, indicating when the data becomes relevant. | -| `Last Update Timestamp` | `1753476931520000000` | The timestamp of the last valid price update, in nanoseconds since epoch. | -| `Expires At` | `1756143893` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. | -| `Mid Price` | `213940000000000000000` | The observed median price in the report. For readability: `213.94`. | -| `Market Status` | `1` | The DON's consensus on whether the market is currently open. Possible values: `0` (`Unknown`), `1` (`Closed`), `2` (`Open`). | -| `Link Fee` | `17515847021884305` | The fee to pay in LINK tokens for onchain verification of the report data. | -| `Native Fee` | `85879244037647` | The fee to pay in the native blockchain token (e.g., ETH) for onchain verification. | - -#### Payload for onchain verification - -In this tutorial, you log and decode the `fullReport` payload to extract the report data. In a -production environment, you should verify the data to ensure its integrity and authenticity. Refer to the -[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) tutorial. - -### Fetch and decode reports for multiple streams - -1. Create a new Go file, `multiple-streams.go`, in your project directory: - - ```bash - touch multiple-streams.go - ``` - -1. Insert the following code example in your `multiple-streams.go` file: - - ```go - package main - - import ( - "context" - "fmt" - "os" - "time" - - streams "github.com/smartcontractkit/data-streams-sdk/go" - feed "github.com/smartcontractkit/data-streams-sdk/go/feed" - report "github.com/smartcontractkit/data-streams-sdk/go/report" - v8 "github.com/smartcontractkit/data-streams-sdk/go/report/v8" // Import the v8 report schema for RWA streams - ) - - func main() { - // Validate command-line arguments - if len(os.Args) < 3 { - fmt.Printf("Usage: go run multiple-streams.go [StreamID1] [StreamID2] ...\n"+ - "Example: go run multiple-streams.go [STREAM_ID_1] [STREAM_ID_2]\n") - os.Exit(1) - } - - // Get API credentials from environment variables - apiKey := os.Getenv("API_KEY") - apiSecret := os.Getenv("API_SECRET") - if apiKey == "" || apiSecret == "" { - fmt.Printf("API_KEY and API_SECRET environment variables must be set\n") - os.Exit(1) - } - - // Define the configuration for the SDK client - cfg := streams.Config{ - ApiKey: apiKey, - ApiSecret: apiSecret, - RestURL: "https://api.testnet-dataengine.chain.link", - Logger: streams.LogPrintf, - } - - // Initialize the SDK client - client, err := streams.New(cfg) - if err != nil { - cfg.Logger("Failed to create client: %v\n", err) - os.Exit(1) - } - - // Create context with timeout - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - // Parse Feed IDs - var ids []feed.ID - for _, arg := range os.Args[1:] { - var fid feed.ID - if err := fid.FromString(arg); err != nil { - cfg.Logger("Invalid feed ID format '%s': %v\n", arg, err) - continue - } - ids = append(ids, fid) - } - - if len(ids) == 0 { - cfg.Logger("No valid feed IDs provided\n") - os.Exit(1) - } - - // Fetch reports for all streams - timestamp := uint64(time.Now().Unix()) - reportResponses, err := client.GetReports(ctx, ids, timestamp) - if err != nil { - cfg.Logger("Failed to get reports: %v\n", err) - os.Exit(1) - } - - // Process reports - for _, reportResponse := range reportResponses { - // Log the raw report data - cfg.Logger("Raw report data for Stream ID %s: %+v\n", - reportResponse.FeedID.String(), reportResponse) - - // Decode the report - decodedReport, err := report.Decode[v8.Data](reportResponse.FullReport) - if err != nil { - cfg.Logger("Failed to decode report for Stream ID %s: %v\n", - reportResponse.FeedID.String(), err) - continue // Skip to next report if decoding fails - } - - // Format and display the decoded report - fmt.Printf( - "\nDecoded Report for Stream ID %s:\n"+ - "------------------------------------------\n"+ - "Observations Timestamp : %d\n"+ - "Valid From Timestamp : %d\n"+ - "Last Update Timestamp : %d\n"+ - "Expires At : %d\n"+ - "Mid Price : %s\n"+ - "Market Status : %d\n"+ - "Link Fee (wei) : %s\n"+ - "Native Fee (wei) : %s\n"+ - "------------------------------------------\n", - feedIDInput, - decodedReport.Data.ObservationsTimestamp, - decodedReport.Data.ValidFromTimestamp, - decodedReport.Data.LastUpdateTimestamp, - decodedReport.Data.ExpiresAt, - decodedReport.Data.MidPrice.String(), - decodedReport.Data.MarketStatus, - decodedReport.Data.LinkFee.String(), - decodedReport.Data.NativeFee.String(), - ) - } - } - ``` - -1. Before running the example, verify that your API credentials are still set in your current terminal session: - - ```bash - echo $API_KEY - echo $API_SECRET - ``` - - If the commands above don't show your credentials, set them again: - - ```bash - export API_KEY="" - export API_SECRET="" - ``` - -1. For this example, you will read from two RWA streams. Run your application. Replace `[STREAM_ID_1]` and `[STREAM_ID_2]` with your stream IDs. - - ```bash - go run multiple-streams.go [STREAM_ID_1] [STREAM_ID_2] - ``` - - Expect to see output similar to the following in your terminal: - - ```bash - 2024-12-14T17:53:30-05:00 Raw report data for Stream ID [STREAM_ID_1]: {"fullReport":"0x...","feedID":"[STREAM_ID_1]","validFromTimestamp":1734216809,"observationsTimestamp":1734216809} - - - Decoded Report for Stream ID [STREAM_ID_1]: - ------------------------------------------ - Observations Timestamp : 1753551893 - Valid From Timestamp : 1753551893 - Last Update Timestamp : 1753476931520000000 - Expires At : 1756143893 - Mid Price : 213940000000000000000 - Market Status : 1 - Link Fee (wei) : 17515847021884305 - Native Fee (wei) : 85879244037647 - ------------------------------------------ - 2024-12-14T17:53:30-05:00 Raw report data for Stream ID [STREAM_ID_2]: {"fullReport":"0x...","feedID":"[STREAM_ID_2]","validFromTimestamp":1734216809,"observationsTimestamp":1734216809} - - - Decoded Report for Stream ID [STREAM_ID_2]: - ------------------------------------------ - Observations Timestamp : 1753551893 - Valid From Timestamp : 1753551893 - Last Update Timestamp : 1753476931520000000 - Expires At : 1756143893 - Mid Price : 213940000000000000000 - Market Status : 1 - Link Fee (wei) : 17515847021884305 - Native Fee (wei) : 85879244037647 - ------------------------------------------ - ``` - - Your application has successfully fetched and decoded data for both streams. - -#### Payload for onchain verification - -In this guide, you log and decode the `fullReport` payloads to extract the report data. In a -production environment, you should verify the data to ensure its integrity and authenticity. Refer to the -[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) guide. - -## Explanation - -### Initializing the client and configuration - -The Data Streams client is initialized in two steps: - -1. Configure the client with [`streams.Config`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/config.go#L10): - - ```go - cfg := streams.Config{ - ApiKey: os.Getenv("API_KEY"), - ApiSecret: os.Getenv("API_SECRET"), - RestURL: "https://api.testnet-dataengine.chain.link", - Logger: streams.LogPrintf, - } - ``` - - The configuration requires: - - - `ApiKey` and `ApiSecret` for authentication (required) - - `RestURL` for the API endpoint (required) - - `Logger` for debugging and error tracking (optional, defaults to `streams.LogPrintf`) - -2. Create the client with [`streams.New`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L56): - ```go - client, err := streams.New(cfg) - ``` - The client handles: - - Authentication with HMAC signatures - - Connection management and timeouts - - Error handling and retries - -### Fetching reports - -The SDK provides two main methods to fetch reports: - -1. Latest report for a single stream with [`GetLatestReport`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L130): - - ```go - reportResponse, err := client.GetLatestReport(ctx, feedID) - ``` - - - Takes a context and feed ID - - Returns a single `ReportResponse` with the most recent data - - No timestamp parameter needed - - Useful for real-time price monitoring - -2. Latest reports for multiple streams with [`GetReports`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L208): - - ```go - reportResponses, err := client.GetReports(ctx, ids, timestamp) - ``` - - - Takes context, feed IDs array, and Unix timestamp - - Returns array of `ReportResponse`, one per feed ID - - Timestamp determines the point in time for the reports - - Efficient for monitoring multiple assets simultaneously - -Each API request automatically: - -- Handles authentication with API credentials -- Manages request timeouts via context -- Processes responses into structured types - -### Decoding reports - -Reports are decoded in two steps: - -1. Report decoding with [`report.Decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/report/report.go#L30): - - ```go - decodedReport, err := report.Decode[v8.Data](reportResponse.FullReport) - ``` - - This step: - - - Takes the raw `FullReport` bytes from the response - - Uses `v8.Data` schema for RWA streams (use `v3.Data` for Crypto streams) - - Validates the format and decodes using Go generics - - Returns a structured report with typed data - -2. Data access: - ```go - data := decodedReport.Data - price := data.MidPrice.String(), // Convert big number to string - validFrom := data.ValidFromTimestamp // Unix timestamp - expiresAt := data.ExpiresAt // Unix timestamp - marketStatus := data.MarketStatus // Market status (0: Unknown, 1: Closed, 2: Open) - ``` - Provides access to: - - Benchmark price (as big number) - - Fee information (LINK and native token fees) - - Timestamp data (validity period) - - Market status information - - All numeric values require `.String()` for display - -### Error handling - -The SDK uses Go's standard error handling patterns with some enhancements: - -1. Context management: - - ```go - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - ``` - - - Sets request timeouts for API calls - - `defer cancel()` ensures cleanup of resources - - Same context pattern for both single and multiple reports - -2. Error checking: - - ```go - if err != nil { - cfg.Logger("Failed to decode report: %v\n", err) - os.Exit(1) // Fatal errors: exit the program - // or - continue // Non-fatal errors: skip this report - } - ``` - - - Fatal errors (client creation, no valid feeds) use `os.Exit(1)` - - Non-fatal errors (single report decode) use `continue` - - All errors are logged before handling - -3. SDK logging: - ```go - cfg.Logger("Raw report data: %+v\n", reportResponse) - ``` - - Uses configured logger for SDK operations - - `fmt.Printf` for user-facing output - - Debug information includes raw report data - - Structured error messages with context - -The decoded data can be used for further processing or display in your application. For production environments, you must verify the data onchain using the provided `fullReport` payload. diff --git a/src/content/data-streams/tutorials/api-rwa-rust.mdx b/src/content/data-streams/tutorials/api-rwa-rust.mdx deleted file mode 100644 index 1b821059c90..00000000000 --- a/src/content/data-streams/tutorials/api-rwa-rust.mdx +++ /dev/null @@ -1,302 +0,0 @@ ---- -section: dataStreams -date: Last Modified -title: "Fetch and decode V8 reports using the Rust SDK" -metadata: - title: "Fetch and Decode Real World Asset Data with Rust SDK | Chainlink Data Streams" - description: "Learn how to use the Rust SDK to fetch and decode Real World Asset (RWA) market data reports with V8 schema from Chainlink Data Streams." - keywords: - ["Rust SDK", "RWA", "Real World Assets", "V8 Reports", "API Tutorial", "Data Streams", "Forex", "Commodities"] -whatsnext: - { - "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/ws-rwa-rust", - "Learn how to verify your data onchain": "/data-streams/reference/data-streams-api/onchain-verification", - "Find the list of available Stream IDs": "/data-streams/rwa-streams", - } ---- - -import { CopyText, PageTabs } from "@components" -import DataStreams from "@features/data-streams/common/DataStreams.astro" - - - - - -In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/reference/data-streams-api/rust-sdk) for Rust to fetch and decode [V8 reports](/data-streams/reference/report-schema-v8) for [Real World Assets (RWAs) streams](/data-streams/rwa-streams) from the Data Streams Aggregation Network. You'll set up your Rust project, retrieve reports, decode them, and log their attributes. - - - -## Requirements - -- **Rust**: Make sure you have Rust installed. You can install Rust by following the instructions on the official [Rust website](https://www.rust-lang.org/tools/install). -- **API Credentials**: Access to Data Streams requires API credentials. If you haven't already, [contact us](https://chainlinkcommunity.typeform.com/datastreams?typeform-source=docs.chain.link#ref_id=docs) to request mainnet or testnet access. - -## Tutorial - -You'll start with the set up of your Rust project. Next, you'll fetch and decode reports for RWA streams and log their attributes to your terminal. - -### Set up your Rust project - -1. Create a new directory for your project and navigate to it: - - ```bash - mkdir my-data-streams-project && cd my-data-streams-project - ``` - -1. Initialize a new Rust project: - - ```bash - cargo init - ``` - -1. Add the following dependencies to your `Cargo.toml` file: - - ```toml - [dependencies] - chainlink-data-streams-sdk = "1.0.3" - chainlink-data-streams-report = "1.0.3" - tokio = { version = "1.4", features = ["full"] } - hex = "0.4" - ``` - -### Fetch and decode a report with a single stream - -1. Replace the contents of `src/main.rs` with the following code: - - ```rust - use chainlink_data_streams_report::feed_id::ID; - use chainlink_data_streams_report::report::{ decode_full_report, v8::ReportDataV8 }; - use chainlink_data_streams_sdk::client::Client; - use chainlink_data_streams_sdk::config::Config; - use std::env; - use std::error::Error; - - #[tokio::main] - async fn main() -> Result<(), Box> { - // Get feed ID from command line arguments - let args: Vec = env::args().collect(); - if args.len() < 2 { - eprintln!("Usage: cargo run [FeedID]"); - std::process::exit(1); - } - let feed_id_input = &args[1]; - - // Get API credentials from environment variables - let api_key = env::var("API_KEY").expect("API_KEY must be set"); - let api_secret = env::var("API_SECRET").expect("API_SECRET must be set"); - - // Initialize the configuration - let config = Config::new( - api_key, - api_secret, - "https://api.testnet-dataengine.chain.link".to_string(), - "wss://api.testnet-dataengine.chain.link/ws".to_string() - ).build()?; - - // Initialize the client - let client = Client::new(config)?; - - // Parse the feed ID - let feed_id = ID::from_hex_str(feed_id_input)?; - - // Fetch the latest report - let response = client.get_latest_report(feed_id).await?; - println!("\nRaw report data: {:?}\n", response.report); - - // Decode the report - let full_report = hex::decode(&response.report.full_report[2..])?; - let (_report_context, report_blob) = decode_full_report(&full_report)?; - let report_data = ReportDataV8::decode(&report_blob)?; - - // Print decoded report details - println!("\nDecoded Report for Stream ID {}:", feed_id_input); - println!("------------------------------------------"); - println!("Valid From Timestamp : {}", response.report.valid_from_timestamp); - println!("Observations Timestamp: {}", response.report.observations_timestamp); - println!("Last Update Timestamp : {}", report_data.last_update_timestamp); - println!("Expires At : {}", report_data.expires_at); - println!("Mid Price : {}", report_data.mid_price); - println!("Link Fee : {}", report_data.link_fee); - println!("Native Fee : {}", report_data.native_fee); - println!("Market Status : {}", report_data.market_status); - println!("------------------------------------------"); - - Ok(()) - } - - ``` - -1. Set up your API credentials as environment variables: - - ```bash - export API_KEY="" - export API_SECRET="" - ``` - - Replace `` and `` with your API credentials. - -1. For this example, you will read from an RWA stream. See the [Data Streams RWA streams](/data-streams/rwa-streams) page for a complete list of available Real World Assets. - - Build and run your application. Replace `[STREAM_ID]` with your stream ID. - - ```bash - cargo run -- [STREAM_ID] - ``` - - Expect output similar to the following in your terminal: - - ```bash - Raw report data: Report { feed_id: [STREAM_ID], valid_from_timestamp: 1734125487, observations_timestamp: 1734125487, full_report: "0x..." } - - - Decoded Report for Stream ID [STREAM_ID]: - ------------------------------------------ - Valid From Timestamp : 1753554142 - Observations Timestamp: 1753554142 - Last Update Timestamp : 1753476931520000000 - Expires At : 1756146142 - Mid Price : 213940000000000000000 - Link Fee : 17474419425934927 - Native Fee : 85926694786199 - Market Status : 1 - ------------------------------------------ - ``` - -#### Decoded report details - -The decoded report details include: - -| Attribute | Value | Description | -| ------------------------ | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -| `Stream ID` | `[STREAM_ID]` | The unique identifier for the stream. | -| `Valid From Timestamp` | `1753554142` | The start validity timestamp for the report, indicating when the data becomes relevant. | -| `Observations Timestamp` | `1753554142` | The timestamp indicating when the data was captured. | -| `Last Update Timestamp` | `1753476931520000000` | The timestamp of the last valid price update, in nanoseconds since epoch. | -| `Expires At` | `1756146142` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. | -| `Mid Price` | `213940000000000000000` | The observed median price in the report. For readability: `213.94`. | -| `Link Fee` | `17474419425934927` | The fee to pay in LINK tokens for onchain verification of the report data. | -| `Native Fee` | `85926694786199` | The fee to pay in the native blockchain token (e.g., ETH) for onchain verification. | -| `Market Status` | `1` | The DON's consensus on whether the market is currently open. Possible values: `0` (`Unknown`), `1` (`Closed`), `2` (`Open`). | - -#### Payload for onchain verification - -In this tutorial, you log and decode the `full_report` payload to extract the report data. In a -production environment, you should verify the data to ensure its integrity and authenticity. Refer to the -[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) tutorial. - -## Explanation - -### Initializing the API client and configuration - -The API client is initialized in two steps: - -1. [`Config::new`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/config.rs#L131) creates a configuration with your API credentials and endpoints. This function: - - - Validates your API key and secret - - Sets up the REST API endpoint for data retrieval - - Configures optional settings like TLS verification - -2. [`Client::new`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/client.rs#L131) creates the HTTP client with your configuration. This client: - - Handles authentication automatically - - Manages HTTP connections efficiently - - Implements retry logic for failed requests - -### Fetching reports - -The SDK provides several methods to fetch reports through the REST API: - -1. Latest report: [`get_latest_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/client.rs#L165) retrieves the most recent report for a feed: - - - Takes a feed ID as input - - Returns a single report with the latest timestamp - - Useful for applications that need the most current data - -2. Historical report: [`get_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/client.rs#L242) fetches a report at a specific timestamp: - - Takes both feed ID and timestamp - - Returns the report closest to the requested timestamp - - Helpful for historical analysis or verification - -Each API request automatically: - -- Generates HMAC authentication headers -- Includes proper timestamps -- Handles HTTP response status codes -- Deserializes the JSON response into Rust structures - -### Decoding reports - -Reports are decoded in three stages: - -1. Hex decoding: The `full_report` field comes as a hex string prefixed with "0x": - - ```rust - let full_report = hex::decode(&response.report.full_report[2..])?; - ``` - -2. Report separation: [`decode_full_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report.rs#L77) splits the binary data: - - - Extracts the report context (metadata) - - Isolates the report blob (actual data) - - Validates the report format - -3. Data extraction: [`ReportDataV8::decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report/v8.rs#L60) parses the report blob into structured data: - - Price - - Market status (Open, Closed, or Unknown) - - Fee information for onchain verification - - Timestamp information - -### Error handling - -The example demonstrates Rust's robust error handling: - -1. Type-safe errors: - - - Uses custom error types for different failure scenarios - - Implements the `Error` trait for proper error propagation - - Provides detailed error messages for debugging - -2. Error propagation: - - - Uses the `?` operator for clean error handling - - Converts errors between types when needed - - Bubbles up errors to the main function - -3. Input validation: - - Checks command-line arguments - - Validates environment variables - - Verifies feed ID format - -The decoded data can be used for further processing, analysis, or display in your application. For production environments, you must verify the data onchain using the provided `full_report` payload. diff --git a/src/content/data-streams/tutorials/evm-onchain-report-verification.mdx b/src/content/data-streams/tutorials/evm-onchain-report-verification.mdx index 3d746b24426..badf39632ec 100644 --- a/src/content/data-streams/tutorials/evm-onchain-report-verification.mdx +++ b/src/content/data-streams/tutorials/evm-onchain-report-verification.mdx @@ -44,8 +44,8 @@ In this tutorial, you'll learn how to verify onchain the integrity of reports by Make sure you understand how to fetch reports via the [REST API](/data-streams/reference/data-streams-api/interface-api) or [WebSocket](/data-streams/reference/data-streams-api/interface-ws) connection. Refer to the following tutorials for more information: -- [Fetch and decode reports via a REST API](/data-streams/tutorials/api-go) -- [Stream and decode reports via WebSocket](/data-streams/tutorials/ws-go) +- [Fetch and decode reports via a REST API](/data-streams/tutorials/go-sdk-fetch) +- [Stream and decode reports via WebSocket](/data-streams/tutorials/go-sdk-stream) ## Requirements @@ -126,7 +126,7 @@ For this tutorial on _Arbitrum Sepolia_, fees are required, so you need to fund 1. In Remix, on the **Deploy & Run Transactions** tab, expand your verifier contract under the **Deployed Contracts** section. -1. Fill in the `verifyReport` function input parameter with the report payload you want to verify. You can use the following full report payload obtained in the [Fetch and decode report via a REST API](/data-streams/tutorials/api-go) tutorial as an example: +1. Fill in the `verifyReport` function input parameter with the report payload you want to verify. You can use the following full report payload obtained in the [Fetch and decode report via a REST API](/data-streams/tutorials/go-sdk-fetch) tutorial as an example: ``` 0x000660403d36be006d0c15d9b306f93c8660c5cfeab7db8e28c78ba316d395970000000000000000000000000000000000000000000000000000000032c3780a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200003c8e550d2fc5304993010112de9b69798297e4cc11990ee6250e464daf760000000000000000000000000000000000000000000000000000000006706e595000000000000000000000000000000000000000000000000000000006706e595000000000000000000000000000000000000000000000000000025bd3eb74c080000000000000000000000000000000000000000000000000021c6a95c654c7400000000000000000000000000000000000000000000000000000000670837150000000000000000000000000000000000000000000000079a2ab4077fc8fc6000000000000000000000000000000000000000000000000799fcb42536dfd8300000000000000000000000000000000000000000000000079a59496c3f29a0000000000000000000000000000000000000000000000000000000000000000002bd4acd37ce3cd5799de05d156ab328a5effd94468ebbaf2ff18d13d9631259cbe66cca01af6a8bb36e79d2d731a44e16791ee31e46ce27ed6530f1590cd7734c0000000000000000000000000000000000000000000000000000000000000002391562f1f2e4986bdb978fbf5ee27f7012992a79301af42d3473761ef2ede6271a61fbf4b32ac5be68a598bcfa523e035b624dab3b3d9a46276834f824ee592a @@ -174,8 +174,11 @@ The `verifyReport` function is the core function that handles onchain report ver - Schema version `0x0003` corresponds to the [report schema v3](/data-streams/reference/report-schema-v3) (Crypto assets). - Schema version `0x0008` corresponds to the [report schema v8](/data-streams/reference/report-schema-v8) (Real World Assets). - Schema version `0x0009` corresponds to the [report schema v9](/data-streams/reference/report-schema-v9) (NAV data). + - Schema version `0x000A` corresponds to the [report schema v10](/data-streams/reference/report-schema-v10) (Backed xStock data). - If the report version is unsupported, the function reverts with an InvalidReportVersion error. + For more information, see the [Report Schemas](/data-streams/reference/report-schema-overview) documentation. + - **Fee calculation and handling**: - The function first checks if a `FeeManager` contract exists by querying `s_feeManager()` on the verifier proxy. @@ -196,7 +199,7 @@ The `verifyReport` function is the core function that handles onchain report ver - **Data decoding**: - - Depending on the report version, the function decodes the verified report data into the appropriate struct (`ReportV3`, `ReportV8`, or `ReportV9`). + - Depending on the [report version](/data-streams/reference/report-schema-overview), the function decodes the verified report data into the appropriate struct (`ReportV3`, `ReportV8`,`ReportV9`, etc.). - It emits a `DecodedPrice` event with the price extracted from the verified report. - The `lastDecodedPrice` state variable is updated with the new price. diff --git a/src/content/data-streams/tutorials/api-go.mdx b/src/content/data-streams/tutorials/go-sdk-fetch.mdx similarity index 53% rename from src/content/data-streams/tutorials/api-go.mdx rename to src/content/data-streams/tutorials/go-sdk-fetch.mdx index 4fcc91a788c..4ad8a4aafc9 100644 --- a/src/content/data-streams/tutorials/api-go.mdx +++ b/src/content/data-streams/tutorials/go-sdk-fetch.mdx @@ -1,20 +1,20 @@ --- section: dataStreams date: Last Modified -title: "Fetch and decode V3 reports using the Go SDK" +title: "Fetch and decode Data Streams reports using the Go SDK" metadata: - title: "Fetch and Decode Cryptocurrency Data with Go SDK | Chainlink Data Streams" - description: "Learn how to use the Go SDK to fetch and decode cryptocurrency market data reports from Chainlink Data Streams in your Go applications." - keywords: ["Go SDK", "Golang", "Cryptocurrency", "V3 Reports", "API Tutorial", "Data Streams", "Market Data"] + title: "Fetch and Decode Data Streams Reports with Go SDK | Chainlink Data Streams" + description: "Learn how to use the Go SDK to fetch and decode data reports from Chainlink Data Streams in your Go applications." + keywords: ["Go SDK", "Golang", "Cryptocurrency", "API Tutorial", "Data Streams", "Market Data"] whatsnext: { - "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/ws-go", + "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/go-sdk-stream", "Learn how to verify your data onchain": "/data-streams/reference/data-streams-api/onchain-verification", - "Find the list of available Stream IDs": "/data-streams/crypto-streams", + "Find the list of available Streams and view their schemas": "/data-streams/reference/report-schema-overview", } --- -import { CopyText, PageTabs } from "@components" +import { Aside, CopyText, PageTabs } from "@components" import DataStreams from "@features/data-streams/common/DataStreams.astro" @@ -22,39 +22,19 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro" -In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/reference/data-streams-api/go-sdk) for Go to fetch and decode [V3 reports](/data-streams/reference/report-schema-v3) for [Crypto streams](/data-streams/crypto-streams) from the Data Streams Aggregation Network. You'll set up your Go project, retrieve reports, decode them, and log their attributes. +In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/reference/data-streams-api/go-sdk) for Go to fetch and decode [reports](/data-streams/reference/report-schema-overview) from the Data Streams Aggregation Network. You'll set up your Go project, retrieve reports, decode them, and log their attributes. @@ -66,7 +46,7 @@ In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/r ## Tutorial -You'll start with the set up of your Go project. Next, you'll fetch and decode reports for both single and multiple [crypto streams](/data-streams/crypto-streams), and log their attributes to your terminal. +You'll start with the set up of your Go project, installing the SDK and pasting example code. This will let you decode reports for both single and multiple [streams](/data-streams/crypto-streams), logging their attributes to your terminal. ### Set up your Go project @@ -83,7 +63,7 @@ You'll start with the set up of your Go project. Next, you'll fetch and decode r go mod init my-data-streams-project ``` -1. Install the Data Streams SDK: +1. Install the [Data Streams SDK](https://github.com/smartcontractkit/data-streams-sdk/tree/main/go): ```bash go get github.com/smartcontractkit/data-streams-sdk/go @@ -91,190 +71,181 @@ You'll start with the set up of your Go project. Next, you'll fetch and decode r ### Fetch and decode a report with a single stream -1. Create a new Go file, `single-stream.go`, in your project directory: +1. Create a new Go file, `single-stream.go`, in your project directory: - ```bash - touch single-stream.go - ``` + ```bash + touch single-stream.go + ``` -1. Insert the following code example and save your `single-stream.go` file: +1. Insert the following code example and save your `single-stream.go` file: - ```go - package main - - import ( - "context" - "fmt" - "os" - "time" - - streams "github.com/smartcontractkit/data-streams-sdk/go" - feed "github.com/smartcontractkit/data-streams-sdk/go/feed" - report "github.com/smartcontractkit/data-streams-sdk/go/report" - v3 "github.com/smartcontractkit/data-streams-sdk/go/report/v3" // Import the v3 report schema for Crypto streams - ) - - func main() { - // Validate command-line arguments - if len(os.Args) < 2 { - fmt.Printf("Usage: go run main.go [FeedID]\nExample: go run main.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782\n") - os.Exit(1) - } - feedIDInput := os.Args[1] - - // Get API credentials from environment variables - apiKey := os.Getenv("API_KEY") - apiSecret := os.Getenv("API_SECRET") - if apiKey == "" || apiSecret == "" { - fmt.Printf("API_KEY and API_SECRET environment variables must be set\n") - os.Exit(1) - } - - // Define the configuration for the SDK client - cfg := streams.Config{ - ApiKey: apiKey, - ApiSecret: apiSecret, - RestURL: "https://api.testnet-dataengine.chain.link", - Logger: streams.LogPrintf, - } - - // Initialize the SDK client - client, err := streams.New(cfg) - if err != nil { - cfg.Logger("Failed to create client: %v\n", err) - os.Exit(1) - } - - // Create context with timeout - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - // Parse the feed ID - var feedID feed.ID - if err := feedID.FromString(feedIDInput); err != nil { - cfg.Logger("Invalid feed ID format '%s': %v\n", feedIDInput, err) - os.Exit(1) - } - - // Fetch the latest report - reportResponse, err := client.GetLatestReport(ctx, feedID) - if err != nil { - cfg.Logger("Failed to get latest report: %v\n", err) - os.Exit(1) - } - - // Log the raw report data - cfg.Logger("Raw report data: %+v\n", reportResponse) - - // Decode the report - decodedReport, err := report.Decode[v3.Data](reportResponse.FullReport) - if err != nil { - cfg.Logger("Failed to decode report: %v\n", err) - os.Exit(1) - } - - // Format and display the decoded report - fmt.Printf("\nDecoded Report for Stream ID %s:\n"+ - "------------------------------------------\n"+ - "Observations Timestamp: %d\n"+ - "Benchmark Price : %s\n"+ - "Bid : %s\n"+ - "Ask : %s\n"+ - "Valid From Timestamp : %d\n"+ - "Expires At : %d\n"+ - "Link Fee : %s\n"+ - "Native Fee : %s\n"+ - "------------------------------------------\n", - feedIDInput, - decodedReport.Data.ObservationsTimestamp, - decodedReport.Data.BenchmarkPrice.String(), - decodedReport.Data.Bid.String(), - decodedReport.Data.Ask.String(), - decodedReport.Data.ValidFromTimestamp, - decodedReport.Data.ExpiresAt, - decodedReport.Data.LinkFee.String(), - decodedReport.Data.NativeFee.String(), - ) - } - ``` + ```go + package main -1. Download the required dependencies and update the `go.mod` and `go.sum` files: + import ( + "context" + "fmt" + "os" + "time" - ```bash - go mod tidy - ``` + streams "github.com/smartcontractkit/data-streams-sdk/go" + feed "github.com/smartcontractkit/data-streams-sdk/go/feed" + report "github.com/smartcontractkit/data-streams-sdk/go/report" + // NOTE: Use the report version (v3, v8, etc.) that matches your stream + v3 "github.com/smartcontractkit/data-streams-sdk/go/report/v3" + ) -1. Set up the SDK client configuration within `single-stream.go` with your API credentials and the REST endpoint: + func main() { + // Validate command-line arguments + if len(os.Args) < 2 { + fmt.Printf("Usage: go run main.go [FeedID]\nExample: go run main.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782\n") + os.Exit(1) + } + feedIDInput := os.Args[1] - ```go - cfg := streams.Config{ - ApiKey: os.Getenv("API_KEY"), - ApiSecret: os.Getenv("API_SECRET"), - RestURL: "https://api.testnet-dataengine.chain.link", - Logger: streams.LogPrintf, - } - ``` + // Get API credentials from environment variables + apiKey := os.Getenv("API_KEY") + apiSecret := os.Getenv("API_SECRET") + if apiKey == "" || apiSecret == "" { + fmt.Printf("API_KEY and API_SECRET environment variables must be set\n") + os.Exit(1) + } - - Set your API credentials as environment variables: + // Define the configuration for the SDK client + cfg := streams.Config{ + ApiKey: apiKey, + ApiSecret: apiSecret, + RestURL: "https://api.testnet-dataengine.chain.link", + Logger: streams.LogPrintf, + } - ```bash - export API_KEY="" - export API_SECRET="" - ``` + // Initialize the SDK client + client, err := streams.New(cfg) + if err != nil { + cfg.Logger("Failed to create client: %v\n", err) + os.Exit(1) + } - Replace `` and `` with your API credentials. + // Create context with timeout + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() - - `RestURL` is the REST endpoint to poll for specific reports. See the [Data Streams Interface](/data-streams/reference/data-streams-api/interface-api#domains) page for more information. + // Parse the feed ID + var feedID feed.ID + if err := feedID.FromString(feedIDInput); err != nil { + cfg.Logger("Invalid feed ID format '%s': %v\n", feedIDInput, err) + os.Exit(1) + } - See the [SDK Reference](/data-streams/reference/data-streams-api/go-sdk#config-struct) page for more configuration options. + // Fetch the latest report + reportResponse, err := client.GetLatestReport(ctx, feedID) + if err != nil { + cfg.Logger("Failed to get latest report: %v\n", err) + os.Exit(1) + } -1. For this example, you will read from the ETH/USD crypto stream. This stream ID is . See the [Stream Addresses](/data-streams/crypto-streams) page for a complete list of available crypto assets. + // Log the raw report data + cfg.Logger("Raw report data: %+v\n", reportResponse) - Execute your application: + // Decode the report + // NOTE: Use the report version (v3, v8, etc.) that matches your stream + decodedReport, err := report.Decode[v3.Data](reportResponse.FullReport) + if err != nil { + cfg.Logger("Failed to decode report: %v\n", err) + os.Exit(1) + } -```bash -go run single-stream.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 -``` + // Format and display the decoded report + // NOTE: Adjust for your report and desired output + fmt.Printf("\nDecoded Report for Stream ID %s:\n"+ + "------------------------------------------\n"+ + "Observations Timestamp: %d\n"+ + "Benchmark Price : %s\n"+ + "Bid : %s\n"+ + "Ask : %s\n"+ + "Valid From Timestamp : %d\n"+ + "Expires At : %d\n"+ + "Link Fee : %s\n"+ + "Native Fee : %s\n"+ + "------------------------------------------\n", + feedIDInput, + decodedReport.Data.ObservationsTimestamp, + decodedReport.Data.BenchmarkPrice.String(), + decodedReport.Data.Bid.String(), + decodedReport.Data.Ask.String(), + decodedReport.Data.ValidFromTimestamp, + decodedReport.Data.ExpiresAt, + decodedReport.Data.LinkFee.String(), + decodedReport.Data.NativeFee.String(), + ) + } + ``` -Expect output similar to the following in your terminal: + -```bash -Raw report data: {"fullReport":"0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff1578000000000000000000000000000000000000000000000000000000004f8e8a11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba78200000000000000000000000000000000000000000000000000000000675e0a5b00000000000000000000000000000000000000000000000000000000675e0a5b00000000000000000000000000000000000000000000000000001787ff5c6fb8000000000000000000000000000000000000000000000000000c01807477ecd000000000000000000000000000000000000000000000000000000000675f5bdb0000000000000000000000000000000000000000000000d1865f8f627c4113300000000000000000000000000000000000000000000000d18572c6cdc3b915000000000000000000000000000000000000000000000000d1879ab8e98f743ad00000000000000000000000000000000000000000000000000000000000000002f3316e5c964d118f6683eecda454985fcc696e4ba34d65edb4a71a8d0cfe970676f465618c7d01196e433cc35b6994e7ad7b8189b0462b51458e663d601fdfaa0000000000000000000000000000000000000000000000000000000000000002219a4493fdf311421d664e0c8d69efa74b776461f8e252d191eda7edb980ab9a5cce69ec0ad35ba210cf60a201ceff6771b35b44860fda859f4aaba242c476bf","feedID":"0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782","validFromTimestamp":1734216283,"observationsTimestamp":1734216283} +1. Download the required dependencies and update the `go.mod` and `go.sum` files: -Decoded Report for Stream ID 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782: ------------------------------------------- -Observations Timestamp: 1734216283 -Benchmark Price : 3865052126782320350000 -Bid : 3864985478146740000000 -Ask : 3865140837060103650000 -Valid From Timestamp : 1734216283 -Expires At : 1734302683 -Link Fee : 3379350941986000 -Native Fee : 25872872271800 ------------------------------------------- -``` + ```bash + go mod tidy + ``` -#### Decoded report details +1. Set up your API credentials as environment variables: -The decoded report details include: + ```bash + export API_KEY="" + export API_SECRET="" + ``` + + Replace `` and `` with your actual credentials. + + The Go script uses `os.Getenv("API_KEY")` and `os.Getenv("API_SECRET")` in its `streams.Config` to read these values. From the code sample above: + + ```go + cfg := streams.Config{ + ApiKey: os.Getenv("API_KEY"), + ApiSecret: os.Getenv("API_SECRET"), + RestURL: "https://api.testnet-dataengine.chain.link", + Logger: streams.LogPrintf, + } + ``` + + This configuration also specifies the `RestURL`, which the base URL for the API. In this case, it is already set to the testnet URL for Data Streams. -| Attribute | Value | Description | -| ------------------------ | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `Stream ID` | `0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782` | The unique identifier for the stream. In this example, the stream is for ETH/USD. | -| `Observations Timestamp` | `1734216283` | The timestamp indicating when the data was captured. | -| `Benchmark Price` | `3865052126782320350000` | The observed price in the report, with 18 decimals. For readability: `3,865.0521267823204` USD per ETH. | -| `Bid` | `3864985478146740000000` | The highest price a buyer is willing to pay for an asset, with 18 decimals. For readability: `3,864.9854781467400` USD per ETH. Learn more about the [Bid price](/data-streams/concepts/liquidity-weighted-prices). (For [DEX State Price streams](/data-streams/concepts/dex-state-price-streams), this value equals `Benchmark Price`.) | -| `Ask` | `3865140837060103650000` | The lowest price a seller is willing to accept for an asset, with 18 decimals. For readability: `3,865.1408370601037` USD per ETH. Learn more about the [Ask price](/data-streams/concepts/liquidity-weighted-prices). (For [DEX State Price streams](/data-streams/concepts/dex-state-price-streams), this value equals `Benchmark Price`.) | -| `Valid From Timestamp` | `1734216283` | The start validity timestamp for the report, indicating when the data becomes relevant. | -| `Expires At` | `1734302683` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. | -| `Link Fee` | `3379350941986000` | The fee to pay in LINK tokens for the onchain verification of the report data. With 18 decimals. For readability: `0.03379350941986` LINK. **Note:** This example fee is not indicative of actual fees. | -| `Native Fee` | `25872872271800` | The fee to pay in the native blockchain token (e.g., ETH on Ethereum) for the onchain verification of the report data. With 18 decimals. **Note:** This example fee is not indicative of actual fees. | + See the [SDK Reference](/data-streams/reference/data-streams-api/go-sdk#config-struct) page for more configuration options. -#### Payload for onchain verification +1. Read from a [testnet crypto stream](/data-streams/crypto-streams?page=1&testnetPage=1#testnet-crypto-streams). The below example executes the application, reading from the `ETH/USD` crypto stream: -In this tutorial, you log and decode the `full_report` payload to extract the report data. In a -production environment, you should verify the data to ensure its integrity and authenticity. Refer to the -[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) tutorial. + ```bash + go run single-stream.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 + ``` + + Expect output similar to the following in your terminal: + + ```bash + Raw report data: {"fullReport":"0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff1578000000000000000000000000000000000000000000000000000000004f8e8a11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba78200000000000000000000000000000000000000000000000000000000675e0a5b00000000000000000000000000000000000000000000000000000000675e0a5b00000000000000000000000000000000000000000000000000001787ff5c6fb8000000000000000000000000000000000000000000000000000c01807477ecd000000000000000000000000000000000000000000000000000000000675f5bdb0000000000000000000000000000000000000000000000d1865f8f627c4113300000000000000000000000000000000000000000000000d18572c6cdc3b915000000000000000000000000000000000000000000000000d1879ab8e98f743ad00000000000000000000000000000000000000000000000000000000000000002f3316e5c964d118f6683eecda454985fcc696e4ba34d65edb4a71a8d0cfe970676f465618c7d01196e433cc35b6994e7ad7b8189b0462b51458e663d601fdfaa0000000000000000000000000000000000000000000000000000000000000002219a4493fdf311421d664e0c8d69efa74b776461f8e252d191eda7edb980ab9a5cce69ec0ad35ba210cf60a201ceff6771b35b44860fda859f4aaba242c476bf","feedID":"0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782","validFromTimestamp":1734216283,"observationsTimestamp":1734216283} + + Decoded Report for Stream ID 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782: + ------------------------------------------ + Observations Timestamp: 1734216283 + Benchmark Price : 3865052126782320350000 + Bid : 3864985478146740000000 + Ask : 3865140837060103650000 + Valid From Timestamp : 1734216283 + Expires At : 1734302683 + Link Fee : 3379350941986000 + Native Fee : 25872872271800 + ------------------------------------------ + ``` + + Your application has successfully decoded the report data. + + [Learn more about the decoded report details](#decoded-report-details). ### Fetch and decode reports for multiple streams @@ -298,7 +269,8 @@ production environment, you should verify the data to ensure its integrity and a streams "github.com/smartcontractkit/data-streams-sdk/go" feed "github.com/smartcontractkit/data-streams-sdk/go/feed" report "github.com/smartcontractkit/data-streams-sdk/go/report" - v3 "github.com/smartcontractkit/data-streams-sdk/go/report/v3" // Import the v3 report schema for Crypto streams + // NOTE: Use the report version (v3, v8, etc.) that matches your stream + v3 "github.com/smartcontractkit/data-streams-sdk/go/report/v3" ) func main() { @@ -377,6 +349,7 @@ production environment, you should verify the data to ensure its integrity and a } // Format and display the decoded report + // NOTE: Adjust for your report and desired output fmt.Printf("\nDecoded Report for Stream ID %s:\n"+ "------------------------------------------\n"+ "Observations Timestamp: %d\n"+ @@ -402,6 +375,16 @@ production environment, you should verify the data to ensure its integrity and a } ``` + + 1. Before running the example, verify that your API credentials are still set in your current terminal session: ```bash @@ -416,7 +399,7 @@ production environment, you should verify the data to ensure its integrity and a export API_SECRET="" ``` -1. For this example, you will read from the ETH/USD and LINK/USD Data Streams crypto streams. Run your application: +1. Read from two [testnet crypto streams](/data-streams/crypto-streams?page=1&testnetPage=1#testnet-crypto-streams). For this example, you will read from the ETH/USD and LINK/USD Data Streams crypto streams. Run your application: ```bash go run multiple-streams.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265 @@ -457,11 +440,65 @@ production environment, you should verify the data to ensure its integrity and a Your application has successfully fetched and decoded data for both streams. -#### Payload for onchain verification + [Learn more about the decoded report details](#decoded-report-details). + +### Decoded report details + +The decoded [crypto v3 report](/data-streams/reference/report-schema-v3) details include: + +| Attribute | Value | Description | +| ---------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Stream ID | `0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782` | The unique identifier for the stream. In this example, the stream is for ETH/USD. | +| Observations Timestamp | `1734216283` | The timestamp indicating when the data was captured. | +| Benchmark Price | `3865052126782320350000` | The observed price in the report, with 18 decimals. For readability: `3,865.0521267823204` USD per ETH. | +| Bid | `3864985478146740000000` | The highest price a buyer is willing to pay for an asset, with 18 decimals. For readability: `3,864.9854781467400` USD per ETH. Learn more about the [Bid price](/data-streams/concepts/liquidity-weighted-prices). (For [DEX State Price streams](/data-streams/concepts/dex-state-price-streams), this value equals `Benchmark Price`.) | +| Ask | `3865140837060103650000` | The lowest price a seller is willing to accept for an asset, with 18 decimals. For readability: `3,865.1408370601037` USD per ETH. Learn more about the [Ask price](/data-streams/concepts/liquidity-weighted-prices). (For [DEX State Price streams](/data-streams/concepts/dex-state-price-streams), this value equals `Benchmark Price`.) | +| Valid From Timestamp | `1734216283` | The start validity timestamp for the report, indicating when the data becomes relevant. | +| Expires At | `1734302683` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. | +| Link Fee | `3379350941986000` | The fee to pay in LINK tokens for the onchain verification of the report data. With 18 decimals. For readability: `0.03379350941986` LINK. **Note:** This example fee is not indicative of actual fees. | +| Native Fee | `25872872271800` | The fee to pay in the native blockchain token (e.g., ETH on Ethereum) for the onchain verification of the report data. With 18 decimals. **Note:** This example fee is not indicative of actual fees. | + +For descriptions and data types of other report schemas, see the [Report Schema Overview](/data-streams/reference/report-schema-overview). + +### Payload for onchain verification + +In this tutorial, you logged and decoded the `full_report` payloads to extract the report data. However, in a production environment, you should verify the data to ensure its integrity and authenticity. + +Refer to the [Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) tutorial to learn more. + +## Adapting code for different report schema versions + +When working with different versions of [Data Stream reports](/data-streams/reference/report-schema-overview), you'll need to adapt your code to handle the specific report schema version they use: -In this guide, you log and decode the `fullReport` payloads to extract the report data. In a -production environment, you should verify the data to ensure its integrity and authenticity. Refer to the -[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) guide. +1. Import the correct schema version. Examples: + + - For v3 schema (as used in this example): + + ```go + v3 "github.com/smartcontractkit/data-streams-sdk/go/report/v3" + ``` + + - For v8 schema: + + ```go + v8 "github.com/smartcontractkit/data-streams-sdk/go/report/v8" + ``` + +1. Update the decode function to use the correct schema version. Examples: + + - For v3 schema (as used in this example): + + ```go + decodedReport, err := report.Decode[v3.Data](reportResponse.FullReport) + ``` + + - For v8 schema: + + ```go + decodedReport, err := report.Decode[v8.Data](reportResponse.FullReport) + ``` + +1. Access fields according to the schema version structure. Refer to the [Report Schemas](/data-streams/reference/report-schema-overview) documentation for complete field references for each version. ## Explanation @@ -486,6 +523,8 @@ The Data Streams client is initialized in two steps: - `RestURL` for the API endpoint (required) - `Logger` for debugging and error tracking (optional, defaults to `streams.LogPrintf`) + See the [SDK Reference](/data-streams/reference/data-streams-api/go-sdk#config-struct) page for more configuration options. + 2. Create the client with [`streams.New`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L56): ```go client, err := streams.New(cfg) @@ -539,10 +578,10 @@ Reports are decoded in two steps: This step: - - Takes the raw `FullReport` bytes from the response - - Uses `v3.Data` schema for Crypto streams (use `v8.Data` for RWA streams) - - Validates the format and decodes using Go generics - - Returns a structured report with typed data + 1. Takes the raw `FullReport` bytes from the response + 1. Uses `v3.Data` schema for Crypto streams (use the appropriate schema for your stream) + 1. Validates the format and decodes using Go generics + 1. Returns a structured report with typed data 2. Data access: ```go @@ -552,6 +591,7 @@ Reports are decoded in two steps: ask := data.Ask.String() validFrom := data.ValidFromTimestamp // Unix timestamp expiresAt := data.ExpiresAt // Unix timestamp + // ...additional or different fields depending on the report schema ``` Provides access to: - Benchmark price, bid, and ask prices (as big numbers) diff --git a/src/content/data-streams/tutorials/go-sdk-stream.mdx b/src/content/data-streams/tutorials/go-sdk-stream.mdx new file mode 100644 index 00000000000..5804e3c1b34 --- /dev/null +++ b/src/content/data-streams/tutorials/go-sdk-stream.mdx @@ -0,0 +1,383 @@ +--- +section: dataStreams +date: Last Modified +title: "Stream and decode Data Streams reports via WebSocket using the Go SDK" +metadata: + title: "Stream Real-time Data Streams Reports with Go SDK | WebSocket Tutorial" + description: "Learn how to use the Go SDK to stream and decode real-time data streams reports via WebSocket connections from Chainlink Data Streams." + keywords: ["WebSocket", "Go SDK", "Golang", "Real-time", "Streaming", "Data Streams"] +whatsnext: + { + "Learn how to verify your data onchain": "/data-streams/reference/data-streams-api/onchain-verification", + "Find the list of available Streams and view their schemas": "/data-streams/reference/report-schema-overview", + } +--- + +import { Aside, CopyText, PageTabs } from "@components" +import DataStreams from "@features/data-streams/common/DataStreams.astro" + + + + + +In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/reference/data-streams-api/go-sdk) for Go to subscribe to real-time [reports](/data-streams/reference/report-schema-overview) via a [WebSocket connection](/data-streams/reference/data-streams-api/interface-ws). You'll set up your Go project, listen for real-time reports from the Data Streams Aggregation Network, decode the report data, and log their attributes to your terminal. + + + +## Requirements + +- **Git**: Make sure you have Git installed. You can check your current version by running in your terminal and download the latest version from the official [Git website](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) if necessary. +- **Go Version**: Make sure you have Go version 1.21 or higher. You can check your current version by running `go version` in your terminal and download the latest version from the official [Go website](https://go.dev/) if necessary. +- **API Credentials**: Access to Data Streams requires API credentials. If you haven't already, [contact us](https://chainlinkcommunity.typeform.com/datastreams?typeform-source=docs.chain.link#ref_id=docs) to request mainnet or testnet access. + +## Tutorial + +First, you'll set up a basic Go project, installing the SDK and pasting example code. This will let you stream reports for [streams](/data-streams/crypto-streams), logging their attributes to your terminal. + +### Set up your Go project + +1. Create a new directory for your project and navigate to it: + + ```bash + mkdir my-data-streams-project + cd my-data-streams-project + ``` + +1. Initialize a new Go module: + + ```bash + go mod init my-data-streams-project + ``` + +1. Install the Data Streams SDK: + + ```bash + go get github.com/smartcontractkit/data-streams-sdk/go + ``` + +### Establish a WebSocket connection and listen for real-time reports + +1. Create a new Go file, `stream.go`, in your project directory: + + ```bash + touch stream.go + ``` + +1. Insert the following code example and save your `stream.go` file: + + ```go + package main + + import ( + "context" + "fmt" + "os" + "time" + + streams "github.com/smartcontractkit/data-streams-sdk/go" + feed "github.com/smartcontractkit/data-streams-sdk/go/feed" + report "github.com/smartcontractkit/data-streams-sdk/go/report" + // NOTE: Use the report version (v3, v8, etc.) that matches your stream + v3 "github.com/smartcontractkit/data-streams-sdk/go/report/v3" + ) + + func main() { + if len(os.Args) < 2 { + fmt.Println("Usage: go run stream.go [StreamID1] [StreamID2] ...") + os.Exit(1) + } + + // Set up the SDK client configuration + cfg := streams.Config{ + ApiKey: os.Getenv("API_KEY"), + ApiSecret: os.Getenv("API_SECRET"), + WsURL: "wss://ws.testnet-dataengine.chain.link", + Logger: streams.LogPrintf, + } + + // Create a new client + client, err := streams.New(cfg) + if err != nil { + cfg.Logger("Failed to create client: %v\n", err) + os.Exit(1) + } + + // Parse the feed IDs from the command line arguments + var ids []feed.ID + for _, arg := range os.Args[1:] { + var fid feed.ID + if err := fid.FromString(arg); err != nil { + cfg.Logger("Invalid stream ID %s: %v\n", arg, err) + os.Exit(1) + } + ids = append(ids, fid) + } + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + // Subscribe to the feeds + stream, err := client.Stream(ctx, ids) + if err != nil { + cfg.Logger("Failed to subscribe: %v\n", err) + os.Exit(1) + } + + defer stream.Close() + for { + reportResponse, err := stream.Read(context.Background()) + if err != nil { + cfg.Logger("Error reading from stream: %v\n", err) + continue + } + + // Log the contents of the report before decoding + cfg.Logger("Raw report data: %+v\n", reportResponse) + + // Decode each report as it comes in + // NOTE: Use the report version (v3, v8, etc.) that matches your stream + decodedReport, decodeErr := report.Decode[v3.Data](reportResponse.FullReport) + if decodeErr != nil { + cfg.Logger("Failed to decode report: %v\n", decodeErr) + continue + } + + // Log the decoded report + // NOTE: Adjust for your report and desired output + cfg.Logger("\n--- Report Stream ID: %s ---\n" + + "------------------------------------------\n" + + "Observations Timestamp : %d\n" + + "Benchmark Price : %s\n" + + "Bid : %s\n" + + "Ask : %s\n" + + "Valid From Timestamp : %d\n" + + "Expires At : %d\n" + + "Link Fee : %s\n" + + "Native Fee : %s\n" + + "------------------------------------------\n", + reportResponse.FeedID.String(), + decodedReport.Data.ObservationsTimestamp, + decodedReport.Data.BenchmarkPrice.String(), + decodedReport.Data.Bid.String(), + decodedReport.Data.Ask.String(), + decodedReport.Data.ValidFromTimestamp, + decodedReport.Data.ExpiresAt, + decodedReport.Data.LinkFee.String(), + decodedReport.Data.NativeFee.String(), + ) + + // Also, log the stream stats + cfg.Logger("\n--- Stream Stats ---\n" + + stream.Stats().String() + "\n" + + "--------------------------------------------------------------------------------------------------------------------------------------------\n", + ) + } + } + ``` + + + +1. Download the required dependencies and update the `go.mod` and `go.sum` files: + + ```bash + go mod tidy + ``` + +1. Set up your API credentials as environment variables: + + ```bash + export API_KEY="" + export API_SECRET="" + ``` + + Replace `` and `` with your actual credentials. + + The Go script uses `os.Getenv("API_KEY")` and `os.Getenv("API_SECRET")` in its `streams.Config` to read these values. From the code sample above: + + ```go + cfg := streams.Config{ + ApiKey: os.Getenv("API_KEY"), + ApiSecret: os.Getenv("API_SECRET"), + WsURL: "wss://ws.testnet-dataengine.chain.link", + Logger: streams.LogPrintf, + } + ``` + + This configuration also specifies the `WsURL`, which the [Websocket URL for the API](/data-streams/reference/data-streams-api/interface-ws#domains). In this case, it is already set to the testnet URL for Data Streams. + + See the [SDK Reference](/data-streams/reference/data-streams-api/go-sdk#config-struct) page for more configuration options. + +1. Subscribe to a [testnet crypto stream](/data-streams/crypto-streams?page=1&testnetPage=1#testnet-crypto-streams). The below example executes the application, subscribing to the `ETH/USD` crypto stream: + + Execute your application: + + ```bash + go run stream.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 + ``` + + Expect output similar to the following in your terminal: + + ```bash + 2024-07-31T15:34:27-05:00 Raw report data: {"fullReport":"0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff15780000000000000000000000000000000000000000000000000000000035252f11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba7820000000000000000000000000000000000000000000000000000000066aa9fd30000000000000000000000000000000000000000000000000000000066aa9fd300000000000000000000000000000000000000000000000000001c23cdce76d0000000000000000000000000000000000000000000000000001ba0a27c8b79d40000000000000000000000000000000000000000000000000000000066abf1530000000000000000000000000000000000000000000000af35b91cbc421fe2800000000000000000000000000000000000000000000000af354910dbd1830c200000000000000000000000000000000000000000000000af3629289cb2be3f800000000000000000000000000000000000000000000000000000000000000002e03c8b14707a80c59922eeb6b89c79dd8ac6b4b925203b3fe2f0903ba6765934aaf6c4170522c0e54abecb90e7ba7b26e27a83b12740e6a6fd5835c5ece9034c000000000000000000000000000000000000000000000000000000000000000252088e89df570d7022fd2bfc71eb53bfe72423ccba1834a785d80c278b334fab65d4acced307504358554844c2007ab0322b7ab2b7bfa2bc39563bf823654a36","feedID":"0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782","validFromTimestamp":1722458067,"observationsTimestamp":1722458067} + + 2024-07-31T15:34:27-05:00 + --- Report Stream ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 --- + ------------------------------------------ + Observations Timestamp : 1722458067 + Benchmark Price : 3232051369848762000000 + Bid : 3232019831592780500000 + Ask : 3232082908104743600000 + Valid From Timestamp : 1722458067 + Expires At : 1722544467 + Link Fee : 7776444105849300 + Native Fee : 30940102293200 + ------------------------------------------ + + 2024-07-31T15:34:27-05:00 + --- Stream Stats --- + accepted: 1, deduplicated: 0, total_received 1, partial_reconnects: 0, full_reconnects: 0, configured_connections: 1, active_connections 1 + -------------------------------------------------------------------------------------------------------------------------------------------- + + 2024-07-31T15:34:28-05:00 Raw report data: {"fullReport":"0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff15780000000000000000000000000000000000000000000000000000000035252f14000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba7820000000000000000000000000000000000000000000000000000000066aa9fd40000000000000000000000000000000000000000000000000000000066aa9fd400000000000000000000000000000000000000000000000000001c23c416de34000000000000000000000000000000000000000000000000001ba0909c32d3c00000000000000000000000000000000000000000000000000000000066abf1540000000000000000000000000000000000000000000000af35f59d91552300000000000000000000000000000000000000000000000000af34696c66686640800000000000000000000000000000000000000000000000af3c6a5680c2a6000000000000000000000000000000000000000000000000000000000000000000020d3c5953a51793330c4bb5082d0e82eca98281d340d56088b5707dbc77e5c106311585b943ced71c62a3e6b100dc9316c3580354aee92626280228dd9b6a2c3900000000000000000000000000000000000000000000000000000000000000026398ed0026b877ba17280888f1c7f93f42ca4c3148cf33761412af03b19c08880e4ee75f222eb928db5429fc4339aa1e275bf5a5ffeb6345aa0acef594024abc","feedID":"0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782","validFromTimestamp":1722458068,"observationsTimestamp":1722458068} + + 2024-07-31T15:34:28-05:00 + --- Report Stream ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 --- + ------------------------------------------ + Observations Timestamp : 1722458068 + Benchmark Price : 3232068400000000000000 + Bid : 3231956881848792400000 + Ask : 3232533600000000000000 + Valid From Timestamp : 1722458068 + Expires At : 1722544468 + Link Fee : 7776367327499200 + Native Fee : 30939939266100 + ------------------------------------------ + + 2024-07-31T15:34:28-05:00 + --- Stream Stats --- + accepted: 2, deduplicated: 0, total_received 2, partial_reconnects: 0, full_reconnects: 0, configured_connections: 1, active_connections 1 + -------------------------------------------------------------------------------------------------------------------------------------------- + + 2024-07-31T15:34:29-05:00 Raw report data: {"fullReport":"0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff15780000000000000000000000000000000000000000000000000000000035252f19000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba7820000000000000000000000000000000000000000000000000000000066aa9fd50000000000000000000000000000000000000000000000000000000066aa9fd500000000000000000000000000000000000000000000000000001c2232164340000000000000000000000000000000000000000000000000001ba02d9e17e83c0000000000000000000000000000000000000000000000000000000066abf1550000000000000000000000000000000000000000000000af3fbd367bea5ac0000000000000000000000000000000000000000000000000af3f1f78eb5653c0000000000000000000000000000000000000000000000000af405a99196de7800000000000000000000000000000000000000000000000000000000000000000020a7b2c4de654a6fb2e0b9c3706521a94bb852c705fe03e682da43301986c229f99b40a47c34b2d23c51e6323274d68b5c6d0d36dbc02586233d50dfc3ef193700000000000000000000000000000000000000000000000000000000000000002364b1b5d922cfe20faa94011a22324ed452fe17a0c1d1475a468974a39419aae33a027865c4a2738fbd59f2ce3a1c72435054a72084b4802f205fe7a690d1ecc","feedID":"0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782","validFromTimestamp":1722458069,"observationsTimestamp":1722458069} + + 2024-07-31T15:34:29-05:00 + --- Report Stream ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 --- + ------------------------------------------ + Observations Timestamp : 1722458069 + Benchmark Price : 3232773100000000000000 + Bid : 3232728700000000000000 + Ask : 3232817400000000000000 + Valid From Timestamp : 1722458069 + Expires At : 1722544469 + Link Fee : 7775942157527100 + Native Fee : 30933194785600 + ------------------------------------------ + + 2024-07-31T15:34:29-05:00 + --- Stream Stats --- + accepted: 3, deduplicated: 0, total_received 3, partial_reconnects: 0, full_reconnects: 0, configured_connections: 1, active_connections 1 + -------------------------------------------------------------------------------------------------------------------------------------------- + + [...] + ``` + + Your application has successfully subscribed to the report data. + + [Learn more about the decoded report details](#decoded-report-details). + +### Decoded report details + +The decoded report details include: + +| Attribute | Value | Description | +| ------------------------ | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Stream ID` | `0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782` | The unique identifier for the stream. In this example, the stream is for ETH/USD. | +| `Observations Timestamp` | `1722458069` | The timestamp indicating when the data was captured. | +| `Benchmark Price` | `3232773100000000000000` | The observed price in the report. For readability: `3,232.7731000000000` USD per ETH. | +| `Bid` | `3232728700000000000000` | The highest price a buyer is willing to pay for an asset. For readability: `3,232.7287000000000` USD per ETH. Learn more about the [Bid price](/data-streams/concepts/liquidity-weighted-prices). | +| `Ask` | `3232817400000000000000` | The lowest price a seller is willing to accept for an asset. For readability: `3,232.8174000000000` USD per ETH. Learn more about the [Ask price](/data-streams/concepts/liquidity-weighted-prices). | +| `Valid From Timestamp` | `1722458069` | The start validity timestamp for the report, indicating when the data becomes relevant. | +| `Expires At` | `1722544469` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. | +| `Link Fee` | `7775942157527100` | The fee to pay in LINK tokens for the onchain verification of the report data. For readability: `0.0077759421575271` LINK. | +| `Native Fee` | `30933194785600` | The fee to pay in the native blockchain token (e.g., ETH on Ethereum) for the onchain verification of the report data. **Note:** This example fee is not indicative of actual fees. | + +For descriptions and data types of other report schemas, see the [Report Schema Overview](/data-streams/reference/report-schema-overview). + +### Payload for onchain verification + +In this tutorial, you logged and decoded the `full_report` payloads to extract the report data. However, in a production environment, you should verify the data to ensure its integrity and authenticity. + +Refer to the [Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) tutorial to learn more. + +## Adapting code for different report schema versions + +When working with different versions of [Data Stream reports](/data-streams/reference/report-schema-overview), you'll need to adapt your code to handle the specific report schema version they use: + +1. Import the correct schema version. Examples: + + - For v3 schema (as used in this example): + + ```go + v3 "github.com/smartcontractkit/data-streams-sdk/go/report/v3" + ``` + + - For v8 schema: + + ```go + v8 "github.com/smartcontractkit/data-streams-sdk/go/report/v8" + ``` + +1. Update the decode function to use the correct schema version. Examples: + + - For v3 schema (as used in this example): + + ```go + decodedReport, err := report.Decode[v3.Data](reportResponse.FullReport) + ``` + + - For v8 schema: + + ```go + decodedReport, err := report.Decode[v8.Data](reportResponse.FullReport) + ``` + +1. Access fields according to the schema version structure. Refer to the [Report Schemas](/data-streams/reference/report-schema-overview) documentation for complete field references for each version. + +## Explanation + +### Establishing a WebSocket connection and listening for reports + +Your application uses the [Stream](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L103) function in the [Data Streams SDK](/data-streams/reference/data-streams-api/go-sdk)'s client package to establish a real-time WebSocket connection with the Data Streams Aggregation Network. + +Once the WebSocket connection is established, your application subscribes to one or more streams by passing an array of `feed.IDs` to the `Stream` function. This subscription lets the client receive real-time updates whenever new report data is available for the specified streams. + +### Decoding a report + +As data reports arrive via the established WebSocket connection, they are processed in real-time: + +- Reading streams: The [`Read`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/stream.go#L292) method on the returned Stream object is continuously called within a loop. This method blocks until new data is available, ensuring that all incoming reports are captured as soon as they are broadcasted. + +- Decoding reports: For each received report, the SDK's [`Decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/report/report.go#L36) function parses and transforms the raw data into a structured format (in this tutorial, `v3.Data` for [crypto streams](/data-streams/crypto-streams)). This decoded data includes data such as the benchmark price and [bid and ask](/data-streams/concepts/liquidity-weighted-prices) prices. + +### Handling the decoded data + +In this example, the application logs the structured report data to the terminal. However, this data can be used for further processing, analysis, or display in your own application. diff --git a/src/content/data-streams/tutorials/overview.mdx b/src/content/data-streams/tutorials/overview.mdx index b1f1227f053..134fa664638 100644 --- a/src/content/data-streams/tutorials/overview.mdx +++ b/src/content/data-streams/tutorials/overview.mdx @@ -18,8 +18,8 @@ Explore several tutorials to learn how to use the Data Streams. ## Fetch, Stream, and Decode Reports -- [Fetch and decode reports](/data-streams/tutorials/api-go): Learn how to fetch and decode reports from the Data Streams Aggregation Network, using the [Go](/data-streams/reference/data-streams-api/go-sdk) or [Rust](/data-streams/reference/data-streams-api/rust-sdk) SDKs. -- [Stream and decode reports (WebSocket)](/data-streams/tutorials/ws-go): Learn how to listen for real-time reports from the Data Streams Aggregation Network, decode the report data, and log their attributes, using the [Go](/data-streams/reference/data-streams-api/go-sdk) or [Rust](/data-streams/reference/data-streams-api/rust-sdk) SDKs. +- [Fetch and decode reports](/data-streams/tutorials/go-sdk-fetch): Learn how to fetch and decode reports from the Data Streams Aggregation Network, using the [Go](/data-streams/reference/data-streams-api/go-sdk) or [Rust](/data-streams/reference/data-streams-api/rust-sdk) SDKs. +- [Stream and decode reports (WebSocket)](/data-streams/tutorials/go-sdk-stream): Learn how to listen for real-time reports from the Data Streams Aggregation Network, decode the report data, and log their attributes, using the [Go](/data-streams/reference/data-streams-api/go-sdk) or [Rust](/data-streams/reference/data-streams-api/rust-sdk) SDKs.