UNPKG

@reality.eth/cli-tools

Version:

Command-line tools for interacting with the Reality.eth fact verification platform. Mainly intended for doing arbitration from an offline computer.

289 lines (246 loc) 9.3 kB
'use strict'; const ethers = require("ethers"); const axios = require('axios'); const rc_question = require('@reality.eth/reality-eth-lib/formatters/question.js'); const rc_template = require('@reality.eth/reality-eth-lib/formatters/template.js'); const rc_contracts = require('@reality.eth/contracts'); if(process.argv.length < 3) { console.log('Usage: node load_questions_from_graph.js <chain_id> <offset|all> <num_per_fetch> <filter> <order>'); } let chain_id = parseInt(process.argv[2]); let offset; let do_fetch_all = false; if (process.argv[3] == 'all') { offset = 0; do_fetch_all = true; } else { offset = parseInt(process.argv[3]); } let num_display = parseInt(process.argv[4]); let filter_str = process.argv[5]; let order = process.argv[6]; let no_ts = true; offset = offset ? offset : 0; num_display = num_display ? num_display : 1000; filter_str = (filter_str == '') ? filter_str : '{}'; let CONTRACT_CONFIGS = {}; const chain_info = rc_contracts.chainData(chain_id); const tokens = rc_contracts.chainTokenList(chain_id); for(const t in tokens) { const configs = rc_contracts.realityETHConfigs(chain_id, t); for(const c in configs) { CONTRACT_CONFIGS[c.toLowerCase()] = configs[c]; } } if (do_fetch_all) { fetch_all(); } else { fetchAndDisplayQuestionFromGraph(chain_info, offset, num_display, filter_str, order); } async function fetch_all() { let some_left = true; while(some_left) { some_left = await fetchAndDisplayQuestionFromGraph(chain_info, offset, num_display, filter_str, order); offset = offset + num_display; } } async function fetchAndDisplayQuestionFromGraph(CHAIN_INFO, offset, num_display, filter_str, order) { const ts_now = parseInt(new Date()/1000); // const contract_str = JSON.stringify(displayed_contracts); /* const ranking_where = { 'questions-active-answered': `{${extra_filter_str} contract_in: ${contract_str}, isPendingArbitration: false, answerFinalizedTimestamp_gt: ${ts_now}, openingTimestamp_lte: ${ts_now}}`, 'questions-active-unanswered': `{${extra_filter_str} contract_in: ${contract_str}, isPendingArbitration: false, answerFinalizedTimestamp: null, openingTimestamp_lte: ${ts_now}}`, 'questions-upcoming': `{${extra_filter_str} contract_in: ${contract_str}, isPendingArbitration: false, openingTimestamp_gt: ${ts_now}}`, 'questions-resolved': `{${extra_filter_str} contract_in: ${contract_str}, answerFinalizedTimestamp_lt: ${ts_now}}`, 'questions-awaiting-arbitration': `{${extra_filter_str} contract_in: ${contract_str}, isPendingArbitration: true}`, } const ranking_order = { 'questions-active-answered': 'lastBond', 'questions-active-unanswered': 'createdTimestamp', 'questions-upcoming': 'createdTimestamp', 'questions-resolved': 'answerFinalizedTimestamp', 'questions-awaiting-arbitration': 'lastBond' } */ const network_graph_url = CHAIN_INFO.graphURL; if (!network_graph_url) { throw new Error('No graph endpoint found for the chain', chain_id); } // console.log('graph url is ', network_graph_url); const question_fetch_fields = questionFetchFields(); // const question_fetch_fields = 'questionId' // questions(first: ${num_display}, skip: ${offset}, where: ${filter_str}, orderBy: ${order}, orderDirection: desc) { const query = ` { questions(first: ${num_display}, skip: ${offset}, where: ${filter_str}, orderDirection: desc) { ${question_fetch_fields} } } `; // console.log(query); const fetched_ms = Date.now(); // console.log('sending graph query', query); const res = await axios.post(network_graph_url, {query: query}); // console.log('graph res', res); let found = false; for (const q of res.data.data.questions) { found = true; handleQuestion(q, fetched_ms) // const question_posted = RCInstance(q.contract).filters.LogNewQuestion(q.questionId); // const result = await RCInstance(q.contract).queryFilter(question_posted, parseInt(q.createdBlock), parseInt(q.createdBlock)); } return found; } function handleQuestion(q, fetched_ms) { const fq = filledQuestion(q, fetched_ms); console.log(fq); } function filledAnswer(item, fetched_ms) { // For now we make this look like what we get from a log event let ans = {}; if (item.isCommitment) { ans.commitment_id = item.commitmentId; ans.is_commitment = true; ans.revealed_block = item.revealedBlock } else { ans.is_commitment = false; ans.commitment_id = null; ans.revealed_block = null; } ans.answer = item.answer; // ans.isUnrevealed = = item.isUnrevealed; // TODO: use this later ans.bond = ethers.BigNumber.from(item.bond); ans.history_hash = item.historyHash; ans.user = item.user; ans.ts = ethers.BigNumber.from(item.timestamp); // txid isn't filled from the graph, only from our unconfirmed transactions ans.txid = item.txid; if (!no_ts) { ans.fetched_ms = fetched_ms; } return ans; } function filledQuestion(item, fetched_ms) { let question = {'history_unconfirmed': []}; question.arbitrator = item.arbitrator; question.question_id = item.questionId; question.creation_ts = ethers.BigNumber.from(item.createdTimestamp); question.question_creator = item.user; question.question_created_block = item.createdBlock; question.content_hash = item.contentHash; question.question_text= item.data; question.template_id = item.template.templateId; question.block_mined = item.createdBlock; if (!no_ts) { question.fetched_ms = fetched_ms; } if (item.openingTimestamp) { question.opening_ts = ethers.BigNumber.from(item.openingTimestamp); } else { question.opening_ts = ethers.BigNumber.from(0); } question.contract = item.contract; question.version_number = CONTRACT_CONFIGS[question.contract.toLowerCase()].version_number; if (item.reopens) { question.reopener_of_question_id = item.reopens.id; } if (item.reopenedBy) { question.reopened_by = item.reopenedBy.id; } //question.bounty = data.args['bounty']; try { // question.question_json = JSON.parse(item.json_str); question.question_json = rc_question.populatedJSONForTemplate(item.template.questionText, item.data, true); question.has_invalid_option = rc_question.hasInvalidOption(question.question_json, question.version_number); question.has_too_soon_option = rc_question.hasAnsweredTooSoonOption(question.question_json, question.version_number); } catch (e) { console.log('error parsing json', e); return null; // question.question_json = null; } if (item.answerFinalizedTimestamp) { question.finalization_ts = ethers.BigNumber.from(item.answerFinalizedTimestamp); // GRAPH_TODO - check this is what we need } else { question.finalization_ts = ethers.BigNumber.from(0); } question.is_pending_arbitration = item.isPendingArbitration; question.timeout = ethers.BigNumber.from(item.timeout); question.bounty = ethers.BigNumber.from(item.bounty); question.best_answer = item.currentAnswer; question.bond = ethers.BigNumber.from(item.lastBond); question.history_hash = item.historyHash; if (!question.history_hash) { question.history_hash = "0x0000000000000000000000000000000000000000000000000000000000000000"; } question.min_bond = ethers.BigNumber.from(item.minBond); question.history = []; for(let respi in item.responses) { question.history.push(filledAnswer(item.responses[respi], fetched_ms)); } question.history = question.history.sort((a, b) => (a.bond.isZero() || ( a.bond.gt(b.bond) && !b.bond.isZero() ) ) ? 1 : -1); return question; } function questionFetchFields() { const txt = ` id, questionId, contract, createdBlock, createdTimestamp, updatedBlock, updatedTimestamp, data, qJsonStr, qTitle, qCategory, qLang, qType, arbitrator, user, openingTimestamp, timeout, bounty, currentAnswer, currentAnswerBond, currentAnswerTimestamp, contentHash, historyHash, minBond, lastBond, cumulativeBonds, arbitrationRequestedTimestamp, arbitrationRequestedBy, isPendingArbitration, arbitrationOccurred, answerFinalizedTimestamp, currentScheduledFinalizationTimestamp, template { id, templateId, questionText }, reopenedBy { id }, reopens { id }, responses { id, timestamp, answer, isUnrevealed, isCommitment, commitmentId, bond, user, historyHash, createdBlock, revealedBlock } `; return txt; }