Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c256ad9
chore: bump ledger version
siandreev Sep 16, 2025
334a2bd
fix: temporary set ledger query id to 0
siandreev Sep 16, 2025
05f3f96
fix: PRO-342
siandreev Sep 17, 2025
815e3f0
fix: PRO-360
siandreev Sep 17, 2025
5760d3d
fix: PRO-373
siandreev Sep 17, 2025
d3e3a33
fix: PRO-346
siandreev Sep 17, 2025
4736213
fix: show multisig host not enough balance error
siandreev Sep 17, 2025
73b1e7e
chore: patch mobile version
siandreev Sep 17, 2025
243a759
fix: add wallet lag
siandreev Sep 17, 2025
86be78b
fix: add secure wallet notification for iPad
siandreev Sep 17, 2025
36247dc
fix: change secure notification frequency period
siandreev Sep 17, 2025
e003e0e
fix: import wallet modal bug
siandreev Sep 18, 2025
a936f68
fix: i18n
siandreev Sep 19, 2025
5d728b0
fix: PRO-363
siandreev Sep 19, 2025
0611f70
fix: nft transfer for ledger 2.7.0
siandreev Sep 19, 2025
d9322ea
fix: support /currencies endpoint
siandreev Sep 19, 2025
1eb5e9a
fix: iPad unlock page input shift when keyboard is open
siandreev Sep 22, 2025
432ffcf
fix: PRO-377
siandreev Sep 22, 2025
d1b75f7
fix: ledger send nft
siandreev Sep 22, 2025
db2d54f
fix: desktop confirm dialog
siandreev Sep 23, 2025
c684f67
fix: remove battery charges decimals
siandreev Sep 23, 2025
1200b5b
fix: unlock screen
siandreev Sep 23, 2025
3ce5c8f
fix: add fr, pa, ptm vi locales
siandreev Sep 23, 2025
631f0ba
fix: add bip39
siandreev Sep 25, 2025
095abe9
Merge branch 'fix/PRO-374' into fix/bip39-derevations
siandreev Sep 25, 2025
d3e6b70
fix: types
siandreev Sep 25, 2025
6d40824
fix: TEMPORARY use single ton wallet for all bip39 derivations
siandreev Sep 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions apps/desktop/src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ import { DesktopManageMultisigsPage } from '@tonkeeper/uikit/dist/desktop-pages/
import { useGlobalSetup } from '@tonkeeper/uikit/dist/state/globalSetup';
import { DesktopMultisigOrdersPage } from '@tonkeeper/uikit/dist/desktop-pages/multisig-orders/DesktopMultisigOrders';
import { useRealtimeUpdatesInvalidation } from '@tonkeeper/uikit/dist/hooks/realtime';
import { DesktopMobileAppBanner } from '@tonkeeper/uikit/dist/components/pro/DesktopMobileAppBanner';
import { CryptoStrategyInstaller } from '@tonkeeper/uikit/dist/components/pro/CryptoStrategyInstaller';
import { localesList } from '@tonkeeper/locales/localesList';
import { useAppCountryInfo } from '@tonkeeper/uikit/dist/state/country';
import { SecureWalletNotification } from '@tonkeeper/uikit/dist/components/desktop/SecureWalletNotification';

