reality-data-service
TypeScript icon, indicating that this package has built-in type declarations

0.5.4 • Public • Published

Reality Data Service

A comprehensive library for interacting with Reality.eth questions and disputes across multiple blockchains.

Overview

Reality Data Service provides React hooks and utilities for fetching, filtering, and displaying Reality.eth questions and their associated dispute data. The library supports multiple blockchains including Ethereum, Gnosis Chain, and Polygon.

Installation

npm install reality-data-service

Core Exports

Hooks

useQuestions

A React hook for fetching and managing Reality.eth questions.

function useQuestions({
  chain,
  searchTerm,
  filters
}: UseQuestionsConfig): UseQuestionsResult

Parameters:

  • chain: The blockchain to fetch questions from (see Chain type)
  • searchTerm (optional): String to filter questions by title/content
  • filters (optional): Object with additional filtering criteria

Returns:

  • questions: Array of all fetched questions
  • filteredQuestions: Array of questions after filters are applied
  • loading: Boolean indicating if questions are being loaded
  • error: Error message if fetch failed, null otherwise
  • hasMore: Boolean indicating if more questions can be loaded
  • loadMore: Function to load more questions
  • refresh: Function to refresh the questions
  • loadingState: Object with detailed loading state information
  • status: Current fetch status ('idle', 'loading', 'success', 'error')

Example:

function QuestionsList() {
  const {
    questions,
    loading,
    error,
    loadMore,
    hasMore
  } = useQuestions({
    chain: SUPPORTED_CHAINS[0], // Ethereum
    searchTerm: "climate"
  });

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;

  return (
    <>
      <ul>
        {questions.map(q => (
          <li key={q.id}>{q.title}</li>
        ))}
      </ul>
      {hasMore && <button onClick={loadMore}>Load More</button>}
    </>
  );
}

useDisputeData

A React hook for fetching dispute data for a specific Reality.eth question.

function useDisputeData(question: Question): {
  disputeId: string | null;
  dispute: Dispute | undefined;
  disputeLoading: boolean;
  evidences: Evidence[];
  metaEvidence: any;
  arbitrableContractAddress: string | undefined;
}

Parameters:

  • question: A Question object (must include the chain property)

Returns:

  • disputeId: The ID of the dispute, or null if no dispute exists
  • dispute: The dispute data, or undefined if not loaded
  • disputeLoading: Boolean indicating if dispute data is being loaded
  • evidences: Array of evidence submitted for the dispute
  • metaEvidence: Metadata about the dispute
  • arbitrableContractAddress: The address of the arbitrable contract

Example:

function DisputeView({ question }) {
  const {
    dispute,
    disputeLoading,
    evidences
  } = useDisputeData(question);

  if (disputeLoading) return <div>Loading dispute data...</div>;
  if (!dispute) return <div>No dispute found</div>;

  return (
    <div>
      <h2>Dispute #{dispute.id}</h2>
      <p>Status: {dispute.ruled ? 'Ruled' : 'Pending'}</p>
      <h3>Evidence ({evidences.length})</h3>
      {evidences.map(e => (
        <div key={e.id}>
          <h4>{e.URI_contents.name}</h4>
          <p>{e.URI_contents.description}</p>
          <small>Submitted by: {e.sender}</small>
        </div>
      ))}
    </div>
  );
}

Types

Question

Represents a Reality.eth question.

interface Question {
  id: string;                   // Unique identifier for the question
  title: string;                // Question title
  description: string;          // Detailed description
  arbitrator: string;           // Address of the arbitrator
  options: string[];            // Possible answer options
  qType: string;                // Question type (binary, multiple-choice, etc.)
  phase: QuestionPhase;         // Current phase of the question
  currentAnswer: string;        // Current answer value
  openingTimestamp: number;     // When the question opened for answering
  arbitrationStatus?: ArbitrationStatus; // Status of arbitration if requested
  currentBond: string;          // Current bond amount
  timeToOpen: number;           // Time until question opens (ms)
  timeRemaining: number;        // Time remaining until finalization (ms)
  answers: Answer[];            // Ignore, use responses instead for answer history
  contract: string;             // Contract address
  createdTimestamp: number;     // When the question was created
  currentScheduledFinalizationTimestamp?: string; // When finalization is scheduled
  finalAnswer?: string;         // Final answer if finalized
  disputeId?: number;           // ID of associated dispute
  appealPeriodEnd?: number;     // When appeal period ends
  minimumBond: string;          // Minimum bond required
  arbitrationRequestedBy?: string; // Who requested arbitration
  responses: {                  // User responses, should be used to construct the answer history
    value: string;
    timestamp: number;
    bond: string;
    user: string;
  }[];
  chain: Chain;                 // Blockchain the question is on
  template?: Template;          // Template used to create the question
}

QuestionPhase

Enum representing the possible phases of a question.

enum QuestionPhase {
  NOT_CREATED = 'NOT_CREATED',
  OPEN = 'OPEN',
  UPCOMING = 'UPCOMING',
  PENDING_ARBITRATION = 'PENDING_ARBITRATION',
  FINALIZED = 'FINALIZED',
  SETTLED_TOO_SOON = 'SETTLED_TOO_SOON'
}

