diff --git a/jest.config.ts b/jest.config.ts
index 50060dbd93..ad9b757172 100644
--- a/jest.config.ts
+++ b/jest.config.ts
@@ -3,6 +3,8 @@
* https://jestjs.io/docs/configuration
*/
+import process from "process";
+
import type { Config } from "jest";
const config: Config = {
@@ -19,7 +21,7 @@ const config: Config = {
clearMocks: true,
// Indicates whether the coverage information should be collected while executing the test
- collectCoverage: true,
+ collectCoverage: process.env.DEV !== "true",
// An array of glob patterns indicating a set of files for which coverage information should be collected
// collectCoverageFrom: undefined,
diff --git a/package.json b/package.json
index 14d72fd409..7a5818a70a 100644
--- a/package.json
+++ b/package.json
@@ -18,7 +18,7 @@
"preview": "vite preview",
"electron:package:linux": "electron-builder -l",
"electron:package:mac": "electron-builder -m",
- "electron:package:mac:debug": "yarn electron:package:mac -c electron-builder.dev.yml",
+ "electron:package:mac:debug": "DEBUG=true yarn build && sed -i='' 's@devTools: false@devTools: true@g' build/electron.js && yarn electron:package:mac -c electron-builder.dev.yml && rm -rf build",
"electron:package:win": "electron-builder -w",
"electron:start": "electronmon .",
"docs": "typedoc --tsconfig tsconfig.e2e.json",
@@ -27,7 +27,7 @@
"lint:ci": "eslint src --ext .js,.jsx,.ts,.tsx --max-warnings=0",
"lint": "eslint src --ext .js,.jsx,.ts,.tsx --fix",
"test": "cross-env TZ=CET jest",
- "test:watch": "yarn test --watch",
+ "test:watch": "cross-env DEV=true yarn test --watch",
"test:e2e": "cross-env TS_NODE_PROJECT=tsconfig.e2e.json cucumber-js",
"test:e2e:focus": "yarn test:e2e --tags='@focus'",
"theme:watch": "chakra-cli tokens src/style/theme.ts --watch",
@@ -68,7 +68,7 @@
"@testing-library/jest-dom": "6.4.5",
"@testing-library/react": "14.3.0",
"@testing-library/user-event": "14.5.2",
- "@toruslabs/customauth": "^15.0.5",
+ "@toruslabs/customauth": "^16.0.6",
"@types/babel__core": "^7",
"@types/babel__preset-env": "^7",
"@types/identity-obj-proxy": "^3",
diff --git a/src/GoogleAuth/GoogleAuth.test.tsx b/src/GoogleAuth/GoogleAuth.test.tsx
deleted file mode 100644
index 50db0a5ecf..0000000000
--- a/src/GoogleAuth/GoogleAuth.test.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { getGoogleCredentials } from "./getGoogleCredentials";
-import { GoogleAuth } from "./GoogleAuth";
-import { act, render, screen, userEvent } from "../mocks/testUtils";
-import { mockToast } from "../mocks/toast";
-
-jest.mock("./getGoogleCredentials");
-
-describe("", () => {
- it("calls the onAuth callback with the secret key and email", async () => {
- const user = userEvent.setup();
- const authSpy = jest.fn();
- jest.mocked(getGoogleCredentials).mockResolvedValue({
- secretKey: "test",
- email: "test@email.com",
- });
- render();
-
- await act(() => user.click(screen.getByTestId("google-auth-button")));
-
- expect(authSpy).toHaveBeenCalledWith("test", "test@email.com");
- });
-
- it("shows an error toast if the auth fails", async () => {
- const user = userEvent.setup();
- const authSpy = jest.fn();
- jest.mocked(getGoogleCredentials).mockRejectedValue(new Error("test"));
- render();
-
- await act(() => user.click(screen.getByTestId("google-auth-button")));
-
- expect(mockToast).toHaveBeenCalledWith({
- description: "test",
- status: "error",
- title: "Social login failed",
- });
-
- expect(authSpy).not.toHaveBeenCalled();
- });
-});
diff --git a/src/GoogleAuth/GoogleAuth.tsx b/src/GoogleAuth/GoogleAuth.tsx
deleted file mode 100644
index 5ec62e9c35..0000000000
--- a/src/GoogleAuth/GoogleAuth.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import { IconButton } from "@chakra-ui/react";
-
-import { getGoogleCredentials } from "./getGoogleCredentials";
-import { GoogleIcon } from "../assets/icons";
-import colors from "../style/colors";
-import { useAsyncActionHandler } from "../utils/hooks/useAsyncActionHandler";
-
-/**
- * Component that's used for onboarding users with Google SSO.
- * It's used on the onboarding page.
- * It opens a popup window with Google SSO on a click.
- *
- * @param onAuth - callback function which is called with the secret key and email of the user
- * on a successful authentication
- */
-export const GoogleAuth: React.FC<{ onAuth: (secretKey: string, email: string) => void }> = ({
- onAuth,
-}) => {
- const { isLoading, handleAsyncAction } = useAsyncActionHandler();
-
- const onClick = async () =>
- handleAsyncAction(
- async () => {
- const { secretKey, email } = await getGoogleCredentials();
- return onAuth(secretKey, email);
- },
- {
- title: "Social login failed",
- }
- );
-
- return (
- }
- isLoading={isLoading}
- onClick={onClick}
- size="lg"
- variant="outline"
- />
- );
-};
diff --git a/src/GoogleAuth/getGoogleCredentials.ts b/src/GoogleAuth/getGoogleCredentials.ts
deleted file mode 100644
index 46d6c5dedd..0000000000
--- a/src/GoogleAuth/getGoogleCredentials.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import { Prefix, b58cencode, prefix } from "@taquito/utils";
-import CustomAuth from "@toruslabs/customauth";
-
-import { withTimeout } from "../utils/withTimeout";
-
-const LOGIN_TIMEOUT = 60 * 1000; // 1 minute
-const WEB3_AUTH_CLIENT_ID =
- "BBQoFIabI50S1-0QsGHGTM4qID_FDjja0ZxIxKPyFqc0El--M-EG0c2giaBYVTVVE6RC9WCUzCJyW24aJrR_Lzc";
-const SUB_VERIFIER_CLIENT_ID =
- "1070572364808-d31nlkneam5ee6dr0tu28fjjbsdkfta5.apps.googleusercontent.com";
-
-/**
- * This function will open a popup window with the google auth page.
- * Once the user authorizes the function will navigate the user back to Umami app.
- * In the end we obtain the user's email and raw secret key.
- *
- * The function has a timeout to prevent infinite loading state.
- */
-export const getGoogleCredentials = async () =>
- withTimeout(async () => {
- const torus = new CustomAuth({
- web3AuthClientId: WEB3_AUTH_CLIENT_ID,
- baseUrl: "https://umamiwallet.com/auth/v2.0.1/",
- redirectPathName: "redirect.html",
- redirectToOpener: true,
- uxMode: "popup",
- network: "mainnet",
- });
- await torus.init({ skipSw: true });
-
- const result = await torus.triggerAggregateLogin({
- verifierIdentifier: "tezos-google",
- aggregateVerifierType: "single_id_verifier",
- subVerifierDetailsArray: [
- {
- clientId: SUB_VERIFIER_CLIENT_ID,
- typeOfLogin: "google",
- verifier: "umami",
- },
- ],
- });
- const privateKey = result.finalKeyData.privKey || result.oAuthKeyData.privKey;
- const secretKey = b58cencode(privateKey, prefix[Prefix.SPSK]);
-
- return {
- secretKey,
- email: result.userInfo[0].email,
- };
- }, LOGIN_TIMEOUT);
diff --git a/src/GoogleAuth/index.tsx b/src/GoogleAuth/index.tsx
deleted file mode 100644
index 4ce5431bb3..0000000000
--- a/src/GoogleAuth/index.tsx
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from "./GoogleAuth";
-export * from "./parseTorusRedirectParams";
-export * from "./getGoogleCredentials";
diff --git a/src/GoogleAuth/parseTorusRedirectParams.test.ts b/src/GoogleAuth/parseTorusRedirectParams.test.ts
deleted file mode 100644
index 291a7209be..0000000000
--- a/src/GoogleAuth/parseTorusRedirectParams.test.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { parseTorusRedirectParams } from "./parseTorusRedirectParams";
-
-// we get URL params in a compressed format generated by zipurl
-const googleAuthDeeplink =
- "umami://auth/H4sIAAAAAAAAA51VSY-zyBL8NV_f3ILCuM2hD2AWY1Ngs1OXFptZXAXYgFl-_QNP683oSXN5EqhQQWZlREYkRfHdU_txGuu56h8fcR5WVYq_n2lSPNO4-_nd-PnnR233nU6nJqp0KvDYEjn4rpZ1kdj8Nj3ibcQ0feJLhXY4AeSfGkQwjgt1p1ZuF3h0oxZDkRzxgByO2ApXhd62MIpTFQGuihRnjZuQZzYxcctENl82I-CIuJNaNlRcufh2_QNYwDLi7_IRdt9TCLjPkOJvwk808QeJCaaKvdoDOTz0Pe-r5xxTkg3QELMQCSMhcpOAjXzWaCHTmK9oCuyWUOdn6bjRrWA942Ezmzl7HISzEXDZGGn8cxCC-YZ9Y-Sn1OY4ykmUyN_iY6bMG-sJ2WvKP8wvlqcOznC2xk68lJtrhINrj81g1F6PVLWH8JAFZ96PLd5ULfl6VHwAC-umZkpTeUnc-hteq3OluMCBonfcR1p8MyzHfbTxd0rCAq-YqeZZ3wqcvp_rJq2K5P2Yd13T_mH4P0BermEYPrO6znAaNkX7Gddk2Qz7Ll-Wvk2fRXWrP__O-X8E_5bxUbz1kEdKvPbRcmaV1gu1VUnXoMPS91ImuigQqEhb5AUzErMtFO-MoZilIZ4ILN0SguWel7bNKNc9lTHEt36o1OfXnGeXvha36-cqu5iB61adHM0hnuuXBuQyABwdVeaskeQVgaRFFltGgFpT5Gm1plBHKMaDbscTnAPKEPmt5l1n6LFtCFgceBSNPAegozokR2cyFPQIyWlGSkcSRaI1Ig_xEfYIcC8ERpz4Oo6J_lrOxFF17Zfzu1XWge--rQBtnoGiw8AFmC5mg3Gg73CW-0jpeuTJne65WCfmBI8mDcuchKQpYmA-UWXmusXm8VH4G4vvzouNFjwshTyW0tZzrYXeSqeD1ValNCx0Ubq9nCdCAMUFnx1TsMwWptY25H_Z87hYVrn3ieKW4WHdX-2I2_VdDNwJAZfVlpatPCJv5P_te59BC3ZMQm_F-pclV54TmasDX6_XfI6n323APlLf3OqiXJm2SfRKf1lEppy1dsK-IqLjfxkbfUCCwiillcNZFwNm4XCNySPPWXtvL3xUyL9nFsB9ctRxtNZXCU3AmHRMnP_Rx1jDif0dLy69Yl36teLqk8NbJ6_A4oQriLcR0E_IQ5fI6VST1ptYQVV0x0pKTAdKuWrZCUgkdAglWU_tnLVmtI0xEjzP4eL5DjQPrvVXoY9whLl-GXdvjM4vv6tGEJG70BtZH_wXjxYufV3qatf3kcKVgTe-45C37UxKXXM2gX_9ByeLlt-cuNt4sRi0V21D-t37w1CEldms8cHMjwFxaF1MiGEv6xzTAYAUBOoMy8Wmdl7qM08bdlIE9tsjyzg6cZ9od94AxTneOj0QJ7MxzmdTGtHliTfb-8stwq87Omwa4Uc3klhEPw81DUb_Pu7I-W5Rzy32TiE851Dtg2SbZWluxRk2-ebr1Zqplmh7y27Vn6-dsG-S8HLazwJ57GN8TjmQXSl3o4YFk1wT2RkPD1JIynysqUIQdiBMVam7tKWYzUIapjo4uTaz6OVmBrg8VmehlmTuVOgJYiYoTAk9ieBQ9j61P1_IT7vvzsMk9Lv55YhfyebpnS8_nHjFvRb1lTen6eNySc4pNSpNtB11W6ppVxOaQpTy0Xi9DJ4NXLO1UnbsIWfxCneRuP12mXKeaZS7o4FHK6y-5K_4JsUd5I9q-sj7QKd2e0_js4_wm_povuO6atOq-3gV3wcy3hwanXzKPZnM8q8D2NQlrJtSItgevkJRPjjYtSy3aQ0_hy5zHRzQjpGMPbcyrcgJpnV4QbcJXJJ7kBEMh3ZDSMzWcDjDJWPoePfRdNXBwUnputJoY1SmivlYhtEdVsIc3PPacXEfys09off_AYBvCkASCAAA";
-
-test("parseTorusRedirectParams", () => {
- expect(parseTorusRedirectParams(googleAuthDeeplink)).toEqual({
- channel: "redirect_channel_u08xyxoznuq",
- data: {
- hashParams: {
- access_token:
- "ya29.a0AfB_byACE3Yyn5QTwmCqN8AXIKhl0ET2Zwc5MZBxmmFpd2-FKL1BgL37byYTsm0KrjUVbfi5WOqT3-zgqCBKOY9gxbLArwBYzflXOxAyeT990UdGbX4lHgGz-SrM5QeAqR75A0CUwKSxtDPj-QblYQulRYxLvqeITwaCgYKAXcSARISFQHGX2MiSfIgGpnWdcsX-ALohGiPMw0169",
- authuser: "0",
- expires_in: "3599",
- hd: "trili.tech",
- id_token:
- "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFmNDBmMGE4ZWYzZDg4MDk3OGRjODJmMjVjM2VjMzE3YzZhNWI3ODEiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIxMDcwNTcyMzY0ODA4LWQzMW5sa25lYW01ZWU2ZHIwdHUyOGZqamJzZGtmdGE1LmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiYXVkIjoiMTA3MDU3MjM2NDgwOC1kMzFubGtuZWFtNWVlNmRyMHR1Mjhmampic2RrZnRhNS5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsInN1YiI6IjEwODE0NTU3MDM2MDY0OTc0Mjg3MiIsImhkIjoidHJpbGkudGVjaCIsImVtYWlsIjoic2VyZ2V5LmtpbnRzZWxAdHJpbGkudGVjaCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJhdF9oYXNoIjoiUWNkT25qeXR4NDFnRTRmNnNvSmF0USIsIm5vbmNlIjoidTA4eHl4b3pudXEiLCJuYmYiOjE3MDUzNDY3NDgsIm5hbWUiOiJTZXJnZXkgS2ludHNlbCIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS9BQ2c4b2NJZWZPbUtIR1NpcGZnbklGemRUMEhISTd2dEZCaEFNeTh5SzZ4clZBWWU9czk2LWMiLCJnaXZlbl9uYW1lIjoiU2VyZ2V5IiwiZmFtaWx5X25hbWUiOiJLaW50c2VsIiwibG9jYWxlIjoiZW4tR0IiLCJpYXQiOjE3MDUzNDcwNDgsImV4cCI6MTcwNTM1MDY0OCwianRpIjoiYzAxYmU1NDdmOTU1Nzc1Y2M0M2IzMjI1NThjNzA1OTdiYTIxMDc2MiJ9.Z6K-2GUHftNYDyRpOKKRExZPrl-4kvVia7kZC-pB_NOdcDZ_qIeYxXkx6mKkS0r4lWJaMKhMIuYd4ggehScglRAp7vsReLdL8STsI_76B8pdaPJ8zBmq8clKe92gQ0V-Iai3dQdFUxCqmiEGzHo0iBB62aeIEtPsjDgzBeaeN2JVT3uYmfRYljHnKBoEF9JiNdZ3yMByd1yD2CjuX08KPm_s8tKwyBu6zvUD7d-rWKP_9DQluLbunWzeeqPPdKe0xGpb4xNTEo1VLBpiDEhxOvvOA5YVRsSe5xuM9SAG9PE984ZCIWROj6HOlxSan7F7cfEctMAHIeqhuYN068WLAg",
- prompt: "consent",
- scope:
- "email%20profile%20openid%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/userinfo.profile",
- state:
- "eyJpbnN0YW5jZUlkIjoidTA4eHl4b3pudXEiLCJ2ZXJpZmllciI6InVtYW1pIiwidHlwZU9mTG9naW4iOiJnb29nbGUiLCJyZWRpcmVjdFRvT3BlbmVyIjp0cnVlfQ%253D%253D",
- token_type: "Bearer",
- },
- instanceParams: {
- instanceId: "u08xyxoznuq",
- redirectToOpener: "true",
- typeOfLogin: "google",
- verifier: "umami",
- },
- },
- error: null,
- });
-});
diff --git a/src/GoogleAuth/parseTorusRedirectParams.ts b/src/GoogleAuth/parseTorusRedirectParams.ts
deleted file mode 100644
index ba2d50d2e4..0000000000
--- a/src/GoogleAuth/parseTorusRedirectParams.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * This function parses the deeplink url we get on a successful social auth.
- *
- * The parameters are built by
- * https://github.com/trilitech/umami-web/blob/main/public/auth/v2.x/redirect.html
- *
- * which is essentially a copy of
- * https://github.com/torusresearch/CustomAuth/blob/master/serviceworker/redirect.html
- */
-
-import { invert } from "lodash";
-import { unzipurl } from "zipurl";
-
-/**
- * these search params are used to reduce the size of the URL
- * which has a limit in some browsers set to 2k characters
- */
-const PARAMS_MAPPING = {
- at: "access_token",
- a: "authuser",
- ei: "expires_in",
- it: "id_token",
- ii: "instanceId",
- p: "prompt",
- sc: "scope",
- st: "state",
- vi: "version_info",
-};
-
-const PARAMS_REVERSE_MAPPING = invert(PARAMS_MAPPING);
-
-export const parseTorusRedirectParams = (url: string) => {
- const params = new URLSearchParams(unzipurl(url.replace("umami://auth/", "")));
-
- const assignValues = (acc: any, key: string) => {
- acc[key] = params.get(PARAMS_REVERSE_MAPPING[key]) ?? params.get(key);
- return acc;
- };
-
- const instanceParams = {
- verifier: "umami",
- redirectToOpener: "true",
- typeOfLogin: "google",
- ...assignValues({}, "instanceId"),
- };
-
- const hashParams = {
- hd: "trili.tech",
- token_type: "Bearer",
- ...["state", "access_token", "expires_in", "scope", "id_token", "authuser", "prompt"].reduce(
- assignValues,
- {}
- ),
- };
-
- return {
- channel: `redirect_channel_${instanceParams.instanceId}`,
- data: { instanceParams, hashParams },
- ...assignValues({}, "error"),
- };
-};
diff --git a/src/WelcomeScreen.tsx b/src/WelcomeScreen.tsx
index 46cee8b112..7d63a4dfa4 100644
--- a/src/WelcomeScreen.tsx
+++ b/src/WelcomeScreen.tsx
@@ -44,7 +44,7 @@ const SliderItems: Item[] = [
>
),
- icon: ,
+ icon: ,
image: MultisigImage,
},
{
diff --git a/src/assets/icons/Email.tsx b/src/assets/icons/Email.tsx
new file mode 100644
index 0000000000..b6102137d8
--- /dev/null
+++ b/src/assets/icons/Email.tsx
@@ -0,0 +1,20 @@
+import { Icon, IconProps } from "@chakra-ui/react";
+
+export const EmailIcon: React.FC = props => (
+
+
+
+);
diff --git a/src/assets/icons/Facebook.tsx b/src/assets/icons/Facebook.tsx
new file mode 100644
index 0000000000..59488be2ff
--- /dev/null
+++ b/src/assets/icons/Facebook.tsx
@@ -0,0 +1,26 @@
+import { Icon, IconProps } from "@chakra-ui/react";
+
+export const FacebookIcon: React.FC = props => (
+
+
+
+
+);
diff --git a/src/assets/icons/Google.tsx b/src/assets/icons/Google.tsx
index 5237ceb528..ed39fdfba3 100644
--- a/src/assets/icons/Google.tsx
+++ b/src/assets/icons/Google.tsx
@@ -5,6 +5,7 @@ export const GoogleIcon: React.FC = props => (
width="24px"
height="24px"
fill="none"
+ data-testid="google-icon"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
{...props}
diff --git a/src/assets/icons/Key.tsx b/src/assets/icons/Key.tsx
index ff1cb0c78d..9c605a8235 100644
--- a/src/assets/icons/Key.tsx
+++ b/src/assets/icons/Key.tsx
@@ -1,10 +1,13 @@
import { Icon, IconProps } from "@chakra-ui/react";
+import colors from "../../style/colors";
+
export const KeyIcon: React.FC = props => (
= props => (
+
+
+
+
+);
diff --git a/src/assets/icons/Social.tsx b/src/assets/icons/Social.tsx
deleted file mode 100644
index e81c525bd2..0000000000
--- a/src/assets/icons/Social.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { Icon, IconProps } from "@chakra-ui/react";
-
-export const SocialIcon = (props: IconProps) => (
-
-
-
-
-
-
-
-
-
-
-
-
-);
diff --git a/src/assets/icons/Twitter.tsx b/src/assets/icons/Twitter.tsx
new file mode 100644
index 0000000000..6ed823cfb6
--- /dev/null
+++ b/src/assets/icons/Twitter.tsx
@@ -0,0 +1,15 @@
+import { Icon, IconProps } from "@chakra-ui/react";
+
+export const TwitterIcon: React.FC = props => (
+
+
+
+);
diff --git a/src/assets/icons/index.tsx b/src/assets/icons/index.tsx
index 18c159f757..4f497c6f4a 100644
--- a/src/assets/icons/index.tsx
+++ b/src/assets/icons/index.tsx
@@ -18,6 +18,7 @@ export * from "./Document";
export * from "./DoubleCheckmark";
export * from "./Download";
export * from "./EditAccount";
+export * from "./Email";
export * from "./Exclamation";
export * from "./ExitArrow";
export * from "./ExternalLink";
@@ -25,6 +26,7 @@ export * from "./Eye";
export * from "./EyeSlash";
export * from "./FA1.2";
export * from "./FA2";
+export * from "./Facebook";
export * from "./Feedback";
export * from "./Fetching";
export * from "./FileArrowDown";
@@ -47,16 +49,17 @@ export * from "./OutgoingArrow";
export * from "./OutlineExclamationCircle";
export * from "./Pen";
export * from "./Plus";
+export * from "./Reddit";
export * from "./RefreshClock";
export * from "./Reload";
export * from "./Rotate";
export * from "./Slash";
export * from "./Sliders";
-export * from "./Social";
export * from "./Tez";
export * from "./ThreeDots";
export * from "./Token";
export * from "./Trash";
+export * from "./Twitter";
export * from "./UnknownContact";
export * from "./USB";
export * from "./Verified";
diff --git a/src/auth/Auth.test.ts b/src/auth/Auth.test.ts
new file mode 100644
index 0000000000..f1a4a16d9d
--- /dev/null
+++ b/src/auth/Auth.test.ts
@@ -0,0 +1,96 @@
+import { TorusAggregateLoginResponse, TorusLoginResponse } from "@toruslabs/customauth";
+
+import { Auth } from "./Auth";
+import { EmailAuth } from "./EmailAuth";
+import { FacebookAuth } from "./FacebookAuth";
+import { GoogleAuth } from "./GoogleAuth";
+import { RedditAuth } from "./RedditAuth";
+import { TwitterAuth } from "./TwitterAuth";
+
+const rawSecretKey = "ad02df00ce58f9e3e1ff882661edbfa4e5a31b9ebceaa4e3e1fe810fb2ba38f2";
+const secretKey = "spsk2jm29sHC99HDi64VBpSwEMZRQ7WfHdvQPVMZCkyWyR4spBrtRW";
+
+describe("Auth", () => {
+ const testCases = [
+ {
+ finalKey: rawSecretKey,
+ oAuthKey: rawSecretKey,
+ email: "some email",
+ name: "some name",
+ resultKey: secretKey,
+ resultName: "some email",
+ },
+ {
+ finalKey: rawSecretKey,
+ oAuthKey: rawSecretKey,
+ email: undefined,
+ name: "some name",
+ resultKey: secretKey,
+ resultName: "some name",
+ },
+ {
+ finalKey: rawSecretKey,
+ oAuthKey: rawSecretKey,
+ email: undefined,
+ name: undefined,
+ resultKey: secretKey,
+ resultName: (p: Auth) => p.idpName,
+ },
+ {
+ finalKey: rawSecretKey,
+ oAuthKey: rawSecretKey + "some extra",
+ email: undefined,
+ name: undefined,
+ resultKey: secretKey,
+ resultName: (p: Auth) => p.idpName,
+ },
+ {
+ finalKey: undefined,
+ oAuthKey: rawSecretKey,
+ email: "some email",
+ name: "some name",
+ resultKey: secretKey,
+ resultName: "some email",
+ },
+ ];
+
+ describe.each(testCases)(
+ "for $finalKey, $oAuthKey, $email, $name",
+ ({ finalKey, oAuthKey, email, name, resultKey, resultName }) => {
+ it.each([GoogleAuth, EmailAuth, RedditAuth])(
+ "handles aggregated login for %p",
+ async Provider => {
+ const provider = new Provider();
+ jest.spyOn(provider, "login").mockImplementation(() =>
+ Promise.resolve({
+ finalKeyData: { privKey: finalKey },
+ oAuthKeyData: { privKey: oAuthKey },
+ userInfo: [{ email, name }],
+ } as TorusAggregateLoginResponse)
+ );
+
+ await expect(provider.getCredentials()).resolves.toEqual({
+ secretKey: resultKey,
+ name: typeof resultName === "function" ? resultName(provider) : resultName,
+ });
+ }
+ );
+
+ it.each([FacebookAuth, TwitterAuth])("handles login for %p", async Provider => {
+ const provider = new Provider();
+ jest.spyOn(provider, "login").mockImplementation(() =>
+ Promise.resolve({
+ finalKeyData: { privKey: finalKey },
+ oAuthKeyData: { privKey: oAuthKey },
+ userInfo: { email, name },
+ } as TorusLoginResponse)
+ );
+
+ await expect(provider.getCredentials()).resolves.toEqual({
+ secretKey: resultKey,
+ name: typeof resultName === "function" ? resultName(provider) : resultName,
+ });
+ });
+ }
+ );
+});
diff --git a/src/auth/Auth.ts b/src/auth/Auth.ts
new file mode 100644
index 0000000000..00a93d7251
--- /dev/null
+++ b/src/auth/Auth.ts
@@ -0,0 +1,51 @@
+import { b58cencode, prefix } from "@taquito/utils";
+import CustomAuth, { TorusAggregateLoginResponse, TorusLoginResponse } from "@toruslabs/customauth";
+
+import { IDP } from "./types";
+
+const WEB3_AUTH_CLIENT_ID =
+ "BBQoFIabI50S1-0QsGHGTM4qID_FDjja0ZxIxKPyFqc0El--M-EG0c2giaBYVTVVE6RC9WCUzCJyW24aJrR_Lzc";
+
+/**
+ * Abstract class that's responsible for the social auth process
+ *
+ * the details are defined in the subclasses.
+ */
+export abstract class Auth {
+ abstract idpName: IDP;
+ abstract clientId: string;
+
+ protected async getTorusClient(): Promise {
+ const torus = new CustomAuth({
+ web3AuthClientId: WEB3_AUTH_CLIENT_ID,
+ baseUrl: "https://umamiwallet.com/auth/v2.2.0/",
+ redirectPathName: "redirect.html",
+ redirectToOpener: true,
+ uxMode: "popup",
+ network: "mainnet",
+ });
+
+ await torus.init({ skipSw: true });
+
+ return torus;
+ }
+
+ abstract login(): Promise;
+
+ async getCredentials(): Promise<{
+ secretKey: string;
+ name: string;
+ }> {
+ const loginResult = await this.login();
+ const privateKey = loginResult.finalKeyData.privKey || loginResult.oAuthKeyData.privKey;
+ const secretKey = b58cencode(privateKey, prefix.spsk);
+
+ const userInfo = Array.isArray(loginResult.userInfo)
+ ? loginResult.userInfo[0]
+ : loginResult.userInfo;
+
+ const accountName = userInfo.email || userInfo.name || this.idpName;
+
+ return { secretKey, name: accountName };
+ }
+}
diff --git a/src/auth/EmailAuth.ts b/src/auth/EmailAuth.ts
new file mode 100644
index 0000000000..2553c41a31
--- /dev/null
+++ b/src/auth/EmailAuth.ts
@@ -0,0 +1,29 @@
+import { Auth } from "./Auth";
+import { JWT_AUTH_DOMAIN } from "./constants";
+import type { IDP } from "./types";
+
+export class EmailAuth extends Auth {
+ clientId = "LTg6fVsacafGmhv14TZlrWF1EavwQoDZ";
+ idpName: IDP = "email";
+
+ override async login() {
+ const client = await this.getTorusClient();
+
+ return client.triggerAggregateLogin({
+ verifierIdentifier: "tezos-google",
+ aggregateVerifierType: "single_id_verifier",
+ subVerifierDetailsArray: [
+ {
+ verifier: "web-kukai-email",
+ typeOfLogin: "jwt",
+ clientId: this.clientId,
+ jwtParams: {
+ connection: "",
+ verifierIdField: "name",
+ domain: JWT_AUTH_DOMAIN,
+ },
+ },
+ ],
+ });
+ }
+}
diff --git a/src/auth/FacebookAuth.ts b/src/auth/FacebookAuth.ts
new file mode 100644
index 0000000000..b10752a7c5
--- /dev/null
+++ b/src/auth/FacebookAuth.ts
@@ -0,0 +1,20 @@
+import { Auth } from "./Auth";
+import type { IDP } from "./types";
+
+export class FacebookAuth extends Auth {
+ idpName: IDP = "facebook";
+ clientId = "523634882377310";
+
+ override async login() {
+ const client = await this.getTorusClient();
+
+ return client.triggerLogin({
+ verifier: "tezos-facebook",
+ clientId: this.clientId,
+ typeOfLogin: "facebook",
+ jwtParams: {
+ scope: "public_profile email",
+ },
+ });
+ }
+}
diff --git a/src/auth/GoogleAuth.ts b/src/auth/GoogleAuth.ts
new file mode 100644
index 0000000000..6f4ea352b2
--- /dev/null
+++ b/src/auth/GoogleAuth.ts
@@ -0,0 +1,23 @@
+import { Auth } from "./Auth";
+import type { IDP } from "./types";
+
+export class GoogleAuth extends Auth {
+ idpName: IDP = "google";
+ clientId = "1070572364808-d31nlkneam5ee6dr0tu28fjjbsdkfta5.apps.googleusercontent.com";
+
+ override async login() {
+ const client = await this.getTorusClient();
+
+ return client.triggerAggregateLogin({
+ verifierIdentifier: "tezos-google",
+ aggregateVerifierType: "single_id_verifier",
+ subVerifierDetailsArray: [
+ {
+ clientId: this.clientId,
+ typeOfLogin: "google",
+ verifier: "umami",
+ },
+ ],
+ });
+ }
+}
diff --git a/src/auth/RedditAuth.ts b/src/auth/RedditAuth.ts
new file mode 100644
index 0000000000..366a925869
--- /dev/null
+++ b/src/auth/RedditAuth.ts
@@ -0,0 +1,29 @@
+import { Auth } from "./Auth";
+import { JWT_AUTH_DOMAIN } from "./constants";
+import type { IDP } from "./types";
+
+export class RedditAuth extends Auth {
+ idpName: IDP = "reddit";
+ clientId = "zyQ9tnKfdg3VNyj6MGhZq4dHbBzbmEvl";
+
+ override async login() {
+ const client = await this.getTorusClient();
+
+ return client.triggerAggregateLogin({
+ verifierIdentifier: "tezos-reddit",
+ aggregateVerifierType: "single_id_verifier",
+ subVerifierDetailsArray: [
+ {
+ verifier: "web-kukai",
+ typeOfLogin: "jwt",
+ clientId: this.clientId,
+ jwtParams: {
+ connection: "Reddit",
+ verifierIdField: "name",
+ domain: JWT_AUTH_DOMAIN,
+ },
+ },
+ ],
+ });
+ }
+}
diff --git a/src/auth/TwitterAuth.ts b/src/auth/TwitterAuth.ts
new file mode 100644
index 0000000000..2b19665c00
--- /dev/null
+++ b/src/auth/TwitterAuth.ts
@@ -0,0 +1,21 @@
+import { Auth } from "./Auth";
+import { JWT_AUTH_DOMAIN } from "./constants";
+import type { IDP } from "./types";
+
+export class TwitterAuth extends Auth {
+ idpName: IDP = "twitter";
+ clientId = "3aCoxh3pw8g8JeFsdlJNUGwdgtLwdwgE";
+
+ override async login() {
+ const client = await this.getTorusClient();
+
+ return client.triggerLogin({
+ verifier: "tezos-twitter",
+ clientId: this.clientId,
+ typeOfLogin: "twitter",
+ jwtParams: {
+ domain: JWT_AUTH_DOMAIN,
+ },
+ });
+ }
+}
diff --git a/src/auth/constants.ts b/src/auth/constants.ts
new file mode 100644
index 0000000000..4d43c38e52
--- /dev/null
+++ b/src/auth/constants.ts
@@ -0,0 +1 @@
+export const JWT_AUTH_DOMAIN = "https://kukai.eu.auth0.com";
diff --git a/src/auth/forIDP.test.ts b/src/auth/forIDP.test.ts
new file mode 100644
index 0000000000..1bd33a6813
--- /dev/null
+++ b/src/auth/forIDP.test.ts
@@ -0,0 +1,18 @@
+import { EmailAuth } from "./EmailAuth";
+import { FacebookAuth } from "./FacebookAuth";
+import { forIDP } from "./forIDP";
+import { GoogleAuth } from "./GoogleAuth";
+import { RedditAuth } from "./RedditAuth";
+import { TwitterAuth } from "./TwitterAuth";
+
+describe("forIDP", () => {
+ it.each([
+ { idp: "google" as const, provider: GoogleAuth },
+ { idp: "facebook" as const, provider: FacebookAuth },
+ { idp: "reddit" as const, provider: RedditAuth },
+ { idp: "twitter" as const, provider: TwitterAuth },
+ { idp: "email" as const, provider: EmailAuth },
+ ])("creates an instance for the $idp IDP", ({ idp, provider }) => {
+ expect(forIDP(idp)).toBeInstanceOf(provider);
+ });
+});
diff --git a/src/auth/forIDP.ts b/src/auth/forIDP.ts
new file mode 100644
index 0000000000..88da6e3f10
--- /dev/null
+++ b/src/auth/forIDP.ts
@@ -0,0 +1,24 @@
+import { EmailAuth } from "./EmailAuth";
+import { FacebookAuth } from "./FacebookAuth";
+import { GoogleAuth } from "./GoogleAuth";
+import { RedditAuth } from "./RedditAuth";
+import { TwitterAuth } from "./TwitterAuth";
+import type { IDP } from "./types";
+
+/**
+ * Returns the Auth instance for the given IDP
+ */
+export const forIDP = (idp: IDP) => {
+ switch (idp) {
+ case "google":
+ return new GoogleAuth();
+ case "email":
+ return new EmailAuth();
+ case "reddit":
+ return new RedditAuth();
+ case "facebook":
+ return new FacebookAuth();
+ case "twitter":
+ return new TwitterAuth();
+ }
+};
diff --git a/src/auth/index.ts b/src/auth/index.ts
new file mode 100644
index 0000000000..2c6796d3b6
--- /dev/null
+++ b/src/auth/index.ts
@@ -0,0 +1,5 @@
+export * from "./Auth";
+export * from "./parseTorusRedirectParams";
+export * from "./types";
+export * from "./constants";
+export * from "./forIDP";
diff --git a/src/auth/parseTorusRedirectParams.test.ts b/src/auth/parseTorusRedirectParams.test.ts
new file mode 100644
index 0000000000..b7f1a2b4f8
--- /dev/null
+++ b/src/auth/parseTorusRedirectParams.test.ts
@@ -0,0 +1,34 @@
+import { parseTorusRedirectParams } from ".";
+
+// we get URL params in a compressed format generated by zipurl
+const googleAuthDeeplink =
+ "umami://auth/channel=redirect_channel_zorelm9guc&instanceId=zorelm9guc&verifier=umami-email&typeOfLogin=jwt&redirectToOpener=true&access_token=eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiaXNzIjoiaHR0cHM6Ly9rdWthaS5ldS5hdXRoMC5jb20vIn0..Isiag-vr2cBKB29w.hKsMfMUA835G7-kcF60tDo8UZW6Hbkjj9iwUEyqg-2bBMZTiG2DJTq8wNsPFjP2eE_bmjrNw7KI6dLv-LMAeocvWtVCJ13NhuPqZCcZGoD0rlVSV9RPSLaUmv47Gxi08zzZjvCmUntYCSQoPMu4XFyIpauHkQwRqmpM7fdlYPIj7KSeU2opa_rkurlggBFBQ70PSZpyYvTWYexsjeMYUr5YkZSlg3553SbkDOCjkmTg0FEeAXZhBQEBziAE9Gy4bawOG0YoedTAnpHEI3qoNg4z0m26dudIMVbelNjW8s6eWUqUK.o2yHQOTA9RFM7lj5L_fylA&scope=openid%2520profile%2520email&expires_in=7200&token_type=Bearer&state=eyJpbnN0YW5jZUlkIjoiem9yZWxtOWd1YyIsInZlcmlmaWVyIjoidW1hbWktZW1haWwiLCJ0eXBlT2ZMb2dpbiI6Imp3dCIsInJlZGlyZWN0VG9PcGVuZXIiOnRydWV9&id_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InFsZ25uU0F6SWE1SkFRTkdud2dEbCJ9.eyJuaWNrbmFtZSI6InNlcmpvbnlhIiwibmFtZSI6InNlcmpvbnlhQGdtYWlsLmNvbSIsInBpY3R1cmUiOiJodHRwczovL3MuZ3JhdmF0YXIuY29tL2F2YXRhci8yODVhZWQ0MGQ4ZWRjZWNjN2VkNDZiODFiZTQwMjhhYT9zPTQ4MCZyPXBnJmQ9aHR0cHMlM0ElMkYlMkZjZG4uYXV0aDAuY29tJTJGYXZhdGFycyUyRnNlLnBuZyIsInVwZGF0ZWRfYXQiOiIyMDI0LTA1LTE5VDIyOjQwOjUwLjg4M1oiLCJlbWFpbCI6InNlcmpvbnlhQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJpc3MiOiJodHRwczovL2t1a2FpLmV1LmF1dGgwLmNvbS8iLCJhdWQiOiJMVGc2ZlZzYWNhZkdtaHYxNFRabHJXRjFFYXZ3UW9EWiIsImlhdCI6MTcxNjE1ODQ1MSwiZXhwIjoxNzE2MTk0NDUxLCJzdWIiOiJlbWFpbHw2NjRhMzVlNjk0MTU2YzgxNmU5MzRjZDciLCJhdXRoX3RpbWUiOjE3MTYxNTg0NTAsImF0X2hhc2giOiJtQkRMR1drNGxRcnJMeE1pRnFPczRBIiwic2lkIjoiRnI1UkZuTmF0TWw2azA1YlFFUGNwZk1TVmdYU2R4MjUiLCJub25jZSI6InpvcmVsbTlndWMifQ.IaSqav42wd980FvjgWFY0HJf93wfwScnor7ocDV1BSLjYAmsL8cRJDvWs_rzPiduaQqQFTcbUSWY6hqMawY7-oPL5-RkEeqcub8M6UxRU_z_NTWYToZLIszblNbRoK0dybFc3Kq9D-dVsJhwVYmp9VzycD0DbDvQeBwbuA3GB1OxMhiB7n6__APCLSfrDSWQF4_uzg636pEtGMHboxJf8h_CpEYgnpHvMkOVAJjDq3UmPJgUB8-fFkyO2x_Q9E8Sbe-3Wp2F9M3QQ-MGxZiBMPTi0eemPoFySZId9yUGaAWYb2xYv8Ysk2b0Cu3XUcr1awibDjJRvgoJ_AhNmH330Q&full_params=true";
+
+test("parseTorusRedirectParams", () => {
+ expect(parseTorusRedirectParams(googleAuthDeeplink)).toEqual({
+ channel: "redirect_channel_zorelm9guc",
+ data: {
+ hashParams: {
+ access_token:
+ "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiaXNzIjoiaHR0cHM6Ly9rdWthaS5ldS5hdXRoMC5jb20vIn0..Isiag-vr2cBKB29w.hKsMfMUA835G7-kcF60tDo8UZW6Hbkjj9iwUEyqg-2bBMZTiG2DJTq8wNsPFjP2eE_bmjrNw7KI6dLv-LMAeocvWtVCJ13NhuPqZCcZGoD0rlVSV9RPSLaUmv47Gxi08zzZjvCmUntYCSQoPMu4XFyIpauHkQwRqmpM7fdlYPIj7KSeU2opa_rkurlggBFBQ70PSZpyYvTWYexsjeMYUr5YkZSlg3553SbkDOCjkmTg0FEeAXZhBQEBziAE9Gy4bawOG0YoedTAnpHEI3qoNg4z0m26dudIMVbelNjW8s6eWUqUK.o2yHQOTA9RFM7lj5L_fylA",
+ authuser: null,
+ expires_in: "7200",
+ hd: null,
+ id_token:
+ "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InFsZ25uU0F6SWE1SkFRTkdud2dEbCJ9.eyJuaWNrbmFtZSI6InNlcmpvbnlhIiwibmFtZSI6InNlcmpvbnlhQGdtYWlsLmNvbSIsInBpY3R1cmUiOiJodHRwczovL3MuZ3JhdmF0YXIuY29tL2F2YXRhci8yODVhZWQ0MGQ4ZWRjZWNjN2VkNDZiODFiZTQwMjhhYT9zPTQ4MCZyPXBnJmQ9aHR0cHMlM0ElMkYlMkZjZG4uYXV0aDAuY29tJTJGYXZhdGFycyUyRnNlLnBuZyIsInVwZGF0ZWRfYXQiOiIyMDI0LTA1LTE5VDIyOjQwOjUwLjg4M1oiLCJlbWFpbCI6InNlcmpvbnlhQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJpc3MiOiJodHRwczovL2t1a2FpLmV1LmF1dGgwLmNvbS8iLCJhdWQiOiJMVGc2ZlZzYWNhZkdtaHYxNFRabHJXRjFFYXZ3UW9EWiIsImlhdCI6MTcxNjE1ODQ1MSwiZXhwIjoxNzE2MTk0NDUxLCJzdWIiOiJlbWFpbHw2NjRhMzVlNjk0MTU2YzgxNmU5MzRjZDciLCJhdXRoX3RpbWUiOjE3MTYxNTg0NTAsImF0X2hhc2giOiJtQkRMR1drNGxRcnJMeE1pRnFPczRBIiwic2lkIjoiRnI1UkZuTmF0TWw2azA1YlFFUGNwZk1TVmdYU2R4MjUiLCJub25jZSI6InpvcmVsbTlndWMifQ.IaSqav42wd980FvjgWFY0HJf93wfwScnor7ocDV1BSLjYAmsL8cRJDvWs_rzPiduaQqQFTcbUSWY6hqMawY7-oPL5-RkEeqcub8M6UxRU_z_NTWYToZLIszblNbRoK0dybFc3Kq9D-dVsJhwVYmp9VzycD0DbDvQeBwbuA3GB1OxMhiB7n6__APCLSfrDSWQF4_uzg636pEtGMHboxJf8h_CpEYgnpHvMkOVAJjDq3UmPJgUB8-fFkyO2x_Q9E8Sbe-3Wp2F9M3QQ-MGxZiBMPTi0eemPoFySZId9yUGaAWYb2xYv8Ysk2b0Cu3XUcr1awibDjJRvgoJ_AhNmH330Q",
+ prompt: null,
+ scope: "openid%20profile%20email",
+ state:
+ "eyJpbnN0YW5jZUlkIjoiem9yZWxtOWd1YyIsInZlcmlmaWVyIjoidW1hbWktZW1haWwiLCJ0eXBlT2ZMb2dpbiI6Imp3dCIsInJlZGlyZWN0VG9PcGVuZXIiOnRydWV9",
+ token_type: "Bearer",
+ },
+ instanceParams: {
+ instanceId: "zorelm9guc",
+ redirectToOpener: "true",
+ typeOfLogin: "jwt",
+ verifier: "umami-email",
+ },
+ },
+ error: null,
+ });
+});
diff --git a/src/auth/parseTorusRedirectParams.ts b/src/auth/parseTorusRedirectParams.ts
new file mode 100644
index 0000000000..cb6cd7c4da
--- /dev/null
+++ b/src/auth/parseTorusRedirectParams.ts
@@ -0,0 +1,40 @@
+/**
+ * This function parses the deeplink url we get on a successful social auth.
+ *
+ * The parameters are built by
+ * https://github.com/trilitech/umami-web/blob/main/public/auth/v2.x/redirect.html
+ *
+ * which is essentially a copy of
+ * https://github.com/torusresearch/CustomAuth/blob/master/serviceworker/redirect.html
+ */
+
+export const parseTorusRedirectParams = (url: string) => {
+ const params = new URLSearchParams(url.replace("umami://auth/", ""));
+ const instanceParams = {
+ instanceId: params.get("instanceId"),
+ verifier: params.get("verifier"),
+ typeOfLogin: params.get("typeOfLogin"),
+ redirectToOpener: params.get("redirectToOpener"),
+ };
+
+ const hashParams = {
+ state: params.get("state"),
+ access_token: params.get("access_token"),
+ token_type: params.get("token_type"),
+ expires_in: params.get("expires_in"),
+ scope: params.get("scope"),
+ id_token: params.get("id_token"),
+ authuser: params.get("authuser"),
+ hd: params.get("hd"),
+ prompt: params.get("prompt"),
+ };
+
+ const data = { instanceParams, hashParams };
+ const result = {
+ channel: params.get("channel"),
+ data: data,
+ error: params.get("error"),
+ };
+
+ return result;
+};
diff --git a/src/auth/types.ts b/src/auth/types.ts
new file mode 100644
index 0000000000..15629238bd
--- /dev/null
+++ b/src/auth/types.ts
@@ -0,0 +1 @@
+export type IDP = "google" | "email" | "reddit" | "facebook" | "twitter";
diff --git a/src/components/AccountDrawer/AccountDrawerDisplay.tsx b/src/components/AccountDrawer/AccountDrawerDisplay.tsx
index 7c00c0d8af..73ea1a92df 100644
--- a/src/components/AccountDrawer/AccountDrawerDisplay.tsx
+++ b/src/components/AccountDrawer/AccountDrawerDisplay.tsx
@@ -17,7 +17,6 @@ import { getLastDelegation } from "../../utils/tezos";
import { accountIconGradient } from "../AccountTile/AccountTile";
import { AccountTileIcon } from "../AccountTile/AccountTileIcon";
import { AddressPill } from "../AddressPill/AddressPill";
-import { useAddressKind } from "../AddressTile/useAddressKind";
import { BuyTezForm } from "../BuyTez/BuyTezForm";
import { DynamicModalContext } from "../DynamicModal";
import { FormPage as DelegationFormPage } from "../SendFlow/Delegation/FormPage";
@@ -73,7 +72,6 @@ export const AccountDrawerDisplay: React.FC = ({
}) => {
const isMultisig = account.type === "multisig";
const { openWith } = useContext(DynamicModalContext);
- const addressKind = useAddressKind(account.address);
const network = useSelectedNetwork();
const [delegation, setDelegation] = useState(null);
@@ -106,7 +104,7 @@ export const AccountDrawerDisplay: React.FC = ({
})}
data-testid={`account-card-${account.address.pkh}`}
>
-
+
{account.label}
diff --git a/src/components/AccountDrawer/AssetsPanel/MultisigPendingOperations/MultisigSignerTile.tsx b/src/components/AccountDrawer/AssetsPanel/MultisigPendingOperations/MultisigSignerTile.tsx
index 1a9ade7ed9..d1d4a61584 100644
--- a/src/components/AccountDrawer/AssetsPanel/MultisigPendingOperations/MultisigSignerTile.tsx
+++ b/src/components/AccountDrawer/AssetsPanel/MultisigPendingOperations/MultisigSignerTile.tsx
@@ -13,7 +13,7 @@ import { useAsyncActionHandler } from "../../../../utils/hooks/useAsyncActionHan
import { MultisigOperation } from "../../../../utils/multisig/types";
import { estimate } from "../../../../utils/tezos";
import { AccountTileBase, LabelAndAddress } from "../../../AccountTile/AccountTile";
-import { AccountTileIcon } from "../../../AccountTile/AccountTileIcon";
+import { AddressTileIcon } from "../../../AddressTile/AddressTileIcon";
import { useAddressKind } from "../../../AddressTile/useAddressKind";
import { DynamicModalContext } from "../../../DynamicModal";
import { SignPage } from "../../../SendFlow/Multisig/SignPage";
@@ -81,7 +81,7 @@ export const MultisigSignerTile: React.FC<{
padding="15px"
borderRadius="8px"
backgroundColor={colors.gray[700]}
- icon={}
+ icon={}
leftElement={}
rightElement={
", () => {
},
{
balance: "3",
- iconTestId: "social-icon",
+ iconTestId: "google-icon",
account: mockSocialAccount(0),
},
{
diff --git a/src/components/AccountTile/AccountTile.tsx b/src/components/AccountTile/AccountTile.tsx
index 24ed045f93..476f912f19 100644
--- a/src/components/AccountTile/AccountTile.tsx
+++ b/src/components/AccountTile/AccountTile.tsx
@@ -23,11 +23,11 @@ export const AccountTileBase: React.FC<
> = ({ icon, leftElement, rightElement, ...flexProps }) => (
@@ -55,6 +55,28 @@ export const LabelAndAddress: React.FC<{ label: string | null; pkh: string }> =
const MAX_NFT_COUNT = 7;
+const accountIconGradientColor = (account: Account) => {
+ switch (account.type) {
+ case "mnemonic":
+ case "secret_key":
+ return identiconColor(account.address.pkh);
+ case "ledger":
+ case "multisig":
+ return colors.gray[450];
+ case "social":
+ switch (account.idp) {
+ case "facebook":
+ return "#1977F2";
+ case "google":
+ case "reddit":
+ return "#EA4335";
+ case "email":
+ case "twitter":
+ return colors.gray[450];
+ }
+ }
+};
+
export const accountIconGradient = ({
account,
radius,
@@ -70,19 +92,7 @@ export const accountIconGradient = ({
mainBackgroundColor?: string;
opacity?: string;
}) => {
- let color: string;
- switch (account.type) {
- case "mnemonic":
- case "secret_key":
- color = identiconColor(account.address.pkh);
- break;
- case "ledger":
- case "multisig":
- color = colors.gray[450];
- break;
- case "social":
- color = "#EA4335";
- }
+ let color = accountIconGradientColor(account);
color += opacity;
@@ -135,7 +145,7 @@ export const AccountTile: React.FC<{
padding={0}
border="none"
data-testid={`account-tile-${pkh}` + (isSelected ? "-selected" : "")}
- icon={}
+ icon={}
leftElement={}
rightElement={
diff --git a/src/components/AccountTile/AccountTileIcon.test.tsx b/src/components/AccountTile/AccountTileIcon.test.tsx
index 2038c71586..916c93811b 100644
--- a/src/components/AccountTile/AccountTileIcon.test.tsx
+++ b/src/components/AccountTile/AccountTileIcon.test.tsx
@@ -1,41 +1,49 @@
import { AccountTileIcon } from "./AccountTileIcon";
+import { IDP } from "../../auth";
+import {
+ mockLedgerAccount,
+ mockMnemonicAccount,
+ mockMultisigAccount,
+ mockSocialAccount,
+} from "../../mocks/factories";
+import { addAccount } from "../../mocks/helpers";
import { render, screen } from "../../mocks/testUtils";
-import { AddressKind } from "../AddressTile/types";
+import { Account } from "../../types/Account";
-const fixture = (addressKind: AddressKind) => ;
+const fixture = (account: Account) => ;
-describe("", () => {
- it("displays the mnemonic icon", () => {
- render(fixture({ type: "mnemonic", pkh: "tz1", label: "label" }));
- expect(screen.getByTestId("identicon")).toBeInTheDocument();
+describe("", () => {
+ it.each(["mnemonic", "secret_key"])("displays the %s icon", () => {
+ render(fixture(mockMnemonicAccount(0)));
+ expect(screen.getByTestId("identicon")).toBeVisible();
});
- it("displays the social icon", () => {
- render(fixture({ type: "social", pkh: "tz1", label: "label" }));
- expect(screen.getByTestId("social-icon")).toBeInTheDocument();
+ it.each([
+ "google" as const,
+ "facebook" as const,
+ "twitter" as const,
+ "reddit" as const,
+ "email" as const,
+ ])("displays the %s social icon", (idp: IDP) => {
+ render(fixture(mockSocialAccount(0, "account label", idp)));
+ expect(screen.getByTestId(`${idp}-icon`)).toBeVisible();
});
it("displays the ledger icon", () => {
- render(fixture({ type: "ledger", pkh: "tz1", label: "label" }));
- expect(screen.getByTestId("ledger-icon")).toBeInTheDocument();
+ const account = mockLedgerAccount(0);
+ addAccount(account);
+
+ render(fixture(account));
+
+ expect(screen.getByTestId("ledger-icon")).toBeVisible();
});
it("displays the multisig icon", () => {
- render(fixture({ type: "multisig", pkh: "tz1", label: "label" }));
- expect(screen.getByTestId("key-icon")).toBeInTheDocument();
- });
+ const account = mockMultisigAccount(0);
+ addAccount(account);
- it("displays the baker icon", () => {
- render(fixture({ type: "baker", pkh: "tz1", label: "label" }));
- expect(screen.getByTestId("baker-icon")).toBeInTheDocument();
- });
+ render(fixture(account));
- it("displays the contact icon", () => {
- render(fixture({ type: "contact", pkh: "tz1", label: "label" }));
- expect(screen.getByTestId("contact-icon")).toBeInTheDocument();
- });
- it("displays the unknown icon", () => {
- render(fixture({ type: "unknown", pkh: "tz1", label: null }));
- expect(screen.getByTestId("unknown-contact-icon")).toBeInTheDocument();
+ expect(screen.getByTestId("key-icon")).toBeVisible();
});
});
diff --git a/src/components/AccountTile/AccountTileIcon.tsx b/src/components/AccountTile/AccountTileIcon.tsx
index d50d13426a..93a7e2f2ee 100644
--- a/src/components/AccountTile/AccountTileIcon.tsx
+++ b/src/components/AccountTile/AccountTileIcon.tsx
@@ -1,41 +1,149 @@
-import { Flex } from "@chakra-ui/react";
+import { memo } from "react";
+import {
+ EmailIcon,
+ FacebookIcon,
+ GoogleIcon,
+ KeyIcon,
+ LedgerIcon,
+ RedditIcon,
+ TwitterIcon,
+} from "../../assets/icons";
import colors from "../../style/colors";
-import { AddressTileIcon } from "../AddressTile/AddressTileIcon";
-import { AddressKind } from "../AddressTile/types";
+import { Account } from "../../types/Account";
+import { AddressTileIconSize } from "../AddressTile/AddressTileIconSize";
import { Identicon } from "../Identicon";
-export const AccountTileIcon: React.FC<{ addressKind: AddressKind }> = ({ addressKind }) => {
- switch (addressKind.type) {
- case "secret_key":
- case "mnemonic":
- return (
-
- );
- case "social":
- case "contact":
- case "ledger":
- case "multisig":
- case "unknown":
- case "baker": {
- const bg = addressKind.type === "social" ? "white" : colors.gray[500];
- return (
-
-
-
- );
+const SIZES = {
+ lg: {
+ defaults: {
+ width: "48px",
+ height: "48px",
+ borderRadius: "4px",
+ },
+ mnemonic: {
+ padding: "8px",
+ identiconSize: 32,
+ },
+ ledger: {
+ padding: "10px",
+ },
+ secret_key: {
+ padding: "8px",
+ identiconSize: 32,
+ },
+ multisig: {
+ padding: "10px",
+ },
+ social: {
+ google: {
+ paddingX: "10.28px",
+ paddingY: "10px",
+ },
+ facebook: {
+ padding: "9px",
+ },
+ twitter: {
+ paddingX: "12.78px",
+ paddingY: "13.5px",
+ },
+ reddit: {
+ padding: "10px",
+ },
+ email: {
+ padding: "10px",
+ },
+ },
+ },
+ sm: {
+ defaults: {
+ width: "30px",
+ height: "30px",
+ borderRadius: "4px",
+ },
+ mnemonic: {
+ padding: "5px",
+ identiconSize: 20,
+ },
+ ledger: {
+ padding: "5px",
+ },
+ secret_key: {
+ padding: "5px",
+ identiconSize: 20,
+ },
+ multisig: {
+ padding: "5px",
+ },
+ social: {
+ google: {
+ paddingX: "6.425px",
+ paddingY: "6.25px",
+ },
+ facebook: {
+ padding: "6px",
+ },
+ twitter: {
+ paddingX: "7.5px",
+ paddingY: "8px",
+ },
+ reddit: {
+ padding: "6px",
+ },
+ email: {
+ padding: "6px",
+ },
+ },
+ },
+} as const;
+
+/**
+ * Displays an icon for an account based on its type.
+ *
+ * @param account - The account to display the icon for.
+ * @param size - The size of the icon.
+ */
+export const AccountTileIcon: React.FC<{ account: Account; size: AddressTileIconSize }> = memo(
+ ({ account, size }) => {
+ const sizeObj = SIZES[size];
+ const defaults = sizeObj.defaults;
+
+ switch (account.type) {
+ case "secret_key":
+ return ;
+ case "mnemonic":
+ return ;
+ case "ledger":
+ return ;
+ case "multisig":
+ return (
+
+ );
+ case "social": {
+ switch (account.idp) {
+ case "google":
+ return ;
+
+ case "facebook":
+ return ;
+
+ case "twitter":
+ return ;
+
+ case "reddit":
+ return ;
+
+ case "email":
+ return (
+
+ );
+ }
+ }
}
}
-};
+);
diff --git a/src/components/AddressPill/AddressPillIcon.test.tsx b/src/components/AddressPill/AddressPillIcon.test.tsx
index c61e33ddf9..7b48fd489d 100644
--- a/src/components/AddressPill/AddressPillIcon.test.tsx
+++ b/src/components/AddressPill/AddressPillIcon.test.tsx
@@ -1,15 +1,20 @@
import { LeftIcon, RightIcon } from "./AddressPillIcon";
-import { AddressKindType } from "./types";
import { mockFA2Address } from "../../mocks/addressKind";
import { mockContractAddress } from "../../mocks/factories";
import { render, screen } from "../../mocks/testUtils";
describe("AddressPill Icons", () => {
- it.each(["multisig", "fa1.2", "fa2", "baker", "contact"])("renders %s left icon", type => {
+ it.each([
+ "multisig" as const,
+ "fa1.2" as const,
+ "fa2" as const,
+ "baker" as const,
+ "contact" as const,
+ ])("renders %s left icon", type => {
render(
;
}
- const knownTypes: AddressKindType[] = ["implicit", "multisig", "baker"];
+ const knownTypes: AddressKind["type"][] = ["implicit", "multisig", "baker"];
if (knownTypes.includes(type) || addressExistsInContacts(pkh)) {
return null;
diff --git a/src/components/AddressPill/types.ts b/src/components/AddressPill/types.ts
index 1388f30ab9..89847e4e6c 100644
--- a/src/components/AddressPill/types.ts
+++ b/src/components/AddressPill/types.ts
@@ -6,33 +6,21 @@ import {
UnknownAddress,
} from "../AddressTile/types";
-export type AddressKindType =
- | "implicit"
- | "multisig"
- | "fa1.2"
- | "fa2"
- | "baker"
- | "contact"
- | "unknown";
-
-type AddressKindBase = {
- type: AddressKindType;
- pkh: RawPkh;
- label: string | null;
-};
-
-export type OwnedImplicitAddress = AddressKindBase & {
+export type OwnedImplicitAddress = {
type: "implicit";
+ pkh: RawPkh;
label: string;
};
-export type FA12Address = AddressKindBase & {
+export type FA12Address = {
type: "fa1.2";
+ pkh: RawPkh;
label: null;
};
-export type FA2Address = AddressKindBase & {
+export type FA2Address = {
type: "fa2";
+ pkh: RawPkh;
label: null;
};
diff --git a/src/components/AddressTile/AddressTile.tsx b/src/components/AddressTile/AddressTile.tsx
index 12904df0f4..dc208a3e04 100644
--- a/src/components/AddressTile/AddressTile.tsx
+++ b/src/components/AddressTile/AddressTile.tsx
@@ -37,7 +37,7 @@ export const AddressTile: React.FC<{ address: Address; hideBalance?: boolean } &
{...flexProps}
>
-
+
{addressKind.type === "unknown" ? (
diff --git a/src/components/AddressTile/AddressTileIcon.test.tsx b/src/components/AddressTile/AddressTileIcon.test.tsx
index e8e286fb44..4458ab976d 100644
--- a/src/components/AddressTile/AddressTileIcon.test.tsx
+++ b/src/components/AddressTile/AddressTileIcon.test.tsx
@@ -1,42 +1,75 @@
import { AddressTileIcon } from "./AddressTileIcon";
import { AddressKind } from "./types";
+import type { IDP } from "../../auth";
+import {
+ mockImplicitAddress,
+ mockLedgerAccount,
+ mockMnemonicAccount,
+ mockMultisigAccount,
+ mockSecretKeyAccount,
+ mockSocialAccount,
+} from "../../mocks/factories";
+import { addAccount } from "../../mocks/helpers";
import { render, screen } from "../../mocks/testUtils";
-const fixture = (addressKind: AddressKind) => ;
+const fixture = (addressKind: AddressKind) => (
+
+);
describe("", () => {
- it("displays the mnemonic icon", () => {
- render(fixture({ type: "mnemonic", pkh: "tz1", label: "label" }));
- expect(screen.getByTestId("identicon")).toBeInTheDocument();
+ const label = "some label";
+
+ it.each([mockMnemonicAccount(0), mockSecretKeyAccount(0)])("displays the $type icon", account => {
+ addAccount(account);
+ render(fixture({ ...account, pkh: account.address.pkh }));
+ expect(screen.getByTestId("identicon")).toBeVisible();
});
- it("displays the social icon", () => {
- render(fixture({ type: "social", pkh: "tz1", label: "label" }));
- expect(screen.getByTestId("social-icon")).toBeInTheDocument();
+ it.each([
+ "google" as const,
+ "facebook" as const,
+ "twitter" as const,
+ "reddit" as const,
+ "email" as const,
+ ])("displays the %s social icon", (idp: IDP) => {
+ const account = mockSocialAccount(0, "account label", idp);
+ addAccount(account);
+
+ render(fixture({ ...account.address, type: "social", label }));
+
+ expect(screen.getByTestId(`${idp}-icon`)).toBeVisible();
});
it("displays the ledger icon", () => {
- render(fixture({ type: "ledger", pkh: "tz1", label: "label" }));
- expect(screen.getByTestId("ledger-icon")).toBeInTheDocument();
+ const account = mockLedgerAccount(0);
+ addAccount(account);
+
+ render(fixture({ ...account.address, type: "ledger", label }));
+
+ expect(screen.getByTestId("ledger-icon")).toBeVisible();
});
it("displays the multisig icon", () => {
- render(fixture({ type: "multisig", pkh: "tz1", label: "label" }));
- expect(screen.getByTestId("key-icon")).toBeInTheDocument();
+ const account = mockMultisigAccount(0);
+ addAccount(account);
+
+ render(fixture({ ...account.address, type: "multisig", label }));
+
+ expect(screen.getByTestId("key-icon")).toBeVisible();
});
it("displays the baker icon", () => {
- render(fixture({ type: "baker", pkh: "tz1", label: "label" }));
- expect(screen.getByTestId("baker-icon")).toBeInTheDocument();
+ render(fixture({ ...mockImplicitAddress(0), type: "baker", label }));
+ expect(screen.getByTestId("baker-icon")).toBeVisible();
});
it("displays the contact icon", () => {
- render(fixture({ type: "contact", pkh: "tz1", label: "label" }));
- expect(screen.getByTestId("contact-icon")).toBeInTheDocument();
+ render(fixture({ ...mockImplicitAddress(0), type: "contact", label }));
+ expect(screen.getByTestId("contact-icon")).toBeVisible();
});
it("displays the unknown icon", () => {
- render(fixture({ type: "unknown", pkh: "tz1", label: null }));
- expect(screen.getByTestId("unknown-contact-icon")).toBeInTheDocument();
+ render(fixture({ ...mockImplicitAddress(0), type: "unknown", label: null }));
+ expect(screen.getByTestId("unknown-contact-icon")).toBeVisible();
});
});
diff --git a/src/components/AddressTile/AddressTileIcon.tsx b/src/components/AddressTile/AddressTileIcon.tsx
index d43ddd9ca0..f6e23411dd 100644
--- a/src/components/AddressTile/AddressTileIcon.tsx
+++ b/src/components/AddressTile/AddressTileIcon.tsx
@@ -1,86 +1,77 @@
-import { AspectRatio, Image } from "@chakra-ui/react";
+import { Image } from "@chakra-ui/react";
+import { memo } from "react";
+import { AddressTileIconSize } from "./AddressTileIconSize";
import { AddressKind } from "./types";
-import {
- ContactIcon,
- KeyIcon,
- LedgerIcon,
- SocialIcon,
- UnknownContactIcon,
-} from "../../assets/icons";
+import { ContactIcon, UnknownContactIcon } from "../../assets/icons";
import colors from "../../style/colors";
-import { Identicon } from "../Identicon";
+import { useGetOwnedAccountSafe } from "../../utils/hooks/getAccountDataHooks";
+import { AccountTileIcon } from "../AccountTile/AccountTileIcon";
const baseIconProps = {
stroke: colors.gray[400],
borderRadius: "4px",
- padding: "5px",
background: colors.gray[500],
};
-type AddressTileIconSize = "sm" | "md" | "lg";
-
+/**
+ * Displays an icon for an address based on its kind.
+ * Can be used with arbitrary addresses, not just accounts.
+ * Though for accounts it'll reuse {@link AccountTileIcon}.
+ *
+ * @param addressKind - The address to display the icon for.
+ * @param size - The size of the icon.
+ */
export const AddressTileIcon: React.FC<{
addressKind: AddressKind;
- size?: AddressTileIconSize;
- identiconSize?: number; // only used for secret_key and mnemonic
-}> = ({ addressKind, size = "sm", identiconSize = 20 }) => {
+ size: AddressTileIconSize;
+}> = memo(({ addressKind, size }) => {
+ const getAccount = useGetOwnedAccountSafe();
+ const account = getAccount(addressKind.pkh);
+
+ if (account) {
+ return ;
+ }
+
let sizeInPx;
+ let padding;
switch (size) {
case "sm":
sizeInPx = "30px";
- break;
- case "md":
- sizeInPx = "38.5px";
+ padding = "5px";
break;
case "lg":
- sizeInPx = "45.5px";
- break;
+ sizeInPx = "48px";
+ padding = "10px";
}
switch (addressKind.type) {
- case "secret_key":
- case "mnemonic":
+ case "contact":
return (
-
+
);
- case "social":
+ case "unknown":
return (
-
);
- case "ledger":
- return ;
- case "multisig":
- return ;
- case "contact":
- return ;
- case "unknown":
- return ;
- case "baker": {
- const bakerLogoUrl = `https://services.tzkt.io/v1/avatars/${addressKind.pkh}`;
+ case "baker":
return (
-
-
-
+ src={`https://services.tzkt.io/v1/avatars/${addressKind.pkh}`}
+ />
);
- }
+ case "secret_key":
+ case "mnemonic":
+ case "social":
+ case "ledger":
+ case "multisig":
+ return null; // impossible state
}
-};
+});
diff --git a/src/components/AddressTile/AddressTileIconSize.ts b/src/components/AddressTile/AddressTileIconSize.ts
new file mode 100644
index 0000000000..7116371bbf
--- /dev/null
+++ b/src/components/AddressTile/AddressTileIconSize.ts
@@ -0,0 +1 @@
+export type AddressTileIconSize = "sm" | "lg";
diff --git a/src/components/AddressTile/types.ts b/src/components/AddressTile/types.ts
index 75046f7c64..9794e4c767 100644
--- a/src/components/AddressTile/types.ts
+++ b/src/components/AddressTile/types.ts
@@ -1,29 +1,13 @@
import { RawPkh } from "../../types/Address";
-type AddressKindType =
- | "mnemonic"
- | "secret_key"
- | "social"
- | "ledger"
- | "multisig"
- | "baker"
- | "contact"
- | "unknown";
-
-type AddressKindBase = {
- type: AddressKindType;
- pkh: RawPkh;
- label: string | null;
-};
-
-type MnemonicAddress = AddressKindBase & { type: "mnemonic"; label: string };
-type SecretKeyAddress = AddressKindBase & { type: "secret_key"; label: string };
-type SocialAddress = AddressKindBase & { type: "social"; label: string };
-type LedgerAddress = AddressKindBase & { type: "ledger"; label: string };
-export type OwnedMultisigAddress = AddressKindBase & { type: "multisig"; label: string };
-export type BakerAddress = AddressKindBase & { type: "baker"; label: string };
-export type ContactAddress = AddressKindBase & { type: "contact"; label: string };
-export type UnknownAddress = AddressKindBase & { type: "unknown"; label: null };
+type MnemonicAddress = { type: "mnemonic"; pkh: RawPkh; label: string };
+type SecretKeyAddress = { type: "secret_key"; pkh: RawPkh; label: string };
+type SocialAddress = { type: "social"; pkh: RawPkh; label: string };
+type LedgerAddress = { type: "ledger"; pkh: RawPkh; label: string };
+export type OwnedMultisigAddress = { type: "multisig"; pkh: RawPkh; label: string };
+export type BakerAddress = { type: "baker"; pkh: RawPkh; label: string };
+export type ContactAddress = { type: "contact"; pkh: RawPkh; label: string };
+export type UnknownAddress = { type: "unknown"; pkh: RawPkh; label: null };
export type OwnedAddress =
| MnemonicAddress
diff --git a/src/components/Identicon.tsx b/src/components/Identicon.tsx
index e48e4ae9e1..3fcf2e726e 100644
--- a/src/components/Identicon.tsx
+++ b/src/components/Identicon.tsx
@@ -3,13 +3,13 @@ import md5 from "md5";
import React from "react";
import { ReactIdenticon } from "./ReactIdenticon";
-import { RawPkh } from "../types/Address";
+import { Address, RawPkh } from "../types/Address";
export const color = (address: RawPkh) => `#${md5(address).slice(0, 6)}`;
export const Identicon: React.FC<
{
- address: RawPkh;
+ address: Address;
identiconSize: number;
} & ChakraProps
> = ({ address, identiconSize, ...props }) => (
@@ -19,7 +19,7 @@ export const Identicon: React.FC<
borderRadius: "4px",
},
}}
- zIndex={10}
+ zIndex={3}
background="white"
borderRadius="4px"
data-testid="identicon"
@@ -28,7 +28,7 @@ export const Identicon: React.FC<
void }) => {
const {
register,
handleSubmit,
formState: { errors },
- } = useForm<{ pkh: string; name: string }>({ mode: "onBlur" });
+ } = useForm<{ pkh: string; name: string; idp?: IDP }>({ mode: "onBlur" });
const restoreLedger = useRestoreLedger();
+ const restoreSocial = useRestoreSocial();
- const onSubmit = async ({ pkh, name }: { pkh: string; name: string }) => {
- const rpc = new RpcClient(MAINNET.rpcUrl);
+ const onSubmit = async ({ pkh, name, idp }: { pkh: string; name: string; idp?: IDP }) => {
+ if (idp && idp.length > 0) {
+ if (!["google", "facebook", "twitter", "reddit", "email"].includes(idp)) {
+ throw new Error("Invalid IDP");
+ }
+ }
+ const rpc = new RpcClient(GHOSTNET.rpcUrl);
const managerKey = await rpc.getManagerKey(pkh);
const pk = typeof managerKey === "string" ? managerKey : managerKey.key;
- restoreLedger(
- defaultDerivationPathTemplate,
- makeDerivationPath(defaultDerivationPathTemplate, 0),
- pk,
- pkh,
- name
- );
+
+ if (idp) {
+ restoreSocial(pk, pkh, name, idp);
+ } else {
+ restoreLedger(
+ defaultDerivationPathTemplate,
+ makeDerivationPath(defaultDerivationPathTemplate, 0),
+ pk,
+ pkh,
+ name
+ );
+ }
onClose();
};
return (
} title="Add a Fake Account">
diff --git a/src/components/Onboarding/connectOrCreate/ConnectOrCreate.tsx b/src/components/Onboarding/connectOrCreate/ConnectOrCreate.tsx
index 48266c0a52..19d1867a13 100644
--- a/src/components/Onboarding/connectOrCreate/ConnectOrCreate.tsx
+++ b/src/components/Onboarding/connectOrCreate/ConnectOrCreate.tsx
@@ -1,12 +1,13 @@
-import { Button, Divider, Flex, Text, VStack, useToast } from "@chakra-ui/react";
+import { Button, Divider, Flex, Text, VStack } from "@chakra-ui/react";
+import { OnboardWithEmailButton } from "./OnboardWithEmailButton";
+import { OnboardWithFacebookButton } from "./OnboardWithFacebookButton";
+import { OnboardWithGoogleButton } from "./OnboardWithGoogleButton";
+import { OnboardWithRedditButton } from "./OnboardWithRedditButton";
+import { OnboardWithTwitterButton } from "./OnboardWithTwitterButton";
import { WalletPlusIcon } from "../../../assets/icons";
import { IS_DEV } from "../../../env";
-import { GoogleAuth } from "../../../GoogleAuth";
import colors from "../../../style/colors";
-import { useRestoreSocial } from "../../../utils/hooks/setAccountDataHooks";
-import { useAsyncActionHandler } from "../../../utils/hooks/useAsyncActionHandler";
-import { getPublicKeyPairFromSk } from "../../../utils/tezos";
import { ModalContentWrapper } from "../ModalContentWrapper";
import { OnboardingStep } from "../OnboardingStep";
@@ -16,58 +17,44 @@ export const ConnectOrCreate = ({
}: {
goToStep: (step: OnboardingStep) => void;
closeModal: () => void;
-}) => {
- const { handleAsyncAction } = useAsyncActionHandler();
- const restoreSocial = useRestoreSocial();
- const toast = useToast();
-
- const onSocialAuth = (sk: string, email: string) =>
- handleAsyncAction(async () => {
- const { pk, pkh } = await getPublicKeyPairFromSk(sk);
- restoreSocial(pk, pkh, email);
- toast({ description: `Successfully added ${email} account`, status: "success" });
- closeModal();
- });
-
- return (
- } title="Connect or Create Account">
-
-
+}) => (
+ } title="Connect or Create Account">
+
+
+
+ {IS_DEV && (
- {IS_DEV && (
-
- )}
-
-
-
- Continue with Google
-
-
-
-
-
-
- );
-};
+ )}
+
+
+
+ Continue with social
+
+
+
+
+
+
+
+
+
+
+
+
+);
diff --git a/src/components/Onboarding/connectOrCreate/OnboardWithEmailButton.tsx b/src/components/Onboarding/connectOrCreate/OnboardWithEmailButton.tsx
new file mode 100644
index 0000000000..bd8fbdd715
--- /dev/null
+++ b/src/components/Onboarding/connectOrCreate/OnboardWithEmailButton.tsx
@@ -0,0 +1,22 @@
+import { IconButton } from "@chakra-ui/react";
+
+import { useOnboardWithSocial } from "./useOnboardWithSocial";
+import { EmailIcon } from "../../../assets/icons";
+import colors from "../../../style/colors";
+
+export const OnboardWithEmailButton = ({ onAuth }: { onAuth: () => void }) => {
+ const { isLoading, onboard } = useOnboardWithSocial("email", onAuth);
+
+ return (
+ }
+ isLoading={isLoading}
+ onClick={onboard}
+ variant="socialLogin"
+ />
+ );
+};
diff --git a/src/components/Onboarding/connectOrCreate/OnboardWithFacebookButton.tsx b/src/components/Onboarding/connectOrCreate/OnboardWithFacebookButton.tsx
new file mode 100644
index 0000000000..095f083769
--- /dev/null
+++ b/src/components/Onboarding/connectOrCreate/OnboardWithFacebookButton.tsx
@@ -0,0 +1,19 @@
+import { IconButton } from "@chakra-ui/react";
+
+import { useOnboardWithSocial } from "./useOnboardWithSocial";
+import { FacebookIcon } from "../../../assets/icons";
+
+export const OnboardWithFacebookButton = ({ onAuth }: { onAuth: () => void }) => {
+ const { isLoading, onboard } = useOnboardWithSocial("facebook", onAuth);
+
+ return (
+ }
+ isLoading={isLoading}
+ onClick={onboard}
+ variant="socialLogin"
+ />
+ );
+};
diff --git a/src/components/Onboarding/connectOrCreate/OnboardWithGoogleButton.tsx b/src/components/Onboarding/connectOrCreate/OnboardWithGoogleButton.tsx
new file mode 100644
index 0000000000..d5e6bd516f
--- /dev/null
+++ b/src/components/Onboarding/connectOrCreate/OnboardWithGoogleButton.tsx
@@ -0,0 +1,19 @@
+import { IconButton } from "@chakra-ui/react";
+
+import { useOnboardWithSocial } from "./useOnboardWithSocial";
+import { GoogleIcon } from "../../../assets/icons";
+
+export const OnboardWithGoogleButton = ({ onAuth }: { onAuth: () => void }) => {
+ const { isLoading, onboard } = useOnboardWithSocial("google", onAuth);
+
+ return (
+ }
+ isLoading={isLoading}
+ onClick={onboard}
+ variant="socialLogin"
+ />
+ );
+};
diff --git a/src/components/Onboarding/connectOrCreate/OnboardWithRedditButton.tsx b/src/components/Onboarding/connectOrCreate/OnboardWithRedditButton.tsx
new file mode 100644
index 0000000000..ad18471114
--- /dev/null
+++ b/src/components/Onboarding/connectOrCreate/OnboardWithRedditButton.tsx
@@ -0,0 +1,19 @@
+import { IconButton } from "@chakra-ui/react";
+
+import { useOnboardWithSocial } from "./useOnboardWithSocial";
+import { RedditIcon } from "../../../assets/icons";
+
+export const OnboardWithRedditButton = ({ onAuth }: { onAuth: () => void }) => {
+ const { isLoading, onboard } = useOnboardWithSocial("reddit", onAuth);
+
+ return (
+ }
+ isLoading={isLoading}
+ onClick={onboard}
+ variant="socialLogin"
+ />
+ );
+};
diff --git a/src/components/Onboarding/connectOrCreate/OnboardWithTwitterButton.tsx b/src/components/Onboarding/connectOrCreate/OnboardWithTwitterButton.tsx
new file mode 100644
index 0000000000..90e011c5dd
--- /dev/null
+++ b/src/components/Onboarding/connectOrCreate/OnboardWithTwitterButton.tsx
@@ -0,0 +1,22 @@
+import { IconButton } from "@chakra-ui/react";
+
+import { useOnboardWithSocial } from "./useOnboardWithSocial";
+import { TwitterIcon } from "../../../assets/icons";
+import colors from "../../../style/colors";
+
+export const OnboardWithTwitterButton = ({ onAuth }: { onAuth: () => void }) => {
+ const { isLoading, onboard } = useOnboardWithSocial("twitter", onAuth);
+
+ return (
+ }
+ isLoading={isLoading}
+ onClick={onboard}
+ variant="socialLogin"
+ />
+ );
+};
diff --git a/src/components/Onboarding/connectOrCreate/useOnboardWithSocial.tsx b/src/components/Onboarding/connectOrCreate/useOnboardWithSocial.tsx
new file mode 100644
index 0000000000..9b1c4ff6eb
--- /dev/null
+++ b/src/components/Onboarding/connectOrCreate/useOnboardWithSocial.tsx
@@ -0,0 +1,44 @@
+import { useToast } from "@chakra-ui/react";
+import { minutesToMilliseconds } from "date-fns";
+import { useCallback } from "react";
+
+import * as Auth from "../../../auth";
+import { useRestoreSocial } from "../../../utils/hooks/setAccountDataHooks";
+import { useAsyncActionHandler } from "../../../utils/hooks/useAsyncActionHandler";
+import { getPublicKeyPairFromSk } from "../../../utils/tezos";
+import { withTimeout } from "../../../utils/withTimeout";
+
+const LOGIN_TIMEOUT = minutesToMilliseconds(1);
+
+/**
+ * Hook to onboard with a social identity provider.
+ * Handles the authentication process and adds the account to the user's wallet.
+ *
+ * @param idp - the identity provider to use for authentication
+ * @param onAuth - callback which will be called on a successful authentication
+ */
+export const useOnboardWithSocial = (idp: Auth.IDP, onAuth: () => void) => {
+ const toast = useToast();
+ const { isLoading, handleAsyncAction } = useAsyncActionHandler();
+ const restoreSocial = useRestoreSocial();
+
+ const onboard = useCallback(
+ () =>
+ handleAsyncAction(
+ async () => {
+ const { secretKey, name } = await withTimeout(
+ () => Auth.forIDP(idp).getCredentials(),
+ LOGIN_TIMEOUT
+ );
+ const { pk, pkh } = await getPublicKeyPairFromSk(secretKey);
+ restoreSocial(pk, pkh, name, idp);
+ toast({ description: `Successfully added ${name} account`, status: "success" });
+ onAuth();
+ },
+ { title: "Social login failed" }
+ ),
+ [idp, toast, handleAsyncAction, restoreSocial, onAuth]
+ );
+
+ return { isLoading, onboard };
+};
diff --git a/src/components/Onboarding/restoreMnemonic/RestoreMnemonic.tsx b/src/components/Onboarding/restoreMnemonic/RestoreMnemonic.tsx
index 9c69009261..f93ba5123e 100644
--- a/src/components/Onboarding/restoreMnemonic/RestoreMnemonic.tsx
+++ b/src/components/Onboarding/restoreMnemonic/RestoreMnemonic.tsx
@@ -76,7 +76,7 @@ export const RestoreMnemonic = ({ goToStep }: { goToStep: (step: OnboardingStep)
return (
}
+ icon={}
subtitle="Please fill in the Seed Phrase in sequence."
title="Import Seed Phrase"
>
diff --git a/src/components/Onboarding/restoreSecretKey/RestoreSecretKey.tsx b/src/components/Onboarding/restoreSecretKey/RestoreSecretKey.tsx
index 88f0dc0ac6..3670e9abc5 100644
--- a/src/components/Onboarding/restoreSecretKey/RestoreSecretKey.tsx
+++ b/src/components/Onboarding/restoreSecretKey/RestoreSecretKey.tsx
@@ -4,7 +4,6 @@ import { useState } from "react";
import { FormProvider, useForm } from "react-hook-form";
import { KeyIcon } from "../../../assets/icons";
-import colors from "../../../style/colors";
import { useAsyncActionHandler } from "../../../utils/hooks/useAsyncActionHandler";
import { isEncryptedSecretKeyPrefix } from "../../../utils/redux/thunks/secretKeyAccount";
import { PasswordInput } from "../../PasswordInput";
@@ -60,10 +59,7 @@ export const RestoreSecretKey = ({ goToStep }: { goToStep: (step: OnboardingStep
});
return (
- }
- title="Insert Secret Key"
- >
+ } title="Insert Secret Key">
{balance && (
diff --git a/src/views/home/AccountsList.tsx b/src/views/home/AccountsList.tsx
index b4575ed711..ed8b77262c 100644
--- a/src/views/home/AccountsList.tsx
+++ b/src/views/home/AccountsList.tsx
@@ -48,7 +48,7 @@ export const AccountsList = () => {
color={colors.gray[400]}
textAlign="center"
>
-
+
Create New Multisig
diff --git a/src/views/tokens/AccountTokens.tsx b/src/views/tokens/AccountTokens.tsx
index 07ee453756..3a00bd00bd 100644
--- a/src/views/tokens/AccountTokens.tsx
+++ b/src/views/tokens/AccountTokens.tsx
@@ -16,9 +16,8 @@ import { TokenNameWithIcon } from "./TokenNameWithIcon";
import { TokenIcon } from "../../assets/icons";
import { AccountBalance } from "../../components/AccountBalance";
import { accountIconGradient } from "../../components/AccountTile/AccountTile";
+import { AccountTileIcon } from "../../components/AccountTile/AccountTileIcon";
import { AddressPill } from "../../components/AddressPill/AddressPill";
-import { AddressTileIcon } from "../../components/AddressTile/AddressTileIcon";
-import { useAddressKind } from "../../components/AddressTile/useAddressKind";
import { DynamicModalContext } from "../../components/DynamicModal";
import { SendButton } from "../../components/SendButton";
import { FormPage as SendTokenFormPage } from "../../components/SendFlow/Token/FormPage";
@@ -33,7 +32,6 @@ const Header: React.FC<{
account: Account;
}> = ({ account }) => {
const { address, label } = account;
- const addressKind = useAddressKind(address);
return (
-
+
diff --git a/vite.config.ts b/vite.config.ts
index fcae5a1dae..26858c0f37 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,3 +1,5 @@
+import process from "process";
+
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
import { checker } from "vite-plugin-checker";
@@ -18,6 +20,7 @@ export default defineConfig({
}),
react(),
checker({
+ enableBuild: false,
overlay: false,
terminal: true,
typescript: true,
@@ -30,5 +33,6 @@ export default defineConfig({
build: {
outDir: "build",
chunkSizeWarningLimit: 5 * 1024, // 5MB
+ sourcemap: process.env.DEBUG === "true",
},
});
diff --git a/yarn.lock b/yarn.lock
index 375ff30889..9e7278d7fe 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1968,7 +1968,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.21.5, @babel/runtime@npm:^7.4.2, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2":
+"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.4.2, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2":
version: 7.22.10
resolution: "@babel/runtime@npm:7.22.10"
dependencies:
@@ -2004,7 +2004,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/runtime@npm:^7.24.5":
+"@babel/runtime@npm:^7.22.10, @babel/runtime@npm:^7.24.5":
version: 7.24.5
resolution: "@babel/runtime@npm:7.24.5"
dependencies:
@@ -2167,9 +2167,9 @@ __metadata:
linkType: hard
"@chaitanyapotti/register-service-worker@npm:^1.7.3":
- version: 1.7.3
- resolution: "@chaitanyapotti/register-service-worker@npm:1.7.3"
- checksum: 10/995b875e434a11dcb24ccde8d7914e2f6f95047e83278f5747cfd0d83813a81c712b6794d60e7371ff92734393b5a399e31e68fa5fa5a8a2ab91aa9bdffc8e4d
+ version: 1.7.4
+ resolution: "@chaitanyapotti/register-service-worker@npm:1.7.4"
+ checksum: 10/77df892ffcac378c57aaccd1c7ffb98619a15c04296c8a9bf9813756073f84351d674483fe5a56b91fa3ca3280234f9987f757cb7c1c57faec9c974997034611
languageName: node
linkType: hard
@@ -4748,16 +4748,23 @@ __metadata:
languageName: node
linkType: hard
-"@noble/curves@npm:1.0.0, @noble/curves@npm:~1.0.0":
- version: 1.0.0
- resolution: "@noble/curves@npm:1.0.0"
+"@noble/curves@npm:1.3.0, @noble/curves@npm:~1.3.0":
+ version: 1.3.0
+ resolution: "@noble/curves@npm:1.3.0"
dependencies:
- "@noble/hashes": "npm:1.3.0"
- checksum: 10/6db884e03b3f6c773317bcf4611bf1d9adb8084eab0bf6158407cc998c9c5dcb0560741bdd0aaca9c4393c9e8a3dcd7592b4148a6cfd561d0a00addb77a6129f
+ "@noble/hashes": "npm:1.3.3"
+ checksum: 10/f3cbdd1af00179e30146eac5539e6df290228fb857a7a8ba36d1a772cbe59288a2ca83d06f175d3446ef00db3a80d7fd8b8347f7de9c2d4d5bf3865d8bb78252
languageName: node
linkType: hard
-"@noble/hashes@npm:1.3.0, @noble/hashes@npm:^1.2.0, @noble/hashes@npm:~1.3.0":
+"@noble/hashes@npm:1.3.3, @noble/hashes@npm:~1.3.2":
+ version: 1.3.3
+ resolution: "@noble/hashes@npm:1.3.3"
+ checksum: 10/1025ddde4d24630e95c0818e63d2d54ee131b980fe113312d17ed7468bc18f54486ac86c907685759f8a7e13c2f9b9e83ec7b67d1cc20836f36b5e4a65bb102d
+ languageName: node
+ linkType: hard
+
+"@noble/hashes@npm:^1.2.0":
version: 1.3.0
resolution: "@noble/hashes@npm:1.3.0"
checksum: 10/4680a71941c06ac897cc9eab9d229717d5af1147cea5e8cd4942190c817426ad3173ded750d897f58d764b869f9347d4fc3f6b3c16574541ac81906efa9ddc36
@@ -5007,31 +5014,31 @@ __metadata:
languageName: node
linkType: hard
-"@scure/base@npm:~1.1.0":
- version: 1.1.1
- resolution: "@scure/base@npm:1.1.1"
- checksum: 10/9aaa525ac25215cbe1bde00733a2fd25e99f03793aa1fd2961c567bb62b60c8a3a485a7cb5d748c41604fca79d149de19b05e64449b770c0a04b9ae38d0b5b2b
+"@scure/base@npm:~1.1.4":
+ version: 1.1.6
+ resolution: "@scure/base@npm:1.1.6"
+ checksum: 10/814fd1cce24f1e152751fabca2853d26aaa96ff8a9349c43d9aebc3b3d8ca88dd902966e1c289590a37f35d4c4436c6aedb1b386924b2909072045af4c3e9fe4
languageName: node
linkType: hard
-"@scure/bip32@npm:1.3.0":
- version: 1.3.0
- resolution: "@scure/bip32@npm:1.3.0"
+"@scure/bip32@npm:1.3.3":
+ version: 1.3.3
+ resolution: "@scure/bip32@npm:1.3.3"
dependencies:
- "@noble/curves": "npm:~1.0.0"
- "@noble/hashes": "npm:~1.3.0"
- "@scure/base": "npm:~1.1.0"
- checksum: 10/1fabcc7f2215910b35980bfc455c03fc4ae7f848efed066fe3867960a8dfceb6141c932496434fc2cfbf385d270ff9efdfce2571992e4584103f82e45ac2103f
+ "@noble/curves": "npm:~1.3.0"
+ "@noble/hashes": "npm:~1.3.2"
+ "@scure/base": "npm:~1.1.4"
+ checksum: 10/4b8b75567866ff7d6b3ba154538add02d2951e9433e8dd7f0014331ac500cda5a88fe3d39b408fcc36e86b633682013f172b967af022c2e4e4ab07336801d688
languageName: node
linkType: hard
-"@scure/bip39@npm:1.2.0":
- version: 1.2.0
- resolution: "@scure/bip39@npm:1.2.0"
+"@scure/bip39@npm:1.2.2":
+ version: 1.2.2
+ resolution: "@scure/bip39@npm:1.2.2"
dependencies:
- "@noble/hashes": "npm:~1.3.0"
- "@scure/base": "npm:~1.1.0"
- checksum: 10/2a260eefea0b2658c5d3b2cb982479ef650552c3007e57f667b445943c79717eb923c1a104a664b4873bc210aeb59859bf890c3e7b47fb51ed5b94dc96f75105
+ "@noble/hashes": "npm:~1.3.2"
+ "@scure/base": "npm:~1.1.4"
+ checksum: 10/f71aceda10a7937bf3779fd2b4c4156c95ec9813269470ddca464cb8ab610d2451b173037f4b1e6dac45414e406e7adc7b5814c51279f4474d5d38140bbee542
languageName: node
linkType: hard
@@ -5645,43 +5652,44 @@ __metadata:
languageName: node
linkType: hard
-"@toruslabs/broadcast-channel@npm:^7.0.0":
- version: 7.0.0
- resolution: "@toruslabs/broadcast-channel@npm:7.0.0"
+"@toruslabs/broadcast-channel@npm:^8.0.0":
+ version: 8.0.0
+ resolution: "@toruslabs/broadcast-channel@npm:8.0.0"
dependencies:
- "@babel/runtime": "npm:^7.21.5"
- "@toruslabs/eccrypto": "npm:^3.0.0"
- "@toruslabs/metadata-helpers": "npm:^4.0.0"
+ "@babel/runtime": "npm:^7.22.10"
+ "@toruslabs/eccrypto": "npm:^4.0.0"
+ "@toruslabs/metadata-helpers": "npm:^5.0.0"
bowser: "npm:^2.11.0"
loglevel: "npm:^1.8.1"
oblivious-set: "npm:1.1.1"
- socket.io-client: "npm:^4.6.1"
+ socket.io-client: "npm:^4.7.2"
unload: "npm:^2.4.1"
- checksum: 10/984778b9ff158c1e2f3673dffe3e64f47ec6ff99e75f387336021fb2a6a6dfd7333f45bac4824fda916931259d94d6155be305a6cc0feb6887bff2591385780e
+ checksum: 10/146f792025114615d349b5ca36fb6eab7d6963b1ff7ee8a0582a31f3a4285cad79d25c2fa56aa9688199273fe4f43fb01fe4f1a19c628ab3745ed405faa97037
languageName: node
linkType: hard
-"@toruslabs/constants@npm:^11.0.0":
- version: 11.0.0
- resolution: "@toruslabs/constants@npm:11.0.0"
+"@toruslabs/constants@npm:^13.0.1, @toruslabs/constants@npm:^13.4.0":
+ version: 13.4.0
+ resolution: "@toruslabs/constants@npm:13.4.0"
peerDependencies:
"@babel/runtime": 7.x
- checksum: 10/60ff98b61fdae18fdb164d8f8ccc87e464fa9d8e2e26e9d2014f0aea766266603f95ee5e1ba187ae85f2510755e30ffcec912212f3c4e6cdd420d3413d942b4d
+ checksum: 10/eb4d1446474e66cd8d820eed6ea4beb21fa1563d0545fa77e21803153ac6673260d54050e90ab98c90c82572f885fa19cd88e08dfee37df3fb5345809609959c
languageName: node
linkType: hard
-"@toruslabs/customauth@npm:^15.0.5":
- version: 15.0.5
- resolution: "@toruslabs/customauth@npm:15.0.5"
+"@toruslabs/customauth@npm:^16.0.6":
+ version: 16.0.6
+ resolution: "@toruslabs/customauth@npm:16.0.6"
dependencies:
"@chaitanyapotti/register-service-worker": "npm:^1.7.3"
- "@toruslabs/broadcast-channel": "npm:^7.0.0"
- "@toruslabs/constants": "npm:^11.0.0"
- "@toruslabs/eccrypto": "npm:^3.0.0"
- "@toruslabs/fetch-node-details": "npm:^11.0.1"
- "@toruslabs/http-helpers": "npm:^4.0.0"
- "@toruslabs/metadata-helpers": "npm:^4.0.0"
- "@toruslabs/torus.js": "npm:^10.0.5"
+ "@toruslabs/broadcast-channel": "npm:^8.0.0"
+ "@toruslabs/constants": "npm:^13.0.1"
+ "@toruslabs/eccrypto": "npm:^4.0.0"
+ "@toruslabs/fetch-node-details": "npm:^13.0.1"
+ "@toruslabs/http-helpers": "npm:^5.0.0"
+ "@toruslabs/metadata-helpers": "npm:^5.0.0"
+ "@toruslabs/torus.js": "npm:^11.0.5"
+ base64url: "npm:^3.0.1"
bowser: "npm:^2.11.0"
events: "npm:^3.3.0"
jwt-decode: "npm:^3.1.2"
@@ -5693,47 +5701,47 @@ __metadata:
peerDependenciesMeta:
"@sentry/types":
optional: true
- checksum: 10/172632508c1b942cd9b705193ad30515a79a7a6734eb70b1126860bbbb9d6f99418ecfee0d77eeadc59f819703e812de70830783b98b049fc6ec288b077281a0
+ checksum: 10/8520ed2e66074d5686a641e168481a9c3d63401db6aea86dba8e61bfe8446a86ba4aaf5d75990580f3a6b430b7469117c6c2ded26a332e32fd4bdda73ff50f1e
languageName: node
linkType: hard
-"@toruslabs/eccrypto@npm:^3.0.0":
- version: 3.0.0
- resolution: "@toruslabs/eccrypto@npm:3.0.0"
+"@toruslabs/eccrypto@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "@toruslabs/eccrypto@npm:4.0.0"
dependencies:
elliptic: "npm:^6.5.4"
- checksum: 10/14e56f63ed0b1b4d8a97bd13243699babb2981ba63eb6594417e2feaadba0847f33cfd2b56bb4f1ec3b90351e8020b80552a617420b24e2681fe6065ac1f7ad3
+ checksum: 10/9b8bcc2ccb8c21bd2c4170303a21e4e4e3563b4a44a0a43cc11d0587b6a01029ab0cdccc7b88b4c861ec07f841ee1cdcba7b35e7e07b5abff307f753c31dfdff
languageName: node
linkType: hard
-"@toruslabs/fetch-node-details@npm:^11.0.1":
- version: 11.0.1
- resolution: "@toruslabs/fetch-node-details@npm:11.0.1"
+"@toruslabs/fetch-node-details@npm:^13.0.1":
+ version: 13.4.0
+ resolution: "@toruslabs/fetch-node-details@npm:13.4.0"
dependencies:
- "@toruslabs/constants": "npm:^11.0.0"
- "@toruslabs/fnd-base": "npm:^11.0.1"
- "@toruslabs/http-helpers": "npm:^4.0.0"
- loglevel: "npm:^1.8.1"
+ "@toruslabs/constants": "npm:^13.4.0"
+ "@toruslabs/fnd-base": "npm:^13.4.0"
+ "@toruslabs/http-helpers": "npm:^6.1.1"
+ loglevel: "npm:^1.9.1"
peerDependencies:
"@babel/runtime": 7.x
- checksum: 10/9ef0614db509538a007a294aeb59b36de9f2272c4f2c170413341e3deba155ad1ffa9573139554160bf730227f60be062fdacff8a8f923954debe8cd109f4d62
+ checksum: 10/515638ac2fb9298472db7b5945ab67fa8be6f9512e1b2a05f5f68e8a42dcaca71c64ab830b706da55dffe65cf542ef22a400070cb63736285f2613225c61e10e
languageName: node
linkType: hard
-"@toruslabs/fnd-base@npm:^11.0.1":
- version: 11.0.1
- resolution: "@toruslabs/fnd-base@npm:11.0.1"
+"@toruslabs/fnd-base@npm:^13.4.0":
+ version: 13.4.0
+ resolution: "@toruslabs/fnd-base@npm:13.4.0"
dependencies:
- "@toruslabs/constants": "npm:^11.0.0"
+ "@toruslabs/constants": "npm:^13.4.0"
peerDependencies:
"@babel/runtime": 7.x
- checksum: 10/773f59d53efc0ecc38f18677087c82648e3434c317331c6f25f1f4e06a804abf262a06b7ae56ad4854e3b5cb81aeea28109189e4bab78387e89c488bcb46e643
+ checksum: 10/e728642d476384e8bc5ab295bb4aaa995d35e4174aa04c2a92a1470c9cb4098de86e4e545801f41c823f42c67a7d60a825c0f83e0e6e88eb8b35d369bd7e8c7e
languageName: node
linkType: hard
-"@toruslabs/http-helpers@npm:^4.0.0":
- version: 4.0.0
- resolution: "@toruslabs/http-helpers@npm:4.0.0"
+"@toruslabs/http-helpers@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "@toruslabs/http-helpers@npm:5.0.0"
dependencies:
lodash.merge: "npm:^4.6.2"
loglevel: "npm:^1.8.1"
@@ -5743,40 +5751,56 @@ __metadata:
peerDependenciesMeta:
"@sentry/types":
optional: true
- checksum: 10/60a718a9ed760061fcf77e3bb7d0667a725278885b8e2d06fd270ba67391bcae5974cc25f59496848cee76e250fa1984197e89b8cd9ce3b0096eda12c4f7b0ac
+ checksum: 10/ae87bb8c8e73f3ccf7c62fd86e99129031726cddf51efad4420cea9ad053f2c98e06dcb0acddb7e0a67ff759cd16d2b9b672e6909dd779bcb39c8e9caa548505
languageName: node
linkType: hard
-"@toruslabs/metadata-helpers@npm:^4.0.0":
- version: 4.0.0
- resolution: "@toruslabs/metadata-helpers@npm:4.0.0"
+"@toruslabs/http-helpers@npm:^6.1.0, @toruslabs/http-helpers@npm:^6.1.1":
+ version: 6.1.1
+ resolution: "@toruslabs/http-helpers@npm:6.1.1"
dependencies:
- "@toruslabs/eccrypto": "npm:^3.0.0"
- "@toruslabs/http-helpers": "npm:^4.0.0"
- elliptic: "npm:^6.5.4"
- ethereum-cryptography: "npm:^2.0.0"
- json-stable-stringify: "npm:^1.0.2"
+ lodash.merge: "npm:^4.6.2"
+ loglevel: "npm:^1.9.1"
+ peerDependencies:
+ "@babel/runtime": ^7.x
+ "@sentry/types": ^7.x
+ peerDependenciesMeta:
+ "@sentry/types":
+ optional: true
+ checksum: 10/1d26bf7d3012d061b88792cb75ea604f0ffd4f220082d8c29bd59c028803f8b04d4366e47da270b711dde381a69c2d73defbfc944d9454d513f5ecf9d48d29da
+ languageName: node
+ linkType: hard
+
+"@toruslabs/metadata-helpers@npm:^5.0.0":
+ version: 5.1.0
+ resolution: "@toruslabs/metadata-helpers@npm:5.1.0"
+ dependencies:
+ "@toruslabs/eccrypto": "npm:^4.0.0"
+ "@toruslabs/http-helpers": "npm:^6.1.0"
+ elliptic: "npm:^6.5.5"
+ ethereum-cryptography: "npm:^2.1.3"
+ json-stable-stringify: "npm:^1.1.1"
peerDependencies:
"@babel/runtime": 7.x
- checksum: 10/99f8fd2ca91a570ee481dd0c1b495272c5db08120d3715de6dae3d14eae80a4e429c7861c163097a26e499e3731d9ca17f8cc2c0633d0b0ca731af6484779909
+ checksum: 10/1037864c0170240cf26af607ecb5443ddec169ce86101aec197bc71cc407602df8449cc2f44ccb4e7a4c7b989b01d0aabbc75a0c923a4004430ae5422896010b
languageName: node
linkType: hard
-"@toruslabs/torus.js@npm:^10.0.5":
- version: 10.0.5
- resolution: "@toruslabs/torus.js@npm:10.0.5"
+"@toruslabs/torus.js@npm:^11.0.5":
+ version: 11.0.6
+ resolution: "@toruslabs/torus.js@npm:11.0.6"
dependencies:
- "@toruslabs/constants": "npm:^11.0.0"
- "@toruslabs/eccrypto": "npm:^3.0.0"
- "@toruslabs/http-helpers": "npm:^4.0.0"
+ "@toruslabs/constants": "npm:^13.0.1"
+ "@toruslabs/eccrypto": "npm:^4.0.0"
+ "@toruslabs/http-helpers": "npm:^5.0.0"
bn.js: "npm:^5.2.1"
elliptic: "npm:^6.5.4"
- ethereum-cryptography: "npm:^2.0.0"
+ ethereum-cryptography: "npm:^2.1.2"
json-stable-stringify: "npm:^1.0.2"
loglevel: "npm:^1.8.1"
peerDependencies:
"@babel/runtime": 7.x
- checksum: 10/c046671a10658c41bfa9b106d472c1c2d8c6669d6b880916c0cb61d26f5cd7336389021332e06464e3097668bf1c7bb30bd38442c2a6024a7c51ffd662df36a9
+ checksum: 10/0c5afcf65eadd729782e4fd16b013cc22cdb229259c600d89c333fcd75bfc614ee60b8c874207e834cc53b23e6d538a26fe4fa45c57b7945099ec1af039b6724
languageName: node
linkType: hard
@@ -7589,6 +7613,13 @@ __metadata:
languageName: node
linkType: hard
+"base64url@npm:^3.0.1":
+ version: 3.0.1
+ resolution: "base64url@npm:3.0.1"
+ checksum: 10/a77b2a3a526b3343e25be424de3ae0aa937d78f6af7c813ef9020ef98001c0f4e2323afcd7d8b2d2978996bf8c42445c3e9f60c218c622593e5fdfd54a3d6e18
+ languageName: node
+ linkType: hard
+
"basic-auth@npm:^2.0.1":
version: 2.0.1
resolution: "basic-auth@npm:2.0.1"
@@ -9320,23 +9351,23 @@ __metadata:
languageName: node
linkType: hard
-"engine.io-client@npm:~6.5.1":
- version: 6.5.1
- resolution: "engine.io-client@npm:6.5.1"
+"engine.io-client@npm:~6.5.2":
+ version: 6.5.3
+ resolution: "engine.io-client@npm:6.5.3"
dependencies:
"@socket.io/component-emitter": "npm:~3.1.0"
debug: "npm:~4.3.1"
- engine.io-parser: "npm:~5.1.0"
+ engine.io-parser: "npm:~5.2.1"
ws: "npm:~8.11.0"
xmlhttprequest-ssl: "npm:~2.0.0"
- checksum: 10/827c6c203cd0cb113db99311ef34b74d424a6d6f2f61384d46cce9a8143dd27675f0fa046f7206aaac7f7611c25e7ba239fc2d531bffafaeac94628c70e94141
+ checksum: 10/0d7c3e6de23f37706c163bc8a0e90e70e613c7768be0705bda3675124d5e24d849810fddda005f8dcc721da35aee713976a03a0465d71f0856adfc1af7a80e5d
languageName: node
linkType: hard
-"engine.io-parser@npm:~5.1.0":
- version: 5.1.0
- resolution: "engine.io-parser@npm:5.1.0"
- checksum: 10/9997a91d0d609f95741fe68775947a0b5e2a4032ba7d15f4c14bfa4d70cca9d3a9e17575e1c9f6314ef002a966f243eb910cd0b537aeac7dbc27e6c4c26f60ec
+"engine.io-parser@npm:~5.2.1":
+ version: 5.2.2
+ resolution: "engine.io-parser@npm:5.2.2"
+ checksum: 10/135b1278547bde501412ac462e93b3b4f6a2fecc30a2b843bb9408b96301e8068bb2496c32d124a3d2544eb0aec8b8eddcb4ef0d0d0b84b7d642b1ffde1b2dcf
languageName: node
linkType: hard
@@ -10204,15 +10235,15 @@ __metadata:
languageName: node
linkType: hard
-"ethereum-cryptography@npm:^2.0.0":
- version: 2.0.0
- resolution: "ethereum-cryptography@npm:2.0.0"
+"ethereum-cryptography@npm:^2.1.2, ethereum-cryptography@npm:^2.1.3":
+ version: 2.1.3
+ resolution: "ethereum-cryptography@npm:2.1.3"
dependencies:
- "@noble/curves": "npm:1.0.0"
- "@noble/hashes": "npm:1.3.0"
- "@scure/bip32": "npm:1.3.0"
- "@scure/bip39": "npm:1.2.0"
- checksum: 10/1f87b4d322fce0801d38741955df1dec20861939ea0c0a89dddf182906f21453f7134662e09fe268e35be9a3848f61667349836b5eb5f4efd6b9a02c1e3bcc85
+ "@noble/curves": "npm:1.3.0"
+ "@noble/hashes": "npm:1.3.3"
+ "@scure/bip32": "npm:1.3.3"
+ "@scure/bip39": "npm:1.2.2"
+ checksum: 10/cc5aa9a4368dc1dd7680ba921957c098ced7b3d7dbb1666334013ab2f8d4cd25a785ad84e66fd9f5c5a9b6de337930ea24ff8c722938f36a9c00cec597ca16b5
languageName: node
linkType: hard
@@ -12735,12 +12766,15 @@ __metadata:
languageName: node
linkType: hard
-"json-stable-stringify@npm:^1.0.2":
- version: 1.0.2
- resolution: "json-stable-stringify@npm:1.0.2"
+"json-stable-stringify@npm:^1.0.2, json-stable-stringify@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "json-stable-stringify@npm:1.1.1"
dependencies:
+ call-bind: "npm:^1.0.5"
+ isarray: "npm:^2.0.5"
jsonify: "npm:^0.0.1"
- checksum: 10/96c8d697520072231c4916b7c0084ea857418cad0d06dc910f89a40df3824386a8eee5ed83ceea25b6052d67223fe821f9b1e51be311383104c5b2305b1dc87e
+ object-keys: "npm:^1.1.1"
+ checksum: 10/60853c1f63451319b5c7953465a555aa816cf84e60e3ca36b6c05225d8fdc4615127fb4ecb92f9f5ad880c552ab8cbae9a519f78b995e7788d6d89e57afafdeb
languageName: node
linkType: hard
@@ -12968,10 +13002,10 @@ __metadata:
languageName: node
linkType: hard
-"loglevel@npm:^1.8.1":
- version: 1.8.1
- resolution: "loglevel@npm:1.8.1"
- checksum: 10/36a786082a7e4f1d962de330122291da3a102b88dbde81a45eb92a045c38b0903783958ba39dce641440c0413da303410e7f2565f897bccad828853bd5974c86
+"loglevel@npm:^1.8.1, loglevel@npm:^1.9.1":
+ version: 1.9.1
+ resolution: "loglevel@npm:1.9.1"
+ checksum: 10/863cbbcddf850a937482c604e2d11586574a5110b746bb49c7cc04739e01f6035f6db841d25377106dd330bca7142d74995f15a97c5f3ea0af86d9472d4a99f4
languageName: node
linkType: hard
@@ -15930,15 +15964,15 @@ __metadata:
languageName: node
linkType: hard
-"socket.io-client@npm:^4.6.1":
- version: 4.7.1
- resolution: "socket.io-client@npm:4.7.1"
+"socket.io-client@npm:^4.7.2":
+ version: 4.7.5
+ resolution: "socket.io-client@npm:4.7.5"
dependencies:
"@socket.io/component-emitter": "npm:~3.1.0"
debug: "npm:~4.3.2"
- engine.io-client: "npm:~6.5.1"
+ engine.io-client: "npm:~6.5.2"
socket.io-parser: "npm:~4.2.4"
- checksum: 10/cc44661677c090d936853a37cde548c0fcf2638fbcc1713f065013b19df0fb30e07eee08d91d7e07f8fe7668b914dbc5d1341a94a133c0170aecc52a27a06e67
+ checksum: 10/a9e118081dc1669a63af3abd9defce94f85c8ed8d9146cd7a77665b5f1f78baf0b9f4155cf0fce7770856f97493416551abcba686f02778045f4768ceaafed5c
languageName: node
linkType: hard
@@ -17017,7 +17051,7 @@ __metadata:
"@testing-library/jest-dom": "npm:6.4.5"
"@testing-library/react": "npm:14.3.0"
"@testing-library/user-event": "npm:14.5.2"
- "@toruslabs/customauth": "npm:^15.0.5"
+ "@toruslabs/customauth": "npm:^16.0.6"
"@types/babel__core": "npm:^7"
"@types/babel__preset-env": "npm:^7"
"@types/identity-obj-proxy": "npm:^3"