Documentation Index
Fetch the complete documentation index at: https://seilabs.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
What is Chainlink?
Chainlink is the world’s most widely adopted decentralized oracle network, enabling smart contracts to securely access off-chain data, APIs, and traditional payment systems. Chainlink Data Streams is a pull-based oracle solution that delivers high-frequency, low-latency market data directly to smart contracts.
What This Guide Teaches You
This tutorial will walk you through integrating Chainlink Data Streams on Sei Network to:
- Fetch real-time price data using the Chainlink Data Streams SDK
- Deploy a smart contract that can verify and decode price reports on-chain
- Combine off-chain and on-chain components to create a complete oracle solution
- Verify SEI/USDT price feeds as a practical example
By the end of this guide, you’ll have a working implementation that fetches price data off-chain and verifies it on-chain using Chainlink’s data streams SDK.
Prerequisites
Before starting this tutorial, ensure you have:
Technical Requirements
- Node.js (v18 or higher) and npm installed
- Basic knowledge of TypeScript/JavaScript
- Solidity development experience (basic to intermediate)
- Familiarity with smart contract deployment tools like Remix or Hardhat
Sei Network Setup
Testnet :
- Sei testnet RPC:
https://evm-rpc-testnet.sei-apis.com
- Chain ID: 1328
Mainnet :
- SEI mainnet RPC:
https://evm-rpc.sei-apis.com
- Chain ID: 1329
Chainlink Data Streams Access
You need to contact Chainlink for getting access to API credentials of Data Streams.
Step-by-Step Tutorial
Step 1: Project Setup
Create a new directory and initialize your project:
mkdir chainlink-data-streams-sei
cd chainlink-data-streams-sei
npm init -y
Install the required dependencies:
npm install @chainlink/data-streams-sdk dotenv tsx ethers
npm install -D typescript @types/node
Create a .env file in your project root:
API_KEY=your_chainlink_api_key_here
USER_SECRET=your_chainlink_user_secret_here
Step 2: Fetching Price Data with TypeScript
Create a file called singleStream.ts with the following code:
import { createClient, decodeReport, LogLevel, getReportVersion, formatReport } from '@chainlink/data-streams-sdk';
import 'dotenv/config';
async function main() {
if (process.argv.length < 3) {
console.error('Please provide a feed ID as an argument');
console.error('Example: npx tsx singleStream.ts 0x0003dba2d8553dfd7afe35c2bfe217ef5106d7805e5272c04a08940ddb868117');
process.exit(1);
}
const feedId = process.argv[2];
const version = getReportVersion(feedId);
try {
const config = {
apiKey: process.env.API_KEY || 'YOUR_API_KEY',
userSecret: process.env.USER_SECRET || 'YOUR_USER_SECRET',
endpoint: 'https://api.testnet-dataengine.chain.link',
wsEndpoint: 'wss://ws.testnet-dataengine.chain.link',
// Comment to disable SDK logging:
logging: {
logger: console,
logLevel: LogLevel.INFO
}
};
const client = createClient(config);
console.log(`\nFetching latest report for feed ${feedId} (${version})...\n`);
// Get raw report data
const report = await client.getLatestReport(feedId);
console.log(`Raw Report Blob: ${report.fullReport}`);
// Decode the report
const decodedData = decodeReport(report.fullReport, report.feedID);
// Combine decoded data with report metadata
const decodedReport = {
...decodedData,
feedID: report.feedID,
validFromTimestamp: report.validFromTimestamp,
observationsTimestamp: report.observationsTimestamp
};
console.log(formatReport(decodedReport, version));
} catch (error) {
if (error instanceof Error) {
console.error('Error:', error.message);
} else {
console.error('Unknown error:', error);
}
process.exit(1);
}
}
main();
This script:
- Creates a Data Streams client with your API credentials
- Fetches the latest report for a given feed ID
- Decodes the raw report into readable price data
- Displays both raw and formatted data for debugging
Step 3: Smart Contract Deployment
Create and deploy the verification contract on Sei Network. Copy this Solidity code into Remix IDE:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Common} from "@chainlink/contracts@1.5.0/src/v0.8/llo-feeds/libraries/Common.sol";
import {IVerifierFeeManager} from "@chainlink/contracts@1.5.0/src/v0.8/llo-feeds/v0.3.0/interfaces/IVerifierFeeManager.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
using SafeERC20 for IERC20;
/**
* THIS IS AN EXAMPLE CONTRACT FOR DEMONSTRATION PURPOSES.
* This contract verifies Chainlink Data Streams reports onchain
* and handles fee payments automatically.
*/
interface IVerifierProxy {
function verify(
bytes calldata payload,
bytes calldata parameterPayload
) external payable returns (bytes memory verifierResponse);
function s_feeManager() external view returns (IVerifierFeeManager);
}
interface IFeeManager {
function getFeeAndReward(
address subscriber,
bytes memory unverifiedReport,
address quoteAddress
) external returns (Common.Asset memory, Common.Asset memory, uint256);
function i_linkAddress() external view returns (address);
function i_rewardManager() external view returns (address);
}
contract ClientReportsVerifier {
// Errors
error NothingToWithdraw();
error NotOwner(address caller);
error InvalidReportVersion(uint16 version);
// Report schema v3 (crypto streams)
struct ReportV3 {
bytes32 feedId;
uint32 validFromTimestamp;
uint32 observationsTimestamp;
uint192 nativeFee;
uint192 linkFee;
uint32 expiresAt;
int192 price;
int192 bid;
int192 ask;
}
// Storage
IVerifierProxy public immutable i_verifierProxy;
address private immutable i_owner;
int192 public lastDecodedPrice;
// Events
event DecodedPrice(int192 price);
constructor(address _verifierProxy) {
i_owner = msg.sender;
i_verifierProxy = IVerifierProxy(_verifierProxy);
}
modifier onlyOwner() {
if (msg.sender != i_owner) revert NotOwner(msg.sender);
_;
}
/**
* @notice Verify a Data Streams report and extract price
* @param unverifiedReport Full payload from Data Streams API
*/
function verifyReport(bytes memory unverifiedReport) external {
// Extract report data and version
(, bytes memory reportData) = abi.decode(unverifiedReport, (bytes32[3], bytes));
uint16 reportVersion = (uint16(uint8(reportData[0])) << 8) | uint16(uint8(reportData[1]));
if (reportVersion != 3) {
revert InvalidReportVersion(reportVersion);
}
// Handle fees
IFeeManager feeManager = IFeeManager(address(i_verifierProxy.s_feeManager()));
bytes memory parameterPayload;
if (address(feeManager) != address(0)) {
address feeToken = feeManager.i_linkAddress();
(Common.Asset memory fee,,) = feeManager.getFeeAndReward(
address(this),
reportData,
feeToken
);
IERC20(feeToken).approve(feeManager.i_rewardManager(), fee.amount);
parameterPayload = abi.encode(feeToken);
} else {
parameterPayload = bytes("");
}
// Verify through proxy
bytes memory verified = i_verifierProxy.verify(unverifiedReport, parameterPayload);
// Decode and store price
ReportV3 memory report = abi.decode(verified, (ReportV3));
lastDecodedPrice = report.price;
emit DecodedPrice(report.price);
}
/**
* @notice Withdraw ERC-20 tokens from contract
*/
function withdrawToken(address _beneficiary, address _token) external onlyOwner {
uint256 amount = IERC20(_token).balanceOf(address(this));
if (amount == 0) revert NothingToWithdraw();
IERC20(_token).safeTransfer(_beneficiary, amount);
}
/**
* @notice Get the last decoded price
*/
function getLastPrice() external view returns (int192) {
return lastDecodedPrice;
}
}
Deployment steps in Remix:
- Switch to Sei Testnet in MetaMask
- Deploy with Sei testnet VerifierProxy address:
0x60fAa7faC949aF392DFc858F5d97E3EEfa07E9EB
- Save the contract address for testing
Step 4: Complete Integration Script
Create verifyOnChain.ts to combine off-chain fetching with on-chain verification:
import { createClient, LogLevel } from '@chainlink/data-streams-sdk';
import 'dotenv/config';
// You'll need to install ethers: npm install ethers
import { ethers } from 'ethers';
async function main() {
const feedId = '0x0003dba2d8553dfd7afe35c2bfe217ef5106d7805e5272c04a08940ddb868117';
// 1. Fetch the latest report
const config = {
apiKey: process.env.API_KEY!,
userSecret: process.env.USER_SECRET!,
endpoint: 'https://api.testnet-dataengine.chain.link',
wsEndpoint: 'wss://ws.testnet-dataengine.chain.link',
logging: {
logger: console,
logLevel: LogLevel.INFO
}
};
const client = createClient(config);
console.log('Fetching latest report...');
const report = await client.getLatestReport(feedId);
console.log(`Got report: ${report.fullReport}`);
// 2. Connect to Sei testnet and your deployed contract
const provider = new ethers.JsonRpcProvider('https://evm-rpc-testnet.sei-apis.com');
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
const contractAddress = 'YOUR_DEPLOYED_CONTRACT_ADDRESS';
const abi = ['function verifyReport(bytes memory unverifiedReport) external', 'function getLastPrice() external view returns (int192)', 'event DecodedPrice(int192 price)'];
const contract = new ethers.Contract(contractAddress, abi, wallet);
// 3. Verify the report on-chain
console.log('Verifying report on-chain...');
const tx = await contract.verifyReport(report.fullReport);
await tx.wait();
// 4. Get the decoded price
const price = await contract.getLastPrice();
console.log(`Price verified on-chain: ${ethers.formatUnits(price.toString(), 18)} SEI/USDT`);
}
main().catch(console.error);
How to Run and Test
1. Test Off-chain Data Fetching
Run the single stream script to verify off-chain fetching and decoding:
npx tsx singleStream.ts 0x0003dba2d8553dfd7afe35c2bfe217ef5106d7805e5272c04a08940ddb868117
Expected output:
npx tsx singleStream.ts 0x0003dba2d8553dfd7afe35c2bfe217ef5106d7805e5272c04a08940ddb868117
[DataStreams] Data Streams client initialized
Fetching latest report for feed 0x0003dba2d8553dfd7afe35c2bfe217ef5106d7805e5272c04a08940ddb868117 (V3)...
[DataStreams] Request successful: GET https://api.testnet-dataengine.chain.link/api/v1/reports/latest?feedID=0x0003dba2d8553dfd7afe35c2bfe217ef5106d7805e5272c04a08940ddb868117 - 200
Raw Report Blob: 0x00090d9e8d96765a0c49e03a6ae05c82e8f8de70cf179baa632f18313e54bd690000000000000000000000000000000000000000000000000000000002ad82fe000000000000000000000000000000000000000000000000000000030000000100000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200003dba2d8553dfd7afe35c2bfe217ef5106d7805e5272c04a08940ddb868117000000000000000000000000000000000000000000000000000000006911a843000000000000000000000000000000000000000000000000000000006911a843000000000000000000000000000000000000000000000000000050fde585ef340000000000000000000000000000000000000000000000000045e76ab072da670000000000000000000000000000000000000000000000000000000069393543000000000000000000000000000000000000000000000000027f85b14842c1b4000000000000000000000000000000000000000000000000027f47776cef65d0000000000000000000000000000000000000000000000000027fb6ed8fc487e400000000000000000000000000000000000000000000000000000000000000027d2c18d803d4e1818fff6521a21a336a03e334ae5af3dccee1ee241239c1661d8a3d0384d5ae6159d4ac1151ffbc9d717304359ce7a904faeb1c5f23375c1e69000000000000000000000000000000000000000000000000000000000000000218da9942080bfb1d679e0185216226c52fd6eaf34fb4c9ee139dd1c87f235a3e18d4822b9454d61d010584f27ccdc6812df13dfe50409252d6cbc774f26b53d2
Report Metadata:
Feed ID: 0x0003dba2d8553dfd7afe35c2bfe217ef5106d7805e5272c04a08940ddb868117
Valid From: 1762764867
Observations: 1762764867
Decoded Data:
Native Fee: 89051407707956
LINK Fee: 19676218805901927
Expires At: 1765356867
Price: 180009506586149300
Bid Price: 179941088372418000
Ask Price: 180063641553635300
2. Test Smart Contract Deployment
- Copy the raw report blob from Step 1 output (the long hex string starting with
0x00090d9e...)
- Call
verifyReport() and paste the entire blob as the unverifiedReport parameter
- Call
getLastPrice() - you should see the decoded price (e.g., 180009506586149300)
3. Test Complete Integration
Step 3a: Setup Integration Script
Add your private key to .env:
API_KEY=your_chainlink_api_key_here
USER_SECRET=your_chainlink_user_secret_here
PRIVATE_KEY=your_sei_testnet_private_key_here
Update verifyOnChain.ts with your deployed contract address:
Replace YOUR_DEPLOYED_CONTRACT_ADDRESS in the script with your actual contract address.
Step 3b: Run Integration Test
Expected Output:
npx tsx singleStream.ts
[DataStreams] Data Streams client initialized
Fetching latest report...
[DataStreams] Request successful: GET https://api.testnet-dataengine.chain.link/api/v1/reports/latest?feedID=0x0003dba2d8553dfd7afe35c2bfe217ef5106d7805e5272c04a08940ddb868117 - 200
Got report: 0x00090d9e8d96765a0c49e03a6ae05c82e8f8de70cf179baa632f18313e54bd690000000000000000000000000000000000000000000000000000000002ad80fd000000000000000000000000000000000000000000000000000000030000000100000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200003dba2d8553dfd7afe35c2bfe217ef5106d7805e5272c04a08940ddb868117000000000000000000000000000000000000000000000000000000006911a794000000000000000000000000000000000000000000000000000000006911a794000000000000000000000000000000000000000000000000000051070460a3df0000000000000000000000000000000000000000000000000045e8f0bff5bcd30000000000000000000000000000000000000000000000000000000069393494000000000000000000000000000000000000000000000000027fe207ce1890f4000000000000000000000000000000000000000000000000027fb2bbee1e2038000000000000000000000000000000000000000000000000028013671aa35a0400000000000000000000000000000000000000000000000000000000000000024ef8f65551057e6a89745ffd306a5202162d6b280fc9754360175b54a95f11598da55d6d7d965384479c9d4ff248cd00ffd89078d05de048299c61c48d0361c8000000000000000000000000000000000000000000000000000000000000000278bc17f79bf5d6483310b28fe004e884a64e603cbc212044492098af36b4d50047bf5dc8af1e50abfc5f38060fb7f4b6dc9089589915144211fa6e6ff049dd1e
Verifying report on-chain...
Price verified on-chain: 0.180009506586149300 SEI/USDT
Resources