Signed report verification
A DataLink report is signed by the DataLink oracle network. You can check those signatures on-chain through the VerifierProxy contract before trusting the values — either from your own smart contract or manually.
This guide covers:
- fetching the signed report with your Marketplace API key;
- preparing the payload;
- calling
verify(bytes payload, bytes parameterPayload); - reading the result: the return value, the transaction receipt and the
ReportVerifiedevent.
Contracts
| XDC Mainnet (chain ID 50) | |
|---|---|
| VerifierProxy — call this one | 0xCf49c434f2206Df1D507dE9f5DA70cA8c3dA61d2 (VerifierProxy 2.0.0) |
| Verifier — checks the signatures | 0x181175142a98c8922310e304d9b591d5cbca37b4 (Verifier 1.2.0) |
Always call the VerifierProxy. It reads the report's configuration digest and forwards the report to the Verifier configured for it, so your integration keeps working if the Verifier is ever replaced. The Verifier Proxy address for your feed is also shown on its Feed Access & Integration page in the Consumer portal.
1. Fetch the signed report
Call the Marketplace API with an API key for an active subscription to the feed (create keys in the Consumer portal). Keep the key on your server — never in browser or mobile code.
Bash
curl "$MARKETPLACE_URL/api/v1/reports/latest?feedID=0x00018cd7a1e01e764604c0e299f74a0ff4179d81e92111389e6585ba6318cbd1" \
-H "Authorization: Bearer YOUR_API_KEY"JSON
{
"createdAt": 1794516848,
"feedId": "00018cd7a1e01e764604c0e299f74a0ff4179d81e92111389e6585ba6318cbd1",
"payload": "00065652d1d0bb609d5723654d7388b9b6823c85e269367d4ae558cc4073624e…"
}payloadis the complete signed report, hex-encoded (736 bytes for the current report format).feedIdandpayloadare returned without a0xprefix.createdAtis API metadata (when the report was stored). It is not part of the signed data — see Report schema.
2. Prepare the payload: add 0x
Solidity bytes arguments are passed as 0x-prefixed hex. Add the prefix before
sending the payload anywhere on-chain:
JavaScript
const res = await fetch(`${process.env.MARKETPLACE_URL}/api/v1/reports/latest?feedID=${feedId}`, {
headers: { Authorization: `Bearer ${process.env.DATALINK_API_KEY}` },
});
if (!res.ok) throw new Error(`DataLink request failed: ${res.status}`);
const report = await res.json();
const payload = report.payload.startsWith("0x") ? report.payload : `0x${report.payload}`;Pass the payload exactly as received. Changing, trimming or re-encoding any byte makes verification fail.
3. Call verify
Solidity
interface IVerifierProxy {
function verify(bytes calldata payload, bytes calldata parameterPayload)
external
payable
returns (bytes memory verifierResponse);
}| Argument | Value |
|---|---|
payload | The signed report from step 2 (0x…) |
parameterPayload | 0x (empty) — see below |
On success, verify returns the report's report data: the nine encoded fields
described in Report schema. If the signatures don't match
the report, the call reverts and nothing is returned — see
Troubleshooting.
When parameterPayload can be 0x
parameterPayload carries fee information for a FeeManager. On XDC Mainnet the
VerifierProxy has no FeeManager configured, so verification is free and
parameterPayload is ignored: pass 0x (or "" in Solidity).
Access control
The VerifierProxy can restrict who may call verify through an access controller.
On XDC Mainnet no access controller is configured: any wallet or contract can
verify reports. A restricted caller would get AccessForbidden.
Check a report without a transaction
verify isn't a view function, but your backend can simulate it with an
eth_call — free, and nothing is sent:
JavaScript
import { createPublicClient, http, parseAbi } from "viem";
const client = createPublicClient({ transport: http(process.env.XDC_RPC_URL) });
const { result: reportData } = await client.simulateContract({
address: "0xCf49c434f2206Df1D507dE9f5DA70cA8c3dA61d2",
abi: parseAbi(["function verify(bytes payload, bytes parameterPayload) payable returns (bytes)"]),
functionName: "verify",
args: [payload, "0x"],
});
// reportData: the verified report data (288 bytes) — decode it as shown in Report schema.A simulation proves the report is validly signed right now; only an on-chain transaction (or your own contract) leaves a record of the verification.
4. Verify manually
With Remix
- Open Remix and create
IVerifierProxy.solwith the interface above (plus// SPDX-License-Identifier: MITandpragma solidity ^0.8.24;). - Compile it.
- In Deploy & run transactions, set Environment to Injected Provider and connect a wallet on XDC Mainnet (chain ID 50) with a little XDC for gas.
- Select
IVerifierProxy, paste0xCf49c434f2206Df1D507dE9f5DA70cA8c3dA61d2into At Address, and click it. - Expand
verify, enter the0x-prefixed payload and0xforparameterPayload, then transact and confirm in your wallet.
With a block explorer
If the VerifierProxy's source code is verified on the explorer, its Write
Contract tab offers the same verify call. If it isn't, use Remix (it only needs
the interface above).
5. Read the receipt
A successful verification transaction:
- has status success;
- contains a
ReportVerifiedevent, emitted by the Verifier (not the proxy):
Solidity
event ReportVerified(bytes32 indexed feedId, address requester);| Field | Meaning |
|---|---|
feedId (indexed — the event's second topic) | The feed the verified report belongs to |
requester | The address that called the VerifierProxy: your wallet, or your contract when called from a contract |
Example: a verified transaction
Transaction 0xfb203d3d636309a4ae255fba3e95dac440bc4ee527b521c05dd5c9a7aa4339e7
on XDC Mainnet:
| Block | 109,335,393 |
| To | VerifierProxy 0xCf49c434f2206Df1D507dE9f5DA70cA8c3dA61d2 |
| Function | verify(bytes,bytes) — 736-byte payload, parameterPayload = 0x |
| Status | Success, 88,258 gas used |
| Event | ReportVerified from the Verifier 0x1811…37b4, feedId = 0x00018cd7…cbd1 |
Signed or decoded?
The Marketplace also offers GET /api/v1/reports/decoded with the same report's
values as JSON. It's convenient for dashboards and backends, but decoded JSON is
not cryptographically verifiable on its own. Use the signed report wherever the
values must be trusted.
