Merge remote-tracking branch 'upstream/develop' into feature/refine-i18n-italian

This commit is contained in:
Nicola Benaglia 2025-05-24 19:32:35 +02:00
commit fdc3dfc1d1
126 changed files with 9207 additions and 1730 deletions

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -35,7 +35,7 @@ import PersonSearchIcon from '@mui/icons-material/PersonSearch';
import qortLogo from './assets/qort.png';
import { Return } from './assets/Icons/Return.tsx';
import WarningIcon from '@mui/icons-material/Warning';
import './utils/seedPhrase/RandomSentenceGenerator';
import './utils/seedPhrase/randomSentenceGenerator.ts';
import EngineeringIcon from '@mui/icons-material/Engineering';
import AccountBalanceWalletIcon from '@mui/icons-material/AccountBalanceWallet';
import PriorityHighIcon from '@mui/icons-material/PriorityHigh';
@ -64,7 +64,7 @@ import { Loader } from './components/Loader';
import { PasswordField, ErrorText } from './components';
import { Group, requestQueueMemberNames } from './components/Group/Group';
import { TaskManager } from './components/TaskManager/TaskManager.tsx';
import { useModal } from './common/useModal';
import { useModal } from './hooks/useModal.tsx';
import { CustomizedSnackbars } from './components/Snackbar/Snackbar';
import SettingsIcon from '@mui/icons-material/Settings';
import LogoutIcon from '@mui/icons-material/Logout';
@ -76,7 +76,7 @@ import {
groupApi,
groupApiSocket,
storeWallets,
} from './background';
} from './background/background.ts';
import {
executeEvent,
subscribeToEvent,
@ -118,13 +118,13 @@ import {
} from './atoms/global';
import { NotAuthenticated } from './components/NotAuthenticated.tsx';
import { handleGetFileFromIndexedDB } from './utils/indexedDB';
import { Wallets } from './Wallets';
import { useFetchResources } from './common/useFetchResources';
import { Wallets } from './components/Wallets.tsx';
import { useFetchResources } from './hooks/useFetchResources.tsx';
import { Tutorials } from './components/Tutorials/Tutorials';
import { useHandleTutorials } from './hooks/useHandleTutorials.tsx';
import { useHandleUserInfo } from './hooks/useHandleUserInfo.tsx';
import { Minting } from './components/Minting/Minting';
import { isRunningGateway } from './qortalRequests';
import { isRunningGateway } from './qortal/qortal-requests.ts';
import { QMailStatus } from './components/QMailStatus';
import { GlobalActions } from './components/GlobalActions/GlobalActions';
import { useBlockedAddresses } from './hooks/useBlockUsers.tsx';
@ -236,7 +236,8 @@ const defaultValuesGlobal = {
setOpenTutorialModal: () => {},
};
export const MyContext = createContext<MyContextInterface>(defaultValues);
export const QORTAL_APP_CONTEXT =
createContext<MyContextInterface>(defaultValues);
export let globalApiKey: string | null = null;
@ -307,7 +308,13 @@ function App() {
const [isLoading, setIsLoading] = useState<boolean>(false);
const [isLoadingSendCoin, setIsLoadingSendCoin] = useState<boolean>(false);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const theme = useTheme();
const [
@ -2016,7 +2023,7 @@ function App() {
>
<PdfViewer />
<MyContext.Provider value={contextValue}>
<QORTAL_APP_CONTEXT.Provider value={contextValue}>
<Tutorials />
{extState === 'not-authenticated' && (
<NotAuthenticated
@ -3858,7 +3865,7 @@ function App() {
setInfoSnack={setInfoSnack}
/>
<BuyQortInformation balance={balance} />
</MyContext.Provider>
</QORTAL_APP_CONTEXT.Provider>
{extState === 'create-wallet' && walletToBeDownloaded && (
<ButtonBase

View File

@ -11,7 +11,6 @@ import {
checkLocalFunc,
checkNewMessages,
checkThreads,
clearAllNotifications,
createEndpoint,
createGroup,
decryptDirectFunc,
@ -55,20 +54,20 @@ import {
setGroupData,
updateThreadActivity,
walletVersion,
} from './background';
} from '../background/background.ts';
import {
decryptGroupEncryption,
encryptAndPublishSymmetricKeyGroupChat,
encryptAndPublishSymmetricKeyGroupChatForAdmins,
publishGroupEncryptedResource,
publishOnQDN,
} from './backgroundFunctions/encryption';
import { PUBLIC_NOTIFICATION_CODE_FIRST_SECRET_KEY } from './constants/constants';
import Base58 from './deps/Base58';
import { encryptSingle } from './qdn/encryption/group-encryption';
import { _createPoll, _voteOnPoll } from './qortalRequests/get';
import { createTransaction } from './transactions/transactions';
import { getData, storeData } from './utils/chromeStorage';
} from '../encryption/encryption.ts';
import { PUBLIC_NOTIFICATION_CODE_FIRST_SECRET_KEY } from '../constants/constants';
import Base58 from '../encryption/Base58.ts';
import { encryptSingle } from '../qdn/encryption/group-encryption';
import { _createPoll, _voteOnPoll } from '../qortal/get.ts';
import { createTransaction } from '../transactions/transactions';
import { getData, storeData } from '../utils/chromeStorage';
export function versionCase(request, event) {
event.source.postMessage(
@ -1142,32 +1141,6 @@ export async function getEnteredQmailTimestampCase(request, event) {
}
}
export async function clearAllNotificationsCase(request, event) {
try {
await clearAllNotifications();
event.source.postMessage(
{
requestId: request.requestId,
action: 'clearAllNotifications',
payload: true,
type: 'backgroundMessageResponse',
},
event.origin
);
} catch (error) {
event.source.postMessage(
{
requestId: request.requestId,
action: 'clearAllNotifications',
error: error?.message,
type: 'backgroundMessageResponse',
},
event.origin
);
}
}
export async function setGroupDataCase(request, event) {
try {
const { groupId, secretKeyData, secretKeyResource, admins } =

View File

@ -1,27 +1,27 @@
// @ts-nocheck
import './qortalRequests';
import '../qortal/qortal-requests.ts';
import { isArray } from 'lodash';
import { uint8ArrayToObject } from './backgroundFunctions/encryption';
import Base58 from './deps/Base58';
import { uint8ArrayToObject } from '../encryption/encryption.ts';
import Base58 from '../encryption/Base58';
import axios from 'axios';
import {
base64ToUint8Array,
decryptSingle,
encryptSingle,
objectToBase64,
} from './qdn/encryption/group-encryption';
import ChatComputePowWorker from './chatComputePow.worker.js?worker';
import { reusableGet } from './qdn/publish/pubish';
import { signChat } from './transactions/signChat';
import { createTransaction } from './transactions/transactions';
import { decryptChatMessage } from './utils/decryptChatMessage';
import { decryptStoredWallet } from './utils/decryptWallet';
import PhraseWallet from './utils/generateWallet/phrase-wallet';
import { RequestQueueWithPromise } from './utils/queue/queue';
import { validateAddress } from './utils/validateAddress';
} from '../qdn/encryption/group-encryption';
import ChatComputePowWorker from '../chatComputePow.worker.js?worker';
import { reusableGet } from '../qdn/publish/publish.ts';
import { signChat } from '../transactions/signChat';
import { createTransaction } from '../transactions/transactions';
import { decryptChatMessage } from '../utils/decryptChatMessage';
import { decryptStoredWallet } from '../utils/decryptWallet';
import PhraseWallet from '../utils/generateWallet/phrase-wallet';
import { RequestQueueWithPromise } from '../utils/queue/queue';
import { validateAddress } from '../utils/validateAddress';
import { Sha256 } from 'asmcrypto.js';
import { TradeBotRespondMultipleRequest } from './transactions/TradeBotRespondMultipleRequest';
import { RESOURCE_TYPE_NUMBER_GROUP_CHAT_REACTIONS } from './constants/constants';
import { TradeBotRespondMultipleRequest } from '../transactions/TradeBotRespondMultipleRequest';
import { RESOURCE_TYPE_NUMBER_GROUP_CHAT_REACTIONS } from '../constants/constants';
import {
addDataPublishesCase,
addEnteredQmailTimestampCase,
@ -34,7 +34,6 @@ import {
cancelBanCase,
cancelInvitationToGroupCase,
checkLocalCase,
clearAllNotificationsCase,
createGroupCase,
createPollCase,
createRewardShareCase,
@ -68,7 +67,6 @@ import {
ltcBalanceCase,
makeAdminCase,
nameCase,
notificationCase,
notifyAdminRegenerateSecretKeyCase,
pauseAllQueuesCase,
publishGroupEncryptedResourceCase,
@ -90,9 +88,13 @@ import {
validApiCase,
versionCase,
voteOnPollCase,
} from './background-cases';
import { getData, removeKeysAndLogout, storeData } from './utils/chromeStorage';
import TradeBotRespondRequest from './transactions/TradeBotRespondRequest';
} from '../background/background-cases';
import {
getData,
removeKeysAndLogout,
storeData,
} from '../utils/chromeStorage';
import TradeBotRespondRequest from '../transactions/TradeBotRespondRequest';
export let groupSecretkeys = {};
@ -300,6 +302,7 @@ export const createEndpoint = async (endpoint, customApi?: string) => {
};
export const walletVersion = 2;
// List of your API endpoints
const apiEndpoints = [
'https://api.qortal.org',
@ -433,10 +436,6 @@ export async function performPowTask(chatBytes, difficulty) {
});
}
function playNotificationSound() {
// chrome.runtime.sendMessage({ action: "PLAY_NOTIFICATION_SOUND" });
}
const handleNotificationDirect = async (directs) => {
let isFocused;
const wallet = await getSaveWallet();
@ -600,7 +599,7 @@ export function updateThreadActivity({
threads = JSON.parse(storedData);
}
let lastResetTime = threads.lastResetTime || 0;
const lastResetTime = threads.lastResetTime || 0;
// Check if a week has passed since the last reset
if (currentTime - lastResetTime > ONE_WEEK_IN_MS) {
@ -650,7 +649,7 @@ export function updateThreadActivity({
const handleNotification = async (groups) => {
const wallet = await getSaveWallet();
const address = wallet.address0;
let isDisableNotifications =
const isDisableNotifications =
(await getUserSettings({ key: 'disable-push-notifications' })) || false;
let mutedGroups = (await getUserSettings({ key: 'mutedGroups' })) || [];
@ -675,7 +674,6 @@ const handleNotification = async (groups) => {
const newActiveChats = data;
const oldActiveChats = await getChatHeads();
let results = [];
let newestLatestTimestamp = null;
let oldestLatestTimestamp = null;
// Find the latest timestamp from newActiveChats
@ -875,13 +873,6 @@ export async function storeWallets(wallets) {
});
}
export async function clearAllNotifications() {
// const notifications = await chrome.notifications.getAll();
// for (const notificationId of Object.keys(notifications)) {
// await chrome.notifications.clear(notificationId);
// }
}
export async function getUserInfo() {
const wallet = await getSaveWallet();
const address = wallet.address0;
@ -3230,9 +3221,6 @@ function setupMessageListener() {
case 'addGroupNotificationTimestamp':
addGroupNotificationTimestampCase(request, event);
break;
case 'clearAllNotifications':
clearAllNotificationsCase(request, event);
break;
case 'setGroupData':
setGroupDataCase(request, event);
break;

View File

@ -1,14 +0,0 @@
export const CustomSvg = ({ src, color = 'black', size = 24 }) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
style={{ fill: color }}
>
{src}
</svg>
);
};

View File

@ -37,7 +37,13 @@ export const AppInfo = ({ app, myName }) => {
);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const isSelectedAppPinned = !!sortablePinnedApps?.find(
(item) => item?.name === app?.name && item?.service === app?.service

View File

@ -42,7 +42,13 @@ export const AppInfoSnippet = ({
);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
return (
<AppInfoSnippetContainer

View File

@ -16,13 +16,13 @@ import {
useTheme,
} from '@mui/material';
import { styled } from '@mui/system';
import { MyContext, getBaseApiReact } from '../../App';
import { QORTAL_APP_CONTEXT, getBaseApiReact } from '../../App';
import { Spacer } from '../../common/Spacer';
import { executeEvent } from '../../utils/events';
import { useDropzone } from 'react-dropzone';
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import { fileToBase64 } from '../../utils/fileReading';
import { useTranslation } from 'react-i18next';
@ -65,9 +65,15 @@ export const AppPublish = ({ names, categories }) => {
const [category, setCategory] = useState('');
const [appType, setAppType] = useState('APP');
const [file, setFile] = useState(null);
const { show } = useContext(MyContext);
const { show } = useContext(QORTAL_APP_CONTEXT);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [tag1, setTag1] = useState('');
const [tag2, setTag2] = useState('');
const [tag3, setTag3] = useState('');

View File

@ -1,7 +1,7 @@
import { Box, Rating } from '@mui/material';
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
import { getFee } from '../../background';
import { MyContext, getBaseApiReact } from '../../App';
import { getFee } from '../../background/background.ts';
import { QORTAL_APP_CONTEXT, getBaseApiReact } from '../../App';
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
import { StarFilledIcon } from '../../assets/Icons/StarFilled';
import { StarEmptyIcon } from '../../assets/Icons/StarEmpty';
@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next';
export const AppRating = ({ app, myName, ratingCountPosition = 'right' }) => {
const [value, setValue] = useState(0);
const { show } = useContext(MyContext);
const { show } = useContext(QORTAL_APP_CONTEXT);
const [hasPublishedRating, setHasPublishedRating] = useState<null | boolean>(
null
);
@ -20,7 +20,13 @@ export const AppRating = ({ app, myName, ratingCountPosition = 'right' }) => {
const [openSnack, setOpenSnack] = useState(false);
const [infoSnack, setInfoSnack] = useState(null);
const hasCalledRef = useRef(false);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const getRating = useCallback(async (name, service) => {
try {

View File

@ -45,7 +45,13 @@ export const AppsCategoryDesktop = ({
const [searchValue, setSearchValue] = useState('');
const virtuosoRef = useRef(null);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const categoryList = useMemo(() => {
if (category?.id === 'all') return availableQapps;

View File

@ -1,7 +1,7 @@
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
import { AppsHomeDesktop } from './AppsHomeDesktop';
import { Spacer } from '../../common/Spacer';
import { MyContext, getBaseApiReact } from '../../App';
import { QORTAL_APP_CONTEXT, getBaseApiReact } from '../../App';
import { AppInfo } from './AppInfo';
import {
executeEvent,
@ -48,9 +48,15 @@ export const AppsDesktop = ({
const [categories, setCategories] = useState([]);
const iframeRefs = useRef({});
const [isEnabledDevMode, setIsEnabledDevMode] = useAtom(enabledDevModeAtom);
const { showTutorial } = useContext(MyContext);
const { showTutorial } = useContext(QORTAL_APP_CONTEXT);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const myApp = useMemo(() => {
return availableQapps.find(

View File

@ -47,7 +47,13 @@ export const AppsDevMode = ({
const [categories, setCategories] = useState([]);
const iframeRefs = useRef({});
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
useEffect(() => {
setTimeout(() => {

View File

@ -19,11 +19,11 @@ import {
Input,
} from '@mui/material';
import { Add } from '@mui/icons-material';
import { MyContext, getBaseApiReact } from '../../App';
import { QORTAL_APP_CONTEXT, getBaseApiReact } from '../../App';
import { executeEvent } from '../../utils/events';
import { Spacer } from '../../common/Spacer';
import { useModal } from '../../common/useModal';
import { createEndpoint, isUsingLocal } from '../../background';
import { useModal } from '../../hooks/useModal.tsx';
import { createEndpoint, isUsingLocal } from '../../background/background.ts';
import { Label } from '../Group/AddGroup';
import ShortUniqueId from 'short-unique-id';
import swaggerSVG from '../../assets/svgs/swagger.svg';
@ -41,14 +41,20 @@ export const AppsDevModeHome = ({
const [domain, setDomain] = useState('127.0.0.1');
const [port, setPort] = useState('');
const [selectedPreviewFile, setSelectedPreviewFile] = useState(null);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const { isShow, onCancel, onOk, show, message } = useModal();
const {
openSnackGlobal,
setOpenSnackGlobal,
infoSnackCustom,
setInfoSnackCustom,
} = useContext(MyContext);
} = useContext(QORTAL_APP_CONTEXT);
const handleSelectFile = async (existingFilePath) => {
const filePath = existingFilePath || (await window.electron.selectFile());

View File

@ -27,7 +27,13 @@ export const AppsHomeDesktop = ({
}) => {
const [qortalUrl, setQortalUrl] = useState('');
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const openQortalUrl = () => {
try {

View File

@ -105,7 +105,13 @@ export const AppsLibraryDesktop = ({
const [searchValue, setSearchValue] = useState('');
const virtuosoRef = useRef(null);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const officialApps = useMemo(() => {
return availableQapps.filter(

View File

@ -76,7 +76,13 @@ export const AppsNavBarDesktop = ({ disableBack }) => {
);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [isNewTabWindow, setIsNewTabWindow] = useState(false);
const tabsRef = useRef(null);
const [anchorEl, setAnchorEl] = useState(null);

View File

@ -31,10 +31,10 @@ import {
} from './Apps-styles';
import AddIcon from '@mui/icons-material/Add';
import ImageUploader from '../../common/ImageUploader';
import { MyContext } from '../../App';
import { QORTAL_APP_CONTEXT } from '../../App';
import { fileToBase64 } from '../../utils/fileReading';
import { objectToBase64 } from '../../qdn/encryption/group-encryption';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import { useAtom } from 'jotai';
import { useTranslation } from 'react-i18next';
@ -59,11 +59,17 @@ export const AppsPrivate = ({ myName }) => {
const [isOpenPrivateModal, setIsOpenPrivateModal] = useState(false);
const { show, setInfoSnackCustom, setOpenSnackGlobal } =
useContext(MyContext);
useContext(QORTAL_APP_CONTEXT);
const [memberGroups] = useAtom(memberGroupsAtom);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const myGroupsPrivate = useMemo(() => {
return memberGroups?.filter(

View File

@ -27,7 +27,13 @@ import { useTranslation } from 'react-i18next';
export const BuyQortInformation = ({ balance }) => {
const [isOpen, setIsOpen] = useState(false);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const openBuyQortInfoFunc = useCallback(
(e) => {

View File

@ -19,7 +19,13 @@ export const AdminSpace = ({
isOwner,
}) => {
const [isMoved, setIsMoved] = useState(false);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
useEffect(() => {
if (hide) {

View File

@ -1,6 +1,6 @@
import { useCallback, useContext, useEffect, useState } from 'react';
import {
MyContext,
QORTAL_APP_CONTEXT,
getArbitraryEndpointReact,
getBaseApiReact,
} from '../../App';
@ -10,9 +10,9 @@ import {
getPublishesFromAdmins,
validateSecretKey,
} from '../Group/Group';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import { base64ToUint8Array } from '../../qdn/encryption/group-encryption';
import { uint8ArrayToObject } from '../../backgroundFunctions/encryption';
import { uint8ArrayToObject } from '../../encryption/encryption.ts';
import { formatTimestampForum } from '../../utils/time';
import { Spacer } from '../../common/Spacer';
import { GroupAvatar } from './GroupAvatar';
@ -73,8 +73,14 @@ export const AdminSpaceInner = ({
useState(null);
const [isLoadingPublishKey, setIsLoadingPublishKey] = useState(false);
const { show, setInfoSnackCustom, setOpenSnackGlobal } =
useContext(MyContext);
const { t } = useTranslation(['auth', 'core', 'group']);
useContext(QORTAL_APP_CONTEXT);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const getAdminGroupSecretKey = useCallback(async () => {
try {

View File

@ -8,7 +8,7 @@ import { Box, CircularProgress, useTheme } from '@mui/material';
import { objectToBase64 } from '../../qdn/encryption/group-encryption';
import ShortUniqueId from 'short-unique-id';
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import {
decryptPublishes,
getTempPublish,
@ -40,7 +40,13 @@ export const AnnouncementDiscussion = ({
isPrivate,
}) => {
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [isSending, setIsSending] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [isFocusedParent, setIsFocusedParent] = useState(false);

View File

@ -18,7 +18,13 @@ export const AnnouncementItem = ({
myName,
}) => {
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [commentLength, setCommentLength] = useState(0);
const getNumberOfComments = useCallback(async () => {

View File

@ -20,7 +20,13 @@ export const AnnouncementList = ({
myName,
}) => {
const [messages, setMessages] = useState(initialMessages);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
useEffect(() => {
cache.clearAll();

View File

@ -14,8 +14,8 @@ import {
pauseAllQueues,
resumeAllQueues,
} from '../../App';
import { getPublicKey } from '../../background';
import { useMessageQueue } from '../../MessageQueueContext';
import { getPublicKey } from '../../background/background.ts';
import { useMessageQueue } from '../../messaging/MessageQueueContext.tsx';
import {
executeEvent,
subscribeToEvent,
@ -42,7 +42,13 @@ export const ChatDirect = ({
setMobileViewModeKeepOpen,
}) => {
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const { queueChats, addToQueue, processWithNewMessages } = useMessageQueue();
const [isFocusedParent, setIsFocusedParent] = useState(false);
const [onEditMessage, setOnEditMessage] = useState(null);

View File

@ -19,13 +19,13 @@ import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
import {
getBaseApiReact,
getBaseApiReactSocket,
MyContext,
QORTAL_APP_CONTEXT,
pauseAllQueues,
resumeAllQueues,
} from '../../App';
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
import { PUBLIC_NOTIFICATION_CODE_FIRST_SECRET_KEY } from '../../constants/constants';
import { useMessageQueue } from '../../MessageQueueContext';
import { useMessageQueue } from '../../messaging/MessageQueueContext.tsx';
import {
executeEvent,
subscribeToEvent,
@ -44,7 +44,7 @@ import ShortUniqueId from 'short-unique-id';
import { ReplyPreview } from './MessageItem';
import { ExitIcon } from '../../assets/Icons/ExitIcon';
import { RESOURCE_TYPE_NUMBER_GROUP_CHAT_REACTIONS } from '../../constants/constants';
import { getFee, isExtMsg } from '../../background';
import { getFee, isExtMsg } from '../../background/background.ts';
import AppViewerContainer from '../Apps/AppViewerContainer';
import CloseIcon from '@mui/icons-material/Close';
import { throttle } from 'lodash';
@ -71,7 +71,7 @@ export const ChatGroup = ({
hideView,
isPrivate,
}) => {
const { isUserBlocked, show } = useContext(MyContext);
const { isUserBlocked, show } = useContext(QORTAL_APP_CONTEXT);
const [messages, setMessages] = useState([]);
const [chatReferences, setChatReferences] = useState({});
const [isSending, setIsSending] = useState(false);
@ -96,7 +96,13 @@ export const ChatGroup = ({
const [, forceUpdate] = useReducer((x) => x + 1, 0);
const lastReadTimestamp = useRef(null);
const handleUpdateRef = useRef(null);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const getTimestampEnterChat = async (selectedGroup) => {
try {

View File

@ -181,7 +181,13 @@ export const ChatList = ({
}, []);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
return (
<Box

View File

@ -60,7 +60,13 @@ export const ChatOptions = ({
const [searchValue, setSearchValue] = useState('');
const [selectedMember, setSelectedMember] = useState(0);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const parentRef = useRef(null);
const parentRefMentions = useRef(null);
const [lastMentionTimestamp, setLastMentionTimestamp] = useState(null);

View File

@ -3,19 +3,19 @@ import { Box, Button, Typography, useTheme } from '@mui/material';
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
import { LoadingButton } from '@mui/lab';
import {
MyContext,
QORTAL_APP_CONTEXT,
getArbitraryEndpointReact,
getBaseApiReact,
pauseAllQueues,
} from '../../App';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import {
decryptResource,
getGroupAdmins,
validateSecretKey,
} from '../Group/Group';
import { base64ToUint8Array } from '../../qdn/encryption/group-encryption';
import { uint8ArrayToObject } from '../../backgroundFunctions/encryption';
import { uint8ArrayToObject } from '../../encryption/encryption.ts';
import { useSetAtom } from 'jotai';
import { txListAtom } from '../../atoms/global';
import { useTranslation } from 'react-i18next';
@ -32,7 +32,7 @@ export const CreateCommonSecret = ({
setIsForceShowCreationKeyPopup,
isForceShowCreationKeyPopup,
}) => {
const { show } = useContext(MyContext);
const { show } = useContext(QORTAL_APP_CONTEXT);
const setTxList = useSetAtom(txListAtom);
const [openSnack, setOpenSnack] = useState(false);
@ -40,7 +40,13 @@ export const CreateCommonSecret = ({
const [isLoading, setIsLoading] = useState(false);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const getPublishesFromAdmins = async (admins: string[]) => {
const queryString = admins.map((name) => `name=${name}`).join('&');

View File

@ -7,7 +7,7 @@ import {
useRef,
useState,
} from 'react';
import { uint8ArrayToObject } from '../../backgroundFunctions/encryption';
import { uint8ArrayToObject } from '../../encryption/encryption.ts';
import {
base64ToUint8Array,
objectToBase64,
@ -15,7 +15,7 @@ import {
import Tiptap from './TipTap';
import { CustomButton } from '../../styles/App-styles';
import CircularProgress from '@mui/material/CircularProgress';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
import { Box, Typography, useTheme } from '@mui/material';
import { Spacer } from '../../common/Spacer';
@ -24,7 +24,7 @@ import { AnnouncementList } from './AnnouncementList';
import CampaignIcon from '@mui/icons-material/Campaign';
import { AnnouncementDiscussion } from './AnnouncementDiscussion';
import {
MyContext,
QORTAL_APP_CONTEXT,
getArbitraryEndpointReact,
getBaseApiReact,
pauseAllQueues,
@ -142,7 +142,7 @@ export const GroupAnnouncements = ({
const [selectedAnnouncement, setSelectedAnnouncement] = useState(null);
const [isFocusedParent, setIsFocusedParent] = useState(false);
const { show } = useContext(MyContext);
const { show } = useContext(QORTAL_APP_CONTEXT);
const [openSnack, setOpenSnack] = useState(false);
const [infoSnack, setInfoSnack] = useState(null);
const hasInitialized = useRef(false);
@ -153,7 +153,13 @@ export const GroupAnnouncements = ({
editorRef.current = editorInstance;
};
const [, forceUpdate] = useReducer((x) => x + 1, 0);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const triggerRerender = () => {
forceUpdate(); // Trigger re-render by updating the state

View File

@ -1,7 +1,7 @@
import { useCallback, useContext, useEffect, useState } from 'react';
import Logo2 from '../../assets/svgs/Logo2.svg';
import {
MyContext,
QORTAL_APP_CONTEXT,
getArbitraryEndpointReact,
getBaseApiReact,
} from '../../App';
@ -16,7 +16,7 @@ import {
} from '@mui/material';
import { Spacer } from '../../common/Spacer';
import ImageUploader from '../../common/ImageUploader';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import { fileToBase64 } from '../../utils/fileReading';
import { LoadingButton } from '@mui/lab';
import ErrorIcon from '@mui/icons-material/Error';
@ -32,8 +32,14 @@ export const GroupAvatar = ({
const [hasAvatar, setHasAvatar] = useState(false);
const [avatarFile, setAvatarFile] = useState(null);
const [tempAvatar, setTempAvatar] = useState(null);
const { show } = useContext(MyContext);
const { t } = useTranslation(['auth', 'core', 'group']);
const { show } = useContext(QORTAL_APP_CONTEXT);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [anchorEl, setAnchorEl] = useState(null);
const [isLoading, setIsLoading] = useState(false);
// Handle child element click to open Popover
@ -262,7 +268,13 @@ const PopoverComp = ({
myName,
}) => {
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
return (
<Popover

View File

@ -2,7 +2,13 @@ import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import { useTranslation } from 'react-i18next';
export default forwardRef((props, ref) => {
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [selectedIndex, setSelectedIndex] = useState(0);

View File

@ -22,7 +22,7 @@ import {
useTheme,
} from '@mui/material';
import { formatTimestamp } from '../../utils/time';
import { MyContext, getBaseApiReact } from '../../App';
import { QORTAL_APP_CONTEXT, getBaseApiReact } from '../../App';
import { generateHTML } from '@tiptap/react';
import Highlight from '@tiptap/extension-highlight';
import Mention from '@tiptap/extension-mention';
@ -113,7 +113,7 @@ export const MessageItem = memo(
onEdit,
isPrivate,
}) => {
const { getIndividualUserInfo } = useContext(MyContext);
const { getIndividualUserInfo } = useContext(QORTAL_APP_CONTEXT);
const [anchorEl, setAnchorEl] = useState(null);
const [selectedReaction, setSelectedReaction] = useState(null);
const [userInfo, setUserInfo] = useState(null);
@ -170,7 +170,13 @@ export const MessageItem = memo(
}, [message?.id]);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
return (
<>
@ -612,7 +618,13 @@ export const MessageItem = memo(
export const ReplyPreview = ({ message, isEdit = false }) => {
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
return (
<Box

View File

@ -54,7 +54,13 @@ const MenuBar = memo(
const { editor } = useCurrentEditor();
const fileInputRef = useRef(null);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
useEffect(() => {
if (editor && setEditorRef) {

View File

@ -13,7 +13,13 @@ export const CoreSyncStatus = () => {
const [coreInfos, setCoreInfos] = useState({});
const [isUsingGateway, setIsUsingGateway] = useState(false);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const theme = useTheme();
useEffect(() => {

View File

@ -67,7 +67,13 @@ export const DesktopFooter = ({
}) => {
const [isEnabledDevMode, setIsEnabledDevMode] = useAtom(enabledDevModeAtom);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
if (hide) return;
return (

View File

@ -84,7 +84,13 @@ export const DesktopHeader = ({
}) => {
const [value, setValue] = useState(0);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
return (
<Box

View File

@ -28,7 +28,13 @@ export const DesktopSideBar = ({
const [isEnabledDevMode, setIsEnabledDevMode] = useAtom(enabledDevModeAtom);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
return (
<Box

View File

@ -1,5 +1,5 @@
import { useContext, useState } from 'react';
import { MyContext, getBaseApiReact } from '../../App';
import { QORTAL_APP_CONTEXT, getBaseApiReact } from '../../App';
import {
Card,
CardContent,
@ -36,9 +36,15 @@ export const AttachmentCard = ({
selectedGroupId,
}) => {
const [isOpen, setIsOpen] = useState(true);
const { downloadResource } = useContext(MyContext);
const { downloadResource } = useContext(QORTAL_APP_CONTEXT);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const saveToDisk = async () => {
const { name, service, identifier } = resourceData;
@ -226,8 +232,7 @@ export const AttachmentCard = ({
width: '100%',
}}
>
{' '}
<CustomLoader />{' '}
<CustomLoader />
</Box>
)}
{errorMsg && (

View File

@ -63,7 +63,13 @@ export const Embed = ({ embedLink }) => {
const [parsedData, setParsedData] = useState(null);
const setBlobs = useSetAtom(blobControllerAtom);
const [selectedGroupId] = useAtom(selectedGroupIdAtom);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const resourceData = useMemo(() => {
const parsedDataOnTheFly = parseQortalLink(embedLink);
if (

View File

@ -30,7 +30,13 @@ export const ImageCard = ({
encryptionType,
}) => {
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [isOpen, setIsOpen] = useState(true);
const [height, setHeight] = useState('400px');

View File

@ -1,5 +1,5 @@
import { useContext, useEffect, useState } from 'react';
import { MyContext } from '../../App';
import { QORTAL_APP_CONTEXT } from '../../App';
import {
Card,
CardContent,
@ -16,7 +16,7 @@ import {
} from '@mui/material';
import { getNameInfo } from '../Group/Group';
import PollIcon from '@mui/icons-material/Poll';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import RefreshIcon from '@mui/icons-material/Refresh';
import { Spacer } from '../../common/Spacer';
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
@ -37,10 +37,16 @@ export const PollCard = ({
const [ownerName, setOwnerName] = useState('');
const [showResults, setShowResults] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const { show, userInfo } = useContext(MyContext);
const { show, userInfo } = useContext(QORTAL_APP_CONTEXT);
const [isLoadingSubmit, setIsLoadingSubmit] = useState(false);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const handleVote = async () => {
const fee = await getFee('VOTE_ON_POLL');
@ -379,7 +385,13 @@ const PollResults = ({ votes }) => {
...votes?.voteCounts?.map((option) => option.voteCount)
);
const options = votes?.voteCounts;
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
return (
<Box sx={{ width: '100%', p: 2 }}>

View File

@ -21,7 +21,7 @@ import {
} from '@mui/icons-material';
import { styled } from '@mui/system';
import { Refresh } from '@mui/icons-material';
import { MyContext, getBaseApiReact } from '../../App';
import { QORTAL_APP_CONTEXT, getBaseApiReact } from '../../App';
import { resourceKeySelector } from '../../atoms/global';
import { useAtomValue } from 'jotai';
@ -88,7 +88,7 @@ export const VideoPlayer: FC<VideoPlayerProps> = ({
}, [service, name, identifier]);
const download = useAtomValue(resourceKeySelector(keyIdentifier));
const { downloadResource } = useContext(MyContext);
const { downloadResource } = useContext(QORTAL_APP_CONTEXT);
const videoRef = useRef<HTMLVideoElement | null>(null);
const [playing, setPlaying] = useState(false);
const [volume, setVolume] = useState(1);

View File

@ -32,7 +32,13 @@ export const GeneralNotifications = ({ address }) => {
setAnchorEl(event.currentTarget);
};
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const theme = useTheme();
return (

View File

@ -11,8 +11,8 @@ import {
useTheme,
} from '@mui/material';
import { CustomButtonAccept } from '../../styles/App-styles';
import { getBaseApiReact, MyContext } from '../../App';
import { getFee } from '../../background';
import { getBaseApiReact, QORTAL_APP_CONTEXT } from '../../App';
import { getFee } from '../../background/background.ts';
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
import { FidgetSpinner } from 'react-loader-spinner';
import { useAtom, useSetAtom } from 'jotai';
@ -20,7 +20,7 @@ import { memberGroupsAtom, txListAtom } from '../../atoms/global';
import { useTranslation } from 'react-i18next';
export const JoinGroup = () => {
const { show } = useContext(MyContext);
const { show } = useContext(QORTAL_APP_CONTEXT);
const setTxList = useSetAtom(txListAtom);
const [memberGroups] = useAtom(memberGroupsAtom);
const [openSnack, setOpenSnack] = useState(false);
@ -29,7 +29,13 @@ export const JoinGroup = () => {
const [isLoadingInfo, setIsLoadingInfo] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [isLoadingJoinGroup, setIsLoadingJoinGroup] = useState(false);
const handleJoinGroup = async (e) => {

View File

@ -34,8 +34,8 @@ import {
import { AddGroupList } from './AddGroupList';
import { UserListOfInvites } from './UserListOfInvites';
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
import { getFee } from '../../background';
import { MyContext } from '../../App';
import { getFee } from '../../background/background.ts';
import { QORTAL_APP_CONTEXT } from '../../App';
import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
import { useTranslation } from 'react-i18next';
import { useSetAtom } from 'jotai';
@ -59,7 +59,7 @@ const Transition = forwardRef(function Transition(
});
export const AddGroup = ({ address, open, setOpen }) => {
const { show } = useContext(MyContext);
const { show } = useContext(QORTAL_APP_CONTEXT);
const setTxList = useSetAtom(txListAtom);
const [openAdvance, setOpenAdvance] = useState(false);
@ -97,7 +97,13 @@ export const AddGroup = ({ address, open, setOpen }) => {
setMaxBlock(event.target.value as string);
};
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const theme = useTheme();
const handleCreateGroup = async () => {

View File

@ -23,9 +23,9 @@ import {
List,
} from 'react-virtualized';
import _ from 'lodash';
import { MyContext, getBaseApiReact } from '../../App';
import { QORTAL_APP_CONTEXT, getBaseApiReact } from '../../App';
import { LoadingButton } from '@mui/lab';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import LockIcon from '@mui/icons-material/Lock';
import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmailerrorred';
import { Spacer } from '../../common/Spacer';
@ -39,10 +39,16 @@ const cache = new CellMeasurerCache({
});
export const AddGroupList = ({ setInfoSnack, setOpenSnack }) => {
const { show } = useContext(MyContext);
const { show } = useContext(QORTAL_APP_CONTEXT);
const [memberGroups] = useAtom(memberGroupsAtom);
const setTxList = useSetAtom(txListAtom);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [groups, setGroups] = useState([]);
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open

View File

@ -11,7 +11,7 @@ import {
useTheme,
} from '@mui/material';
import { useContext, useEffect, useState } from 'react';
import { getBaseApiReact, MyContext } from '../../App';
import { getBaseApiReact, QORTAL_APP_CONTEXT } from '../../App';
import { Spacer } from '../../common/Spacer';
import {
executeEvent,
@ -20,7 +20,7 @@ import {
} from '../../utils/events';
import { validateAddress } from '../../utils/validateAddress';
import { getNameInfo, requestQueueMemberNames } from './Group';
import { useModal } from '../../common/useModal';
import { useModal } from '../../hooks/useModal';
import { isOpenBlockedModalAtom } from '../../atoms/global';
import InfoIcon from '@mui/icons-material/Info';
import { useAtom } from 'jotai';
@ -28,7 +28,13 @@ import { useTranslation } from 'react-i18next';
export const BlockedUsersModal = () => {
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [isOpenBlockedModal, setIsOpenBlockedModal] = useAtom(
isOpenBlockedModalAtom
);
@ -42,7 +48,7 @@ export const BlockedUsersModal = () => {
addToBlockList,
setOpenSnackGlobal,
setInfoSnackCustom,
} = useContext(MyContext);
} = useContext(QORTAL_APP_CONTEXT);
const [blockedUsers, setBlockedUsers] = useState({
addresses: {},

View File

@ -73,7 +73,13 @@ export const GroupMail = ({
const anchorElInstanceFilter = useRef<any>(null);
const [tempPublishedList, setTempPublishedList] = useState([]);
const dataPublishes = useRef({});
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const theme = useTheme();
const [isLoading, setIsLoading] = useState(false);
const groupIdRef = useRef<any>(null);

View File

@ -17,8 +17,12 @@ import { ReusableModal } from './ReusableModal';
import { Spacer } from '../../../common/Spacer';
import { CreateThreadIcon } from '../../../assets/Icons/CreateThreadIcon';
import { SendNewMessage } from '../../../assets/Icons/SendNewMessage';
import { MyContext, pauseAllQueues, resumeAllQueues } from '../../../App';
import { getFee } from '../../../background';
import {
QORTAL_APP_CONTEXT,
pauseAllQueues,
resumeAllQueues,
} from '../../../App';
import { getFee } from '../../../background/background';
import TipTap from '../../Chat/TipTap';
import { MessageDisplay } from '../../Chat/MessageDisplay';
import { CustomizedSnackbars } from '../../Snackbar/Snackbar';
@ -140,8 +144,14 @@ export const NewThread = ({
setPostReply,
isPrivate,
}: NewMessageProps) => {
const { t } = useTranslation(['auth', 'core', 'group']);
const { show } = useContext(MyContext);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const { show } = useContext(QORTAL_APP_CONTEXT);
const [isOpen, setIsOpen] = useState<boolean>(false);
const [value, setValue] = useState('');
const [isSending, setIsSending] = useState(false);

View File

@ -115,7 +115,13 @@ export const Thread = ({
const [isLoading, setIsLoading] = useState(true);
const [postReply, setPostReply] = useState(null);
const [hasLastPage, setHasLastPage] = useState(false);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const theme = useTheme();
// Update: Use a new ref for the scrollable container
const threadContainerRef = useRef(null);
@ -931,6 +937,7 @@ export const Thread = ({
}}
>
<CustomLoader />
<Typography
sx={{
fontSize: '18px',

View File

@ -13,7 +13,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { ChatGroup } from '../Chat/ChatGroup';
import { CreateCommonSecret } from '../Chat/CreateCommonSecret';
import { base64ToUint8Array } from '../../qdn/encryption/group-encryption';
import { uint8ArrayToObject } from '../../backgroundFunctions/encryption';
import { uint8ArrayToObject } from '../../encryption/encryption';
import { AddGroup } from './AddGroup';
import CreateIcon from '@mui/icons-material/Create';
import {
@ -43,7 +43,7 @@ import {
} from '../../utils/events';
import { RequestQueueWithPromise } from '../../utils/queue/queue';
import { WebSocketActive } from './WebsocketActive';
import { useMessageQueue } from '../../MessageQueueContext';
import { useMessageQueue } from '../../messaging/MessageQueueContext';
import { HomeDesktop } from './HomeDesktop';
import { IconWrapper } from '../Desktop/DesktopFooter';
import { DesktopHeader } from '../Desktop/DesktopHeader';
@ -444,7 +444,13 @@ export const Group = ({
const [isForceShowCreationKeyPopup, setIsForceShowCreationKeyPopup] =
useState(false);
const groupsOwnerNamesRef = useRef({});
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [groupsProperties, setGroupsProperties] = useAtom(groupsPropertiesAtom);
const setGroupsOwnerNames = useSetAtom(groupsOwnerNamesAtom);

View File

@ -18,7 +18,13 @@ export const GroupInvites = ({ myAddress, setOpenAddGroup }) => {
const [groupsWithJoinRequests, setGroupsWithJoinRequests] = useState([]);
const [isExpanded, setIsExpanded] = useState(false);
const [loading, setLoading] = useState(true);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const theme = useTheme();
const getJoinRequests = async () => {

View File

@ -28,7 +28,13 @@ export const GroupJoinRequests = ({
setDesktopViewMode,
}) => {
const [isExpanded, setIsExpanded] = useState(false);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [groupsWithJoinRequests, setGroupsWithJoinRequests] = useState([]);
const [loading, setLoading] = useState(true);
const [txList] = useAtom(txListAtom);

View File

@ -49,7 +49,13 @@ export const GroupList = ({
myAddress,
}) => {
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [isRunningPublicNode] = useAtom(isRunningPublicNodeAtom);
return (

View File

@ -31,7 +31,13 @@ export const HomeDesktop = ({
const [checked1, setChecked1] = useState(false);
const [checked2, setChecked2] = useState(false);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const theme = useTheme();
useEffect(() => {

View File

@ -3,14 +3,20 @@ import { Box, Input, MenuItem, Select, SelectChangeEvent } from '@mui/material';
import { useState } from 'react';
import { Spacer } from '../../common/Spacer';
import { Label } from './AddGroup';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import { useTranslation } from 'react-i18next';
export const InviteMember = ({ groupId, setInfoSnack, setOpenSnack, show }) => {
const [value, setValue] = useState('');
const [expiryTime, setExpiryTime] = useState<string>('259200');
const [isLoadingInvite, setIsLoadingInvite] = useState(false);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const inviteMember = async () => {
try {

View File

@ -15,7 +15,7 @@ import {
List,
} from 'react-virtualized';
import { getNameInfo } from './Group';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import { LoadingButton } from '@mui/lab';
import { getBaseApiReact } from '../../App';
import { useTranslation } from 'react-i18next';
@ -56,7 +56,13 @@ export const ListOfBans = ({ groupId, setInfoSnack, setOpenSnack, show }) => {
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
const listRef = useRef(null);
const [isLoadingUnban, setIsLoadingUnban] = useState(false);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const getInvites = async (groupId) => {
try {

View File

@ -21,7 +21,7 @@ import { LoadingButton } from '@mui/lab';
import LockIcon from '@mui/icons-material/Lock';
import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmailerrorred';
import {
MyContext,
QORTAL_APP_CONTEXT,
getArbitraryEndpointReact,
getBaseApiReact,
} from '../../App';
@ -42,7 +42,7 @@ import { useVirtualizer } from '@tanstack/react-virtual';
import ErrorBoundary from '../../common/ErrorBoundary';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import { useAtom, useSetAtom } from 'jotai';
import { useTranslation } from 'react-i18next';
@ -88,10 +88,16 @@ export const ListOfGroupPromotions = () => {
const [fee, setFee] = useState(null);
const [isLoadingJoinGroup, setIsLoadingJoinGroup] = useState(false);
const [isLoadingPublish, setIsLoadingPublish] = useState(false);
const { show } = useContext(MyContext);
const { show } = useContext(QORTAL_APP_CONTEXT);
const setTxList = useSetAtom(txListAtom);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const listRef = useRef(null);
const rowVirtualizer = useVirtualizer({
count: promotions.length,

View File

@ -15,7 +15,7 @@ import {
List,
} from 'react-virtualized';
import { getNameInfo } from './Group';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import { LoadingButton } from '@mui/lab';
import { getBaseApiReact } from '../../App';
import { useTranslation } from 'react-i18next';
@ -60,7 +60,13 @@ export const ListOfInvites = ({
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
const [isLoadingCancelInvite, setIsLoadingCancelInvite] = useState(false);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const listRef = useRef(null);
const getInvites = async (groupId) => {

View File

@ -15,7 +15,7 @@ import {
List,
} from 'react-virtualized';
import { getNameInfo } from './Group';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import { LoadingButton } from '@mui/lab';
import { getBaseApiReact } from '../../App';
import { txListAtom } from '../../atoms/global';
@ -64,7 +64,13 @@ export const ListOfJoinRequests = ({
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
const listRef = useRef(null);
const [isLoadingAccept, setIsLoadingAccept] = useState(false);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const getInvites = async (groupId) => {
try {

View File

@ -17,7 +17,7 @@ import {
List,
} from 'react-virtualized';
import { LoadingButton } from '@mui/lab';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import { getBaseApiReact } from '../../App';
import { useTranslation } from 'react-i18next';
@ -42,7 +42,13 @@ const ListOfMembers = ({
const [isLoadingMakeAdmin, setIsLoadingMakeAdmin] = useState(false);
const [isLoadingRemoveAdmin, setIsLoadingRemoveAdmin] = useState(false);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const listRef = useRef(null);
const handlePopoverOpen = (event, index) => {

View File

@ -14,7 +14,13 @@ import { useTranslation } from 'react-i18next';
export const ListOfThreadPostsWatched = () => {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const getPosts = async () => {
try {

View File

@ -25,10 +25,10 @@ import { ListOfBans } from './ListOfBans';
import { ListOfJoinRequests } from './ListOfJoinRequests';
import { Box, ButtonBase, Card, Tab, Tabs, useTheme } from '@mui/material';
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
import { MyContext, getBaseApiReact } from '../../App';
import { QORTAL_APP_CONTEXT, getBaseApiReact } from '../../App';
import { getGroupMembers, getNames } from './Group';
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import { LoadingButton } from '@mui/lab';
import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
import { Spacer } from '../../common/Spacer';
@ -71,8 +71,14 @@ export const ManageMembers = ({
setValue(newValue);
};
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { show } = useContext(MyContext);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const { show } = useContext(QORTAL_APP_CONTEXT);
const setTxList = useSetAtom(txListAtom);
const handleClose = () => {

View File

@ -54,7 +54,13 @@ export const QMailMessages = ({ userName, userAddress }) => {
const [loading, setLoading] = useState(true);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const getMails = useCallback(async () => {
try {

View File

@ -36,9 +36,9 @@ import { useAtom } from 'jotai';
import { decryptStoredWallet } from '../../utils/decryptWallet';
import { Spacer } from '../../common/Spacer';
import PhraseWallet from '../../utils/generateWallet/phrase-wallet';
import { walletVersion } from '../../background';
import Base58 from '../../deps/Base58';
import { MyContext } from '../../App';
import { walletVersion } from '../../background/background.ts';
import Base58 from '../../encryption/Base58.ts';
import { QORTAL_APP_CONTEXT } from '../../App';
import { useTranslation } from 'react-i18next';
const LocalNodeSwitch = styled(Switch)(({ theme }) => ({
@ -87,7 +87,13 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
const [checked, setChecked] = useState(false);
const [isEnabledDevMode, setIsEnabledDevMode] = useAtom(enabledDevModeAtom);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
setChecked(event.target.checked);
@ -233,8 +239,15 @@ const ExportPrivateKey = ({ rawWallet }) => {
const [password, setPassword] = useState('');
const [privateKey, setPrivateKey] = useState('');
const [isOpen, setIsOpen] = useState(false);
const { setOpenSnackGlobal, setInfoSnackCustom } = useContext(MyContext);
const { t } = useTranslation(['auth', 'core', 'group']);
const { setOpenSnackGlobal, setInfoSnackCustom } =
useContext(QORTAL_APP_CONTEXT);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const exportPrivateKeyFunc = async () => {
try {

View File

@ -14,9 +14,9 @@ import {
CellMeasurerCache,
List,
} from 'react-virtualized';
import { MyContext, getBaseApiReact } from '../../App';
import { QORTAL_APP_CONTEXT, getBaseApiReact } from '../../App';
import { LoadingButton } from '@mui/lab';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import LockIcon from '@mui/icons-material/Lock';
import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmailerrorred';
import { Spacer } from '../../common/Spacer';
@ -55,13 +55,19 @@ export const UserListOfInvites = ({
setInfoSnack,
setOpenSnack,
}) => {
const { show } = useContext(MyContext);
const { show } = useContext(QORTAL_APP_CONTEXT);
const setTxList = useSetAtom(txListAtom);
const [invites, setInvites] = useState<any[]>([]);
const [isLoading, setIsLoading] = useState(false);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
const listRef = useRef(null);

View File

@ -15,7 +15,13 @@ import { useAtom } from 'jotai';
import { useTranslation } from 'react-i18next';
export const WalletsAppWrapper = () => {
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const iframeRef = useRef(null);
const [isOpen, setIsOpen] = useState(false);
const [navigationController, setNavigationController] = useAtom(

View File

@ -1,6 +1,10 @@
import { useContext, useEffect, useState } from 'react';
import Logo2 from '../assets/svgs/Logo2.svg';
import { MyContext, getArbitraryEndpointReact, getBaseApiReact } from '../App';
import {
QORTAL_APP_CONTEXT,
getArbitraryEndpointReact,
getBaseApiReact,
} from '../App';
import {
Avatar,
Box,
@ -12,7 +16,7 @@ import {
} from '@mui/material';
import { Spacer } from '../common/Spacer';
import ImageUploader from '../common/ImageUploader';
import { getFee } from '../background';
import { getFee } from '../background/background.ts';
import { fileToBase64 } from '../utils/fileReading';
import { LoadingButton } from '@mui/lab';
import ErrorIcon from '@mui/icons-material/Error';
@ -22,7 +26,7 @@ export const MainAvatar = ({ myName, balance, setOpenSnack, setInfoSnack }) => {
const [hasAvatar, setHasAvatar] = useState(false);
const [avatarFile, setAvatarFile] = useState(null);
const [tempAvatar, setTempAvatar] = useState(null);
const { show } = useContext(MyContext);
const { show } = useContext(QORTAL_APP_CONTEXT);
const [anchorEl, setAnchorEl] = useState(null);
const [isLoading, setIsLoading] = useState(false);
@ -41,7 +45,13 @@ export const MainAvatar = ({ myName, balance, setOpenSnack, setInfoSnack }) => {
const open = Boolean(anchorEl);
const id = open ? 'avatar-img' : undefined;
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const checkIfAvatarExists = async () => {
try {
@ -253,7 +263,13 @@ const PopoverComp = ({
myName,
}) => {
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
return (
<Popover

View File

@ -21,10 +21,10 @@ import {
subscribeToEvent,
unsubscribeFromEvent,
} from '../../utils/events';
import { getFee } from '../../background';
import { getFee } from '../../background/background.ts';
import { Spacer } from '../../common/Spacer';
import { FidgetSpinner } from 'react-loader-spinner';
import { useModal } from '../../common/useModal';
import { useModal } from '../../hooks/useModal.tsx';
import { useAtom, useSetAtom } from 'jotai';
import { memberGroupsAtom, txListAtom } from '../../atoms/global';
import { useTranslation } from 'react-i18next';
@ -45,7 +45,13 @@ export const Minting = ({ setIsOpenMinting, myAddress, show }) => {
const { show: showKey, message } = useModal();
const { isShow: isShowNext, onOk, show: showNext } = useModal();
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [info, setInfo] = useState(null);
const [names, setNames] = useState({});
const [accountInfos, setAccountInfos] = useState({});

View File

@ -3,7 +3,13 @@ import { Spacer } from '../common/Spacer';
import { useTranslation } from 'react-i18next';
export const NewUsersCTA = ({ balance }) => {
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
if (balance === undefined || +balance > 0) return null;

View File

@ -27,12 +27,12 @@ import {
import Logo1Dark from '../assets/svgs/Logo1Dark.svg';
import HelpIcon from '@mui/icons-material/Help';
import { CustomizedSnackbars } from './Snackbar/Snackbar';
import { cleanUrl, gateways } from '../background';
import { cleanUrl, gateways } from '../background/background.ts';
import Tooltip, { TooltipProps, tooltipClasses } from '@mui/material/Tooltip';
import ThemeSelector from './Theme/ThemeSelector';
import { useTranslation } from 'react-i18next';
import LanguageSelector from './Language/LanguageSelector';
import { MyContext } from '../App';
import { QORTAL_APP_CONTEXT } from '../App';
export const manifestData = {
version: '0.5.4',
@ -81,7 +81,8 @@ export const NotAuthenticated = ({
const [showSelectApiKey, setShowSelectApiKey] = useState(false);
const [enteredApiKey, setEnteredApiKey] = useState('');
const [customNodeToSaveIndex, setCustomNodeToSaveIndex] = useState(null);
const { showTutorial, hasSeenGettingStarted } = useContext(MyContext);
const { showTutorial, hasSeenGettingStarted } =
useContext(QORTAL_APP_CONTEXT);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core']);

View File

@ -8,7 +8,13 @@ import { useTranslation } from 'react-i18next';
import { useAtom } from 'jotai';
export const QMailStatus = () => {
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const theme = useTheme();
const [lastEnteredTimestamp, setLastEnteredTimestamp] = useAtom(

View File

@ -2,12 +2,18 @@ import { Box, useTheme } from '@mui/material';
import { useState } from 'react';
import { TextP } from '../styles/App-styles';
import { Spacer } from '../common/Spacer';
import { getFee } from '../background';
import { getFee } from '../background/background.ts';
import { useTranslation } from 'react-i18next';
export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [paymentTo, setPaymentTo] = useState<string>(defaultPaymentTo);
const [paymentAmount, setPaymentAmount] = useState<number>(0);
const [paymentPassword, setPaymentPassword] = useState<string>('');

View File

@ -17,7 +17,7 @@ import {
import { Label } from './Group/AddGroup';
import { Spacer } from '../common/Spacer';
import { getBaseApiReact } from '../App';
import { getFee } from '../background';
import { getFee } from '../background/background.ts';
import RadioButtonCheckedIcon from '@mui/icons-material/RadioButtonChecked';
import { subscribeToEvent, unsubscribeFromEvent } from '../utils/events';
import { BarSpinner } from '../common/Spinners/BarSpinner/BarSpinner';
@ -51,7 +51,13 @@ export const RegisterName = ({
);
const [nameFee, setNameFee] = useState(null);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const checkIfNameExisits = async (name) => {
if (!name?.trim()) {
setIsNameAvailable(Availability.NULL);

View File

@ -18,20 +18,20 @@ import {
useTheme,
} from '@mui/material';
import { objectToBase64 } from '../../qdn/encryption/group-encryption';
import { MyContext } from '../../App';
import { getFee } from '../../background';
import { QORTAL_APP_CONTEXT } from '../../App';
import { getFee } from '../../background/background.ts';
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
import { SaveIcon } from '../../assets/Icons/SaveIcon';
import { IconWrapper } from '../Desktop/DesktopFooter';
import { Spacer } from '../../common/Spacer';
import { LoadingButton } from '@mui/lab';
import { saveToLocalStorage } from '../Apps/AppsNavBarDesktop';
import { decryptData, encryptData } from '../../qortalRequests/get';
import { decryptData, encryptData } from '../../qortal/get.ts';
import { saveFileToDiskGeneric } from '../../utils/generateWallet/generateWallet';
import {
base64ToUint8Array,
uint8ArrayToObject,
} from '../../backgroundFunctions/encryption';
} from '../../encryption/encryption.ts';
import { useTranslation } from 'react-i18next';
import { useAtom, useSetAtom } from 'jotai';
@ -82,9 +82,15 @@ export const Save = ({ isDesktop, disableWidth, myName }) => {
const [oldPinnedApps, setOldPinnedApps] = useAtom(oldPinnedAppsAtom);
const [anchorEl, setAnchorEl] = useState(null);
const { show } = useContext(MyContext);
const { show } = useContext(QORTAL_APP_CONTEXT);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const hasChanged = useMemo(() => {
const newChanges = {

View File

@ -82,7 +82,13 @@ export default function ThemeManager() {
});
const [currentTab, setCurrentTab] = useState('light');
const nameInputRef = useRef(null);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
useEffect(() => {
if (openEditor && nameInputRef.current) {

View File

@ -5,7 +5,13 @@ import DarkModeIcon from '@mui/icons-material/DarkMode';
import { useTranslation } from 'react-i18next';
const ThemeSelector = () => {
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const { themeMode, toggleTheme } = useThemeContext();
return (

View File

@ -1,5 +1,5 @@
import { useContext, useState } from 'react';
import { MyContext } from '../../App';
import { QORTAL_APP_CONTEXT } from '../../App';
import {
Button,
Dialog,
@ -16,7 +16,8 @@ import { VideoPlayer } from '../Embeds/VideoPlayer';
import { useTranslation } from 'react-i18next';
export const Tutorials = () => {
const { openTutorialModal, setOpenTutorialModal } = useContext(MyContext);
const { openTutorialModal, setOpenTutorialModal } =
useContext(QORTAL_APP_CONTEXT);
const [multiNumber, setMultiNumber] = useState(0);
const theme = useTheme();
const { t } = useTranslation(['core', 'tutorial']);

View File

@ -19,7 +19,10 @@ import {
useTheme,
Autocomplete,
} from '@mui/material';
import { getAddressInfo, getNameOrAddress } from '../../background';
import {
getAddressInfo,
getNameOrAddress,
} from '../../background/background.ts';
import { getBaseApiReact } from '../../App';
import { getNameInfo } from '../Group/Group';
import AccountCircleIcon from '@mui/icons-material/AccountCircle';
@ -46,7 +49,13 @@ function formatAddress(str) {
export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [nameOrAddress, setNameOrAddress] = useState('');
const [inputValue, setInputValue] = useState('');
const { results, isLoading } = useNameSearch(inputValue);

View File

@ -18,20 +18,24 @@ import {
Input,
useTheme,
} from '@mui/material';
import { CustomButton } from './styles/App-styles';
import { CustomButton } from '../styles/App-styles.ts';
import { useDropzone } from 'react-dropzone';
import EditIcon from '@mui/icons-material/Edit';
import { Label } from './components/Group/AddGroup';
import { Spacer } from './common/Spacer';
import { getWallets, storeWallets, walletVersion } from './background';
import { useModal } from './common/useModal';
import PhraseWallet from './utils/generateWallet/phrase-wallet';
import { decryptStoredWalletFromSeedPhrase } from './utils/decryptWallet';
import { crypto } from './constants/decryptWallet';
import { Label } from './Group/AddGroup.tsx';
import { Spacer } from '../common/Spacer.tsx';
import {
getWallets,
storeWallets,
walletVersion,
} from '../background/background.ts';
import { useModal } from '../hooks/useModal.tsx';
import PhraseWallet from '../utils/generateWallet/phrase-wallet.ts';
import { decryptStoredWalletFromSeedPhrase } from '../utils/decryptWallet.ts';
import { crypto } from '../constants/decryptWallet.ts';
import { LoadingButton } from '@mui/lab';
import { PasswordField } from './components';
import { HtmlTooltip } from './components/NotAuthenticated';
import { MyContext } from './App';
import { PasswordField } from './index.ts';
import { HtmlTooltip } from './NotAuthenticated.tsx';
import { QORTAL_APP_CONTEXT } from '../App.tsx';
import { useTranslation } from 'react-i18next';
const parsefilenameQortal = (filename) => {
@ -44,12 +48,18 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
const [seedValue, setSeedValue] = useState('');
const [seedName, setSeedName] = useState('');
const [seedError, setSeedError] = useState('');
const { hasSeenGettingStarted } = useContext(MyContext);
const { hasSeenGettingStarted } = useContext(QORTAL_APP_CONTEXT);
const [password, setPassword] = useState('');
const [isOpenSeedModal, setIsOpenSeedModal] = useState(false);
const [isLoadingEncryptSeed, setIsLoadingEncryptSeed] = useState(false);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const { isShow, onCancel, onOk, show } = useModal();
const { getRootProps, getInputProps } = useDropzone({
@ -65,7 +75,7 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
const fileContents = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onabort = () => reject('File reading was aborted');
reader.onabort = () => reject('File reading was aborted'); // TODO translate
reader.onerror = () => reject('File reading has failed');
reader.onload = () => {
// Resolve the promise with the reader result when reading completes
@ -457,7 +467,13 @@ const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
const [note, setNote] = useState('');
const [isEdit, setIsEdit] = useState(false);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
useEffect(() => {
if (wallet?.name) {

View File

@ -7,14 +7,20 @@ import {
useTheme,
} from '@mui/material';
import { executeEvent } from '../utils/events';
import { MyContext } from '../App';
import { QORTAL_APP_CONTEXT } from '../App';
import { useAtom } from 'jotai';
import { isRunningPublicNodeAtom } from '../atoms/global';
import { useTranslation } from 'react-i18next';
export const WrapperUserAction = ({ children, address, name, disabled }) => {
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [isRunningPublicNode] = useAtom(isRunningPublicNodeAtom);
const [anchorEl, setAnchorEl] = useState(null);
@ -175,9 +181,15 @@ const BlockUser = ({ address, name, handleClose }) => {
const [isAlreadyBlocked, setIsAlreadyBlocked] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const { isUserBlocked, addToBlockList, removeBlockFromList } =
useContext(MyContext);
useContext(QORTAL_APP_CONTEXT);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
useEffect(() => {
if (!address) return;

View File

@ -1,864 +0,0 @@
// @ts-nocheck
;
import Base58 from '../deps/Base58.js'
import {Sha256, Sha512} from 'asmcrypto.js'
import jsSHA from 'jssha'
import RIPEMD160 from '../deps/ripemd160.js'
import utils from '../utils/utils'
import {BigInteger, EllipticCurve} from './ecbn'
import {Buffer} from 'buffer'
export default class AltcoinHDWallet {
constructor(addressParams) {
/**
* Seed - 32 bytes
*/
this.seed = new Uint8Array(32)
/**
* Version Bytes - 4 byte
*/
this.versionBytes = addressParams
/**
* Depth - 1 byte
*/
this.depth = 0
/**
* Parent Fingerprint - 4 bytes
*/
this.parentFingerprint = '0x00000000' // master key
/**
* Child Index - 4 bytes
*/
this.childIndex = '0x00000000' // master key
/**
* Chain Code - 32 bytes
*/
this.chainCode = new Uint8Array(32)
/**
* Key Data - 33 bytes
*/
this.keyData = new Uint8Array(33)
/**
* Seed Hash - 64 bytes
*/
this.seedHash = new Uint8Array(64)
/**
* Private Key - 32 bytes
*/
this.privateKey = new Uint8Array(32)
/**
* Public Key - 33 bytes (compressed)
*/
this.publicKey = new Uint8Array(33)
/**
* Public Key Hash160 (used to derive the parent fingerprint for derived)
*/
this.publicKeyHash = new Uint8Array(20)
/**
* Master Private Key (Base58 encoded)
*/
this.masterPrivateKey = ''
/**
* Master Public Key (Base58 encoded)
*/
this.masterPublicKey = ''
/**
* Testnet Master Private Key (Base58 encoded) - THIS IS TESTNET
*/
this._tMasterPrivateKey = ''
/**
* Testnet Master Public Key (Base58 encoded) - THIS IS TESTNET
*/
this._tmasterPublicKey = ''
/**
* Child Keys Derivation from the Parent Keys
*/
/**
* Child Private Key - 32 bytes
*/
this.childPrivateKey = new Uint8Array(32)
/**
* Child Chain Code - 32 bytes
*/
this.childChainCode = new Uint8Array(32)
/**
* Child Public Key - 33 bytes (compressed)
*/
this.childPublicKey = new Uint8Array(33)
/**
* Child Public Key Hash160 (used to derive the parent fingerprint for derived)
*/
this.childPublicKeyHash = new Uint8Array(20)
/**
* Extended Private Child Key - Base58 encoded
*/
this.xPrivateChildKey = ''
/**
* Extended Public Child Key - Base58 encoded
*/
this.xPublicChildKey = ''
/**
* Grand Child Keys Derivation from the Child Keys
*/
/**
* Grand Child Private Key - 32 bytes
*/
this.grandChildPrivateKey = new Uint8Array(32)
/**
* Grand Child Chain Code - 32 bytes
*/
this.grandChildChainCode = new Uint8Array(32)
/**
* Grand Child Public Key - 33 bytes (compressed)
*/
this.grandChildPublicKey = new Uint8Array(33)
/**
* Grand Public Key Hash160 (used to derive the parent fingerprint for derived)
*/
this.grandChildPublicKeyHash = new Uint8Array(20)
/**
* Extended Private Grand Child Key - Base58 encoded
*/
this.xPrivateGrandChildKey = ''
/**
* Extended Public Grand Child Key - Base58 encoded
*/
this.xPublicGrandChildKey = ''
/**
* Litecoin Legacy Address - Derived from the Grand Child Public Key Hash
*/
this.litecoinLegacyAddress = ''
/**
* TESTNET Litecoin Legacy Address (Derived from the Grand Child Public Key Hash) - THIS IS TESTNET
*/
this._tlitecoinLegacyAddress = ''
/**
* Wallet - Wallet Object (keys...)
*/
this.wallet = {}
}
setSeed(seed) {
this.seed = seed
}
createWallet(seed, isBIP44, indicator = null) {
// Set Seeed
this.setSeed(seed)
// Generate Seed Hash
this.generateSeedHash(this.seed, isBIP44, indicator)
// Generate Private Key
this.generatePrivateKey(this.seedHash)
// Generate Chain Code
this.generateChainCode(this.seedHash)
// Generate Public Key from Private Key
this.generatePublicKey(this.privateKey)
// Generate Mainnet Master Private Key
this.generateMainnetMasterPrivateKey()
// Generate Mainnet Master Public Key
this.generateMainnetMasterPublicKey()
// Generate Testnet Master Private Key
this.generateTestnetMasterPrivateKey()
// Generate Testnet Master Public Key
this.generateTestnetMasterPublicKey()
// Generate Child and Grand Child Keys
this.generateDerivedChildKeys()
// Return Wallet Object Specification
return this.returnWallet()
}
generateSeedHash(seed, isBIP44, indicator = null) {
let buffer
if (isBIP44) {
buffer = utils.appendBuffer(seed.reverse(), utils.int32ToBytes(indicator))
} else {
if(indicator !== null) {
const indicatorString = utils.stringtoUTF8Array(indicator)
buffer = utils.appendBuffer(seed.reverse(), indicatorString)
}
else
{
buffer = seed.reverse()
}
}
const _reverseSeedHash = new Sha256().process(buffer).finish().result
this.seedHash = new Sha512().process(utils.appendBuffer(seed, _reverseSeedHash)).finish().result
}
generatePrivateKey(seedHash) {
const SECP256K1_CURVE_ORDER = new BigInteger("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141")
const privateKeyHash = seedHash.slice(0, 32)
this.seed58 = Base58.encode(privateKeyHash)
const _privateKeyHash = [...privateKeyHash]
let privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKeyHash)
const privateKey = (privateKeyBigInt.mod(SECP256K1_CURVE_ORDER.subtract(BigInteger.ONE))).add(BigInteger.ONE)
this.privateKey = privateKey.toByteArrayUnsigned()
}
generateChainCode(seedHash) {
this.chainCode = new Sha256().process(seedHash.slice(32, 64)).finish().result
}
generatePublicKey(privateKey) {
const _privateKey = [...privateKey]
const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey)
const epCurve = EllipticCurve.getSECCurveByName("secp256k1")
const curvePoints = epCurve.getG().multiply(privateKeyBigInt)
const x = curvePoints.getX().toBigInteger()
const y = curvePoints.getY().toBigInteger()
/**
* Deriving Uncompressed Public Key (65 bytes)
*
* const publicKeyBytes = EllipticCurve.integerToBytes(x, 32)
* this.publicKey = publicKeyBytes.concat(EllipticCurve.integerToBytes(y, 32))
* this.publicKey.unshift(0x04) // append point indicator
*/
// Compressed Public Key (33 bytes)
this.publicKey = EllipticCurve.integerToBytes(x, 32)
if (y.isEven()) {
this.publicKey.unshift(0x02) // append point indicator
} else {
this.publicKey.unshift(0x03) // append point indicator
}
// PublicKey Hash
const publicKeySHA256 = new Sha256().process(new Uint8Array(this.publicKey)).finish().result
const _publicKeyHash = new RIPEMD160().update(Buffer.from(publicKeySHA256)).digest('hex')
this.publicKeyHash = _publicKeyHash
}
generateMainnetMasterPrivateKey() {
// Serialization Variable
const s = []
// Append Version Byte
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.private)))
// Append Depth
s.push(this.depth)
// Append Parent Fingerprint
s.push(...(utils.int32ToBytes(this.parentFingerprint)))
// Append Child Number
s.push(...(utils.int32ToBytes(this.childIndex)))
// Append Chain Code
s.push(...this.chainCode)
// Append 1 byte '0x00' (to make the key data 33 bytes, DO THIS ONLY FOR PRIVATE KEYS )
s.push(0)
//if the private key length is less than 32 let's add leading zeros
if(this.privateKey.length<32){
for(let i=this.privateKey.length;i<32;i++){
s.push(0)
}
}
// Append Private Key
s.push(...this.privateKey)
// Generate CheckSum
const _s = new Uint8Array(s)
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
const checkSum = _checkSum.slice(0, 4)
// Append CheckSum
s.push(...checkSum) // And this brings us to the end of the serialization...
// Save to Private Key as Base58 encoded
this.masterPrivateKey = Base58.encode(s)
}
generateMainnetMasterPublicKey() {
// Serialization Variable
const s = []
// Append Version Byte
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.public)))
// Append Depth
s.push(this.depth)
// Append Parent Fingerprint
s.push(...(utils.int32ToBytes(this.parentFingerprint)))
// Append Child Number
s.push(...(utils.int32ToBytes(this.childIndex)))
// Append Chain Code
s.push(...this.chainCode)
// Append Public Key
s.push(...this.publicKey)
// Generate CheckSum
const _s = new Uint8Array(s)
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
const checkSum = _checkSum.slice(0, 4)
// Append CheckSum
s.push(...checkSum) // And this brings us to the end of the serialization...
// Save to Public Key as Base58 encoded
this.masterPublicKey = Base58.encode(s)
}
generateTestnetMasterPrivateKey() {
// To be Used ONLY in Testnet...
// Serialization Variable
const s = []
// Append Version Byte
s.push(...(utils.int32ToBytes(this.versionBytes.testnet.private)))
// Append Depth
s.push(this.depth)
// Append Parent Fingerprint
s.push(...(utils.int32ToBytes(this.parentFingerprint)))
// Append Child Number
s.push(...(utils.int32ToBytes(this.childIndex)))
// Append Chain Code
s.push(...this.chainCode)
// Append 1 byte '0x00' (to make the key data 33 bytes, DO THIS ONLY FOR PRIVATE KEYS )
s.push(0)
// Append Private Key
s.push(...this.privateKey)
// Generate CheckSum
const _s = new Uint8Array(s)
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
const checkSum = _checkSum.slice(0, 4)
// Append CheckSum
s.push(...checkSum) // And this brings us to the end of the serialization...
// Save to Private Key as Base58 encoded
this._tMasterPrivateKey = Base58.encode(s)
}
generateTestnetMasterPublicKey() {
// To be Used ONLY in Testnet...
// Serialization Variable
const s = []
// Append Version Byte
s.push(...(utils.int32ToBytes(this.versionBytes.testnet.public)))
// Append Depth
s.push(this.depth)
// Append Parent Fingerprint
s.push(...(utils.int32ToBytes(this.parentFingerprint)))
// Append Child Number
s.push(...(utils.int32ToBytes(this.childIndex)))
// Append Chain Code
s.push(...this.chainCode)
// Append Private Key
s.push(...this.publicKey)
// Generate CheckSum
const _s = new Uint8Array(s)
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
const checkSum = _checkSum.slice(0, 4)
// Append CheckSum
s.push(...checkSum) // And this brings us to the end of the serialization...
// Save to Private Key as Base58 encoded
this._tmasterPublicKey = Base58.encode(s)
}
generateDerivedChildKeys() {
// SPEC INFO: https://en.bitcoin.it/wiki/BIP_0032#Child_key_derivation_.28CKD.29_functions
// NOTE: will not be using some of derivations func as the value is known. (So I'd rather shove in the values and rewrite out the derivations later ?)
// NOTE: I "re-wrote" and "reduplicate" the code for child and grandChild keys derivations inorder to get the child and grandchild from the child
// TODO: Make this more better in the future
const path = 'm/0/0'
// let p = path.split('/')
// Get Public kEY
const derivePublicChildKey = () => {
const _privateKey = [...this.childPrivateKey]
const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey)
const epCurve = EllipticCurve.getSECCurveByName("secp256k1")
const curvePoints = epCurve.getG().multiply(privateKeyBigInt)
const x = curvePoints.getX().toBigInteger()
const y = curvePoints.getY().toBigInteger()
// Compressed Public Key (33 bytes)
this.childPublicKey = EllipticCurve.integerToBytes(x, 32)
if (y.isEven()) {
this.childPublicKey.unshift(0x02) // append point indicator
} else {
this.childPublicKey.unshift(0x03) // append point indicator
}
// PublicKey Hash
const childPublicKeySHA256 = new Sha256().process(new Uint8Array(this.childPublicKey)).finish().result
const _childPublicKeyHash = new RIPEMD160().update(Buffer.from(childPublicKeySHA256)).digest('hex')
this.childPublicKeyHash = _childPublicKeyHash
// Call deriveExtendedPublicChildKey // WIll be hardcoding the values...
deriveExtendedPublicChildKey(1, 0)
}
const derivePrivateChildKey = (cI) => {
let ib = []
ib.push((cI >> 24) & 0xff)
ib.push((cI >> 16) & 0xff)
ib.push((cI >> 8) & 0xff)
ib.push(cI & 0xff)
const s = [...this.publicKey].concat(ib)
const _hmacSha512 = new jsSHA("SHA-512", "UINT8ARRAY", { numRounds: 1, hmacKey: { value: this.chainCode, format: "UINT8ARRAY" } })
_hmacSha512.update(new Uint8Array(s))
const IL = BigInteger.fromByteArrayUnsigned([..._hmacSha512.getHMAC('UINT8ARRAY').slice(0, 32)])
this.childChainCode = _hmacSha512.getHMAC('UINT8ARRAY').slice(32, 64) // IR according to the SPEC
// SECP256k1 init
const epCurve = EllipticCurve.getSECCurveByName("secp256k1")
const ki = IL.add(BigInteger.fromByteArrayUnsigned(this.privateKey)).mod(epCurve.getN()) // parse256(IL) + kpar (mod n) ==> ki
this.childPrivateKey = ki.toByteArrayUnsigned()
// Call deriveExtendedPrivateChildKey
deriveExtendedPrivateChildKey(1, 0)
}
const deriveExtendedPrivateChildKey = (i, childIndex) => {
// Serialization Variable
const s = []
// Append Version Byte
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.private)))
// Append Depth (using the index as depth)
i = parseInt(i)
s.push(i)
// Append Parent Fingerprint
s.push(...(this.publicKeyHash.slice(0, 4)))
// Append Child Index
s.push(childIndex >>> 24)
s.push((childIndex >>> 16) & 0xff)
s.push((childIndex >>> 8) & 0xff)
s.push(childIndex & 0xff)
// Append Chain Code
s.push(...this.childChainCode)
// Append 1 byte '0x00' (to make the key data 33 bytes, DO THIS ONLY FOR PRIVATE KEYS )
s.push(0)
// Append Private Key
s.push(...this.childPrivateKey)
// Generate CheckSum
const _s = new Uint8Array(s)
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
const checkSum = _checkSum.slice(0, 4)
// Append CheckSum
s.push(...checkSum) // And this brings us to the end of the serialization...
// Save to Private Key as Base58 encoded
this.xPrivateChildKey = Base58.encode(s)
}
const deriveExtendedPublicChildKey = (i, childIndex) => {
// Serialization Variable
const s = []
// Append Version Byte
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.public)))
// Append Depth
i = parseInt(i)
s.push(i)
// Append Parent Fingerprint
s.push(...(this.publicKeyHash.slice(0, 4)))
// Append Child Index
s.push(childIndex >>> 24)
s.push((childIndex >>> 16) & 0xff)
s.push((childIndex >>> 8) & 0xff)
s.push(childIndex & 0xff)
// Append Chain Code
s.push(...this.childChainCode)
// Append Public Key
s.push(...this.childPublicKey)
// Generate CheckSum
const _s = new Uint8Array(s)
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
const checkSum = _checkSum.slice(0, 4)
// Append CheckSum
s.push(...checkSum) // And this brings us to the end of the serialization...
// Save to Public Key as Base58 encoded
this.xPublicChildKey = Base58.encode(s)
}
/**
* GRAND CHILD KEYS
*
* NOTE: I know this is not the best way to generate this (even though it works the way it ought)
* Things to rewrite will be and not limited to deriving this through a for loop, removing hard code values, etc...
*/
const derivePublicGrandChildKey = () => {
const _privateKey = [...this.grandChildPrivateKey]
const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey)
const epCurve = EllipticCurve.getSECCurveByName("secp256k1")
const curvePoints = epCurve.getG().multiply(privateKeyBigInt)
const x = curvePoints.getX().toBigInteger()
const y = curvePoints.getY().toBigInteger()
// Compressed Public Key (33 bytes)
this.grandChildPublicKey = EllipticCurve.integerToBytes(x, 32)
if (y.isEven()) {
this.grandChildPublicKey.unshift(0x02) // append point indicator
} else {
this.grandChildPublicKey.unshift(0x03) // append point indicator
}
// PublicKey Hash
const grandChildPublicKeySHA256 = new Sha256().process(new Uint8Array(this.grandChildPublicKey)).finish().result
const _grandChildPublicKeyHash = new RIPEMD160().update(Buffer.from(grandChildPublicKeySHA256)).digest('hex')
this.grandChildPublicKeyHash = _grandChildPublicKeyHash
// Call deriveExtendedPublicChildKey // WIll be hardcoding the values...
deriveExtendedPublicGrandChildKey(2, 0)
/**
* Derive Litecoin Legacy Address
*/
// Append Address Prefix
let prefix = [this.versionBytes.mainnet.prefix]
if (2 == this.versionBytes.mainnet.prefix.length) {
prefix = [this.versionBytes.mainnet.prefix[0]]
prefix.push([this.versionBytes.mainnet.prefix[1]])
}
const k = prefix.concat(...this.grandChildPublicKeyHash)
// Derive Checksum
const _addressCheckSum = new Sha256().process(new Sha256().process(new Uint8Array(k)).finish().result).finish().result
const addressCheckSum = _addressCheckSum.slice(0, 4)
// Append CheckSum
const _litecoinLegacyAddress = k.concat(...addressCheckSum)
// Convert to Base58
this.litecoinLegacyAddress = Base58.encode(_litecoinLegacyAddress)
/**
* Derive TESTNET Litecoin Legacy Address
*/
// Append Version Byte
const tK = [this.versionBytes.testnet.prefix].concat(...this.grandChildPublicKeyHash)
// Derive Checksum
const _tAddressCheckSum = new Sha256().process(new Sha256().process(new Uint8Array(tK)).finish().result).finish().result
const tAddressCheckSum = _tAddressCheckSum.slice(0, 4)
// Append CheckSum
const _tlitecoinLegacyAddress = tK.concat(...tAddressCheckSum)
// Convert to Base58
this._tlitecoinLegacyAddress = Base58.encode(_tlitecoinLegacyAddress)
}
const derivePrivateGrandChildKey = (cI, i) => {
let ib = []
ib.push((cI >> 24) & 0xff)
ib.push((cI >> 16) & 0xff)
ib.push((cI >> 8) & 0xff)
ib.push(cI & 0xff)
const s = [...this.childPublicKey].concat(ib)
const _hmacSha512 = new jsSHA("SHA-512", "UINT8ARRAY", { numRounds: 1, hmacKey: { value: this.childChainCode, format: "UINT8ARRAY" } })
_hmacSha512.update(new Uint8Array(s))
const IL = BigInteger.fromByteArrayUnsigned([..._hmacSha512.getHMAC('UINT8ARRAY').slice(0, 32)])
this.grandChildChainCode = _hmacSha512.getHMAC('UINT8ARRAY').slice(32, 64) // IR according to the SPEC
// SECP256k1 init
const epCurve = EllipticCurve.getSECCurveByName("secp256k1")
const ki = IL.add(BigInteger.fromByteArrayUnsigned(this.childPrivateKey)).mod(epCurve.getN()) // parse256(IL) + kpar (mod n) ==> ki
this.grandChildPrivateKey = ki.toByteArrayUnsigned()
// Call deriveExtendedPrivateChildKey
deriveExtendedPrivateGrandChildKey(2, 0)
}
const deriveExtendedPrivateGrandChildKey = (i, childIndex) => {
// Serialization Variable
const s = []
// Append Version Byte
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.private)))
// Append Depth (using the index as depth)
i = parseInt(i)
s.push(i)
// Append Parent Fingerprint
s.push(...(this.childPublicKeyHash.slice(0, 4)))
// Append Child Index
s.push(childIndex >>> 24)
s.push((childIndex >>> 16) & 0xff)
s.push((childIndex >>> 8) & 0xff)
s.push(childIndex & 0xff)
// Append Chain Code
s.push(...this.grandChildChainCode)
// Append 1 byte '0x00' (to make the key data 33 bytes, DO THIS ONLY FOR PRIVATE KEYS )
s.push(0)
// Append Private Key
s.push(...this.grandChildPrivateKey)
// Generate CheckSum
const _s = new Uint8Array(s)
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
const checkSum = _checkSum.slice(0, 4)
// Append CheckSum
s.push(...checkSum) // And this brings us to the end of the serialization...
// Save to Private Key as Base58 encoded
this.xPrivateGrandChildKey = Base58.encode(s)
}
const deriveExtendedPublicGrandChildKey = (i, childIndex) => {
// Serialization Variable
const s = []
// Append Version Byte
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.public)))
// Append Depth
i = parseInt(i)
s.push(i)
// Append Parent Fingerprint
s.push(...(this.childPublicKeyHash.slice(0, 4)))
// Append Child Index
s.push(childIndex >>> 24)
s.push((childIndex >>> 16) & 0xff)
s.push((childIndex >>> 8) & 0xff)
s.push(childIndex & 0xff)
// Append Chain Code
s.push(...this.grandChildChainCode)
// Append Public Key
s.push(...this.grandChildPublicKey)
// Generate CheckSum
const _s = new Uint8Array(s)
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
const checkSum = _checkSum.slice(0, 4)
// Append CheckSum
s.push(...checkSum) // And this brings us to the end of the serialization...
// Save to Public Key as Base58 encoded
this.xPublicGrandChildKey = Base58.encode(s)
}
// Hard Code value..
let childIndex = 0
// Call derivePrivateChildKey //Hard code value
derivePrivateChildKey(childIndex)
// Call derivePublicChildKey
derivePublicChildKey()
// Call derivePrivateGrandChildKey // Hard Code value...
derivePrivateGrandChildKey(0, 2)
// Call derivePublicGrandChildKey
derivePublicGrandChildKey()
}
returnWallet() {
// Will be limiting the exported Wallet Object to just the Master keys and Legacy Addresses
const wallet = {
derivedMasterPrivateKey: this.masterPrivateKey,
derivedMasterPublicKey: this.masterPublicKey,
_tDerivedMasterPrivateKey: this._tMasterPrivateKey,
_tDerivedmasterPublicKey: this._tmasterPublicKey,
seed58: this.seed58,
// derivedPrivateChildKey: this.xPrivateChildKey,
// derivedPublicChildKey: this.xPublicChildKey,
// derivedPrivateGrandChildKey: this.xPrivateGrandChildKey,
// derivedPublicGrandChildKey: this.xPublicGrandChildKey,
address: this.litecoinLegacyAddress,
_taddress: this._tlitecoinLegacyAddress
}
this.wallet = wallet
return wallet
}
}

View File

@ -0,0 +1,881 @@
// @ts-nocheck
import Base58 from './Base58.js';
import { Sha256, Sha512 } from 'asmcrypto.js';
import jsSHA from 'jssha';
import RIPEMD160 from './ripemd160.js';
import utils from '../utils/utils.js';
import { BigInteger, EllipticCurve } from './ecbn';
import { Buffer } from 'buffer';
export default class AltcoinHDWallet {
constructor(addressParams) {
/**
* Seed - 32 bytes
*/
this.seed = new Uint8Array(32);
/**
* Version Bytes - 4 byte
*/
this.versionBytes = addressParams;
/**
* Depth - 1 byte
*/
this.depth = 0;
/**
* Parent Fingerprint - 4 bytes
*/
this.parentFingerprint = '0x00000000'; // master key
/**
* Child Index - 4 bytes
*/
this.childIndex = '0x00000000'; // master key
/**
* Chain Code - 32 bytes
*/
this.chainCode = new Uint8Array(32);
/**
* Key Data - 33 bytes
*/
this.keyData = new Uint8Array(33);
/**
* Seed Hash - 64 bytes
*/
this.seedHash = new Uint8Array(64);
/**
* Private Key - 32 bytes
*/
this.privateKey = new Uint8Array(32);
/**
* Public Key - 33 bytes (compressed)
*/
this.publicKey = new Uint8Array(33);
/**
* Public Key Hash160 (used to derive the parent fingerprint for derived)
*/
this.publicKeyHash = new Uint8Array(20);
/**
* Master Private Key (Base58 encoded)
*/
this.masterPrivateKey = '';
/**
* Master Public Key (Base58 encoded)
*/
this.masterPublicKey = '';
/**
* Testnet Master Private Key (Base58 encoded) - THIS IS TESTNET
*/
this._tMasterPrivateKey = '';
/**
* Testnet Master Public Key (Base58 encoded) - THIS IS TESTNET
*/
this._tmasterPublicKey = '';
/**
* Child Keys Derivation from the Parent Keys
*/
/**
* Child Private Key - 32 bytes
*/
this.childPrivateKey = new Uint8Array(32);
/**
* Child Chain Code - 32 bytes
*/
this.childChainCode = new Uint8Array(32);
/**
* Child Public Key - 33 bytes (compressed)
*/
this.childPublicKey = new Uint8Array(33);
/**
* Child Public Key Hash160 (used to derive the parent fingerprint for derived)
*/
this.childPublicKeyHash = new Uint8Array(20);
/**
* Extended Private Child Key - Base58 encoded
*/
this.xPrivateChildKey = '';
/**
* Extended Public Child Key - Base58 encoded
*/
this.xPublicChildKey = '';
/**
* Grand Child Keys Derivation from the Child Keys
*/
/**
* Grand Child Private Key - 32 bytes
*/
this.grandChildPrivateKey = new Uint8Array(32);
/**
* Grand Child Chain Code - 32 bytes
*/
this.grandChildChainCode = new Uint8Array(32);
/**
* Grand Child Public Key - 33 bytes (compressed)
*/
this.grandChildPublicKey = new Uint8Array(33);
/**
* Grand Public Key Hash160 (used to derive the parent fingerprint for derived)
*/
this.grandChildPublicKeyHash = new Uint8Array(20);
/**
* Extended Private Grand Child Key - Base58 encoded
*/
this.xPrivateGrandChildKey = '';
/**
* Extended Public Grand Child Key - Base58 encoded
*/
this.xPublicGrandChildKey = '';
/**
* Litecoin Legacy Address - Derived from the Grand Child Public Key Hash
*/
this.litecoinLegacyAddress = '';
/**
* TESTNET Litecoin Legacy Address (Derived from the Grand Child Public Key Hash) - THIS IS TESTNET
*/
this._tlitecoinLegacyAddress = '';
/**
* Wallet - Wallet Object (keys...)
*/
this.wallet = {};
}
setSeed(seed) {
this.seed = seed;
}
createWallet(seed, isBIP44, indicator = null) {
// Set Seeed
this.setSeed(seed);
// Generate Seed Hash
this.generateSeedHash(this.seed, isBIP44, indicator);
// Generate Private Key
this.generatePrivateKey(this.seedHash);
// Generate Chain Code
this.generateChainCode(this.seedHash);
// Generate Public Key from Private Key
this.generatePublicKey(this.privateKey);
// Generate Mainnet Master Private Key
this.generateMainnetMasterPrivateKey();
// Generate Mainnet Master Public Key
this.generateMainnetMasterPublicKey();
// Generate Testnet Master Private Key
this.generateTestnetMasterPrivateKey();
// Generate Testnet Master Public Key
this.generateTestnetMasterPublicKey();
// Generate Child and Grand Child Keys
this.generateDerivedChildKeys();
// Return Wallet Object Specification
return this.returnWallet();
}
generateSeedHash(seed, isBIP44, indicator = null) {
let buffer;
if (isBIP44) {
buffer = utils.appendBuffer(
seed.reverse(),
utils.int32ToBytes(indicator)
);
} else {
if (indicator !== null) {
const indicatorString = utils.stringtoUTF8Array(indicator);
buffer = utils.appendBuffer(seed.reverse(), indicatorString);
} else {
buffer = seed.reverse();
}
}
const _reverseSeedHash = new Sha256().process(buffer).finish().result;
this.seedHash = new Sha512()
.process(utils.appendBuffer(seed, _reverseSeedHash))
.finish().result;
}
generatePrivateKey(seedHash) {
const SECP256K1_CURVE_ORDER = new BigInteger(
'0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141'
);
const privateKeyHash = seedHash.slice(0, 32);
this.seed58 = Base58.encode(privateKeyHash);
const _privateKeyHash = [...privateKeyHash];
let privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKeyHash);
const privateKey = privateKeyBigInt
.mod(SECP256K1_CURVE_ORDER.subtract(BigInteger.ONE))
.add(BigInteger.ONE);
this.privateKey = privateKey.toByteArrayUnsigned();
}
generateChainCode(seedHash) {
this.chainCode = new Sha256()
.process(seedHash.slice(32, 64))
.finish().result;
}
generatePublicKey(privateKey) {
const _privateKey = [...privateKey];
const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey);
const epCurve = EllipticCurve.getSECCurveByName('secp256k1');
const curvePoints = epCurve.getG().multiply(privateKeyBigInt);
const x = curvePoints.getX().toBigInteger();
const y = curvePoints.getY().toBigInteger();
/**
* Deriving Uncompressed Public Key (65 bytes)
*
* const publicKeyBytes = EllipticCurve.integerToBytes(x, 32)
* this.publicKey = publicKeyBytes.concat(EllipticCurve.integerToBytes(y, 32))
* this.publicKey.unshift(0x04) // append point indicator
*/
// Compressed Public Key (33 bytes)
this.publicKey = EllipticCurve.integerToBytes(x, 32);
if (y.isEven()) {
this.publicKey.unshift(0x02); // append point indicator
} else {
this.publicKey.unshift(0x03); // append point indicator
}
// PublicKey Hash
const publicKeySHA256 = new Sha256()
.process(new Uint8Array(this.publicKey))
.finish().result;
const _publicKeyHash = new RIPEMD160()
.update(Buffer.from(publicKeySHA256))
.digest('hex');
this.publicKeyHash = _publicKeyHash;
}
generateMainnetMasterPrivateKey() {
// Serialization Variable
const s = [];
// Append Version Byte
s.push(...utils.int32ToBytes(this.versionBytes.mainnet.private));
// Append Depth
s.push(this.depth);
// Append Parent Fingerprint
s.push(...utils.int32ToBytes(this.parentFingerprint));
// Append Child Number
s.push(...utils.int32ToBytes(this.childIndex));
// Append Chain Code
s.push(...this.chainCode);
// Append 1 byte '0x00' (to make the key data 33 bytes, DO THIS ONLY FOR PRIVATE KEYS )
s.push(0);
//if the private key length is less than 32 let's add leading zeros
if (this.privateKey.length < 32) {
for (let i = this.privateKey.length; i < 32; i++) {
s.push(0);
}
}
// Append Private Key
s.push(...this.privateKey);
// Generate CheckSum
const _s = new Uint8Array(s);
const _checkSum = new Sha256()
.process(new Sha256().process(_s).finish().result)
.finish().result;
const checkSum = _checkSum.slice(0, 4);
// Append CheckSum
s.push(...checkSum); // And this brings us to the end of the serialization...
// Save to Private Key as Base58 encoded
this.masterPrivateKey = Base58.encode(s);
}
generateMainnetMasterPublicKey() {
// Serialization Variable
const s = [];
// Append Version Byte
s.push(...utils.int32ToBytes(this.versionBytes.mainnet.public));
// Append Depth
s.push(this.depth);
// Append Parent Fingerprint
s.push(...utils.int32ToBytes(this.parentFingerprint));
// Append Child Number
s.push(...utils.int32ToBytes(this.childIndex));
// Append Chain Code
s.push(...this.chainCode);
// Append Public Key
s.push(...this.publicKey);
// Generate CheckSum
const _s = new Uint8Array(s);
const _checkSum = new Sha256()
.process(new Sha256().process(_s).finish().result)
.finish().result;
const checkSum = _checkSum.slice(0, 4);
// Append CheckSum
s.push(...checkSum); // And this brings us to the end of the serialization...
// Save to Public Key as Base58 encoded
this.masterPublicKey = Base58.encode(s);
}
generateTestnetMasterPrivateKey() {
// To be Used ONLY in Testnet...
// Serialization Variable
const s = [];
// Append Version Byte
s.push(...utils.int32ToBytes(this.versionBytes.testnet.private));
// Append Depth
s.push(this.depth);
// Append Parent Fingerprint
s.push(...utils.int32ToBytes(this.parentFingerprint));
// Append Child Number
s.push(...utils.int32ToBytes(this.childIndex));
// Append Chain Code
s.push(...this.chainCode);
// Append 1 byte '0x00' (to make the key data 33 bytes, DO THIS ONLY FOR PRIVATE KEYS )
s.push(0);
// Append Private Key
s.push(...this.privateKey);
// Generate CheckSum
const _s = new Uint8Array(s);
const _checkSum = new Sha256()
.process(new Sha256().process(_s).finish().result)
.finish().result;
const checkSum = _checkSum.slice(0, 4);
// Append CheckSum
s.push(...checkSum); // And this brings us to the end of the serialization...
// Save to Private Key as Base58 encoded
this._tMasterPrivateKey = Base58.encode(s);
}
generateTestnetMasterPublicKey() {
// To be Used ONLY in Testnet...
// Serialization Variable
const s = [];
// Append Version Byte
s.push(...utils.int32ToBytes(this.versionBytes.testnet.public));
// Append Depth
s.push(this.depth);
// Append Parent Fingerprint
s.push(...utils.int32ToBytes(this.parentFingerprint));
// Append Child Number
s.push(...utils.int32ToBytes(this.childIndex));
// Append Chain Code
s.push(...this.chainCode);
// Append Private Key
s.push(...this.publicKey);
// Generate CheckSum
const _s = new Uint8Array(s);
const _checkSum = new Sha256()
.process(new Sha256().process(_s).finish().result)
.finish().result;
const checkSum = _checkSum.slice(0, 4);
// Append CheckSum
s.push(...checkSum); // And this brings us to the end of the serialization...
// Save to Private Key as Base58 encoded
this._tmasterPublicKey = Base58.encode(s);
}
generateDerivedChildKeys() {
// SPEC INFO: https://en.bitcoin.it/wiki/BIP_0032#Child_key_derivation_.28CKD.29_functions
// NOTE: will not be using some of derivations func as the value is known. (So I'd rather shove in the values and rewrite out the derivations later ?)
// NOTE: I "re-wrote" and "reduplicate" the code for child and grandChild keys derivations inorder to get the child and grandchild from the child
// TODO: Make this more better in the future
const path = 'm/0/0';
// let p = path.split('/')
// Get Public kEY
const derivePublicChildKey = () => {
const _privateKey = [...this.childPrivateKey];
const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey);
const epCurve = EllipticCurve.getSECCurveByName('secp256k1');
const curvePoints = epCurve.getG().multiply(privateKeyBigInt);
const x = curvePoints.getX().toBigInteger();
const y = curvePoints.getY().toBigInteger();
// Compressed Public Key (33 bytes)
this.childPublicKey = EllipticCurve.integerToBytes(x, 32);
if (y.isEven()) {
this.childPublicKey.unshift(0x02); // append point indicator
} else {
this.childPublicKey.unshift(0x03); // append point indicator
}
// PublicKey Hash
const childPublicKeySHA256 = new Sha256()
.process(new Uint8Array(this.childPublicKey))
.finish().result;
const _childPublicKeyHash = new RIPEMD160()
.update(Buffer.from(childPublicKeySHA256))
.digest('hex');
this.childPublicKeyHash = _childPublicKeyHash;
// Call deriveExtendedPublicChildKey // WIll be hardcoding the values...
deriveExtendedPublicChildKey(1, 0);
};
const derivePrivateChildKey = (cI) => {
let ib = [];
ib.push((cI >> 24) & 0xff);
ib.push((cI >> 16) & 0xff);
ib.push((cI >> 8) & 0xff);
ib.push(cI & 0xff);
const s = [...this.publicKey].concat(ib);
const _hmacSha512 = new jsSHA('SHA-512', 'UINT8ARRAY', {
numRounds: 1,
hmacKey: { value: this.chainCode, format: 'UINT8ARRAY' },
});
_hmacSha512.update(new Uint8Array(s));
const IL = BigInteger.fromByteArrayUnsigned([
..._hmacSha512.getHMAC('UINT8ARRAY').slice(0, 32),
]);
this.childChainCode = _hmacSha512.getHMAC('UINT8ARRAY').slice(32, 64); // IR according to the SPEC
// SECP256k1 init
const epCurve = EllipticCurve.getSECCurveByName('secp256k1');
const ki = IL.add(BigInteger.fromByteArrayUnsigned(this.privateKey)).mod(
epCurve.getN()
); // parse256(IL) + kpar (mod n) ==> ki
this.childPrivateKey = ki.toByteArrayUnsigned();
// Call deriveExtendedPrivateChildKey
deriveExtendedPrivateChildKey(1, 0);
};
const deriveExtendedPrivateChildKey = (i, childIndex) => {
// Serialization Variable
const s = [];
// Append Version Byte
s.push(...utils.int32ToBytes(this.versionBytes.mainnet.private));
// Append Depth (using the index as depth)
i = parseInt(i);
s.push(i);
// Append Parent Fingerprint
s.push(...this.publicKeyHash.slice(0, 4));
// Append Child Index
s.push(childIndex >>> 24);
s.push((childIndex >>> 16) & 0xff);
s.push((childIndex >>> 8) & 0xff);
s.push(childIndex & 0xff);
// Append Chain Code
s.push(...this.childChainCode);
// Append 1 byte '0x00' (to make the key data 33 bytes, DO THIS ONLY FOR PRIVATE KEYS )
s.push(0);
// Append Private Key
s.push(...this.childPrivateKey);
// Generate CheckSum
const _s = new Uint8Array(s);
const _checkSum = new Sha256()
.process(new Sha256().process(_s).finish().result)
.finish().result;
const checkSum = _checkSum.slice(0, 4);
// Append CheckSum
s.push(...checkSum); // And this brings us to the end of the serialization...
// Save to Private Key as Base58 encoded
this.xPrivateChildKey = Base58.encode(s);
};
const deriveExtendedPublicChildKey = (i, childIndex) => {
// Serialization Variable
const s = [];
// Append Version Byte
s.push(...utils.int32ToBytes(this.versionBytes.mainnet.public));
// Append Depth
i = parseInt(i);
s.push(i);
// Append Parent Fingerprint
s.push(...this.publicKeyHash.slice(0, 4));
// Append Child Index
s.push(childIndex >>> 24);
s.push((childIndex >>> 16) & 0xff);
s.push((childIndex >>> 8) & 0xff);
s.push(childIndex & 0xff);
// Append Chain Code
s.push(...this.childChainCode);
// Append Public Key
s.push(...this.childPublicKey);
// Generate CheckSum
const _s = new Uint8Array(s);
const _checkSum = new Sha256()
.process(new Sha256().process(_s).finish().result)
.finish().result;
const checkSum = _checkSum.slice(0, 4);
// Append CheckSum
s.push(...checkSum); // And this brings us to the end of the serialization...
// Save to Public Key as Base58 encoded
this.xPublicChildKey = Base58.encode(s);
};
/**
* GRAND CHILD KEYS
*
* NOTE: I know this is not the best way to generate this (even though it works the way it ought)
* Things to rewrite will be and not limited to deriving this through a for loop, removing hard code values, etc...
*/
const derivePublicGrandChildKey = () => {
const _privateKey = [...this.grandChildPrivateKey];
const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey);
const epCurve = EllipticCurve.getSECCurveByName('secp256k1');
const curvePoints = epCurve.getG().multiply(privateKeyBigInt);
const x = curvePoints.getX().toBigInteger();
const y = curvePoints.getY().toBigInteger();
// Compressed Public Key (33 bytes)
this.grandChildPublicKey = EllipticCurve.integerToBytes(x, 32);
if (y.isEven()) {
this.grandChildPublicKey.unshift(0x02); // append point indicator
} else {
this.grandChildPublicKey.unshift(0x03); // append point indicator
}
// PublicKey Hash
const grandChildPublicKeySHA256 = new Sha256()
.process(new Uint8Array(this.grandChildPublicKey))
.finish().result;
const _grandChildPublicKeyHash = new RIPEMD160()
.update(Buffer.from(grandChildPublicKeySHA256))
.digest('hex');
this.grandChildPublicKeyHash = _grandChildPublicKeyHash;
// Call deriveExtendedPublicChildKey // WIll be hardcoding the values...
deriveExtendedPublicGrandChildKey(2, 0);
/**
* Derive Litecoin Legacy Address
*/
// Append Address Prefix
let prefix = [this.versionBytes.mainnet.prefix];
if (2 == this.versionBytes.mainnet.prefix.length) {
prefix = [this.versionBytes.mainnet.prefix[0]];
prefix.push([this.versionBytes.mainnet.prefix[1]]);
}
const k = prefix.concat(...this.grandChildPublicKeyHash);
// Derive Checksum
const _addressCheckSum = new Sha256()
.process(new Sha256().process(new Uint8Array(k)).finish().result)
.finish().result;
const addressCheckSum = _addressCheckSum.slice(0, 4);
// Append CheckSum
const _litecoinLegacyAddress = k.concat(...addressCheckSum);
// Convert to Base58
this.litecoinLegacyAddress = Base58.encode(_litecoinLegacyAddress);
/**
* Derive TESTNET Litecoin Legacy Address
*/
// Append Version Byte
const tK = [this.versionBytes.testnet.prefix].concat(
...this.grandChildPublicKeyHash
);
// Derive Checksum
const _tAddressCheckSum = new Sha256()
.process(new Sha256().process(new Uint8Array(tK)).finish().result)
.finish().result;
const tAddressCheckSum = _tAddressCheckSum.slice(0, 4);
// Append CheckSum
const _tlitecoinLegacyAddress = tK.concat(...tAddressCheckSum);
// Convert to Base58
this._tlitecoinLegacyAddress = Base58.encode(_tlitecoinLegacyAddress);
};
const derivePrivateGrandChildKey = (cI, i) => {
let ib = [];
ib.push((cI >> 24) & 0xff);
ib.push((cI >> 16) & 0xff);
ib.push((cI >> 8) & 0xff);
ib.push(cI & 0xff);
const s = [...this.childPublicKey].concat(ib);
const _hmacSha512 = new jsSHA('SHA-512', 'UINT8ARRAY', {
numRounds: 1,
hmacKey: { value: this.childChainCode, format: 'UINT8ARRAY' },
});
_hmacSha512.update(new Uint8Array(s));
const IL = BigInteger.fromByteArrayUnsigned([
..._hmacSha512.getHMAC('UINT8ARRAY').slice(0, 32),
]);
this.grandChildChainCode = _hmacSha512
.getHMAC('UINT8ARRAY')
.slice(32, 64); // IR according to the SPEC
// SECP256k1 init
const epCurve = EllipticCurve.getSECCurveByName('secp256k1');
const ki = IL.add(
BigInteger.fromByteArrayUnsigned(this.childPrivateKey)
).mod(epCurve.getN()); // parse256(IL) + kpar (mod n) ==> ki
this.grandChildPrivateKey = ki.toByteArrayUnsigned();
// Call deriveExtendedPrivateChildKey
deriveExtendedPrivateGrandChildKey(2, 0);
};
const deriveExtendedPrivateGrandChildKey = (i, childIndex) => {
// Serialization Variable
const s = [];
// Append Version Byte
s.push(...utils.int32ToBytes(this.versionBytes.mainnet.private));
// Append Depth (using the index as depth)
i = parseInt(i);
s.push(i);
// Append Parent Fingerprint
s.push(...this.childPublicKeyHash.slice(0, 4));
// Append Child Index
s.push(childIndex >>> 24);
s.push((childIndex >>> 16) & 0xff);
s.push((childIndex >>> 8) & 0xff);
s.push(childIndex & 0xff);
// Append Chain Code
s.push(...this.grandChildChainCode);
// Append 1 byte '0x00' (to make the key data 33 bytes, DO THIS ONLY FOR PRIVATE KEYS )
s.push(0);
// Append Private Key
s.push(...this.grandChildPrivateKey);
// Generate CheckSum
const _s = new Uint8Array(s);
const _checkSum = new Sha256()
.process(new Sha256().process(_s).finish().result)
.finish().result;
const checkSum = _checkSum.slice(0, 4);
// Append CheckSum
s.push(...checkSum); // And this brings us to the end of the serialization...
// Save to Private Key as Base58 encoded
this.xPrivateGrandChildKey = Base58.encode(s);
};
const deriveExtendedPublicGrandChildKey = (i, childIndex) => {
// Serialization Variable
const s = [];
// Append Version Byte
s.push(...utils.int32ToBytes(this.versionBytes.mainnet.public));
// Append Depth
i = parseInt(i);
s.push(i);
// Append Parent Fingerprint
s.push(...this.childPublicKeyHash.slice(0, 4));
// Append Child Index
s.push(childIndex >>> 24);
s.push((childIndex >>> 16) & 0xff);
s.push((childIndex >>> 8) & 0xff);
s.push(childIndex & 0xff);
// Append Chain Code
s.push(...this.grandChildChainCode);
// Append Public Key
s.push(...this.grandChildPublicKey);
// Generate CheckSum
const _s = new Uint8Array(s);
const _checkSum = new Sha256()
.process(new Sha256().process(_s).finish().result)
.finish().result;
const checkSum = _checkSum.slice(0, 4);
// Append CheckSum
s.push(...checkSum); // And this brings us to the end of the serialization...
// Save to Public Key as Base58 encoded
this.xPublicGrandChildKey = Base58.encode(s);
};
// Hard Code value..
let childIndex = 0;
// Call derivePrivateChildKey //Hard code value
derivePrivateChildKey(childIndex);
// Call derivePublicChildKey
derivePublicChildKey();
// Call derivePrivateGrandChildKey // Hard Code value...
derivePrivateGrandChildKey(0, 2);
// Call derivePublicGrandChildKey
derivePublicGrandChildKey();
}
returnWallet() {
// Will be limiting the exported Wallet Object to just the Master keys and Legacy Addresses
const wallet = {
derivedMasterPrivateKey: this.masterPrivateKey,
derivedMasterPublicKey: this.masterPublicKey,
_tDerivedMasterPrivateKey: this._tMasterPrivateKey,
_tDerivedmasterPublicKey: this._tmasterPublicKey,
seed58: this.seed58,
// derivedPrivateChildKey: this.xPrivateChildKey,
// derivedPublicChildKey: this.xPublicChildKey,
// derivedPrivateGrandChildKey: this.xPrivateGrandChildKey,
// derivedPublicGrandChildKey: this.xPublicGrandChildKey,
address: this.litecoinLegacyAddress,
_taddress: this._tlitecoinLegacyAddress,
};
this.wallet = wallet;
return wallet;
}
}

View File

@ -1,60 +1,24 @@
import { getBaseApi } from '../background';
import i18n from '../i18n/i18n';
import { getBaseApi } from '../background/background.ts';
import i18n from '../i18n/i18n.ts';
import {
createSymmetricKeyAndNonce,
decryptGroupData,
encryptDataGroup,
objectToBase64,
} from '../qdn/encryption/group-encryption';
import { publishData } from '../qdn/publish/pubish';
import { getData } from '../utils/chromeStorage';
import { RequestQueueWithPromise } from '../utils/queue/queue';
} from '../qdn/encryption/group-encryption.ts';
import { publishData } from '../qdn/publish/publish.ts';
import { getData } from '../utils/chromeStorage.ts';
import { RequestQueueWithPromise } from '../utils/queue/queue.ts';
export const requestQueueGetPublicKeys = new RequestQueueWithPromise(10);
const apiEndpoints = [
'https://api.qortal.org',
'https://api2.qortal.org',
'https://appnode.qortal.org',
'https://apinode.qortalnodes.live',
'https://apinode1.qortalnodes.live',
'https://apinode2.qortalnodes.live',
'https://apinode3.qortalnodes.live',
'https://apinode4.qortalnodes.live',
];
async function findUsableApi() {
for (const endpoint of apiEndpoints) {
try {
const response = await fetch(`${endpoint}/admin/status`);
if (!response.ok) throw new Error('Failed to fetch');
const data = await response.json();
if (data.isSynchronizing === false && data.syncPercent === 100) {
console.log(`Usable API found: ${endpoint}`);
return endpoint;
} else {
console.log(`API not ready: ${endpoint}`);
}
} catch (error) {
console.error(`Error checking API ${endpoint}:`, error);
}
}
throw new Error(
i18n.t('question:message.error.no_api_found', {
postProcess: 'capitalizeFirstChar',
})
);
}
async function getSaveWallet() {
const res = await getData<any>('walletInfo').catch(() => null);
if (res) {
return res;
} else {
throw new Error('No wallet saved');
throw new Error('No wallet saved'); // TODO translate
}
}

View File

@ -1,7 +1,10 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { getBaseApiReact } from '../App';
import { getData, storeData } from '../utils/chromeStorage';
import { checkDifference, getNameInfoForOthers } from '../background';
import {
checkDifference,
getNameInfoForOthers,
} from '../background/background.ts';
import { lastPaymentSeenTimestampAtom } from '../atoms/global';
import { subscribeToEvent, unsubscribeFromEvent } from '../utils/events';
import { useAtom } from 'jotai';

View File

@ -1,14 +1,14 @@
import { useContext, useState } from 'react';
import { executeEvent } from '../utils/events';
import { getBaseApiReact, MyContext } from '../App';
import { createEndpoint } from '../background';
import { getBaseApiReact, QORTAL_APP_CONTEXT } from '../App';
import { createEndpoint } from '../background/background.ts';
import {
settingsLocalLastUpdatedAtom,
sortablePinnedAppsAtom,
} from '../atoms/global';
import { saveToLocalStorage } from '../components/Apps/AppsNavBarDesktop';
import { base64ToUint8Array } from '../qdn/encryption/group-encryption';
import { uint8ArrayToObject } from '../backgroundFunctions/encryption';
import { uint8ArrayToObject } from '../encryption/encryption.ts';
import { useSetAtom } from 'jotai';
import { useTranslation } from 'react-i18next';
@ -19,10 +19,16 @@ export const useHandlePrivateApps = () => {
setOpenSnackGlobal,
infoSnackCustom,
setInfoSnackCustom,
} = useContext(MyContext);
} = useContext(QORTAL_APP_CONTEXT);
const setSortablePinnedApps = useSetAtom(sortablePinnedAppsAtom);
const setSettingsLocalLastUpdated = useSetAtom(settingsLocalLastUpdatedAtom);
const { t } = useTranslation(['auth', 'core', 'group']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const openApp = async (
privateAppProperties,

View File

@ -12,7 +12,7 @@ import { decryptResource } from '../components/Group/Group';
import {
base64ToUint8Array,
uint8ArrayToObject,
} from '../backgroundFunctions/encryption';
} from '../encryption/encryption';
import { useAtom, useSetAtom } from 'jotai';
function fetchFromLocalStorage(key) {

Some files were not shown because too many files have changed in this diff Show More