Onchain report verification (EVM chains)
About Verification
When you fetch a report from Data Streams, you receive a signed payload. Onchain verification submits that payload to Chainlink's VerifierProxy contract, which checks the DON's signature and returns the decoded report data your contract can use. Your contract never talks to the Verifier contract directly: the proxy handles routing.
The IVerifierProxy interface exposes two verification functions:
| Function | Use case |
|---|---|
verify() | Verify a single report payload in one transaction |
verifyBulk() | Verify multiple report payloads in a single transaction |
What Chainlink deploys: The VerifierProxy contract. You only need its address, which is listed on the Stream Addresses page.
What you deploy: Your own contract that calls VerifierProxy.verify() or verifyBulk(). The contract example below shows the full pattern and is a starting point โ see the disclaimer before using it in production.
IVerifierProxy interface
IVerifierProxy is the single onchain entry point for report verification. Your contract calls it directly โ you never interact with the underlying Verifier contract. The proxy routes each call to the correct Verifier and returns the verified report data.
You will need the deployed VerifierProxy address for the network you are targeting. Find it on the Stream Addresses page.
interface IVerifierProxy {
// Verify a single report. Returns the verified report body as ABI-encoded bytes.
// Decode the return value into the appropriate report struct (v3, v8, etc.).
function verify(
bytes calldata payload, // Full report payload from the Streams API
bytes calldata parameterPayload // pass empty fee metadata for Data Streams subscription billing
) external payable returns (bytes memory verifierResponse);
// Verify multiple reports in one transaction. Accepts different feed IDs in the same call.
// Returns verified report bytes in the same order as the input array.
function verifyBulk(
bytes[] calldata payloads, // Array of report payloads โ may span different feed IDs
bytes calldata parameterPayload // pass empty fee metadata for Data Streams subscription billing
) external payable returns (bytes[] memory verifiedReports);
// Legacy FeeManager accessor. Data Streams verification does not require
// per-verification fee quoting or approvals.
function s_feeManager() external view returns (IVerifierFeeManager);
}
verify()
Verifies a single report payload. Pass the raw payload bytes returned by the Streams API directly as payload โ no transformation is needed.
| Parameter | Type | Description |
|---|---|---|
payload | bytes calldata | The full report payload returned by the Streams API (header + signed report body). |
parameterPayload | bytes calldata | Fee metadata parameter retained for legacy fee-manager integrations. Pass empty bytes "" for current Data Streams subscription billing. |
Returns
| Return | Type | Description |
|---|---|---|
verifierResponse | bytes memory | ABI-encoded verified report body. Decode into the appropriate report struct according to the report schema version. |
Fee handling for verify()
Data Streams uses subscription-based billing. Your contract does not need to quote or approve a per-verification fee before calling verify(), and no supported EVM chain requires LINK funding for this step. Pass empty bytes "" as parameterPayload because no fee token metadata is required.
verifyBulk()
Verifies multiple report payloads in a single transaction. Reports may reference different feed IDs, enabling atomic multi-feed updates. Pass the raw payload bytes from the Streams API directly โ no transformation is needed.
| Parameter | Type | Description |
|---|---|---|
payloads | bytes[] calldata | Array of full report payloads from the Streams API. Each entry may correspond to a different feed ID. Order is preserved in the output. |
parameterPayload | bytes calldata | Fee metadata parameter retained for legacy fee-manager integrations. Pass empty bytes "" for current Data Streams subscription billing. |
Returns
| Return | Type | Description |
|---|---|---|
verifiedReports | bytes[] memory | Array of ABI-encoded verified report bodies in the same order as payloads. Decode each entry into the appropriate report struct. |
Fee handling for verifyBulk()
Data Streams uses subscription-based billing. Your contract does not need to quote, sum, or approve per-report verification fees before calling verifyBulk(). Pass empty bytes "" as parameterPayload because no fee token metadata is required.
When to use verifyBulk()
Use verifyBulk() when your protocol needs price data from multiple feeds in the same block. Common use cases include:
- Calculating a portfolio's value across multiple asset prices atomically.
- Executing a trade that depends on both a base and a quote asset price (e.g. ETH/USD and BTC/USD).
- Updating multiple onchain price references in a single transaction to reduce state inconsistency.
verifyBulk() accepts multiple feed IDs in the same call โ there is no requirement that all payloads reference the same stream.
Gas considerations
verifyBulk() reduces overhead compared to issuing N separate verify() calls, each of which incurs an additional base transaction cost (21,000 gas). The per-report cryptographic verification cost is the same regardless of which function you use.
- What you save: one base transaction cost (21,000 gas) per additional report beyond the first.
- What you do not save: the cryptographic verification cost per report.
- Fee cost: Data Streams does not charge a per-report onchain verification fee.
Contract example
The contract below is an example you deploy yourself. It demonstrates the full verification pattern for both verifyReport() (single report) and verifyBulkReports() (multiple reports). Use it as a reference when writing your own contract.
undefined
verifyReport() โ single report
- Input: one
bytespayload from the Streams API โ pass it directly. - Fee: passes empty bytes for
parameterPayload; no per-verification LINK fee is required. - Output: stores the decoded price in
lastDecodedPriceand emitsDecodedPrice(int192 price).
See the Verify report data onchain (EVM) tutorial for a step-by-step walkthrough using this function.
verifyBulkReports() โ multiple reports
- Input:
bytes[]array of payloads from the Streams API โ each may reference a different feed ID. - Fee: passes empty bytes for
parameterPayload; no per-verification LINK fee is required. - Output: stores the decoded prices in
lastDecodedPrices(anint192[]array in the same order as the inputs) and emitsDecodedPrice(int192 price)once per report.