From 4520a5c7d2c3cd0bb96f3d825e3db59df1389e76 Mon Sep 17 00:00:00 2001 From: Devin DiStefano Date: Fri, 22 Aug 2025 12:06:42 -0700 Subject: [PATCH 01/13] init restructure --- src/config/sidebar.ts | 24 +- .../reference/report-schema-overview.mdx | 49 ++ .../data-streams/tutorials/go-sdk-decode.mdx | 585 ++++++++++++++++++ .../data-streams/tutorials/go-sdk-stream.mdx | 360 +++++++++++ .../tutorials/rust-sdk-decode.mdx | 311 ++++++++++ .../tutorials/rust-sdk-stream.mdx | 407 ++++++++++++ 6 files changed, 1720 insertions(+), 16 deletions(-) create mode 100644 src/content/data-streams/reference/report-schema-overview.mdx create mode 100644 src/content/data-streams/tutorials/go-sdk-decode.mdx create mode 100644 src/content/data-streams/tutorials/go-sdk-stream.mdx create mode 100644 src/content/data-streams/tutorials/rust-sdk-decode.mdx create mode 100644 src/content/data-streams/tutorials/rust-sdk-stream.mdx diff --git a/src/config/sidebar.ts b/src/config/sidebar.ts index 9367b078dd9..c51a0816a41 100644 --- a/src/config/sidebar.ts +++ b/src/config/sidebar.ts @@ -343,6 +343,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", @@ -402,25 +406,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-decode", + highlightAsCurrent: ["data-streams/tutorials/rust-sdk-decode"], }, { 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/reference/report-schema-overview.mdx b/src/content/data-streams/reference/report-schema-overview.mdx new file mode 100644 index 00000000000..027788935df --- /dev/null +++ b/src/content/data-streams/reference/report-schema-overview.mdx @@ -0,0 +1,49 @@ +--- +section: dataStreams +date: Last Modified +title: "Overview" +--- + +import DataStreams from "@features/data-streams/common/DataStreams.astro" +import { PageTabs } from "@components" + + + + + +## Available Reports + +Below is a summary of all available Data Streams reports, schemas, their main use cases, and key fields. + +| Report | Schema | Use Case / Purpose | Key Fields | +| ------------------------------------------------------------------ | ---------------------------------------- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| [Cryptocurrency](/data-streams/reference/report-schema) | [View schema (v3)](report-schema-v3) | Crypto price streams | `price`, `bid`, `ask` | +| [DEX State Price](/data-streams/reference/report-schema-v3-dex) | [View schema (v3)](report-schema-v3-dex) | DEX state crypto price streams | `price`, `bid`, `ask`
(All fields equal; [details](/data-streams/concepts/dex-state-price-streams#how-to-use-dex-state-price-streams)) | +| [Real World Asset (RWA)](/data-streams/reference/report-schema-v8) | [View schema (v8)](report-schema-v8) | Real World Asset (RWA) price streams | `midPrice`, `marketStatus` | +| [Net Asset Value (NAV)](/data-streams/reference/report-schema-v9) | [View schema (v9)](report-schema-v9) | Net Asset Value (NAV) streams | `navPerShare`, `navDate`, `ripcord` | +| [Backed xStock](/data-streams/reference/report-schema-v10) | [View schema (v10)](report-schema-v10) | Tokenized stocks and backed asset streams | `price`, `tokenizedPrice`,
`marketStatus`, `currentMultiplier`, `newMultiplier` | diff --git a/src/content/data-streams/tutorials/go-sdk-decode.mdx b/src/content/data-streams/tutorials/go-sdk-decode.mdx new file mode 100644 index 00000000000..a83ec549bb4 --- /dev/null +++ b/src/content/data-streams/tutorials/go-sdk-decode.mdx @@ -0,0 +1,585 @@ +--- +section: dataStreams +date: Last Modified +title: "Fetch and decode Data Streams reports using the Go SDK" +metadata: + 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/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", + } +--- + +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 [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. + + + +## 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 [crypto streams](/data-streams/crypto-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" + 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(), + ) + } + ``` + +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 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. + + Execute your application: + +```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 +------------------------------------------ +``` + +#### 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` | `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. | + +#### 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. + +### 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" + 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) < 3 { + fmt.Printf("Usage: go run multiple-streams.go [StreamID1] [StreamID2] ...\n"+ + "Example: go run multiple-streams.go "+ + "0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 "+ + "0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265\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[v3.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"+ + "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(), + ) + } + } + ``` + +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 the ETH/USD and LINK/USD Data Streams crypto streams. Run your application: + + ```bash + go run multiple-streams.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265 + ``` + + Expect to see the output below in your terminal: + + ```bash + 2024-12-14T17:49:06-05:00 Raw report data for Stream ID 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782: {"fullReport":"0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff1578000000000000000000000000000000000000000000000000000000004f8eb301000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba78200000000000000000000000000000000000000000000000000000000675e0b6100000000000000000000000000000000000000000000000000000000675e0b610000000000000000000000000000000000000000000000000000178bcfba6d60000000000000000000000000000000000000000000000000000c1536af09b42c00000000000000000000000000000000000000000000000000000000675f5ce10000000000000000000000000000000000000000000000d1646f5fd0b1e6e6a00000000000000000000000000000000000000000000000d1635f8df6b0fce2600000000000000000000000000000000000000000000000d1677c13a6c9d89620000000000000000000000000000000000000000000000000000000000000000222412e1bd137097dc97def8914c72ae7305179eedc5c15e344bc119a06f1db76ef20f3e6493a97c2be2ab831199bfc00dbbf02551f2a27a70cfd55653270acac0000000000000000000000000000000000000000000000000000000000000002343957d73014b446eb0b0436072e16261a643102e502529d3b97412027c3468977bf0806e8971a37e6487b855243957a57749cde2ac92ebc2bda412d94981251","feedID":"0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782","validFromTimestamp":1734216545,"observationsTimestamp":1734216545} + + + Decoded Report for Stream ID 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782: + ------------------------------------------ + Observations Timestamp: 1734216545 + Benchmark Price : 3862606619881446500000 + Bid : 3862530109428509500000 + Ask : 3862826368095386900000 + Valid From Timestamp : 1734216545 + Expires At : 1734302945 + Link Fee : 3401024329593900 + Native Fee : 25889252994400 + ------------------------------------------ + 2024-12-14T17:49:06-05:00 Raw report data for Stream ID 0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265: {"fullReport":"0x00060a2676459d14176b64106fcf3246631d3a03734171737eb082fe79c956e0000000000000000000000000000000000000000000000000000000005437220a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002800001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d026500000000000000000000000000000000000000000000000000000000675e0b6100000000000000000000000000000000000000000000000000000000675e0b610000000000000000000000000000000000000000000000000000178bc5ba4c04000000000000000000000000000000000000000000000000000c153d429e703c00000000000000000000000000000000000000000000000000000000675f5ce1000000000000000000000000000000000000000000000001980b3d7d3ec2df6000000000000000000000000000000000000000000000000197f69e569cfba588000000000000000000000000000000000000000000000001981e643ba148a6040000000000000000000000000000000000000000000000000000000000000002ae4d6d1a241622f6b9c5cc53c5ac6abc4e46759c7bda4942936e02f2fc9ba7374869e71ce1572ae581049e6e9463537056031e30b0c11f84ff44e45363e3fa9300000000000000000000000000000000000000000000000000000000000000021ab422f2202e0f59016a29b37c2795b47d78c19ba2358808794c6f0cd3b04bde7adb2f30669b051ddde1059f106c161c65c401909b78d76bd13ad593e31ab13e","feedID":"0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265","validFromTimestamp":1734216545,"observationsTimestamp":1734216545} + + + Decoded Report for Stream ID 0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265: + ------------------------------------------ + Observations Timestamp: 1734216545 + Benchmark Price : 29402662200351580000 + Bid : 29396857712545605000 + Ask : 29408052824047658500 + Valid From Timestamp : 1734216545 + Expires At : 1734302945 + Link Fee : 3401052575395900 + Native Fee : 25889085213700 + ------------------------------------------ + ``` + + 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[v3.Data](reportResponse.FullReport) + ``` + + 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 + +2. Data access: + ```go + data := decodedReport.Data + price := data.BenchmarkPrice.String() // Convert big number to string + bid := data.Bid.String() + ask := data.Ask.String() + validFrom := data.ValidFromTimestamp // Unix timestamp + expiresAt := data.ExpiresAt // Unix timestamp + ``` + Provides access to: + - Benchmark price, bid, and ask prices (as big numbers) + - **Note:** For [DEX State Price streams](/data-streams/concepts/dex-state-price-streams), which also use the V3 schema, the `bid` and `ask` fields contain the same value as `BenchmarkPrice`. + - 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. 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..70b6bf32396 --- /dev/null +++ b/src/content/data-streams/tutorials/go-sdk-stream.mdx @@ -0,0 +1,360 @@ +--- +section: dataStreams +date: Last Modified +title: "Stream and decode V3 reports via WebSocket using the Go SDK" +metadata: + title: "Stream Real-time Cryptocurrency Data with Go SDK | WebSocket Tutorial" + description: "Learn how to use the Go SDK to stream and decode real-time cryptocurrency market data via WebSocket connections from Chainlink Data Streams." + keywords: ["WebSocket", "Go SDK", "Golang", "Real-time", "Streaming", "Crypto Data", "V3 Reports", "Data Streams"] +whatsnext: + { + "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", + } +--- + +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 subscribe to real-time [V3 reports](/data-streams/reference/report-schema-v3) for [Crypto streams](/data-streams/crypto-streams) 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 + +### 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" + v3 "github.com/smartcontractkit/data-streams-sdk/go/report/v3" // Import the v3 report schema for Crypto streams. For RWA streams, use the v8 schema. + ) + + 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 + 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 + 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 the SDK client configuration within `stream.go` with your API credentials and the WebSocket URL: + + ```go + cfg := streams.Config{ + ApiKey: os.Getenv("API_KEY"), + ApiSecret: os.Getenv("API_SECRET"), + WsURL: "wss://ws.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. + + - `WsURL` is the [WebSocket URL](/data-streams/reference/data-streams-api/interface-ws#domains) for the Data Streams Aggregation Network. Use for the testnet environment. + + See the [SDK Reference](/data-streams/reference/data-streams-api/go-sdk#config-struct) page for more configuration options. + +1. For this example, you'll subscribe to the ETH/USD Data Streams crypto stream. This stream ID is . See the [Crypto Streams](/data-streams/crypto-streams) page for a complete list of available crypto assets. + + 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 + -------------------------------------------------------------------------------------------------------------------------------------------- + + [...] + ``` + +#### 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. | + +#### 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. + +## 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#L98) 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#L266) 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#L30) function parses and transforms the raw data into a structured format (`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/rust-sdk-decode.mdx b/src/content/data-streams/tutorials/rust-sdk-decode.mdx new file mode 100644 index 00000000000..010838e425f --- /dev/null +++ b/src/content/data-streams/tutorials/rust-sdk-decode.mdx @@ -0,0 +1,311 @@ +--- +section: dataStreams +date: Last Modified +title: "Fetch and decode V3 reports using the Rust SDK" +metadata: + title: "Fetch and Decode Cryptocurrency Data with Rust SDK | Chainlink Data Streams" + description: "Learn how to use the Rust SDK to fetch and decode cryptocurrency market data reports from Chainlink Data Streams in your Rust applications." + keywords: ["Rust SDK", "Cryptocurrency", "V3 Reports", "API Tutorial", "Data Streams", "Market Data", "Async"] +whatsnext: + { + "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/ws-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/crypto-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 [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 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 crypto 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, v3::ReportDataV3 }; + 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 = ReportDataV3::decode(&report_blob)?; + + // Print decoded report details + println!("\nDecoded Report for Stream ID {}:", feed_id_input); + println!("------------------------------------------"); + println!("Observations Timestamp: {}", response.report.observations_timestamp); + println!("Benchmark Price : {}", report_data.benchmark_price); + println!("Bid : {}", report_data.bid); + println!("Ask : {}", report_data.ask); + println!("Valid From Timestamp : {}", response.report.valid_from_timestamp); + println!("Expires At : {}", report_data.expires_at); + 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 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. + + Build and run your application: + + ```bash + cargo run -- 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 + ``` + + Expect output similar to the following in your terminal: + + ```bash + Raw report data: Report { feed_id: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782, valid_from_timestamp: 1734124400, observations_timestamp: 1734124400, full_report: "0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff1578000000000000000000000000000000000000000000000000000000004f56930f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba78200000000000000000000000000000000000000000000000000000000675ca37000000000000000000000000000000000000000000000000000000000675ca3700000000000000000000000000000000000000000000000000000174be1bd8758000000000000000000000000000000000000000000000000000cb326ce8c3ea800000000000000000000000000000000000000000000000000000000675df4f00000000000000000000000000000000000000000000000d3a30bcc15e207c0000000000000000000000000000000000000000000000000d3a1557b5e634060200000000000000000000000000000000000000000000000d3ab99a974ff10f400000000000000000000000000000000000000000000000000000000000000000292bdd75612560e46ed9b0c2437898f81eb0e18b6b902a161b9708e9177175cf3b8ef2b279f230f766fb29306250ee90856516ee349ca42b2d7fb141deb006745000000000000000000000000000000000000000000000000000000000000000221c156e80276827e1bfeb6542ab064dfa958f5be955f516fb62b1c93437472c31cc65fcaba68c9d661701190bc32025a0690af0eefe027ac218fd15c588dd4d5" } + + + Decoded Report for Stream ID 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782: + ------------------------------------------ + Observations Timestamp: 1734124400 + Benchmark Price : 3904011708000000000000 + Bid : 3903888333211164500000 + Ask : 3904628100124598400000 + Valid From Timestamp : 1734124400 + Expires At : 1734210800 + Link Fee : 3574678975954600 + Native Fee : 25614677280600 + ------------------------------------------ + ``` + +#### 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` | `1734124400` | The timestamp indicating when the data was captured. | +| `Benchmark Price` | `3904011708000000000000` | The observed price in the report, with 18 decimals. For readability: `3,904.0117080000000` USD per ETH. | +| `Bid` | `3903888333211164500000` | The highest price a buyer is willing to pay for an asset, with 18 decimals. For readability: `3,903.8883332111645` 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` | `3904628100124598400000` | The lowest price a seller is willing to accept for an asset, with 18 decimals. For readability: `3,904.6281001245984` 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` | `1734124400` | The start validity timestamp for the report, indicating when the data becomes relevant. | +| `Expires At` | `1734210800` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. | +| `Link Fee` | `3574678975954600` | The fee to pay in LINK tokens for the onchain verification of the report data. With 18 decimals. For readability: `0.003574678975954600` LINK. **Note:** This example fee is not indicative of actual fees. | +| `Native Fee` | `25614677280600` | 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. For readability: `0.0000256146772806000` ETH. **Note:** This example fee is not indicative of actual fees. | + +#### 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 + +1. [`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 + - 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 + +1. 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..])?; + ``` + +1. 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 + +1. Data extraction: [`ReportDataV3::decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report/v3.rs#L80) parses the report blob into structured data: + - Benchmark price + - Bid and ask prices for [liquidity-weighted pricing](/data-streams/concepts/liquidity-weighted-prices) + - **Note:** For [DEX State Price streams](/data-streams/concepts/dex-state-price-streams), which also use the V3 schema, the `bid` and `ask` fields contain the same value as `benchmark_price`. + - 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 + +1. Error propagation: + + - Uses the `?` operator for clean error handling + - Converts errors between types when needed + - Bubbles up errors to the main function + +1. 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/rust-sdk-stream.mdx b/src/content/data-streams/tutorials/rust-sdk-stream.mdx new file mode 100644 index 00000000000..cf269e254a4 --- /dev/null +++ b/src/content/data-streams/tutorials/rust-sdk-stream.mdx @@ -0,0 +1,407 @@ +--- +section: dataStreams +date: Last Modified +title: "Stream and decode V3 reports via WebSocket using the Rust SDK" +metadata: + title: "WebSocket Integration with Rust SDK | Chainlink Data Streams" + description: "Learn how to stream and decode Chainlink Data Streams V3 reports using WebSocket connections with the Rust SDK." + keywords: ["WebSocket", "Rust SDK", "Data Streams", "Real-time data", "Crypto pricing", "Tutorial"] +whatsnext: + { + "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", + } +--- + +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 subscribe to real-time [V3 reports](/data-streams/reference/report-schema-v3) for [Crypto streams](/data-streams/crypto-streams) via a [WebSocket connection](/data-streams/reference/data-streams-api/interface-ws). You'll set up your Rust project, listen for real-time reports from the Data Streams Aggregation Network, decode the report data, and log their attributes to your terminal. + + + +## 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 + +### 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" + tracing = "0.1" + tracing-subscriber = { version = "0.3", features = ["time"] } + ``` + + Note: The `tracing` feature is required for logging functionality. + +### Establish a WebSocket connection and listen for real-time reports + +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, v3::ReportDataV3 }; + use chainlink_data_streams_sdk::config::Config; + use chainlink_data_streams_sdk::stream::Stream; + use std::env; + use std::error::Error; + use tracing::{ info, warn }; + use tracing_subscriber::fmt::time::UtcTime; + + #[tokio::main] + async fn main() -> Result<(), Box> { + // Initialize logging with UTC timestamps + tracing_subscriber + ::fmt() + .with_timer(UtcTime::rfc_3339()) + .with_max_level(tracing::Level::INFO) + .init(); + + // Get feed IDs from command line arguments + let args: Vec = env::args().collect(); + if args.len() < 2 { + eprintln!("Usage: cargo run [StreamID1] [StreamID2] ..."); + std::process::exit(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"); + + // Parse feed IDs from command line arguments + let mut feed_ids = Vec::new(); + for arg in args.iter().skip(1) { + let feed_id = ID::from_hex_str(arg)?; + feed_ids.push(feed_id); + } + + // Initialize the configuration + let config = Config::new( + api_key, + api_secret, + "https://api.testnet-dataengine.chain.link".to_string(), + "wss://ws.testnet-dataengine.chain.link".to_string() + ).build()?; + + // Create and initialize the stream + let mut stream = Stream::new(&config, feed_ids).await?; + stream.listen().await?; + + info!("WebSocket connection established. Listening for reports..."); + + // Process incoming reports + loop { + match stream.read().await { + Ok(response) => { + info!("\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 = ReportDataV3::decode(&report_blob)?; + + // Print decoded report details + info!( + "\n--- Report Stream ID: {} ---\n\ + ------------------------------------------\n\ + Observations Timestamp : {}\n\ + Price : {}\n\ + Bid : {}\n\ + Ask : {}\n\ + Valid From Timestamp : {}\n\ + Expires At : {}\n\ + Link Fee : {}\n\ + Native Fee : {}\n\ + ------------------------------------------", + response.report.feed_id.to_hex_string(), + response.report.observations_timestamp, + report_data.benchmark_price, + report_data.bid, + report_data.ask, + response.report.valid_from_timestamp, + report_data.expires_at, + report_data.link_fee, + report_data.native_fee + ); + + // Print stream stats + info!( + "\n--- Stream Stats ---\n{:#?}\n\ + --------------------------------------------------------------------------------------------------------------------------------------------", + stream.get_stats() + ); + } + Err(e) => { + warn!("Error reading from stream: {:?}", e); + } + } + } + + // Note: In a production environment, you should implement proper cleanup + // by calling stream.close() when the application is terminated. + // For example: + // + // tokio::select! { + // _ = tokio::signal::ctrl_c() => { + // info!("Received shutdown signal"); + // stream.close().await?; + // } + // result = stream.read() => { + // // Process result + // } + // } + } + ``` + +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'll subscribe to the ETH/USD Data Streams crypto stream. This stream ID is . See the [Crypto Streams](/data-streams/crypto-streams) page for a complete list of available crypto assets. + + Build and run your application: + + ```bash + cargo run -- 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 + ``` + + Expect output similar to the following in your terminal: + + ```bash + 2024-12-13T23:07:56.463719Z INFO my_data_streams_project: WebSocket connection established. Listening for reports... + 2024-12-13T23:07:56.463824Z INFO data_streams_sdk::stream::monitor_connection: Received ping: [49] + 2024-12-13T23:07:56.463868Z INFO data_streams_sdk::stream::monitor_connection: Responding with pong: [49] + 2024-12-13T23:07:57.060504Z INFO data_streams_sdk::stream::monitor_connection: Received new report from Data Streams Endpoint. + 2024-12-13T23:07:57.061078Z INFO my_data_streams_project: + Raw report data: Report { feed_id: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782, valid_from_timestamp: 1734131277, observations_timestamp: 1734131277, full_report: "0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff1578000000000000000000000000000000000000000000000000000000004f5ac90d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba78200000000000000000000000000000000000000000000000000000000675cbe4d00000000000000000000000000000000000000000000000000000000675cbe4d000000000000000000000000000000000000000000000000000017489b06e8fc000000000000000000000000000000000000000000000000000c7badb615bd1400000000000000000000000000000000000000000000000000000000675e0fcd0000000000000000000000000000000000000000000000d3c0d34ca0d14d85600000000000000000000000000000000000000000000000d3bda64c97c9f3a3a00000000000000000000000000000000000000000000000d3c1a08e0cffd77690000000000000000000000000000000000000000000000000000000000000000238102110cad488ecf151a17276fcfad6ef1f05593edfe80f6823b729416f826972ba32d085525b1d7ab79e6ae8188928c86051a4fc75f500bffabda2acd1d1f900000000000000000000000000000000000000000000000000000000000000024dddbc660abf75c30cb3c2aa375c87d228b2ee8735e339f59c5214897c0b89af39a7602df754364cce029f6eb7699ee02ffded96d0c46b5919e81ee4f650d1cb" } + + 2024-12-13T23:07:57.062344Z INFO my_data_streams_project: + --- Report Stream ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 --- + ------------------------------------------ + Observations Timestamp : 1734131277 + Price : 3906157533081673500000 + Bid : 3905928693886829700000 + Ask : 3906215307384792250000 + Valid From Timestamp : 1734131277 + Expires At : 1734217677 + Link Fee : 3513685734964500 + Native Fee : 25600606005500 + ------------------------------------------ + 2024-12-13T23:07:57.062489Z INFO my_data_streams_project: + --- Stream Stats --- + StatsSnapshot { + accepted: 1, + deduplicated: 0, + total_received: 1, + partial_reconnects: 0, + full_reconnects: 0, + configured_connections: 1, + active_connections: 1, + } + -------------------------------------------------------------------------------------------------------------------------------------------- + 2024-12-13T23:07:58.065686Z INFO data_streams_sdk::stream::monitor_connection: Received new report from Data Streams Endpoint. + 2024-12-13T23:07:58.066315Z INFO my_data_streams_project: + Raw report data: Report { feed_id: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782, valid_from_timestamp: 1734131278, observations_timestamp: 1734131278, full_report: "0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff1578000000000000000000000000000000000000000000000000000000004f5ac911000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba78200000000000000000000000000000000000000000000000000000000675cbe4e00000000000000000000000000000000000000000000000000000000675cbe4e00000000000000000000000000000000000000000000000000001748ee300af4000000000000000000000000000000000000000000000000000c7b8b51304fbc00000000000000000000000000000000000000000000000000000000675e0fce0000000000000000000000000000000000000000000000d3bddf08d0b10a28e00000000000000000000000000000000000000000000000d3bb84af9f92f963c00000000000000000000000000000000000000000000000d3bf1d6bf14e501fc000000000000000000000000000000000000000000000000000000000000000021402b6b82c20826315384d74b3235b95f136ac65bba8c9e97c24d786e499894f298b51ae4aeba55cce0f85f2463e49e0a5e001b9a66f5b7b91e8be37d81d6cc5000000000000000000000000000000000000000000000000000000000000000217895cb599abc88d7b695edafed5ca5a5fc970f079b48bc2218888eec1fcccb0430c1ba2aa13b0d10f6c6b19a43cdb770029f4fb5804b0e2ef5ba3e73ca710f8" } + + 2024-12-13T23:07:58.067395Z INFO my_data_streams_project: + --- Report Stream ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 --- + ------------------------------------------ + Observations Timestamp : 1734131278 + Price : 3905944663438106700000 + Bid : 3905775117434634200000 + Ask : 3906034281472429400000 + Valid From Timestamp : 1734131278 + Expires At : 1734217678 + Link Fee : 3513538013319100 + Native Fee : 25602001210100 + ------------------------------------------ + 2024-12-13T23:07:58.067633Z INFO my_data_streams_project: + --- Stream Stats --- + StatsSnapshot { + accepted: 2, + deduplicated: 0, + total_received: 2, + partial_reconnects: 0, + full_reconnects: 0, + configured_connections: 1, + active_connections: 1, + } + + [...] + ``` + +The example above demonstrates streaming data from a single crypto stream. For production environments, especially when subscribing to multiple streams, it's recommended to enable [High Availability (HA) mode](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/docs/examples/wss_multiple.md). This can be achieved by: + +1. Adding multiple WebSocket endpoints in the configuration: + + ```rust + "wss://ws.testnet-dataengine.chain.link,wss://ws.testnet-dataengine.chain.link" + ``` + +1. Enabling HA mode in the configuration: + ```rust + use chainlink_data_streams_sdk::config::WebSocketHighAvailability; + // ... + .with_ws_ha(WebSocketHighAvailability::Enabled) + ``` + +When HA mode is enabled and multiple WebSocket origins are provided, the Stream will maintain concurrent connections to different instances. This ensures high availability, fault tolerance, and minimizes the risk of report gaps. + +You can subscribe to multiple streams by providing additional stream IDs as command-line arguments: + +```bash +cargo run -- \ + 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 \ + 0x00037da06d56d083fe599397a4769a042d63aa73dc4ef57709d31e9971a5b439 +``` + +This will subscribe to both ETH/USD and BTC/USD streams. + +#### 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` | `1734131277` | The timestamp indicating when the data was captured. | +| `Price` | `3906157533081673500000` | The observed price in the report. For readability: `3,906.1575330816735` USD per ETH. | +| `Bid` | `3905928693886829700000` | The highest price a buyer is willing to pay for an asset. For readability: `3,905.9286938868297` USD per ETH. Learn more about the [Bid price](/data-streams/concepts/liquidity-weighted-prices). | +| `Ask` | `3906215307384792250000` | The lowest price a seller is willing to accept for an asset. For readability: `3,906.2153073847923` USD per ETH. Learn more about the [Ask price](/data-streams/concepts/liquidity-weighted-prices). | +| `Valid From Timestamp` | `1734131277` | The start validity timestamp for the report, indicating when the data becomes relevant. | +| `Expires At` | `1734217677` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. | +| `Link Fee` | `3513685734964500` | The fee to pay in LINK tokens for the onchain verification of the report data. For readability: `0.0035136857349645` LINK. **Note:** This example fee is not indicative of actual fees. | +| `Native Fee` | `25600606005500` | The fee to pay in the native blockchain token (e.g., ETH on Ethereum) for the onchain verification of the report data. For readability: `0.0000256006060055` ETH. **Note:** This example fee is not indicative of actual fees. | + +#### 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 + +### Establishing a WebSocket connection and listening for reports + +The WebSocket connection is established in two steps: + +1. [`Stream::new`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/stream.rs#L131) initializes a new stream instance with your configuration and feed IDs. This function prepares the connection parameters but doesn't establish the connection yet. + +2. [`stream.listen()`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/stream.rs#L162) establishes the actual WebSocket connection and starts the background tasks that maintain the connection. These tasks handle: + - Automatic reconnection if the connection is lost + - Ping/pong messages to keep the connection alive + - Message queueing and delivery + +### Decoding a report + +As data reports arrive via the WebSocket connection, they are processed in real-time through several steps: + +1. Reading streams: The [`read`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/stream.rs#L218) method on the Stream object is called within a loop. This asynchronous method: + + - Awaits the next report from the WebSocket connection + - Handles backpressure automatically + - Returns a [`WebSocketReport`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/stream.rs#L43) containing the report data + +2. Decoding reports: Each report is decoded in two stages: + - [`decode_full_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report.rs#L77) parses the raw hexadecimal data, separating the report context (containing metadata) from the report blob + - [`ReportDataV3::decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report/v3.rs#L80) transforms the report blob into a structured format containing: + - The benchmark price + - Bid and ask prices for [liquidity-weighted pricing](/data-streams/concepts/liquidity-weighted-prices) + - Fee information for onchain verification + - Timestamp information + +### Handling the decoded data + +The example demonstrates several best practices for handling the decoded data: + +1. Logging: + + - Uses the [`tracing`](https://github.com/tokio-rs/tracing) crate for structured logging + - Configures UTC timestamps for consistent time representation + - Includes both raw report data and decoded fields for debugging + +2. Error handling: + + - Uses Rust's `Result` type for robust error handling + - Implements the `?` operator for clean error propagation + - Logs errors with appropriate context using `warn!` macro + +3. Stream monitoring: + - Tracks stream statistics through [`get_stats()`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/stream.rs#L253) + - Monitors connection status and reconnection attempts + - Reports message acceptance and deduplication counts + +The decoded data can be used for further processing, analysis, or display in your application. For production environments, it's recommended to verify the data onchain using the provided `full_report` payload. From 6c182b32621529f6ea88eadd4ba2507d5d82b71d Mon Sep 17 00:00:00 2001 From: Devin DiStefano Date: Mon, 25 Aug 2025 16:34:33 -0700 Subject: [PATCH 02/13] new content for generic DS tutorials --- .../data-streams/tutorials/go-sdk-decode.mdx | 415 +++++++------ .../data-streams/tutorials/go-sdk-stream.mdx | 543 +++++++++--------- .../tutorials/rust-sdk-decode.mdx | 126 ++-- .../tutorials/rust-sdk-stream.mdx | 168 +++--- 4 files changed, 701 insertions(+), 551 deletions(-) diff --git a/src/content/data-streams/tutorials/go-sdk-decode.mdx b/src/content/data-streams/tutorials/go-sdk-decode.mdx index a83ec549bb4..e975e2ecd3d 100644 --- a/src/content/data-streams/tutorials/go-sdk-decode.mdx +++ b/src/content/data-streams/tutorials/go-sdk-decode.mdx @@ -10,11 +10,11 @@ whatsnext: { "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" @@ -34,10 +34,7 @@ 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. @@ -49,7 +46,7 @@ retrieve reports, decode them, and log their attributes. ## 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 @@ -66,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 @@ -74,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) + } + + // Log the raw report data + cfg.Logger("Raw report data: %+v\n", reportResponse) + + // 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) + } + + // 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(), + ) + } + ``` + + + +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: -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. + ```bash + export API_KEY="" + export API_SECRET="" + ``` - Execute your application: + Replace `` and `` with your actual credentials. -```bash -go run single-stream.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 -``` + 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: -Expect output similar to the following in your terminal: + ```go + cfg := streams.Config{ + ApiKey: os.Getenv("API_KEY"), + ApiSecret: os.Getenv("API_SECRET"), + RestURL: "https://api.testnet-dataengine.chain.link", + Logger: streams.LogPrintf, + } + ``` -```bash -Raw report data: {"fullReport":"0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff1578000000000000000000000000000000000000000000000000000000004f8e8a11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba78200000000000000000000000000000000000000000000000000000000675e0a5b00000000000000000000000000000000000000000000000000000000675e0a5b00000000000000000000000000000000000000000000000000001787ff5c6fb8000000000000000000000000000000000000000000000000000c01807477ecd000000000000000000000000000000000000000000000000000000000675f5bdb0000000000000000000000000000000000000000000000d1865f8f627c4113300000000000000000000000000000000000000000000000d18572c6cdc3b915000000000000000000000000000000000000000000000000d1879ab8e98f743ad00000000000000000000000000000000000000000000000000000000000000002f3316e5c964d118f6683eecda454985fcc696e4ba34d65edb4a71a8d0cfe970676f465618c7d01196e433cc35b6994e7ad7b8189b0462b51458e663d601fdfaa0000000000000000000000000000000000000000000000000000000000000002219a4493fdf311421d664e0c8d69efa74b776461f8e252d191eda7edb980ab9a5cce69ec0ad35ba210cf60a201ceff6771b35b44860fda859f4aaba242c476bf","feedID":"0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782","validFromTimestamp":1734216283,"observationsTimestamp":1734216283} + 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. -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 ------------------------------------------- -``` + See the [SDK Reference](/data-streams/reference/data-streams-api/go-sdk#config-struct) page for more configuration options. -#### Decoded report details +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: -The decoded report details include: + ```bash + go run single-stream.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 + ``` + + Expect output similar to the following in your terminal: -| 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. | + ```bash + Raw report data: {"fullReport":"0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff1578000000000000000000000000000000000000000000000000000000004f8e8a11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba78200000000000000000000000000000000000000000000000000000000675e0a5b00000000000000000000000000000000000000000000000000000000675e0a5b00000000000000000000000000000000000000000000000000001787ff5c6fb8000000000000000000000000000000000000000000000000000c01807477ecd000000000000000000000000000000000000000000000000000000000675f5bdb0000000000000000000000000000000000000000000000d1865f8f627c4113300000000000000000000000000000000000000000000000d18572c6cdc3b915000000000000000000000000000000000000000000000000d1879ab8e98f743ad00000000000000000000000000000000000000000000000000000000000000002f3316e5c964d118f6683eecda454985fcc696e4ba34d65edb4a71a8d0cfe970676f465618c7d01196e433cc35b6994e7ad7b8189b0462b51458e663d601fdfaa0000000000000000000000000000000000000000000000000000000000000002219a4493fdf311421d664e0c8d69efa74b776461f8e252d191eda7edb980ab9a5cce69ec0ad35ba210cf60a201ceff6771b35b44860fda859f4aaba242c476bf","feedID":"0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782","validFromTimestamp":1734216283,"observationsTimestamp":1734216283} -#### Payload for onchain verification + 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 + ------------------------------------------ + ``` -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. + 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 @@ -281,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() { @@ -360,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"+ @@ -385,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 @@ -399,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 @@ -440,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). -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. +### 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](/datalink/pull-delivery/reference/report-schemas) documentation for complete field references for each version. ## Explanation @@ -469,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) @@ -522,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 @@ -535,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 index 70b6bf32396..9e3437e1a52 100644 --- a/src/content/data-streams/tutorials/go-sdk-stream.mdx +++ b/src/content/data-streams/tutorials/go-sdk-stream.mdx @@ -1,19 +1,19 @@ --- section: dataStreams date: Last Modified -title: "Stream and decode V3 reports via WebSocket using the Go SDK" +title: "Stream and decode Data Streams reports via WebSocket using the Go SDK" metadata: - title: "Stream Real-time Cryptocurrency Data with Go SDK | WebSocket Tutorial" - description: "Learn how to use the Go SDK to stream and decode real-time cryptocurrency market data via WebSocket connections from Chainlink Data Streams." - keywords: ["WebSocket", "Go SDK", "Golang", "Real-time", "Streaming", "Crypto Data", "V3 Reports", "Data Streams"] + 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 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" @@ -21,49 +21,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 subscribe to real-time [V3 reports](/data-streams/reference/report-schema-v3) for [Crypto streams](/data-streams/crypto-streams) 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. +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. @@ -75,6 +45,8 @@ In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/r ## 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: @@ -98,252 +70,303 @@ In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/r ### 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" - v3 "github.com/smartcontractkit/data-streams-sdk/go/report/v3" // Import the v3 report schema for Crypto streams. For RWA streams, use the v8 schema. - ) - - 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{ +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, - } - - // 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 - 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 - 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", - ) - } } - ``` + ``` + + 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 -1. Download the required dependencies and update the `go.mod` and `go.sum` files: +The decoded report details include: - ```bash - go mod tidy - ``` +| 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. | -1. Set up the SDK client configuration within `stream.go` with your API credentials and the WebSocket URL: +For descriptions and data types of other report schemas, see the [Report Schema Overview](/data-streams/reference/report-schema-overview). - ```go - cfg := streams.Config{ - ApiKey: os.Getenv("API_KEY"), - ApiSecret: os.Getenv("API_SECRET"), - WsURL: "wss://ws.testnet-dataengine.chain.link", - Logger: streams.LogPrintf, - } - ``` +### Payload for onchain verification - - Set your API credentials as environment variables: +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. - ```bash - export API_KEY="" - export API_SECRET="" - ``` +Refer to the [Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) tutorial to learn more. - Replace `` and `` with your API credentials. +## Adapting code for different report schema versions - - `WsURL` is the [WebSocket URL](/data-streams/reference/data-streams-api/interface-ws#domains) for the Data Streams Aggregation Network. Use for the testnet environment. +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: - See the [SDK Reference](/data-streams/reference/data-streams-api/go-sdk#config-struct) page for more configuration options. +1. Import the correct schema version. Examples: -1. For this example, you'll subscribe to the ETH/USD Data Streams crypto stream. This stream ID is . See the [Crypto Streams](/data-streams/crypto-streams) page for a complete list of available crypto assets. + - For v3 schema (as used in this example): - Execute your application: + ```go + v3 "github.com/smartcontractkit/data-streams-sdk/go/report/v3" + ``` - ```bash - go run stream.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 - ``` + - For v8 schema: - Expect output similar to the following in your terminal: + ```go + v8 "github.com/smartcontractkit/data-streams-sdk/go/report/v8" + ``` - ```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 - -------------------------------------------------------------------------------------------------------------------------------------------- - - [...] - ``` +1. Update the decode function to use the correct schema version. Examples: -#### Decoded report details + - For v3 schema (as used in this example): -The decoded report details include: + ```go + decodedReport, err := report.Decode[v3.Data](reportResponse.FullReport) + ``` -| 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 v8 schema: -#### Payload for onchain verification + ```go + decodedReport, err := report.Decode[v8.Data](reportResponse.FullReport) + ``` -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. +1. Access fields according to the schema version structure. Refer to the [Report Schemas](/datalink/pull-delivery/reference/report-schemas) 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#L98) 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. +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. @@ -351,9 +374,9 @@ Once the WebSocket connection is established, your application subscribes to one 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#L266) 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. +- 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#L30) function parses and transforms the raw data into a structured format (`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. +- 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 diff --git a/src/content/data-streams/tutorials/rust-sdk-decode.mdx b/src/content/data-streams/tutorials/rust-sdk-decode.mdx index 010838e425f..1dd316f233a 100644 --- a/src/content/data-streams/tutorials/rust-sdk-decode.mdx +++ b/src/content/data-streams/tutorials/rust-sdk-decode.mdx @@ -1,20 +1,20 @@ --- section: dataStreams date: Last Modified -title: "Fetch and decode V3 reports using the Rust SDK" +title: "Fetch and decode Data Streams reports using the Rust SDK" metadata: - title: "Fetch and Decode Cryptocurrency Data with Rust SDK | Chainlink Data Streams" - description: "Learn how to use the Rust SDK to fetch and decode cryptocurrency market data reports from Chainlink Data Streams in your Rust applications." - keywords: ["Rust SDK", "Cryptocurrency", "V3 Reports", "API Tutorial", "Data Streams", "Market Data", "Async"] + title: "Fetch and Decode Data Streams Reports with Rust SDK | Chainlink Data Streams" + description: "Learn how to use the Rust SDK to fetch and decode Data Streams reports from Chainlink Data Streams in your Rust applications." + keywords: ["Rust SDK", "API Tutorial", "Data Streams", "Market Data", "Async"] whatsnext: { "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/ws-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/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,49 +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/rust-sdk) for Rust 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 Rust 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/rust-sdk) for Rust to fetch and decode [reports](/data-streams/reference/report-schema-overview) from the Data Streams Aggregation Network. You'll set up your Rust project, retrieve reports, decode them, and log their attributes. @@ -75,7 +45,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 Rust project. Next, you'll fetch and decode reports for crypto streams and log their attributes to your terminal. +You'll start with the set up of your Rust project, installing the SDK and pasting example code. Next, you'll fetch and decode reports for crypto streams and log their attributes to your terminal. ### Set up your Rust project @@ -107,6 +77,7 @@ You'll start with the set up of your Rust project. Next, you'll fetch and decode ```rust use chainlink_data_streams_report::feed_id::ID; + // NOTE: Use the report version (v3, v8, etc.) that matches your stream use chainlink_data_streams_report::report::{ decode_full_report, v3::ReportDataV3 }; use chainlink_data_streams_sdk::client::Client; use chainlink_data_streams_sdk::config::Config; @@ -148,9 +119,11 @@ You'll start with the set up of your Rust project. Next, you'll fetch and decode // Decode the report let full_report = hex::decode(&response.report.full_report[2..])?; let (_report_context, report_blob) = decode_full_report(&full_report)?; + // NOTE: Use the report version (v3, v8, etc.) that matches your stream let report_data = ReportDataV3::decode(&report_blob)?; // Print decoded report details + // NOTE: Adjust for your report and desired output println!("\nDecoded Report for Stream ID {}:", feed_id_input); println!("------------------------------------------"); println!("Observations Timestamp: {}", response.report.observations_timestamp); @@ -176,9 +149,26 @@ You'll start with the set up of your Rust project. Next, you'll fetch and decode Replace `` and `` with your API credentials. -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. + The Rust code sample reads these environment variables using `std::env::var("API_KEY")` and `std::env::var("API_SECRET")` when building the client configuration: + + ```rust + let api_key = std::env::var("API_KEY").expect("API_KEY must be set"); + let api_secret = std::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()?; + ``` + + This configuration also specifies the `rest_url`, which is the base URL for the API, along with the WebSocket endpoint [for subscribing to a streamed data report](rust-sdk-stream). In this example, both are set to the testnet URLs for Data Streams. + + See the [Rust SDK Reference](/data-streams/reference/data-streams-api/rust-sdk#config-struct) page for more configuration options. - Build and run your application: +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: ```bash cargo run -- 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 @@ -203,6 +193,10 @@ You'll start with the set up of your Rust project. Next, you'll fetch and decode ------------------------------------------ ``` + Your application has successfully decoded the report data. + + [Learn more about the decoded report details](#decoded-report-details). + #### Decoded report details The decoded report details include: @@ -219,11 +213,47 @@ The decoded report details include: | `Link Fee` | `3574678975954600` | The fee to pay in LINK tokens for the onchain verification of the report data. With 18 decimals. For readability: `0.003574678975954600` LINK. **Note:** This example fee is not indicative of actual fees. | | `Native Fee` | `25614677280600` | 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. For readability: `0.0000256146772806000` ETH. **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 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. +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 DataLink providers, you'll need to adapt your code to handle the specific report schema version they use: + +1. Import the correct schema version module. Examples: + + - For v3 schema (as used in this example): + + ```rust + use chainlink_data_streams_report::report::{ decode_full_report, v3::ReportDataV3 }; + ``` + + - For v8 schema: + + ```rust + use chainlink_data_streams_report::report::{ decode_full_report, v8::ReportDataV8 }; + ``` + +1. Update the decode function to use the correct schema version. Examples: + + - For v3 schema (as used in this example): + + ```rust + let report_data = ReportDataV3::decode(&report_blob)?; + ``` + + - For v8 schema: + + ```rust + let report_data = ReportDataV8::decode(&report_blob)?; + ``` + +1. Access fields according to the schema version structure. Refer to the [Report Schemas](/datalink/pull-delivery/reference/report-schemas) documentation for complete field references for each version. ## Explanation @@ -274,7 +304,7 @@ Reports are decoded in three stages: let full_report = hex::decode(&response.report.full_report[2..])?; ``` -1. 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: +1. Report separation: [`decode_full_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report.rs#L83) splits the binary data: - Extracts the report context (metadata) - Isolates the report blob (actual data) diff --git a/src/content/data-streams/tutorials/rust-sdk-stream.mdx b/src/content/data-streams/tutorials/rust-sdk-stream.mdx index cf269e254a4..042a519ade0 100644 --- a/src/content/data-streams/tutorials/rust-sdk-stream.mdx +++ b/src/content/data-streams/tutorials/rust-sdk-stream.mdx @@ -1,19 +1,19 @@ --- section: dataStreams date: Last Modified -title: "Stream and decode V3 reports via WebSocket using the Rust SDK" +title: "Stream and decode Data Streams reports via WebSocket using the Rust SDK" metadata: - title: "WebSocket Integration with Rust SDK | Chainlink Data Streams" - description: "Learn how to stream and decode Chainlink Data Streams V3 reports using WebSocket connections with the Rust SDK." - keywords: ["WebSocket", "Rust SDK", "Data Streams", "Real-time data", "Crypto pricing", "Tutorial"] + title: "Stream Real-time Data Streams Reports with Rust SDK | WebSocket Tutorial" + description: "Learn how to stream and decode Chainlink Data Streams reports using WebSocket connections with the Rust SDK." + keywords: ["WebSocket", "Rust SDK", "Data Streams", "Real-time data", "Tutorial"] whatsnext: { "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" @@ -21,49 +21,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/rust-sdk) for Rust to subscribe to real-time [V3 reports](/data-streams/reference/report-schema-v3) for [Crypto streams](/data-streams/crypto-streams) via a [WebSocket connection](/data-streams/reference/data-streams-api/interface-ws). You'll set up your Rust project, listen for real-time reports from the Data Streams Aggregation Network, decode the report data, and log their attributes to your terminal. +In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/reference/data-streams-api/rust-sdk) for Rust 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 Rust project, listen for real-time reports from the Data Streams Aggregation Network, decode the report data, and log their attributes to your terminal. @@ -108,6 +78,7 @@ In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/r ```rust use chainlink_data_streams_report::feed_id::ID; + // NOTE: Use the report version (v3, v8, etc.) that matches your stream use chainlink_data_streams_report::report::{ decode_full_report, v3::ReportDataV3 }; use chainlink_data_streams_sdk::config::Config; use chainlink_data_streams_sdk::stream::Stream; @@ -166,9 +137,11 @@ In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/r // Decode the report let full_report = hex::decode(&response.report.full_report[2..])?; let (_report_context, report_blob) = decode_full_report(&full_report)?; + // NOTE: Use the report version (v3, v8, etc.) that matches your stream let report_data = ReportDataV3::decode(&report_blob)?; // Print decoded report details + // NOTE: Adjust for your report and desired output info!( "\n--- Report Stream ID: {} ---\n\ ------------------------------------------\n\ @@ -221,6 +194,14 @@ In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/r } ``` + + 1. Set up your API credentials as environment variables: ```bash @@ -230,9 +211,26 @@ In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/r Replace `` and `` with your API credentials. -1. For this example, you'll subscribe to the ETH/USD Data Streams crypto stream. This stream ID is . See the [Crypto Streams](/data-streams/crypto-streams) page for a complete list of available crypto assets. + The Rust code sample reads these environment variables using `std::env::var("API_KEY")` and `std::env::var("API_SECRET")` when building the client configuration: + + ```rust + let api_key = std::env::var("API_KEY").expect("API_KEY must be set"); + let api_secret = std::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()?; + ``` + + This configuration also specifies the `rest_url`, which is the base URL for the API, along with the WebSocket endpoint [for subscribing to a streamed data report](rust-sdk-stream). In this example, both are set to the testnet URLs for Data Streams. + + See the [Rust SDK Reference](/data-streams/reference/data-streams-api/rust-sdk#config-struct) page for more configuration options. - Build and run your application: +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: ```bash cargo run -- 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 @@ -263,13 +261,13 @@ In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/r 2024-12-13T23:07:57.062489Z INFO my_data_streams_project: --- Stream Stats --- StatsSnapshot { - accepted: 1, - deduplicated: 0, - total_received: 1, - partial_reconnects: 0, - full_reconnects: 0, - configured_connections: 1, - active_connections: 1, + accepted: 1, + deduplicated: 0, + total_received: 1, + partial_reconnects: 0, + full_reconnects: 0, + configured_connections: 1, + active_connections: 1, } -------------------------------------------------------------------------------------------------------------------------------------------- 2024-12-13T23:07:58.065686Z INFO data_streams_sdk::stream::monitor_connection: Received new report from Data Streams Endpoint. @@ -291,18 +289,24 @@ In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/r 2024-12-13T23:07:58.067633Z INFO my_data_streams_project: --- Stream Stats --- StatsSnapshot { - accepted: 2, - deduplicated: 0, - total_received: 2, - partial_reconnects: 0, - full_reconnects: 0, - configured_connections: 1, - active_connections: 1, + accepted: 2, + deduplicated: 0, + total_received: 2, + 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). + +### High Availability (HA) Mode + The example above demonstrates streaming data from a single crypto stream. For production environments, especially when subscribing to multiple streams, it's recommended to enable [High Availability (HA) mode](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/docs/examples/wss_multiple.md). This can be achieved by: 1. Adding multiple WebSocket endpoints in the configuration: @@ -330,7 +334,7 @@ cargo run -- \ This will subscribe to both ETH/USD and BTC/USD streams. -#### Decoded report details +### Decoded report details The decoded report details include: @@ -346,11 +350,47 @@ The decoded report details include: | `Link Fee` | `3513685734964500` | The fee to pay in LINK tokens for the onchain verification of the report data. For readability: `0.0035136857349645` LINK. **Note:** This example fee is not indicative of actual fees. | | `Native Fee` | `25600606005500` | The fee to pay in the native blockchain token (e.g., ETH on Ethereum) for the onchain verification of the report data. For readability: `0.0000256006060055` ETH. **Note:** This example fee is not indicative of actual fees. | -#### Payload for onchain verification +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 DataLink providers, you'll need to adapt your code to handle the specific report schema version they use: + +1. Import the correct schema version module. Examples: + + - For v3 schema (as used in this example): + + ```rust + use chainlink_data_streams_report::report::{ decode_full_report, v3::ReportDataV3 }; + ``` + + - For v8 schema: + + ```rust + use chainlink_data_streams_report::report::{ decode_full_report, v8::ReportDataV8 }; + ``` + +1. Update the decode function to use the correct schema version. Examples: + + - For v3 schema (as used in this example): + + ```rust + let report_data = ReportDataV3::decode(&report_blob)?; + ``` + + - For v8 schema: + + ```rust + let report_data = ReportDataV8::decode(&report_blob)?; + ``` -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. +1. Access fields according to the schema version structure. Refer to the [Report Schemas](/datalink/pull-delivery/reference/report-schemas) documentation for complete field references for each version. ## Explanation @@ -373,10 +413,10 @@ As data reports arrive via the WebSocket connection, they are processed in real- - Awaits the next report from the WebSocket connection - Handles backpressure automatically - - Returns a [`WebSocketReport`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/stream.rs#L43) containing the report data + - Returns a [`WebSocketReport`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/stream.rs#L51) containing the report data 2. Decoding reports: Each report is decoded in two stages: - - [`decode_full_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report.rs#L77) parses the raw hexadecimal data, separating the report context (containing metadata) from the report blob + - [`decode_full_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report.rs#L83) parses the raw hexadecimal data, separating the report context (containing metadata) from the report blob - [`ReportDataV3::decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report/v3.rs#L80) transforms the report blob into a structured format containing: - The benchmark price - Bid and ask prices for [liquidity-weighted pricing](/data-streams/concepts/liquidity-weighted-prices) From 9610651561f0a89baf70a8492626ed7f68b87751 Mon Sep 17 00:00:00 2001 From: Devin DiStefano Date: Mon, 25 Aug 2025 18:22:25 -0700 Subject: [PATCH 03/13] remove old tutos and update links, redirects --- src/content/data-streams/architecture.mdx | 2 +- .../developer-responsibilities.mdx | 2 +- src/content/data-streams/index.mdx | 4 +- .../reference/data-streams-api/go-sdk.mdx | 4 +- .../reference/data-streams-api/rust-sdk.mdx | 8 +- src/content/data-streams/tutorials/api-go.mdx | 602 ----------------- .../data-streams/tutorials/api-nav-go.mdx | 618 ------------------ .../data-streams/tutorials/api-nav-rust.mdx | 308 --------- .../data-streams/tutorials/api-rust.mdx | 301 --------- .../data-streams/tutorials/api-rwa-go.mdx | 603 ----------------- .../data-streams/tutorials/api-rwa-rust.mdx | 302 --------- .../evm-onchain-report-verification.mdx | 6 +- .../data-streams/tutorials/overview.mdx | 4 +- .../tutorials/rust-sdk-decode.mdx | 2 +- src/content/data-streams/tutorials/ws-go.mdx | 350 ---------- .../data-streams/tutorials/ws-nav-go.mdx | 356 ---------- .../data-streams/tutorials/ws-nav-rust.mdx | 386 ----------- .../data-streams/tutorials/ws-rust.mdx | 397 ----------- .../data-streams/tutorials/ws-rwa-go.mdx | 348 ---------- .../data-streams/tutorials/ws-rwa-rust.mdx | 374 ----------- .../data-streams/common/gettingStarted.mdx | 2 +- .../common/gettingStartedHardhat.mdx | 2 +- src/features/feeds/components/FeedPage.astro | 2 +- src/features/redirects/redirects.json | 80 +++ 24 files changed, 99 insertions(+), 4964 deletions(-) delete mode 100644 src/content/data-streams/tutorials/api-go.mdx delete mode 100644 src/content/data-streams/tutorials/api-nav-go.mdx delete mode 100644 src/content/data-streams/tutorials/api-nav-rust.mdx delete mode 100644 src/content/data-streams/tutorials/api-rust.mdx delete mode 100644 src/content/data-streams/tutorials/api-rwa-go.mdx delete mode 100644 src/content/data-streams/tutorials/api-rwa-rust.mdx delete mode 100644 src/content/data-streams/tutorials/ws-go.mdx delete mode 100644 src/content/data-streams/tutorials/ws-nav-go.mdx delete mode 100644 src/content/data-streams/tutorials/ws-nav-rust.mdx delete mode 100644 src/content/data-streams/tutorials/ws-rust.mdx delete mode 100644 src/content/data-streams/tutorials/ws-rwa-go.mdx delete mode 100644 src/content/data-streams/tutorials/ws-rwa-rust.mdx diff --git a/src/content/data-streams/architecture.mdx b/src/content/data-streams/architecture.mdx index 231f03df117..b0d0924dfe6 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-decode", "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..34a52cdfc83 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-decode", } --- diff --git a/src/content/data-streams/index.mdx b/src/content/data-streams/index.mdx index f126bd2b511..7ce852951c9 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-decode", "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", @@ -88,7 +88,7 @@ Access data directly through REST APIs or WebSocket connections using our SDKs: 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. 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-decode) 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..64dd4834832 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-decode", + "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..f8d37340eb6 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-decode", + "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-decode) +- [Stream and decode reports via WebSocket](/data-streams/tutorials/rust-sdk-stream) ### More Examples diff --git a/src/content/data-streams/tutorials/api-go.mdx b/src/content/data-streams/tutorials/api-go.mdx deleted file mode 100644 index 4fcc91a788c..00000000000 --- a/src/content/data-streams/tutorials/api-go.mdx +++ /dev/null @@ -1,602 +0,0 @@ ---- -section: dataStreams -date: Last Modified -title: "Fetch and decode V3 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"] -whatsnext: - { - "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/ws-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/crypto-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 [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. - - - -## 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 [crypto streams](/data-streams/crypto-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" - 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(), - ) - } - ``` - -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 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. - - Execute your application: - -```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 ------------------------------------------- -``` - -#### 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` | `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. | - -#### 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. - -### 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" - 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) < 3 { - fmt.Printf("Usage: go run multiple-streams.go [StreamID1] [StreamID2] ...\n"+ - "Example: go run multiple-streams.go "+ - "0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 "+ - "0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265\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[v3.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"+ - "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(), - ) - } - } - ``` - -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 the ETH/USD and LINK/USD Data Streams crypto streams. Run your application: - - ```bash - go run multiple-streams.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265 - ``` - - Expect to see the output below in your terminal: - - ```bash - 2024-12-14T17:49:06-05:00 Raw report data for Stream ID 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782: {"fullReport":"0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff1578000000000000000000000000000000000000000000000000000000004f8eb301000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba78200000000000000000000000000000000000000000000000000000000675e0b6100000000000000000000000000000000000000000000000000000000675e0b610000000000000000000000000000000000000000000000000000178bcfba6d60000000000000000000000000000000000000000000000000000c1536af09b42c00000000000000000000000000000000000000000000000000000000675f5ce10000000000000000000000000000000000000000000000d1646f5fd0b1e6e6a00000000000000000000000000000000000000000000000d1635f8df6b0fce2600000000000000000000000000000000000000000000000d1677c13a6c9d89620000000000000000000000000000000000000000000000000000000000000000222412e1bd137097dc97def8914c72ae7305179eedc5c15e344bc119a06f1db76ef20f3e6493a97c2be2ab831199bfc00dbbf02551f2a27a70cfd55653270acac0000000000000000000000000000000000000000000000000000000000000002343957d73014b446eb0b0436072e16261a643102e502529d3b97412027c3468977bf0806e8971a37e6487b855243957a57749cde2ac92ebc2bda412d94981251","feedID":"0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782","validFromTimestamp":1734216545,"observationsTimestamp":1734216545} - - - Decoded Report for Stream ID 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782: - ------------------------------------------ - Observations Timestamp: 1734216545 - Benchmark Price : 3862606619881446500000 - Bid : 3862530109428509500000 - Ask : 3862826368095386900000 - Valid From Timestamp : 1734216545 - Expires At : 1734302945 - Link Fee : 3401024329593900 - Native Fee : 25889252994400 - ------------------------------------------ - 2024-12-14T17:49:06-05:00 Raw report data for Stream ID 0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265: {"fullReport":"0x00060a2676459d14176b64106fcf3246631d3a03734171737eb082fe79c956e0000000000000000000000000000000000000000000000000000000005437220a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002800001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d026500000000000000000000000000000000000000000000000000000000675e0b6100000000000000000000000000000000000000000000000000000000675e0b610000000000000000000000000000000000000000000000000000178bc5ba4c04000000000000000000000000000000000000000000000000000c153d429e703c00000000000000000000000000000000000000000000000000000000675f5ce1000000000000000000000000000000000000000000000001980b3d7d3ec2df6000000000000000000000000000000000000000000000000197f69e569cfba588000000000000000000000000000000000000000000000001981e643ba148a6040000000000000000000000000000000000000000000000000000000000000002ae4d6d1a241622f6b9c5cc53c5ac6abc4e46759c7bda4942936e02f2fc9ba7374869e71ce1572ae581049e6e9463537056031e30b0c11f84ff44e45363e3fa9300000000000000000000000000000000000000000000000000000000000000021ab422f2202e0f59016a29b37c2795b47d78c19ba2358808794c6f0cd3b04bde7adb2f30669b051ddde1059f106c161c65c401909b78d76bd13ad593e31ab13e","feedID":"0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265","validFromTimestamp":1734216545,"observationsTimestamp":1734216545} - - - Decoded Report for Stream ID 0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265: - ------------------------------------------ - Observations Timestamp: 1734216545 - Benchmark Price : 29402662200351580000 - Bid : 29396857712545605000 - Ask : 29408052824047658500 - Valid From Timestamp : 1734216545 - Expires At : 1734302945 - Link Fee : 3401052575395900 - Native Fee : 25889085213700 - ------------------------------------------ - ``` - - 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[v3.Data](reportResponse.FullReport) - ``` - - 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 - -2. Data access: - ```go - data := decodedReport.Data - price := data.BenchmarkPrice.String() // Convert big number to string - bid := data.Bid.String() - ask := data.Ask.String() - validFrom := data.ValidFromTimestamp // Unix timestamp - expiresAt := data.ExpiresAt // Unix timestamp - ``` - Provides access to: - - Benchmark price, bid, and ask prices (as big numbers) - - **Note:** For [DEX State Price streams](/data-streams/concepts/dex-state-price-streams), which also use the V3 schema, the `bid` and `ask` fields contain the same value as `BenchmarkPrice`. - - 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. 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-rust.mdx b/src/content/data-streams/tutorials/api-rust.mdx deleted file mode 100644 index c0ad366ad99..00000000000 --- a/src/content/data-streams/tutorials/api-rust.mdx +++ /dev/null @@ -1,301 +0,0 @@ ---- -section: dataStreams -date: Last Modified -title: "Fetch and decode V3 reports using the Rust SDK" -metadata: - title: "Fetch and Decode Cryptocurrency Data with Rust SDK | Chainlink Data Streams" - description: "Learn how to use the Rust SDK to fetch and decode cryptocurrency market data reports from Chainlink Data Streams in your Rust applications." - keywords: ["Rust SDK", "Cryptocurrency", "V3 Reports", "API Tutorial", "Data Streams", "Market Data", "Async"] -whatsnext: - { - "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/ws-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/crypto-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 [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 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 crypto 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, v3::ReportDataV3 }; - 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 = ReportDataV3::decode(&report_blob)?; - - // Print decoded report details - println!("\nDecoded Report for Stream ID {}:", feed_id_input); - println!("------------------------------------------"); - println!("Observations Timestamp: {}", response.report.observations_timestamp); - println!("Benchmark Price : {}", report_data.benchmark_price); - println!("Bid : {}", report_data.bid); - println!("Ask : {}", report_data.ask); - println!("Valid From Timestamp : {}", response.report.valid_from_timestamp); - println!("Expires At : {}", report_data.expires_at); - 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 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. - - Build and run your application: - - ```bash - cargo run -- 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 - ``` - - Expect output similar to the following in your terminal: - - ```bash - Raw report data: Report { feed_id: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782, valid_from_timestamp: 1734124400, observations_timestamp: 1734124400, full_report: "0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff1578000000000000000000000000000000000000000000000000000000004f56930f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba78200000000000000000000000000000000000000000000000000000000675ca37000000000000000000000000000000000000000000000000000000000675ca3700000000000000000000000000000000000000000000000000000174be1bd8758000000000000000000000000000000000000000000000000000cb326ce8c3ea800000000000000000000000000000000000000000000000000000000675df4f00000000000000000000000000000000000000000000000d3a30bcc15e207c0000000000000000000000000000000000000000000000000d3a1557b5e634060200000000000000000000000000000000000000000000000d3ab99a974ff10f400000000000000000000000000000000000000000000000000000000000000000292bdd75612560e46ed9b0c2437898f81eb0e18b6b902a161b9708e9177175cf3b8ef2b279f230f766fb29306250ee90856516ee349ca42b2d7fb141deb006745000000000000000000000000000000000000000000000000000000000000000221c156e80276827e1bfeb6542ab064dfa958f5be955f516fb62b1c93437472c31cc65fcaba68c9d661701190bc32025a0690af0eefe027ac218fd15c588dd4d5" } - - - Decoded Report for Stream ID 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782: - ------------------------------------------ - Observations Timestamp: 1734124400 - Benchmark Price : 3904011708000000000000 - Bid : 3903888333211164500000 - Ask : 3904628100124598400000 - Valid From Timestamp : 1734124400 - Expires At : 1734210800 - Link Fee : 3574678975954600 - Native Fee : 25614677280600 - ------------------------------------------ - ``` - -#### 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` | `1734124400` | The timestamp indicating when the data was captured. | -| `Benchmark Price` | `3904011708000000000000` | The observed price in the report, with 18 decimals. For readability: `3,904.0117080000000` USD per ETH. | -| `Bid` | `3903888333211164500000` | The highest price a buyer is willing to pay for an asset, with 18 decimals. For readability: `3,903.8883332111645` 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` | `3904628100124598400000` | The lowest price a seller is willing to accept for an asset, with 18 decimals. For readability: `3,904.6281001245984` 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` | `1734124400` | The start validity timestamp for the report, indicating when the data becomes relevant. | -| `Expires At` | `1734210800` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. | -| `Link Fee` | `3574678975954600` | The fee to pay in LINK tokens for the onchain verification of the report data. With 18 decimals. For readability: `0.003574678975954600` LINK. **Note:** This example fee is not indicative of actual fees. | -| `Native Fee` | `25614677280600` | 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. For readability: `0.0000256146772806000` ETH. **Note:** This example fee is not indicative of actual fees. | - -#### 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 - -1. [`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 - - 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 - -1. 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..])?; - ``` - -1. 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 - -1. Data extraction: [`ReportDataV3::decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report/v3.rs#L80) parses the report blob into structured data: - - Benchmark price - - Bid and ask prices for [liquidity-weighted pricing](/data-streams/concepts/liquidity-weighted-prices) - - **Note:** For [DEX State Price streams](/data-streams/concepts/dex-state-price-streams), which also use the V3 schema, the `bid` and `ask` fields contain the same value as `benchmark_price`. - - 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 - -1. Error propagation: - - - Uses the `?` operator for clean error handling - - Converts errors between types when needed - - Bubbles up errors to the main function - -1. 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/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..0b7cc5ea40b 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-decode) +- [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-decode) tutorial as an example: ``` 0x000660403d36be006d0c15d9b306f93c8660c5cfeab7db8e28c78ba316d395970000000000000000000000000000000000000000000000000000000032c3780a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200003c8e550d2fc5304993010112de9b69798297e4cc11990ee6250e464daf760000000000000000000000000000000000000000000000000000000006706e595000000000000000000000000000000000000000000000000000000006706e595000000000000000000000000000000000000000000000000000025bd3eb74c080000000000000000000000000000000000000000000000000021c6a95c654c7400000000000000000000000000000000000000000000000000000000670837150000000000000000000000000000000000000000000000079a2ab4077fc8fc6000000000000000000000000000000000000000000000000799fcb42536dfd8300000000000000000000000000000000000000000000000079a59496c3f29a0000000000000000000000000000000000000000000000000000000000000000002bd4acd37ce3cd5799de05d156ab328a5effd94468ebbaf2ff18d13d9631259cbe66cca01af6a8bb36e79d2d731a44e16791ee31e46ce27ed6530f1590cd7734c0000000000000000000000000000000000000000000000000000000000000002391562f1f2e4986bdb978fbf5ee27f7012992a79301af42d3473761ef2ede6271a61fbf4b32ac5be68a598bcfa523e035b624dab3b3d9a46276834f824ee592a diff --git a/src/content/data-streams/tutorials/overview.mdx b/src/content/data-streams/tutorials/overview.mdx index b1f1227f053..8a191081b91 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-decode): 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.