Fetch and decode reports using the SDK (RWA Streams)

Guide Versions

This guide is available in multiple versions. Choose the one that matches your needs.

In this guide, you'll learn how to use Chainlink Data Streams with the Streams Direct implementation and the Data Streams SDK for Go to fetch and decode V4 reports for Real World Assets (RWAs) 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 git --version in your terminal and download the latest version from the official Git website 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 if necessary.
  • API Credentials: Access to the Streams Direct implementation requires API credentials. If you haven't already, contact us to request mainnet or testnet early access.

Guide

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, and log their attributes to your terminal.

Set up your Go project

  1. Create a new directory for your project and navigate to it:

    mkdir my-data-streams-project
    cd my-data-streams-project
    
  2. Initialize a new Go module:

    go mod init my-data-streams-project
    
  3. Install the Data Streams SDK:

    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:

    touch single-stream.go
    
  2. Insert the following code example and save your single-stream.go file:

     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"
         v4 "github.com/smartcontractkit/data-streams-sdk/go/report/v4" // Import the v4 report schema for RWA streams. For Crypto streams, use the v3 schema.
     )
    
     func main() {
         if len(os.Args) < 2 {
             fmt.Printf("Usage: go run main.go [FeedID]\n")
             os.Exit(1)
         }
         feedIDInput := os.Args[1]
    
         // Define the configuration for the SDK client.
         cfg := streams.Config{
             ApiKey:    os.Getenv("API_KEY"),
             ApiSecret: os.Getenv("API_SECRET"),
             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 for timeout.
         ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
         defer cancel()
    
         // Define the FeedID from user input.
         var FeedID feed.ID
         if err := FeedID.FromString(feedIDInput); err != nil {
             cfg.Logger("Failed to parse stream ID: %v\n", err)
             os.Exit(1)
         }
    
         // Fetch the latest report for the given FeedID.
         reportResponse, err := client.GetLatestReport(ctx, FeedID)
         if err != nil {
             cfg.Logger("Failed to get latest report: %v\n", err)
             os.Exit(1)
         }
    
         // Log the contents of the report before decoding
         cfg.Logger("Raw report data: %+v\n", reportResponse)
    
         // Decode the report.
         decodedReport, err := report.Decode[v4.Data](reportResponse.FullReport)
         if err != nil {
             cfg.Logger("Failed to decode report: %v\n", err)
             os.Exit(1)
         }
    
         // Log the decoded report
         cfg.Logger("\nDecoded Report for Stream ID %s:\n------------------------------------------\n"+
             "Observations Timestamp: %d\n"+
             "Benchmark Price       : %s\n"+
             "Valid From Timestamp  : %d\n"+
             "Expires At            : %d\n"+
             "Link Fee              : %s\n"+
             "Native Fee            : %s\n"+
             "Market Status         : %d\n"+
             "------------------------------------------\n",
             feedIDInput,
             decodedReport.Data.ObservationsTimestamp,
             decodedReport.Data.BenchmarkPrice.String(),
             decodedReport.Data.ValidFromTimestamp,
             decodedReport.Data.ExpiresAt,
             decodedReport.Data.LinkFee.String(),
             decodedReport.Data.NativeFee.String(),
             decodedReport.Data.MarketStatus,
         )
     }
    
  3. Download the required dependencies and update the go.mod and go.sum files:

    go mod tidy
    
  4. Set up the SDK client configuration within single-stream.go with your API credentials and the REST endpoint:

    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:

      export API_KEY="<YOUR_API_KEY>"
      export API_SECRET="<YOUR_API_SECRET>"
      

      Replace <YOUR_API_KEY> and <YOUR_API_SECRET> with your API credentials.

    • RestURL is the REST endpoint to poll for specific reports. See the Streams Direct Interface page for more information.

    See the SDK Reference page for more configuration options.

  5. For this example, you will read from the AUD/USD stream. This stream ID is 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea. See the Data Streams RWA streams page for a complete list of available Real World Assets.

    Execute your application:

    go run single-stream.go 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea
    

    Expect output similar to the following in your terminal:

    2024-10-24T12:29:17-05:00 Raw report data: {"fullReport":"0x0006aee203ef23a892e75b579f8c3f26fd933d9ca45de95c2f8ac470f4ddcd7600000000000000000000000000000000000000000000000000000000015d0313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000026001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea00000000000000000000000000000000000000000000000000000000671a83ec00000000000000000000000000000000000000000000000000000000671a83ec0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000671bd56c0000000000000000000000000000000000000000000000000937d6369661b00000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002b0b4627e06e3f597f0ff27c8f16ef94ac1ff6d3668899e68383571508e579ab5fb266fe087a8a45b948627b214440f7c8cc5a45f5b94b69d351af4c1e22ed319000000000000000000000000000000000000000000000000000000000000000278f7b0eded2afe5e17553776cf8ab37899a5fc39858e5ad7a0b537c30be28ca51e05bbd08d4ff766d76b7a5a64b9437947ecbe68a3cb7d7b3fe3f151ea56a248","feedID":"0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea","validFromTimestamp":1729790956,"observationsTimestamp":1729790956}
    
    2024-10-24T12:29:17-05:00
    Decoded Report for Stream ID 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea:
    ------------------------------------------
    Observations Timestamp: 1729790956
    Benchmark Price       : 664235000000000000
    Valid From Timestamp  : 1729790956
    Expires At            : 1729877356
    Link Fee              : 0
    Native Fee            : 0
    Market Status         : 2
    ------------------------------------------
    

Decoded report details

The decoded report details include:

AttributeValueDescription
Stream ID0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7eaThe unique identifier for the stream. In this example, the stream is for AUD/USD.
Observations Timestamp1729790956The timestamp indicating when the data was captured.
Benchmark Price664235000000000000The observed price in the report, with 18 decimals. For readability: 0.664235 USD per AUD.
Valid From Timestamp1729790956The start validity timestamp for the report, indicating when the data becomes relevant.
Expires At1729877356The expiration timestamp of the report, indicating the point at which the data becomes outdated.
Link Fee0The fee to pay in LINK tokens for the onchain verification of the report data. With 18 decimals. Note: This example fee is not indicative of actual fees.
Native Fee0The 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.
Market Status2The DON's consensus on whether the market is currently open. Possible values: 0 (Unknown), 1 (Closed), 2 (Open).

Payload for onchain verification

In this guide, you log and decode the fullReport payload to extract the report data. In a production environment, you should verify the data onchain to ensure its integrity and authenticity. Refer to the Verify report data onchain guide.

Fetch and decode reports for multiple streams

  1. Create a new Go file, multiple-streams.go, in your project directory:

    touch multiple-streams.go
    
  2. Insert the following code example in your multiple-streams.go file:

    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"
        v4 "github.com/smartcontractkit/data-streams-sdk/go/report/v4" // Import the v4 report schema for RWA streams. For Crypto streams, use the v3 schema.
    )
    
    func main() {
        if len(os.Args) < 3 { // Ensure there are at least two stream IDs provided
            fmt.Printf("Usage: go run multiple-streams.go [StreamID1] [StreamID2] ...\n")
            os.Exit(1)
        }
    
        // Define the configuration for the SDK client.
        cfg := streams.Config{
            ApiKey:    os.Getenv("API_KEY"),
            ApiSecret: os.Getenv("API_SECRET"),
            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 for timeout
        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
        defer cancel()
    
        // Parse Feed IDs from 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("Failed to parse stream ID %s: %v\n", arg, err)
                os.Exit(1)
            }
            ids = append(ids, fid)
        }
    
        // Fetch reports for the given feed IDs
        reportResponses, err := client.GetReports(ctx, ids, uint64(time.Now().Unix())) // Using current time as an example timestamp
        if err != nil {
            cfg.Logger("Failed to get reports: %v\n", err)
            os.Exit(1)
        }
    
        for _, reportResponse := range reportResponses {
            // Log the contents of the report before decoding
            cfg.Logger("Raw report data for Stream ID %s: %+v\n", reportResponse.FeedID.String(), reportResponse)
    
            // Decode the report
            decodedReport, err := report.Decode[v4.Data](reportResponse.FullReport)
            if err != nil {
                cfg.Logger("Failed to decode report for Stream ID %s: %v\n", reportResponse.FeedID, err)
                continue // Skip to next report if decoding fails
            }
    
            // Log the decoded report
            cfg.Logger("\nDecoded Report for Stream ID %s:\n------------------------------------------\n"+
                "Observations Timestamp: %d\n"+
                "Benchmark Price       : %s\n"+
                "Valid From Timestamp  : %d\n"+
                "Expires At            : %d\n"+
                "Link Fee              : %s\n"+
                "Native Fee            : %s\n"+
                "Market Status         : %d\n"+
                "------------------------------------------\n",
                reportResponse.FeedID.String(),
                decodedReport.Data.ObservationsTimestamp,
                decodedReport.Data.BenchmarkPrice.String(),
                decodedReport.Data.ValidFromTimestamp,
                decodedReport.Data.ExpiresAt,
                decodedReport.Data.LinkFee.String(),
                decodedReport.Data.NativeFee.String(),
                decodedReport.Data.MarketStatus,
            )
        }
    }
    
  3. Set your API credentials as environment variables if you haven't already:

    export API_KEY="<YOUR_API_KEY>"
    export API_SECRET="<YOUR_API_SECRET>"
    

    Replace <YOUR_API_KEY> and <YOUR_API_SECRET> with your API credentials.

  4. For this example, you will read from the AUD/USD and the USD/JPY RWA streams. Run your application:

    go run multiple-streams.go 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea 0x00046ab03823e37bebe5f228d923ce27110e554b12d7fd476a4ae652f5bf7788
    

    Expect to see the output below in your terminal:

    2024-10-24T12:38:46-05:00 Raw report data for Stream ID 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea: {"fullReport":"0x0006aee203ef23a892e75b579f8c3f26fd933d9ca45de95c2f8ac470f4ddcd7600000000000000000000000000000000000000000000000000000000015d5a0d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000026001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea00000000000000000000000000000000000000000000000000000000671a862600000000000000000000000000000000000000000000000000000000671a86260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000671bd7a6000000000000000000000000000000000000000000000000093850feb96d200000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002b66c644a48c683c603863006dc6ab3a46fb9b7d6a40436b5c7f74f9a446034d6b6968bff3195c5c68105246ea7f50d9dd852f69f67a98b9fc685ad302e4426bf00000000000000000000000000000000000000000000000000000000000000027eca79b9559bae4b904ea7c40055d7f4f4d5c11f07cd0dfca0672c489e8801952063471d66c984d240edd3f3b8e43f7d9ed3eaa7ddbe1a51c6bcd52cfc91f9d4","feedID":"0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea","validFromTimestamp":1729791526,"observationsTimestamp":1729791526}
    
    2024-10-24T12:38:46-05:00
    Decoded Report for Stream ID 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea:
    ------------------------------------------
    Observations Timestamp: 1729791526
    Benchmark Price       : 664370000000000000
    Valid From Timestamp  : 1729791526
    Expires At            : 1729877926
    Link Fee              : 0
    Native Fee            : 0
    Market Status         : 2
    ------------------------------------------
    
    2024-10-24T12:38:46-05:00 Raw report data for Stream ID 0x00046ab03823e37bebe5f228d923ce27110e554b12d7fd476a4ae652f5bf7788: {"fullReport":"0x000692e617d2f6b01349da9090017ba25738b084f88878fa8ac1974a72f8b774000000000000000000000000000000000000000000000000000000000156e219000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000046ab03823e37bebe5f228d923ce27110e554b12d7fd476a4ae652f5bf778800000000000000000000000000000000000000000000000000000000671a862600000000000000000000000000000000000000000000000000000000671a86260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000671bd7a6000000000000000000000000000000000000000000000008376a2776afa18000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000029d9c488b9746dee5dd698b0cf82a3c02a4efa782348a996c62593457c7a3287e5cd34a79e9a1e31eb38e0b0d0a5c2271d725c243694171b1f29c4e45fc2f2545000000000000000000000000000000000000000000000000000000000000000252f67cb0f8fac3e67ce1919b5837f90681c4f48106548071906955addcbf57297736be3904a7eac1ef188ade6f9d65f5408e52786f5d06c8cf02e9b682b5586c","feedID":"0x00046ab03823e37bebe5f228d923ce27110e554b12d7fd476a4ae652f5bf7788","validFromTimestamp":1729791526,"observationsTimestamp":1729791526}
    
    2024-10-24T12:38:46-05:00
    Decoded Report for Stream ID 0x00046ab03823e37bebe5f228d923ce27110e554b12d7fd476a4ae652f5bf7788:
    ------------------------------------------
    Observations Timestamp: 1729791526
    Benchmark Price       : 151567000000000000000
    Valid From Timestamp  : 1729791526
    Expires At            : 1729877926
    Link Fee              : 0
    Native Fee            : 0
    Market Status         : 2
    ------------------------------------------
    

    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 onchain to ensure its integrity and authenticity. Refer to the Verify report data onchain guide.

Explanation

Fetching reports

Your application uses the Data Streams SDK to fetch reports from the Data Streams Aggregation Network. Different functions from the SDK are invoked based on whether a single stream or multiple streams are queried:

  • Single Stream: The application calls the GetLatestReport function from the SDK's streams package to fetch a single stream report. This function sends an API request to retrieve the latest available report for a specified stream ID. The response includes the report's data in a structured format suitable for further processing and analysis.

  • Multiple Streams: The GetReports function is used for multiple streams. This function allows you to fetch reports for multiple stream IDs simultaneously, specifying a timestamp to retrieve reports valid at a particular point in time.

The responses include a fullReport blob containing the encoded report's context and observations.

Decoding reports

After retrieving the report data, the application decodes it using the Decode function available in the report package of the SDK. This function is designed to handle different data formats by specifying the version of the data structure as a type parameter (e.g., v4.Data for Real World Asset streams).

The Decode function unpacks the encoded report blob into a usable data structure (Report[v4.Data] for RWA streams). It extracts information such as observation timestamps, benchmark prices, and the market status from the report data.

Handling the decoded data

The application logs the report data to the terminal. However, this data can be used for further processing, analysis, or display in your own application.

What's next

Get the latest Chainlink content straight to your inbox.