ArbitrationStatus

Enum representing the possible statuses of arbitration.

enum ArbitrationStatus {
  WAITING = 'WAITING',
  APPEALABLE = 'APPEALABLE',
  SOLVED = 'SOLVED'
}

Answer

Represents an answer to a question.

interface Answer {
  value: string;      // Answer value
  bond: string;       // Bond amount
  timestamp: number;  // When the answer was provided
  provider: string;   // Address of the answer provider
}

Evidence

Represents evidence submitted for a dispute.

interface Evidence {
  id: string;                 // Unique identifier
  URI: string;                // URI pointing to evidence
  URI_contents: {             // Contents of the evidence
    name: string;
    description: string;
  };
  creationTime: string;       // When the evidence was created
  sender: string;             // Address of the evidence submitter
}

Note: When working with evidence URIs from subgraphs, you must prepend https://cdn.kleros.link to the URI to form the complete URL. For example, if the URI is /ipfs/QmRXgRaKkcKKfXjTFozwoWLosFHmtcEaeuj1cL1G8xKHJd/file.pdf, the complete URL would be https://cdn.kleros.link/ipfs/QmRXgRaKkcKKfXjTFozwoWLosFHmtcEaeuj1cL1G8xKHJd/file.pdf.

Evidence JSON Format: The JSON retrieved from an evidence URI typically follows this structure:

{
  "name": "Response to \"The new candidate' justification for Invalid stands\"",
  "description": "The response argues against the claim that a \"new pool of candidates\" makes an election invalid...",
  "fileURI": "/ipfs/QmRXgRaKkcKKfXjTFozwoWLosFHmtcEaeuj1cL1G8xKHJd/Response.pdf",
  "evidenceSide": 0
}

The fileURI field may point to additional documents, which also need to be prefixed with https://cdn.kleros.link.

Template

Represents a template used to create a Reality.eth question.

interface Template {
  templateId: string;         // Unique identifier for the template
  questionText: string;       // Text of the template with placeholders
  creationTimestamp: string;  // When the template was created
  creator: string;            // Address of the template creator
}

Note: Templates contain placeholders like ${0}, ${1}, etc. that are replaced with actual values when a question is created. The template system allows for standardized question formats across the Reality.eth ecosystem.

Dispute

Represents a dispute for a question.

interface Dispute {
  id: string;                 // Unique identifier
  period: number;             // Current period of the dispute
  periodDeadline: string;     // Deadline for the current period
  nbRounds: string;           // Number of rounds
  nbChoices: string;          // Number of choices
  rounds: {                   // Information about rounds
    jurors: string;
    isCurrentRound: boolean;
  }[];
  lastPeriodChangeTs: string; // Timestamp of last period change
  arbitrableHistory: {        // History of arbitrable events
    id: string;
    metaEvidence: string;
  }[];
  arbitrated: string;         // Address of arbitrated contract
  ruled: boolean;             // Whether the dispute has been ruled
  ruling: string;             // The ruling
  evidenceGroup: {            // Group of evidence
    id: string;
    length: string;
    evidence: Evidence[];
  };
}

Chain

Represents a blockchain network.

interface Chain {
  id: string;           // Unique identifier (e.g., "ethereum")
  name: string;         // Display name (e.g., "Ethereum")
  subgraphUrl: string;  // URL for The Graph subgraph
  public_rpc_url: string; // Public RPC endpoint
  native_currency: string; // The native currency of the chain, used for the bonds of each question
}

Bridge

Represents a bridge between chains for Reality.eth questions.

interface Bridge {
  Name: string;
  Comment: string | null;
  "Home Chain": string;
  "Home Proxy": string | null;
  "Foreign Chain": string;
  "Foreign Proxy": string | null;
  Testnet: "Yes" | "No";
  Oracle: string | null;
  Bond: string | null;
  Appeals: boolean | null;
  Governor: boolean | null;
  Bot: boolean | false | "?" | null;
  Dispute: string | null;
}

Constants

SUPPORTED_CHAINS

Array of supported blockchain networks.

const SUPPORTED_CHAINS: Chain[] = [
  {
    id: "ethereum",
    name: "Ethereum",
    subgraphUrl: "https://gateway-arbitrum.network.thegraph.com/api/9a2c1f62c4da897f79c95a6a67600891/subgraphs/id/AGLkTv6eaW7JhQsLgB6SMzo43uM9V12ZoNkjAw7uijra",
    public_rpc_url: "https://rpc.ankr.com/eth",
  },
  {
    id: "gnosis",
    name: "Gnosis",
    subgraphUrl: "https://gateway-arbitrum.network.thegraph.com/api/9a2c1f62c4da897f79c95a6a67600891/subgraphs/id/E7ymrCnNcQdAAgLbdFWzGE5mvr5Mb5T9VfT43FqA7bNh",
    public_rpc_url: "https://rpc.ankr.com/gnosis",
  },
  {
    id: "polygon",
    name: "Polygon",
    subgraphUrl: "https://gateway-arbitrum.network.thegraph.com/api/9a2c1f62c4da897f79c95a6a67600891/subgraphs/id/AWx6jkeKZ3xKRzkrzgfCAMPT7d6Jc3AMcqB8koN3QEqE",
    public_rpc_url: "https://rpc.ankr.com/polygon",
  },
]

