Skip to content

Commit

Permalink
v3.0.25
Browse files Browse the repository at this point in the history
  • Loading branch information
mytonwalletorg committed Oct 2, 2024
1 parent 6f675fe commit 7b6a21d
Show file tree
Hide file tree
Showing 38 changed files with 165 additions and 120 deletions.
1 change: 1 addition & 0 deletions changelogs/3.0.25.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Bug fixes and performance improvements
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mytonwallet",
"version": "3.0.24",
"version": "3.0.25",
"description": "The most feature-rich web wallet and browser extension for TON – with support of multi-accounts, tokens (jettons), NFT, TON DNS, TON Sites, TON Proxy, and TON Magic.",
"main": "index.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion public/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.0.24
3.0.25
31 changes: 18 additions & 13 deletions src/api/chains/ton/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import * as bip39 from 'bip39';
import nacl from 'tweetnacl';

import type {
ApiLedgerAccount, ApiNetwork, ApiTonAccount, ApiTonWallet,
ApiAccountWithMnemonic,
ApiLedgerAccount,
ApiNetwork,
ApiTonAccount,
ApiTonWallet,
} from '../../types';
import type { ApiTonWalletVersion } from './types';
import type { TonWallet } from './util/tonCore';
Expand All @@ -14,7 +18,7 @@ import isMnemonicPrivateKey from '../../../util/isMnemonicPrivateKey';
import { logDebugError } from '../../../util/logs';
import { toBase64Address } from './util/tonCore';
import { fetchStoredAccount, getNewAccountId, setAccountValue } from '../../common/accounts';
import { fetchMnemonic, validateBip39Mnemonic } from '../../common/mnemonic';
import { getMnemonic } from '../../common/mnemonic';
import { bytesToHex, hexToBytes } from '../../common/utils';
import { TON_BIP39_PATH } from './constants';
import { buildWallet, pickBestWallet, publicKeyToAddress } from './wallet';
Expand All @@ -31,15 +35,9 @@ export function privateKeyHexToKeyPair(privateKeyHex: string) {
return nacl.sign.keyPair.fromSeed(hexToBytes(privateKeyHex));
}

export function mnemonicToKeyPair(mnemonic: string[]) {
return validateBip39Mnemonic(mnemonic)
? bip39MnemonicToKeyPair(mnemonic)
: tonWebMnemonic.mnemonicToKeyPair(mnemonic);
}

