Skip to content

Commit 0c2d47f

Browse files
v3.0.0
1 parent 2199122 commit 0c2d47f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+1045
-441
lines changed

.eslintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
}
5858
}
5959
],
60+
"react/jsx-key": [2, { "checkFragmentShorthand": true}],
6061
"arrow-body-style": "off",
6162
"no-else-return": "off",
6263
"no-plusplus": "off",

changelogs/1.20.19.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Bug fixes and performance improvements

changelogs/2.0.0.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Bug fixes and performance improvements

changelogs/3.0.0.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
- Significantly Improved In-App Browser Interface.
2+
- Manual NFT Hiding.
3+
- Enhanced Scam Detection.
4+
- Ledger v2.1 Support.
5+
- W5 Wallet Version Support.
6+
- Boosted Connection Speed & App Performance.
7+
- Dapp Connection Fixes.
8+
- Multiple Fixes and Improvements.

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mytonwallet",
3-
"version": "1.20.18",
3+
"version": "3.0.0",
44
"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.",
55
"main": "index.js",
66
"scripts": {

public/version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.20.18
1+
3.0.0

src/api/blockchains/ton/transactions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -626,18 +626,18 @@ async function populateTransactions(network: ApiNetwork, transactions: ApiTransa
626626

627627
if (parsedPayload?.type === 'nft:ownership-assigned') {
628628
const nft = nftsByAddress[parsedPayload.nftAddress];
629+
transaction.nft = nft;
629630
if (nft?.isScam) {
630631
transaction.metadata = { ...transaction.metadata, isScam: true };
631632
} else {
632-
transaction.nft = nft;
633633
transaction.fromAddress = addressBook[parsedPayload.prevOwner].user_friendly;
634634
}
635635
} else if (parsedPayload?.type === 'nft:transfer') {
636636
const nft = nftsByAddress[parsedPayload.nftAddress];
637+
transaction.nft = nft;
637638
if (nft?.isScam) {
638639
transaction.metadata = { ...transaction.metadata, isScam: true };
639640
} else {
640-
transaction.nft = nft;
641641
transaction.toAddress = addressBook[parsedPayload.newOwner].user_friendly;
642642
}
643643
}

src/api/blockchains/ton/util/tonCore.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,10 +303,7 @@ export function buildLiquidStakingWithdrawBody(options: {
303303
queryId, amount, responseAddress, waitTillRoundEnd, fillOrKill,
304304
} = options;
305305

306-
const customPayload = new Builder()
307-
.storeUint(Number(waitTillRoundEnd), 1)
308-
.storeUint(Number(fillOrKill), 1)
309-
.asCell();
306+
const customPayload = buildLiquidStakingWithdrawCustomPayload(waitTillRoundEnd, fillOrKill);
310307

311308
return new Builder()
312309
.storeUint(JettonOpCode.Burn, 32)
@@ -318,6 +315,13 @@ export function buildLiquidStakingWithdrawBody(options: {
318315
.asCell();
319316
}
320317

318+
export function buildLiquidStakingWithdrawCustomPayload(waitTillRoundEnd?: boolean, fillOrKill?: boolean) {
319+
return new Builder()
320+
.storeUint(Number(waitTillRoundEnd), 1)
321+
.storeUint(Number(fillOrKill), 1)
322+
.asCell();
323+
}
324+
321325
export function getTokenBalance(network: ApiNetwork, walletAddress: string) {
322326
const tokenWallet = getTonClient(network).open(new JettonWallet(Address.parse(walletAddress)));
323327
return tokenWallet.getJettonBalance();

src/api/common/addresses.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import type { ApiAddressInfo, ApiKnownAddresses } from '../types';
22

3-
import {
4-
RE_EMPTY_CHARS,
5-
RE_FAKE_DOTS, RE_LINK_TEMPLATE, RE_SPACE_CHARS, RE_TG_BOT_MENTION,
6-
} from '../../config';
3+
import { RE_LINK_TEMPLATE, RE_TG_BOT_MENTION } from '../../config';
4+
import { cleanText } from '../../lib/confusables';
75
import { logDebugError } from '../../util/logs';
86
import { callBackendGet } from './backend';
97

@@ -51,11 +49,7 @@ export function checkIsTrustedCollection(address: string) {
5149
}
5250

5351
export function checkHasScamLink(text: string) {
54-
const matches = text
55-
.replace(RE_EMPTY_CHARS, '')
56-
.replace(RE_SPACE_CHARS, ' ')
57-
.replace(RE_FAKE_DOTS, '.')
58-
.matchAll(RE_LINK_TEMPLATE);
52+
const matches = cleanText(text).matchAll(RE_LINK_TEMPLATE);
5953

6054
for (const match of matches) {
6155
const host = match.groups?.host;
@@ -68,5 +62,5 @@ export function checkHasScamLink(text: string) {
6862
}
6963

7064
export function checkHasTelegramBotMention(text: string) {
71-
return RE_TG_BOT_MENTION.test(text.replace(RE_EMPTY_CHARS, '').replace(RE_SPACE_CHARS, ' '));
65+
return RE_TG_BOT_MENTION.test(cleanText(text));
7266
}

src/api/common/helpers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,11 @@ export function buildLocalTransaction(
7070

7171
export function updateTransactionMetadata(transaction: ApiTransactionExtra): ApiTransactionExtra {
7272
const {
73-
normalizedAddress, comment, type, isIncoming,
73+
normalizedAddress, comment, type, isIncoming, nft,
7474
} = transaction;
7575
let { metadata = {} } = transaction;
7676

77-
const isNftTransfer = type === 'nftTransferred' || type === 'nftReceived';
77+
const isNftTransfer = type === 'nftTransferred' || type === 'nftReceived' || Boolean(nft);
7878
const knownAddresses = getKnownAddresses();
7979
const hasScamMarkers = comment ? getScamMarkers().some((sm) => sm.test(comment)) : false;
8080
const shouldCheckComment = !hasScamMarkers && comment && isIncoming

src/api/methods/accounts.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
sendUpdateTokens,
1212
setupBalanceBasedPolling,
1313
setupStakingPolling,
14-
setupSwapPolling,
1514
setupVestingPolling,
1615
setupWalletVersionsPolling,
1716
} from './polling';
@@ -33,7 +32,7 @@ export async function activateAccount(accountId: string, newestTxIds?: ApiTxIdBy
3332
deactivateAllDapps();
3433
}
3534

36-
callHook('onFirstLogin');
35+
void callHook('onFirstLogin');
3736

3837
onActiveDappAccountUpdated(accountId);
3938
}
@@ -44,7 +43,6 @@ export async function activateAccount(accountId: string, newestTxIds?: ApiTxIdBy
4443

4544
void setupBalanceBasedPolling(accountId, newestTxIds);
4645
void setupStakingPolling(accountId);
47-
void setupSwapPolling(accountId);
4846
void setupWalletVersionsPolling(accountId);
4947
void setupVestingPolling(accountId);
5048
}
@@ -55,7 +53,7 @@ export function deactivateAllAccounts() {
5553

5654
if (IS_EXTENSION) {
5755
deactivateAllDapps();
58-
callHook('onFullLogout');
56+
void callHook('onFullLogout');
5957
}
6058
}
6159

src/api/methods/dapps.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ export async function deleteAllDapps(accountId: string) {
165165
accountId,
166166
origin,
167167
});
168-
callHook('onDappDisconnected', accountId, origin);
168+
void callHook('onDappDisconnected', accountId, origin);
169169
});
170170

171171
await callHook('onDappsChanged');
@@ -208,7 +208,7 @@ export function getDappsState(): Promise<ApiDappsState | undefined> {
208208
export async function removeAccountDapps(accountId: string) {
209209
await removeAccountValue(accountId, 'dapps');
210210

211-
callHook('onDappsChanged');
211+
void callHook('onDappsChanged');
212212
}
213213

214214
export async function removeAllDapps() {

src/api/methods/init.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import * as methods from '.';
1313
addHooks({
1414
onDappDisconnected: tonConnectSse.sendSseDisconnect,
1515
onDappsChanged: tonConnectSse.resetupSseConnection,
16-
onSwapCreated: methods.setupSwapPolling,
1716
});
1817

1918
// eslint-disable-next-line @typescript-eslint/no-unused-vars

src/api/methods/polling.ts

Lines changed: 2 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import type {
99
ApiStakingCommonData,
1010
ApiStakingState,
1111
ApiSwapAsset,
12-
ApiSwapHistoryItem,
1312
ApiTokenPrice,
1413
ApiTransactionActivity,
1514
ApiTxIdBySlug,
@@ -39,9 +38,7 @@ import { processNftUpdates, updateAccountNfts } from './nfts';
3938
import { resolveDataPreloadPromise } from './preload';
4039
import { getBaseCurrency } from './prices';
4140
import { getBackendStakingState, tryUpdateStakingCommonData } from './staking';
42-
import {
43-
swapGetAssets, swapGetHistory, swapItemToActivity, swapReplaceTransactionsByRanges,
44-
} from './swap';
41+
import { swapGetAssets, swapReplaceTransactionsByRanges } from './swap';
4542
import { fetchVestings } from './vesting';
4643

4744
type IsAccountActiveFn = (accountId: string) => boolean;
@@ -59,9 +56,6 @@ const STAKING_INTERVAL_WHEN_NOT_FOCUSED = 10 * SEC;
5956
const BACKEND_INTERVAL = 30 * SEC;
6057
const LONG_BACKEND_INTERVAL = 60 * SEC;
6158
const NFT_FULL_INTERVAL = 60 * SEC;
62-
const SWAP_POLLING_INTERVAL = 3 * SEC;
63-
const SWAP_POLLING_INTERVAL_WHEN_NOT_FOCUSED = 10 * SEC;
64-
const SWAP_FINISHED_STATUSES = new Set(['failed', 'completed', 'expired']);
6559
const VERSIONS_INTERVAL = 5 * 60 * SEC;
6660
const VERSIONS_INTERVAL_WHEN_NOT_FOCUSED = 15 * 60 * SEC;
6761
const VESTING_INTERVAL = 10 * SEC;
@@ -81,7 +75,7 @@ const prices: {
8175
baseCurrency: DEFAULT_PRICE_CURRENCY,
8276
bySlug: {},
8377
};
84-
let swapPollingAccountId: string | undefined;
78+
8579
const lastBalanceCache: Record<string, AccountBalanceCache> = {};
8680

8781
export async function initPolling(_onUpdate: OnApiUpdate, _isAccountActive: IsAccountActiveFn) {
@@ -563,100 +557,10 @@ export function sendUpdateTokens() {
563557
});
564558
}
565559

566-
export async function setupSwapPolling(accountId: string) {
567-
if (swapPollingAccountId === accountId) return; // Double launch is not allowed
568-
swapPollingAccountId = accountId;
569-
570-
const { address, lastFinishedSwapTimestamp } = await fetchStoredAccount(accountId);
571-
572-
let fromTimestamp = lastFinishedSwapTimestamp ?? await getActualLastFinishedSwapTimestamp(accountId, address);
573-
574-
const localOnUpdate = onUpdate;
575-
const swapById: Record<string, ApiSwapHistoryItem> = {};
576-
577-
while (isAlive(localOnUpdate, accountId)) {
578-
try {
579-
const swaps = await swapGetHistory(address, {
580-
fromTimestamp,
581-
});
582-
if (!isAlive(localOnUpdate, accountId)) break;
583-
if (!swaps.length) break;
584-
585-
swaps.reverse();
586-
587-
let isLastFinishedSwapUpdated = false;
588-
let isPrevFinished = true;
589-
590-
for (const swap of swaps) {
591-
if (swap.cex) {
592-
if (swap.cex.status === swapById[swap.id]?.cex!.status) {
593-
continue;
594-
}
595-
} else if (swap.status === swapById[swap.id]?.status) {
596-
continue;
597-
}
598-
599-
swapById[swap.id] = swap;
600-
601-
const isFinished = SWAP_FINISHED_STATUSES.has(swap.status);
602-
if (isFinished && isPrevFinished) {
603-
fromTimestamp = swap.timestamp;
604-
isLastFinishedSwapUpdated = true;
605-
}
606-
isPrevFinished = isFinished;
607-
608-
if (swap.cex || swap.status !== 'completed') {
609-
// Completed onchain swaps are processed in swapReplaceTransactions
610-
onUpdate({
611-
type: 'newActivities',
612-
accountId,
613-
activities: [swapItemToActivity(swap)],
614-
});
615-
}
616-
}
617-
618-
if (isLastFinishedSwapUpdated) {
619-
await updateStoredAccount(accountId, {
620-
lastFinishedSwapTimestamp: fromTimestamp,
621-
});
622-
}
623-
} catch (err) {
624-
logDebugError('setupSwapPolling', err);
625-
}
626-
627-
await pauseOrFocus(SWAP_POLLING_INTERVAL, SWAP_POLLING_INTERVAL_WHEN_NOT_FOCUSED);
628-
}
629-
630-
if (accountId === swapPollingAccountId) {
631-
swapPollingAccountId = undefined;
632-
}
633-
}
634-
635560
function isAlive(localOnUpdate: OnApiUpdate, accountId: string) {
636561
return isUpdaterAlive(localOnUpdate) && isAccountActive(accountId);
637562
}
638563

639-
async function getActualLastFinishedSwapTimestamp(accountId: string, address: string) {
640-
const swaps = await swapGetHistory(address, {});
641-
642-
swaps.reverse();
643-
644-
let timestamp = Date.now();
645-
for (const swap of swaps) {
646-
if (SWAP_FINISHED_STATUSES.has(swap.status)) {
647-
timestamp = swap.timestamp;
648-
} else {
649-
break;
650-
}
651-
}
652-
653-
await updateStoredAccount(accountId, {
654-
lastFinishedSwapTimestamp: timestamp,
655-
});
656-
657-
return timestamp;
658-
}
659-
660564
function logAndRescue(err: Error) {
661565
logDebugError('Polling error', err);
662566

src/api/methods/staking.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ export async function submitUnstake(
111111
}
112112

113113
export async function getBackendStakingState(accountId: string): Promise<ApiBackendStakingState> {
114-
const { address, ledger } = await fetchStoredAccount(accountId);
115-
const state = await fetchBackendStakingState(address, Boolean(ledger));
114+
const { address } = await fetchStoredAccount(accountId);
115+
const state = await fetchBackendStakingState(address);
116116
return {
117117
...state,
118118
nominatorsPool: {
@@ -123,7 +123,7 @@ export async function getBackendStakingState(accountId: string): Promise<ApiBack
123123
};
124124
}
125125

126-
export async function fetchBackendStakingState(address: string, isLedger: boolean): Promise<ApiBackendStakingState> {
126+
export async function fetchBackendStakingState(address: string): Promise<ApiBackendStakingState> {
127127
const cacheItem = backendStakingStateByAddress[address];
128128
if (cacheItem && cacheItem[0] > Date.now()) {
129129
return cacheItem[1];
@@ -136,9 +136,7 @@ export async function fetchBackendStakingState(address: string, isLedger: boolea
136136
'X-App-Env': APP_ENV,
137137
};
138138

139-
const stakingState = await callBackendGet(`/staking/state/${address}`, {
140-
isLedger,
141-
}, headers);
139+
const stakingState = await callBackendGet(`/staking/state/${address}`, headers);
142140
stakingState.balance = fromDecimal(stakingState.balance);
143141
stakingState.totalProfit = fromDecimal(stakingState.totalProfit);
144142

@@ -178,3 +176,11 @@ export async function tryUpdateStakingCommonData() {
178176
logDebugError('tryUpdateLiquidStakingState', err);
179177
}
180178
}
179+
180+
export async function getStakingState(accountId: string) {
181+
const blockchain = blockchains[resolveBlockchainKey(accountId)!];
182+
const backendState = await getBackendStakingState(accountId);
183+
const state = await blockchain.getStakingState(accountId, backendState);
184+
185+
return { backendState, state };
186+
}

0 commit comments

Comments
 (0)