diff --git a/CHANGELOG.md b/CHANGELOG.md index 439212c1..d1dcc67e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- [Added faucet and issue token](https://github.com/multiversx/mx-wallet-dapp/pull/41) - [Fixed package.json scripts](https://github.com/multiversx/mx-wallet-dapp/pull/39) - [Added gateway adapter](https://github.com/multiversx/mx-wallet-dapp/pull/35) diff --git a/package-lock.json b/package-lock.json index b02e5b1f..2669a0b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,8 @@ "moment": "2.29.4", "react": "18.2.0", "react-dom": "18.2.0", - "react-draggable-tags": "^1.0.6", + "react-draggable-tags": "1.0.6", + "react-google-recaptcha": "3.1.0", "react-qr-code": "2.0.14", "react-redux": "8.0.5", "react-router-dom": "6.16.0", @@ -58,6 +59,7 @@ "@types/puppeteer": "7.0.4", "@types/react": "18.2.23", "@types/react-dom": "18.2.8", + "@types/react-google-recaptcha": "2.1.9", "@types/react-router-dom": "5.3.3", "@typescript-eslint/eslint-plugin": "7.13.0", "@typescript-eslint/parser": "7.13.0", @@ -5841,6 +5843,14 @@ "node": ">=10" } }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true + }, "node_modules/@swc/jest": { "version": "0.2.27", "resolved": "https://registry.npmjs.org/@swc/jest/-/jest-0.2.27.tgz", @@ -5858,6 +5868,17 @@ "@swc/core": "*" } }, + "node_modules/@swc/types": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.12.tgz", + "integrity": "sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, "node_modules/@testing-library/dom": { "version": "9.3.4", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", @@ -6752,7 +6773,6 @@ "version": "18.2.23", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.23.tgz", "integrity": "sha512-qHLW6n1q2+7KyBEYnrZpcsAmU/iiCh9WGCKgXvMxx89+TYdJWRjZohVIo9XTcoLhfX3+/hP0Pbulu3bCZQ9PSA==", - "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -6764,7 +6784,6 @@ "version": "18.2.8", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.8.tgz", "integrity": "sha512-bAIvO5lN/U8sPGvs1Xm61rlRHHaq5rp5N3kp9C+NJ/Q41P8iqjkXSu0+/qu8POsjH9pNWb0OYabFez7taP7omw==", - "dev": true, "license": "MIT", "dependencies": { "@types/react": "*" @@ -6774,13 +6793,22 @@ "version": "18.3.3", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", - "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, + "node_modules/@types/react-google-recaptcha": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.9.tgz", + "integrity": "sha512-nT31LrBDuoSZJN4QuwtQSF3O89FVHC4jLhM+NtKEmVF5R1e8OY0Jo4//x2Yapn2aNHguwgX5doAq8Zo+Ehd0ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-router": { "version": "5.1.20", "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", @@ -6849,7 +6877,6 @@ "version": "0.23.0", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.23.0.tgz", "integrity": "sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==", - "dev": true, "license": "MIT" }, "node_modules/@types/stack-utils": { @@ -8667,6 +8694,20 @@ "dev": true, "license": "MIT" }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", @@ -8674,6 +8715,31 @@ "dev": true, "license": "MIT" }, + "node_modules/builtins": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", + "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/builtins/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -10401,6 +10467,37 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-compat-utils": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", + "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-compat-utils/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/eslint-config-prettier": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", @@ -10574,6 +10671,29 @@ "eslint": ">=4.19.1" } }, + "node_modules/eslint-plugin-es-x": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", + "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/ota-meshi", + "https://opencollective.com/eslint" + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.11.0", + "eslint-compat-utils": "^0.5.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": ">=8" + } + }, "node_modules/eslint-plugin-import": { "version": "2.28.1", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz", @@ -10623,6 +10743,81 @@ "dev": true, "license": "MIT" }, + "node_modules/eslint-plugin-n": { + "version": "16.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz", + "integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "builtins": "^5.0.1", + "eslint-plugin-es-x": "^7.5.0", + "get-tsconfig": "^4.7.0", + "globals": "^13.24.0", + "ignore": "^5.2.4", + "is-builtin-module": "^3.2.1", + "is-core-module": "^2.12.1", + "minimatch": "^3.1.2", + "resolve": "^1.22.2", + "semver": "^7.5.3" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-n/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-n/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-n/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint-plugin-node": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", @@ -12457,6 +12652,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -16881,6 +17093,19 @@ "node": ">=0.10.0" } }, + "node_modules/react-async-script": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz", + "integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==", + "license": "MIT", + "dependencies": { + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.0" + }, + "peerDependencies": { + "react": ">=16.4.1" + } + }, "node_modules/react-collapsed": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/react-collapsed/-/react-collapsed-3.6.0.tgz", @@ -16926,6 +17151,19 @@ "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==", "license": "MIT" }, + "node_modules/react-google-recaptcha": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz", + "integrity": "sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.5.0", + "react-async-script": "^1.2.0" + }, + "peerDependencies": { + "react": ">=16.4.1" + } + }, "node_modules/react-idle-timer": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/react-idle-timer/-/react-idle-timer-5.0.0.tgz", diff --git a/package.json b/package.json index 3807606d..c39a7a2d 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,8 @@ "moment": "2.29.4", "react": "18.2.0", "react-dom": "18.2.0", - "react-draggable-tags": "^1.0.6", + "react-draggable-tags": "1.0.6", + "react-google-recaptcha": "3.1.0", "react-qr-code": "2.0.14", "react-redux": "8.0.5", "react-router-dom": "6.16.0", @@ -85,6 +86,7 @@ "@types/puppeteer": "7.0.4", "@types/react": "18.2.23", "@types/react-dom": "18.2.8", + "@types/react-google-recaptcha": "2.1.9", "@types/react-router-dom": "5.3.3", "@typescript-eslint/eslint-plugin": "7.13.0", "@typescript-eslint/parser": "7.13.0", diff --git a/src/App.tsx b/src/App.tsx index 15675673..3f788e8a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,6 +3,7 @@ import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; import { PersistGate } from 'redux-persist/integration/react'; import { + AxiosInterceptor, AxiosInterceptorContext, DappProvider, Layout, @@ -48,22 +49,20 @@ const AppContent = () => { } }} > - - - - } /> - {routes.map((route) => ( - } - /> - ))} - } /> - - - - + + + } /> + {routes.map((route) => ( + } + /> + ))} + } /> + + + ); }; @@ -76,9 +75,11 @@ export const MainApp = () => { - - - + + + + + ); diff --git a/src/components/AxiosInterceptor/AxiosInterceptor.tsx b/src/components/AxiosInterceptor/AxiosInterceptor.tsx new file mode 100644 index 00000000..44375936 --- /dev/null +++ b/src/components/AxiosInterceptor/AxiosInterceptor.tsx @@ -0,0 +1,29 @@ +import React, { useEffect } from 'react'; +import { useGetAccount } from 'lib'; +import { + handleError, + useSetNativeAuthInterceptors, + useSetResponseInterceptors +} from './helpers'; + +export const AxiosInterceptor = ({ children }: React.PropsWithChildren) => { + const { setNativeAuthTokenInterceptors, nativeAuthToken } = + useSetNativeAuthInterceptors(); + const { address } = useGetAccount(); + const isLoggedIn = Boolean(address); + const { setResponseInterceptors, axiosErrorUrl } = + useSetResponseInterceptors(); + + useEffect(() => { + handleError(axiosErrorUrl); + }, [axiosErrorUrl]); + + useEffect(() => { + if (nativeAuthToken) { + setNativeAuthTokenInterceptors(nativeAuthToken); + setResponseInterceptors(); + } + }, [nativeAuthToken, isLoggedIn]); + + return <>{children}; +}; diff --git a/src/components/AxiosInterceptor/helpers/handleError.ts b/src/components/AxiosInterceptor/helpers/handleError.ts new file mode 100644 index 00000000..94f21415 --- /dev/null +++ b/src/components/AxiosInterceptor/helpers/handleError.ts @@ -0,0 +1,63 @@ +import { faWarning } from '@fortawesome/free-solid-svg-icons'; +import { addNewCustomToast } from 'lib'; +import { + CUSTOM_TOAST_DEFAULT_DURATION, + IS_DEVELOPMENT, + IS_TEST +} from 'localConstants'; +import { CustomToastType } from 'types'; +import { hash } from '../../../../version.json'; + +const IGNORED_LIST = [ + '/stake-pool', + '/version', + 'usernames/', + '/v1/login', + '/v1/users' +]; +const walletVersion = hash; +let isToastVisible = false; + +const createNotification = () => { + if (isToastVisible) { + return; + } + + isToastVisible = true; + + const newToast: CustomToastType = { + toastId: 'axiosError' + Date.now(), + type: 'custom', + message: 'Your funds are safe.', + duration: CUSTOM_TOAST_DEFAULT_DURATION, + title: 'Failed to display some information.', + status: 'Please try again later.', + icon: faWarning, + iconClassName: 'bg-warning' + }; + + addNewCustomToast(newToast); + + setTimeout(() => { + isToastVisible = false; + }, CUSTOM_TOAST_DEFAULT_DURATION); +}; + +export const handleError = (axiosErrorUrl: string) => { + if (IS_TEST) { + return; + } + + const logError = + axiosErrorUrl && !IGNORED_LIST.some((url) => axiosErrorUrl.includes(url)); + + if (!logError) { + return; + } + + const hasWalletVersion = walletVersion != null; + + if (!hasWalletVersion && IS_DEVELOPMENT) { + createNotification(); + } +}; diff --git a/src/components/AxiosInterceptor/helpers/index.ts b/src/components/AxiosInterceptor/helpers/index.ts new file mode 100644 index 00000000..3e4d506a --- /dev/null +++ b/src/components/AxiosInterceptor/helpers/index.ts @@ -0,0 +1,3 @@ +export * from './handleError'; +export * from './useSetNativeAuthInterceptors'; +export * from './useSetResponseInterceptors'; diff --git a/src/components/AxiosInterceptor/helpers/useSetNativeAuthInterceptors.ts b/src/components/AxiosInterceptor/helpers/useSetNativeAuthInterceptors.ts new file mode 100644 index 00000000..22942f52 --- /dev/null +++ b/src/components/AxiosInterceptor/helpers/useSetNativeAuthInterceptors.ts @@ -0,0 +1,79 @@ +import axios from 'axios'; +import { useSelector } from 'react-redux'; +import { retry } from 'helpers'; +import { useAxiosInterceptorContext } from 'lib'; +import { IS_TEST } from 'localConstants'; +import { accountSelector } from 'redux/selectors'; + +let nativeAuthToken: string | undefined; +let requestInterceptorId = -1; + +export const useSetNativeAuthInterceptors = () => { + const { + loginInfo: { tokenLogin } + } = useAxiosInterceptorContext(); + const { externalNativeAuthToken } = useSelector(accountSelector); + nativeAuthToken = externalNativeAuthToken || tokenLogin?.nativeAuthToken; + + /** + * `isLoggedIn` gets set before token arrives, so this polling makes + * `axios` wait until token arrives + */ + const getToken = async (): Promise => { + const pollForToken = () => + new Promise(function (resolve, reject) { + if (nativeAuthToken) { + resolve(nativeAuthToken); + } + + return IS_TEST + ? resolve('Auth token not found') + : reject('Auth token not found'); + }); + + return retry({ + fn: pollForToken, + retries: 3, + error: 'Auth token not found' + }); + }; + + const setNativeAuthTokenInterceptors = ( + newToken?: string, + onRequest?: () => void + ) => { + axios.interceptors.request.eject(requestInterceptorId); + requestInterceptorId = axios.interceptors.request.use( + async (config) => { + onRequest?.(); + + let bearerToken = newToken; + const hasAllowedURLs = + config.baseURL?.includes('extras-api.multiversx.com') || + config.baseURL?.includes('api.xportal.com') || + config.baseURL?.includes('tools.multiversx.com'); + + if (hasAllowedURLs) { + try { + bearerToken = await getToken(); + } catch (error) { + console.log(error); + } + } + + if (!bearerToken) { + return config; + } + + config.headers.set('Authorization', `Bearer ${bearerToken}`); + + return config; + }, + (error) => { + Promise.reject(error); + } + ); + }; + + return { nativeAuthToken, setNativeAuthTokenInterceptors }; +}; diff --git a/src/components/AxiosInterceptor/helpers/useSetResponseInterceptors.ts b/src/components/AxiosInterceptor/helpers/useSetResponseInterceptors.ts new file mode 100644 index 00000000..1867ff48 --- /dev/null +++ b/src/components/AxiosInterceptor/helpers/useSetResponseInterceptors.ts @@ -0,0 +1,34 @@ +import { useState } from 'react'; +import axios from 'axios'; + +export const useSetResponseInterceptors = () => { + const [responseId, setResponseId] = useState(-1); + const [axiosErrorUrl, setAxiosErrorUrl] = useState(''); + + const setResponseInterceptors = () => { + const newResponseId = axios.interceptors.response.use( + (response) => response, + (error) => { + let url = error.config.url; + if (error.config.params) { + const queryString = new URLSearchParams(error.config.params); + url += `?${queryString.toString()}`; + } + try { + const { pathname } = new URL(url); + if (pathname === '/websocket/config') { + // send event to InternalTestnetLoop + const customEvent = new CustomEvent('wsFailed'); + document.dispatchEvent(customEvent); + } + } catch {} + + setAxiosErrorUrl(url); + return Promise.reject(error); + } + ); + setResponseId(newResponseId); + }; + + return { setResponseInterceptors, responseId, axiosErrorUrl }; +}; diff --git a/src/components/AxiosInterceptor/index.tsx b/src/components/AxiosInterceptor/index.tsx new file mode 100644 index 00000000..4ac8f31a --- /dev/null +++ b/src/components/AxiosInterceptor/index.tsx @@ -0,0 +1 @@ +export * from './AxiosInterceptor'; diff --git a/src/components/NetworkSwitcher/NetworkSwitcher.tsx b/src/components/NetworkSwitcher/NetworkSwitcher.tsx index 12d84b6e..1335ed8c 100644 --- a/src/components/NetworkSwitcher/NetworkSwitcher.tsx +++ b/src/components/NetworkSwitcher/NetworkSwitcher.tsx @@ -1,12 +1,13 @@ -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import { networks } from 'config'; import { networkSelector } from 'redux/selectors'; -import { changeNetwork } from 'redux/slices'; +import { useRefreshNativeAuthTokenForNetwork } from './hooks'; import { Dropdown, DropdownOption } from '../Dropdown'; export const NetworkSwitcher = () => { const { activeNetwork } = useSelector(networkSelector); - const dispatch = useDispatch(); + const refreshNativeAuthTokenForNetwork = + useRefreshNativeAuthTokenForNetwork(); const networkOptions = networks.map((network) => ({ label: network.name, value: network.id @@ -17,7 +18,7 @@ export const NetworkSwitcher = () => { value: activeNetwork.id }; - const handleNetworkSwitch = (option: DropdownOption) => { + const handleNetworkSwitch = async (option: DropdownOption) => { const selectedNetwork = networks.find( (network) => network.id === option.value ); @@ -26,7 +27,11 @@ export const NetworkSwitcher = () => { return; } - dispatch(changeNetwork(selectedNetwork)); + await refreshNativeAuthTokenForNetwork({ + networkId: selectedNetwork.id, + origin: window.location.origin, + signMessageCallback: (messageToSign) => Promise.resolve(messageToSign) + }); }; return ( diff --git a/src/components/NetworkSwitcher/hooks/index.ts b/src/components/NetworkSwitcher/hooks/index.ts new file mode 100644 index 00000000..a9ad4d2f --- /dev/null +++ b/src/components/NetworkSwitcher/hooks/index.ts @@ -0,0 +1 @@ +export * from './useRefreshNativeAuthTokenForNetwork'; diff --git a/src/components/NetworkSwitcher/hooks/useRefreshNativeAuthTokenForNetwork.ts b/src/components/NetworkSwitcher/hooks/useRefreshNativeAuthTokenForNetwork.ts new file mode 100644 index 00000000..4ad77f6f --- /dev/null +++ b/src/components/NetworkSwitcher/hooks/useRefreshNativeAuthTokenForNetwork.ts @@ -0,0 +1,49 @@ +import { SignableMessage } from '@multiversx/sdk-core/out'; +import { useDispatch } from 'react-redux'; +import { useSetNativeAuthInterceptors } from 'components/AxiosInterceptor/helpers'; +import { networks } from 'config'; +import { useLoginService } from 'lib'; +import { useGetNativeAuthConfig } from 'pages/Unlock/hooks'; +import { changeNetwork } from 'redux/slices'; + +export const useRefreshNativeAuthTokenForNetwork = () => { + const nativeAuthConfig = useGetNativeAuthConfig(); + const loginService = useLoginService(nativeAuthConfig); + const dispatch = useDispatch(); + const { setNativeAuthTokenInterceptors } = useSetNativeAuthInterceptors(); + + return async ({ + networkId, + origin, + signMessageCallback + }: { + networkId: string; + origin: string; + signMessageCallback: ( + messageToSign: SignableMessage + ) => Promise; + }) => { + const foundNetwork = networks.find(({ id }) => id === networkId); + + if (!foundNetwork) { + return; + } + + try { + const nativeAuthToken = await loginService.refreshNativeAuthTokenLogin({ + signMessageCallback, + nativeAuthClientConfig: { + origin, + apiAddress: foundNetwork?.apiAddress, + expirySeconds: 86400 + } + }); + + setNativeAuthTokenInterceptors(nativeAuthToken); + } catch (error) { + console.error('Could not refresh nativeAuth token', error); + } + + dispatch(changeNetwork(foundNetwork)); + }; +}; diff --git a/src/components/Utilities/Utilities.tsx b/src/components/Utilities/Utilities.tsx index c65058cc..d374f843 100644 --- a/src/components/Utilities/Utilities.tsx +++ b/src/components/Utilities/Utilities.tsx @@ -1,5 +1,9 @@ import { useSelector } from 'react-redux'; -import { TransactionsToastList, NotificationModal } from 'components'; +import { + TransactionsToastList, + NotificationModal, + AxiosInterceptorContext +} from 'components'; import { CUSTOM_TOAST_DEFAULT_DURATION } from 'localConstants'; import { hookSelector } from 'redux/selectors'; import { PostMessageListener, SendModals, SignModals } from './components'; @@ -19,6 +23,7 @@ export const Utilities = () => { + ); }; diff --git a/src/components/index.ts b/src/components/index.ts index 4019981b..9f3a8ee3 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,3 +1,4 @@ +export * from './AxiosInterceptor'; export * from './Button'; export * from './Card'; export * from './Copy'; diff --git a/src/config/config.devnet.ts b/src/config/config.devnet.ts index 7e3a4527..697b604b 100644 --- a/src/config/config.devnet.ts +++ b/src/config/config.devnet.ts @@ -10,8 +10,10 @@ export const networks: NetworkType[] = [ name: 'Devnet', apiAddress: 'https://devnet-api.multiversx.com', gatewayUrl: '', + extrasApi: 'https://devnet-extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://devnet-api.multiversx.com'], sovereignContractAddress: '', + walletAddress: 'https://devnet-wallet.multiversx.com', WEGLDid: '' }, { @@ -20,8 +22,10 @@ export const networks: NetworkType[] = [ name: 'Gateway', apiAddress: '', gatewayUrl: 'https://devnet-gateway.multiversx.com', + extrasApi: 'https://devnet-extras-api.multiversx.com', sampleAuthenticatedDomains: [''], sovereignContractAddress: '', + walletAddress: 'https://devnet-wallet.multiversx.com', WEGLDid: '' }, { @@ -30,8 +34,10 @@ export const networks: NetworkType[] = [ name: 'Mainnet', apiAddress: 'https://api.multiversx.com', gatewayUrl: '', + extrasApi: 'https://extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://api.multiversx.com'], sovereignContractAddress: '', + walletAddress: 'https://wallet.multiversx.com', WEGLDid: '' }, { @@ -40,9 +46,11 @@ export const networks: NetworkType[] = [ name: 'Sovereign', apiAddress: 'https://api-sovereign-test.elrond.ro', gatewayUrl: '', + extrasApi: 'https://extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://api-sovereign-test.elrond.ro'], sovereignContractAddress: 'erd1qqqqqqqqqqqqqpgqfcm6l6rd42hwhskmk4thlp9kz58npfq50gfqdrthqa', + walletAddress: 'https://wallet.voyager1.dev', WEGLDid: 'WEGLD-bd4d79' }, { @@ -51,8 +59,10 @@ export const networks: NetworkType[] = [ name: 'Testnet', apiAddress: 'https://testnet-api.multiversx.com', gatewayUrl: '', + extrasApi: 'https://testnet-extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://testnet-api.multiversx.com'], sovereignContractAddress: '', + walletAddress: 'https://testnet-wallet.multiversx.com', WEGLDid: '' } ]; diff --git a/src/config/config.gateway.ts b/src/config/config.gateway.ts index 1acbbd52..f26160df 100644 --- a/src/config/config.gateway.ts +++ b/src/config/config.gateway.ts @@ -10,8 +10,10 @@ export const networks: NetworkType[] = [ name: 'Devnet', apiAddress: 'https://devnet-api.multiversx.com', gatewayUrl: '', + extrasApi: 'https://devnet-extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://devnet-api.multiversx.com'], sovereignContractAddress: '', + walletAddress: 'https://devnet-wallet.multiversx.com', WEGLDid: '' }, { @@ -20,8 +22,10 @@ export const networks: NetworkType[] = [ name: 'Gateway', apiAddress: '', gatewayUrl: 'https://devnet-gateway.multiversx.com', + extrasApi: 'https://devnet-extras-api.multiversx.com', sampleAuthenticatedDomains: [''], sovereignContractAddress: '', + walletAddress: 'https://devnet-wallet.multiversx.com', WEGLDid: '' }, { @@ -30,8 +34,10 @@ export const networks: NetworkType[] = [ name: 'Mainnet', apiAddress: 'https://api.multiversx.com', gatewayUrl: '', + extrasApi: 'https://extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://api.multiversx.com'], sovereignContractAddress: '', + walletAddress: 'https://wallet.multiversx.com', WEGLDid: '' }, { @@ -40,9 +46,11 @@ export const networks: NetworkType[] = [ name: 'Sovereign', apiAddress: 'https://api-sovereign-test.elrond.ro', gatewayUrl: '', + extrasApi: 'https://extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://api-sovereign-test.elrond.ro'], sovereignContractAddress: 'erd1qqqqqqqqqqqqqpgqfcm6l6rd42hwhskmk4thlp9kz58npfq50gfqdrthqa', + walletAddress: 'https://wallet.voyager1.dev', WEGLDid: 'WEGLD-bd4d79' }, { @@ -51,8 +59,10 @@ export const networks: NetworkType[] = [ name: 'Testnet', apiAddress: 'https://testnet-api.multiversx.com', gatewayUrl: '', + extrasApi: 'https://testnet-extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://testnet-api.multiversx.com'], sovereignContractAddress: '', + walletAddress: 'https://testnet-wallet.multiversx.com', WEGLDid: '' } ]; diff --git a/src/config/config.mainnet.ts b/src/config/config.mainnet.ts index 490f7767..81d8952c 100644 --- a/src/config/config.mainnet.ts +++ b/src/config/config.mainnet.ts @@ -10,8 +10,10 @@ export const networks: NetworkType[] = [ name: 'Devnet', apiAddress: 'https://devnet-api.multiversx.com', gatewayUrl: '', + extrasApi: 'https://devnet-extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://devnet-api.multiversx.com'], sovereignContractAddress: '', + walletAddress: 'https://devnet-wallet.multiversx.com', WEGLDid: '' }, { @@ -20,8 +22,10 @@ export const networks: NetworkType[] = [ name: 'Gateway', apiAddress: '', gatewayUrl: 'https://devnet-gateway.multiversx.com', + extrasApi: 'https://devnet-extras-api.multiversx.com', sampleAuthenticatedDomains: [''], sovereignContractAddress: '', + walletAddress: 'https://devnet-wallet.multiversx.com', WEGLDid: '' }, { @@ -30,8 +34,10 @@ export const networks: NetworkType[] = [ name: 'Mainnet', apiAddress: 'https://api.multiversx.com', gatewayUrl: '', + extrasApi: 'https://extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://api.multiversx.com'], sovereignContractAddress: '', + walletAddress: 'https://wallet.multiversx.com', WEGLDid: '' }, { @@ -40,9 +46,11 @@ export const networks: NetworkType[] = [ name: 'Sovereign', apiAddress: 'https://api-sovereign-test.elrond.ro', gatewayUrl: '', + extrasApi: 'https://extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://api-sovereign-test.elrond.ro'], sovereignContractAddress: 'erd1qqqqqqqqqqqqqpgqfcm6l6rd42hwhskmk4thlp9kz58npfq50gfqdrthqa', + walletAddress: 'https://wallet.voyager1.dev', WEGLDid: 'WEGLD-bd4d79' }, { @@ -51,8 +59,10 @@ export const networks: NetworkType[] = [ name: 'Testnet', apiAddress: 'https://testnet-api.multiversx.com', gatewayUrl: '', + extrasApi: 'https://testnet-extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://testnet-api.multiversx.com'], sovereignContractAddress: '', + walletAddress: 'https://testnet-wallet.multiversx.com', WEGLDid: '' } ]; diff --git a/src/config/config.sovereign.ts b/src/config/config.sovereign.ts index d919fff9..d9ee6b5f 100644 --- a/src/config/config.sovereign.ts +++ b/src/config/config.sovereign.ts @@ -10,8 +10,10 @@ export const networks: NetworkType[] = [ name: 'Devnet', apiAddress: 'https://devnet-api.multiversx.com', gatewayUrl: '', + extrasApi: 'https://devnet-extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://devnet-api.multiversx.com'], sovereignContractAddress: '', + walletAddress: 'https://devnet-wallet.multiversx.com', WEGLDid: '' }, { @@ -20,8 +22,10 @@ export const networks: NetworkType[] = [ name: 'Gateway', apiAddress: '', gatewayUrl: 'https://devnet-gateway.multiversx.com', + extrasApi: 'https://devnet-extras-api.multiversx.com', sampleAuthenticatedDomains: [''], sovereignContractAddress: '', + walletAddress: 'https://devnet-wallet.multiversx.com', WEGLDid: '' }, { @@ -30,8 +34,10 @@ export const networks: NetworkType[] = [ name: 'Mainnet', apiAddress: 'https://api.multiversx.com', gatewayUrl: '', + extrasApi: 'https://extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://api.multiversx.com'], sovereignContractAddress: '', + walletAddress: 'https://wallet.multiversx.com', WEGLDid: '' }, { @@ -40,9 +46,11 @@ export const networks: NetworkType[] = [ name: 'Sovereign', apiAddress: 'https://api-sovereign-test.elrond.ro', gatewayUrl: '', + extrasApi: 'https://extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://api-sovereign-test.elrond.ro'], sovereignContractAddress: 'erd1qqqqqqqqqqqqqpgqfcm6l6rd42hwhskmk4thlp9kz58npfq50gfqdrthqa', + walletAddress: 'https://wallet.voyager1.dev', WEGLDid: 'WEGLD-bd4d79' }, { @@ -51,8 +59,10 @@ export const networks: NetworkType[] = [ name: 'Testnet', apiAddress: 'https://testnet-api.multiversx.com', gatewayUrl: '', + extrasApi: 'https://testnet-extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://testnet-api.multiversx.com'], sovereignContractAddress: '', + walletAddress: 'https://testnet-wallet.multiversx.com', WEGLDid: '' } ]; diff --git a/src/config/config.testnet.ts b/src/config/config.testnet.ts index eccf3f2a..7fb6863a 100644 --- a/src/config/config.testnet.ts +++ b/src/config/config.testnet.ts @@ -10,18 +10,22 @@ export const networks: NetworkType[] = [ name: 'Devnet', apiAddress: 'https://devnet-api.multiversx.com', gatewayUrl: '', + extrasApi: 'https://devnet-extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://devnet-api.multiversx.com'], sovereignContractAddress: '', + walletAddress: 'https://devnet-wallet.multiversx.com', WEGLDid: '' }, { - default: true, + default: false, id: EnvironmentsEnum.devnet, name: 'Gateway', apiAddress: '', gatewayUrl: 'https://devnet-gateway.multiversx.com', + extrasApi: 'https://devnet-extras-api.multiversx.com', sampleAuthenticatedDomains: [''], sovereignContractAddress: '', + walletAddress: 'https://devnet-wallet.multiversx.com', WEGLDid: '' }, { @@ -30,8 +34,10 @@ export const networks: NetworkType[] = [ name: 'Mainnet', apiAddress: 'https://api.multiversx.com', gatewayUrl: '', + extrasApi: 'https://extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://api.multiversx.com'], sovereignContractAddress: '', + walletAddress: 'https://wallet.multiversx.com', WEGLDid: '' }, { @@ -40,9 +46,11 @@ export const networks: NetworkType[] = [ name: 'Sovereign', apiAddress: 'https://api-sovereign-test.elrond.ro', gatewayUrl: '', + extrasApi: 'https://extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://api-sovereign-test.elrond.ro'], sovereignContractAddress: 'erd1qqqqqqqqqqqqqpgqfcm6l6rd42hwhskmk4thlp9kz58npfq50gfqdrthqa', + walletAddress: 'https://wallet.voyager1.dev', WEGLDid: 'WEGLD-bd4d79' }, { @@ -51,8 +59,10 @@ export const networks: NetworkType[] = [ name: 'Testnet', apiAddress: 'https://testnet-api.multiversx.com', gatewayUrl: '', + extrasApi: 'https://testnet-extras-api.multiversx.com', sampleAuthenticatedDomains: ['https://testnet-api.multiversx.com'], sovereignContractAddress: '', + walletAddress: 'https://testnet-wallet.multiversx.com', WEGLDid: '' } ]; diff --git a/src/config/sharedConfig.ts b/src/config/sharedConfig.ts index 081361a1..6751a6c1 100644 --- a/src/config/sharedConfig.ts +++ b/src/config/sharedConfig.ts @@ -1,6 +1,8 @@ // Generate your own WalletConnect 2 ProjectId here: https://cloud.walletconnect.com/app export const walletConnectV2ProjectId = '9b1a9564f91cb659ffe21b73d5c4e2d8'; export const apiTimeout = 6000; +export const faucetEndpoint = '/faucet'; +export const faucetSettingEndpoint = `${faucetEndpoint}/settings`; export const transactionSize = 10; export const nativeAuth = true; export const BATCH_TRANSACTIONS_SC = { diff --git a/src/helpers/api/getAxiosConfig.ts b/src/helpers/api/getAxiosConfig.ts new file mode 100644 index 00000000..bff41623 --- /dev/null +++ b/src/helpers/api/getAxiosConfig.ts @@ -0,0 +1,10 @@ +import { AxiosRequestConfig } from 'axios'; +import { apiTimeout } from 'config'; +import { getBaseURL } from './getBaseURL'; + +export const getAxiosConfig = (url: string): AxiosRequestConfig => ({ + baseURL: getBaseURL(), + url, + method: 'GET', + timeout: apiTimeout +}); diff --git a/src/helpers/api/getBaseURL.ts b/src/helpers/api/getBaseURL.ts index 107ebd30..6e90ee2c 100644 --- a/src/helpers/api/getBaseURL.ts +++ b/src/helpers/api/getBaseURL.ts @@ -1,11 +1,7 @@ -import { networkSelector } from 'redux/selectors'; -import { RootState, store } from 'redux/store'; +import { getCurrentNetwork } from './getCurrentNetwork'; export function getBaseURL() { - const state: RootState = store.getState(); - const { - activeNetwork: { apiAddress } - } = networkSelector(state); + const { apiAddress } = getCurrentNetwork(); return apiAddress; } diff --git a/src/helpers/api/getExtrasApi.ts b/src/helpers/api/getExtrasApi.ts new file mode 100644 index 00000000..54636033 --- /dev/null +++ b/src/helpers/api/getExtrasApi.ts @@ -0,0 +1,7 @@ +import { getCurrentNetwork } from './getCurrentNetwork'; + +export function getExtrasApi() { + const { extrasApi } = getCurrentNetwork(); + + return extrasApi; +} diff --git a/src/helpers/api/index.ts b/src/helpers/api/index.ts index cd0a21a6..d110533e 100644 --- a/src/helpers/api/index.ts +++ b/src/helpers/api/index.ts @@ -1,2 +1,5 @@ +export * from './getAxiosConfig'; export * from './getBaseURL'; export * from './getCurrentNetwork'; +export * from './getExtrasApi'; +export * from './retry'; diff --git a/src/helpers/api/retry.ts b/src/helpers/api/retry.ts new file mode 100644 index 00000000..889d4eca --- /dev/null +++ b/src/helpers/api/retry.ts @@ -0,0 +1,17 @@ +export const retry = (props: { + fn: () => any; + retries: number; + error: string; +}) => { + const { fn, error = '', retries = 3 } = props; + + if (!retries) { + return Promise.reject(error); + } + + return fn().catch((err: any) => { + return setTimeout(() => { + retry({ fn, error: err, retries: retries - 1 }); + }, 100); + }); +}; diff --git a/src/lib/sdkDapp.ts b/src/lib/sdkDapp.ts index 47ef958b..1e60c438 100644 --- a/src/lib/sdkDapp.ts +++ b/src/lib/sdkDapp.ts @@ -63,3 +63,10 @@ export { setTransactionsToSignedState } from '@multiversx/sdk-dapp/services/transactions/updateSignedTransactions'; export { sendBatchTransactions } from '@multiversx/sdk-dapp/services/transactions/sendBatchTransactions'; +export { useAxiosInterceptorContext } from '@multiversx/sdk-dapp/wrappers/AxiosInterceptorContext'; +export { storage } from '@multiversx/sdk-dapp/utils/storage'; +export { addNewCustomToast } from '@multiversx/sdk-dapp/utils/toasts'; +export { + maxDecimals, + stringIsFloat +} from '@multiversx/sdk-dapp/utils/validation'; diff --git a/src/localConstants/dataTestIds.enum.ts b/src/localConstants/dataTestIds.enum.ts index 70c510e2..8d09c94e 100644 --- a/src/localConstants/dataTestIds.enum.ts +++ b/src/localConstants/dataTestIds.enum.ts @@ -1,14 +1,15 @@ export enum DataTestIdsEnum { accessPass = 'accessPass', accessWalletBtn = 'accessWalletBtn', + activeNetwork = 'activeNetwork', addTokenBtn = 'addTokenBtn', amountError = 'amountError', amountInput = 'amountInput', availableAmount = 'availableAmount', backToWordsButton = 'backToWordsButton', cancelBtn = 'cancelBtn', - activeNetwork = 'activeNetwork', cancelSignMessageBtn = 'cancelSignMessageBtn', + captcha = 'captcha', check = 'check', checkNetwork = 'checkNetwork', closeButton = 'closeButton', @@ -30,8 +31,11 @@ export enum DataTestIdsEnum { gasLimitInput = 'gasLimitInput', goToCheckMnemonic = 'goToCheckMnemonic', goToDownloadButton = 'goToDownloadButton', + issueTokenBtn = 'issueTokenBtn', keystoreBtn = 'keystoreBtn', logoutBtn = 'logoutBtn', + mintedValueError = 'mintedValueError', + mintedValueInput = 'mintedValueInput', mnemonicCheck = 'mnemonicCheck', mnemonicInput = 'mnemonicInput', mnemonicWord = 'mnemonicWord', @@ -39,6 +43,9 @@ export enum DataTestIdsEnum { mnemonicsDisclaimer = 'mnemonicsDisclaimer', modalSubtitle = 'modalSubtitle', modalTitle = 'modalTitle', + networkSwitcher = 'networkSwitcher', + numDecimalsError = 'numDecimalsError', + numDecimalsInput = 'numDecimalsInput', password = 'password', passwordError = 'passwordError', passwordRepeat = 'passwordRepeat', @@ -48,7 +55,7 @@ export enum DataTestIdsEnum { receiverInput = 'receiverInput', recoverWalletBtn = 'recoverWalletBtn', removeTokenBtn = 'removeTokenBtn', - networkSwitcher = 'networkSwitcher', + requestTokensButton = 'requestTokensButton', sendBtn = 'sendBtn', sendEsdtTypeInput = 'sendEsdtTypeInput', sendNFtTypeInput = 'sendNFtTypeInput', @@ -59,6 +66,10 @@ export enum DataTestIdsEnum { sovereignTransferBtn = 'sovereignTransferBtn', submitButton = 'submitButton', tokenError = 'tokenError', + tokenNameError = 'tokenNameError', + tokenNameInput = 'tokenNameInput', + tokenTickerError = 'tokenTickerError', + tokenTickerInput = 'tokenTickerInput', transactionToastTitle = 'transactionToastTitle', unlockPage = 'unlockPage', userAddress = 'userAddress', diff --git a/src/localConstants/misc.ts b/src/localConstants/misc.ts index 12f9f2bd..0266a51d 100644 --- a/src/localConstants/misc.ts +++ b/src/localConstants/misc.ts @@ -3,3 +3,4 @@ export const WALLET_FILE = 'walletFile'; export const MAX_ALLOWED_TRANSACTIONS_TO_SIGN = 5; export const CUSTOM_TOAST_DEFAULT_DURATION = 5000; export const SOVEREIGN_TRANSFER_GAS_LIMIT = 20_000_000; +export const TOKEN_KEY = 'token'; diff --git a/src/localConstants/routes/routeNames.enums.ts b/src/localConstants/routes/routeNames.enums.ts index 8e177f93..14baa4cc 100644 --- a/src/localConstants/routes/routeNames.enums.ts +++ b/src/localConstants/routes/routeNames.enums.ts @@ -14,7 +14,8 @@ export enum RouteNamesEnum { logout = '/logout', sign = '/sign', signMessage = '/sign-message', - sovereignTransfer = '/sovereign-transfer' + sovereignTransfer = '/sovereign-transfer', + issueToken = '/issue-token' } export enum HooksPageEnum { diff --git a/src/pages/CreateRecover/components/RecoverMnemonics/hooks/useRecoverMnemonics.ts b/src/pages/CreateRecover/components/RecoverMnemonics/hooks/useRecoverMnemonics.ts index 6b89b111..f632e0a7 100644 --- a/src/pages/CreateRecover/components/RecoverMnemonics/hooks/useRecoverMnemonics.ts +++ b/src/pages/CreateRecover/components/RecoverMnemonics/hooks/useRecoverMnemonics.ts @@ -15,7 +15,7 @@ export const useRecoverMnemonics = ({ setMnemonic }: RecoverMnemonicsPropsType) => { const [words, setWords] = useState([]); - const [error, setError] = useState(''); + const [error, setError] = useState(''); const [inputValue, setInputValue] = useState({ label: '', value: '' diff --git a/src/pages/Dashboard/widgets/Account/Account.tsx b/src/pages/Dashboard/widgets/Account/Account.tsx index cb9cd8d0..67cdd59a 100644 --- a/src/pages/Dashboard/widgets/Account/Account.tsx +++ b/src/pages/Dashboard/widgets/Account/Account.tsx @@ -3,6 +3,7 @@ import { Copy, MxLink } from 'components'; import { FormatAmount } from 'components/sdkDapp.components'; import { useGetAccountInfo, useGetNetworkConfig } from 'lib'; import { DataTestIdsEnum } from 'localConstants'; +import { Faucet } from 'pages/Faucet'; import { explorerAddressSelector, useSdkDappSelector @@ -53,7 +54,7 @@ export const Account = () => { -
diff --git a/src/pages/Dashboard/widgets/Tokens/Tokens.tsx b/src/pages/Dashboard/widgets/Tokens/Tokens.tsx index b050cfc8..6821c04a 100644 --- a/src/pages/Dashboard/widgets/Tokens/Tokens.tsx +++ b/src/pages/Dashboard/widgets/Tokens/Tokens.tsx @@ -1,7 +1,9 @@ import { useEffect } from 'react'; -import { OutputContainer } from 'components'; +import { MxLink, OutputContainer } from 'components'; import { useGetAccountInfo } from 'lib'; +import { DataTestIdsEnum } from 'localConstants'; import { useLazyGetTokensQuery } from 'redux/endpoints'; +import { routeNames } from 'routes'; import { TokenType } from 'types'; import { TokenRow } from './components'; @@ -28,6 +30,15 @@ export const Tokens = () => { ))} +
+ + Issue Token + +
); }; diff --git a/src/pages/Faucet/Faucet.tsx b/src/pages/Faucet/Faucet.tsx new file mode 100644 index 00000000..9669197c --- /dev/null +++ b/src/pages/Faucet/Faucet.tsx @@ -0,0 +1,29 @@ +import { Button, ModalContainer, PrivateKeyCheckWrapper } from 'components'; +import { DataTestIdsEnum } from 'localConstants'; +import { FaucetModal } from './components/FaucetModal'; +import { useModal } from '../../hooks'; + +export const Faucet = () => { + const { show, handleShow, handleClose } = useModal(); + + return ( + <> + + + + + + + + ); +}; diff --git a/src/pages/Faucet/components/FaucetError/FaucetError.tsx b/src/pages/Faucet/components/FaucetError/FaucetError.tsx new file mode 100644 index 00000000..94dee761 --- /dev/null +++ b/src/pages/Faucet/components/FaucetError/FaucetError.tsx @@ -0,0 +1,25 @@ +import { faTimes } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { DataTestIdsEnum } from 'localConstants'; + +export const FaucetError = ({ message }: { message: string }) => ( +
+

+ Failed +

+ +

+ {message} +

+
+); diff --git a/src/pages/Faucet/components/FaucetError/index.ts b/src/pages/Faucet/components/FaucetError/index.ts new file mode 100644 index 00000000..f6e717c5 --- /dev/null +++ b/src/pages/Faucet/components/FaucetError/index.ts @@ -0,0 +1 @@ +export * from './FaucetError'; diff --git a/src/pages/Faucet/components/FaucetModal/FaucetModal.tsx b/src/pages/Faucet/components/FaucetModal/FaucetModal.tsx new file mode 100644 index 00000000..06705ede --- /dev/null +++ b/src/pages/Faucet/components/FaucetModal/FaucetModal.tsx @@ -0,0 +1,72 @@ +import { useRef, useState } from 'react'; + +import { Loader } from 'components'; +import { getEgldLabel } from 'lib'; +import { DataTestIdsEnum } from 'localConstants'; + +import { + useGetFaucetSettingsQuery, + useRequestFundsMutation +} from 'redux/endpoints'; +import { FaucetError } from '../FaucetError'; +import { FaucetScreen } from '../FaucetScreen'; +import { FaucetSuccess } from '../FaucetSuccess'; + +export const FaucetModal = () => { + const ref = useRef(null); + const [getFunds, { isSuccess }] = useRequestFundsMutation(); + const [fundsReceived, setFundsReceived] = useState(false); + const [requestFailed, setRequestFailed] = useState(''); + + const { data: settings, error: settingsError } = useGetFaucetSettingsQuery(); + const egldLabel = getEgldLabel(); + + const handleRequestClick = async (captcha: string) => { + const response = await getFunds(captcha); + + if ('error' in response) { + setRequestFailed( + (response.error as any).data.message || + 'The faucet is available once every 24 hours.' + ); + } + + if (ref.current !== null) { + setFundsReceived(true); + } + }; + + if (settingsError) { + return ; + } + + if (!settings) { + return ( +
+

+ {egldLabel} Faucet +

+ +
+ ); + } + + if (requestFailed) { + return ; + } + + const showFaucetScreen = !fundsReceived && !isSuccess; + + return ( +
+ {showFaucetScreen ? ( + + ) : ( + + )} +
+ ); +}; diff --git a/src/pages/Faucet/components/FaucetModal/index.tsx b/src/pages/Faucet/components/FaucetModal/index.tsx new file mode 100644 index 00000000..2ea1549f --- /dev/null +++ b/src/pages/Faucet/components/FaucetModal/index.tsx @@ -0,0 +1 @@ +export * from './FaucetModal'; diff --git a/src/pages/Faucet/components/FaucetScreen/FaucetScreen.tsx b/src/pages/Faucet/components/FaucetScreen/FaucetScreen.tsx new file mode 100644 index 00000000..3ed55f06 --- /dev/null +++ b/src/pages/Faucet/components/FaucetScreen/FaucetScreen.tsx @@ -0,0 +1,64 @@ +import { useState } from 'react'; +import ReCAPTCHA from 'react-google-recaptcha'; +import { Button } from 'components'; +import { getEgldLabel } from 'lib'; +import { DataTestIdsEnum } from 'localConstants'; + +const sitekey = import.meta.env.VITE_APP_GOOGLE_RECAPTCHA_KEY; +const isDisabled = process.env.NODE_ENV === 'production'; + +export interface FaucetScreenPropsType { + settings: string; + onRequestClick: (captcha: string) => void; +} + +export const FaucetScreen = ({ + settings, + onRequestClick +}: FaucetScreenPropsType) => { + const [captcha, setCaptcha] = useState(''); + const [requestDisabled, setRequestDisabled] = useState(isDisabled); + const egldLabel = getEgldLabel(); + + const onRecaptchaChange = (value: string | null) => { + setRequestDisabled(!value); + + if (value) { + setCaptcha(value); + } + }; + + const handleRequestTokens = () => { + onRequestClick(captcha); + }; + + return ( +
+

+ {egldLabel} Faucet +

+

+ You can request {settings} every 24 hours +

+ +
+ +
+ + +
+ ); +}; diff --git a/src/pages/Faucet/components/FaucetScreen/index.ts b/src/pages/Faucet/components/FaucetScreen/index.ts new file mode 100644 index 00000000..04059aa9 --- /dev/null +++ b/src/pages/Faucet/components/FaucetScreen/index.ts @@ -0,0 +1 @@ +export * from './FaucetScreen'; diff --git a/src/pages/Faucet/components/FaucetSuccess/FaucetSuccess.tsx b/src/pages/Faucet/components/FaucetSuccess/FaucetSuccess.tsx new file mode 100644 index 00000000..ab36726c --- /dev/null +++ b/src/pages/Faucet/components/FaucetSuccess/FaucetSuccess.tsx @@ -0,0 +1,25 @@ +import { faCheck } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { DataTestIdsEnum } from 'localConstants'; + +export const FaucetSuccess = ({ settings }: { settings: string }) => ( +
+

+ Success +

+ +

+ {settings} have been sent to your address. +

+
+); diff --git a/src/pages/Faucet/components/FaucetSuccess/index.ts b/src/pages/Faucet/components/FaucetSuccess/index.ts new file mode 100644 index 00000000..33ee5f38 --- /dev/null +++ b/src/pages/Faucet/components/FaucetSuccess/index.ts @@ -0,0 +1 @@ +export * from './FaucetSuccess'; diff --git a/src/pages/Faucet/index.ts b/src/pages/Faucet/index.ts new file mode 100644 index 00000000..75889484 --- /dev/null +++ b/src/pages/Faucet/index.ts @@ -0,0 +1 @@ +export * from './Faucet'; diff --git a/src/pages/IssueToken/IssueToken.tsx b/src/pages/IssueToken/IssueToken.tsx new file mode 100644 index 00000000..31c8e4fa --- /dev/null +++ b/src/pages/IssueToken/IssueToken.tsx @@ -0,0 +1,8 @@ +import { IssueTokenForm } from './components'; + +export const IssueToken = () => ( +
+

Issue Token

+ +
+); diff --git a/src/pages/IssueToken/components/IssueTokenForm.tsx b/src/pages/IssueToken/components/IssueTokenForm.tsx new file mode 100644 index 00000000..2baf3951 --- /dev/null +++ b/src/pages/IssueToken/components/IssueTokenForm.tsx @@ -0,0 +1,176 @@ +import classNames from 'classnames'; +import { Button, MxLink } from 'components'; +import { DataTestIdsEnum } from 'localConstants'; + +import { routeNames } from 'routes'; +import { useIssueTokenForm } from '../hooks'; +import { IssueTokenFieldsEnum } from '../types'; + +export const IssueTokenForm = () => { + const formik = useIssueTokenForm(); + + return ( +
+
+
+ + + {formik.touched[IssueTokenFieldsEnum.tokenName] && + formik.errors[IssueTokenFieldsEnum.tokenName] && ( +
+ {formik.errors[IssueTokenFieldsEnum.tokenName]} +
+ )} +
+
+ + + {formik.touched[IssueTokenFieldsEnum.tokenTicker] && + formik.errors[IssueTokenFieldsEnum.tokenTicker] && ( +
+ {formik.errors[IssueTokenFieldsEnum.tokenTicker]} +
+ )} +
+
+ + + {formik.touched[IssueTokenFieldsEnum.mintedValue] && + formik.errors[IssueTokenFieldsEnum.mintedValue] && ( +
+ {formik.errors[IssueTokenFieldsEnum.mintedValue]} +
+ )} +
+
+ + + {formik.touched[IssueTokenFieldsEnum.numDecimals] && + formik.errors[IssueTokenFieldsEnum.numDecimals] && ( +
+ {formik.errors[IssueTokenFieldsEnum.numDecimals]} +
+ )} +
+
+
+ + + Cancel + +
+
+ ); +}; diff --git a/src/pages/IssueToken/components/index.tsx b/src/pages/IssueToken/components/index.tsx new file mode 100644 index 00000000..e5b4038b --- /dev/null +++ b/src/pages/IssueToken/components/index.tsx @@ -0,0 +1 @@ +export * from './IssueTokenForm'; diff --git a/src/pages/IssueToken/hooks/index.ts b/src/pages/IssueToken/hooks/index.ts new file mode 100644 index 00000000..f3ca6f3f --- /dev/null +++ b/src/pages/IssueToken/hooks/index.ts @@ -0,0 +1 @@ +export * from './useIssueTokenForm'; diff --git a/src/pages/IssueToken/hooks/useIssueTokenForm.ts b/src/pages/IssueToken/hooks/useIssueTokenForm.ts new file mode 100644 index 00000000..b6238dbf --- /dev/null +++ b/src/pages/IssueToken/hooks/useIssueTokenForm.ts @@ -0,0 +1,97 @@ +import { + Address, + TokenManagementTransactionsFactory, + TransactionsFactoryConfig +} from '@multiversx/sdk-core/out'; + +import { useFormik } from 'formik'; +import { object, string } from 'yup'; +import { useSendTransactions } from 'hooks'; +import { + useGetAccount, + useGetNetworkConfig, + maxDecimals, + stringIsFloat +} from 'lib'; + +import { DECIMALS } from 'localConstants'; +import { IssueTokenFieldsEnum } from '../types'; + +export const useIssueTokenForm = () => { + const { address } = useGetAccount(); + const { sendTransactions } = useSendTransactions(); + + const { + network: { chainId } + } = useGetNetworkConfig(); + + const factory = new TokenManagementTransactionsFactory({ + config: new TransactionsFactoryConfig({ chainID: chainId }) + }); + + const formik = useFormik({ + initialValues: { + [IssueTokenFieldsEnum.tokenName]: '', + [IssueTokenFieldsEnum.tokenTicker]: '', + [IssueTokenFieldsEnum.numDecimals]: 18, + [IssueTokenFieldsEnum.mintedValue]: '' + }, + validationSchema: object().shape({ + tokenName: string() + .required('Required') + .matches(/^[a-zA-Z0-9]*$/, 'Alphanumeric characters only') + .test( + 'validLength', + 'Must be between 3 - 50 characters long', + (value) => Boolean(value && value.length >= 3 && value.length <= 50) + ), + tokenTicker: string() + .matches(/^[A-Z0-9]*$/, 'Alphanumeric uppercase characters only') + .required('Required') + .test( + 'validLength', + 'Must be between 3 - 10 characters long', + (value) => Boolean(value && value.length >= 3 && value.length <= 10) + ), + numDecimals: string() + .matches(/^[0-9]*$/, 'Invalid number') + .required('Required') + .test('validLength', `Must be between 0 - ${DECIMALS}`, (value) => + Boolean(value && parseInt(value) >= 0 && parseInt(value) <= DECIMALS) + ), + mintedValue: string() + .required('Required') + .test('decimals', `Maximum ${DECIMALS} decimals allowed`, (value) => + maxDecimals(String(value)) + ) + .test('isValidNumber', 'Invalid number', (value) => + Boolean(value && stringIsFloat(value)) + ) + }), + onSubmit: async (values) => { + try { + const transaction = factory.createTransactionForIssuingFungible({ + sender: new Address(address), + tokenName: values.tokenName, + tokenTicker: values.tokenTicker.toUpperCase(), + initialSupply: BigInt(values.mintedValue), + numDecimals: BigInt(values.numDecimals), + canFreeze: true, + canWipe: true, + canPause: true, + canChangeOwner: true, + canUpgrade: true, + canAddSpecialRoles: true + }); + + await sendTransactions([transaction]); + } catch (err) { + //setErrors({ amount: err.message }); + } + + formik.resetForm(); + } + }); + + return formik; +}; diff --git a/src/pages/IssueToken/index.ts b/src/pages/IssueToken/index.ts new file mode 100644 index 00000000..3f7443c0 --- /dev/null +++ b/src/pages/IssueToken/index.ts @@ -0,0 +1 @@ +export * from './components/IssueTokenForm'; diff --git a/src/pages/IssueToken/types/index.ts b/src/pages/IssueToken/types/index.ts new file mode 100644 index 00000000..c1e82bfd --- /dev/null +++ b/src/pages/IssueToken/types/index.ts @@ -0,0 +1 @@ +export * from './issueTokenFieldsEnum'; diff --git a/src/pages/IssueToken/types/issueTokenFieldsEnum.ts b/src/pages/IssueToken/types/issueTokenFieldsEnum.ts new file mode 100644 index 00000000..e14cd5db --- /dev/null +++ b/src/pages/IssueToken/types/issueTokenFieldsEnum.ts @@ -0,0 +1,6 @@ +export enum IssueTokenFieldsEnum { + tokenName = 'tokenName', + tokenTicker = 'tokenTicker', + numDecimals = 'numDecimals', + mintedValue = 'mintedValue' +} diff --git a/src/pages/Send/Send.tsx b/src/pages/Send/Send.tsx index 47b442ae..90ad2311 100644 --- a/src/pages/Send/Send.tsx +++ b/src/pages/Send/Send.tsx @@ -1,10 +1,8 @@ import { SendForm } from './components'; -export const Send = () => { - return ( -
-

Send

- -
- ); -}; +export const Send = () => ( +
+

Send

+ +
+); diff --git a/src/pages/SovereignTransfer/SovereignTransfer.tsx b/src/pages/SovereignTransfer/SovereignTransfer.tsx index cd5f133a..366c4b8e 100644 --- a/src/pages/SovereignTransfer/SovereignTransfer.tsx +++ b/src/pages/SovereignTransfer/SovereignTransfer.tsx @@ -1,12 +1,10 @@ import { SovereignTransferForm } from './components'; -export const SovereignTransfer = () => { - return ( -
-

- Sovereign Transfer -

- -
- ); -}; +export const SovereignTransfer = () => ( +
+

+ Sovereign Transfer +

+ +
+); diff --git a/src/pages/Unlock/components/Pem/components/PemModal/PemModal.tsx b/src/pages/Unlock/components/Pem/components/PemModal/PemModal.tsx index 92fc3b17..ba679044 100644 --- a/src/pages/Unlock/components/Pem/components/PemModal/PemModal.tsx +++ b/src/pages/Unlock/components/Pem/components/PemModal/PemModal.tsx @@ -32,7 +32,7 @@ export const PemModal = ({ handleClose, show }: UseModalReturnType) => { const { type: hook, loginToken: hookInitToken } = useSelector(hookSelector); const navigate = useNavigate(); const { pathname } = useLocation(); - const [fileName, setFileName] = useState(''); + const [fileName, setFileName] = useState(''); const handleModalClose = () => { handleClose(); diff --git a/src/pages/Unlock/hooks/index.ts b/src/pages/Unlock/hooks/index.ts index f1c28375..82553727 100644 --- a/src/pages/Unlock/hooks/index.ts +++ b/src/pages/Unlock/hooks/index.ts @@ -1,3 +1,4 @@ +export * from './useGetNativeAuthConfig'; export * from './useInitToken'; export * from './useOnFileLogin'; export * from './useOnLoginHookRedirect'; diff --git a/src/pages/Unlock/hooks/useGetNativeAuthConfig.ts b/src/pages/Unlock/hooks/useGetNativeAuthConfig.ts new file mode 100644 index 00000000..77450441 --- /dev/null +++ b/src/pages/Unlock/hooks/useGetNativeAuthConfig.ts @@ -0,0 +1,27 @@ +import { useSelector } from 'react-redux'; +import { IS_DEVELOPMENT, IS_TEST, TOKEN_KEY } from 'localConstants'; +import { networkSelector } from 'redux/selectors'; + +interface ConfigType { + origin?: string; + extraRequestHeaders?: { + Authorization: string; + }; +} + +export const useGetNativeAuthConfig = () => { + const token = localStorage.getItem(TOKEN_KEY); + const { activeNetwork } = useSelector(networkSelector); + const extraRequestHeaders = { Authorization: `Bearer ${token}` }; + + const walletConfig: ConfigType = + IS_DEVELOPMENT || IS_TEST + ? { extraRequestHeaders, origin: activeNetwork.walletAddress } + : { extraRequestHeaders }; + + if (!token) { + delete walletConfig.extraRequestHeaders; + } + + return walletConfig; +}; diff --git a/src/pages/Unlock/hooks/useOnFileLogin.ts b/src/pages/Unlock/hooks/useOnFileLogin.ts index a3b785f8..fba83b97 100644 --- a/src/pages/Unlock/hooks/useOnFileLogin.ts +++ b/src/pages/Unlock/hooks/useOnFileLogin.ts @@ -15,6 +15,7 @@ import { setExternalNativeAuthToken, setTokenLogin } from 'redux/slices'; +import { useGetNativeAuthConfig } from './useGetNativeAuthConfig'; import { signMessage } from '../helpers'; interface UseOnLoginType { @@ -36,7 +37,8 @@ export const useOnFileLogin = () => { const dispatch = useDispatch(); const { loginToken, hasNativeAuthToken } = useSelector(hookSelector); const { address: loggedInAddress } = useGetAccountInfo(); - const loginService = useLoginService(); + const nativeAuthConfig = useGetNativeAuthConfig(); + const loginService = useLoginService(nativeAuthConfig); const navigate = useNavigate(); const { getRedirectPathname } = useRedirectPathname(); diff --git a/src/pages/index.tsx b/src/pages/index.tsx index cecf07e3..3cc267de 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -3,6 +3,7 @@ export * from './SovereignTransfer'; export * from './Disclaimer'; export * from './Home'; export * from './Hook'; +export * from './IssueToken'; export * from './Logout'; export * from './PageNotFound'; export * from './Send'; diff --git a/src/redux/endpoints/faucet.endpoint.ts b/src/redux/endpoints/faucet.endpoint.ts new file mode 100644 index 00000000..4f7289ae --- /dev/null +++ b/src/redux/endpoints/faucet.endpoint.ts @@ -0,0 +1,85 @@ +import { PartialTokenType } from '@multiversx/sdk-dapp-form'; +import { FetchBaseQueryError } from '@reduxjs/toolkit/dist/query'; +import { faucetSettingEndpoint, faucetEndpoint } from 'config'; +import { getAxiosConfig, getExtrasApi } from 'helpers'; +import { formatAmount, getEgldLabel, stringIsInteger } from 'lib'; +import { DECIMALS, DIGITS, TOKENS_ENDPOINT, ZERO } from 'localConstants'; +import { RootApi } from 'redux/rootApi'; + +interface FaucetSettingsType { + address: string; + amount: string; + token?: string; + tokenAmount?: string; +} + +const faucetEndpoints = RootApi.injectEndpoints({ + overrideExisting: true, + endpoints: (builder) => ({ + getFaucetSettings: builder.query({ + async queryFn(_, _queryApi, _extraOptions, fetchWithBQ) { + const egldLabel = getEgldLabel(); + + const settingsData = await fetchWithBQ({ + ...getAxiosConfig(faucetSettingEndpoint), + baseURL: getExtrasApi() + }); + + if (settingsData.error) { + return { error: settingsData.error as FetchBaseQueryError }; + } + + const { token, tokenAmount, amount } = + settingsData.data as FaucetSettingsType; + + const egldAmount = formatAmount({ + input: stringIsInteger(amount) ? amount : ZERO, + digits: DIGITS, + decimals: DECIMALS, + showLastNonZeroDecimal: false, + addCommas: true + }); + + const faucetTokenList = `${egldAmount} ${egldLabel}`; + + if (!token || !tokenAmount) { + return { data: faucetTokenList }; + } + + const tokenData = await fetchWithBQ({ + ...getAxiosConfig(`/${TOKENS_ENDPOINT}/${token}`) + }); + + if (tokenData.error) { + return { error: tokenData.error as FetchBaseQueryError }; + } + + const { decimals } = tokenData.data as PartialTokenType; + + const denominatedTokenAmount = formatAmount({ + input: tokenAmount, + decimals, + digits: DIGITS, + showLastNonZeroDecimal: true, + addCommas: true + }); + + return { + data: `${faucetTokenList} & ${denominatedTokenAmount} ${token}` + }; + } + }), + requestFunds: builder.mutation({ + query: (captcha: string) => ({ + baseURL: getExtrasApi(), + url: faucetEndpoint, + method: 'POST', + data: { captcha }, + validateStatus: (status) => status >= 200 && status < 300 + }) + }) + }) +}); + +export const { useGetFaucetSettingsQuery, useRequestFundsMutation } = + faucetEndpoints; diff --git a/src/redux/endpoints/index.ts b/src/redux/endpoints/index.ts index 52941b8a..96c6ea8b 100644 --- a/src/redux/endpoints/index.ts +++ b/src/redux/endpoints/index.ts @@ -1,3 +1,4 @@ +export * from './faucet.endpoint'; export * from './nfts.endpoint'; export * from './tokens.endpoint'; export * from './transactions.endpoint'; diff --git a/src/redux/slices/network.ts b/src/redux/slices/network.ts index 84af7e7d..1c9425f7 100644 --- a/src/redux/slices/network.ts +++ b/src/redux/slices/network.ts @@ -5,12 +5,14 @@ export interface NetworkType { WEGLDid: string; apiAddress: string; default: boolean; + extrasApi: string; faucet?: boolean; gatewayUrl: string; id: string; name: string; sampleAuthenticatedDomains: string[]; sovereignContractAddress: string; + walletAddress: string; } interface NetworkSliceType { @@ -21,11 +23,13 @@ interface NetworkSliceType { export const emptyNetwork: NetworkType = { apiAddress: '', default: false, + extrasApi: '', gatewayUrl: '', id: 'not-configured', name: 'NOT CONFIGURED', sampleAuthenticatedDomains: [], sovereignContractAddress: '', + walletAddress: '', WEGLDid: '' }; diff --git a/src/routes/routes.tsx b/src/routes/routes.tsx index 5cb00567..b644d7b7 100644 --- a/src/routes/routes.tsx +++ b/src/routes/routes.tsx @@ -20,6 +20,7 @@ import { CreateRecoverRoutes, CreateRecoverRoutesEnum } from '../pages/CreateRecover/routes'; +import { IssueToken } from '../pages/IssueToken/IssueToken'; export interface RouteWithTitleType extends RouteType { title: string; @@ -92,6 +93,15 @@ const routesObject: Record< ) }, + [RouteNamesEnum.issueToken]: { + path: RouteNamesEnum.issueToken, + title: 'Issue Token', + component: () => ( + + + + ) + }, [HooksPageEnum.login]: { path: HooksPageEnum.login, title: 'Login', diff --git a/src/types/sdkDapp.types.ts b/src/types/sdkDapp.types.ts index bd1c78d2..cddffef7 100644 --- a/src/types/sdkDapp.types.ts +++ b/src/types/sdkDapp.types.ts @@ -30,3 +30,4 @@ export type { export type { TransactionsDataTokensType } from '@multiversx/sdk-dapp/types/transactions.types'; export type { SignedTransactionsType } from '@multiversx/sdk-dapp/types/transactions.types'; export type { SendBatchTransactionsPropsType } from '@multiversx/sdk-dapp/types/transactions.types'; +export type { CustomToastType } from '@multiversx/sdk-dapp/types/toasts.types'; diff --git a/version.json b/version.json index 6029bb0b..3b255c42 100644 --- a/version.json +++ b/version.json @@ -1 +1 @@ -{ "hash": "e8d8eda" } \ No newline at end of file +{ "hash": "2ae334c" } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 64ec6a32..5b50d4c0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -33,7 +33,28 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz" integrity sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ== -"@babel/core@^7.11.6": +"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.0.0-0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.12.0", "@babel/core@^7.13.0", "@babel/core@^7.4.0-0", "@babel/core@7.21.8": + version "7.21.8" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.21.8.tgz" + integrity sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.21.4" + "@babel/generator" "^7.21.5" + "@babel/helper-compilation-targets" "^7.21.5" + "@babel/helper-module-transforms" "^7.21.5" + "@babel/helpers" "^7.21.5" + "@babel/parser" "^7.21.8" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.5" + "@babel/types" "^7.21.5" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.0" + +"@babel/core@^7.11.6", "@babel/core@^7.8.0": version "7.25.2" resolved "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz" integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA== @@ -138,27 +159,6 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/core@7.21.8": - version "7.21.8" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.21.8.tgz" - integrity sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.21.4" - "@babel/generator" "^7.21.5" - "@babel/helper-compilation-targets" "^7.21.5" - "@babel/helper-module-transforms" "^7.21.5" - "@babel/helpers" "^7.21.5" - "@babel/parser" "^7.21.8" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.5" - "@babel/types" "^7.21.5" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.2" - semver "^6.3.0" - "@babel/generator@^7.21.5", "@babel/generator@^7.25.0", "@babel/generator@^7.7.2": version "7.25.0" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz" @@ -1248,14 +1248,14 @@ resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz" integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== -"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": +"@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0", "@eslint-community/regexpp@^4.6.1": version "4.11.0" resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz" integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A== @@ -1337,7 +1337,7 @@ resolved "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz" integrity sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A== -"@fortawesome/fontawesome-svg-core@6.5.1": +"@fortawesome/fontawesome-svg-core@~1 || ~6", "@fortawesome/fontawesome-svg-core@6.5.1": version "6.5.1" resolved "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz" integrity sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ== @@ -1568,7 +1568,7 @@ jest-mock "^29.7.0" jest-util "^29.7.0" -"@jest/globals@^29.7.0": +"@jest/globals@^29.7.0", "@jest/globals@>= 28": version "29.7.0" resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz" integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== @@ -1935,31 +1935,31 @@ resolved "https://registry.npmjs.org/@multiversx/sdk-bls-wasm/-/sdk-bls-wasm-0.3.5.tgz" integrity sha512-c0tIdQUnbBLSt6NYU+OpeGPYdL0+GV547HeHT8Xc0BKQ7Cj0v82QUoA2QRtWrR1G4MNZmLsIacZSsf6DrIS2Bw== -"@multiversx/sdk-core@12.18.0": - version "12.18.0" - resolved "https://registry.npmjs.org/@multiversx/sdk-core/-/sdk-core-12.18.0.tgz" - integrity sha512-F+xGslPMkkZ0S/Q8UJZsMYl0mgHIuK/GdVsNFPiMKxQsKkxA2LTjNdPxVxjwgvRmN7WfdsTtQvmlsA5O1NYhBg== +"@multiversx/sdk-core@>= 12.1.0", "@multiversx/sdk-core@>= 12.18.0", "@multiversx/sdk-core@>= 12.5.0", "@multiversx/sdk-core@>= 13.0.0", "@multiversx/sdk-core@>=12.18.0", "@multiversx/sdk-core@>13.0.0", "@multiversx/sdk-core@13.0.1": + version "13.0.1" + resolved "https://registry.npmjs.org/@multiversx/sdk-core/-/sdk-core-13.0.1.tgz" + integrity sha512-3fCtNVJ9qv0v39UWkNTNkLBUm4jYCDLFGu5erbzZEgdjFCFET3vFbdXtf7aqSZlFW6UGhFZGZGmCOHjIUJZf9g== dependencies: "@multiversx/sdk-transaction-decoder" "1.0.2" bech32 "1.1.4" - bignumber.js "9.0.1" blake2b "2.1.3" buffer "6.0.3" - json-duplicate-key-handle "1.0.0" + json-bigint "1.0.0" keccak "3.0.2" - protobufjs "7.2.4" -"@multiversx/sdk-core@13.0.1": - version "13.0.1" - resolved "https://registry.npmjs.org/@multiversx/sdk-core/-/sdk-core-13.0.1.tgz" - integrity sha512-3fCtNVJ9qv0v39UWkNTNkLBUm4jYCDLFGu5erbzZEgdjFCFET3vFbdXtf7aqSZlFW6UGhFZGZGmCOHjIUJZf9g== +"@multiversx/sdk-core@12.18.0": + version "12.18.0" + resolved "https://registry.npmjs.org/@multiversx/sdk-core/-/sdk-core-12.18.0.tgz" + integrity sha512-F+xGslPMkkZ0S/Q8UJZsMYl0mgHIuK/GdVsNFPiMKxQsKkxA2LTjNdPxVxjwgvRmN7WfdsTtQvmlsA5O1NYhBg== dependencies: "@multiversx/sdk-transaction-decoder" "1.0.2" bech32 "1.1.4" + bignumber.js "9.0.1" blake2b "2.1.3" buffer "6.0.3" - json-bigint "1.0.0" + json-duplicate-key-handle "1.0.0" keccak "3.0.2" + protobufjs "7.2.4" "@multiversx/sdk-dapp-core@0.0.0-alpha.6": version "0.0.0-alpha.6" @@ -1995,12 +1995,12 @@ classnames "2.3.2" react-select "5.4.0" -"@multiversx/sdk-dapp-utils@^0.0.1": +"@multiversx/sdk-dapp-utils@^0.0.1", "@multiversx/sdk-dapp-utils@>= 0.0.1", "@multiversx/sdk-dapp-utils@>=0.0.1", "@multiversx/sdk-dapp-utils@0.0.1": version "0.0.1" resolved "https://registry.npmjs.org/@multiversx/sdk-dapp-utils/-/sdk-dapp-utils-0.0.1.tgz" integrity sha512-fl3TdES93Jc4T559BI+QxNRGRUTabb7TiAXHKL9g6mbLD+silK+5euAoDpPBkbZpVFnfsXQssUVuyKBV4Ine6w== -"@multiversx/sdk-dapp@2.35.0-alpha.0": +"@multiversx/sdk-dapp@>=2.28.0", "@multiversx/sdk-dapp@2.35.0-alpha.0": version "2.35.0-alpha.0" resolved "https://registry.npmjs.org/@multiversx/sdk-dapp/-/sdk-dapp-2.35.0-alpha.0.tgz" integrity sha512-ZgbAYsanHRgIDFMkMSz+LYAd5hAW6Xj54C6ggTRRN9DXjmGYebGnvhgYefftTfVumYBKKhizvwAFyKYj+VFfIw== @@ -2145,7 +2145,7 @@ tweetnacl "1.0.3" uuid "8.3.2" -"@multiversx/sdk-web-wallet-cross-window-provider@0.2.0": +"@multiversx/sdk-web-wallet-cross-window-provider@>=0.2.0", "@multiversx/sdk-web-wallet-cross-window-provider@0.2.0": version "0.2.0" resolved "https://registry.npmjs.org/@multiversx/sdk-web-wallet-cross-window-provider/-/sdk-web-wallet-cross-window-provider-0.2.0.tgz" integrity sha512-HyHKir96e8i3DnwtR1TOwINs9dOJH5kDjMOMjJvpqUlZm/07+O/KrWDxVRCAF7Qxhg0Lm09w6kfkBIoHfdux0w== @@ -2714,7 +2714,7 @@ "@svgr/babel-plugin-transform-react-native-svg" "8.1.0" "@svgr/babel-plugin-transform-svg-component" "8.0.0" -"@svgr/core@^8.1.0": +"@svgr/core@*", "@svgr/core@^8.1.0": version "8.1.0" resolved "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz" integrity sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA== @@ -2783,7 +2783,7 @@ resolved "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.74.tgz" integrity sha512-2rMV4QxM583jXcREfo0MhV3Oj5pgRSfSh/kVrB1twL2rQxOrbzkAPT/8flmygdVoL4f2F7o1EY5lKlYxEBiIKQ== -"@swc/core@1.3.74": +"@swc/core@*", "@swc/core@>= 1.3", "@swc/core@>= 1.4.13", "@swc/core@>=1.2.50", "@swc/core@1.3.74": version "1.3.74" resolved "https://registry.npmjs.org/@swc/core/-/core-1.3.74.tgz" integrity sha512-P+MIExOTdWlfq8Heb1/NhBAke6UTckd4cRDuJoFcFMGBRvgoCMNWhnfP3FRRXPLI7GGg27dRZS+xHiqYyQmSrA== @@ -2799,6 +2799,11 @@ "@swc/core-win32-ia32-msvc" "1.3.74" "@swc/core-win32-x64-msvc" "1.3.74" +"@swc/counter@^0.1.3": + version "0.1.3" + resolved "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz" + integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== + "@swc/jest@0.2.27": version "0.2.27" resolved "https://registry.npmjs.org/@swc/jest/-/jest-0.2.27.tgz" @@ -2807,7 +2812,14 @@ "@jest/create-cache-key-function" "^27.4.2" jsonc-parser "^3.2.0" -"@testing-library/dom@^9.0.0": +"@swc/types@>= 0.1": + version "0.1.12" + resolved "https://registry.npmjs.org/@swc/types/-/types-0.1.12.tgz" + integrity sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA== + dependencies: + "@swc/counter" "^0.1.3" + +"@testing-library/dom@^9.0.0", "@testing-library/dom@>=7.21.4": version "9.3.4" resolved "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz" integrity sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ== @@ -3020,7 +3032,7 @@ expect "^29.0.0" pretty-format "^29.0.0" -"@types/jest@29.5.5": +"@types/jest@>= 28", "@types/jest@29.5.5": version "29.5.5" resolved "https://registry.npmjs.org/@types/jest/-/jest-29.5.5.tgz" integrity sha512-ebylz2hnsWR9mYvmBFbXJXr+33UPc4+ZdxyDXh5w0FlPBTfCVN3wPL+kuOiQt3xvrK419v7XWeAs+AeOksafXg== @@ -3067,12 +3079,10 @@ "@types/node" "*" form-data "^4.0.0" -"@types/node@*": - version "22.1.0" - resolved "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz" - integrity sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw== - dependencies: - undici-types "~6.13.0" +"@types/node@*", "@types/node@>= 14", "@types/node@>=13.7.0", "@types/node@20.7.1": + version "20.7.1" + resolved "https://registry.npmjs.org/@types/node/-/node-20.7.1.tgz" + integrity sha512-LT+OIXpp2kj4E2S/p91BMe+VgGX2+lfO+XTpfXhh+bCk2LkQtHZSub8ewFBMGP5ClysPjTDFa4sMI8Q3n4T0wg== "@types/node@^22.1.0": version "22.1.0" @@ -3081,11 +3091,6 @@ dependencies: undici-types "~6.13.0" -"@types/node@>=13.7.0", "@types/node@20.7.1": - version "20.7.1" - resolved "https://registry.npmjs.org/@types/node/-/node-20.7.1.tgz" - integrity sha512-LT+OIXpp2kj4E2S/p91BMe+VgGX2+lfO+XTpfXhh+bCk2LkQtHZSub8ewFBMGP5ClysPjTDFa4sMI8Q3n4T0wg== - "@types/node@11.11.6": version "11.11.6" resolved "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz" @@ -3120,6 +3125,13 @@ resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz" integrity sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw== +"@types/react-dom@^16.8 || ^17.0 || ^18.0", "@types/react-dom@^18.0.8", "@types/react-dom@18.2.8": + version "18.2.8" + resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.8.tgz" + integrity sha512-bAIvO5lN/U8sPGvs1Xm61rlRHHaq5rp5N3kp9C+NJ/Q41P8iqjkXSu0+/qu8POsjH9pNWb0OYabFez7taP7omw== + dependencies: + "@types/react" "*" + "@types/react-dom@^18.0.0": version "18.3.0" resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz" @@ -3127,10 +3139,10 @@ dependencies: "@types/react" "*" -"@types/react-dom@18.2.8": - version "18.2.8" - resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.8.tgz" - integrity sha512-bAIvO5lN/U8sPGvs1Xm61rlRHHaq5rp5N3kp9C+NJ/Q41P8iqjkXSu0+/qu8POsjH9pNWb0OYabFez7taP7omw== +"@types/react-google-recaptcha@2.1.9": + version "2.1.9" + resolved "https://registry.npmjs.org/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.9.tgz" + integrity sha512-nT31LrBDuoSZJN4QuwtQSF3O89FVHC4jLhM+NtKEmVF5R1e8OY0Jo4//x2Yapn2aNHguwgX5doAq8Zo+Ehd0ug== dependencies: "@types/react" "*" @@ -3158,15 +3170,7 @@ dependencies: "@types/react" "*" -"@types/react@*": - version "18.3.3" - resolved "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz" - integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw== - dependencies: - "@types/prop-types" "*" - csstype "^3.0.2" - -"@types/react@18.2.23": +"@types/react@*", "@types/react@^16.8 || ^17.0 || ^18.0", "@types/react@^18.0.24", "@types/react@>=16.8", "@types/react@18.2.23": version "18.2.23" resolved "https://registry.npmjs.org/@types/react/-/react-18.2.23.tgz" integrity sha512-qHLW6n1q2+7KyBEYnrZpcsAmU/iiCh9WGCKgXvMxx89+TYdJWRjZohVIo9XTcoLhfX3+/hP0Pbulu3bCZQ9PSA== @@ -3246,7 +3250,7 @@ natural-compare "^1.4.0" ts-api-utils "^1.3.0" -"@typescript-eslint/parser@7.13.0": +"@typescript-eslint/parser@^7.0.0", "@typescript-eslint/parser@7.13.0": version "7.13.0" resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.0.tgz" integrity sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA== @@ -3555,7 +3559,7 @@ acorn-walk@^8.0.2, acorn-walk@^8.1.1: dependencies: acorn "^8.11.0" -acorn@^8.1.0, acorn@^8.11.0, acorn@^8.11.3, acorn@^8.4.1, acorn@^8.8.1, acorn@^8.9.0: +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.1.0, acorn@^8.11.0, acorn@^8.11.3, acorn@^8.4.1, acorn@^8.8.1, acorn@^8.9.0: version "8.12.1" resolved "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz" integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== @@ -3844,7 +3848,7 @@ axios@^1.6.8: form-data "^4.0.0" proxy-from-env "^1.1.0" -axios@1.6.5: +axios@>=1.6.5, axios@1.6.5: version "1.6.5" resolved "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz" integrity sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg== @@ -4024,20 +4028,15 @@ bignumber.js@^9.0.0: resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz" integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== -bignumber.js@9.0.1: - version "9.0.1" - resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz" - integrity sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA== - -bignumber.js@9.0.2: +bignumber.js@^9.0.1, bignumber.js@>=9.0.2, bignumber.js@9.0.2, bignumber.js@9.x: version "9.0.2" resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz" integrity sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw== -bignumber.js@9.x: - version "9.1.2" - resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz" - integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== +bignumber.js@9.0.1: + version "9.0.1" + resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz" + integrity sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA== binary-extensions@^2.0.0: version "2.3.0" @@ -4180,7 +4179,7 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@^4.21.10, browserslist@^4.23.1, browserslist@^4.23.3: +browserslist@^4.21.10, browserslist@^4.23.1, browserslist@^4.23.3, "browserslist@>= 4.21.0": version "4.23.3" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz" integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== @@ -4244,11 +4243,23 @@ buffer@^6.0.3, buffer@6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" +builtin-modules@^3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== + builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz" integrity sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ== +builtins@^5.0.1: + version "5.1.0" + resolved "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz" + integrity sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg== + dependencies: + semver "^7.0.0" + call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz" @@ -4917,7 +4928,7 @@ detect-newline@^3.0.0: resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -devtools-protocol@0.0.1299070: +devtools-protocol@*, devtools-protocol@0.0.1299070: version "0.0.1299070" resolved "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1299070.tgz" integrity sha512-+qtL3eX50qsJ7c+qVyagqi7AWMoQCBGNfoyJZMwm/NSXVqLYbuitrWEEIzxfUmTNy7//Xe8yhMmQ+elj3uAqSg== @@ -5332,6 +5343,13 @@ escodegen@^2.0.0, escodegen@^2.1.0: optionalDependencies: source-map "~0.6.1" +eslint-compat-utils@^0.5.1: + version "0.5.1" + resolved "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz" + integrity sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q== + dependencies: + semver "^7.5.4" + eslint-config-prettier@9.0.0: version "9.0.0" resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz" @@ -5381,6 +5399,15 @@ eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0: dependencies: debug "^3.2.7" +eslint-plugin-es-x@^7.5.0: + version "7.8.0" + resolved "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz" + integrity sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ== + dependencies: + "@eslint-community/eslint-utils" "^4.1.2" + "@eslint-community/regexpp" "^4.11.0" + eslint-compat-utils "^0.5.1" + eslint-plugin-es@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz" @@ -5389,7 +5416,7 @@ eslint-plugin-es@^3.0.0: eslint-utils "^2.0.0" regexpp "^3.0.0" -eslint-plugin-import@2.28.1: +eslint-plugin-import@*, eslint-plugin-import@^2.25.2, eslint-plugin-import@>=1.4.0, eslint-plugin-import@2.28.1: version "2.28.1" resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz" integrity sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A== @@ -5412,6 +5439,23 @@ eslint-plugin-import@2.28.1: semver "^6.3.1" tsconfig-paths "^3.14.2" +"eslint-plugin-n@^15.0.0 || ^16.0.0 ": + version "16.6.2" + resolved "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz" + integrity sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + builtins "^5.0.1" + eslint-plugin-es-x "^7.5.0" + get-tsconfig "^4.7.0" + globals "^13.24.0" + ignore "^5.2.4" + is-builtin-module "^3.2.1" + is-core-module "^2.12.1" + minimatch "^3.1.2" + resolve "^1.22.2" + semver "^7.5.3" + eslint-plugin-node@11.1.0: version "11.1.0" resolved "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz" @@ -5432,7 +5476,7 @@ eslint-plugin-prettier@5.0.0: prettier-linter-helpers "^1.0.0" synckit "^0.8.5" -eslint-plugin-promise@6.1.1: +eslint-plugin-promise@^6.0.0, eslint-plugin-promise@6.1.1: version "6.1.1" resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz" integrity sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig== @@ -5489,7 +5533,7 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@8.50.0: +eslint@*, "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.0.0 || ^8.0.0", eslint@^8.0.1, eslint@^8.56.0, eslint@>=4.19.1, eslint@>=5.16.0, eslint@>=6.0.0, eslint@>=7.0.0, eslint@>=8, eslint@>=8.0.0, eslint@8.50.0: version "8.50.0" resolved "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz" integrity sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg== @@ -6015,7 +6059,7 @@ get-symbol-description@^1.0.2: es-errors "^1.3.0" get-intrinsic "^1.2.4" -get-tsconfig@^4.5.0: +get-tsconfig@^4.5.0, get-tsconfig@^4.7.0: version "4.7.6" resolved "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.6.tgz" integrity sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA== @@ -6100,6 +6144,13 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" +globals@^13.24.0: + version "13.24.0" + resolved "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + globalthis@^1.0.3: version "1.0.4" resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz" @@ -6349,12 +6400,12 @@ ieee754@^1.1.13, ieee754@^1.2.1: resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^5.1.1, ignore@^5.2.0, ignore@^5.3.1: +ignore@^5.1.1, ignore@^5.2.0, ignore@^5.2.4, ignore@^5.3.1: version "5.3.1" resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz" integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== -immer@^9.0.16, immer@^9.0.7: +immer@^9.0.16, immer@^9.0.7, immer@>=9.0.6: version "9.0.21" resolved "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz" integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA== @@ -6485,12 +6536,19 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-builtin-module@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz" + integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== + dependencies: + builtin-modules "^3.3.0" + is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.11.0, is-core-module@^2.13.0: +is-core-module@^2.11.0, is-core-module@^2.12.1, is-core-module@^2.13.0: version "2.15.0" resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz" integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA== @@ -7100,7 +7158,7 @@ jest-resolve-dependencies@^29.7.0: jest-regex-util "^29.6.3" jest-snapshot "^29.7.0" -jest-resolve@^29.7.0, jest-resolve@29.7.0: +jest-resolve@*, jest-resolve@^29.7.0, jest-resolve@29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== @@ -7256,7 +7314,7 @@ jest-worker@^29.7.0: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@29.7.0: +"jest@^26.0.1 || ^27.0.0", "jest@>= 28", jest@29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz" integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== @@ -7493,7 +7551,7 @@ linkify-react@4.0.2: resolved "https://registry.npmjs.org/linkify-react/-/linkify-react-4.0.2.tgz" integrity sha512-WFHnwOUo6EeKwrQQy1d+UjeKsv+SPQ9toPpaRIXHV1CMo+0kgZBSIsEBxQrFQIEy7WD20QD+sPwNNaJJpynN6g== -linkifyjs@4.0.2: +linkifyjs@^4.0.0, linkifyjs@4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.0.2.tgz" integrity sha512-/VSoCZiglX0VMsXmL5PN3lRg45M86lrD9PskdkA2abWaTKap1bIcJ11LS4EE55bcUl9ZOR4eZ792UtQ9E/5xLA== @@ -8502,7 +8560,7 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0: resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.4.23: +postcss@^8.0.0, postcss@^8.2.14, postcss@^8.4.21, postcss@^8.4.23, postcss@>=8.0.9: version "8.4.40" resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz" integrity sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q== @@ -8511,6 +8569,15 @@ postcss@^8.4.23: picocolors "^1.0.1" source-map-js "^1.2.0" +postcss@^8.1.0, postcss@8.4.30: + version "8.4.30" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz" + integrity sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + postcss@^8.4.27: version "8.4.40" resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz" @@ -8520,15 +8587,6 @@ postcss@^8.4.27: picocolors "^1.0.1" source-map-js "^1.2.0" -postcss@8.4.30: - version "8.4.30" - resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz" - integrity sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g== - dependencies: - nanoid "^3.3.6" - picocolors "^1.0.0" - source-map-js "^1.0.2" - prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" @@ -8541,7 +8599,7 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@3.0.3: +prettier@>=3.0.0, prettier@3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz" integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg== @@ -8601,7 +8659,7 @@ prompts@^2.0.1, prompts@^2.4.2: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@^15.5.0, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -8615,10 +8673,10 @@ property-expr@^2.0.4, property-expr@^2.0.5: resolved "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz" integrity sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA== -protobufjs@7.2.4: - version "7.2.4" - resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz" - integrity sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ== +protobufjs@^7.2.6, protobufjs@7.2.6: + version "7.2.6" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.6.tgz" + integrity sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" @@ -8633,10 +8691,10 @@ protobufjs@7.2.4: "@types/node" ">=13.7.0" long "^5.0.0" -protobufjs@7.2.6: - version "7.2.6" - resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.6.tgz" - integrity sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw== +protobufjs@7.2.4: + version "7.2.4" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz" + integrity sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" @@ -8737,7 +8795,7 @@ puppeteer@*: devtools-protocol "0.0.1312386" puppeteer-core "22.15.0" -puppeteer@22.11.1: +puppeteer@>=19, puppeteer@22.11.1: version "22.11.1" resolved "https://registry.npmjs.org/puppeteer/-/puppeteer-22.11.1.tgz" integrity sha512-NhpLQC2NMXcNvCquRCeFWxu12ywfBeZ8wK9TyupOnSyaX2czeuqZdBVOQ33mBzmG8qTnM7DsStY8Z+TOgshMdA== @@ -8850,6 +8908,14 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" +react-async-script@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz" + integrity sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q== + dependencies: + hoist-non-react-statics "^3.3.0" + prop-types "^15.5.0" + react-collapsed@3.6.0: version "3.6.0" resolved "https://registry.npmjs.org/react-collapsed/-/react-collapsed-3.6.0.tgz" @@ -8857,7 +8923,7 @@ react-collapsed@3.6.0: dependencies: tiny-warning "^1.0.3" -react-dom@18.2.0: +"react-dom@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^18.0.0", "react-dom@^16.8 || ^17", "react-dom@^16.8 || ^17.0 || ^18.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", react-dom@^18.0.0, react-dom@^18.2.0, "react-dom@>= 16.0", react-dom@>=16, react-dom@>=16.14.0, react-dom@>=16.6.0, react-dom@>=16.8, react-dom@>=18, react-dom@18.2.0: version "18.2.0" resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz" integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== @@ -8865,7 +8931,7 @@ react-dom@18.2.0: loose-envify "^1.1.0" scheduler "^0.23.0" -react-draggable-tags@^1.0.6: +react-draggable-tags@1.0.6: version "1.0.6" resolved "https://registry.npmjs.org/react-draggable-tags/-/react-draggable-tags-1.0.6.tgz" integrity sha512-8Sl6UnLRCotqkaPih5D9L2DoKX858fV/zIf/ZkvcCht3Y58hkOLWO5V1M4XgdcZ0NMKh2ttcI55MCZqKO17DCg== @@ -8877,6 +8943,14 @@ react-fast-compare@^2.0.1: resolved "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz" integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== +react-google-recaptcha@3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz" + integrity sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg== + dependencies: + prop-types "^15.5.0" + react-async-script "^1.2.0" + react-idle-timer@5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/react-idle-timer/-/react-idle-timer-5.0.0.tgz" @@ -8917,7 +8991,7 @@ react-qr-code@2.0.14: prop-types "^15.8.1" qr.js "0.0.0" -react-redux@8.0.2: +"react-redux@^7.2.1 || ^8.0.0-beta", react-redux@8.0.2: version "8.0.2" resolved "https://registry.npmjs.org/react-redux/-/react-redux-8.0.2.tgz" integrity sha512-nBwiscMw3NoP59NFCXFf02f8xdo+vSHT/uZ1ldDwF7XaTpzm+Phk97VT4urYBl5TYAPNVaFm12UHAEyzkpNzRA== @@ -8929,7 +9003,7 @@ react-redux@8.0.2: react-is "^18.0.0" use-sync-external-store "^1.0.0" -react-redux@8.0.5: +"react-redux@^7.2.1 || ^8.0.2", react-redux@8.0.5: version "8.0.5" resolved "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz" integrity sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw== @@ -9007,7 +9081,7 @@ react-transition-group@^4.3.0: loose-envify "^1.4.0" prop-types "^15.6.2" -react@18.2.0: +react@*, "react@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^18.0.0", "react@^16.11.0 || ^17.0.0 || ^18.0.0", "react@^16.8 || ^17", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.9.0 || ^17.0.0 || ^18", react@^18.0.0, react@^18.2.0, "react@>= 15.0.0", "react@>= 16.0", react@>=16, react@>=16.14.0, react@>=16.3, react@>=16.4.1, react@>=16.6.0, react@>=16.8, react@>=16.8.0, react@>=18, react@18.2.0: version "18.2.0" resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz" integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== @@ -9091,7 +9165,7 @@ redux-thunk@^2.4.1, redux-thunk@^2.4.2: resolved "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz" integrity sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q== -redux@^4.1.2, redux@^4.2.0: +redux@^4, redux@^4.1.2, redux@^4.2.0, redux@>4.0.0: version "4.2.1" resolved "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz" integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== @@ -9272,7 +9346,7 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" -rollup@^3.27.1: +rollup@^1.20.0||^2.0.0||^3.0.0||^4.0.0, rollup@^3.27.1: version "3.29.4" resolved "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz" integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw== @@ -9368,6 +9442,11 @@ semver@^6.1.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0, semver@^6.3.1: resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== +semver@^7.0.0: + version "7.6.3" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + semver@^7.3.5: version "7.6.3" resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" @@ -10107,7 +10186,7 @@ ts-interface-checker@^0.1.9: resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz" integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== -ts-node@10.9.2: +ts-node@>=9.0.0, ts-node@10.9.2: version "10.9.2" resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz" integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== @@ -10247,7 +10326,7 @@ typed-array-length@^1.0.6: is-typed-array "^1.1.13" possible-typed-array-names "^1.0.0" -typescript@5.2.2: +"typescript@^4.3.5 || ^5.0.0", "typescript@>= 4.3", "typescript@>= 4.7.x", typescript@>=2.7, typescript@>=4.2.0, typescript@>=4.9.5, typescript@5.2.2: version "5.2.2" resolved "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz" integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== @@ -10507,7 +10586,7 @@ vite-tsconfig-paths@4.2.1: globrex "^0.1.2" tsconfck "^2.1.0" -vite@4.4.9: +vite@*, "vite@^2.0.0 || ^3.0.0 || ^4.0.0", "vite@^2.6.0 || 3 || 4", "vite@^3.0.0 || ^4.0.0", vite@^4.2.0, vite@4.4.9: version "4.4.9" resolved "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz" integrity sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==