diff --git a/src/App.js b/src/App.js index 89822d4e..9b9133e4 100644 --- a/src/App.js +++ b/src/App.js @@ -2,15 +2,15 @@ import React from 'react' import { BrowserRouter } from 'react-router-dom' import { Main, ToastHub } from '@aragon/ui' import theme from './theme-court' +import AppLoader from './components/AppLoader' +import GlobalErrorHandler from './GlobalErrorHandler' import MainView from './components/MainView' +import OnboardingLoader from './components/OnboardingLoader' +import Routes from './Routes' import { ActivityProvider } from './components/Activity/ActivityProvider' import { CourtClockProvider } from './providers/CourtClock' import { CourtConfigProvider } from './providers/CourtConfig' import { WalletProvider } from './providers/Wallet' -import AppLoader from './components/AppLoader' -import OnboardingLoader from './components/OnboardingLoader' -import Routes from './Routes' -import GlobalErrorHandler from './GlobalErrorHandler' function App() { return ( diff --git a/src/components/Disputes/DisputeActions.js b/src/components/Disputes/DisputeActions.js index 47a33c24..d1ce3992 100644 --- a/src/components/Disputes/DisputeActions.js +++ b/src/components/Disputes/DisputeActions.js @@ -187,6 +187,7 @@ function InformationSection({ } // Helper function that returns main attributes for the YourVoteInfo component +// TODO: Contemplate final round cases (when a juror has voted, the ANJ amount is pre-slashed) const useInfoAttributes = ({ hasJurorVoted, jurorDraft, diff --git a/src/graphql-exchanges.js b/src/graphql-exchanges.js new file mode 100644 index 00000000..c5dd99a4 --- /dev/null +++ b/src/graphql-exchanges.js @@ -0,0 +1,37 @@ +import { fetchExchange, subscriptionExchange } from 'urql' +import { SubscriptionClient } from 'subscriptions-transport-ws' +import { captureMessage } from '@sentry/browser' +import endpoints from './endpoints' + +const GRAPH_API_ENDPOINTS = endpoints() +const subscriptionClient = new SubscriptionClient(GRAPH_API_ENDPOINTS[1], { + reconnect: true, + reconnectionAttempts: 10, +}) + +// Default exchanges +const DEFAULT_FETCH_EXCHANGE = fetchExchange +const DEFAULT_SUBSCRIPTION_EXCHANGE = subscriptionExchange({ + forwardSubscription: operation => subscriptionClient.request(operation), +}) + +export function getFetchExchange() { + return DEFAULT_FETCH_EXCHANGE +} + +export function getSubscriptionExchange() { + return DEFAULT_SUBSCRIPTION_EXCHANGE +} + +let connectionAttempts = 0 +subscriptionClient.onConnected(() => (connectionAttempts = 0)) + +// Check for connection errors and if reaches max attempts send error log to Sentry +subscriptionClient.onError(err => { + const maxReconnectionAttempts = subscriptionClient.reconnectionAttempts + + if (maxReconnectionAttempts === ++connectionAttempts) { + captureMessage(`Connection error, could not connect to ${err.target.url}`) + } + console.log('Retrying connection...') +}) diff --git a/src/hooks/query-hooks.js b/src/hooks/query-hooks.js index 4751c0d9..52578f50 100644 --- a/src/hooks/query-hooks.js +++ b/src/hooks/query-hooks.js @@ -1,8 +1,8 @@ import { useQuery } from 'urql' +import { JurorFirstANJActivationMovement } from '../queries/balances' +import { ActiveJurors, JurorFeesClaimed } from '../queries/juror' import { JurorDrafts } from '../queries/jurorDrafts' -import { JurorFeesClaimed } from '../queries/juror' -import { ActiveJurors, FirstANJActivationMovement } from '../queries/balances' export function useJurorDraftQuery(jurorId) { const [result] = useQuery({ @@ -42,7 +42,7 @@ export function useJurorRewardsEverClaimedQuery(jurorId) { export function useFirstANJActivationQuery(jurorId, { pause = false }) { const [result] = useQuery({ - query: FirstANJActivationMovement, + query: JurorFirstANJActivationMovement, variables: { id: jurorId.toLowerCase() }, pause, }) diff --git a/src/hooks/subscription-hooks.js b/src/hooks/subscription-hooks.js index daf6c725..d3d79646 100644 --- a/src/hooks/subscription-hooks.js +++ b/src/hooks/subscription-hooks.js @@ -1,38 +1,45 @@ import { useMemo } from 'react' import { useSubscription } from 'urql' +import { useCourtConfig } from '../providers/CourtConfig' + +// queries import { OpenTasks } from '../queries/tasks' import { CourtConfig, FeeMovements, JurorsRegistryModule, } from '../queries/court' -import { useCourtConfig } from '../providers/CourtConfig' -import { SingleDispute, AllDisputes } from '../queries/disputes' +import { AllDisputes, SingleDispute } from '../queries/disputes' import { AppealsByMaker, AppealsByTaker } from '../queries/appeals' -import { ANJBalance, Juror, JurorTreasuryBalances } from '../queries/balances' import { - JurorDraftsNotRewarded, - CurrentTermJurorDrafts, -} from '../queries/jurorDrafts' -import { CourtModuleType } from '../types/court-module-types' + JurorANJBalances, + JurorANJWalletBalance, + JurorTreasuryBalances, +} from '../queries/balances' +import { JurorDraftsFrom, JurorDraftsNotRewarded } from '../queries/jurorDrafts' + +// utils import { bigNum } from '../lib/math-utils' import { dayjs } from '../utils/date-utils' import { groupMovements } from '../utils/anj-movement-utils' import { transformAppealDataAttributes } from '../utils/appeal-utils' import { transformDisputeDataAttributes } from '../utils/dispute-utils' import { transformJurorDataAttributes } from '../utils/juror-draft-utils' +import { transformClaimedFeesDataAttributes } from '../utils/subscription-utils' import { getModuleAddress, transformCourtConfigDataAttributes, } from '../utils/court-utils' -import { transformClaimedFeesDataAttributes } from '../utils/subscription-utils' + +// types +import { CourtModuleType } from '../types/court-module-types' const NO_AMOUNT = bigNum(0) // Subscription to get juror's wallet balance function useANJBalance(jurorId) { const [{ data, error }] = useSubscription({ - query: ANJBalance, + query: JurorANJWalletBalance, variables: { id: jurorId.toLowerCase() }, }) @@ -48,7 +55,7 @@ function useJuror(jurorId) { .unix() const [{ data, error }] = useSubscription({ - query: Juror, + query: JurorANJBalances, variables: { id: jurorId.toLowerCase(), from: yesterday }, }) @@ -203,7 +210,7 @@ export function useDisputesSubscription() { const disputes = useMemo( () => - data && data.disputes + data?.disputes ? data.disputes.map(dispute => transformDisputeDataAttributes(dispute, courtConfig) ) @@ -227,7 +234,7 @@ export function useCurrentTermJurorDraftsSubscription( pause ) { const [result] = useSubscription({ - query: CurrentTermJurorDrafts, + query: JurorDraftsFrom, variables: { id: jurorId.toLowerCase(), from: termStartTime }, pause, }) diff --git a/src/index.js b/src/index.js index 93eaa480..67ad7604 100644 --- a/src/index.js +++ b/src/index.js @@ -5,11 +5,9 @@ import { Provider as UrqlProvider, cacheExchange, debugExchange, - fetchExchange, - subscriptionExchange, } from 'urql' -import { SubscriptionClient } from 'subscriptions-transport-ws' -import { captureMessage } from '@sentry/browser' +import { getFetchExchange, getSubscriptionExchange } from './graphql-exchanges' + import { devtoolsExchange } from '@urql/devtools' import { createGlobalStyle } from 'styled-components' import App from './App' @@ -18,12 +16,7 @@ import initializeSentry from './sentry' initializeSentry() -const [GRAPH_API_ENDPOINT_HTTP, GRAPH_API_ENDPOINT_WS] = endpoints() - -const subscriptionClient = new SubscriptionClient(GRAPH_API_ENDPOINT_WS, { - reconnect: true, - reconnectionAttempts: 10, -}) +const [GRAPH_API_ENDPOINT_HTTP] = endpoints() const client = createClient({ url: GRAPH_API_ENDPOINT_HTTP, @@ -31,26 +24,11 @@ const client = createClient({ debugExchange, devtoolsExchange, cacheExchange, - fetchExchange, - subscriptionExchange({ - forwardSubscription: operation => subscriptionClient.request(operation), - }), + getFetchExchange(), + getSubscriptionExchange(), ], }) -let connectionAttempts = 0 -subscriptionClient.onConnected(() => (connectionAttempts = 0)) - -// Check for connection errors and if reaches max attempts send error log to Sentry -subscriptionClient.onError(err => { - const maxReconnectionAttempts = subscriptionClient.reconnectionAttempts - - if (maxReconnectionAttempts === ++connectionAttempts) { - captureMessage(`Connection error, could not connect to ${err.target.url}`) - } - console.log('Retrying connection...') -}) - const GlobalStyle = createGlobalStyle` body img { user-select:none; diff --git a/src/queries/appeals.js b/src/queries/appeals.js index 4ae6cfac..9080a999 100644 --- a/src/queries/appeals.js +++ b/src/queries/appeals.js @@ -1,7 +1,7 @@ import gql from 'graphql-tag' export const AppealsByMaker = gql` - subscription($maker: Bytes!, $settled: Boolean!) { + subscription AppealsByMaker($maker: Bytes!, $settled: Boolean!) { appeals(where: { maker: $maker, settled: $settled }) { id round { @@ -27,7 +27,7 @@ export const AppealsByMaker = gql` ` export const AppealsByTaker = gql` - subscription($taker: Bytes!, $settled: Boolean!) { + subscription AppealsByTaker($taker: Bytes!, $settled: Boolean!) { appeals(where: { taker: $taker, settled: $settled }) { id round { diff --git a/src/queries/balances.js b/src/queries/balances.js index 2338447e..1cce4086 100644 --- a/src/queries/balances.js +++ b/src/queries/balances.js @@ -1,15 +1,15 @@ import gql from 'graphql-tag' -export const ANJBalance = gql` - subscription ANJBalance($id: ID!) { +export const JurorANJWalletBalance = gql` + subscription JurorANJWalletBalance($id: ID!) { anjbalance(id: $id) { amount } } ` -export const Juror = gql` - subscription Juror($id: ID!, $from: BigInt!) { +export const JurorANJBalances = gql` + subscription JurorANJBalances($id: ID!, $from: BigInt!) { juror(id: $id) { activeBalance lockedBalance @@ -47,8 +47,8 @@ export const JurorTreasuryBalances = gql` } ` -export const FirstANJActivationMovement = gql` - query Juror($id: ID!) { +export const JurorFirstANJActivationMovement = gql` + query JurorFirstANJActivationMovement($id: ID!) { juror(id: $id) { anjMovements( where: { type: "Activation" } @@ -64,10 +64,3 @@ export const FirstANJActivationMovement = gql` } } ` -export const ActiveJurors = gql` - query Jurors { - jurors(first: 1000, where: { activeBalance_gt: 0 }) { - id - } - } -` diff --git a/src/queries/disputes.js b/src/queries/disputes.js index 6264df2b..6b4f0dcc 100644 --- a/src/queries/disputes.js +++ b/src/queries/disputes.js @@ -4,27 +4,16 @@ export const AllDisputes = gql` subscription AllDisputes($limit: Int) { disputes(first: $limit, orderBy: createdAt, orderDirection: desc) { id - txHash - createTermId - possibleRulings finalRuling lastRoundId state metadata - createdAt rounds { id state number draftTermId - jurorsNumber - settledPenalties - jurorFees delayedTerms - selectedJurors - coherentJurors - collectedTokens - createdAt jurors { juror { id @@ -32,18 +21,9 @@ export const AllDisputes = gql` commitment outcome } - vote { - id - winningOutcome - } + appeal { id - maker - appealedRuling - taker - opposedRuling - settled - createdAt } } } @@ -51,7 +31,7 @@ export const AllDisputes = gql` ` export const SingleDispute = gql` - subscription Dispute($id: ID!) { + subscription SingleDispute($id: ID!) { dispute(id: $id) { id txHash diff --git a/src/queries/juror.js b/src/queries/juror.js index b1b21cfd..ce53a1de 100644 --- a/src/queries/juror.js +++ b/src/queries/juror.js @@ -8,3 +8,11 @@ export const JurorFeesClaimed = gql` } } ` + +export const ActiveJurors = gql` + query ActiveJurors { + jurors(first: 1000, where: { activeBalance_gt: 0 }) { + id + } + } +` diff --git a/src/queries/jurorDrafts.js b/src/queries/jurorDrafts.js index 8730b657..851c2b95 100644 --- a/src/queries/jurorDrafts.js +++ b/src/queries/jurorDrafts.js @@ -2,14 +2,12 @@ import gql from 'graphql-tag' // All juror drafts by `id` not yet rewarded export const JurorDraftsNotRewarded = gql` - subscription JurorDraft($id: ID!) { + subscription JurorDraftsNotRewarded($id: ID!) { juror(id: $id) { id drafts(where: { rewarded: false }) { id weight - locked - rewarded outcome round { number @@ -29,8 +27,8 @@ export const JurorDraftsNotRewarded = gql` ` // First juror draft already rewarded -export const JurorDraftRewarded = gql` - query JurorDraft($id: ID!) { +export const JurorDraftsRewarded = gql` + query JurorDraftsRewarded($id: ID!) { juror(id: $id) { id drafts(where: { rewarded: true }, first: 1) { @@ -40,9 +38,9 @@ export const JurorDraftRewarded = gql` } ` -// Jurors drafts by `id` for current term -export const CurrentTermJurorDrafts = gql` - subscription JurorDrafts($id: ID!, $from: BigInt!) { +// Jurors drafts for juror with id `$id` created since `$from` +export const JurorDraftsFrom = gql` + subscription JurorDraftsFrom($id: ID!, $from: BigInt!) { juror(id: $id) { id drafts(where: { createdAt_gt: $from }) { @@ -53,7 +51,8 @@ export const CurrentTermJurorDrafts = gql` } ` -// All juror drafts by `id` +// All juror drafts for juror with id `id` +// Useful query to know all disputes that the juror by `$id` is part of export const JurorDrafts = gql` query JurorDrafts($id: ID!) { juror(id: $id) {