diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 11b79315e..c20d20ddf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,6 +5,7 @@ jobs: runs-on: ubuntu-latest env: APP_NAME: wallet + ETHERSCAN_API_KEY: "${{ github.ref == 'refs/heads/master' && secrets.ETHERSCAN_API_KEY_PROD || secrets.ETHERSCAN_API_KEY_DEV }}" WALLET_CONNECT_PROJECT_ID: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} TOKEN_SALES_URL_MAINNET: ${{ secrets.TOKEN_SALES_URL_MAINNET }} TOKEN_SALES_URL_TESTNET: ${{ secrets.TOKEN_SALES_URL_TESTNET }} diff --git a/src/composables/connectionStatus.ts b/src/composables/connectionStatus.ts index 8d53372c5..eac40630e 100644 --- a/src/composables/connectionStatus.ts +++ b/src/composables/connectionStatus.ts @@ -11,6 +11,7 @@ import { import { StatusIconType } from '@/types'; import { ROUTE_ACCOUNT } from '@/popup/router/routeNames'; import { useAeMiddleware, useAeTippingBackend } from '@/protocols/aeternity/composables'; +import { isEtherscanUnavailable } from '@/protocols/ethereum/libs/EtherscanService'; import { tg as t } from '@/popup/plugins/i18n'; interface StatusType { @@ -38,14 +39,7 @@ export function useConnectionStatus() { const showMultisigError = computed( () => route.name === ROUTE_ACCOUNT && isMultisigBackendUnavailable.value, ); - const isError = computed(() => ( - !isOnline.value - || isAeNodeError.value - || isMiddlewareUnavailable.value - || (middlewareStatus.value && !middlewareStatus.value.mdwSynced) - || showMultisigError.value - || isBackendUnavailable.value - )); + const isError = computed(() => !isAeNodeConnecting.value && !justBeenConnected.value); // Display "Connected" message for a while after connecting to node. watch(isAeNodeReady, (val) => { @@ -97,6 +91,13 @@ export function useConnectionStatus() { description: t('connectionStatus.backend.description'), icon: 'critical', }; + case isEtherscanUnavailable.value: + return { + statusMessage: t('connectionStatus.etherscan.statusMessage'), + title: t('connectionStatus.etherscan.title'), + description: t('connectionStatus.etherscan.description'), + icon: 'critical', + }; case showMultisigError.value: return { statusMessage: t('connectionStatus.multisig.statusMessage'), diff --git a/src/popup/components/ConnectionStatus.vue b/src/popup/components/ConnectionStatus.vue index 89c05dfb0..32ceba30d 100644 --- a/src/popup/components/ConnectionStatus.vue +++ b/src/popup/components/ConnectionStatus.vue @@ -16,9 +16,6 @@ :icon="status.icon" warning class="btn-help" - :class="{ - 'is-error': isError, - }" /> diff --git a/src/popup/locales/en.json b/src/popup/locales/en.json index c68cbc842..9903d8fa8 100644 --- a/src/popup/locales/en.json +++ b/src/popup/locales/en.json @@ -104,6 +104,11 @@ "title": "Multisig backend failure", "description": "Multisig vaults may not be accessible at the moment due to temporary backend failure.

If you are trying to access your multisig vaults please try again later.

" }, + "etherscan": { + "statusMessage": "Etherscan services are down.", + "title": "Etherscan services are down", + "description": "Some features such as fetching transaction history and transaction details on Ethereum network may not be functioning properly at the moment." + }, "backend": { "statusMessage": "Temporary backend failure.", "title": "Backend failure", diff --git a/src/protocols/ethereum/libs/EtherscanService.ts b/src/protocols/ethereum/libs/EtherscanService.ts index be34b7ad3..c7c1f2b9f 100644 --- a/src/protocols/ethereum/libs/EtherscanService.ts +++ b/src/protocols/ethereum/libs/EtherscanService.ts @@ -1,4 +1,6 @@ +import { ref } from 'vue'; import { fromWei } from 'web3-utils'; + import type { AccountAddress, AssetContractId, ITransaction } from '@/types'; import { ETHERSCAN_API_KEY, PROTOCOLS, TXS_PER_PAGE } from '@/constants'; import { fetchJson, removeObjectUndefinedProperties, sleep } from '@/utils'; @@ -21,6 +23,8 @@ interface EtherscanApiCallParams { let lastCallTime: number; +export const isEtherscanUnavailable = ref(false); + /** * @see docs.etherscan.io */ @@ -28,7 +32,7 @@ export class EtherscanService { apiUrl: string; // TODO - update delay if we use paid API key - freeVersionTimeDelay = ETHERSCAN_API_KEY ? 250 : 5300; + freeVersionTimeDelay = 5300; constructor(apiUrl: string) { this.apiUrl = apiUrl; @@ -40,7 +44,6 @@ export class EtherscanService { apikey: ETHERSCAN_API_KEY, }).toString(); - // Without API key amount of calls are limited to one per every 5 seconds. // With free API key we can make 5 calls per second. // We're adding delays between calls to avoid getting empty results. // TODO: Use own node or paid version @@ -50,8 +53,14 @@ export class EtherscanService { if (timeToWait > 0) { await sleep(timeToWait); } - - return fetchJson(`${this.apiUrl}?${query}`); + try { + const response = await fetchJson(`${this.apiUrl}?${query}`); + isEtherscanUnavailable.value = false; + return response; + } catch (e) { + isEtherscanUnavailable.value = true; + throw e; + } } /**