Skip to content

Commit

Permalink
Make account, transactions, and validators list error more readable
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaw3d committed Jul 1, 2022
1 parent d23168f commit f556050
Show file tree
Hide file tree
Showing 13 changed files with 65 additions and 39 deletions.
1 change: 1 addition & 0 deletions src/app/components/ErrorFormatter/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export function ErrorFormatter(props: Props) {
indexerName: backendToLabel[backend()],
},
),
[WalletErrors.DisconnectedError]: t('errors.disconnectedError', 'Lost connection.'),
}

const error = errorMap[props.code]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
selectTransactionsError,
} from '../../../../state/account/selectors'
import { selectSelectedNetwork } from 'app/state/network/selectors'
import { ErrorFormatter } from 'app/components/ErrorFormatter'

interface Props {}

Expand All @@ -35,11 +36,8 @@ export function TransactionHistory(props: Props) {
<Box gap="small" margin="none">
{transactionsError && (
<p>
{t(
'account.transaction.loadingError',
"Couldn't load transactions. List may be empty or out of date.",
)}{' '}
{transactionsError}
{t('account.transaction.loadingError', "Couldn't load transactions.")}{' '}
<ErrorFormatter code={transactionsError.code} message={transactionsError.message} />
</p>
)}
{allTransactions.length ? (
Expand Down
13 changes: 7 additions & 6 deletions src/app/pages/AccountPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* AccountPage
*
*/
import { AlertBox } from 'app/components/AlertBox'
import { ErrorFormatter } from 'app/components/ErrorFormatter'
import { TransactionModal } from 'app/components/TransactionModal'
import { TransitionRoute } from 'app/components/TransitionRoute'
Expand Down Expand Up @@ -116,19 +117,19 @@ export function AccountPage(props: Props) {
</Layer>
)}
{account.accountError && (
<p>
{t('account.loadingError', "Couldn't load account. Information may be missing or out of date.")}{' '}
{account.accountError}
</p>
<AlertBox color="status-error">
{t('account.loadingError', "Couldn't load account.")}{' '}
<ErrorFormatter code={account.accountError.code} message={account.accountError.message} />
</AlertBox>
)}
{stake.updateDelegationsError && (
<p>
<AlertBox color="status-error">
{t('delegations.loadingError', "Couldn't load delegations.")}{' '}
<ErrorFormatter
code={stake.updateDelegationsError.code}
message={stake.updateDelegationsError.message}
/>
</p>
</AlertBox>
)}
{address && address !== '' && (
<>
Expand Down
5 changes: 4 additions & 1 deletion src/app/pages/StakingPage/Features/ValidatorList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*
*/
import { AmountFormatter } from 'app/components/AmountFormatter'
import { ErrorFormatter } from 'app/components/ErrorFormatter'
import { ShortAddress } from 'app/components/ShortAddress'
import { ValidatorStatus } from 'app/pages/StakingPage/Features/ValidatorList/ValidatorStatus'
import { stakingActions } from 'app/state/staking'
Expand Down Expand Up @@ -112,7 +113,9 @@ export const ValidatorList = memo((props: Props) => {
staleTimestamp: new Date(validatorsTimestamp!).toLocaleString(),
})}
<br />
{updateValidatorsError}
{validators.length <= 0 && (
<ErrorFormatter code={updateValidatorsError.code} message={updateValidatorsError.message} />
)}
</p>
)}
<TypeSafeDataTable
Expand Down
13 changes: 7 additions & 6 deletions src/app/state/account/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { PayloadAction } from '@reduxjs/toolkit'
import { Transaction } from 'app/state/transaction/types'
import { ErrorPayload } from 'types/errors'
import { createSlice } from 'utils/@reduxjs/toolkit'
import { AccountState, Account } from './types'

export const initialState: AccountState = {
address: '',
liquid_balance: 0,

accountError: null,
accountError: undefined,
transactions: [],
transactionsError: null,
transactionsError: undefined,
loading: true,
}

Expand All @@ -22,17 +23,17 @@ const slice = createSlice({
},
fetchAccount(state, action: PayloadAction<string>) {},
accountLoaded(state, action: PayloadAction<Account>) {
state.accountError = null
state.accountError = undefined
Object.assign(state, action.payload)
},
accountError(state, action: PayloadAction<string>) {
accountError(state, action: PayloadAction<ErrorPayload>) {
state.accountError = action.payload
},
transactionsLoaded(state, action: PayloadAction<Transaction[]>) {
state.transactionsError = null
state.transactionsError = undefined
state.transactions = action.payload
},
transactionsError(state, action: PayloadAction<string>) {
transactionsError(state, action: PayloadAction<ErrorPayload>) {
state.transactionsError = action.payload
},
setLoading(state, action: PayloadAction<boolean>) {
Expand Down
24 changes: 18 additions & 6 deletions src/app/state/account/saga.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { PayloadAction } from '@reduxjs/toolkit'
import { addressToPublicKey, parseRpcBalance } from 'app/lib/helpers'
import { all, call, fork, join, put, select, take, takeLatest } from 'typed-redux-saga'
import { WalletError, WalletErrors } from 'types/errors'

import { accountActions as actions } from '.'
import { getExplorerAPIs, getOasisNic } from '../network/saga'
Expand All @@ -27,16 +28,24 @@ export function* loadAccount(action: PayloadAction<string>) {
try {
const account = yield* call(getAccount, address)
yield put(actions.accountLoaded(account))
} catch (apiError) {
} catch (apiError: any) {
console.error('get account failed, continuing to RPC fallback.', apiError)
try {
const account = yield* call([nic, nic.stakingAccount], { owner: publicKey, height: 0 })
const balance = parseRpcBalance(account)
yield put(actions.accountLoaded({ address, liquid_balance: parseFloat(balance.available) }))
} catch (rpcError) {
console.error('get account with RPC failed, continuing without updated account.', rpcError)
yield put(actions.accountError('' + apiError))
return
if (apiError instanceof WalletError) {
yield* put(actions.accountError({ code: apiError.type, message: apiError.message }))
} else {
yield* put(
actions.accountError({
code: WalletErrors.UnknownError,
message: apiError.message,
}),
)
}
}
}
}),
Expand All @@ -49,10 +58,13 @@ export function* loadAccount(action: PayloadAction<string>) {
limit: 20,
})
yield put(actions.transactionsLoaded(transactions))
} catch (e) {
} catch (e: any) {
console.error('get transactions list failed, continuing without updated list.', e)
yield put(actions.transactionsError('' + e))
return
if (e instanceof WalletError) {
yield* put(actions.transactionsError({ code: e.type, message: e.message }))
} else {
yield* put(actions.transactionsError({ code: WalletErrors.UnknownError, message: e.message }))
}
}
}),
),
Expand Down
5 changes: 3 additions & 2 deletions src/app/state/account/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Transaction } from 'app/state/transaction/types'
import { ErrorPayload } from 'types/errors'