export async function fetchPrivateKey(accountId: string, password: string) {
export async function fetchPrivateKey(accountId: string, password: string, account?: ApiAccountWithMnemonic) {
try {
const { secretKey: privateKey } = await fetchKeyPair(accountId, password) || {};
const { secretKey: privateKey } = await fetchKeyPair(accountId, password, account) || {};

return privateKey;
} catch (err) {
Expand All @@ -50,14 +48,21 @@ export async function fetchPrivateKey(accountId: string, password: string) {
}
}

export async function fetchKeyPair(accountId: string, password: string) {
export async function fetchKeyPair(accountId: string, password: string, account?: ApiAccountWithMnemonic) {
try {
const mnemonic = await fetchMnemonic(accountId, password);
account = account ?? await fetchStoredAccount<ApiAccountWithMnemonic>(accountId);
const mnemonic = await getMnemonic(accountId, password, account);
if (!mnemonic) {
return undefined;
}

return isMnemonicPrivateKey(mnemonic) ? privateKeyHexToKeyPair(mnemonic[0]) : await mnemonicToKeyPair(mnemonic);
if (isMnemonicPrivateKey(mnemonic)) {
return privateKeyHexToKeyPair(mnemonic[0]);
} else if (account.type === 'bip39') {
return bip39MnemonicToKeyPair(mnemonic);
} else {
return await tonWebMnemonic.mnemonicToKeyPair(mnemonic);
}
} catch (err) {
logDebugError('fetchKeyPair', err);

Expand Down
1 change: 0 additions & 1 deletion src/api/chains/ton/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export {
generateMnemonic,
rawSign,
mnemonicToKeyPair,
validateMnemonic,
fetchPrivateKey,
getWalletFromBip39Mnemonic,
Expand Down
22 changes: 10 additions & 12 deletions src/api/chains/ton/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
import type { DieselStatus } from '../../../global/types';
import type { CheckTransactionDraftOptions } from '../../methods/types';
import type {
ApiAccountWithMnemonic,
ApiActivity,
ApiAnyDisplayError,
ApiNetwork,
Expand Down Expand Up @@ -56,7 +57,7 @@ import {
resolveTokenWalletAddress,
toBase64Address,
} from './util/tonCore';
import { fetchStoredTonWallet } from '../../common/accounts';
import { fetchStoredAccount, fetchStoredTonWallet } from '../../common/accounts';
import { callBackendGet } from '../../common/backend';
import { updateTransactionMetadata } from '../../common/helpers';
import { getTokenByAddress, getTokenBySlug } from '../../common/tokens';
Expand Down Expand Up @@ -357,12 +358,10 @@ export async function submitTransfer(options: ApiSubmitTransferOptions): Promise
const { network } = parseAccountId(accountId);

try {
const [wallet, { address: fromAddress, isInitialized }, keyPair] = await Promise.all([
getTonWallet(accountId),
fetchStoredTonWallet(accountId),
fetchKeyPair(accountId, password),
]);
const { publicKey, secretKey } = keyPair!;
const account = await fetchStoredAccount<ApiAccountWithMnemonic>(accountId);
const { address: fromAddress, isInitialized } = account.ton;
const wallet = await getTonWallet(accountId, account.ton);
const { publicKey, secretKey } = (await fetchKeyPair(accountId, password, account))!;

let encryptedComment: string | undefined;

Expand Down Expand Up @@ -904,11 +903,10 @@ export async function submitMultiTransfer({
const { network } = parseAccountId(accountId);

try {
const [wallet, { address: fromAddress, isInitialized }, privateKey] = await Promise.all([
getTonWallet(accountId),
fetchStoredTonWallet(accountId),
fetchPrivateKey(accountId, password),
]);
const account = await fetchStoredAccount<ApiAccountWithMnemonic>(accountId);
const { address: fromAddress, isInitialized } = account.ton;
const wallet = await getTonWallet(accountId, account.ton);
const privateKey = await fetchPrivateKey(accountId, password, account);

let totalAmount = 0n;
messages.forEach((message) => {
Expand Down
6 changes: 3 additions & 3 deletions src/api/chains/ton/wallet.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { beginCell, storeStateInit } from '@ton/core';

import type { ApiNetwork, ApiWalletInfo } from '../../types';
import type { ApiNetwork, ApiTonWallet, ApiWalletInfo } from '../../types';
import type { ApiTonWalletVersion, ContractInfo } from './types';
import type { TonWallet } from './util/tonCore';

Expand Down Expand Up @@ -230,9 +230,9 @@ export function pickWalletByAddress(network: ApiNetwork, publicKey: Uint8Array,
return allWallets.find((w) => w.address === address)!;
}

export async function getTonWallet(accountId: string) {
export async function getTonWallet(accountId: string, tonWallet?: ApiTonWallet) {
const { network } = parseAccountId(accountId);
const { publicKey, version } = await fetchStoredTonWallet(accountId);
const { publicKey, version } = tonWallet ?? await fetchStoredTonWallet(accountId);

const publicKeyBytes = hexToBytes(publicKey);
return buildWallet(network, publicKeyBytes, version);
Expand Down
10 changes: 6 additions & 4 deletions src/api/chains/tron/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import type { ContractParamter, Transaction } from 'tronweb/lib/commonjs/types';

import type { ApiSubmitTransferOptions, CheckTransactionDraftOptions } from '../../methods/types';
import type { ApiCheckTransactionDraftResult } from '../ton/types';
import type { ApiAccountWithMnemonic } from '../../types';
import { ApiTransactionDraftError, ApiTransactionError } from '../../types';

import { parseAccountId } from '../../../util/account';
import { logDebugError } from '../../../util/logs';
import { getChainParameters, getTronClient } from './util/tronweb';
import { fetchStoredTronWallet } from '../../common/accounts';
import { fetchMnemonic } from '../../common/mnemonic';
import { fetchStoredAccount, fetchStoredTronWallet } from '../../common/accounts';
import { getMnemonic } from '../../common/mnemonic';
import { handleServerError } from '../../errors';
import { getWalletBalance } from './wallet';
import type { ApiSubmitTransferTronResult } from './types';
Expand Down Expand Up @@ -91,7 +92,8 @@ export async function submitTransfer(options: ApiSubmitTransferOptions): Promise
try {
const tronWeb = getTronClient(network);

const { address } = await fetchStoredTronWallet(accountId);
const account = await fetchStoredAccount<ApiAccountWithMnemonic>(accountId);
const { address } = account.ton;
const trxBalance = await getWalletBalance(network, address);

const trxAmount = tokenAddress ? fee : fee + amount;
Expand All @@ -101,7 +103,7 @@ export async function submitTransfer(options: ApiSubmitTransferOptions): Promise
return { error: ApiTransactionError.InsufficientBalance };
}

const mnemonic = await fetchMnemonic(accountId, password);
const mnemonic = await getMnemonic(accountId, password, account);
const privateKey = tronWeb.fromMnemonic(mnemonic!.join(' ')).privateKey.slice(2);

if (tokenAddress) {
Expand Down
5 changes: 3 additions & 2 deletions src/api/common/accounts.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { StorageKey } from '../storages/types';
import type {
ApiAccountAny,
ApiAccountWithMnemonic,
ApiAccountWithTon,
ApiAccountWithTron,
ApiBip39Account,
Expand Down Expand Up @@ -39,10 +40,10 @@ export async function getAccountIds(): Promise<string[]> {
return Object.keys(await storage.getItem('accounts') || {});
}

export async function getAccountIdWithMnemonic() {
export async function getAccountWithMnemonic() {
const byId = await fetchStoredAccounts();

return Object.entries(byId).find(([, { type }]) => type !== 'ledger')?.[0];
return Object.entries(byId).find(([, { type }]) => type !== 'ledger') as [string, ApiAccountWithMnemonic] | undefined;
}

export async function getNewAccountId(network: ApiNetwork) {
Expand Down
6 changes: 3 additions & 3 deletions src/api/common/mnemonic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as bip39 from 'bip39';

import { type ApiAccountWithMnemonic, ApiCommonError } from '../types';

import { fetchStoredAccount, updateStoredAccount } from './accounts';
import { updateStoredAccount } from './accounts';

const PBKDF2_IMPORT_KEY_ARGS = [
{ name: 'PBKDF2' },
Expand Down Expand Up @@ -118,9 +118,9 @@ async function decryptMnemonicLegacy(encrypted: string, password: string) {
return plaintext.split(',');
}

export async function fetchMnemonic(accountId: string, password: string) {
export async function getMnemonic(accountId: string, password: string, account: ApiAccountWithMnemonic) {
try {
const { mnemonicEncrypted } = (await fetchStoredAccount<ApiAccountWithMnemonic>(accountId));
const { mnemonicEncrypted } = account;
const mnemonic = await decryptMnemonic(mnemonicEncrypted, password);

if (!mnemonicEncrypted.includes(':')) {
Expand Down
18 changes: 10 additions & 8 deletions src/api/methods/wallet.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,36 @@
import * as tonWebMnemonic from 'tonweb-mnemonic';

import type { ApiChain, ApiNetwork } from '../types';
import type { ApiAccountWithMnemonic, ApiChain, ApiNetwork } from '../types';

import { parseAccountId } from '../../util/account';
import chains from '../chains';
import {
fetchStoredAccount,
fetchStoredAddress,
fetchStoredTonWallet,
getAccountIdWithMnemonic,
getAccountWithMnemonic,
} from '../common/accounts';
import * as dappPromises from '../common/dappPromises';
import { fetchMnemonic } from '../common/mnemonic';
import { getMnemonic } from '../common/mnemonic';

const ton = chains.ton;

export function getMnemonic(accountId: string, password: string) {
return fetchMnemonic(accountId, password);
export async function fetchMnemonic(accountId: string, password: string) {
const account = await fetchStoredAccount<ApiAccountWithMnemonic>(accountId);
return getMnemonic(accountId, password, account);
}

export function getMnemonicWordList() {
return tonWebMnemonic.wordlists.default;
}

export async function verifyPassword(password: string) {
const accountId = await getAccountIdWithMnemonic();
if (!accountId) {
const [accountId, account] = (await getAccountWithMnemonic()) ?? [];
if (!accountId || !account) {
throw new Error('The user is not authorized in the wallet');
}

return Boolean(await fetchMnemonic(accountId, password));
return Boolean(await getMnemonic(accountId, password, account));
}

export function confirmDappRequest(promiseId: string, data: any) {
Expand Down
Binary file modified src/assets/lottie/icon_clock_dark.tgs
Binary file not shown.
Binary file modified src/assets/lottie/icon_clock_dark_blue.tgs
Binary file not shown.
Binary file modified src/assets/lottie/icon_clock_dark_gray.tgs
Binary file not shown.
Binary file modified src/assets/lottie/icon_clock_dark_gray_white.tgs
Binary file not shown.
Binary file modified src/assets/lottie/icon_clock_dark_green.tgs
Binary file not shown.
Binary file modified src/assets/lottie/icon_clock_dark_purple.tgs
Binary file not shown.
Binary file modified src/assets/lottie/icon_clock_dark_purple_white.tgs
Binary file not shown.
Binary file modified src/assets/lottie/icon_clock_light.tgs
Binary file not shown.
Binary file modified src/assets/lottie/icon_clock_light_blue.tgs
Binary file not shown.
Binary file modified src/assets/lottie/icon_clock_light_gray.tgs
Binary file not shown.
Binary file modified src/assets/lottie/icon_clock_light_gray_white.tgs
Binary file not shown.
Binary file modified src/assets/lottie/icon_clock_light_green.tgs
Binary file not shown.
Binary file modified src/assets/lottie/icon_clock_light_purple.tgs
Binary file not shown.
Binary file modified src/assets/lottie/icon_clock_light_purple_white.tgs
Binary file not shown.
1 change: 1 addition & 0 deletions src/components/auth/AuthBackupWalletModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ function AuthBackupWalletModal({
hasCloseButton
isOpen={isOpen}
dialogClassName={styles.modalDialog}
forceFullNative={renderingKey !== BackupState.Accept}
nativeBottomSheetKey="disclaimer"
onClose={closeAuthBackupWalletModal}
onCloseAnimationEnd={handleModalClose}
Expand Down
2 changes: 1 addition & 1 deletion src/components/main/modals/BackupModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ function BackupModal({

const handlePasswordSubmit = useLastCallback(async (password: string) => {
setIsLoading(true);
mnemonicRef.current = await callApi('getMnemonic', currentAccountId!, password);
mnemonicRef.current = await callApi('fetchMnemonic', currentAccountId!, password);

if (!mnemonicRef.current) {
setError('Wrong password, please try again.');
Expand Down
7 changes: 7 additions & 0 deletions src/components/receive/ReceiveModal.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,15 @@
}
}

// `min-height: 100%` should be set for the Transition component to work,
// because on iOS the dialog doesn't have a height value, and the container uses `align-items: flex-start`.
.iosModalDialog {
min-height: 100%;
}

.contentWrapper {
overflow: hidden;
flex-grow: 1;
}

.content {
Expand Down
2 changes: 1 addition & 1 deletion src/components/receive/ReceiveModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function ReceiveModal({
return (
<Modal
isOpen={isOpen}
dialogClassName={IS_IOS_APP ? undefined : styles.modalDialog}
dialogClassName={IS_IOS_APP ? styles.iosModalDialog : styles.modalDialog}
nativeBottomSheetKey="receive"
onClose={closeReceiveModal}
>
Expand Down
11 changes: 6 additions & 5 deletions src/components/ui/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import freezeWhenClosed from '../../hooks/freezeWhenClosed';
import { useDelegatedBottomSheet } from '../../hooks/useDelegatedBottomSheet';
import { useDelegatingBottomSheet } from '../../hooks/useDelegatingBottomSheet';
import { useDeviceScreen } from '../../hooks/useDeviceScreen';
import useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps';
import useHideBrowser from '../../hooks/useHideBrowser';
import useHistoryBack from '../../hooks/useHistoryBack';
import useLang from '../../hooks/useLang';
Expand Down Expand Up @@ -111,12 +112,12 @@ function Modal({
onBack: onClose,
});

useEffect(() => {
if (!IS_DELEGATED_BOTTOM_SHEET || !isCompact) return;

useEffectWithPrevDeps(([prevIsOpen]) => {
// Expand NBS to full size for a compact modal inside NBS
BottomSheet.toggleSelfFullSize({ isFullSize: !!isOpen });
}, [isCompact, isOpen]);
if (IS_DELEGATED_BOTTOM_SHEET && isCompact && (prevIsOpen || isOpen)) {
BottomSheet.toggleSelfFullSize({ isFullSize: !!isOpen });
}
}, [isOpen, isCompact]);

useEffect(
() => (isOpen ? captureKeyboardListeners({
Expand Down
8 changes: 4 additions & 4 deletions src/components/ui/PinPad.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -120,17 +120,17 @@

height: 5rem;

.minified > & {
height: 4.75rem;
}

font-size: 2rem;
font-weight: 700;
line-height: 2rem;
text-align: center;

transition: opacity 200ms;

.minified > & {
height: 4.75rem;
}

@media (max-height: 55rem) {
height: 4rem;
}
Expand Down
Loading

0 comments on commit 7b6a21d

Please sign in to comment.