Skip to content
VerdictJEV

Integrate VerdictJEV

One call to ask(), one callback. The oracle lives at (not deployed yet) on Robinhood Chain (chain id 4663).

Example consumer

Pay oracle.quote(callbackGasLimit) with the call. Any overpayment is kept as part of the fee.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {VerdictOracle} from "verdict/VerdictOracle.sol";
import {Kind, AskParams, Result} from "verdict/VerdictTypes.sol";
import {IVerdictConsumer} from "verdict/interfaces/IVerdictConsumer.sol";

contract CopycatFilter is IVerdictConsumer {
    VerdictOracle public immutable oracle;
    mapping(uint256 => address) public tokenOf;   // request -> token
    mapping(address => bool) public flagged;

    constructor(VerdictOracle oracle_) { oracle = oracle_; }

    function check(address token, string calldata description) external payable {
        string[] memory criteria = new string[](2);
        criteria[0] = "It copies another token's name, ticker or branding";
        criteria[1] = "It has its own identity";
        uint256 id = oracle.ask{value: msg.value}(AskParams({
            kind: Kind.Noul,
            instructions: "Is this token a copycat?",
            options: criteria,
            descriptions: new string[](0),
            state: description,
            sources: new string[](0),
            callbackGasLimit: 100_000
        }));
        tokenOf[id] = token;
    }

    function onVerdict(uint256 id, bool ok, Result calldata r) external {
        require(msg.sender == address(oracle), "only oracle");
        if (!ok) return;                        // rejected or refunded
        if (r.value >= 8_000) flagged[tokenOf[id]] = true;   // P(yes) >= 80%
    }
}

Question types

Yes / No returns the probability of yes. Choice picks one option among your labels. Score rates along ordered levels and also returns a weighted score that can land between levels. Criteria matter: describe what each answer means.

instructions
1 – 1024 bytes
state (context)
0 – 8192 bytes
choice options
2 – 32 unique labels, ≤ 128 bytes each
score levels
2 – 10, lowest first, ≤ 256 bytes each
yes/no criteria
none, or exactly [yes means, no means]
sources
0 – 3 https:// URLs, ≤ 256 bytes, fetched at decision time
state or sources
at least one must be non-empty
callbackGasLimit
0 (no callback) up to maxCallbackGas()

What you receive

probsBps
one entry per outcome, sums to exactly 10 000. Yes/No is [P(no), P(yes)]
answer
argmax of probsBps (lowest index wins ties), computed on-chain
value
Yes/No: P(yes) · Choice: P(answer) · Score: weighted level × 10 000
confidenceBps
JEV's confidence (Yes/No: the larger probability)

Results are also stored: getResult(id) and getRequest(id) work without a callback.

Lifecycle

  1. Pending — the fee is escrowed; Asked is emitted with every input.
  2. Fulfilled — probabilities are stored, your callback runs with exactly the gas you asked for. A reverting callback never blocks the answer.
  3. Rejected — JEV refused the request as invalid; your callback gets ok = false. The fee pays for the work.
  4. Refunded — nobody answered before the deadline: anyone can call refund(id), the fee is credited back to the requester (withdrawCredit) and the callback gets ok = false.

Verify a decision

  1. Read archiveHash from the Fulfilled event.
  2. Download http://localhost:8787/v1/archives/<archiveHash> and check keccak256(bytes) == archiveHash.
  3. Recompute keccak256(abi.encode(chainid, oracle, id, requester, params)) from the archive and compare it with getRequest(id).requestHash.
  4. Send the archived jev_request to JEV with your own key and compare.

Every decision page runs steps 1 – 3 in your browser automatically.

Relayer API

GET /health
status, relayer balance, model, queue stats
GET /v1/decisions
?limit=1..100&before=<id> — newest first
GET /v1/decisions/:id
one request with params, result and transactions
GET /v1/archives/:hash
the exact archived bytes (immutable)

Sources

The documents this project is built from. The full annotated list is in SOURCES.md.