diff --git a/src/App.tsx b/src/App.tsx index 0c88c4a..e9555ff 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -15,6 +15,7 @@ import MainScrollManagerProvider from "./hooks/main-scroll-manager"; import EnvsMonitoring from "./components/EnvsMonitoring"; import { ServicesFactory } from "./services/services-factory"; import AnalyticsProvider from "./hooks/analytics/Provider"; +import { LoggerProvider } from "./hooks/logger"; const FONTS_LIST = [ "BebasNeuePro-Regular", @@ -29,6 +30,8 @@ const FONTS_LIST = [ const services = ServicesFactory.init({ env, }); +const logger = services.getLoggerService(); +const vaultClient = services.getVaultClient(); // TODO REFACTOR THIS TO AVOID THIS GLOBAL VARIABLE AND USE A CONTEXT INSTEAD WITH HOOKS TO ACCESS SERVICES const isImpersonated = services.getVaultConfigParser().get()?.vault?.impersonate?.length > 0; @@ -40,61 +43,60 @@ const removeHexadecimalNumbers = (event: Sentry.Event) => { return JSON.parse(eventHexadecimalNumbers); }; -!env.disabledSentry && - Sentry.init({ - dsn: "https://715ab6b127b4455b83e5849bd4c3a5e9@o1362988.ingest.sentry.io/4504838094323712", - integrations: [ - new Sentry.Integrations.Breadcrumbs({ - fetch: false, - xhr: false, - }), - ], - release: env.sentryReleaseName, - ignoreErrors: [ - // Random plugins/extensions - "top.GLOBALS", - // See: http://blog.errorception.com/2012/03/tale-of-unfindable-js-error.html - "originalCreateNotification", - "canvas.contentDocument", - "MyApp_RemoveAllHighlights", - "http://tt.epicplay.com", - "Can't find variable: ZiteReader", - "jigsaw is not defined", - "ComboSearch is not defined", - "http://loading.retry.widdit.com/", - "atomicFindClose", - // Facebook borked - "fb_xd_fragment", - // ISP "optimizing" proxy - `Cache-Control: no-transform` seems to - // reduce this. (thanks @acdha) - // See http://stackoverflow.com/questions/4113268 - "bmi_SafeAddOnload", - "EBCallBackMessageReceived", - // See http://toolbar.conduit.com/Developer/HtmlAndGadget/Methods/JSInjection.aspx - "conduitPage", - ], - denyUrls: [ - // Facebook flakiness - /graph\.facebook\.com/i, - // Facebook blocked - /connect\.facebook\.net\/en_US\/all\.js/i, - // Woopra flakiness - /eatdifferent\.com\.woopra-ns\.com/i, - /static\.woopra\.com\/js\/woopra\.js/i, - // Chrome extensions - /extensions\//i, - /^chrome:\/\//i, - // Other plugins - /127\.0\.0\.1:4001\/isrunning/i, // Cacaoweb - /webappstoolbarba\.texthelp\.com\//i, - /metrics\.itunes\.apple\.com\.edgesuite\.net\//i, - ], - environment: env.name, - tracesSampleRate: 1.0, - beforeSend(event) { - return removeHexadecimalNumbers(event); - }, - }); +Sentry.init({ + dsn: "https://715ab6b127b4455b83e5849bd4c3a5e9@o1362988.ingest.sentry.io/4504838094323712", + integrations: [ + new Sentry.Integrations.Breadcrumbs({ + fetch: false, + xhr: false, + }), + ], + release: env.sentryReleaseName, + ignoreErrors: [ + // Random plugins/extensions + "top.GLOBALS", + // See: http://blog.errorception.com/2012/03/tale-of-unfindable-js-error.html + "originalCreateNotification", + "canvas.contentDocument", + "MyApp_RemoveAllHighlights", + "http://tt.epicplay.com", + "Can't find variable: ZiteReader", + "jigsaw is not defined", + "ComboSearch is not defined", + "http://loading.retry.widdit.com/", + "atomicFindClose", + // Facebook borked + "fb_xd_fragment", + // ISP "optimizing" proxy - `Cache-Control: no-transform` seems to + // reduce this. (thanks @acdha) + // See http://stackoverflow.com/questions/4113268 + "bmi_SafeAddOnload", + "EBCallBackMessageReceived", + // See http://toolbar.conduit.com/Developer/HtmlAndGadget/Methods/JSInjection.aspx + "conduitPage", + ], + denyUrls: [ + // Facebook flakiness + /graph\.facebook\.com/i, + // Facebook blocked + /connect\.facebook\.net\/en_US\/all\.js/i, + // Woopra flakiness + /eatdifferent\.com\.woopra-ns\.com/i, + /static\.woopra\.com\/js\/woopra\.js/i, + // Chrome extensions + /extensions\//i, + /^chrome:\/\//i, + // Other plugins + /127\.0\.0\.1:4001\/isrunning/i, // Cacaoweb + /webappstoolbarba\.texthelp\.com\//i, + /metrics\.itunes\.apple\.com\.edgesuite\.net\//i, + ], + environment: env.name, + tracesSampleRate: 1.0, + beforeSend(event) { + return removeHexadecimalNumbers(event); + }, +}); function App() { useEffect(() => { @@ -112,8 +114,6 @@ function App() { Promise.all(FONTS_LIST.map((font) => loadFonts(font))); }, []); - // services from the factoryService to SismoProvider and vaultProvider - return ( @@ -121,17 +121,19 @@ function App() { - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/src/components/EnvsMonitoring/index.tsx b/src/components/EnvsMonitoring/index.tsx index b2bef5c..7a1ca24 100644 --- a/src/components/EnvsMonitoring/index.tsx +++ b/src/components/EnvsMonitoring/index.tsx @@ -1,10 +1,10 @@ -import * as Sentry from "@sentry/react"; import axios from "axios"; import React, { useEffect } from "react"; import env from "../../environment"; import { useVault } from "../../hooks/vault"; import packageJson from "../../../package.json"; import { getMainMinified } from "../../utils/getMain"; +import { useLogger } from "../../hooks/logger"; const COMMITMENT_MAPPER_PUBKEY = env.sismoDestination.commitmentMapperPubKey; @@ -16,6 +16,7 @@ export default function EnvsMonitoring({ children: React.ReactNode; }): JSX.Element { const vault = useVault(); + const logger = useLogger(); useEffect(() => { const logEnvironment = async () => { @@ -54,7 +55,7 @@ export default function EnvsMonitoring({ if (!vault.importedAccounts) return; if (env.name === "DEMO") return; if (isImpersonated) return; - const test = () => { + const testCommitmentMapper = () => { for (let account of [...vault.importedAccounts]) { if ( COMMITMENT_MAPPER_PUBKEY[0] !== account.commitmentMapperPubKey[0] || @@ -65,13 +66,15 @@ export default function EnvsMonitoring({ )}\nenv pubKey = [${(window as any).env.commitmentMapperPubKey}]\nvault pubKey = [${ account.commitmentMapperPubKey }]`; - console.error(msg); - Sentry.captureMessage(msg); + logger.error({ + error: new Error(msg), + sourceId: "app-EnvsMonitoring-testCommitmentMapper", + }); } } }; - test(); - }, [vault.importedAccounts, isImpersonated]); + testCommitmentMapper(); + }, [vault.importedAccounts, isImpersonated, logger]); return
{children}
; } diff --git a/src/components/Notifications/index.tsx b/src/components/Notifications/index.tsx index 7761906..d6feea3 100644 --- a/src/components/Notifications/index.tsx +++ b/src/components/Notifications/index.tsx @@ -2,18 +2,19 @@ import styled from "styled-components"; import Icon from "../Icon"; import colors from "../../theme/colors"; import { useNotifications } from "./provider"; +import { CircleWavyWarning } from "phosphor-react"; const Container = styled.div` position: fixed; bottom: 60px; right: 60px; - z-index: 4000; + z-index: 40000; `; -const Notification = styled.div<{ backgroundColor: string }>` +const Notification = styled.div<{ backgroundColor: string; withCode: boolean }>` max-width: 290px; min-width: 100px; - padding: 10px 20px; + padding: 10px 25px 10px 10px; background-color: ${(props) => props.backgroundColor}; border-radius: 5px; margin-top: 10px; @@ -22,6 +23,7 @@ const Notification = styled.div<{ backgroundColor: string }>` display: flex; justify-content: flex-start; align-items: flex-start; + gap: 10px; transition: all 0.3s; @@ -35,21 +37,35 @@ const Notification = styled.div<{ backgroundColor: string }>` transform: translate3d(0, 0, 0); } } + ${(props) => + props.withCode && + ` + padding-bottom: 20px; + `} `; const NotificationText = styled.div` font-size: 14px; color: ${(props) => props.color}; - margin-left: 10px; - padding-right: 10px; +`; + +const NotificationCode = styled.div` + position: absolute; + bottom: 5px; + right: 20px; + font-size: 9px; + color: ${(props) => props.color}; `; const Close = styled.div` position: absolute; - right: 12px; + right: 5px; + top: 2px; cursor: pointer; `; +const IconContainer = styled.div``; + export default function Notifications(): JSX.Element { const color = "#13203D"; const { notifications, notificationDeleted } = useNotifications(); @@ -63,13 +79,21 @@ export default function Notifications(): JSX.Element { backgroundColor = colors.error; } return ( - - {notif.type === "success" && ( - - )} + + + {notif.type === "success" && ( + + )} + {notif.type === "error" && } + {notif.text} + {notif.code} notificationDeleted(notif.id)}> - + ); diff --git a/src/components/Notifications/provider/index.tsx b/src/components/Notifications/provider/index.tsx index f25f046..a5b435b 100644 --- a/src/components/Notifications/provider/index.tsx +++ b/src/components/Notifications/provider/index.tsx @@ -9,6 +9,7 @@ export type NotificationsState = { export type Notification = { type: "error" | "info" | "warning" | "success"; text: string; + code?: string; id?: number; }; @@ -49,6 +50,7 @@ export default function NotificationsProvider({ return _notifications; }); }, []); + const notificationDeleted = (id: number) => { setNotifications((currentNotifications) => { const _notifications = [...currentNotifications]; diff --git a/src/hooks/logger/index.tsx b/src/hooks/logger/index.tsx new file mode 100644 index 0000000..1dae8c9 --- /dev/null +++ b/src/hooks/logger/index.tsx @@ -0,0 +1,71 @@ +import React, { useCallback, useContext, useMemo } from "react"; +import { LoggerService } from "../../services/logger-service/logger-service"; +import { ErrorContexts, ErrorType } from "../../services/logger-service/interfaces/logger-provider"; +import { VaultClient } from "../../services/vault-client"; +import { getVaultErrorContext } from "./utils/getVaultErrorContext"; + +interface LoggerContextType { + error: (params: { + error: ErrorType; + sourceId: string; + contexts?: ErrorContexts; + level?: "error" | "fatal"; + }) => Promise; + info: (...msg: any) => void; +} + +export function useLogger(): LoggerContextType { + const context = useContext(LoggerContext); + if (context === null) { + throw new Error("useLogger must be used within a LoggerProvider"); + } + return context; +} + +export const LoggerContext = React.createContext(null); + +export function LoggerProvider({ + children, + logger, + vaultClient, +}: { + children: React.ReactNode; + logger: LoggerService; + vaultClient: VaultClient; +}): JSX.Element { + const error = useCallback( + async ({ + error, + sourceId, + contexts, + level, + }: { + error: ErrorType; + sourceId: string; + contexts?: ErrorContexts; + level?: "error" | "fatal"; + }) => { + const vault = await getVaultErrorContext({ vaultClient }); + const errorId = logger.error({ + error, + sourceId, + level, + contexts: { + ...contexts, + vault, + }, + }); + return errorId; + }, + [logger, vaultClient] + ); + + const value: LoggerContextType = useMemo(() => { + return { + error, + info: logger.info, + }; + }, [error, logger]); + + return {children}; +} diff --git a/src/hooks/logger/utils/getVaultErrorContext.ts b/src/hooks/logger/utils/getVaultErrorContext.ts new file mode 100644 index 0000000..1cdd340 --- /dev/null +++ b/src/hooks/logger/utils/getVaultErrorContext.ts @@ -0,0 +1,37 @@ +import { ErrorContext } from "../../../services/logger-service/interfaces/logger-provider"; +import { VaultClient } from "../../../services/vault-client"; +import { formatDate } from "../../../utils/formatDate"; + +export type VaultErrorContext = {}; + +export const getVaultErrorContext = async ({ + vaultClient, +}: { + vaultClient: VaultClient; +}): Promise => { + const vault = await vaultClient.load(); + if (!vault) + return { + connected: false, + }; + let dataSources = {}; + if (vault.importedAccounts) + for (let account of vault.importedAccounts) { + if (!dataSources[account.type]) { + dataSources[account.type] = 1; + } else { + dataSources[account.type]++; + } + } + return { + dataSources, + owners: vault?.owners?.length, + recoveryKeys: vault?.recoveryKeys?.length, + version: vault?.version, + settings: { + autoImportOwners: vault?.settings?.autoImportOwners, + keepConnected: vault?.settings?.keepConnected, + }, + createdAt: formatDate(new Date(vault.timestamp)), + }; +}; diff --git a/src/hooks/vault/index.tsx b/src/hooks/vault/index.tsx index 0012856..620e5cc 100644 --- a/src/hooks/vault/index.tsx +++ b/src/hooks/vault/index.tsx @@ -9,13 +9,13 @@ import { VaultNamespaceInputs, WalletPurpose, } from "../../services/vault-client"; -import { useVaultState } from "./useVaultState"; import { getVaultV2ConnectedOwner } from "./utils/getVaultV2ConnectedOwner"; import { demoOwner } from "../../services/vault-client/client/demo-client.mock"; import { getVaultV1ConnectedOwner } from "./utils/getVaultV1ConnectedOwner"; import { CommitmentMapper } from "../../services/commitment-mapper"; import { ServicesFactory } from "../../services/services-factory"; import { useNotifications } from "../../components/Notifications/provider"; +import { useVaultState } from "./useVaultState"; type ReactVault = { mnemonics: string[]; @@ -137,6 +137,7 @@ export default function SismoVaultProvider({ }, []); const connect = useCallback(async (owner: Owner): Promise => { + throw new Error("connect"); let vaultV2 = await vaultClient.unlock(owner.seed); let vaultV1 = null; if (env.name !== "DEMO" && vaultSynchronizer) { @@ -199,6 +200,7 @@ export default function SismoVaultProvider({ }; const getVaultSecret = useCallback(async (): Promise => { + throw new Error("getVaultSecret"); return await vaultClient.getVaultSecret(); }, [vaultClient]); diff --git a/src/hooks/vault/useVaultState.tsx b/src/hooks/vault/useVaultState.tsx index 247f50d..e23c53e 100644 --- a/src/hooks/vault/useVaultState.tsx +++ b/src/hooks/vault/useVaultState.tsx @@ -1,8 +1,10 @@ import { useState } from "react"; -import { ImportedAccount, Owner, RecoveryKey, Vault } from "../../services/vault-client"; +import { ImportedAccount, RecoveryKey, Vault, Owner } from "../../services/vault-client"; import { useWallet } from "../wallet"; export type VaultState = { + version: number; + timestamp: number; vaultName: string; autoImportOwners: boolean; keepConnected: boolean; @@ -19,6 +21,8 @@ export type VaultState = { export const useVaultState = (): VaultState => { const wallet = useWallet(); const [vaultName, setVaultName] = useState(null); + const [timestamp, setTimestamp] = useState(null); + const [version, setVersion] = useState(null); const [autoImportOwners, setAutoImportOwners] = useState(null); const [keepConnected, setKeepConnected] = useState(null); const [importedAccounts, setImportedAccounts] = useState(null); @@ -100,6 +104,18 @@ export const useVaultState = (): VaultState => { } }; + const updateTimestamp = async (vault: Vault): Promise => { + if (vault.timestamp !== timestamp) { + setTimestamp(vault.timestamp); + } + }; + + const updateVersion = async (vault: Vault): Promise => { + if (vault.version !== version) { + setVersion(vault.version); + } + }; + const updateVaultState = async (vault: Vault) => { if (!vault) return; if (vault.mnemonics && vault.mnemonics.length === 0) setDeletable(true); @@ -110,6 +126,8 @@ export const useVaultState = (): VaultState => { updateAutoImportOwners(vault), updateRecoveryKeys(vault), updateKeepConnected(vault), + updateTimestamp(vault), + updateVersion(vault), ]); }; @@ -134,6 +152,8 @@ export const useVaultState = (): VaultState => { }; return { + version, + timestamp, vaultName, autoImportOwners, importedAccounts, diff --git a/src/pages/Connect/Flow/DataRequests/components/DataClaimRequest.tsx b/src/pages/Connect/Flow/DataRequests/components/DataClaimRequest.tsx index a4be352..3fb68b0 100644 --- a/src/pages/Connect/Flow/DataRequests/components/DataClaimRequest.tsx +++ b/src/pages/Connect/Flow/DataRequests/components/DataClaimRequest.tsx @@ -118,9 +118,7 @@ export function DataClaimRequest({ const isEligible = claimRequestEligibility?.isEligible && vault?.isConnected; const isSelectableByUser = !proofLoading && claim?.isSelectableByUser; - const isLoading = importAccount?.importing - ? true - : false || loadingEligible || typeof claimRequestEligibility === "undefined"; + const isLoading = importAccount?.importing ? true : false || loadingEligible; function onOptInChange(isOptIn: boolean) { const newSelectedSismoConnectRequest = { diff --git a/src/pages/Connect/Flow/DataRequests/components/DataSourceRequest.tsx b/src/pages/Connect/Flow/DataRequests/components/DataSourceRequest.tsx index 574c44a..7bd328f 100644 --- a/src/pages/Connect/Flow/DataRequests/components/DataSourceRequest.tsx +++ b/src/pages/Connect/Flow/DataRequests/components/DataSourceRequest.tsx @@ -124,9 +124,7 @@ export function DataSourceRequest({ const isOptional = auth?.isOptional; const isEligible = authRequestEligibility?.isEligible && vault?.isConnected; const isSelectableByUser = !proofLoading && auth?.isSelectableByUser; - const isLoading = importAccount?.importing - ? true - : false || loadingEligible || typeof authRequestEligibility === "undefined"; + const isLoading = importAccount?.importing ? true : false || loadingEligible; const isWeb2Impersonating = isImpersonating && diff --git a/src/pages/Connect/Flow/DataRequests/index.tsx b/src/pages/Connect/Flow/DataRequests/index.tsx index 2f849c0..7d91894 100644 --- a/src/pages/Connect/Flow/DataRequests/index.tsx +++ b/src/pages/Connect/Flow/DataRequests/index.tsx @@ -12,11 +12,12 @@ import colors from "../../../../theme/colors"; import { DataSourceRequest } from "./components/DataSourceRequest"; import { useSismo } from "../../../../hooks/sismo"; import { useVault } from "../../../../hooks/vault"; -import * as Sentry from "@sentry/react"; import { ImportedAccount } from "../../../../services/vault-client"; import { getIsEligible } from "../../utils/getIsEligible"; import { DataClaimRequest } from "./components/DataClaimRequest"; import { getAllVaultIdentifiers } from "../../../../utils/getAllVaultIdentifiers"; +import { useLogger } from "../../../../hooks/logger"; +import { useNotifications } from "../../../../components/Notifications/provider"; const Container = styled.div` border: 1px solid ${(props) => props.theme.colors.blue7}; @@ -98,6 +99,9 @@ export default function DataRequests({ const { getClaimRequestEligibilities, getAuthRequestEligibilities } = useSismo(); const { importedAccounts, getVaultSecret } = useVault(); + const { notificationAdded } = useNotifications(); + const logger = useLogger(); + /* ************************************************************* */ /* ********************* SET DEFAULT VALUE ********************* */ /* ************************************************************* */ @@ -232,15 +236,29 @@ export default function DataRequests({ }); onSelectedSismoRequest(_selectedSismoConnectRequest); } - setLoadingEligible(false); - } catch (e) { - console.error(e); - Sentry.captureException(e); + } catch (error) { + const errorId = await logger.error({ + error, + sourceId: "connect-DataRequests-getEligibilities", + level: "fatal", + }); + notificationAdded( + { + type: "error", + text: `An error occurred while testing your eligibility. If this persists, please feel free to contact us on Discord with a screenshot of this message.`, + code: errorId, + }, + 1000000 + ); + } finally { + console.log("finally"); setLoadingEligible(false); } }; getEligibilities(); }, [ + logger, + notificationAdded, importedAccounts, getVaultSecret, getClaimRequestEligibilities, diff --git a/src/pages/Connect/Flow/index.tsx b/src/pages/Connect/Flow/index.tsx index f03545a..c0f0cf2 100644 --- a/src/pages/Connect/Flow/index.tsx +++ b/src/pages/Connect/Flow/index.tsx @@ -3,7 +3,6 @@ import { useCallback, useState } from "react"; import { useVault } from "../../../hooks/vault"; import { useSismo } from "../../../hooks/sismo"; -import * as Sentry from "@sentry/react"; import { ArrowLeft, ArrowSquareOut, Info, Warning } from "phosphor-react"; import { FactoryApp } from "../../../services/sismo-client"; @@ -23,6 +22,8 @@ import { SignatureRequest } from "./components/SignatureRequest"; import SignInButton from "../../../components/SignInButton"; import { useImportAccount } from "../../Modals/ImportAccount/provider"; import { SismoConnectGem } from "../../../components/SismoReactIcon"; +import { useLogger } from "../../../hooks/logger"; +import { useNotifications } from "../../../components/Notifications/provider"; const Container = styled.div` position: relative; @@ -175,7 +176,6 @@ export default function ConnectFlow({ onResponse, }: Props): JSX.Element { const [loadingProof, setLoadingProof] = useState(false); - const [, setErrorProof] = useState(false); const [response, setResponse] = useState(); const [registryTreeRoot, setRegistryTreeRoot] = useState(); const [proofModalOpen, setProofModalOpen] = useState(false); @@ -188,13 +188,15 @@ export default function ConnectFlow({ const { getRegistryTreeRoot, generateResponse } = useSismo(); const vault = useVault(); + const { notificationAdded } = useNotifications(); + const logger = useLogger(); + /* ***************************************************** */ /* ************* GENERATE RESPONSE ********************* */ /* ***************************************************** */ const generate = async () => { setLoadingProof(true); - setErrorProof(false); try { const vaultSecret = await vault.getVaultSecret(); console.time("generateResponse"); @@ -205,7 +207,6 @@ export default function ConnectFlow({ vaultSecret ); console.timeEnd("generateResponse"); - setErrorProof(false); setLoadingProof(false); setResponse(_sismoConnectResponse); @@ -219,13 +220,20 @@ export default function ConnectFlow({ return; } onResponse(_sismoConnectResponse); - } catch (e) { - Sentry.withScope(function (scope) { - scope.setLevel("fatal"); - Sentry.captureException(e); + } catch (error) { + const errorId = await logger.error({ + error, + sourceId: "connect-ConnectFlow-generateResponse", + level: "fatal", }); - console.error(e); - setErrorProof(true); + notificationAdded( + { + type: "error", + text: `An error occurred while generating the proof. If this persists, please feel free to contact us on Discord with a screenshot of this message.`, + code: errorId, + }, + 1000000 + ); } setLoadingProof(false); // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/src/pages/Connect/index.tsx b/src/pages/Connect/index.tsx index a7a7ba8..6a30d48 100644 --- a/src/pages/Connect/index.tsx +++ b/src/pages/Connect/index.tsx @@ -3,7 +3,6 @@ import { useSearchParams } from "react-router-dom"; import styled from "styled-components"; import env from "../../environment"; import WrongUrlScreen from "./components/WrongUrlScreen"; -import * as Sentry from "@sentry/react"; import { FactoryApp } from "../../services/sismo-client"; import { useSismo } from "../../hooks/sismo"; import { getSismoConnectRequest } from "./utils/getSismoConnectRequest"; @@ -25,6 +24,7 @@ import { RequestValidationStatus, validateSismoConnectRequest, } from "./utils/validate-sismo-connect-request"; +import { useLogger } from "../../hooks/logger"; const Container = styled.div` position: relative; @@ -111,6 +111,8 @@ export default function Connect({ isImpersonated }: Props): JSX.Element { const { getGroupMetadata, getFactoryApp, initDevConfig } = useSismo(); + const logger = useLogger(); + /* ********************************************************** */ /* ************************ LOAD IMAGE ********************** */ /* ********************************************************** */ @@ -222,12 +224,14 @@ export default function Connect({ isImpersonated }: Props): JSX.Element { status: true, message: "Invalid appId: " + sismoConnectRequest.appId, }); - Sentry.captureException(e); - console.error(e); + logger.error({ + error: e, + sourceId: "connect-getFactoryAppData", + }); } } getFactoryAppData(); - }, [getFactoryApp, isWrongUrl?.status, sismoConnectRequest]); + }, [getFactoryApp, isWrongUrl?.status, sismoConnectRequest, logger]); /* *********************************************************** */ /* ***************** GET THE REFERRER ************************ */ @@ -284,12 +288,14 @@ export default function Connect({ isImpersonated }: Props): JSX.Element { status: true, message: "Invalid referrer: " + e, }); - console.log(e); - Sentry.captureException(e); + logger.error({ + error: e, + sourceId: "connect-setReferrerInfo", + }); } } setReferrerInfo(); - }, [isWrongUrl?.status, sismoConnectRequest]); + }, [isWrongUrl?.status, sismoConnectRequest, logger]); /* *********************************************************** */ /* ***************** GET THE GROUP METADATA ****************** */ @@ -299,6 +305,7 @@ export default function Connect({ isImpersonated }: Props): JSX.Element { if (!sismoConnectRequest) return; async function getGroupMetadataData() { + console.log("getGroupMetadataData"); if (!sismoConnectRequest?.claims?.length) { setRequestGroupsMetadata(null); return; @@ -319,18 +326,20 @@ export default function Connect({ isImpersonated }: Props): JSX.Element { }); setRequestGroupsMetadata(requestGroupsMetadata); - } catch (e) { + } catch (error) { if (isWrongUrl?.status) return; setIsWrongUrl({ status: true, - message: "Invalid Claim requests: " + e, + message: "Invalid Claim requests: " + error, + }); + logger.error({ + error, + sourceId: "connect-getGroupMetadataData", }); - Sentry.captureException(e); - console.error(e); } } getGroupMetadataData(); - }, [getGroupMetadata, isWrongUrl?.status, sismoConnectRequest]); + }, [getGroupMetadata, isWrongUrl?.status, sismoConnectRequest, logger]); /* *********************************************************** */ /* ***************** ON RESPONSE ***************************** */ diff --git a/src/pages/LoggerTest/index.tsx b/src/pages/LoggerTest/index.tsx new file mode 100644 index 0000000..02e11e9 --- /dev/null +++ b/src/pages/LoggerTest/index.tsx @@ -0,0 +1,90 @@ +import styled from "styled-components"; +import { useLogger } from "../../hooks/logger"; +import Button from "../../components/Button"; +import axios from "axios"; + +const Container = styled.div` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + color: white; +`; + +export default function LoggerTest(): JSX.Element { + const logger = useLogger(); + + return ( + +

Logger Test

+

Info

+ +

Error

+ + + + +
+ ); +} diff --git a/src/pages/Modals/ConnectVaultModal/components/A2_SignStep.tsx b/src/pages/Modals/ConnectVaultModal/components/A2_SignStep.tsx index a5769f2..f51ac52 100644 --- a/src/pages/Modals/ConnectVaultModal/components/A2_SignStep.tsx +++ b/src/pages/Modals/ConnectVaultModal/components/A2_SignStep.tsx @@ -10,7 +10,7 @@ import { useNotifications } from "../../../../components/Notifications/provider" import colors from "../../../../theme/colors"; import Logo, { LogoType } from "../../../../components/Logo"; import { ArrowsLeftRight } from "phosphor-react"; -import * as Sentry from "@sentry/react"; +import { useLogger } from "../../../../hooks/logger"; const Container = styled.div` width: 400px; @@ -89,6 +89,7 @@ export default function SignStep({ const [loading, setLoading] = useState(false); const wallet = useWallet(); const vault = useVault(); + const logger = useLogger(); const { notificationAdded } = useNotifications(); const signToConnect = async () => { @@ -105,7 +106,6 @@ export default function SignStep({ seed, timestamp: Date.now(), }; - const isConnected = await vault.connect(owner); if (isConnected) { onVaultConnected(); @@ -114,13 +114,20 @@ export default function SignStep({ return; } } - } catch (e) { - Sentry.captureException(e); - console.error(e); - notificationAdded({ - text: "En error occurred, please clean your cache and refresh your page.", - type: "error", + } catch (error) { + const errorId = await logger.error({ + error, + sourceId: "ConnectVaultModal-SignStep-signToConnect", + level: "fatal", }); + notificationAdded( + { + text: "An error occurred while connecting to your Vault. If this persists, please feel free to contact us on Discord with a screenshot of this message.", + type: "error", + code: errorId, + }, + 1000000 + ); } onLoading(false); setLoading(false); diff --git a/src/pages/Modals/ConnectVaultModal/components/AccessRecoveryKey.tsx b/src/pages/Modals/ConnectVaultModal/components/AccessRecoveryKey.tsx index bf68f30..3a34584 100644 --- a/src/pages/Modals/ConnectVaultModal/components/AccessRecoveryKey.tsx +++ b/src/pages/Modals/ConnectVaultModal/components/AccessRecoveryKey.tsx @@ -7,7 +7,7 @@ import Button from "../../../../components/Button"; import Icon from "../../../../components/Icon"; import { useNotifications } from "../../../../components/Notifications/provider"; import TextArea from "../../../../components/TextArea"; -import * as Sentry from "@sentry/react"; +import { useLogger } from "../../../../hooks/logger"; const Container = styled.div` width: 330px; @@ -56,6 +56,7 @@ export default function AccessRecoveryKey({ onConnected }: Props): JSX.Element { const [recoveryKey, setRecoveryKey] = useState(""); const [noVaultFound, setNoVaultFound] = useState(null); const vault = useVault(); + const logger = useLogger(); const { notificationAdded } = useNotifications(); const connect = async () => { @@ -73,12 +74,20 @@ export default function AccessRecoveryKey({ onConnected }: Props): JSX.Element { } else { setNoVaultFound(true); } - } catch (e) { - Sentry.captureException(e); - notificationAdded({ - text: "En error occurred, please clean your cache and refresh your page.", - type: "error", + } catch (error) { + const errorId = await logger.error({ + error, + sourceId: "ConnectVaultModal-AccessRecoveryKey-connect", + level: "fatal", }); + notificationAdded( + { + text: "An error occurred while connecting to your Vault. If this persists, please feel free to contact us on Discord with a screenshot of this message.", + type: "error", + code: errorId, + }, + 1000000 + ); } setLoading(false); }; diff --git a/src/pages/Modals/ConnectVaultModal/components/B1_CreateVaultStep.tsx b/src/pages/Modals/ConnectVaultModal/components/B1_CreateVaultStep.tsx index ff1f8e0..d0f1e93 100644 --- a/src/pages/Modals/ConnectVaultModal/components/B1_CreateVaultStep.tsx +++ b/src/pages/Modals/ConnectVaultModal/components/B1_CreateVaultStep.tsx @@ -10,7 +10,7 @@ import { useNotifications } from "../../../../components/Notifications/provider" import { Owner } from "../../../../services/vault-client"; import { CommitmentMapper, Seed } from "../../../../services/sismo-client"; import VaultAccessModal from "./VaultAccessModal"; -import * as Sentry from "@sentry/react"; +import { useLogger } from "../../../../hooks/logger"; const Container = styled.div` width: 400px; @@ -100,6 +100,8 @@ export default function CreateVaultStep({ "idle" | "connecting" | "sign-seed" | "sign-ownership" | "creating-vault" >("idle"); + const logger = useLogger(); + const connectWallet = async () => { onOnboardIsOpen(true); setConnecting(false); @@ -124,6 +126,7 @@ export default function CreateVaultStep({ const signToGenerateSeed = async (identifier: string): Promise => { const _seedSignature = await wallet.sign(Seed.getSeedMsg(identifier)); + if (!_seedSignature) return null; return await Seed.generateSeed(_seedSignature); }; @@ -166,13 +169,12 @@ export default function CreateVaultStep({ }; const addSecureWallet = async (identifier: string) => { + setStatus("sign-seed"); + let seed = null; try { - setStatus("sign-seed"); - let seed = null; - try { - seed = await signToGenerateSeed(identifier); - } catch (e) { - Sentry.captureException(e); + seed = await signToGenerateSeed(identifier); + // If the user reject the signature, we stop the process + if (!seed) { setStatus("idle"); return; } @@ -188,27 +190,30 @@ export default function CreateVaultStep({ } setStatus("sign-ownership"); let ownershipSignature = null; - try { - ownershipSignature = await signToOwnership(identifier); - } catch (e) { - Sentry.captureException(e); + ownershipSignature = await signToOwnership(identifier); + // If the user reject the signature, we stop the process + if (!ownershipSignature) { setStatus("idle"); return; } setStatus("creating-vault"); await create(ownershipSignature, seed, identifier); onCreated(); - } catch (e) { - Sentry.withScope(function (scope) { - scope.setLevel("fatal"); - Sentry.captureException(e); + } catch (error) { + const errorId = await logger.error({ + error, + sourceId: "ConnectVaultModal-CreateVaultStep-addSecureWallet", + level: "fatal", }); - console.error(e); + notificationAdded( + { + text: "An error occurred while creating your Vault. If this persists, please feel free to contact us on Discord with a screenshot of this message.", + type: "error", + code: errorId, + }, + 1000000 + ); setStatus("idle"); - notificationAdded({ - type: "error", - text: "An error occurred, while importing new owner", - }); } }; diff --git a/src/pages/Modals/ConnectVaultModal/components/B2_VaultDetectedStep.tsx b/src/pages/Modals/ConnectVaultModal/components/B2_VaultDetectedStep.tsx index bbf156a..8d61694 100644 --- a/src/pages/Modals/ConnectVaultModal/components/B2_VaultDetectedStep.tsx +++ b/src/pages/Modals/ConnectVaultModal/components/B2_VaultDetectedStep.tsx @@ -8,7 +8,7 @@ import { useVault } from "../../../../hooks/vault"; import { useNotifications } from "../../../../components/Notifications/provider"; import { useEffect, useState } from "react"; import VaultAccessModal from "./VaultAccessModal"; -import * as Sentry from "@sentry/react"; +import { useLogger } from "../../../../hooks/logger"; const Container = styled.div` width: 320px; @@ -89,6 +89,8 @@ export default function VaultDetectedStep({ const { notificationAdded } = useNotifications(); const [isModalOpen, setIsModalOpen] = useState(false); + const logger = useLogger(); + const connect = async () => { try { const owner: Owner = { @@ -103,13 +105,20 @@ export default function VaultDetectedStep({ //Vault must exist, it's tested in the previous step throw new Error(); } - } catch (e) { - Sentry.captureException(e); - console.error(e); - notificationAdded({ - text: "En error occurred, please clean your cache and refresh your page.", - type: "error", + } catch (error) { + const errorId = await logger.error({ + error, + sourceId: "ConnectVaultModal-VaultDetectedStep-connect", + level: "fatal", }); + notificationAdded( + { + text: "An error occurred while connecting to your Vault. If this persists, please feel free to contact us on Discord with a screenshot of this message.", + type: "error", + code: errorId, + }, + 1000000 + ); } }; diff --git a/src/pages/Modals/ConnectVaultModal/index.tsx b/src/pages/Modals/ConnectVaultModal/index.tsx index 2261e1d..cc7fefe 100644 --- a/src/pages/Modals/ConnectVaultModal/index.tsx +++ b/src/pages/Modals/ConnectVaultModal/index.tsx @@ -5,7 +5,6 @@ import AccessOrCreateStep from "./components/0_AccessOrCreateStep"; import SignStep from "./components/A2_SignStep"; import VaultNotFound from "./components/A3_VaultNotFoundStep"; import { useWallet } from "../../../hooks/wallet"; -import * as Sentry from "@sentry/react"; import { useVault } from "../../../hooks/vault"; import CreateVaultStep from "./components/B1_CreateVaultStep"; import ConnectWalletStep from "./components/A1_ConnectStep"; @@ -49,13 +48,8 @@ export default function ConnectVaultModal({ if (wallet && wallet.connected) { try { await wallet.disconnect({ label: wallet.connected.label }); - } catch (e) { - console.error(e); - Sentry.captureException(e, { - extra: { - disconnectWallet: "connectVaultModal", - }, - }); + } catch (error) { + console.error(error); } } onClose(); diff --git a/src/pages/Modals/GenerateRecoveryKey/index.tsx b/src/pages/Modals/GenerateRecoveryKey/index.tsx index aef7010..7c31f6f 100644 --- a/src/pages/Modals/GenerateRecoveryKey/index.tsx +++ b/src/pages/Modals/GenerateRecoveryKey/index.tsx @@ -9,7 +9,7 @@ import { useVault } from "../../../hooks/vault"; import { useNotifications } from "../../../components/Notifications/provider"; import Icon from "../../../components/Icon"; import Loader from "../../../components/Loader"; -import * as Sentry from "@sentry/react"; +import { useLogger } from "../../../hooks/logger"; const Content = styled.div` display: flex; @@ -79,6 +79,7 @@ export default function GenerateRecoveryKeyModal(): JSX.Element { const [loading, setLoading] = useState(null); const vault = useVault(); const { notificationAdded } = useNotifications(); + const logger = useLogger(); useEffect(() => { if (!generateRecoveryKey.isOpen) { @@ -98,16 +99,20 @@ export default function GenerateRecoveryKeyModal(): JSX.Element { _key = await vault.generateRecoveryKey(); setKey(_key); setName(_name); - } catch (e) { - Sentry.withScope(function (scope) { - scope.setLevel("fatal"); - Sentry.captureException(e); - }); - console.log("e", e); - notificationAdded({ - text: "An error occurred while saving your vault, please try again.", - type: "error", + } catch (error) { + const errorId = await logger.error({ + error, + sourceId: "GenerateRecoveryKeyModal-generate", + level: "fatal", }); + notificationAdded( + { + text: "An error occurred while generating your key. If this persists, please feel free to contact us on Discord with a screenshot of this message.", + type: "error", + code: errorId, + }, + 1000000 + ); } finally { setLoading(false); } diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 20764d7..ff760a6 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -12,6 +12,7 @@ import Connect from "./Connect"; import ConnectVaultModal from "./Modals/ConnectVaultModal"; import Home from "./Home"; import { getMockUrl } from "./Connect/mockRequest"; +import LoggerTest from "./LoggerTest"; export default function Pages({ isImpersonated }: { isImpersonated: boolean }): JSX.Element { const vault = useVault(); @@ -68,6 +69,7 @@ export default function Pages({ isImpersonated }: { isImpersonated: boolean }): } /> } /> + } /> {/* } diff --git a/src/services/logger-service/index.ts b/src/services/logger-service/index.ts new file mode 100644 index 0000000..970343a --- /dev/null +++ b/src/services/logger-service/index.ts @@ -0,0 +1 @@ +export * from "./logger-service"; diff --git a/src/services/logger-service/interfaces/logger-provider.ts b/src/services/logger-service/interfaces/logger-provider.ts new file mode 100644 index 0000000..6f83ebb --- /dev/null +++ b/src/services/logger-service/interfaces/logger-provider.ts @@ -0,0 +1,18 @@ +import { AxiosError } from "axios"; + +export type ErrorContext = Record; +export type ErrorContexts = Record; +export type LogErrorParams = { + error: ErrorType; + errorId: string; + sourceId: string; + contexts?: ErrorContexts; + level?: "error" | "fatal"; +}; + +export type ErrorType = Error | AxiosError; + +export interface LoggerProvider { + logInfo(message: string, ...optionalParams: any[]): void; + logError({ error, errorId, sourceId, contexts, level }: LogErrorParams): void; +} diff --git a/src/services/logger-service/logger-service.ts b/src/services/logger-service/logger-service.ts new file mode 100644 index 0000000..096cfca --- /dev/null +++ b/src/services/logger-service/logger-service.ts @@ -0,0 +1,48 @@ +import SHA3 from "sha3"; +import { ErrorContexts, ErrorType, LoggerProvider } from "./interfaces/logger-provider"; + +export class LoggerService { + private _loggerProviders: LoggerProvider[]; + + constructor({ loggerProviders }: { loggerProviders: LoggerProvider[] }) { + this._loggerProviders = loggerProviders; + } + + info(...msg: any): void { + for (const provider of this._loggerProviders) { + provider.logInfo(msg); + } + } + + error({ + error, + sourceId, + contexts, + level, + }: { + error: ErrorType; + sourceId: string; + contexts?: ErrorContexts; + level?: "error" | "fatal"; + }): string { + const timestamp = Date.now(); + let min = 1000000; + let max = 9999999; + let random_number = Math.floor(Math.random() * (max - min + 1)) + min; + + const hash = new SHA3(256); + const sourceHash = hash.update(sourceId).digest("hex"); + + const errorId = `${timestamp}-${random_number}-${sourceHash.slice(-8)}`; + for (const provider of this._loggerProviders) { + provider.logError({ + error, + errorId, + sourceId, + contexts, + level, + }); + } + return errorId; + } +} diff --git a/src/services/logger-service/providers/sentry-logger-provider.ts b/src/services/logger-service/providers/sentry-logger-provider.ts new file mode 100644 index 0000000..1a52b43 --- /dev/null +++ b/src/services/logger-service/providers/sentry-logger-provider.ts @@ -0,0 +1,43 @@ +import * as Sentry from "@sentry/react"; +import { LogErrorParams, LoggerProvider } from "../interfaces/logger-provider"; +import { AxiosError } from "axios"; + +export class SentryLoggerProvider implements LoggerProvider { + logInfo(): void {} + logError({ error, sourceId, errorId, contexts, level }: LogErrorParams): void { + level = level ?? "error"; + if ((error as AxiosError).isAxiosError) { + const sentryError = error as AxiosError; + const { method, url } = sentryError.config; + const { statusText, data } = sentryError.response; + const { status } = sentryError.response; + sentryError.name = `${method.toUpperCase()} ${url} ${status} (${statusText})`; + sentryError.message = JSON.stringify(data); + Sentry.captureException(sentryError, { + level, + contexts: { + ...contexts, + axios: { + code: sentryError.code, + data: sentryError.response?.data, + status: status, + url: url, + }, + }, + tags: { + sourceId, + errorId, + }, + }); + return; + } + Sentry.captureException(error, { + level, + contexts, + tags: { + sourceId, + errorId, + }, + }); + } +} diff --git a/src/services/logger-service/providers/stdout-loger-provider.ts b/src/services/logger-service/providers/stdout-loger-provider.ts new file mode 100644 index 0000000..3361e48 --- /dev/null +++ b/src/services/logger-service/providers/stdout-loger-provider.ts @@ -0,0 +1,14 @@ +import { LogErrorParams, LoggerProvider } from "../interfaces/logger-provider"; + +export class StdOutLoggerProvider implements LoggerProvider { + logInfo(...msg: any): void { + console.info(...msg); + } + logError({ error, errorId, sourceId, level }: LogErrorParams): void { + console.error( + `errorId: ${errorId} / sourceId: ${sourceId} / level: ${level ?? "error"}`, + "\n", + error + ); + } +} diff --git a/src/services/services-factory/index.ts b/src/services/services-factory/index.ts index 2f39e80..63cf059 100644 --- a/src/services/services-factory/index.ts +++ b/src/services/services-factory/index.ts @@ -6,14 +6,17 @@ import { } from "../commitment-mapper"; import { VaultClient as VaultClientV1 } from "../vault-client-v1"; import { VaultClient } from "../vault-client"; -import { AWSStore } from "../../libs/vault-store/aws-store"; -import { MemoryStore } from "../../libs/vault-store/memory-store"; +import { AWSStore } from "../vault-store/aws-store"; +import { MemoryStore } from "../vault-store/memory-store"; import { VaultsSynchronizer } from "../vaults-synchronizer"; import { ImpersonatedVaultCreator } from "../impersonated-vault-creator"; import { AccountResolver } from "../account-resolver"; import { VaultConfigParser } from "../vault-config-parser"; import { SismoConnectProvers } from "../sismo-connect-provers"; import { IndexDbCache } from "../cache-service/indexdb-cache"; +import { LoggerService } from "../logger-service/logger-service"; +import { StdOutLoggerProvider } from "../logger-service/providers/stdout-loger-provider"; +import { SentryLoggerProvider } from "../logger-service/providers/sentry-logger-provider"; // factory service type Configuration = { @@ -26,6 +29,7 @@ type Configuration = { impersonatedVaultCreator: ImpersonatedVaultCreator; accountResolver: AccountResolver; sismoConnectProvers: SismoConnectProvers; + loggerService: LoggerService; }; export class ServicesFactory { @@ -83,6 +87,12 @@ export class ServicesFactory { vaultClientV2: vaultClient, }); + const loggerProviders = [new StdOutLoggerProvider()]; + if (!env.disabledSentry) { + loggerProviders.push(new SentryLoggerProvider()); + } + const loggerService = new LoggerService({ loggerProviders }); + const configuration = { vaultConfigParser: vaultConfigParser, vaultsSynchronizer, @@ -93,11 +103,16 @@ export class ServicesFactory { impersonatedVaultCreator: impersonatedVaultCreator, accountResolver: accountResolver, sismoConnectProvers: sismoConnectProvers, + loggerService: loggerService, }; return new ServicesFactory(configuration); } + public getLoggerService() { + return this._configuration.loggerService; + } + public getSismoConnectProvers() { return this._configuration.sismoConnectProvers; } diff --git a/src/services/vault-client-v1/client/client.test.ts b/src/services/vault-client-v1/client/client.test.ts index c28afde..bc0cf9d 100644 --- a/src/services/vault-client-v1/client/client.test.ts +++ b/src/services/vault-client-v1/client/client.test.ts @@ -1,5 +1,5 @@ import { RecoveryKey, ImportedAccount, Owner, VaultClient } from "."; -import { LocalStore } from "../../../libs/vault-store/local-store"; +import { LocalStore } from "../../vault-store/local-store"; describe("Vault client V1", () => { let vaultClient: VaultClient; diff --git a/src/services/vault-client-v1/client/client.ts b/src/services/vault-client-v1/client/client.ts index 80a8789..b1bc7f4 100644 --- a/src/services/vault-client-v1/client/client.ts +++ b/src/services/vault-client-v1/client/client.ts @@ -8,7 +8,7 @@ import { RecoveryKey, Vault } from "./client.types"; import SHA3 from "sha3"; import { BigNumber } from "ethers"; import { SNARK_FIELD } from "@sismo-core/hydra-s2"; -import { BaseStore } from "../../../libs/vault-store/base-store"; +import { BaseStore } from "../../vault-store/base-store"; export class VaultClient { private _provider: VaultProvider; diff --git a/src/services/vault-client-v1/provider/provider.test.ts b/src/services/vault-client-v1/provider/provider.test.ts index 79e4b9f..fd6bf8e 100644 --- a/src/services/vault-client-v1/provider/provider.test.ts +++ b/src/services/vault-client-v1/provider/provider.test.ts @@ -1,5 +1,5 @@ import { VaultProvider } from "."; -import { LocalStore } from "../../../libs/vault-store/local-store"; +import { LocalStore } from "../../vault-store/local-store"; describe("Vault provider", () => { let provider: VaultProvider; diff --git a/src/services/vault-client-v1/provider/provider.ts b/src/services/vault-client-v1/provider/provider.ts index 3cab92c..31fd982 100644 --- a/src/services/vault-client-v1/provider/provider.ts +++ b/src/services/vault-client-v1/provider/provider.ts @@ -1,6 +1,6 @@ import SHA3 from "sha3"; import CryptoJS from "crypto-js"; -import { BaseStore } from "../../../libs/vault-store/base-store"; +import { BaseStore } from "../../vault-store/base-store"; export class VaultProvider { private store: BaseStore; diff --git a/src/services/vault-client/client/client.test.ts b/src/services/vault-client/client/client.test.ts index c28afde..bc0cf9d 100644 --- a/src/services/vault-client/client/client.test.ts +++ b/src/services/vault-client/client/client.test.ts @@ -1,5 +1,5 @@ import { RecoveryKey, ImportedAccount, Owner, VaultClient } from "."; -import { LocalStore } from "../../../libs/vault-store/local-store"; +import { LocalStore } from "../../vault-store/local-store"; describe("Vault client V1", () => { let vaultClient: VaultClient; diff --git a/src/services/vault-client/client/client.ts b/src/services/vault-client/client/client.ts index ca04898..c37aeda 100644 --- a/src/services/vault-client/client/client.ts +++ b/src/services/vault-client/client/client.ts @@ -3,7 +3,7 @@ import { Seed } from "../../sismo-client"; import migration from "../migration/migration"; import { ImportedAccount } from ".."; import { VaultProvider } from "../provider/provider"; -import { BaseStore } from "../../../libs/vault-store/base-store"; +import { BaseStore } from "../../vault-store/base-store"; import { SismoWallet, WalletPurpose } from "../wallet"; import { RecoveryKey, Vault, VaultNamespaceInputs } from "./client.types"; import SHA3 from "sha3"; @@ -20,7 +20,6 @@ export class VaultClient { constructor(store: BaseStore) { this._provider = new VaultProvider({ store }); } - /*****************************************************************/ /***************************** CREATE ****************************/ /*****************************************************************/ @@ -432,7 +431,7 @@ export class VaultClient { private async _getCurrentVault(): Promise { if (this._unSavedVault) return this._unSavedVault; - if (!this._seed) throw new Error("No vault unlocked"); + if (!this._seed) return null; const currentVault = await this._get(this._seed); if (!currentVault) { this._seed = null; diff --git a/src/services/vault-client/provider/provider.test.ts b/src/services/vault-client/provider/provider.test.ts index 79e4b9f..fd6bf8e 100644 --- a/src/services/vault-client/provider/provider.test.ts +++ b/src/services/vault-client/provider/provider.test.ts @@ -1,5 +1,5 @@ import { VaultProvider } from "."; -import { LocalStore } from "../../../libs/vault-store/local-store"; +import { LocalStore } from "../../vault-store/local-store"; describe("Vault provider", () => { let provider: VaultProvider; diff --git a/src/services/vault-client/provider/provider.ts b/src/services/vault-client/provider/provider.ts index 3cab92c..31fd982 100644 --- a/src/services/vault-client/provider/provider.ts +++ b/src/services/vault-client/provider/provider.ts @@ -1,6 +1,6 @@ import SHA3 from "sha3"; import CryptoJS from "crypto-js"; -import { BaseStore } from "../../../libs/vault-store/base-store"; +import { BaseStore } from "../../vault-store/base-store"; export class VaultProvider { private store: BaseStore; diff --git a/src/libs/vault-store/aws-store.ts b/src/services/vault-store/aws-store.ts similarity index 100% rename from src/libs/vault-store/aws-store.ts rename to src/services/vault-store/aws-store.ts diff --git a/src/libs/vault-store/base-store.ts b/src/services/vault-store/base-store.ts similarity index 100% rename from src/libs/vault-store/base-store.ts rename to src/services/vault-store/base-store.ts diff --git a/src/libs/vault-store/local-store.ts b/src/services/vault-store/local-store.ts similarity index 100% rename from src/libs/vault-store/local-store.ts rename to src/services/vault-store/local-store.ts diff --git a/src/libs/vault-store/memory-store.ts b/src/services/vault-store/memory-store.ts similarity index 100% rename from src/libs/vault-store/memory-store.ts rename to src/services/vault-store/memory-store.ts diff --git a/src/services/vaults-synchronizer/tests/migrate-commitment.test.ts b/src/services/vaults-synchronizer/tests/migrate-commitment.test.ts index 02a3edd..9d796ac 100644 --- a/src/services/vaults-synchronizer/tests/migrate-commitment.test.ts +++ b/src/services/vaults-synchronizer/tests/migrate-commitment.test.ts @@ -1,6 +1,6 @@ import { VaultClient as VaultClientV1 } from "../../vault-client-v1"; import { ImportedAccount, VaultClient as VaultClientV2, WalletPurpose } from "../../vault-client"; -import { LocalStore } from "../../../libs/vault-store/local-store"; +import { LocalStore } from "../../vault-store/local-store"; import { CommitmentMapperTest } from "./commitment-mapper-test"; import { getS1Commitment, getS2Commitment } from "./utils/getCommitments"; import { VaultsSynchronizerTest } from "./vaults-synchronizer-test"; diff --git a/src/services/vaults-synchronizer/tests/vaults-synchronizer-e2e.test.ts b/src/services/vaults-synchronizer/tests/vaults-synchronizer-e2e.test.ts index 986391c..306859f 100644 --- a/src/services/vaults-synchronizer/tests/vaults-synchronizer-e2e.test.ts +++ b/src/services/vaults-synchronizer/tests/vaults-synchronizer-e2e.test.ts @@ -7,7 +7,7 @@ import { VaultClient as VaultClientV1, } from "../../vault-client-v1"; import { VaultClient as VaultClientV2 } from "../../vault-client"; -import { LocalStore } from "../../../libs/vault-store/local-store"; +import { LocalStore } from "../../vault-store/local-store"; import { isAccountInVault } from "../utils/isAccountInVault"; import { isOwnerInVault } from "../utils/isOwnerInVault"; import { isRecoveryKeyInVault } from "../utils/isRecoveryKeyInVault"; diff --git a/src/utils/formatDate.ts b/src/utils/formatDate.ts new file mode 100644 index 0000000..42d2368 --- /dev/null +++ b/src/utils/formatDate.ts @@ -0,0 +1,5 @@ +export const formatDate = (date: Date) => { + return `${date.getFullYear()}-${("0" + (date.getMonth() + 1)).slice(-2)}-${( + "0" + date.getDate() + ).slice(-2)}`; +};