reality-data-service
v0.6.7
Published
A comprehensive library for interacting with Reality.eth questions and disputes across multiple blockchains.
Readme
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-serviceCore Exports
Hooks
useQuestions
A React hook for fetching and managing Reality.eth questions.
function useQuestions({
chain,
searchTerm,
filters
}: UseQuestionsConfig): UseQuestionsResultParameters:
chain: The blockchain to fetch questions from (seeChaintype)searchTerm(optional): String to filter questions by title/contentfilters(optional): Object with additional filtering criteria
Returns:
questions: Array of all fetched questionsfilteredQuestions: Array of questions after filters are appliedloading: Boolean indicating if questions are being loadederror: Error message if fetch failed, null otherwisehasMore: Boolean indicating if more questions can be loadedloadMore: Function to load more questionsrefresh: Function to refresh the questionsloadingState: Object with detailed loading state informationstatus: 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 thechainproperty)
Returns:
disputeId: The ID of the dispute, or null if no dispute existsdispute: The dispute data, or undefined if not loadeddisputeLoading: Boolean indicating if dispute data is being loadedevidences: Array of evidence submitted for the disputemetaEvidence: Metadata about the disputearbitrableContractAddress: 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.linkto the URI to form the complete URL. For example, if the URI is/ipfs/QmRXgRaKkcKKfXjTFozwoWLosFHmtcEaeuj1cL1G8xKHJd/file.pdf, the complete URL would behttps://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
fileURIfield may point to additional documents, which also need to be prefixed withhttps://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
useQuestionsfetches questions from The Graph subgraphs for the selected chain- Questions are transformed and cached for performance
- When a specific question is selected,
useDisputeDatafetches dispute information - 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:
- Bridge configurations that map home chains to foreign chains
- Automatic detection of the appropriate chain for dispute resolution
- Proper routing of RPC calls to the correct endpoints
Troubleshooting
Common Issues
- No questions loading: Verify the chain's subgraph URL is correct and accessible
- Dispute data not loading: Check that the question has an arbitrator assigned and that arbitration has been requested
- Missing evidence: Evidence may take time to be indexed by The Graph
