diff --git a/changelogs/3.1.2.txt b/changelogs/3.1.2.txt new file mode 100644 index 00000000..619f4cd5 --- /dev/null +++ b/changelogs/3.1.2.txt @@ -0,0 +1 @@ +Bug fixes and performance improvements diff --git a/dev/resolveStackTrace.js b/dev/resolveStackTrace.js new file mode 100644 index 00000000..2fece785 --- /dev/null +++ b/dev/resolveStackTrace.js @@ -0,0 +1,197 @@ +const fs = require('fs'); +const { SourceMapConsumer } = require('source-map'); +const path = require('path'); + +const USAGE_GUIDE = `This script is intended to be used manually. +It makes JavaScript errors from user logs more readable by converting the stacktrace references from minified file addresses to source code addresses. + +To use the script, build the application first. +Make sure the application version you build is the same as the version of the application that produced the logs. +Then run any of these commands: + + npm run resolve-stacktrace + npm run resolve-stacktrace + +Where is an error string from a log file exported by the application, +and is the path to a directory with the application's sourcemaps (default: dist). +Examples: + + npm run resolve-stacktrace ${JSON.stringify('{"name":"Error","message":"Test","stack":"Error: Test\n at t.BitBuilder.writeVarUint (https://mytonwallet.local/941.c17ba5754ec7f174fec2.js:2:25840)\n at t.BitBuilder.writeCoins (https://mytonwallet.local/941.c17ba5754ec7f174fec2.js:2:26382)"}')} + + npm run resolve-stacktrace "Error: Test\n at t.BitBuilder.writeVarUint (https://mytonwallet.local/941.c17ba5754ec7f174fec2.js:2:25840)\n at t.BitBuilder.writeCoins (https://mytonwallet.local/941.c17ba5754ec7f174fec2.js:2:26382)"`; + +const DEFAULT_MAP_DIRECTORY = path.join(__dirname, '..', 'dist'); + +const { mapDirectory, stackTrace } = resolveArguments(); +const resolvedStackTrace = resolveStackTrace(mapDirectory, stackTrace); +process.stdout.write(`${resolvedStackTrace}\n`); +process.exit(0); + +function resolveArguments() { + const arguments = process.argv.slice(2); + switch (arguments.length) { + case 0: + process.stderr.write(`Too few arguments!\n\n${USAGE_GUIDE}\n`) + process.exit(1); + break; + case 1: + return { + mapDirectory: DEFAULT_MAP_DIRECTORY, + stackTrace: parseStackTrace(arguments[0]), + }; + case 2: + return { + mapDirectory: arguments[0], + stackTrace: parseStackTrace(arguments[1]), + }; + default: + process.stderr.write(`Too many arguments!\n\n${USAGE_GUIDE}\n`) + process.exit(1); + break; + } +} + +function parseStackTrace(inputText) { + const decoders = [parseJsonStackTrace, parsePlainStackTrace]; + + for (const decoder of decoders) { + const decoded = decoder(inputText); + if (decoded) { + return decoded; + } + } + + process.stderr.write(`Unknown input error format. Check the examples.\n\n${USAGE_GUIDE}\n`) + process.exit(1); +} + +// Decodes a line from a log file as is. For example: +// "{\"name\":\"TypeError\",\"message\":\"Cannot... +function parseJsonStackTrace(inputText) { + let data + try { + data = JSON.parse(inputText); + } catch { + return null; + } + + if (!data || typeof data !== 'object' || typeof data.stack !== 'string') { + return null; + } + + return data.stack; +} + +function parsePlainStackTrace(inputText) { + if (/^(.+)(\n.*:\d+:\d+)+$/.test(inputText)) { + return inputText; + } + + return null; +} + +function resolveStackTrace(mapDirectory, stackTrace) { + const consumerCache = {}; + + return stackTrace + .split('\n') + .map(line => resolveStackTraceLine(mapDirectory, consumerCache, line)) + .join('\n'); +} + +function resolveStackTraceLine(mapDirectory, consumerCache, line) { + const parsedLine = parseStackTraceLine(line); + if (!parsedLine) { + return line; + } + + const newTrace = resolveTrace( + mapDirectory, + consumerCache, + parsedLine.fileUrl, + parsedLine.lineNumber, + parsedLine.columnNumber, + ); + if (!newTrace) { + return line; + } + + return `${parsedLine.lineIndent}at ${newTrace.name ?? ''} ${newTrace.filePath}:${newTrace.lineNumber}:${newTrace.columnNumber}`; +} + +function parseStackTraceLine(line) { + // Example: at t.BitBuilder.writeCoins (https://mytonwallet.local/941.c17ba5754ec7f174fec2.js:2:26382) + const chromeRegex1 = /^(\s*)at\s.+\((.+):(\d+):(\d+)\)\s*$/; + // Example: at async https://mytonwallet.local/941.c17ba5754ec7f174fec2.js:2:1906473 + const chromeRegex2 = /^(\s*)at(?:\sasync)?\s(.+):(\d+):(\d+)\s*$/; + // Example: safeExec@http://localhost:4321/main.0f90301c98b9aa1b7228.js:55739:14 + // Example: @http://localhost:4321/main.0f90301c98b9aa1b7228.js:49974:25 + // Example: ./src/lib/teact/teact.ts/runUpdatePassOnRaf item.isFile() && extractBundleIdFromFilePath(item.name, '.js.map') === bundleId; + return directoryContent.find(isDesiredMap)?.name ?? null; +} + +function extractFilePathFromUrl(fileUrl) { + return fileUrl.replace(/^https?:\/\/[^\/]*\//, ''); +} + +function extractBundleIdFromFilePath(filePath, extension) { + if (!filePath.endsWith(extension)) { + return null; + } + + const match = /^([\w.-]*)\.[\w]{16,}$/.exec(filePath.slice(0, filePath.length - extension.length)); + if (!match) { + return null; + } + + return match[1]; +} + +function resolveSourceFilePath(sourceFileUrl) { + return sourceFileUrl.replace(/^webpack:\/\/[^\/]*\//, ''); +} diff --git a/package-lock.json b/package-lock.json index 08ee1eb5..53597157 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mytonwallet", - "version": "3.1.1", + "version": "3.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mytonwallet", - "version": "3.1.1", + "version": "3.1.2", "license": "GPL-3.0-or-later", "dependencies": { "@awesome-cordova-plugins/core": "6.9.0", @@ -143,6 +143,7 @@ "sass-loader": "16.0.2", "script-loader": "0.7.2", "serve": "14.2.3", + "source-map": "0.6.1", "stylelint": "14.16.1", "stylelint-config-clean-order": "0.8.0", "stylelint-config-recommended-scss": "8.0.0", @@ -22250,6 +22251,8 @@ }, "node_modules/source-map": { "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", "engines": { diff --git a/package.json b/package.json index ef704cf7..c29c1dea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mytonwallet", - "version": "3.1.1", + "version": "3.1.2", "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": { @@ -42,7 +42,8 @@ "postversion": "./deploy/postversion.sh", "giveaways:build": "webpack --config ./webpack-giveaways.config.ts && bash ./deploy/copy_to_dist.sh dist-giveaways", "giveaways:build:dev": "APP_ENV=development webpack --mode development --config ./webpack-giveaways.config.ts && bash ./deploy/copy_to_dist.sh dist-giveaways", - "giveaways:dev": "APP_ENV=development webpack serve --mode development --port 4322 --config ./webpack-giveaways.config.ts" + "giveaways:dev": "APP_ENV=development webpack serve --mode development --port 4322 --config ./webpack-giveaways.config.ts", + "resolve-stacktrace": "node ./dev/resolveStackTrace.js" }, "engines": { "node": "^22", @@ -167,6 +168,7 @@ "sass-loader": "16.0.2", "script-loader": "0.7.2", "serve": "14.2.3", + "source-map": "0.6.1", "stylelint": "14.16.1", "stylelint-config-clean-order": "0.8.0", "stylelint-config-recommended-scss": "8.0.0", diff --git a/public/version.txt b/public/version.txt index 94ff29cc..ef538c28 100644 --- a/public/version.txt +++ b/public/version.txt @@ -1 +1 @@ -3.1.1 +3.1.2 diff --git a/src/api/methods/swap.ts b/src/api/methods/swap.ts index b7fd092c..30d29d07 100644 --- a/src/api/methods/swap.ts +++ b/src/api/methods/swap.ts @@ -54,7 +54,9 @@ export async function swapBuildTransfer( const { network } = parseAccountId(accountId); const authToken = await getBackendAuthToken(accountId, password); - const { address } = await fetchStoredTonWallet(accountId); + const { address, version } = await fetchStoredTonWallet(accountId); + request.walletVersion = version; + const { id, transfers } = await swapBuild(authToken, request); const transferList = transfers.map((transfer) => ({ @@ -183,7 +185,12 @@ export async function fetchSwaps(accountId: string, ids: string[]) { return { nonExistentIds, swaps }; } -export function swapEstimate(request: ApiSwapEstimateRequest): Promise { +export async function swapEstimate( + accountId: string, + request: ApiSwapEstimateRequest, +): Promise { + request.walletVersion = (await fetchStoredTonWallet(accountId)).version; + return callBackendPost('/swap/ton/estimate', request, { isAllowBadRequest: true, }); diff --git a/src/api/types/backend.ts b/src/api/types/backend.ts index b6bf7cde..ff8bda1b 100644 --- a/src/api/types/backend.ts +++ b/src/api/types/backend.ts @@ -1,4 +1,5 @@ import type { DieselStatus } from '../../global/types'; +import type { ApiTonWalletVersion } from '../chains/ton/types'; import type { ApiLoyaltyType } from './misc'; export type ApiSwapEstimateRequest = { @@ -9,6 +10,7 @@ export type ApiSwapEstimateRequest = { toAmount?: string; fromAddress: string; shouldTryDiesel?: boolean; + walletVersion?: ApiTonWalletVersion; }; export type ApiSwapEstimateResponse = ApiSwapEstimateRequest & { diff --git a/src/components/AppLocked.tsx b/src/components/AppLocked.tsx index cc1f03df..331f3c56 100644 --- a/src/components/AppLocked.tsx +++ b/src/components/AppLocked.tsx @@ -37,6 +37,16 @@ import logoLightPath from '../assets/logoLight.svg'; const WINDOW_EVENTS_LATENCY = 5000; const INTERVAL_CHECK_PERIOD = 5000; const PINPAD_RESET_DELAY = 300; +const ACTIVATION_EVENT_NAMES = [ + 'focus', // For Web + 'mousemove', // For Web + 'touch', // For Capacitor + 'wheel', + 'keydown', +]; +// `capture: true` is necessary because otherwise a `stopPropagation` call inside the main UI will prevent the event +// from getting to the listeners inside `AppLocked`. +const ACTIVATION_EVENT_OPTIONS = { capture: true }; interface StateProps { isNonNativeBiometricAuthEnabled: boolean; @@ -131,18 +141,14 @@ function AppLocked({ const handleActivityThrottled = useThrottledCallback(handleActivity, [handleActivity], WINDOW_EVENTS_LATENCY); useEffectOnce(() => { - window.addEventListener('focus', handleActivityThrottled, { capture: true }); // For Web - window.addEventListener('mousemove', handleActivityThrottled, { capture: true }); // For Web - window.addEventListener('touch', handleActivityThrottled, { capture: true }); // For Capacitor - window.addEventListener('wheel', handleActivityThrottled, { capture: true }); - window.addEventListener('keydown', handleActivityThrottled); + for (const eventName of ACTIVATION_EVENT_NAMES) { + window.addEventListener(eventName, handleActivityThrottled, ACTIVATION_EVENT_OPTIONS); + } return () => { - window.removeEventListener('focus', handleActivityThrottled, { capture: true }); - window.removeEventListener('mousemove', handleActivityThrottled, { capture: true }); - window.removeEventListener('touch', handleActivityThrottled, { capture: true }); - window.removeEventListener('wheel', handleActivityThrottled, { capture: true }); - window.removeEventListener('keydown', handleActivityThrottled); + for (const eventName of ACTIVATION_EVENT_NAMES) { + window.removeEventListener(eventName, handleActivityThrottled, ACTIVATION_EVENT_OPTIONS); + } }; }); diff --git a/src/components/main/sections/Content/Nfts.tsx b/src/components/main/sections/Content/Nfts.tsx index 5a776f48..0b602f23 100644 --- a/src/components/main/sections/Content/Nfts.tsx +++ b/src/components/main/sections/Content/Nfts.tsx @@ -5,15 +5,13 @@ import type { ApiNft } from '../../../../api/types'; import { ANIMATED_STICKER_BIG_SIZE_PX, - GETGEMS_BASE_MAINNET_URL, - GETGEMS_BASE_TESTNET_URL, NOTCOIN_VOUCHERS_ADDRESS, + TON_DIAMONDS_URL, } from '../../../../config'; import renderText from '../../../../global/helpers/renderText'; import { selectCurrentAccountState } from '../../../../global/selectors'; import buildClassName from '../../../../util/buildClassName'; import captureEscKeyListener from '../../../../util/captureEscKeyListener'; -import { IS_ANDROID_APP, IS_IOS_APP } from '../../../../util/windowEnvironment'; import { ANIMATED_STICKERS_PATHS } from '../../../ui/helpers/animatedAssets'; import { useDeviceScreen } from '../../../../hooks/useDeviceScreen'; @@ -37,20 +35,18 @@ interface StateProps { selectedAddresses?: string[]; byAddress?: Record; currentCollectionAddress?: string; - isTestnet?: boolean; blacklistedNftAddresses?: string[]; whitelistedNftAddresses?: string[]; + isNftBuyingDisabled?: boolean; } -const GETGEMS_ENABLED = !IS_IOS_APP && !IS_ANDROID_APP; - function Nfts({ isActive, orderedAddresses, selectedAddresses, byAddress, currentCollectionAddress, - isTestnet, + isNftBuyingDisabled, blacklistedNftAddresses, whitelistedNftAddresses, }: OwnProps & StateProps) { @@ -63,8 +59,6 @@ function Nfts({ useEffect(clearNftsSelection, [clearNftsSelection, isActive, currentCollectionAddress]); useEffect(() => (hasSelection ? captureEscKeyListener(clearNftsSelection) : undefined), [hasSelection]); - const getgemsBaseUrl = isTestnet ? GETGEMS_BASE_TESTNET_URL : GETGEMS_BASE_MAINNET_URL; - const nfts = useMemo(() => { if (!orderedAddresses || !byAddress) { return undefined; @@ -112,11 +106,11 @@ function Nfts({ nonInteractive />