BRIDGES

Array of bridges between chains for Reality.eth questions.

Advanced Usage

Filtering Questions

The useQuestions hook supports filtering questions by various criteria:

const { filteredQuestions } = useQuestions({
  chain: SUPPORTED_CHAINS[0],
  filters: {
    phase: QuestionPhase.OPEN,
    // Add any property from the Question type
  }
});

Handling Pagination

The useQuestions hook supports pagination through the loadMore function:

function QuestionsList() {
  const { questions, hasMore, loadMore, loadingState } = useQuestions({
    chain: SUPPORTED_CHAINS[0]
  });

  return (
    <div>
      <ul>{questions.map(q => <li key={q.id}>{q.title}</li>)}</ul>
      
      {loadingState.loadingMore && <div>Loading more...</div>}
      
      {hasMore && (
        <button onClick={loadMore} disabled={loadingState.loadingMore}>
          Load More
        </button>
      )}
    </div>
  );
}

Complete Question Flow

This example shows how to list questions and then view details for a selected question:

function RealityApp() {
  const [selectedChain, setSelectedChain] = useState(SUPPORTED_CHAINS[0]);
  const [selectedQuestion, setSelectedQuestion] = useState(null);
  
  const { questions, loading } = useQuestions({
    chain: selectedChain
  });
  
  if (loading) return <div>Loading questions...</div>;
  
  if (selectedQuestion) {
    return (
      <QuestionDetail 
        question={selectedQuestion}
        onBack={() => setSelectedQuestion(null)}
      />
    );
  }
  
  return (
    <div>
      <h1>Reality.eth Questions</h1>
      <select onChange={e => {
        const chain = SUPPORTED_CHAINS.find(c => c.id === e.target.value);
        if (chain) setSelectedChain(chain);
      }}>
        {SUPPORTED_CHAINS.map(chain => (
          <option key={chain.id} value={chain.id}>
            {chain.name}
          </option>
        ))}
      </select>
      
      <ul>
        {questions.map(question => (
          <li key={question.id}>
            <h3>{question.title}</h3>
            <p>Phase: {question.phase}</p>
            <button onClick={() => setSelectedQuestion(question)}>
              View Details
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}

function QuestionDetail({ question, onBack }) {
  const { dispute, disputeLoading, evidences } = useDisputeData(question);
  
  return (
    <div>
      <button onClick={onBack}>Back to List</button>
      <h2>{question.title}</h2>
      <p>{question.description}</p>
      
      <h3>Options:</h3>
      <ul>
        {question.options.map((option, i) => (
          <li key={i}>{option}</li>
        ))}
      </ul>
      
      <h3>Current Answer: {question.currentAnswer}</h3>
      <p>Current Bond: {question.currentBond}</p>
      
      <h3>Dispute Information:</h3>
      {disputeLoading ? (
        <p>Loading dispute data...</p>
      ) : dispute ? (
        <div>
          <p>Dispute ID: {dispute.id}</p>
          <p>Status: {dispute.ruled ? 'Ruled' : 'Pending'}</p>
          <p>Ruling: {dispute.ruling}</p>
          
          <h4>Evidence:</h4>
          {evidences.length > 0 ? (
            <ul>
              {evidences.map(e => (
                <li key={e.id}>
                  <h5>{e.URI_contents.name}</h5>
                  <p>{e.URI_contents.description}</p>
                  <small>From: {e.sender}</small>
                </li>
              ))}
            </ul>
          ) : (
            <p>No evidence submitted</p>
          )}
        </div>
      ) : (
        <p>No dispute found for this question</p>
      )}
    </div>
  );
}

Technical Details

Data Flow

  1. useQuestions fetches questions from The Graph subgraphs for the selected chain
  2. Questions are transformed and cached for performance
  3. When a specific question is selected, useDisputeData fetches dispute information
  4. Dispute data is retrieved through a combination of:
    • The Graph subgraphs for dispute details
    • RPC calls to determine dispute IDs
    • Bridge information to handle cross-chain disputes

Cross-Chain Support

Reality.eth questions can be created on one chain and have their disputes resolved on another. The library handles this complexity through:

  1. Bridge configurations that map home chains to foreign chains
  2. Automatic detection of the appropriate chain for dispute resolution
  3. Proper routing of RPC calls to the correct endpoints

Troubleshooting

Common Issues

  1. No questions loading: Verify the chain's subgraph URL is correct and accessible
  2. Dispute data not loading: Check that the question has an arbitrator assigned and that arbitration has been requested
  3. Missing evidence: Evidence may take time to be indexed by The Graph

Readme

Keywords

none

Package Sidebar

Install

npm i reality-data-service

Weekly Downloads

153

Version

0.5.4

License

none

Unpacked Size

88 kB

Total Files

22

Last publish

Collaborators

  • gmkung