diff --git a/packages/frontend/src/components/steps/Step2.tsx b/packages/frontend/src/components/steps/Step2.tsx index c62ca04..4e36750 100644 --- a/packages/frontend/src/components/steps/Step2.tsx +++ b/packages/frontend/src/components/steps/Step2.tsx @@ -12,7 +12,6 @@ import { Job } from 'bull' import { ContractTransactionReceipt, ContractTransactionResponse, - EventLog, hexlify, Interface, parseUnits, diff --git a/packages/frontend/src/hooks/useExecutorService.test.ts b/packages/frontend/src/hooks/useExecutorService.test.ts index e009991..3458e4e 100644 --- a/packages/frontend/src/hooks/useExecutorService.test.ts +++ b/packages/frontend/src/hooks/useExecutorService.test.ts @@ -1,4 +1,5 @@ import { renderHook, waitFor } from '@testing-library/react' +import axios from 'axios' import EventSourceMock, { sources } from 'eventsourcemock' import { vi } from 'vitest' @@ -6,7 +7,7 @@ import useExecutorService, { ExecuteDto, TracingOptions, } from './useExecutorService' -import axios from 'axios' +import { ExecuteError, ExecuteProcessorError } from '../types' const validExecuteDtoMock: ExecuteDto = { logIndexes: [], @@ -145,6 +146,10 @@ describe('observeExecutorServiceJob', () => { }) it('should error() when eventsource sends error event', async () => { + const errorMock: ExecuteError = { + type: ExecuteProcessorError.CERTIFICATE_NOT_FOUND, + message: 'message', + } const { result } = renderHook(() => useExecutorService()) await waitFor(() => { @@ -158,13 +163,13 @@ describe('observeExecutorServiceJob', () => { ) observable.subscribe({ error: (error) => { - expect(error).toBe('"any error"') + expect(error).toBe(errorMock.message) }, }) sources[ `${import.meta.env.VITE_EXECUTOR_SERVICE_ENDPOINT}/v1/job/subscribe/1` - ].emitError('any error') + ].emitError({ data: JSON.stringify(errorMock) }) } }) }) diff --git a/packages/frontend/src/hooks/useExecutorService.ts b/packages/frontend/src/hooks/useExecutorService.ts index 17c7201..f70b94a 100644 --- a/packages/frontend/src/hooks/useExecutorService.ts +++ b/packages/frontend/src/hooks/useExecutorService.ts @@ -1,11 +1,19 @@ +import * as ERC20MessagingJSON from '@topos-protocol/topos-smart-contracts/artifacts/contracts/examples/ERC20Messaging.sol/ERC20Messaging.json' +import * as BurnableMintableCappedERC20JSON from '@topos-protocol/topos-smart-contracts/artifacts/contracts/topos-core/BurnableMintableCappedERC20.sol/BurnableMintableCappedERC20.json' import axios from 'axios' import { Job, JobId } from 'bull' +import { OAuthResponse } from 'common' +import { Interface } from 'ethers' import { EventSourcePolyfill } from 'event-source-polyfill' import { useContext, useEffect, useMemo, useState } from 'react' import { Observable } from 'rxjs' -import { OAuthResponse } from 'common' import { ErrorsContext } from '../contexts/errors' +import { + ExecuteError, + ExecuteProcessorError, + ExecuteTransactionError, +} from '../types' export interface ExecuteDto { logIndexes: number[] @@ -106,11 +114,53 @@ export default function useExecutorService() { } } - eventSource.onerror = (error: any) => { - const message = error.data || JSON.stringify(error) - console.error(message) - eventSource.close() - subscriber.error(message) + eventSource.onerror = ({ data }: any) => { + try { + const executeError: ExecuteError = JSON.parse(data) + let { message } = executeError + + if ( + executeError.type === + ExecuteProcessorError.EXECUTE_TRANSACTION_REVERT + ) { + const executeTransactionError: ExecuteTransactionError = + JSON.parse(executeError.message) + + if (!executeTransactionError.decoded) { + const ERC20MessagingInterface = new Interface( + ERC20MessagingJSON.abi + ) + const ERC20Interface = new Interface( + BurnableMintableCappedERC20JSON.abi + ) + + const decodedError = + ERC20MessagingInterface.parseError( + executeTransactionError.data + ) || ERC20Interface.parseError(executeTransactionError.data) + + message = JSON.stringify({ + type: ExecuteProcessorError.EXECUTE_TRANSACTION_REVERT, + message: decodedError?.name, + }) + } else { + message = JSON.stringify({ + type: ExecuteProcessorError.EXECUTE_TRANSACTION_REVERT, + message: executeTransactionError.data, + }) + } + } else { + message = executeError.message + } + + console.error(message) + eventSource.close() + subscriber.error(message) + } catch (error) { + console.error(error) + eventSource.close() + subscriber.error(error) + } } }) } diff --git a/packages/frontend/src/types.ts b/packages/frontend/src/types.ts index c9f31da..03c01e2 100644 --- a/packages/frontend/src/types.ts +++ b/packages/frontend/src/types.ts @@ -21,3 +21,23 @@ export interface FetchData { error?: Error loading?: boolean } + +export enum ExecuteProcessorError { + PROVIDER_INVALID_ENDPOINT = 'PROVIDER_INVALID_ENDPOINT', + CONTRACT_INVALID_ADDRESS = 'CONTRACT_INVALID_ADDRESS', + CONTRACT_INVALID_NO_CODE = 'CONTRACT_INVALID_NO_CODE', + WALLET_INVALID_PRIVATE_KEY = 'WALLET_INVALID_PRIVATE_KEY', + CERTIFICATE_NOT_FOUND = 'CERTIFICATE_NOT_FOUND', + EXECUTE_TRANSACTION_FAILED_INIT = 'EXECUTE_TRANSACTION_FAILED_INIT', + EXECUTE_TRANSACTION_REVERT = 'EXECUTE_TRANSACTION_REVERT', +} + +export interface ExecuteError { + type: ExecuteProcessorError + message: string +} + +export interface ExecuteTransactionError { + decoded?: boolean + data: string +}