{lang('No NFTs yet')}

- {GETGEMS_ENABLED && ( + {!isNftBuyingDisabled && ( <>

{renderText(lang('$nft_explore_offer'))}

- - {lang('Open Getgems')} + + {lang('Open TON Diamonds')} )} @@ -158,6 +152,7 @@ export default memo( currentCollectionAddress, selectedAddresses, } = selectCurrentAccountState(global)?.nfts || {}; + const { isNftBuyingDisabled } = global.restrictions; const { blacklistedNftAddresses, @@ -169,9 +164,9 @@ export default memo( selectedAddresses, byAddress, currentCollectionAddress, - isTestnet: global.settings.isTestnet, blacklistedNftAddresses, whitelistedNftAddresses, + isNftBuyingDisabled, }; }, (global, _, stickToFirst) => { diff --git a/src/components/transfer/TransferInitial.tsx b/src/components/transfer/TransferInitial.tsx index 5c7340da..6c4970c1 100644 --- a/src/components/transfer/TransferInitial.tsx +++ b/src/components/transfer/TransferInitial.tsx @@ -17,7 +17,6 @@ import { import { Big } from '../../lib/big.js'; import renderText from '../../global/helpers/renderText'; import { - selectCurrentAccountSettings, selectCurrentAccountState, selectCurrentAccountTokens, selectIsHardwareAccount, @@ -83,7 +82,6 @@ interface StateProps { isMemoRequired?: boolean; baseCurrency?: ApiBaseCurrency; nfts?: ApiNft[]; - alwaysHiddenSlugs?: string[]; binPayload?: string; stateInit?: string; dieselAmount?: bigint; @@ -140,7 +138,6 @@ function TransferInitial({ binPayload, stateInit, dieselAmount, - alwaysHiddenSlugs, dieselStatus, isDieselAuthorizationStarted, isMultichainAccount, @@ -234,7 +231,7 @@ function TransferInitial({ const isGaslessWithStars = dieselStatus === 'stars-fee'; const isDieselAvailable = dieselStatus === 'available' || isGaslessWithStars; const isDieselNotAuthorized = dieselStatus === 'not-authorized'; - const withDiesel = dieselStatus && dieselStatus !== 'not-available'; + const withDiesel = !isEnoughNativeCoin && dieselStatus && dieselStatus !== 'not-available'; const isEnoughDiesel = withDiesel && amount && balance && dieselAmount ? isGaslessWithStars || skipNextFeeEstimate.current ? true @@ -250,11 +247,11 @@ function TransferInitial({ ? balance : balance - dieselAmount; } - if (nativeToken?.chain === 'tron' && balance) { + if (tokenSlug === TRX.slug && balance) { return balance - ONE_TRX; } return balance; - }, [balance, dieselAmount, isGaslessWithStars, withDiesel, nativeToken]); + }, [balance, dieselAmount, isGaslessWithStars, withDiesel, tokenSlug]); const authorizeDieselInterval = isDieselNotAuthorized && isDieselAuthorizationStarted && tokenSlug && !isToncoin ? AUTHORIZE_DIESEL_INTERVAL_MS @@ -284,7 +281,7 @@ function TransferInitial({ } return tokens.reduce((acc, token) => { - if ((token.amount > 0 || token.slug === tokenSlug) && !alwaysHiddenSlugs?.includes(token.slug)) { + if ((token.amount > 0 && !token.isDisabled) || token.slug === tokenSlug) { acc.push({ value: token.slug, icon: ASSET_LOGO_PATHS[token.symbol.toLowerCase() as keyof typeof ASSET_LOGO_PATHS] || token.image, @@ -295,7 +292,7 @@ function TransferInitial({ return acc; }, []); - }, [alwaysHiddenSlugs, isMultichainAccount, tokenSlug, tokens]); + }, [isMultichainAccount, tokenSlug, tokens]); const validateAndSetAmount = useLastCallback( (newAmount: bigint | undefined, noReset = false) => { @@ -947,7 +944,7 @@ function TransferInitial({ const withButton = isQrScannerSupported || withPasteButton || withAddressClearButton; function renderButtonText() { - if (!isEnoughNativeCoin && withDiesel && !isDieselAvailable) { + if (withDiesel && !isDieselAvailable) { if (dieselStatus === 'pending-previous') { return lang('Awaiting Previous Fee'); } else { @@ -1080,7 +1077,6 @@ export default memo( binPayload, stateInit, tokens: selectCurrentAccountTokens(global), - alwaysHiddenSlugs: selectCurrentAccountSettings(global)?.alwaysHiddenSlugs, savedAddresses: accountState?.savedAddresses, isEncryptedCommentSupported: !isLedger && !nfts?.length && !isMemoRequired, isMemoRequired, diff --git a/src/config.ts b/src/config.ts index bbe763e6..3043c070 100644 --- a/src/config.ts +++ b/src/config.ts @@ -96,12 +96,16 @@ export const TONAPIIO_TESTNET_URL = process.env.TONAPIIO_TESTNET_URL || 'https:/ export const BRILLIANT_API_BASE_URL = process.env.BRILLIANT_API_BASE_URL || 'https://api.mytonwallet.org'; +export const TRON_MAINNET_API_URL = process.env.TRON_MAINNET_API_URL || 'https://tronapi.mytonwallet.org'; +export const TRON_TESTNET_API_URL = process.env.TRON_TESTNET_API_URL || 'https://api.shasta.trongrid.io'; + export const FRACTION_DIGITS = 9; export const SHORT_FRACTION_DIGITS = 2; export const SUPPORT_USERNAME = 'MyTonWalletSupport'; export const MY_TON_WALLET_PROMO_URL = 'https://mytonwallet.io'; export const TELEGRAM_WEB_URL = 'https://web.telegram.org/a/'; +export const TON_DIAMONDS_URL = 'https://ton.diamonds/'; export const GETGEMS_BASE_MAINNET_URL = 'https://getgems.io/'; export const GETGEMS_BASE_TESTNET_URL = 'https://testnet.getgems.io/'; export const EMPTY_HASH_VALUE = 'NOHASH'; @@ -118,7 +122,7 @@ export const PROXY_HOSTS = process.env.PROXY_HOSTS; export const TINY_TRANSFER_MAX_COST = 0.01; -export const LANG_CACHE_NAME = 'mtw-lang-140'; +export const LANG_CACHE_NAME = 'mtw-lang-141'; export const LANG_LIST: LangItem[] = [{ langCode: 'en', @@ -239,11 +243,11 @@ export const CHAIN_CONFIG = { maxTransferToken: 35_000_000n, // 35 TRX }, mainnet: { - apiUrl: 'https://api.trongrid.io', + apiUrl: TRON_MAINNET_API_URL, usdtAddress: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', }, testnet: { - apiUrl: 'https://api.shasta.trongrid.io', + apiUrl: TRON_TESTNET_API_URL, usdtAddress: 'TG3XXyExBkPp9nzdajDZsozEu4BkaSJozs', }, }, diff --git a/src/global/actions/api/swap.ts b/src/global/actions/api/swap.ts index 78edd527..09b60920 100644 --- a/src/global/actions/api/swap.ts +++ b/src/global/actions/api/swap.ts @@ -631,7 +631,7 @@ addActionHandler('estimateSwap', async (global, actions, { shouldBlock, isEnough const shouldTryDiesel = isEnoughToncoin === false; - const estimate = await callApi('swapEstimate', { + const estimate = await callApi('swapEstimate', global.currentAccountId!, { ...estimateAmount, from, to, diff --git a/src/global/actions/apiUpdates/initial.ts b/src/global/actions/apiUpdates/initial.ts index 96addb29..f3aba204 100644 --- a/src/global/actions/apiUpdates/initial.ts +++ b/src/global/actions/apiUpdates/initial.ts @@ -176,6 +176,7 @@ addActionHandler('apiUpdate', (global, actions, update) => { isLimitedRegion, isSwapDisabled: IS_IOS_APP && isLimitedRegion, isOnRampDisabled: IS_IOS_APP && isLimitedRegion, + isNftBuyingDisabled: IS_IOS_APP && isLimitedRegion, isCopyStorageEnabled, supportAccountsCount, countryCode, diff --git a/src/global/initialState.ts b/src/global/initialState.ts index a2d23e46..87c06aa6 100644 --- a/src/global/initialState.ts +++ b/src/global/initialState.ts @@ -86,6 +86,7 @@ export const INITIAL_STATE: GlobalState = { isLimitedRegion: false, isSwapDisabled: IS_IOS_APP, isOnRampDisabled: IS_IOS_APP, + isNftBuyingDisabled: IS_IOS_APP, }, mediaViewer: {}, diff --git a/src/global/types.ts b/src/global/types.ts index d485b208..4b9fabc1 100644 --- a/src/global/types.ts +++ b/src/global/types.ts @@ -639,6 +639,7 @@ export type GlobalState = { isLimitedRegion: boolean; isSwapDisabled: boolean; isOnRampDisabled: boolean; + isNftBuyingDisabled: boolean; isCopyStorageEnabled?: boolean; supportAccountsCount?: number; countryCode?: ApiCountryCode; diff --git a/src/i18n/de.yaml b/src/i18n/de.yaml index 5ef91cde..20a3bf12 100644 --- a/src/i18n/de.yaml +++ b/src/i18n/de.yaml @@ -155,7 +155,7 @@ No NFTs yet: Noch keine NFTs vorhanden $nft_explore_offer: | Erkunden Sie einen Marktplatz, um bestehende NFT-Sammlungen zu entdecken. -Open Getgems: Getgems öffnen +Open TON Diamonds: TON Diamonds öffnen Received: Empfangen Sent: Gesendet $transaction_from: von %address% diff --git a/src/i18n/en.yaml b/src/i18n/en.yaml index 8dc67a02..1840dbbe 100644 --- a/src/i18n/en.yaml +++ b/src/i18n/en.yaml @@ -155,7 +155,7 @@ No NFTs yet: No NFTs yet $nft_explore_offer: | Explore a marketplace to discover existing NFT collections. -Open Getgems: Open Getgems +Open TON Diamonds: Open TON Diamonds Received: Received Sent: Sent $transaction_from: from %address% diff --git a/src/i18n/es.yaml b/src/i18n/es.yaml index 3fce3771..85b23db6 100644 --- a/src/i18n/es.yaml +++ b/src/i18n/es.yaml @@ -154,7 +154,7 @@ No NFTs yet: Aún no tienes NFT $nft_explore_offer: | Explore los mercados para descubrir nuevas colecciones NFT. -Open Getgems: Abrir Getgems +Open TON Diamonds: Abrir TON Diamonds Received: Recibido Sent: Enviado $transaction_from: de %address% diff --git a/src/i18n/pl.yaml b/src/i18n/pl.yaml index 0eefc4d4..869d5335 100644 --- a/src/i18n/pl.yaml +++ b/src/i18n/pl.yaml @@ -157,7 +157,7 @@ No NFTs yet: Nie ma jeszcze NFT $nft_explore_offer: | Przeglądaj rynek, aby odkryć istniejące kolekcje NFT. -Open Getgems: Otwórz Getgems +Open TON Diamonds: Otwórz TON Diamonds Received: Otrzymano Sent: Wysłany $transaction_from: od %address% diff --git a/src/i18n/ru.yaml b/src/i18n/ru.yaml index 3a497a59..aad2ac91 100644 --- a/src/i18n/ru.yaml +++ b/src/i18n/ru.yaml @@ -158,7 +158,7 @@ No NFTs yet: Пока у вас нет NFT $nft_explore_offer: | Но вы можете просмотреть существующие коллекции. -Open Getgems: Открыть Getgems +Open TON Diamonds: Открыть TON Diamonds Received: Получено Sent: Отправлено $transaction_from: от %address% diff --git a/src/i18n/th.yaml b/src/i18n/th.yaml index c6481155..20029939 100644 --- a/src/i18n/th.yaml +++ b/src/i18n/th.yaml @@ -155,7 +155,7 @@ No NFTs yet: ยังไม่มี NFT $nft_explore_offer: | สำรวจมาร์เก็ตเพลสเพื่อค้นพบ แหล่งของ NFT คอลเลกชัน. -Open Getgems: เปิด Getgems +Open TON Diamonds: เปิด TON Diamonds Received: ได้รับ Sent: ส่ง $transaction_from: จาก %address% diff --git a/src/i18n/tr.yaml b/src/i18n/tr.yaml index 0da25a3c..a9073af1 100644 --- a/src/i18n/tr.yaml +++ b/src/i18n/tr.yaml @@ -155,7 +155,7 @@ No NFTs yet: Henüz NFT'niz yok $nft_explore_offer: | Mevcut NFT koleksiyonlarını görmek için NFT pazaryerini inceleyin. -Open Getgems: Getgems'i aç +Open TON Diamonds: TON Diamonds'i aç Received: Alındı Sent: Gönder $transaction_from: "bu adresten = %address%" diff --git a/src/i18n/uk.yaml b/src/i18n/uk.yaml index 19c58178..47f227ca 100644 --- a/src/i18n/uk.yaml +++ b/src/i18n/uk.yaml @@ -158,7 +158,7 @@ No NFTs yet: Поки у вас немає NFT $nft_explore_offer: | Але ви можете переглянути наявні колекції. -Open Getgems: Відкрити Getgems +Open TON Diamonds: Відкрити TON Diamonds Transaction is not completed: Переказ не виконано Received: Отримано Sent: Відправлено diff --git a/src/i18n/zh-Hans.yaml b/src/i18n/zh-Hans.yaml index 786df1f3..c12d53a4 100644 --- a/src/i18n/zh-Hans.yaml +++ b/src/i18n/zh-Hans.yaml @@ -149,7 +149,7 @@ NFT: NFT No NFTs yet: NFT 空空如也··· $nft_explore_offer: | 在市场中寻找心仪的 NFT 收藏。 -Open Getgems: 打开 Getgems +Open TON Diamonds: 打开 TON Diamonds Received: 已收到 Sent: 已发送 $transaction_from: 从 %address% diff --git a/src/i18n/zh-Hant.yaml b/src/i18n/zh-Hant.yaml index c5d8dcd5..32722af1 100644 --- a/src/i18n/zh-Hant.yaml +++ b/src/i18n/zh-Hant.yaml @@ -149,7 +149,7 @@ NFT: NFT No NFTs yet: 尚未有 NFT $nft_explore_offer: | 探索市場來尋找現有的 NFT 收藏. -Open Getgems: 開啟 Getgems +Open TON Diamonds: 開啟 TON Diamonds Received: 已收到 Sent: 已送出 $transaction_from: 從 %address% diff --git a/src/util/deeplink/index.ts b/src/util/deeplink/index.ts index 52d2d81e..a7ef0189 100644 --- a/src/util/deeplink/index.ts +++ b/src/util/deeplink/index.ts @@ -157,7 +157,7 @@ async function processTonDeeplink(url: string) { } } -export function parseTonDeeplink(value: string | unknown) { +export function parseTonDeeplink(value?: string) { if (typeof value !== 'string' || !isTonDeeplink(value) || !value.includes('/transfer/')) { return undefined; } @@ -219,6 +219,8 @@ async function processTonConnectDeeplink(url: string, isFromInAppBrowser = false } export function isSelfDeeplink(url: string) { + url = forceHttpsProtocol(url); + return url.startsWith(SELF_PROTOCOL) || SELF_UNIVERSAL_URLS.some((u) => omitProtocol(url).startsWith(omitProtocol(u))); } @@ -302,7 +304,7 @@ export function processSelfDeeplink(deeplink: string) { } case DeeplinkCommand.Transfer: { - let tonDeeplink = deeplink; + let tonDeeplink = forceHttpsProtocol(deeplink); SELF_UNIVERSAL_URLS.forEach((prefix) => { if (tonDeeplink.startsWith(prefix)) { tonDeeplink = tonDeeplink.replace(`${prefix}/`, TON_PROTOCOL); @@ -322,6 +324,10 @@ function omitProtocol(url: string) { return url.replace(/^https?:\/\//, ''); } +function forceHttpsProtocol(url: string) { + return url.replace(/^http:\/\//, 'https://'); +} + function toNumberOrEmptyString(input?: string | null) { return String(Number(input) || ''); } diff --git a/webpack.config.ts b/webpack.config.ts index 2ce26ad4..8d007cf5 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -292,6 +292,8 @@ export default function createConfig( TONHTTPAPI_V3_MAINNET_API_KEY: '', TONHTTPAPI_V3_TESTNET_API_KEY: '', BRILLIANT_API_BASE_URL: '', + TRON_MAINNET_API_URL: '', + TRON_TESTNET_API_URL: '', PROXY_HOSTS: '', STAKING_POOLS: '', LIQUID_POOL: '',