const queryClient = new QueryClient({
defaultOptions: {
Expand Down Expand Up @@ -361,11 +361,7 @@ export const Content: FC<{
useRealtimeUpdatesInvalidation();

if (lock) {
return (
<FullSizeWrapper>
<Unlock />
</FullSizeWrapper>
);
return <Unlock />;
}

if (!activeAccount || location.pathname.startsWith(AppRoute.import)) {
Expand Down Expand Up @@ -461,6 +457,7 @@ const BackgroundElements = () => {
<PairSignerNotification />
<ConnectLedgerNotification />
<PairKeystoneNotification />
<SecureWalletNotification />
</>
);
};
10 changes: 9 additions & 1 deletion apps/desktop/src/electron/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ import { mainStorage } from './storageService';
import { cookieJar } from './cookie';
import { tonConnectSSE } from './sseEvetns';
import { isValidUrlProtocol } from '@tonkeeper/core/dist/utils/common';
import * as electron from 'electron';
import BaseWindow = Electron.BaseWindow;

const service = 'tonkeeper.com';

const authorizedOpenUrlProtocols = ['http:', 'https:', 'tg:', 'mailto:'];

// eslint-disable-next-line complexity
export const handleBackgroundMessage = async (message: Message): Promise<unknown> => {
export const handleBackgroundMessage = async (
window: BaseWindow,
message: Message
): Promise<unknown> => {
switch (message.king) {
case 'storage-set':
return mainStorage.set(message.key, message.value);
Expand Down Expand Up @@ -102,6 +107,9 @@ export const handleBackgroundMessage = async (message: Message): Promise<unknown
const locale = app.getLocale();
return locale.replaceAll('_', '-').split('-')[0] || null;
}
case 'show-confirm-dialog': {
return electron.dialog.showMessageBoxSync(window, message.options);
}
default:
throw new Error(`Unknown message: ${JSON.stringify(message)}`);
}
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/electron/mainWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export abstract class MainWindow {

ipcMain.handle('message', async (event, message: Message) => {
try {
return await handleBackgroundMessage(message);
return await handleBackgroundMessage(this.mainWindow, message);
} catch (e) {
return e;
}
Expand Down
20 changes: 19 additions & 1 deletion apps/desktop/src/libs/appSdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {
IAppSdk,
BiometryService,
CookieService,
AppCountryInfo
AppCountryInfo,
ConfirmOptions
} from '@tonkeeper/core/dist/AppSdk';
import copyToClipboard from 'copy-to-clipboard';
import packageJson from '../../package.json';
Expand Down Expand Up @@ -63,6 +64,23 @@ export class DesktopAppSdk extends BaseApp implements IAppSdk {
return sendBackground<void>({ king: 'open-page', url });
};

async confirm(options: ConfirmOptions): Promise<boolean> {
const cancelButton = options.cancelButtonTitle || 'Cancel';
const okButton = options.okButtonTitle || 'OK';

return sendBackground<number>({
king: 'show-confirm-dialog',
options: {
message: options.message,
type: options.type,
buttons: [cancelButton, okButton],
defaultId: options.defaultButton === 'cancel' ? 0 : 1,
title: options.title,
cancelId: 0
}
});
}

authorizedOpenUrlProtocols = ['http:', 'https:', 'tg:', 'mailto:'];

version = packageJson.version ?? 'Unknown';
Expand Down
39 changes: 33 additions & 6 deletions apps/desktop/src/libs/keychain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,58 @@ import i18next from '../app/i18n';
import { sendBackground } from './backgroudService';
import { promptDesktopPasswordController } from '@tonkeeper/uikit/dist/components/modals/PromptDesktopPassword';
import { BaseKeychainService } from '@tonkeeper/core/dist/base-keychain-service';
import { KeychainGetError } from '@tonkeeper/core/dist/errors/KeychainError';

export class KeychainDesktop extends BaseKeychainService implements IKeychainService {
constructor(private biometryService: BiometryService, storage: IStorage) {
super(storage);
}

setData = async (key: string, data: string) => {
return sendBackground<void>({ king: 'set-keychain', publicKey: key, mnemonic: data });
try {
await sendBackground<void>({ king: 'set-keychain', publicKey: key, mnemonic: data });
console.info(`[KEYCHAIN] (success) SET key "Wallet-${key}"`);
} catch (e) {
console.info(`[KEYCHAIN] (ERROR) SET key "Wallet-${key}"`, e);
throw e;
}
};

getData = async (key: string) => {
await this.securityCheck();
const value = sendBackground<string | null>({ king: 'get-keychain', publicKey: key });
if (value === null) {
throw new Error('Mnemonic not found in keychain');
let value: string | null = null;
try {
value = await sendBackground<string | null>({ king: 'get-keychain', publicKey: key });
} catch (e) {
console.info(`[KEYCHAIN] (ERROR) GET key "Wallet-${key}"`, e);
throw new KeychainGetError();
}

if (value == null) {
throw new KeychainGetError();
}
console.info(`[KEYCHAIN] (success) GET key "Wallet-${key}"`);
return value;
};

removeData = async (key: string) => {
return sendBackground<void>({ king: 'remove-keychain', publicKey: key });
try {
await sendBackground<void>({ king: 'remove-keychain', publicKey: key });
console.info(`[KEYCHAIN] (success) DELETE key "Wallet-${key}"`);
} catch (e) {
console.info(`[KEYCHAIN] (ERROR) DELETE key "Wallet-${key}"`, e);
throw e;
}
};

clearStorage = async () => {
await sendBackground<void>({ king: 'clear-keychain' });
try {
await sendBackground<void>({ king: 'clear-keychain' });
console.info('[KEYCHAIN] (success) CLEAR all data');
} catch (e) {
console.info('[KEYCHAIN] (ERROR) CLEAR all data');
throw e;
}
await this.resetSecuritySettings();
};

Expand Down
10 changes: 9 additions & 1 deletion apps/desktop/src/libs/message.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { AccountConnectionHttp } from '@tonkeeper/core/dist/service/tonConnect/connectionService';
import { ConfirmOptions } from '@tonkeeper/core/dist/AppSdk';
import MessageBoxSyncOptions = Electron.MessageBoxSyncOptions;

export interface GetStorageMessage {
king: 'storage-get';
Expand Down Expand Up @@ -80,6 +82,11 @@ export interface GetDeviceCountry {
king: 'get-device-country';
}

export interface ConfirmDialog {
king: 'show-confirm-dialog';
options: MessageBoxSyncOptions;
}

export type Message =
| GetStorageMessage
| SetStorageMessage
Expand All @@ -97,4 +104,5 @@ export type Message =
| GetPreferredSystemLanguagesMessage
| TonConnectSendDisconnectMessage
| CleanCookieMessage
| GetDeviceCountry;
| GetDeviceCountry
| ConfirmDialog;
6 changes: 1 addition & 5 deletions apps/extension/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -317,11 +317,7 @@ export const Content: FC<{
}

if (lock) {
return (
<FullSizeWrapper standalone>
<Unlock />
</FullSizeWrapper>
);
return <Unlock />;
}

if (pageView) {
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tonkeeper/mobile",
"version": "4.2.8",
"version": "4.2.9",
"license": "Apache-2.0",
"description": "Your tablet wallet on The Open Network",
"type": "module",
Expand Down
4 changes: 2 additions & 2 deletions apps/mobile/src/app/app-content/NarrowContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { IonContent, IonMenu, IonModal, IonRouterOutlet } from '@ionic/react';
import { DesktopHistoryPage } from '@tonkeeper/uikit/dist/desktop-pages/history/DesktopHistoryPage';
import { DesktopConnectedAppsSettings } from '@tonkeeper/uikit/dist/desktop-pages/settings/DesktopConnectedAppsSettings';
import { DesktopNftSettings } from '@tonkeeper/uikit/dist/desktop-pages/settings/DesktopNftSettings';
import { MAMIndexesPage } from '@tonkeeper/uikit/dist/pages/settings/MamIndexes';
import { DerivableIndexesPage } from 'packages/uikit/src/pages/settings/DerivableIndexes';
import { BatteryPage } from '@tonkeeper/uikit/dist/pages/settings/Battery';
import { WalletVersionPage } from '@tonkeeper/uikit/dist/pages/settings/Version';
import { LedgerIndexesPage } from '@tonkeeper/uikit/dist/pages/settings/LedgerIndexes';
Expand Down Expand Up @@ -316,7 +316,7 @@ const NarrowContentAppRouting = () => {
/>
<Route
path={AppRoute.walletSettings + WalletSettingsRoute.derivations}
component={MAMIndexesPage}
component={DerivableIndexesPage}
/>
<Route
path={AppRoute.walletSettings + WalletSettingsRoute.battery}
Expand Down
8 changes: 3 additions & 5 deletions apps/mobile/src/app/app-content/WideContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { useQueryClient } from '@tanstack/react-query';
import { SplashScreen } from '@capacitor/splash-screen';
import { useRealtimeUpdatesInvalidation } from '@tonkeeper/uikit/dist/hooks/realtime';
import DashboardPage from '@tonkeeper/uikit/dist/desktop-pages/dashboard';
import { SecureWalletNotification } from '@tonkeeper/uikit/dist/components/desktop/SecureWalletNotification';

const FullSizeWrapper = styled(Container)`
max-width: 800px;
Expand Down Expand Up @@ -125,11 +126,7 @@ export const WideContent: FC<{
}, [queryClient]);

if (lock) {
return (
<FullSizeWrapper>
<Unlock />
</FullSizeWrapper>
);
return <Unlock />;
}

if (!activeAccount || location.pathname.startsWith(AppRoute.import)) {
Expand All @@ -156,6 +153,7 @@ export const WideContent: FC<{
</Switch>
</WideContentStyled>
<BackgroundElements />
<SecureWalletNotification />
<PullToRefresh onRefresh={onRefresh} />
</WideLayout>
);
Expand Down
51 changes: 37 additions & 14 deletions apps/mobile/src/libs/keychain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,60 @@ import { BaseKeychainService } from '@tonkeeper/core/dist/base-keychain-service'
import { CAPACITOR_APPLICATION_ID } from './aplication-id';
import { promptDesktopPasswordController } from '@tonkeeper/uikit/dist/components/modals/PromptDesktopPassword';
import { assertUnreachable } from '@tonkeeper/core/dist/utils/types';
import { KeychainGetError } from '@tonkeeper/core/dist/errors/KeychainError';

export class KeychainCapacitor extends BaseKeychainService implements IKeychainService {
constructor(private biometryService: BiometryService, storage: IStorage) {
super(storage);
}

setData = async (key: string, value: string) => {
await SecureStorage.storeData({
id: `Wallet-${key}`,
data: value
});
try {
await SecureStorage.storeData({
id: `Wallet-${key}`,
data: value
});
console.info(`[KEYCHAIN] (success) SET key "Wallet-${key}"`);
} catch (e) {
console.info(`[KEYCHAIN] (ERROR) SET key "Wallet-${key}"`, e);
throw e;
}
};

getData = async (key: string) => {
await this.securityCheck();
const { data } = await SecureStorage.getData({
id: `Wallet-${key}`
});
return data;
try {
const { data } = await SecureStorage.getData({
id: `Wallet-${key}`
});
console.info(`[KEYCHAIN] (success) GET key "Wallet-${key}"`);
return data;
} catch (e) {
console.info(`[KEYCHAIN] (ERROR) GET key "Wallet-${key}"`, e);
throw new KeychainGetError();
}
};

removeData = async (key: string) => {
await SecureStorage.removeData({
id: `Wallet-${key}`
});
console.info(`Deleted password for account "${key}": Success`);
try {
await SecureStorage.removeData({
id: `Wallet-${key}`
});
console.info(`[KEYCHAIN] (success) DELETE key "Wallet-${key}"`);
} catch (e) {
console.info(`[KEYCHAIN] (ERROR) DELETE key "Wallet-${key}"`, e);
throw e;
}
};

clearStorage = async () => {
await SecureStorage.clearStorage();
console.info(`Clear keychain": Success`);
try {
await SecureStorage.clearStorage();
console.info('[KEYCHAIN] (success) CLEAR all data');
} catch (e) {
console.info('[KEYCHAIN] (ERROR) CLEAR all data');
throw e;
}
await this.resetSecuritySettings();
};

Expand Down
6 changes: 1 addition & 5 deletions apps/web/src/AppDesktop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,7 @@ export const DesktopContent: FC<{
const location = useLocation();

if (lock) {
return (
<FullScreen>
<Unlock />
</FullScreen>
);
return <Unlock />;
}

if (!activeAccount || location.pathname.startsWith(AppRoute.import)) {
Expand Down
6 changes: 1 addition & 5 deletions apps/web/src/AppMobile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,7 @@ export const MobileContent: FC<{
const location = useLocation();

if (lock) {
return (
<FullSizeWrapper standalone={standalone}>
<Unlock />
</FullSizeWrapper>
);
return <Unlock />;
}

if (location.pathname.startsWith(AppRoute.signer)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"@ledgerhq/hw-transport-webusb": "^6.28.6",
"@noble/curves": "^1.9.2",
"@noble/ed25519": "^2.3.0",
"@ton-community/ton-ledger": "^7.2.0-pre.3",
"@ton-community/ton-ledger": "^7.4.0-pre.0",
"@ton-keychain/core": "^0.0.4",
"@ton-keychain/trx": "^0.0.7",
"@ton/core": "0.56.0",
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/AppSdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ export interface ConfirmOptions {
message: string;
okButtonTitle?: string;
cancelButtonTitle?: string;
defaultButton?: 'ok' | 'cancel';
type?: 'none' | 'info' | 'error' | 'question' | 'warning';
}

export interface KeyboardService {
Expand Down
Loading