export interface BalanceDetails {
total: number
Expand All @@ -15,7 +16,7 @@ export interface Account {
/* --- STATE --- */
export interface AccountState extends Account {
loading: boolean
accountError: string | null
accountError?: ErrorPayload
transactions: Transaction[]
transactionsError: string | null
transactionsError?: ErrorPayload
}
6 changes: 3 additions & 3 deletions src/app/state/staking/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const initialState: StakingState = {
delegations: [],
updateDelegationsError: undefined,
validators: null,
updateValidatorsError: null,
updateValidatorsError: undefined,
selectedValidatorDetails: null,
selectedValidator: null,
loading: false,
Expand All @@ -24,10 +24,10 @@ const slice = createSlice({
},
fetchAccount(state, action: PayloadAction<string>) {},
updateValidators(state, action: PayloadAction<Validators>) {
state.updateValidatorsError = null
state.updateValidatorsError = undefined
state.validators = action.payload
},
updateValidatorsError(state, action: PayloadAction<{ error: string; validators: Validators }>) {
updateValidatorsError(state, action: PayloadAction<{ error: ErrorPayload; validators: Validators }>) {
state.updateValidatorsError = action.payload.error
state.validators = action.payload.validators
},
Expand Down
8 changes: 6 additions & 2 deletions src/app/state/staking/saga.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as matchers from 'redux-saga-test-plan/matchers'
import { EffectProviders, StaticProvider } from 'redux-saga-test-plan/providers'
import { select } from 'redux-saga/effects'
import { RootState } from 'types'
import { WalletError, WalletErrors } from 'types/errors'

import { initialState, stakingActions, stakingReducer } from '.'
import { getExplorerAPIs, getOasisNic } from '../network/saga'
Expand Down Expand Up @@ -144,7 +145,7 @@ describe('Staking Sagas', () => {
})

it('should use fallback on mainnet', () => {
getAllValidators.mockRejectedValue('apiFailed')
getAllValidators.mockRejectedValue(new WalletError(WalletErrors.IndexerAPIError, 'Request failed'))
const getMainnetDumpValidatorsMock = {
dump_timestamp: 1647996761337,
dump_timestamp_iso: '2022-03-23T00:52:41.337Z',
Expand Down Expand Up @@ -185,7 +186,10 @@ describe('Staking Sagas', () => {
.provide([...providers, [matchers.call.fn(getMainnetDumpValidators), getMainnetDumpValidatorsMock]])
.put(
stakingActions.updateValidatorsError({
error: 'apiFailed',
error: {
code: WalletErrors.IndexerAPIError,
message: 'Request failed',
},
validators: {
timestamp: getMainnetDumpValidatorsMock.dump_timestamp,
network: 'mainnet',
Expand Down
13 changes: 8 additions & 5 deletions src/app/state/staking/saga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,23 @@ export function* refreshValidators() {
list: validators,
}),
)
} catch (errorApi) {
} catch (errorApi: any) {
console.error('get validators list failed', errorApi)

const fallback = yield* call(getFallbackValidators, network, '' + errorApi)
const fallback = yield* call(getFallbackValidators, network, errorApi)
yield* put(
stakingActions.updateValidatorsError({
error: fallback.error,
error: {
code: fallback.error instanceof WalletError ? fallback.error.type : WalletErrors.UnknownError,
message: fallback.error.message,
},
validators: fallback.validators,
}),
)
}
}

function* getFallbackValidators(network: NetworkType, errorApi: string) {
function* getFallbackValidators(network: NetworkType, errorApi: Error) {
let fallbackValidators: Validators = {
timestamp: yield* call(now),
network: network,
Expand Down Expand Up @@ -104,7 +107,7 @@ function* getFallbackValidators(network: NetworkType, errorApi: string) {
} catch (errorDumpValidators) {
// If fetching dump_validators fails, fall back to empty list
return {
error: 'Lost connection',
error: new WalletError(WalletErrors.DisconnectedError, 'Lost connection'),
validators: fallbackValidators,
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/app/state/staking/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export interface StakingState {
validators: Validators | null

/** Error from last attempt to update our list of validators */
updateValidatorsError: string | null
updateValidatorsError?: ErrorPayload

/** List of active delegations for the selected account */
delegations: Delegation[]
Expand Down
5 changes: 3 additions & 2 deletions src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"delegate": "Delegate"
},
"loading": "Loading account",
"loadingError": "Couldn't load account. Information may be missing or out of date.",
"loadingError": "Couldn't load account.",
"otherTransaction": {
"designation": "Other address",
"header": "Unrecognized transaction, method '{{method}}'"
Expand Down Expand Up @@ -54,7 +54,7 @@
"received": "Received <0></0> delegation in escrow",
"sent": "Delegated <0></0> to validator"
},
"loadingError": "Couldn't load transactions. List may be empty or out of date.",
"loadingError": "Couldn't load transactions.",
"reclaimEscrow": {
"received": "<0></0> reclaimed by delegator",
"sent": "Reclaimed <0></0> from validator"
Expand Down Expand Up @@ -106,6 +106,7 @@
"errors": {
"LedgerOasisAppIsNotOpen": "Oasis App on Ledger is closed.",
"cannotSendToSelf": "Cannot send to yourself",
"disconnectedError": "Lost connection.",
"duplicateTransaction": "Duplicate transaction",
"indexerAPIError": "{{indexerName}} appears to be down, some information may be missing or out of date. Please, come back later.",
"insufficientBalance": "Insufficient balance",
Expand Down
1 change: 1 addition & 0 deletions src/types/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export enum WalletErrors {
LedgerTransactionRejected = 'transaction_rejected',
LedgerAppVersionNotSupported = 'ledger_version_not_supported',
IndexerAPIError = 'indexer_api_error',
DisconnectedError = 'disconnected_error',
}

export interface ErrorPayload {
Expand Down

0 comments on commit f556050

Please sign in to comment.