From 217d01b87f90dc547569eb17115a6b52493a4428 Mon Sep 17 00:00:00 2001 From: mytonwalletorg Date: Mon, 3 Feb 2025 15:55:10 +0100 Subject: [PATCH] 3.3.1 --- changelogs/3.3.1.txt | 1 + package-lock.json | 4 +- package.json | 2 +- public/version.txt | 2 +- src/api/chains/ton/util/metadata.ts | 11 +- src/api/tonConnect/index.ts | 2 +- src/api/types/misc.ts | 1 + src/assets/font-icons/telegram-filled.svg | 1 + src/components/App.tsx | 8 +- src/components/auth/Auth.module.scss | 6 + src/components/explore/Category.module.scss | 2 +- src/components/explore/Category.tsx | 4 +- src/components/explore/DappFeed.module.scss | 10 +- src/components/explore/DappFeedItem.tsx | 5 +- src/components/explore/Explore.module.scss | 38 +++-- src/components/explore/Explore.tsx | 30 ++-- src/components/explore/Site.tsx | 14 +- src/components/explore/SiteList.module.scss | 2 +- src/components/ledger/LedgerConnect.tsx | 2 +- src/components/ledger/LedgerModal.module.scss | 4 + .../main/sections/Actions/BottomBar.tsx | 28 ++-- .../main/sections/Content/Content.module.scss | 5 + .../main/sections/Content/Nft.module.scss | 3 + src/components/main/sections/Content/Nfts.tsx | 15 +- .../mediaViewer/hooks/useNftMenu.ts | 12 +- src/components/settings/Settings.module.scss | 8 + src/components/settings/SettingsDapps.tsx | 4 +- src/components/swap/Swap.module.scss | 1 + src/components/swap/SwapInitial.tsx | 16 +- src/components/ui/UpdateAvailable.module.scss | 5 + src/config.ts | 3 + src/global/actions/api/swap.ts | 102 ++++++++---- src/global/actions/ui/dapps.ts | 6 +- src/global/actions/ui/misc.ts | 11 +- src/global/types.ts | 8 +- src/i18n/de.yaml | 24 +-- src/i18n/en.yaml | 20 +-- src/i18n/es.yaml | 22 +-- src/i18n/pl.yaml | 20 +-- src/i18n/ru.yaml | 24 +-- src/i18n/th.yaml | 24 +-- src/i18n/tr.yaml | 18 +-- src/i18n/uk.yaml | 20 +-- src/i18n/zh-Hans.yaml | 24 +-- src/i18n/zh-Hant.yaml | 24 +-- src/styles/brilliant-icons.css | 145 +++++++++--------- src/styles/brilliant-icons.woff | Bin 10800 -> 10884 bytes src/styles/brilliant-icons.woff2 | Bin 9168 -> 9220 bytes src/util/fee/swapFee.ts | 55 ++++++- src/util/swipeController.ts | 1 + src/util/url.ts | 4 + 51 files changed, 485 insertions(+), 316 deletions(-) create mode 100644 changelogs/3.3.1.txt create mode 100644 src/assets/font-icons/telegram-filled.svg diff --git a/changelogs/3.3.1.txt b/changelogs/3.3.1.txt new file mode 100644 index 00000000..619f4cd5 --- /dev/null +++ b/changelogs/3.3.1.txt @@ -0,0 +1 @@ +Bug fixes and performance improvements diff --git a/package-lock.json b/package-lock.json index 0fce8204..d9f7b743 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mytonwallet", - "version": "3.3.0", + "version": "3.3.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mytonwallet", - "version": "3.3.0", + "version": "3.3.1", "license": "GPL-3.0-or-later", "dependencies": { "@awesome-cordova-plugins/core": "6.9.0", diff --git a/package.json b/package.json index 63b7162f..bf60fe59 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mytonwallet", - "version": "3.3.0", + "version": "3.3.1", "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": { diff --git a/public/version.txt b/public/version.txt index 15a27998..bea438e9 100644 --- a/public/version.txt +++ b/public/version.txt @@ -1 +1 @@ -3.3.0 +3.3.1 diff --git a/src/api/chains/ton/util/metadata.ts b/src/api/chains/ton/util/metadata.ts index eb071746..30537da6 100644 --- a/src/api/chains/ton/util/metadata.ts +++ b/src/api/chains/ton/util/metadata.ts @@ -20,7 +20,12 @@ import type { DnsCategory } from '../constants'; import type { ApiTransactionExtra, JettonMetadata } from '../types'; import { - DEBUG, LIQUID_JETTON, MTW_CARDS_COLLECTION, NFT_FRAGMENT_COLLECTIONS, + DEBUG, + LIQUID_JETTON, + MTW_CARDS_COLLECTION, + NFT_FRAGMENT_COLLECTIONS, + NFT_FRAGMENT_GIFT_IMAGE_TO_URL_REGEX, + NFT_FRAGMENT_GIFT_IMAGE_URL_PREFIX, } from '../../../../config'; import { omitUndefined, pick, range } from '../../../../util/iteratees'; import { logDebugError } from '../../../../util/logs'; @@ -730,10 +735,12 @@ export function buildNft(network: ApiNetwork, rawNft: NftItem): ApiNft | undefin const isScam = hasScamLink || description === 'SCAM' || trust === 'blacklist'; const isHidden = renderType === 'hidden' || isScam; const imageFromPreview = previews!.find((x) => x.resolution === '1500x1500')!.url; + const isFragmentGift = image?.startsWith(NFT_FRAGMENT_GIFT_IMAGE_URL_PREFIX); const metadata = { ...(isWhitelisted && { lottie }), ...(collectionAddress === MTW_CARDS_COLLECTION && buildMtwCardsNftMetadata(rawMetadata)), + ...(isFragmentGift && { fragmentUrl: image!.replace(NFT_FRAGMENT_GIFT_IMAGE_TO_URL_REGEX, 'https://$1') }), }; return omitUndefined({ @@ -750,7 +757,7 @@ export function buildNft(network: ApiNetwork, rawNft: NftItem): ApiNft | undefin ...(collection && { collectionAddress, collectionName: collection.name, - isOnFragment: NFT_FRAGMENT_COLLECTIONS.has(collection.address), + isOnFragment: isFragmentGift || NFT_FRAGMENT_COLLECTIONS.has(collection.address), }), metadata, }); diff --git a/src/api/tonConnect/index.ts b/src/api/tonConnect/index.ts index 5a6badc5..61ba84cc 100644 --- a/src/api/tonConnect/index.ts +++ b/src/api/tonConnect/index.ts @@ -633,7 +633,7 @@ export async function fetchDappMetadata(manifestUrl: string, origin?: string): P const data = await fetchJsonMetadata(manifestUrl); const { url, name, iconUrl } = await data; - const safeIconUrl = iconUrl.startsWith('data:') ? BLANK_GIF_DATA_URL : iconUrl; + const safeIconUrl = (iconUrl.startsWith('data:') || iconUrl === '') ? BLANK_GIF_DATA_URL : iconUrl; if (!isValidUrl(url) || !isValidString(name) || !isValidUrl(safeIconUrl)) { throw new Error('Invalid data'); } diff --git a/src/api/types/misc.ts b/src/api/types/misc.ts index 4e5b03fd..288b7dfa 100644 --- a/src/api/types/misc.ts +++ b/src/api/types/misc.ts @@ -90,6 +90,7 @@ export type ApiMtwCardBorderShineType = 'up' | 'down' | 'left' | 'right' | 'radi export interface ApiNftMetadata { lottie?: string; imageUrl?: string; + fragmentUrl?: string; mtwCardId?: number; mtwCardType?: ApiMtwCardType; mtwCardTextType?: ApiMtwCardTextType; diff --git a/src/assets/font-icons/telegram-filled.svg b/src/assets/font-icons/telegram-filled.svg new file mode 100644 index 00000000..7fac0db0 --- /dev/null +++ b/src/assets/font-icons/telegram-filled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/App.tsx b/src/components/App.tsx index 6b885331..52f8651f 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -2,10 +2,10 @@ import React, { memo, useEffect, useLayoutEffect } from '../lib/teact/teact'; import { getActions, withGlobal } from '../global'; import type { Theme } from '../global/types'; -import { AppState, ContentTab } from '../global/types'; +import { AppState } from '../global/types'; import { INACTIVE_MARKER, IS_ANDROID_DIRECT, IS_CAPACITOR } from '../config'; -import { selectCurrentAccountSettings, selectCurrentAccountState } from '../global/selectors'; +import { selectCurrentAccountSettings } from '../global/selectors'; import { useAccentColor } from '../util/accentColor'; import { setActiveTabChangeListener } from '../util/activeTabMonitor'; import buildClassName from '../util/buildClassName'; @@ -261,14 +261,12 @@ function App({ } export default memo(withGlobal((global): StateProps => { - const { activeContentTab } = selectCurrentAccountState(global) ?? {}; - return { appState: global.appState, accountId: global.currentAccountId, isBackupWalletModalOpen: global.isBackupWalletModalOpen, isHardwareModalOpen: global.isHardwareModalOpen, - isExploreOpen: !global.areSettingsOpen && activeContentTab === ContentTab.Explore, + isExploreOpen: global.isExploreOpen, areSettingsOpen: global.areSettingsOpen, isQrScannerOpen: global.isQrScannerOpen, theme: global.settings.theme, diff --git a/src/components/auth/Auth.module.scss b/src/components/auth/Auth.module.scss index 3a0afeb7..eaef6671 100644 --- a/src/components/auth/Auth.module.scss +++ b/src/components/auth/Auth.module.scss @@ -10,6 +10,12 @@ max-width: 31.4375rem; margin: 0 auto; + + &:global(.Transition_slide-to), + &:global(.Transition_slide-from) { + left: 50%; + transform: translateX(-50%); + } } } diff --git a/src/components/explore/Category.module.scss b/src/components/explore/Category.module.scss index 0ebcb56c..35f89cf0 100644 --- a/src/components/explore/Category.module.scss +++ b/src/components/explore/Category.module.scss @@ -67,7 +67,7 @@ object-fit: contain; } -.scaleable { +.scalable { transition: transform 300ms; &:active { diff --git a/src/components/explore/Category.tsx b/src/components/explore/Category.tsx index 6f2c1d84..8d677f3a 100644 --- a/src/components/explore/Category.tsx +++ b/src/components/explore/Category.tsx @@ -46,7 +46,7 @@ function Category({ category, sites }: OwnProps) { ))} {smallSites.length > 0 && ( -
+
{smallSites.map((site) => ( (''); const [isSearchFocused, markSearchFocused, unmarkSearchFocused] = useFlag(false); const [isSuggestionsVisible, showSuggestions, hideSuggestions] = useFlag(false); - const prevSiteCategoryIdRef = useStateRef(usePrevious2(currentSiteCategoryId)); + const { renderingKey } = useModalTransitionKeys(currentSiteCategoryId || 0, !!isActive); + const prevSiteCategoryIdRef = useStateRef(usePrevious2(renderingKey)); const { handleScroll: handleContentScroll, @@ -99,8 +101,8 @@ function Explore({ } = useScrolledState(); useEffect( - () => (currentSiteCategoryId ? captureEscKeyListener(closeSiteCategory) : undefined), - [closeSiteCategory, currentSiteCategoryId], + () => (renderingKey ? captureEscKeyListener(closeSiteCategory) : undefined), + [closeSiteCategory, renderingKey], ); const filteredSites = useMemo(() => { @@ -143,7 +145,7 @@ function Explore({ }, [filteredSites]); useEffect(() => { - if (!IS_TOUCH_ENV || !filteredSites?.length || !currentSiteCategoryId) { + if (!IS_TOUCH_ENV || !filteredSites?.length) { return undefined; } @@ -153,7 +155,7 @@ function Explore({ openSiteCategory({ id: prevSiteCategoryIdRef.current! }); }, }); - }, [currentSiteCategoryId, filteredSites?.length, prevSiteCategoryIdRef]); + }, [filteredSites?.length, prevSiteCategoryIdRef]); useHorizontalScroll({ containerRef: trendingContainerRef, @@ -242,8 +244,11 @@ function Explore({ stopEvent(e); handleMenuClose(); - openSite(searchValue); - setSearchValue(''); + + if (searchValue.length > 0) { + openSite(searchValue); + setSearchValue(''); + } } function renderSearch() { @@ -256,7 +261,7 @@ function Explore({ placeholder={lang('Search or enter address')} value={searchValue} autoCapitalize="none" - type="url" + inputMode="url" autoCorrect="off" onChange={handleSearchValueChange} onFocus={markSearchFocused} @@ -348,14 +353,14 @@ function Explore({ ); case SLIDES.category: { - const currentSiteCategory = allSites[currentSiteCategoryId!]; + const currentSiteCategory = allSites[renderingKey!]; if (!currentSiteCategory) return undefined; return ( ); @@ -392,7 +397,8 @@ function Explore({ {renderContent} diff --git a/src/components/explore/Site.tsx b/src/components/explore/Site.tsx index 770791ed..32b4ad55 100644 --- a/src/components/explore/Site.tsx +++ b/src/components/explore/Site.tsx @@ -5,7 +5,7 @@ import type { ApiSite } from '../../api/types'; import buildClassName from '../../util/buildClassName'; import { vibrate } from '../../util/capacitor'; import { openUrl } from '../../util/openUrl'; -import { getHostnameFromUrl } from '../../util/url'; +import { getHostnameFromUrl, isTelegramUrl } from '../../util/url'; import Image from '../ui/Image'; @@ -44,11 +44,17 @@ function Site({ >
- {name} + + {name} + + {!isTrending && isTelegramUrl(url) && ( + + )} +
{description}
{badgeText &&
{badgeText}
} diff --git a/src/components/explore/SiteList.module.scss b/src/components/explore/SiteList.module.scss index bc3f3b4f..05d6898a 100644 --- a/src/components/explore/SiteList.module.scss +++ b/src/components/explore/SiteList.module.scss @@ -32,7 +32,7 @@ border-radius: var(--border-radius-default); @include respond-below(xs) { - margin: 1rem 1rem 0; + margin: 0.375rem 1rem 0; @include adapt-margin-to-scrollbar(1rem); } diff --git a/src/components/ledger/LedgerConnect.tsx b/src/components/ledger/LedgerConnect.tsx index 20c49d50..b57b441f 100644 --- a/src/components/ledger/LedgerConnect.tsx +++ b/src/components/ledger/LedgerConnect.tsx @@ -335,7 +335,7 @@ function LedgerConnect({ activeKey={!IS_CAPACITOR ? 0 : (selectedTransport !== 'bluetooth' ? 1 : 2)} name="semiFade" className={buildClassName(styles.iconBlock, IS_CAPACITOR && styles.mobile)} - slideClassName={styles.iconBlockSlide} + slideClassName={isStatic ? styles.iconBlockSlideStatic : styles.iconBlockSlide} > { - setActiveContentTab({ tab: ContentTab.Explore }, { forceOnHeavyAnimation: true }); - }); - - const closeExplore = useLastCallback(() => { - setActiveContentTab({ tab: ContentTab.Assets }, { forceOnHeavyAnimation: true }); - }); - const handleWalletClick = useLastCallback(() => { - closeExplore(); - closeSettings(); + closeExplore(undefined, { forceOnHeavyAnimation: true }); + closeSettings(undefined, { forceOnHeavyAnimation: true }); if (!areAssetsActive && isWalletTabActive) { - selectToken({ slug: undefined }); + selectToken({ slug: undefined }, { forceOnHeavyAnimation: true }); setActiveContentTab({ tab: ContentTab.Assets }, { forceOnHeavyAnimation: true }); } }); const handleExploreClick = useLastCallback(() => { if (isExploreOpen) { - closeSiteCategory(); + closeSiteCategory(undefined, { forceOnHeavyAnimation: true }); } - openExplore(); - closeSettings(); + openExplore(undefined, { forceOnHeavyAnimation: true }); + closeSettings(undefined, { forceOnHeavyAnimation: true }); }); const handleSettingsClick = useLastCallback(() => { openSettings(undefined, { forceOnHeavyAnimation: true }); - closeExplore(); + closeExplore(undefined, { forceOnHeavyAnimation: true }); }); useHistoryBack({ @@ -120,12 +112,12 @@ function BottomBar({ areSettingsOpen, areAssetsActive, isExploreOpen }: StatePro } export default memo(withGlobal((global): StateProps => { - const { areSettingsOpen } = global; + const { areSettingsOpen, isExploreOpen } = global; const { activeContentTab } = selectCurrentAccountState(global) ?? {}; return { areSettingsOpen, areAssetsActive: activeContentTab === ContentTab.Assets, - isExploreOpen: !areSettingsOpen && activeContentTab === ContentTab.Explore, + isExploreOpen, }; })(BottomBar)); diff --git a/src/components/main/sections/Content/Content.module.scss b/src/components/main/sections/Content/Content.module.scss index c5ab455c..ab48daf5 100644 --- a/src/components/main/sections/Content/Content.module.scss +++ b/src/components/main/sections/Content/Content.module.scss @@ -54,6 +54,11 @@ /* stylelint-disable-next-line plugin/whole-pixel */ box-shadow: 0 0.025rem 0 0 var(--color-separator); + + @media (-webkit-max-device-pixel-ratio: 1.3) { + /* stylelint-disable-next-line plugin/whole-pixel */ + box-shadow: 0 0.034375rem 0 0 var(--color-separator); + } } .portraitContainer & { diff --git a/src/components/main/sections/Content/Nft.module.scss b/src/components/main/sections/Content/Nft.module.scss index f71e94de..db0dabae 100644 --- a/src/components/main/sections/Content/Nft.module.scss +++ b/src/components/main/sections/Content/Nft.module.scss @@ -40,6 +40,8 @@ } .emptyListButton { + cursor: var(--custom-cursor, pointer); + display: inline-block; margin: 0 auto; @@ -52,6 +54,7 @@ text-decoration: none; background-color: var(--color-accent-button-background); + border: none; border-radius: var(--border-radius-tiny); transition: background-color 150ms, color 150ms; diff --git a/src/components/main/sections/Content/Nfts.tsx b/src/components/main/sections/Content/Nfts.tsx index cbec67fe..7ac0f56f 100644 --- a/src/components/main/sections/Content/Nfts.tsx +++ b/src/components/main/sections/Content/Nfts.tsx @@ -3,11 +3,14 @@ import { getActions, withGlobal } from '../../../../global'; import type { ApiNft } from '../../../../api/types'; -import { ANIMATED_STICKER_BIG_SIZE_PX, TON_DIAMONDS_URL } from '../../../../config'; +import { ANIMATED_STICKER_BIG_SIZE_PX, TON_DIAMONDS_TITLE, 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 { openUrl } from '../../../../util/openUrl'; +import stopEvent from '../../../../util/stopEvent'; +import { getHostnameFromUrl } from '../../../../util/url'; import { ANIMATED_STICKERS_PATHS } from '../../../ui/helpers/animatedAssets'; import { useDeviceScreen } from '../../../../hooks/useDeviceScreen'; @@ -83,6 +86,12 @@ function Nfts({ isDisabled: !nfts?.length, }); + function handleTonDiamondsClick(e: React.MouseEvent) { + stopEvent(e); + + void openUrl(TON_DIAMONDS_URL, undefined, TON_DIAMONDS_TITLE, getHostnameFromUrl(TON_DIAMONDS_URL)); + } + if (nfts === undefined) { return (
@@ -107,9 +116,9 @@ function Nfts({ {!isNftBuyingDisabled && ( <>

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

- + )}
diff --git a/src/components/mediaViewer/hooks/useNftMenu.ts b/src/components/mediaViewer/hooks/useNftMenu.ts index 7a24030f..0db6cb1d 100644 --- a/src/components/mediaViewer/hooks/useNftMenu.ts +++ b/src/components/mediaViewer/hooks/useNftMenu.ts @@ -179,13 +179,17 @@ export default function useNftMenu({ case 'fragment': { let url: string; - if (nft!.collectionName?.toLowerCase().includes('numbers')) { - url = `https://fragment.com/number/${nft!.name?.replace(/[^0-9]/g, '')}`; + const { collectionName, name, metadata: { fragmentUrl } } = nft!; + + if (fragmentUrl) { + url = fragmentUrl; + } else if (collectionName?.toLowerCase().includes('numbers')) { + url = `https://fragment.com/number/${name?.replace(/[^0-9]/g, '')}`; } else { - url = `https://fragment.com/username/${encodeURIComponent(nft!.name?.substring(1) || '')}`; + url = `https://fragment.com/username/${encodeURIComponent(name?.substring(1) || '')}`; } - openUrl(url); + void openUrl(url); break; } diff --git a/src/components/settings/Settings.module.scss b/src/components/settings/Settings.module.scss index 0d4a9838..5f0ceb8d 100644 --- a/src/components/settings/Settings.module.scss +++ b/src/components/settings/Settings.module.scss @@ -562,6 +562,14 @@ a.item:hover { } } +.dapps { + padding-bottom: max(var(--safe-area-bottom), 1.5rem); + + > .block { + margin-bottom: 0; + } +} + .changePasswordButton { width: 100%; padding: 1rem; diff --git a/src/components/settings/SettingsDapps.tsx b/src/components/settings/SettingsDapps.tsx index 826842cf..82ab2fab 100644 --- a/src/components/settings/SettingsDapps.tsx +++ b/src/components/settings/SettingsDapps.tsx @@ -82,7 +82,7 @@ function SettingsDapps({ const dappList = dapps.map(renderDapp); return ( - <> +
- +
); } diff --git a/src/components/swap/Swap.module.scss b/src/components/swap/Swap.module.scss index 7f5a5027..2f9a421b 100644 --- a/src/components/swap/Swap.module.scss +++ b/src/components/swap/Swap.module.scss @@ -257,6 +257,7 @@ .advancedRow { display: flex; + gap: 0.25rem; justify-content: space-between; } diff --git a/src/components/swap/SwapInitial.tsx b/src/components/swap/SwapInitial.tsx index 2c69bc8c..d5892758 100644 --- a/src/components/swap/SwapInitial.tsx +++ b/src/components/swap/SwapInitial.tsx @@ -145,7 +145,7 @@ function SwapInitial({ () => tokens?.find((token) => token.slug === nativeTokenInSlug), [nativeTokenInSlug, tokens], ); - const nativeBalance = nativeUserTokenIn?.amount ?? 0n; + const nativeTokenInBalance = nativeUserTokenIn?.amount ?? 0n; const amountInBigint = amountIn && tokenIn ? fromDecimal(amountIn, tokenIn.decimals) : undefined; const amountOutBigint = amountOut && tokenOut ? fromDecimal(amountOut, tokenOut.decimals) : undefined; @@ -160,9 +160,9 @@ function SwapInitial({ ourFee, dieselStatus, dieselFee, - nativeTokenInBalance: nativeBalance, + nativeTokenInBalance, }), - [swapType, tokenInSlug, networkFee, realNetworkFee, ourFee, dieselStatus, dieselFee, nativeBalance], + [swapType, tokenInSlug, networkFee, realNetworkFee, ourFee, dieselStatus, dieselFee, nativeTokenInBalance], ); const maxAmount = getMaxSwapAmount({ @@ -181,13 +181,13 @@ function SwapInitial({ fullNetworkFee: explainedFee.fullFee?.networkTerms, ourFeePercent, amountIn, - nativeTokenInBalance: nativeBalance, + nativeTokenInBalance, }); const networkFeeBigint = networkFee !== undefined && nativeUserTokenIn ? fromDecimal(networkFee, nativeUserTokenIn.decimals) : 0n; - const isEnoughNative = nativeBalance >= networkFeeBigint; + const isEnoughNative = nativeTokenInBalance >= networkFeeBigint; const isDieselNotAuthorized = explainedFee.isGasless && dieselStatus === 'not-authorized'; @@ -228,11 +228,7 @@ function SwapInitial({ return; } - estimateSwap({ - shouldBlock, - isEnoughToncoin: isEnoughNative, - toncoinBalance: nativeBalance, - }); + estimateSwap({ shouldBlock }); }); const throttledEstimateSwap = useThrottledCallback( diff --git a/src/components/ui/UpdateAvailable.module.scss b/src/components/ui/UpdateAvailable.module.scss index c1a88cad..4e619a3c 100644 --- a/src/components/ui/UpdateAvailable.module.scss +++ b/src/components/ui/UpdateAvailable.module.scss @@ -2,6 +2,7 @@ cursor: var(--custom-cursor, pointer); position: fixed; + z-index: var(--z-notification); bottom: max(var(--safe-area-bottom), 1rem); left: 50%; transform: translateX(-50%); @@ -32,6 +33,10 @@ background: var(--color-accent-button-background-hover); } + + :global(html.with-bottombar) & { + bottom: calc(var(--bottombar-height) + max(var(--safe-area-bottom), 0px) + 1rem); + } } .icon { diff --git a/src/config.ts b/src/config.ts index d866116c..bad028c0 100644 --- a/src/config.ts +++ b/src/config.ts @@ -117,6 +117,7 @@ export const MTW_CARDS_BASE_URL = 'https://static.mytonwallet.org/cards/'; export const MYTONWALLET_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 TON_DIAMONDS_TITLE = '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'; @@ -206,6 +207,8 @@ export const NFT_FRAGMENT_COLLECTIONS = new Set([ '0:0e41dc1dc3c9067ed24248580e12b3359818d83dee0304fabcf80845eafafdb2', // Anonymous Telegram Numbers '0:80d78a35f955a14b679faa887ff4cd5bfc0f43b4a4eea2a7e6927f3701b273c2', // Telegram Usernames ]); +export const NFT_FRAGMENT_GIFT_IMAGE_URL_PREFIX = 'https://nft.fragment.com/gift/'; +export const NFT_FRAGMENT_GIFT_IMAGE_TO_URL_REGEX = /^https?:\/\/nft\.(fragment\.com\/gift\/[\w-]+-\d+)\.\w+$/i; export const MTW_CARDS_COLLECTION = 'EQCQE2L9hfwx1V8sgmF9keraHx1rNK9VmgR1ctVvINBGykyM'; export const TON_DNS_COLLECTION = 'EQC3dNlesgVD8YbAazcauIrXBPfiVhMMr5YYk2in0Mtsz0Bz'; diff --git a/src/global/actions/api/swap.ts b/src/global/actions/api/swap.ts index 56ca79fc..b4197088 100644 --- a/src/global/actions/api/swap.ts +++ b/src/global/actions/api/swap.ts @@ -5,6 +5,7 @@ import type { ApiSwapActivity, ApiSwapBuildRequest, ApiSwapCexCreateTransactionRequest, + ApiSwapDexLabel, ApiSwapEstimateResponse, ApiSwapEstimateVariant, ApiSwapHistoryItem, @@ -24,7 +25,6 @@ import { } from '../../types'; import { - DEFAULT_FEE, DEFAULT_SWAP_FISRT_TOKEN_SLUG, DEFAULT_SWAP_SECOND_TOKEN_SLUG, IS_CAPACITOR, @@ -33,15 +33,17 @@ import { } from '../../../config'; import { Big } from '../../../lib/big.js'; import { vibrateOnError, vibrateOnSuccess } from '../../../util/capacitor'; +import { findChainConfig, getChainConfig } from '../../../util/chain'; import { fromDecimal, getIsPositiveDecimal, roundDecimal, toDecimal, } from '../../../util/decimals'; +import { canAffordSwapEstimateVariant, shouldSwapBeGasless } from '../../../util/fee/swapFee'; import generateUniqueId from '../../../util/generateUniqueId'; import { buildCollectionByKey, pick } from '../../../util/iteratees'; import { callActionInMain, callActionInNative } from '../../../util/multitab'; import { pause } from '../../../util/schedulers'; import { buildSwapId } from '../../../util/swap/buildSwapId'; -import { getIsTonToken, getNativeToken } from '../../../util/tokens'; +import { getChainBySlug, getIsTonToken, getNativeToken } from '../../../util/tokens'; import { IS_DELEGATED_BOTTOM_SHEET, IS_DELEGATING_BOTTOM_SHEET } from '../../../util/windowEnvironment'; import { callApi } from '../../../api'; import { addActionHandler, getGlobal, setGlobal } from '../..'; @@ -114,10 +116,8 @@ function buildSwapBuildRequest(global: GlobalState): ApiSwapBuildRequest { const fromAmount = amountIn!; const toAmount = amountOut!; const account = selectAccount(global, global.currentAccountId!); - const shouldTryDiesel = networkFee - ? selectCurrentToncoinBalance(global) < (fromDecimal(networkFee) + DEFAULT_FEE) - && global.currentSwap.dieselStatus === 'available' - : undefined; + const nativeTokenIn = findChainConfig(getChainBySlug(tokenIn.slug))?.nativeToken; + const nativeTokenInBalance = nativeTokenIn ? selectCurrentAccountTokenBalance(global, nativeTokenIn.slug) : undefined; return { from, @@ -127,7 +127,7 @@ function buildSwapBuildRequest(global: GlobalState): ApiSwapBuildRequest { toMinAmount: amountOutMin!, slippage, fromAddress: account?.addressByChain[tokenIn.chain as ApiChain] || account?.addressByChain.ton!, - shouldTryDiesel, + shouldTryDiesel: shouldSwapBeGasless({ ...global.currentSwap, nativeTokenInBalance }), dexLabel: currentDexLabel!, networkFee: realNetworkFee ?? networkFee!, swapFee: swapFee!, @@ -644,12 +644,12 @@ addActionHandler('setSlippage', (global, actions, { slippage }) => { }); addActionHandler('estimateSwap', async (global, actions, payload) => { - if (isEstimateSwapBeingExecuted) return; + if (isEstimateSwapBeingExecuted || shouldAvoidEstimation(global)) return; try { isEstimateSwapBeingExecuted = true; - const { shouldBlock, toncoinBalance, isEnoughToncoin } = payload; + const { shouldBlock } = payload; const resetParams = { ...feeResetParams, @@ -698,6 +698,7 @@ addActionHandler('estimateSwap', async (global, actions, payload) => { const tokenIn = global.swapTokenInfo!.bySlug[global.currentSwap.tokenInSlug!]; const tokenOut = global.swapTokenInfo!.bySlug[global.currentSwap.tokenOutSlug!]; + const nativeTokenIn = getChainConfig(getChainBySlug(tokenIn.slug)).nativeToken; const from = tokenIn.slug === TONCOIN.slug ? tokenIn.symbol : tokenIn.tokenAddress!; const to = tokenOut.slug === TONCOIN.slug ? tokenOut.symbol : tokenOut.tokenAddress!; @@ -707,7 +708,8 @@ addActionHandler('estimateSwap', async (global, actions, payload) => { const estimateAmount = global.currentSwap.inputSource === SwapInputSource.In ? { fromAmount } : { toAmount }; - const shouldTryDiesel = isEnoughToncoin === false; + const toncoinBalance = selectCurrentToncoinBalance(global); + const shouldTryDiesel = toncoinBalance < fromDecimal(global.currentSwap.networkFee ?? '0', nativeTokenIn.decimals); const estimate = await callApi('swapEstimate', global.currentAccountId!, { ...estimateAmount, @@ -721,11 +723,11 @@ addActionHandler('estimateSwap', async (global, actions, payload) => { }); global = getGlobal(); + if (shouldAvoidEstimation(global)) return; if (!estimate || 'error' in estimate) { - const errorType = estimate?.error && estimate?.error in SERVER_ERRORS_MAP - ? SERVER_ERRORS_MAP[estimate.error as keyof typeof SERVER_ERRORS_MAP] - : SwapErrorType.UnexpectedError; + const errorType = SERVER_ERRORS_MAP[estimate?.error as keyof typeof SERVER_ERRORS_MAP] + ?? SwapErrorType.UnexpectedError; global = updateCurrentSwap(global, { ...resetParams, @@ -759,24 +761,14 @@ addActionHandler('estimateSwap', async (global, actions, payload) => { : undefined; const estimates = buildSwapEstimates(estimate); - const currentDexLabel = global.currentSwap.currentDexLabel && global.currentSwap.isDexLabelChanged - && estimates.some(({ dexLabel }) => dexLabel === global.currentSwap.currentDexLabel) - ? global.currentSwap.currentDexLabel - : estimate.dexLabel; - const currentEstimate = estimates.find(({ dexLabel }) => dexLabel === currentDexLabel)!; + const currentEstimate = chooseSwapEstimate(global, estimates, estimate.dexLabel); global = updateCurrentSwap(global, { - ...( - global.currentSwap.inputSource === SwapInputSource.In - ? { - amountOut: currentEstimate.toAmount, - ...( - isFromAmountMax - ? { amountIn: currentEstimate.fromAmount } - : undefined - ), - } : { amountIn: currentEstimate.fromAmount } + ...(global.currentSwap.inputSource === SwapInputSource.In + ? { amountOut: currentEstimate.toAmount } + : { amountIn: currentEstimate.fromAmount } ), + ...(isFromAmountMax ? { amountIn: currentEstimate.fromAmount } : undefined), bestRateDexLabel: estimate.dexLabel, amountOutMin: currentEstimate.toMinAmount, priceImpact: currentEstimate.impact, @@ -784,7 +776,7 @@ addActionHandler('estimateSwap', async (global, actions, payload) => { errorType, dieselStatus: estimate.dieselStatus, estimates, - currentDexLabel, + currentDexLabel: currentEstimate.dexLabel, // Fees networkFee: currentEstimate.networkFee, realNetworkFee: currentEstimate.realNetworkFee, @@ -801,7 +793,7 @@ addActionHandler('estimateSwap', async (global, actions, payload) => { }); addActionHandler('estimateSwapCex', async (global, actions, { shouldBlock }) => { - if (isEstimateCexSwapBeingExecuted) return; + if (isEstimateCexSwapBeingExecuted || shouldAvoidEstimation(global)) return; try { isEstimateCexSwapBeingExecuted = true; @@ -866,6 +858,7 @@ addActionHandler('estimateSwapCex', async (global, actions, { shouldBlock }) => }); global = getGlobal(); + if (shouldAvoidEstimation(global)) return; if (!estimate || 'errors' in estimate) { global = updateCurrentSwap(global, { @@ -947,6 +940,7 @@ addActionHandler('estimateSwapCex', async (global, actions, { shouldBlock }) => } global = getGlobal(); + if (shouldAvoidEstimation(global)) return; global = updateCurrentSwap(global, { ...resetParams, @@ -1158,3 +1152,51 @@ function convertTransferFeesToSwapFees( return { networkFee, realNetworkFee }; } + +function shouldAvoidEstimation(global: GlobalState) { + // For a better UX, we should leave the fees and the other swap data intact during swap confirmations (for example, + // to avoid switching from/to gasless mode). + return ( + global.currentSwap.state === SwapState.Blockchain + || global.currentSwap.state === SwapState.Password + ); +} + +function chooseSwapEstimate( + global: GlobalState, + newEstimates: ApiSwapEstimateVariant[], + proposedBestDexLabel: ApiSwapDexLabel, +) { + if (newEstimates.length === 0) { + throw new Error('Unexpected empty `newEstimates` array'); + } + + const { tokenInSlug, currentDexLabel, isDexLabelChanged } = global.currentSwap; + + // If the user has chosen a Dex manually, respect that choice + if (currentDexLabel && isDexLabelChanged) { + const selectedEstimate = newEstimates.find(({ dexLabel }) => dexLabel === currentDexLabel); + if (selectedEstimate) { + return selectedEstimate; + } + } + + // Otherwise, select automatically + const tokenIn = tokenInSlug ? global.swapTokenInfo!.bySlug[tokenInSlug] : undefined; + const tokenInBalance = tokenInSlug ? selectCurrentAccountTokenBalance(global, tokenInSlug) : undefined; + const nativeTokenIn = tokenInSlug ? findChainConfig(getChainBySlug(tokenInSlug))?.nativeToken : undefined; + const nativeTokenInBalance = nativeTokenIn && selectCurrentAccountTokenBalance(global, nativeTokenIn.slug); + let availableEstimates = newEstimates.filter((variant) => canAffordSwapEstimateVariant({ + variant, + tokenIn, + tokenInBalance, + nativeTokenInBalance, + })); + + if (availableEstimates.length === 0) { + availableEstimates = newEstimates; + } + + return availableEstimates.find(({ dexLabel }) => dexLabel === proposedBestDexLabel) + ?? availableEstimates[0]; +} diff --git a/src/global/actions/ui/dapps.ts b/src/global/actions/ui/dapps.ts index 5976c124..772c3f01 100644 --- a/src/global/actions/ui/dapps.ts +++ b/src/global/actions/ui/dapps.ts @@ -99,11 +99,9 @@ addActionHandler('updateDappLastOpenedAt', (global, actions, { origin }) => { }); addActionHandler('openSiteCategory', (global, actions, { id }) => { - global = updateCurrentAccountState(global, { currentSiteCategoryId: id }); - setGlobal(global); + return updateCurrentAccountState(global, { currentSiteCategoryId: id }); }); addActionHandler('closeSiteCategory', (global) => { - global = updateCurrentAccountState(global, { currentSiteCategoryId: undefined }); - setGlobal(global); + return updateCurrentAccountState(global, { currentSiteCategoryId: undefined }); }); diff --git a/src/global/actions/ui/misc.ts b/src/global/actions/ui/misc.ts index b2965922..1a08c5ac 100644 --- a/src/global/actions/ui/misc.ts +++ b/src/global/actions/ui/misc.ts @@ -269,7 +269,8 @@ addActionHandler('changeNetwork', (global, actions, { network }) => { addActionHandler('openSettings', (global) => { global = updateSettings(global, { state: SettingsState.Initial }); - setGlobal({ ...global, areSettingsOpen: true }); + + return { ...global, areSettingsOpen: true }; }); addActionHandler('openSettingsWithState', (global, actions, { state }) => { @@ -831,6 +832,14 @@ addActionHandler('closeAllOverlays', (global, actions) => { actions.closeMediaViewer(); }); +addActionHandler('openExplore', (global) => { + return { ...global, isExploreOpen: true }; +}); + +addActionHandler('closeExplore', (global) => { + return { ...global, isExploreOpen: undefined }; +}); + async function connectLedgerAndGetHardwareState() { const ledgerApi = await import('../../../util/ledger'); let newHardwareState; diff --git a/src/global/types.ts b/src/global/types.ts index b53040db..8da42960 100644 --- a/src/global/types.ts +++ b/src/global/types.ts @@ -150,8 +150,6 @@ export enum SwapState { Blockchain, Password, WaitTokens, - ConnectHardware, - ConfirmHardware, Complete, SelectTokenFrom, SelectTokenTo, @@ -634,6 +632,7 @@ export type GlobalState = { isStakingInfoModalOpen?: boolean; isQrScannerOpen?: boolean; areSettingsOpen?: boolean; + isExploreOpen?: boolean; isAppUpdateAvailable?: boolean; // Force show the "Update MyTonWallet" pop-up on all platforms isAppUpdateRequired?: boolean; @@ -845,6 +844,9 @@ export interface ActionPayloads { }; closeHideNftModal: undefined; + openExplore: undefined; + closeExplore: undefined; + closeAnyModal: undefined; closeAllOverlays: undefined; submitSignature: { password: string }; @@ -994,7 +996,7 @@ export interface ActionPayloads { setSlippage: { slippage: number }; loadSwapPairs: { tokenSlug: string; shouldForceUpdate?: boolean }; clearSwapPairsCache: undefined; - estimateSwap: { shouldBlock: boolean; toncoinBalance: bigint; isEnoughToncoin?: boolean }; + estimateSwap: { shouldBlock: boolean }; setSwapScreen: { state: SwapState }; clearSwapError: undefined; estimateSwapCex: { shouldBlock: boolean }; diff --git a/src/i18n/de.yaml b/src/i18n/de.yaml index 83d591e3..66dc88a0 100644 --- a/src/i18n/de.yaml +++ b/src/i18n/de.yaml @@ -67,7 +67,7 @@ Main menu: Hauptmenü TON Proxy: TON Proxy Toggle TON Proxy: TON Proxy aktivieren/deaktivieren TON Magic: TON Magic -Toggle TON Magic: TON Magic aktivieren/deaktivieren +Toggle TON Magic: TON Magic aktivieren/deaktivieren Open Telegram Web: Telegram Web öffnen. Back Up Secret Words: Geheime Wörter sichern Settings: Einstellungen @@ -173,9 +173,9 @@ $transaction_to: an %address% Wallet is not backed up: Die Wallet ist nicht gesichert. Testnet Version: Testnet Version Error reading clipboard: Fehler beim Lesen der Zwischenablage -$fee_value: "Gebühr %fee%" +$fee_value: Gebühr %fee% $fee_value_with_colon: "Gebühr: %fee%" -Pay fee with %stars_symbol%: "Bezahlen mit %stars_symbol%" +Pay fee with %stars_symbol%: Bezahlen mit %stars_symbol% Loading...: Laden... Recipient Address: Empfänger adresse Wallet address or domain: Wallet adresse oder Domain @@ -247,7 +247,7 @@ Confirm Unstaking: Unstaking bestätigen Request for unstaking is sent!: Die Anfrage zum unstaken wurde gesendet! $unstaking_when_receive: Sie erhalten Ihre unstaked Einzahlung in %time%. $unstake_insufficient_balance: Sie müssen %balance% auf Ihrem Hauptguthaben haben, um mit dem unstaken fortzufahren. -at %annual_yield%: "bei %annual_yield%" +at %annual_yield%: bei %annual_yield% Est. %annual_yield%: Geschätzte %annual_yield% Staked: Gestakt Unstake Requested: Unstaking angefordert @@ -280,7 +280,7 @@ Payload: Payload $many_transactions: "%1$d Transaktionen" Total Amount: Gesamtbetrag Unstaking: Entstaken -"Handle ton:// links": Handle ton:// links +Handle ton:// links: Handle ton:// links Back up wallet to have full access to it: Sichern Sie das Wallet, um vollen Zugriff darauf zu haben Consider More Secure Version: Berücksichtigen Sie eine sicherere Version Install our native app or browser extension.: Installieren Sie unsere native App oder Browser-Erweiterung. @@ -390,7 +390,7 @@ Invalid address format. Only URL Safe Base64 format is allowed.: Ungültiges Adr $auth_backup_description1: | "Dies ist eine **sichere Wallet** und wird nur **von Ihnen kontrolliert**. -$auth_backup_description2: "Und mit großer Macht kommt **große Verantwortung**." +$auth_backup_description2: Und mit großer Macht kommt **große Verantwortung**. $auth_backup_description3: | Sie müssen manuell **Geheimschlüssel sichern**, falls Sie Ihr Passwort vergessen oder den Zugriff auf dieses Gerät verlieren. Swap Placed: Tausch platziert @@ -415,7 +415,7 @@ Your address on another blockchain: Ihre Adresse auf einer anderen Blockchain Please provide an address of your wallet in %blockchain% blockchain to receive bought tokens.: Bitte geben Sie eine Adresse Ihres Wallets in der %blockchain%-Blockchain an, um gekaufte Token zu erhalten. The time for sending coins is over.: Die Zeit zum Senden von Coins ist abgelaufen. You have not sent the coins to the specified address.: Sie haben die Coins nicht an die angegebene Adresse gesendet. -$swap_changelly_to_ton_description1: "Sie müssen %value% an diese Adresse in der %Blockchain%-Blockchain innerhalb von %time% senden." +$swap_changelly_to_ton_description1: Sie müssen %value% an diese Adresse in der %Blockchain%-Blockchain innerhalb von %time% senden. Exchange failed and coins were refunded to your wallet.: Der Austausch ist fehlgeschlagen, und die Coins wurden an Ihre Wallet zurückerstattet. $swap_changelly_kyc_security: "Bitte kontaktieren Sie **%email%** und geben Sie die **Transaktions-ID** an, um das KYC-Verfahren zu bestehen:" Swap Expired: Tausch abgelaufen @@ -516,7 +516,7 @@ Unknown error: Unbekannter Fehler Are you sure you want to disable Face ID?: Sind Sie sicher, dass Sie Face ID deaktivieren möchten? Are you sure you want to disable Touch ID?: Sind Sie sicher, dass Sie Touch ID deaktivieren möchten? Are you sure you want to disable biometrics?: Sind Sie sicher, dass Sie die Biometrie deaktivieren möchten? -Yes: Ja +"Yes": Ja Biometric confirmation failed: Biometrische Bestätigung fehlgeschlagen No Activity: Keine aktivität Add / Buy: Aufladen @@ -538,7 +538,7 @@ You have tokens on other versions of your wallet. You can import them from here. $wallet_switch_version_1: Sie können auch %action%. $wallet_switch_version_2: zu einer anderen Wallet-Version wechseln or import from: oder importieren von -Insufficient fee: "Unzureichende Gebühren" +Insufficient fee: Unzureichende Gebühren $insufficient_fee: "Unzureichende Gebühren: %fee%" Required: Erforderlich Comment is too long.: Der Kommentar ist zu lang. @@ -592,8 +592,8 @@ Successfully: Erfolgreich Unstake More: Mehr abstecken WrongAddress: Der Dapp hat eine Transaktion von einer anderen Wallet angefordert. Are you sure you want to burn this NFT? It will be lost forever.: Sind Sie sicher, dass Sie diese NFT verbrennen wollen? Es wird für immer verloren sein. -$multi_burn_nft_warning: "Sie werden %amount% NFTs verbrennen." -$multi_send_nft_warning: "Der Vorgang kann ~%duration% Minuten dauern. Bitte schließen Sie die App nicht und wechseln Sie nicht das Konto, bis es abgeschlossen ist." +$multi_burn_nft_warning: Sie werden %amount% NFTs verbrennen. +$multi_send_nft_warning: Der Vorgang kann ~%duration% Minuten dauern. Bitte schließen Sie die App nicht und wechseln Sie nicht das Konto, bis es abgeschlossen ist. Burn NFT: NFT brennen Burn: Brennen Private Key: Privater Schlüssel @@ -677,7 +677,7 @@ Switch to W5: Zu W5 wechseln Not Scam: Kein Betrug Untitled: Unbenannt $swap_too_small_amount: Zu kleiner Betrag -Not enough %symbol%: "Nicht genug %symbol%" +Not enough %symbol%: Nicht genug %symbol% $receive_tron_description: Scannen Sie diesen QR-Code oder teilen Sie Ihre Adresse, um Ihr Wallet-Guthaben aufzuladen. You have just created a new multichain wallet: Sie haben gerade eine neue Multichain-Wallet erstellt Now you can transfer tokens from your TON and TRON wallets.: Jetzt können Sie Tokens von Ihren TON- und TRON-Wallets übertragen. diff --git a/src/i18n/en.yaml b/src/i18n/en.yaml index 069f7b98..d0c0d82e 100644 --- a/src/i18n/en.yaml +++ b/src/i18n/en.yaml @@ -173,9 +173,9 @@ $transaction_to: to %address% Wallet is not backed up: Wallet is not backed up Testnet Version: Testnet Version Error reading clipboard: Error reading clipboard -$fee_value: "Fee %fee%" +$fee_value: Fee %fee% $fee_value_with_colon: "Fee: %fee%" -Pay fee with %stars_symbol%: "Pay fee with %stars_symbol%" +Pay fee with %stars_symbol%: Pay fee with %stars_symbol% Loading...: Loading... Recipient Address: Recipient Address Wallet address or domain: Wallet address or domain @@ -238,7 +238,7 @@ Currently Staked: Currently Staked Unstake: Unstake Earning History: Earning History $total: "Total: %value%" -$unstake_asset: "Unstake %symbol%" +$unstake_asset: Unstake %symbol% $unstake_information_with_time: | Your current deposit will be fully sent back to your wallet in %time%. This will stop your earnings. @@ -280,7 +280,7 @@ Payload: Payload $many_transactions: "%1$d transactions" Total Amount: Total Amount Unstaking: Unstaking -"Handle ton:// links": Handle ton:// links +Handle ton:// links: Handle ton:// links Back up wallet to have full access to it: Back up wallet to have full access to it Consider More Secure Version: Consider More Secure Version Install our native app or browser extension.: Install our native app or browser extension. @@ -389,7 +389,7 @@ Invalid address format. Only URL Safe Base64 format is allowed.: Invalid address $auth_backup_description1: | This is a **secure wallet** and is only **controlled by you**. -$auth_backup_description2: "And with great power comes **great responsibility**." +$auth_backup_description2: And with great power comes **great responsibility**. $auth_backup_description3: | You need to manually **back up secret keys** in case you forget your password or lose access to this device. Swap Placed: Swap Placed @@ -414,7 +414,7 @@ Your address on another blockchain: Your address on another blockchain Please provide an address of your wallet in %blockchain% blockchain to receive bought tokens.: Please provide an address of your wallet in %blockchain% blockchain to receive bought tokens. The time for sending coins is over.: The time for sending coins is over. You have not sent the coins to the specified address.: You have not sent the coins to the specified address. -$swap_changelly_to_ton_description1: "Send %value% to this address in %blockchain% blockchain within %time%" +$swap_changelly_to_ton_description1: Send %value% to this address in %blockchain% blockchain within %time% Exchange failed and coins were refunded to your wallet.: Exchange failed and coins were refunded to your wallet. $swap_changelly_kyc_security: "Please contact **%email%** and provide **Transaction ID** to pass the KYC procedure:" Swap Expired: Swap Expired @@ -515,7 +515,7 @@ Unknown error: Unknown error Are you sure you want to disable Face ID?: Are you sure you want to disable Face ID? Are you sure you want to disable Touch ID?: Are you sure you want to disable Touch ID? Are you sure you want to disable biometrics?: Are you sure you want to disable biometrics? -Yes: Yes +"Yes": "Yes" Biometric confirmation failed: Biometric confirmation failed No Activity: No Activity Add / Buy: Add / Buy @@ -591,8 +591,8 @@ WrongAddress: The dapp requested a transaction from another wallet. Are you sure you want to burn this NFT? It will be lost forever.: | Are you sure you want to burn this NFT? It will be lost forever. -$multi_burn_nft_warning: "You are going to burn %amount% NFTs." -$multi_send_nft_warning: "The process may take ~%duration% minute(s). Please do not close the app and do not switch accounts until it is finished." +$multi_burn_nft_warning: You are going to burn %amount% NFTs. +$multi_send_nft_warning: The process may take ~%duration% minute(s). Please do not close the app and do not switch accounts until it is finished. Burn NFT: Burn NFT Burn: Burn Private Key: Private Key @@ -677,7 +677,7 @@ Not Scam: Not Scam Untitled: Untitled Multichain: Multichain $swap_too_small_amount: Too small amount -Not enough %symbol%: "Not enough %symbol%" +Not enough %symbol%: Not enough %symbol% $receive_tron_description: Scan this QR or share your address to top up your wallet balance. You have just created a new multichain wallet: You have just created a new multichain wallet Now you can transfer tokens from your TON and TRON wallets.: Now you can transfer tokens from your TON and TRON wallets. diff --git a/src/i18n/es.yaml b/src/i18n/es.yaml index 9b26695c..9398878f 100644 --- a/src/i18n/es.yaml +++ b/src/i18n/es.yaml @@ -27,7 +27,7 @@ Insecure Password: Contraseña insegura Your have entered an insecure password, which can be easily guessed by scammers.: Ha ingresado una contraseña insegura, que puede ser fácilmente adivinada por los estafadores. Continue or change password to something more secure?: ¿Continuar o cambiar la contraseña a una más segura? Change: Cambiar -"%1$d Secret Words": "Frases Semilla" +"%1$d Secret Words": Frases Semilla Secret Words: Frases Semilla $auth_import_mnemonic_description: | Puedes restaurar el acceso a tu billetera ingresando las **12 o 24 palabras secretas** que anotaste al crear la billetera. @@ -172,9 +172,9 @@ $transaction_to: a %address% Wallet is not backed up: El monedero no está respaldado Testnet Version: Versión Testnet Error reading clipboard: Error al leer el portapapeles -$fee_value: "Comisión %fee%" +$fee_value: Comisión %fee% $fee_value_with_colon: "Comisión: %fee%" -Pay fee with %stars_symbol%: "Pagar con %stars_symbol%" +Pay fee with %stars_symbol%: Pagar con %stars_symbol% Loading...: Cargando... Recipient Address: Dirección del destinatario Wallet address or domain: Dirección o dominio del monedero @@ -238,7 +238,7 @@ Currently Staked: Apostados actualmente Unstake: Retirar Earning History: Historial de ganancias $total: "Total: %value%" -$unstake_asset: "Retirar %symbol%" +$unstake_asset: Retirar %symbol% $unstake_information_with_time: | Su depósito actual será enviado completamente a su monedero en %time%. Esto detendrá sus ganancias. @@ -280,7 +280,7 @@ Payload: Carga útil $many_transactions: "%1$d transacciones" Total Amount: Cantidad total Unstaking: Retirando -"Handle ton:// links": Habilitar enlaces ton:// +Handle ton:// links: Habilitar enlaces ton:// Back up wallet to have full access to it: Haga una copia de seguridad del monedero para tener acceso completo al mismo Consider More Secure Version: Mejore la seguridad del monedero Install our native app or browser extension.: Instala una aplicación nativa o una extensión de navegador. @@ -390,7 +390,7 @@ Invalid address format. Only URL Safe Base64 format is allowed.: Formato de dire $auth_backup_description1: | Este es un **monedero seguro** y **totalmente bajo su control**. -$auth_backup_description2: "Y un gran poder conlleva una **gran responsabilidad**." +$auth_backup_description2: Y un gran poder conlleva una **gran responsabilidad**. $auth_backup_description3: | Debe hacer manualmente una **copia de seguridad de la frase semilla** que le permitirá recuperar su monedero en caso de que olvide su contraseña o pierda el acceso a este dispositivo. Swap Placed: Intercambio Colocado @@ -415,7 +415,7 @@ Your address on another blockchain: Tu dirección en otra blockchain Please provide an address of your wallet in %blockchain% blockchain to receive bought tokens.: Proporcione una dirección de su billetera en %blockchain% blockchain para recibir los tokens comprados. The time for sending coins is over.: El tiempo para enviar monedas ha terminado. You have not sent the coins to the specified address.: Usted no ha enviado las monedas a la dirección especificada. -$swap_changelly_to_ton_description1: "Debe enviar %value% a esta dirección en la cadena de bloques %blockchain% dentro de %time%" +$swap_changelly_to_ton_description1: Debe enviar %value% a esta dirección en la cadena de bloques %blockchain% dentro de %time% Exchange failed and coins were refunded to your wallet.: El intercambio falló y las monedas fueron reembolsadas a su billetera. $swap_changelly_kyc_security: "Comuníquese con **%email%** y proporcione **ID de transacción** para pasar el procedimiento KYC:" Swap Expired: Intercambio vencido @@ -514,7 +514,7 @@ Unknown error: Error desconocido Are you sure you want to disable Face ID?: ¿Estás seguro de que quieres deshabilitar Face ID? Are you sure you want to disable Touch ID?: ¿Estás seguro de que quieres deshabilitar Touch ID? Are you sure you want to disable biometrics?: ¿Estás seguro de que quieres deshabilitar la biometría? -Yes: Sí +"Yes": Sí Biometric confirmation failed: La confirmación biométrica ha fallado No Activity: Sin Actividad Add / Buy: Recargar @@ -590,8 +590,8 @@ Successfully: Exitosamente Unstake More: Retirar más WrongAddress: El dapp solicitó una transacción desde otra billetera. Are you sure you want to burn this NFT? It will be lost forever.: ¿Estás seguro de que quieres quemar este NFT? Se perderá para siempre. -$multi_burn_nft_warning: "Vas a quemar %amount% NFTs." -$multi_send_nft_warning: "El proceso puede tardar ~%duration% minutos. Por favor, no cierres la aplicación y no cambies de cuenta hasta que haya terminado." +$multi_burn_nft_warning: Vas a quemar %amount% NFTs. +$multi_send_nft_warning: El proceso puede tardar ~%duration% minutos. Por favor, no cierres la aplicación y no cambies de cuenta hasta que haya terminado. Burn NFT: Quemar NFT Burn: Quemar Private Key: Clave Privada @@ -675,7 +675,7 @@ Switch to W5: Cambiar a W5 Not Scam: No es una estafa Untitled: Sin título $swap_too_small_amount: Cantidad demasiado pequeña -Not enough %symbol%: "No hay suficiente %symbol%" +Not enough %symbol%: No hay suficiente %symbol% $receive_tron_description: Escanea este código QR o comparte tu dirección para recargar el saldo de tu billetera. You have just created a new multichain wallet: Acabas de crear una nueva billetera multichain Now you can transfer tokens from your TON and TRON wallets.: Ahora puedes transferir tokens desde tus billeteras de TON y TRON. diff --git a/src/i18n/pl.yaml b/src/i18n/pl.yaml index 3d438573..a886327c 100644 --- a/src/i18n/pl.yaml +++ b/src/i18n/pl.yaml @@ -175,9 +175,9 @@ $transaction_to: do %address% Wallet is not backed up: Portfel nie ma kopii zapasowej Testnet Version: Wersja Testnet Error reading clipboard: Błąd odczytu schowka -$fee_value: "Opłata %fee%" +$fee_value: Opłata %fee% $fee_value_with_colon: "Opłata: %fee%" -Pay fee with %stars_symbol%: "Opłać z %stars_symbol%" +Pay fee with %stars_symbol%: Opłać z %stars_symbol% Loading...: Ładowanie... Recipient Address: Adres odbiorcy Wallet address or domain: Adres portfela lub domena @@ -240,7 +240,7 @@ Currently Staked: Obecnie zastawione Unstake: Odzastaw Earning History: Historia zarobków $total: "Suma: %value%" -$unstake_asset: "Odzastaw %symbol%" +$unstake_asset: Odzastaw %symbol% $unstake_information_with_time: | Twoja obecna wpłata zostanie w całości zwrócona na Twoje konto w ciągu %time%. Spowoduje to zatrzymanie zarobków. @@ -282,7 +282,7 @@ Payload: Ładunek $many_transactions: "%1$d transakcji" Total Amount: Całkowita kwota Unstaking: Odzastawianie -"Handle ton:// links": Obsłuż ton:// linki +Handle ton:// links: Obsłuż ton:// linki Back up wallet to have full access to it: Zrób kopię zapasową portfela, aby mieć do niego pełny dostęp. Consider More Secure Version: Rozważ bardziej bezpieczną wersję Install our native app or browser extension.: Zainstaluj naszą natywną aplikację lub rozszerzenie przeglądarki. @@ -391,7 +391,7 @@ Invalid address format. Only URL Safe Base64 format is allowed.: Nieprawidłowy $auth_backup_description1: | To jest bezpieczny portfel i jest kontrolowany tylko przez ciebie. -$auth_backup_description2: "A z wielką mocą idzie wielka odpowiedzialność." +$auth_backup_description2: A z wielką mocą idzie wielka odpowiedzialność. $auth_backup_description3: | Musisz ręcznie zrobić kopię zapasową kluczy prywatnych w przypadku zapomnienia hasła lub utraty dostępu do tego urządzenia. Swap Placed: Wymiana złożona @@ -416,7 +416,7 @@ Your address on another blockchain: Twój adres na innym blockchainie Please provide an address of your wallet in %blockchain% blockchain to receive bought tokens.: Podaj adres swojego portfela w blockchainie %blockchain%, aby otrzymać zakupione tokeny. The time for sending coins is over.: Czas wysyłki monet minął. You have not sent the coins to the specified address.: Nie wysłałeś monet na podany adres. -$swap_changelly_to_ton_description1: "Wyślij %value% na ten adres w blockchainie %blockchain% w ciągu %time%" +$swap_changelly_to_ton_description1: Wyślij %value% na ten adres w blockchainie %blockchain% w ciągu %time% Please contact support and provide a transaction ID.: Skontaktuj się z pomocą techniczną i podaj identyfikator transakcji. Exchange failed and coins were refunded to your wallet.: Wymiana nie powiodła się, a monety zostały zwrócone na twój portfel. Please contact security team to pass the KYC procedure.: Skontaktuj się z zespołem ds. bezpieczeństwa, aby przejść procedurę KYC. @@ -518,7 +518,7 @@ Unknown error: Nieznany błąd Are you sure you want to disable Face ID?: Czy na pewno chcesz wyłączyć Face ID? Are you sure you want to disable Touch ID?: Czy na pewno chcesz wyłączyć Touch ID? Are you sure you want to disable biometrics?: Czy na pewno chcesz wyłączyć biometrię? -Yes: Tak +"Yes": Tak Biometric confirmation failed: Potwierdzenie biometryczne nie powiodło się No Activity: Brak aktywności Add / Buy: Doładować @@ -596,8 +596,8 @@ WrongAddress: Dapp zażądał transakcji z innego portfela. Are you sure you want to burn this NFT? It will be lost forever.: | Czy na pewno chcesz spalić ten NFT? Zostanie on stracony na zawsze. -$multi_burn_nft_warning: "Zamierzasz spalić %amount% NFT." -$multi_send_nft_warning: "Proces może zająć około %duration% minut(y). Proszę nie zamykać aplikacji i nie przełączać kont do czasu zakończenia." +$multi_burn_nft_warning: Zamierzasz spalić %amount% NFT. +$multi_send_nft_warning: Proces może zająć około %duration% minut(y). Proszę nie zamykać aplikacji i nie przełączać kont do czasu zakończenia. Burn NFT: Spal NFT Burn: Spal Private Key: Klucz prywatny @@ -681,7 +681,7 @@ Switch to W5: Przełącz na W5 Not Scam: Nie oszustwo Untitled: Bez tytułu $swap_too_small_amount: Zbyt mała kwota -Not enough %symbol%: "Za mało %symbol%" +Not enough %symbol%: Za mało %symbol% $receive_tron_description: Zeskanuj ten kod QR lub udostępnij swój adres, aby doładować saldo portfela. You have just created a new multichain wallet: Właśnie utworzyłeś nowy portfel multichain Now you can transfer tokens from your TON and TRON wallets.: Teraz możesz przesyłać tokeny ze swoich portfeli TON i TRON. diff --git a/src/i18n/ru.yaml b/src/i18n/ru.yaml index 0972e7fe..76562d45 100644 --- a/src/i18n/ru.yaml +++ b/src/i18n/ru.yaml @@ -28,7 +28,7 @@ Your have entered an insecure password, which can be easily guessed by scammers. Continue or change password to something more secure?: Продолжить или изменить пароль на более надёжный? Change: Изменить "%1$d Secret Words": - manyValue: "%1$d секретных слов" + manyValue: "%1$d секретных слов" fewValue: "%1$d секретных слова" Secret Words: Секретных слов $auth_import_mnemonic_description: | @@ -176,9 +176,9 @@ $transaction_to: на %address% Wallet is not backed up: Резервная копия кошелька не создана Testnet Version: Версия Testnet Error reading clipboard: Ошибка буфера обмена -$fee_value: "Комиссия %fee%" +$fee_value: Комиссия %fee% $fee_value_with_colon: "Комиссия: %fee%" -Pay fee with %stars_symbol%: "Оплатить с %stars_symbol%" +Pay fee with %stars_symbol%: Оплатить с %stars_symbol% Loading...: Загрузка... Recipient Address: Адрес получателя Wallet address or domain: Адрес кошелька или домен @@ -219,7 +219,7 @@ Light: Светлая Dark: Тёмная System: Системная $stake_asset: Стейкинг %symbol% -Earn from your tokens while holding them: "Получайте пассивный доход от хранения %symbol% на надёжном официальном смарт-контракте" +Earn from your tokens while holding them: Получайте пассивный доход от хранения %symbol% на надёжном официальном смарт-контракте Est. %annual_yield%: Доходность %annual_yield% Why this is safe: Почему это безопасно Why is staking safe?: Это точно безопасно? @@ -272,13 +272,13 @@ Connect Dapp: Подключить приложение Select wallet to use on this dapp: Выберите кошелёк для использования с этим приложением Connect: Подключить Dapp Permissions: Разрешения для приложения -$dapp_can_view_balance: "Для %dappname% будет доступен ваш адрес кошелька и баланс." +$dapp_can_view_balance: Для %dappname% будет доступен ваш адрес кошелька и баланс. Send Transaction: Отправить перевод Payload: Служебные данные $many_transactions: "%1$d перевода" Total Amount: Общая сумма Unstaking: Вывод -"Handle ton:// links": Обрабатывать ссылки ton:// +Handle ton:// links: Обрабатывать ссылки ton:// Back up wallet to have full access to it: Сделайте резервную копию кошелька, чтобы иметь к нему полный доступ Consider More Secure Version: Повысьте безопасность кошелька Install our native app or browser extension.: Установите наше приложение или браузерное расширение. @@ -419,7 +419,7 @@ Your address on another blockchain: Ваш адрес в другом блокч Please provide an address of your wallet in %blockchain% blockchain to receive bought tokens.: Пожалуйста, укажите адрес вашего кошелька в блокчейне %blockchain% для получения купленных токенов. The time for sending coins is over.: Время отправки монет истекло. You have not sent the coins to the specified address.: Вы не отправили монеты на указанный адрес. -$swap_changelly_to_ton_description1: "Отправьте %value% на этот адрес в блокчейне %blockchain% в течение %time%" +$swap_changelly_to_ton_description1: Отправьте %value% на этот адрес в блокчейне %blockchain% в течение %time% Exchange failed and coins were refunded to your wallet.: Обмен не удался и монеты были возвращены на ваш кошелёк. $swap_changelly_kyc_security: "Пожалуйста, свяжитесь с командой безопасности по адресу **%email%** и предоставьте идентификатор транзакции, чтобы пройти процедуру KYC:" Swap Expired: Обмен истёк @@ -518,7 +518,7 @@ Unknown error: Неизвестная ошибка Are you sure you want to disable Face ID?: Вы уверены, что хотите отключить Face ID? Are you sure you want to disable Touch ID?: Вы уверены, что хотите отключить Touch ID? Are you sure you want to disable biometrics?: Вы уверены, что хотите отключить биометрию? -Yes: Да +"Yes": Да No Activity: Нет активности Add / Buy: Пополнить Buy with Card: Покупка с карты @@ -591,8 +591,8 @@ Successfully: Успешно Unstake More: Вывести ещё WrongAddress: Приложение запрашивает транзакцию с другого кошелька. Are you sure you want to burn this NFT? It will be lost forever.: Вы уверены, что хотите сжечь этот NFT? Он будет потерян навсегда. -$multi_burn_nft_warning: "Вы собираетесь сжечь %amount% NFT." -$multi_send_nft_warning: "Процесс может занять ~%duration% мин. Пожалуйста, не закрывайте приложение и не переключайтесь на другие аккаунты, пока он не завершится." +$multi_burn_nft_warning: Вы собираетесь сжечь %amount% NFT. +$multi_send_nft_warning: Процесс может занять ~%duration% мин. Пожалуйста, не закрывайте приложение и не переключайтесь на другие аккаунты, пока он не завершится. Burn NFT: Сжечь NFT Burn: Сжечь Private Key: Приватный ключ @@ -676,8 +676,8 @@ Switch to W5: Версия W5 Not Scam: Не скам Untitled: Без названия $swap_too_small_amount: Слишком маленькая сумма -Not enough %symbol%: "Недостаточно %symbol%" -$receive_tron_description: "Отсканируйте QR или поделитесь этим адресом для пополнения вашего кошелька." +Not enough %symbol%: Недостаточно %symbol% +$receive_tron_description: Отсканируйте QR или поделитесь этим адресом для пополнения вашего кошелька. You have just created a new multichain wallet: Вы только что создали новый мультичейн-кошелёк Now you can transfer tokens from your TON and TRON wallets.: Теперь вы можете переводить токены из своих кошельков TON и TRON. Enter Secret Words: Введите секретные слова diff --git a/src/i18n/th.yaml b/src/i18n/th.yaml index c5f60840..0b3e762d 100644 --- a/src/i18n/th.yaml +++ b/src/i18n/th.yaml @@ -173,9 +173,9 @@ $transaction_to: ถึง %address% Wallet is not backed up: วอลเล็ตไม่ได้สำรองข้อมูล Testnet Version: เวอร์ชั้น Testnet Error reading clipboard: อ่านคลิปบอร์ดผิดพลาด -$fee_value: "ค่าธรรมเนียม %fee%" +$fee_value: ค่าธรรมเนียม %fee% $fee_value_with_colon: "ค่าธรรมเนียม: %fee%" -Pay fee with %stars_symbol%: "ชำระด้วย %stars_symbol%" +Pay fee with %stars_symbol%: ชำระด้วย %stars_symbol% Loading...: กำลังโหลด... Recipient Address: ที่อยู่บัญชีผู้รับ Wallet address or domain: ที่อยู่บัญชีวอลเล็ตหรือโดเมน @@ -238,7 +238,7 @@ Currently Staked: ทรัพย์สินที่สเต็กปัจ Unstake: ถอนการสเต็ก Earning History: ประวัติการได้รับ $total: "ทั้งหมด: %value%" -$unstake_asset: "ถอนการสเต็ก %symbol%" +$unstake_asset: ถอนการสเต็ก %symbol% $unstake_information_with_time: | ทรัพย์สินในการสเต็กของคุณจะถูกส่งกลับไปยังวอลเล็ตของคุณเต็มจำนวนใน %time%. การสเต็กของคุณจะหยุดลง. @@ -280,7 +280,7 @@ Payload: เปย์โหลด $many_transactions: "%1$d รายการ" Total Amount: มูลค่าสุทธิ Unstaking: ถอนการสเต็ก -"Handle ton:// links": "รับลิงก์ ton://" +Handle ton:// links: รับลิงก์ ton:// Back up wallet to have full access to it: สำรองวอลเล็ตเพื่อให้เข้าถึงได้อย่างเต็มที่ Consider More Secure Version: พิจารณาเวอร์ชันที่ปลอดภัยยิ่งขึ้น Install our native app or browser extension.: ติดตั้งแอปหรือส่วนขยายเบราว์เซอร์ของเรา. @@ -390,7 +390,7 @@ Invalid address format. Only URL Safe Base64 format is allowed.: รูปแบ $auth_backup_description1: | นี้เป็น **วอลเล็ตที่ปลอดภัย** และเป็น **จัดการด้วยโดยตัวคุณเท่านั้น**. -$auth_backup_description2: "และ พลังอันยิ่งใหญ่มาพร้อมกับ **ความรับผิดชอบที่ใหญ่ยิ่ง**." +$auth_backup_description2: และ พลังอันยิ่งใหญ่มาพร้อมกับ **ความรับผิดชอบที่ใหญ่ยิ่ง**. $auth_backup_description3: | คุณต้อง **สำรองซีเคร็ทคีย์** ด้วยตนเอง ในกรณีที่คุณลืมรหัสผ่านหรือสูญเสียการเข้าถึงอุปกรณ์นี้. Swap Placed: สับเปลี่ยนการวางแล้ว @@ -415,7 +415,7 @@ Your address on another blockchain: ที่อยู่ของคุณบ Please provide an address of your wallet in %blockchain% blockchain to receive bought tokens.: โปรดระบุที่อยู่กระเป๋าเงินของคุณใน %blockchain% blockchain เพื่อรับโทเค็นที่ซื้อ The time for sending coins is over.: เวลาส่งโทเคนหมดลงแล้ว. You have not sent the coins to the specified address.: คุณยังไม่ได้ส่งโทเคนไปยังที่อยู่ที่กำหนดไว้. -$swap_changelly_to_ton_description1: "ส่ง %value% ไปยังที่อยู่นี้ใน %blockchain% บล็อกเชนภายใน %time%" +$swap_changelly_to_ton_description1: ส่ง %value% ไปยังที่อยู่นี้ใน %blockchain% บล็อกเชนภายใน %time% Exchange failed and coins were refunded to your wallet.: การแลกเปลี่ยนไม่สำเร็จและโทเคนถูกคืนเงินไปยังวอลเล็ตของคุณ. $swap_changelly_kyc_security: "โปรดติดต่อ **%email%** และระบุ **รหัสธุรกรรม** เพื่อผ่านขั้นตอน KYC:" Swap Expired: การสับเปลี่ยนได้หมดอายุ @@ -448,7 +448,7 @@ Copy Logs: คัดลอกบันทึก Logs were copied!: บันทึกถูกคัดลอกแล้ว! Biometric setup failed.: การตั้งค่าความปลอดภัยด้วย Biometric ล้มเหลว. Biometric confirmation failed.: การยืนยันด้วย Biometric ล้มเหลว. -Failed to disable biometrics.: การปิดการใช้งาน Biometrics ล้มเหลว. +Failed to disable biometrics.: การปิดการใช้งาน Biometrics ล้มเหลว. Biometric Confirmation: การยืนยันด้วย Biometric Please verify the operation.: โปรดยืนยันการทำรายการ. Create Password: สร้างรหัสผ่าน @@ -495,7 +495,7 @@ Not Now: ไม่ตอนนี้ Touch ID: Touch ID Face ID: Face ID Turn Off Touch ID: ปิดการใช้งาน Touch ID -Turn Off Face ID: ปิดการใช้งาน Face ID +Turn Off Face ID: ปิดการใช้งาน Face ID Turn Off Biometrics: ปิดการใช้งาน Biometrics Enter code: กรอกรหัสผ่าน Enter code or use Face ID: กรอกรหัสผ่านหรือใช้ Face ID @@ -503,7 +503,7 @@ Enter code or use Touch ID: กรอกรหัสผ่านหรือใ Enter code or use biometrics: กรอกรหัสผ่านหรือใช้ Biometrics Wrong code, please try again: รหัสผ่านไม่ถูกต้อง, โปรดลองใหม่อีกครั้ง Scan your fingerprint: สแกนลายนิ้วมือของคุณ -Incorrect code, please try again.: รหัสผ่านไม่ถูกต้อง, โปรดลองใหม่อีกครั้ง. +Incorrect code, please try again.: รหัสผ่านไม่ถูกต้อง, โปรดลองใหม่อีกครั้ง. Correct: ถูกต้อง Confirm Action: ยืนยันการดำเนินการ Confirm Swap: ยืนยันการสับเปลี่ยน @@ -516,7 +516,7 @@ Unknown error: ข้อผิดพลาดที่ไม่รู้จั Are you sure you want to disable Face ID?: คุณแน่ใจหรือไม่ว่าจะปิดใช้งาน Face ID? Are you sure you want to disable Touch ID?: คุณแน่ใจหรือไม่ว่าจะปิดใช้งาน Touch ID? Are you sure you want to disable biometrics?: คุณแน่ใจหรือไม่ว่าจะปิดใช้งาน Biometrics? -Yes: ใช่ +"Yes": ใช่ Biometric confirmation failed: การยืนยันข้อมูลชีวภาพล้มเหลว No Activity: ไม่มีกิจกรรม Add / Buy: เพิ่ม / ซื้อ @@ -594,8 +594,8 @@ WrongAddress: Dapp ร้องขอธุรกรรมจากกระเ Are you sure you want to burn this NFT? It will be lost forever.: | คุณแน่ใจหรือไม่ว่าต้องการเบิร์น NFT นี้? มันจะสูญสลายไปตลอดกาล. -$multi_burn_nft_warning: "คุณกำลังเบิร์นจำนวน %amount% NFTs." -$multi_send_nft_warning: "กระบวนการนี้อาจใช้เวลา ~%duration% นาที โปรดอย่าปิดแอปและอย่าเปลี่ยนบัญชีจนกว่าจะเสร็จสิ้น." +$multi_burn_nft_warning: คุณกำลังเบิร์นจำนวน %amount% NFTs. +$multi_send_nft_warning: กระบวนการนี้อาจใช้เวลา ~%duration% นาที โปรดอย่าปิดแอปและอย่าเปลี่ยนบัญชีจนกว่าจะเสร็จสิ้น. Burn NFT: เบิร์น NFT Burn: เบิร์น Private Key: ไพรเวท คีย์ diff --git a/src/i18n/tr.yaml b/src/i18n/tr.yaml index 527b9884..a61453b4 100644 --- a/src/i18n/tr.yaml +++ b/src/i18n/tr.yaml @@ -168,12 +168,12 @@ $nft_explore_offer: | Open TON Diamonds: TON Diamonds'i aç Received: Alındı Sent: Gönder -$transaction_from: "bu adresten = %address%" -$transaction_to: "bu adrese = %address%" +$transaction_from: bu adresten = %address% +$transaction_to: bu adrese = %address% Wallet is not backed up: Cüzdan yedeklenmemiş Testnet Version: Testnet Sürümü Error reading clipboard: Pano okunurken hata oluştu -$fee_value: "Ücret %fee%" +$fee_value: Ücret %fee% $fee_value_with_colon: "Ücret: %fee%" Pay fee with %stars_symbol%: "%stars_symbol% ile öde" Loading...: Yükleniyor... @@ -280,7 +280,7 @@ Payload: Payload $many_transactions: "%1$d işlem" Total Amount: Toplam tutar Unstaking: Unstaking gerçekleşiyor -"Handle ton:// links": ton uzantılı isimler:// link'ler +Handle ton:// links: ton uzantılı isimler:// link'ler Back up wallet to have full access to it: Tam erişime sahip olmak için cüzdanı yedekleyin Consider More Secure Version: Daha güvenli sürümü kullanmayı düşünün Install our native app or browser extension.: Yerel uygulamamızı veya tarayıcı uzantımızı yükleyin. @@ -389,7 +389,7 @@ Invalid address format. Only URL Safe Base64 format is allowed.: Geçersiz adres $auth_backup_description1: | Bu bir **güvenli cüzdandır** ve sadece **sizin tarafınızdan kontrol edilir**. -$auth_backup_description2: "Ve büyük güç **büyük sorumluluğu** da beraberinde getirir." +$auth_backup_description2: Ve büyük güç **büyük sorumluluğu** da beraberinde getirir. $auth_backup_description3: | Parolanızı unutmanız veya bu cihaza erişiminizi kaybetmeniz ihtimaline karşı **gizli anahtarları** manuel olarak **yedeklemeniz** gerekir. Swap Placed: Takas emri gönderildi @@ -515,7 +515,7 @@ Unknown error: Bilinmeyen hata Are you sure you want to disable Face ID?: Face ID'yi devre dışı bırakmak istediğinizden emin misiniz? Are you sure you want to disable Touch ID?: Touch ID'yi devre dışı bırakmak istediğinizden emin misiniz? Are you sure you want to disable biometrics?: Biyometrik korumayı devre dışı bırakmak istediğinizden emin misiniz? -Yes: Evet +"Yes": Evet Biometric confirmation failed: Biyometrik doğrulama başarısız oldu No Activity: Etkinlik yok Add / Buy: Yükleme @@ -556,7 +556,7 @@ $ledger_not_supported_operation: Bu işlem, kullandığınız Ledger TON App sü $ledger_unsupported_ton_connect: TonConnect, Ledger Ton uygulamanızın sürümü tarafından desteklenmez. Lütfen Ledger Live kullanarak güncelleyin. $dapp_transfer_tokens_burn: "%amount% yakılıyor" $dapp_dns_set_wallet_payload: "%domain% alanının bağlı cüzdanını %address% olarak değiştirme" -$dapp_dns_delete_wallet_payload: "Deleting linked wallet of domain %domain%" +$dapp_dns_delete_wallet_payload: Deleting linked wallet of domain %domain% $dapp_dns_change_record_payload: "%domain% alanının \"%category%\" kaydı %value% olarak değiştiriliyor" $dapp_dns_delete_record_payload: "%domain% alan adının \"%category%\" kaydı siliniyor" $dapp_token_bridge_pay_swap_payload: Zincirler arası köprü aracılığıyla değişim onayı @@ -592,7 +592,7 @@ Unstake More: Unstake daha fazla WrongAddress: Dapp başka bir cüzdandan bir işlem talep etti. Are you sure you want to burn this NFT? It will be lost forever.: Bu NFT'yi yakmak istediğinizden emin misiniz? Sonsuza kadar kaybolacak. $multi_burn_nft_warning: "%amount% NFT yakacaksınız." -$multi_send_nft_warning: "İşlem ~%duration% dakika sürebilir. Lütfen işlem tamamlanana kadar uygulamayı kapatmayın ve hesap değiştirmeyin." +$multi_send_nft_warning: İşlem ~%duration% dakika sürebilir. Lütfen işlem tamamlanana kadar uygulamayı kapatmayın ve hesap değiştirmeyin. Burn NFT: NFT'yi yaz Burn: Yakmak Private Key: Gizli anahtar @@ -676,7 +676,7 @@ Switch to W5: W5'e Geç Not Scam: Dolandırıcılık Değil Untitled: Başlıksız $swap_too_small_amount: Çok küçük miktar -Not enough %symbol%: "Yeterli %symbol% yok" +Not enough %symbol%: Yeterli %symbol% yok $receive_tron_description: Cüzdan bakiyenizi artırmak için bu QR'yi tarayın veya adresinizi paylaşın. You have just created a new multichain wallet: Yeni bir çok zincirli cüzdan oluşturdunuz Now you can transfer tokens from your TON and TRON wallets.: Artık TON ve TRON cüzdanlarınızdan token transferi yapabilirsiniz. diff --git a/src/i18n/uk.yaml b/src/i18n/uk.yaml index 84fd8149..8b929060 100644 --- a/src/i18n/uk.yaml +++ b/src/i18n/uk.yaml @@ -177,9 +177,9 @@ $transaction_to: на %address% Wallet is not backed up: Резервну копію гаманця не створено Testnet Version: Версія Testnet Error reading clipboard: Помилка буфера обміну -$fee_value: "Комісія %fee%" +$fee_value: Комісія %fee% $fee_value_with_colon: "Комісія: %fee%" -Pay fee with %stars_symbol%: "Оплатити з %stars_symbol%" +Pay fee with %stars_symbol%: Оплатити з %stars_symbol% Loading...: Завантаження... Recipient Address: Адреса одержувача Wallet address or domain: Адреса гаманця або домен @@ -220,7 +220,7 @@ Light: Світла Dark: Темна System: Системна $stake_asset: Стейкінг %symbol% -Earn from your tokens while holding them: "Отримуйте пасивний дохід від зберігання %symbol% на надійному офіційному смарт-контракті" +Earn from your tokens while holding them: Отримуйте пасивний дохід від зберігання %symbol% на надійному офіційному смарт-контракті Why this is safe: Чому це безпечно Why is staking safe?: Це точно безпечно? $safe_staking_description1: Стейкінг **повністю децентралізований** і управляється **офіційними смарт-контрактами** TON Liquid Staking. @@ -273,13 +273,13 @@ Connect Dapp: Підключити додаток Select wallet to use on this dapp: Виберіть гаманець для використання в цій програмі Connect: Підключити Dapp Permissions: Дозволи для програми -$dapp_can_view_balance: "Для %dappname% буде доступна ваша адреса гаманця і баланс." +$dapp_can_view_balance: Для %dappname% буде доступна ваша адреса гаманця і баланс. Send Transaction: Надіслати переказ Payload: Службові дані $many_transactions: "%1$d переказу" Total Amount: Загальна сума Unstaking: Зняти -"Handle ton:// links": Обробляти посилання ton:// +Handle ton:// links: Обробляти посилання ton:// Back up wallet to have full access to it: Зробіть резервну копію гаманця, щоб мати до нього повний доступ Consider More Secure Version: Підвищіть безпеку гаманця Install our native app or browser extension.: Встановіть наш додаток або браузерне розширення. @@ -420,7 +420,7 @@ Your address on another blockchain: Ваша адреса в іншому бло Please provide an address of your wallet in %blockchain% blockchain to receive bought tokens.: Будь ласка, вкажіть адресу вашого гаманця в блокчейні %blockchain% для отримання куплених токенів. The time for sending coins is over.: Час відправлення монет минув. You have not sent the coins to the specified address.: Ви не відправили монети на вказану адресу. -$swap_changelly_to_ton_description1: "Надішліть %value% на цю адресу в блокчейні %blockchain% протягом %time%" +$swap_changelly_to_ton_description1: Надішліть %value% на цю адресу в блокчейні %blockchain% протягом %time% Please contact support and provide a transaction ID.: Будь ласка, зв'яжіться з підтримкою та надайте ідентифікатор транзакції. Exchange failed and coins were refunded to your wallet.: Обмін не вдався і монети були повернуті на ваш гаманець. Please contact security team to pass the KYC procedure.: Будь ласка, зв'яжіться з командою безпеки, щоб пройти процедуру KYC. @@ -520,7 +520,7 @@ Unknown error: Невідома помилка Are you sure you want to disable Face ID?: Ви впевнені, що хочете відключити Face ID? Are you sure you want to disable Touch ID?: Ви впевнені, що хочете відключити Touch ID? Are you sure you want to disable biometrics?: Ви впевнені, що хочете відключити біометрію? -Yes: Так +"Yes": Так Biometric confirmation failed: Біометричне підтвердження не вдалося No Activity: Немає активності Add / Buy: Поповнити @@ -596,8 +596,8 @@ Successfully: Успішно Unstake More: Вивести ще WrongAddress: Dapp запитав транзакцію з іншого гаманця. Are you sure you want to burn this NFT? It will be lost forever.: Ви впевнені, що хочете спалити цей NFT? Його буде втрачено назавжди. -$multi_burn_nft_warning: "Ви збираєтеся спалити %amount% NFT." -$multi_send_nft_warning: "Процес може зайняти ~%duration% хв. Будь ласка, не закривайте додаток і не перемикайтеся на інші акаунти, поки він не завершиться." +$multi_burn_nft_warning: Ви збираєтеся спалити %amount% NFT. +$multi_send_nft_warning: Процес може зайняти ~%duration% хв. Будь ласка, не закривайте додаток і не перемикайтеся на інші акаунти, поки він не завершиться. Burn NFT: Спалити NFT Burn: Спалити Private Key: Приватний ключ @@ -681,7 +681,7 @@ Switch to W5: Версія W5 Not Scam: Не шахрайство Untitled: Без назви $swap_too_small_amount: Занадто мала сума -Not enough %symbol%: "Недостатньо %symbol%" +Not enough %symbol%: Недостатньо %symbol% $receive_tron_description: Відскануйте цей QR-код або поділіться своєю адресою, щоб поповнити баланс гаманця. You have just created a new multichain wallet: Ви щойно створили новий мультичейн-гаманець Now you can transfer tokens from your TON and TRON wallets.: Тепер ви можете передавати токени з ваших гаманців TON і TRON. diff --git a/src/i18n/zh-Hans.yaml b/src/i18n/zh-Hans.yaml index ca4f803d..7035c12a 100644 --- a/src/i18n/zh-Hans.yaml +++ b/src/i18n/zh-Hans.yaml @@ -169,9 +169,9 @@ $transaction_to: 至 %address% Wallet is not backed up: 钱包未备份 Testnet Version: 测试网版本 Error reading clipboard: 读取剪切板时出现错误 -$fee_value: "手续费 %fee%" +$fee_value: 手续费 %fee% $fee_value_with_colon: "手续费: %fee%" -Pay fee with %stars_symbol%: "使用 %stars_symbol% 支付" +Pay fee with %stars_symbol%: 使用 %stars_symbol% 支付 Loading...: 读取中... Recipient Address: 收款人地址 Wallet address or domain: 钱包地址或域名 @@ -235,7 +235,7 @@ Currently Staked: 当前质押 Unstake: 解除质押 Earning History: 质押奖励历史 $total: "总计: %value%" -$unstake_asset: "解除 %symbol% 质押" +$unstake_asset: 解除 %symbol% 质押 $unstake_information_with_time: | 您当前的质押存款将在 %time% 后存入您的钱包 质押奖励将会停止。 @@ -272,7 +272,7 @@ Payload: 有效载荷 $many_transactions: "%1$d 笔交易" Total Amount: 总金额 Unstaking: 解除质押 -"Handle ton:// links": 处理 ton:// 链接 +Handle ton:// links: 处理 ton:// 链接 Back up wallet to have full access to it: 备份钱包以完全访问它 Consider More Secure Version: 提高钱包安全性 Install our native app or browser extension.: 通过安装浏览器扩展程序或本机应用程序 @@ -406,9 +406,9 @@ Your address on another blockchain: 您在另一个区块链上的地址 Please provide an address of your wallet in %blockchain% blockchain to receive bought tokens.: 请提供您在%blockchain%区块链中的钱包地址,以接收购买的代币。 The time for sending coins is over.: 发送硬币的时间已结束。 You have not sent the coins to the specified address.: 您尚未将硬币发送到指定地址。 -$swap_changelly_to_ton_description1: "您必须在 %time% 内将 %value% 发送到此地址 在 %blockchain% 区块链中" +$swap_changelly_to_ton_description1: 您必须在 %time% 内将 %value% 发送到此地址 在 %blockchain% 区块链中 Exchange failed and coins were refunded to your wallet.: 交换失败,硬币已退还到您的钱包。 -$swap_changelly_kyc_security: "请联系**%email%**并提供**交易ID**以通过KYC程序:" +$swap_changelly_kyc_security: 请联系**%email%**并提供**交易ID**以通过KYC程序: Swap Expired: 交换已过期 Swap On Hold: 交换暂停 Swap Refunded: 交换已退款 @@ -419,7 +419,7 @@ $swap_changelly_terms_of_use: 使用条款 $swap_changelly_privacy_policy: 隐私政策 Password must contain %length% digits.: 密码必须包含%length%位数字。 Deposit Link: 充值链接 -$swap_changelly_from_ton_description: "代币将很快发送到您在%blockchain%区块链中的地址:" +$swap_changelly_from_ton_description: 代币将很快发送到您在%blockchain%区块链中的地址: Please note that it may take up to a few hours for tokens to appear in your wallet.: 请注意,代币显示在您的钱包中可能需要几个小时。 Minimum amount: 最低 %value% Maximum amount: 最高 %value% @@ -505,7 +505,7 @@ Unknown error: 未知错误 Are you sure you want to disable Face ID?: 您确定要禁用Face ID吗? Are you sure you want to disable Touch ID?: 您确定要禁用Touch ID吗? Are you sure you want to disable biometrics?: 您确定要禁用生物识别技术吗? -Yes: 是的 +"Yes": 是的 Biometric confirmation failed: 生物识别确认失败 No Activity: 无活动 Add / Buy: 添加 / 购买 @@ -580,15 +580,15 @@ Successfully: 成功地 Unstake More: 解除质押更多 WrongAddress: 该 dapp 请求另一个钱包进行交易。 Are you sure you want to burn this NFT? It will be lost forever.: 您确定要烧毁这个 NFT 吗? 它将永远失去。 -$multi_burn_nft_warning: "您即将销毁 %amount% 个 NFT。" -$multi_send_nft_warning: "该过程可能需要 ~%duration% 分钟。请勿关闭应用程序,也不要在完成之前切换账户。" +$multi_burn_nft_warning: 您即将销毁 %amount% 个 NFT。 +$multi_send_nft_warning: 该过程可能需要 ~%duration% 分钟。请勿关闭应用程序,也不要在完成之前切换账户。 Burn NFT: 烧毁NFT Burn: 烧伤 Private Key: 私钥 "%amount% NFTs": "%amount% NFT" 1 NFT: 1 NFT 1 NFT Selected: 已选择 1 个 NFT -"%amount% NFTs Selected": "已选择 %amount% 个 NFT" +"%amount% NFTs Selected": 已选择 %amount% 个 NFT For sale. Cannot be sent and burned: 出售。 无法发送和烧毁 Select: 选择 Send All: 全部发送 @@ -596,7 +596,7 @@ Burn All: 全部烧掉 Select All: 全选 Collection: 集合 Transaction ID was copied!: 交易ID已被复制! -$swap_changelly_support: "如果有任何问题,请联系%livechat%或%email%并提供**交易ID**:" +$swap_changelly_support: 如果有任何问题,请联系%livechat%或%email%并提供**交易ID**: Changelly Live Chat: Changelly 实时聊天 Your %blockchain% Address: 您的%blockchain% 地址 Vesting: 归属 diff --git a/src/i18n/zh-Hant.yaml b/src/i18n/zh-Hant.yaml index 7020c18d..621999d9 100644 --- a/src/i18n/zh-Hant.yaml +++ b/src/i18n/zh-Hant.yaml @@ -169,9 +169,9 @@ $transaction_to: 到 %address% Wallet is not backed up: 錢包未備份 Testnet Version: 測試網版本 Error reading clipboard: 讀取剪貼板時出現錯誤 -$fee_value: "手續費 %fee%" +$fee_value: 手續費 %fee% $fee_value_with_colon: "手續費: %fee%" -Pay fee with %stars_symbol%: "使用 %stars_symbol% 支付" +Pay fee with %stars_symbol%: 使用 %stars_symbol% 支付 Loading...: 讀取中... Recipient Address: 接收人地址 Wallet address or domain: 錢包地址或是域名 @@ -235,7 +235,7 @@ Currently Staked: 目前質押數量 Unstake: 解除質押 Earning History: 收益紀錄 $total: "總額: %value%" -$unstake_asset: "解除 %symbol% 質押" +$unstake_asset: 解除 %symbol% 質押 $unstake_information_with_time: | 你的存款將在 %time% 後全數退還到你的錢包。 解除後將不再獲得質押收益。 @@ -272,7 +272,7 @@ Payload: 有效載荷 $many_transactions: "%1$d筆交易" Total Amount: 總金額 Unstaking: 解除質押 -"Handle ton:// links": 處理 ton:// 鏈接 +Handle ton:// links: 處理 ton:// 鏈接 Back up wallet to have full access to it: 備份錢包以完全訪問它 Consider More Secure Version: 提高錢包安全性 Install our native app or browser extension.: 通過安裝瀏覽器擴展程序或本機應用程序 @@ -406,9 +406,9 @@ Your address on another blockchain: 您在另一個區塊鏈上的地址 Please provide an address of your wallet in %blockchain% blockchain to receive bought tokens.: 請提供您在%blockchain%區塊鏈中的錢包地址,以接收購買的代幣。 The time for sending coins is over.: 發送硬幣的時間已結束。 You have not sent the coins to the specified address.: 您尚未將硬幣發送到指定地址。 -$swap_changelly_to_ton_description1: "您必須在 %time% 內將 %value% 發送到此地址 在 %blockchain% 區塊鏈中" +$swap_changelly_to_ton_description1: 您必須在 %time% 內將 %value% 發送到此地址 在 %blockchain% 區塊鏈中 Exchange failed and coins were refunded to your wallet.: 交換失敗,硬幣已退還到您的錢包。 -$swap_changelly_kyc_security: "請聯絡**%email%**並提供**交易ID**以通過KYC程序:" +$swap_changelly_kyc_security: 請聯絡**%email%**並提供**交易ID**以通過KYC程序: Swap Expired: 交換過期 Swap On Hold: 交換暫停 Swap Refunded: 交換退款 @@ -419,7 +419,7 @@ $swap_changelly_terms_of_use: 使用條款 $swap_changelly_privacy_policy: 隱私政策 Password must contain %length% digits.: 密碼必須包含%length%位數字。 Deposit Link: 儲值連結 -$swap_changelly_from_ton_description: "代幣將很快發送到您在%blockchain%區塊鏈中的地址:" +$swap_changelly_from_ton_description: 代幣將很快發送到您在%blockchain%區塊鏈中的地址: Please note that it may take up to a few hours for tokens to appear in your wallet.: 請注意,代幣顯示在您的錢包中可能需要幾個小時。 Minimum amount: 最低 %value% Maximum amount: 最高 %value% @@ -505,7 +505,7 @@ Unknown error: 未知錯誤 Are you sure you want to disable Face ID?: 您確定要禁用Face ID嗎? Are you sure you want to disable Touch ID?: 您確定要禁用Touch ID嗎? Are you sure you want to disable biometrics?: 您確定要禁用生物識別技術嗎? -Yes: 是的 +"Yes": 是的 Biometric confirmation failed: 生物辨識確認失敗 No Activity: 無活動 Add / Buy: 添加 / 購買 @@ -580,15 +580,15 @@ Successfully: 成功地 Unstake More: 解除質押更多 WrongAddress: 該 dapp 請求另一個錢包進行交易。 Are you sure you want to burn this NFT? It will be lost forever.: 您確定要燒掉這個 NFT 嗎? 它將永遠失去。 -$multi_burn_nft_warning: "您即將銷毀 %amount% 個 NFT。" -$multi_send_nft_warning: "該過程可能需要 ~%duration% 分鐘。請勿關閉應用程式,也不要在完成之前切換賬戶。" +$multi_burn_nft_warning: 您即將銷毀 %amount% 個 NFT。 +$multi_send_nft_warning: 該過程可能需要 ~%duration% 分鐘。請勿關閉應用程式,也不要在完成之前切換賬戶。 Burn NFT: 燒毀NFT Burn: 燒傷 Private Key: 私鑰 "%amount% NFTs": "%amount% NFT" 1 NFT: 1 NFT 1 NFT Selected: 已選擇 1 個 NFT -"%amount% NFTs Selected": "已選擇 %amount% 個 NFT" +"%amount% NFTs Selected": 已選擇 %amount% 個 NFT For sale. Cannot be sent and burned: 出售。 無法發送和燒毀 Select: 選擇 Send All: 全部發送 @@ -596,7 +596,7 @@ Burn All: 全部燒掉 Select All: 全選 Collection: 集合 Transaction ID was copied!: 交易ID已被複製! -$swap_changelly_support: "如果有任何問題,請聯絡%livechat%或%email%並提供**交易ID**:" +$swap_changelly_support: 如果有任何問題,請聯絡%livechat%或%email%並提供**交易ID**: Changelly Live Chat: Changelly 即時聊天 Your %blockchain% Address: 您的%blockchain% 地址 Vesting: 歸屬 diff --git a/src/styles/brilliant-icons.css b/src/styles/brilliant-icons.css index b2ef5a8a..8a64a9b6 100644 --- a/src/styles/brilliant-icons.css +++ b/src/styles/brilliant-icons.css @@ -1,7 +1,7 @@ @font-face { font-family: "brilliant-icons"; - src: url("./brilliant-icons.woff?130ea017c9faa89f13a327e92bead72d") format("woff"), -url("./brilliant-icons.woff2?130ea017c9faa89f13a327e92bead72d") format("woff2"); + src: url("./brilliant-icons.woff?a573f60acdc9a6769f2227665a384716") format("woff"), +url("./brilliant-icons.woff2?a573f60acdc9a6769f2227665a384716") format("woff2"); font-weight: normal; font-style: normal; } @@ -56,210 +56,213 @@ url("./brilliant-icons.woff2?130ea017c9faa89f13a327e92bead72d") format("woff2"); .icon-telegram::before { content: "\f10e"; } -.icon-swap::before { +.icon-telegram-filled::before { content: "\f10f"; } -.icon-star::before { +.icon-swap::before { content: "\f110"; } -.icon-star-filled::before { +.icon-star::before { content: "\f111"; } -.icon-spinner::before { +.icon-star-filled::before { content: "\f112"; } -.icon-sort::before { +.icon-spinner::before { content: "\f113"; } -.icon-snow::before { +.icon-sort::before { content: "\f114"; } -.icon-share::before { +.icon-snow::before { content: "\f115"; } -.icon-settings::before { +.icon-share::before { content: "\f116"; } -.icon-send::before { +.icon-settings::before { content: "\f117"; } -.icon-send-small::before { +.icon-send::before { content: "\f118"; } -.icon-send-alt::before { +.icon-send-small::before { content: "\f119"; } -.icon-search::before { +.icon-send-alt::before { content: "\f11a"; } -.icon-replace::before { +.icon-search::before { content: "\f11b"; } -.icon-receive::before { +.icon-replace::before { content: "\f11c"; } -.icon-receive-alt::before { +.icon-receive::before { content: "\f11d"; } -.icon-question::before { +.icon-receive-alt::before { content: "\f11e"; } -.icon-qr-scanner::before { +.icon-question::before { content: "\f11f"; } -.icon-qr-scanner-alt::before { +.icon-qr-scanner::before { content: "\f120"; } -.icon-plus::before { +.icon-qr-scanner-alt::before { content: "\f121"; } -.icon-percent::before { +.icon-plus::before { content: "\f122"; } -.icon-pen::before { +.icon-percent::before { content: "\f123"; } -.icon-paste::before { +.icon-pen::before { content: "\f124"; } -.icon-params::before { +.icon-paste::before { content: "\f125"; } -.icon-more::before { +.icon-params::before { content: "\f126"; } -.icon-missed::before { +.icon-more::before { content: "\f127"; } -.icon-menu-dots::before { +.icon-missed::before { content: "\f128"; } -.icon-manual-lock::before { +.icon-menu-dots::before { content: "\f129"; } -.icon-lock::before { +.icon-manual-lock::before { content: "\f12a"; } -.icon-link::before { +.icon-lock::before { content: "\f12b"; } -.icon-ledger::before { +.icon-link::before { content: "\f12c"; } -.icon-laptop::before { +.icon-ledger::before { content: "\f12d"; } -.icon-globe::before { +.icon-laptop::before { content: "\f12e"; } -.icon-github::before { +.icon-globe::before { content: "\f12f"; } -.icon-flashlight::before { +.icon-github::before { content: "\f130"; } -.icon-fire::before { +.icon-flashlight::before { content: "\f131"; } -.icon-face-id::before { +.icon-fire::before { content: "\f132"; } -.icon-eye::before { +.icon-face-id::before { content: "\f133"; } -.icon-eye-closed::before { +.icon-eye::before { content: "\f134"; } -.icon-external::before { +.icon-eye-closed::before { content: "\f135"; } -.icon-explore::before { +.icon-external::before { content: "\f136"; } -.icon-earn::before { +.icon-explore::before { content: "\f137"; } -.icon-download::before { +.icon-earn::before { content: "\f138"; } -.icon-download-filled::before { +.icon-download::before { content: "\f139"; } -.icon-dot::before { +.icon-download-filled::before { content: "\f13a"; } -.icon-crypto::before { +.icon-dot::before { content: "\f13b"; } -.icon-copy::before { +.icon-crypto::before { content: "\f13c"; } -.icon-cog::before { +.icon-copy::before { content: "\f13d"; } -.icon-close::before { +.icon-cog::before { content: "\f13e"; } -.icon-close-filled::before { +.icon-close::before { content: "\f13f"; } -.icon-chevron-right::before { +.icon-close-filled::before { content: "\f140"; } -.icon-chevron-left::before { +.icon-chevron-right::before { content: "\f141"; } -.icon-chevron-down::before { +.icon-chevron-left::before { content: "\f142"; } -.icon-check::before { +.icon-chevron-down::before { content: "\f143"; } -.icon-changelly::before { +.icon-check::before { content: "\f144"; } -.icon-chain-tron::before { +.icon-changelly::before { content: "\f145"; } -.icon-chain-ton::before { +.icon-chain-tron::before { content: "\f146"; } -.icon-caret-down::before { +.icon-chain-ton::before { content: "\f147"; } -.icon-card::before { +.icon-caret-down::before { content: "\f148"; } -.icon-backspace::before { +.icon-card::before { content: "\f149"; } -.icon-arrow-up::before { +.icon-backspace::before { content: "\f14a"; } -.icon-arrow-up-swap::before { +.icon-arrow-up::before { content: "\f14b"; } -.icon-arrow-right::before { +.icon-arrow-up-swap::before { content: "\f14c"; } -.icon-arrow-right-swap::before { +.icon-arrow-right::before { content: "\f14d"; } -.icon-arrow-down::before { +.icon-arrow-right-swap::before { content: "\f14e"; } -.icon-action-swap::before { +.icon-arrow-down::before { content: "\f14f"; } -.icon-action-send::before { +.icon-action-swap::before { content: "\f150"; } -.icon-action-earn::before { +.icon-action-send::before { content: "\f151"; } -.icon-action-add::before { +.icon-action-earn::before { content: "\f152"; } -.icon-accept::before { +.icon-action-add::before { content: "\f153"; } +.icon-accept::before { + content: "\f154"; +} diff --git a/src/styles/brilliant-icons.woff b/src/styles/brilliant-icons.woff index 934d204da21a17bca7f61183d9b12b34ae52b55b..e611ff1744898913dd058b35e6afd10dd997565e 100644 GIT binary patch delta 10387 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%0A$=BR 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 Bz2E=< diff --git a/src/styles/brilliant-icons.woff2 b/src/styles/brilliant-icons.woff2 index 5f324372d47d54ea83884fb6181e0f7b98b88045..40103ee3a540bdedf0dcecd6c2ba8c79606fdfd2 100644 GIT binary patch delta 9112 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%0A&+UL+Veu;!A?$nm&B#~En_ zxgYK7CozKZxpgtkImi#0X%Pqee?9s{j+jDqKTuaNyrX+IJ?H2S0Kk=ky8FAAq=-4u zk@k;sBs=}_KG3r*cJWAe!EDRy!tR|{V%sNvw9zi*eB9pe&hVn%bPt$?wpR6l!nEG- z)+3wO(2=d|M*m;(fycaMS&PJn!&g`F^5v$c%_xjDr6Yfjwt*)5F zS^W`i!_tzkuZNDz(;Z>2$_@BS)(8^Z85u5aDQo+IfRuSI==myHe~;xU2Bm%e!_J$x z6MBWoxMQ#@$oDpu=$W8@^O1Tp z4+8QTpeq09s|#-h`%1|ty&^X%$EP>uAT0mu4`-uiyE>8IOCDLIw2=oDlecXwfo<&e zAt3MD5Y?JPGf^&&h(UNrJiDeol1%V!gsoQ%^wtv6H zZSo5sun)V&l6@R}-EFEr9)|3+DL0%wbUj{Gt3ugG1N2&ru>7L!hm<}9mftMH*si=$ zQ8u9Z-B*NHRiSI;&^(6y*+ma6f8g9nql61Rt(QgrKMn zIP8&XhhSFKe{4qn=kz{Rbqr6~>TO&9zv{Lq^C5HgIo-lrU$7;WA-wK9Sijqlt`@`S zpxPfO1)K&F=o&Dn@&xCwT*R|YuE$Tlx@*{_nL?ju#YJS+b^6q z0=2Aa{&W39wIn>e?Ov_7;**CVA%E&Q?t-jWdrhSOeiE>cDG1vyoHqjHt%ZaC!#=S- zr0>k|wtMA^UzDpn7#t(tU(#GV&hM`IG{lRmtixwD-BBp8oTh!ZR50_$i{8}4 zr901TeFW@DzjN($c zQmxe+%~re9?ez!0;$`jEgL*6VEY(~OqmJ4 z$7)W#Z2NAa{pm(&Uc8u+Vm(2?p?QlJ>|%UE4iy_bJ1PU!`_xh(C^x5UJ|=f3im4j`O5P?VJ591d+*fM+DSbcK<4 zbQf#KiwSoD6rD>7_&H>;-9tE7hJX#I%4yv4eXfj0TkQ$*yW!IWt?1Q3A+3jSlw`hK WjzNy_Ag~S!LW~uJfZ4AA0002}pQ>O0 delta 9042 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 z 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 E03$7O=l}o! diff --git a/src/util/fee/swapFee.ts b/src/util/fee/swapFee.ts index 6e8853c5..104c1fc4 100644 --- a/src/util/fee/swapFee.ts +++ b/src/util/fee/swapFee.ts @@ -1,4 +1,4 @@ -import type { ApiToken } from '../../api/types'; +import type { ApiSwapEstimateVariant, ApiToken } from '../../api/types'; import type { GlobalState } from '../../global/types'; import type { FeePrecision, FeeTerms } from './types'; import { SwapType } from '../../global/types'; @@ -55,18 +55,27 @@ type MaxSwapAmountInput = Pick | undefined; }; -type BalanceSufficientForSwapInput = Omit & { +type BalanceSufficientForSwapInput = MaxSwapAmountInput & { /** The wallet balance of the native token of the "in" token chain. Undefined means that it's unknown. */ nativeTokenInBalance: bigint | undefined; /** The "in" amount to swap. Undefined means that it's unspecified. */ amountIn: string | undefined; }; +type CanAffordSwapVariant = { + variant: ApiSwapEstimateVariant; + tokenIn: Pick | undefined; + /** The balance of the "in" token. Undefined means that it's unknown. */ + tokenInBalance: bigint | undefined; + /** The wallet balance of the native token of the "in" token chain. Undefined means that it's unknown. */ + nativeTokenInBalance: bigint | undefined; +}; + /** * Converts the swap fee data returned from API into data that is ready to be displayed in the swap form UI. */ export function explainSwapFee(input: ExplainSwapFeeInput): ExplainedSwapFee { - return shouldBeGasless(input) + return shouldSwapBeGasless(input) ? explainGaslessSwapFee(input) : explainGasfullSwapFee(input); } @@ -152,7 +161,43 @@ export function isBalanceSufficientForSwap(input: BalanceSufficientForSwapInput) return swapAmountInBigint <= maxAmount && networkNativeFeeBigint <= nativeTokenInBalance; } -function shouldBeGasless(input: ExplainSwapFeeInput) { +/** + * Decides whether the balance is sufficient for the given swap estimate variant (DEX). + * Returns undefined when it can't be calculated because of insufficient input data. + */ +export function canAffordSwapEstimateVariant(input: CanAffordSwapVariant) { + if (!input.tokenIn || input.nativeTokenInBalance === undefined) { + return undefined; + } + + const nativeTokenIn = findChainConfig(getChainBySlug(input.tokenIn.slug))?.nativeToken; + if (!nativeTokenIn) { + return undefined; + } + + // Try to pay with gas + const networkFeeBigint = fromDecimal(input.variant.networkFee, nativeTokenIn.decimals); + if (input.nativeTokenInBalance >= networkFeeBigint) { + return true; + } + + // Otherwise, try to pay with diesel + if (input.variant.dieselFee) { + if (input.tokenInBalance === undefined) { + return undefined; + } + const dieselFeeBigint = fromDecimal(input.variant.dieselFee, input.tokenIn.decimals); + if (input.tokenInBalance >= dieselFeeBigint) { + return true; + } + } + + return false; +} + +export function shouldSwapBeGasless( + input: Pick, +) { const isNativeIn = getIsNativeToken(input.tokenInSlug); const nativeTokenBalance = getBigNativeTokenInBalance(input); const isInsufficientNative = input.networkFee !== undefined && nativeTokenBalance !== undefined @@ -162,7 +207,7 @@ function shouldBeGasless(input: ExplainSwapFeeInput) { input.swapType === SwapType.OnChain && isInsufficientNative && !isNativeIn - && input.dieselStatus && input.dieselStatus !== 'not-available' + && Boolean(input.dieselStatus) && input.dieselStatus !== 'not-available' ); } diff --git a/src/util/swipeController.ts b/src/util/swipeController.ts index 769a923f..83654cc3 100644 --- a/src/util/swipeController.ts +++ b/src/util/swipeController.ts @@ -28,6 +28,7 @@ export function captureControlledSwipe( return captureEvents(element, { swipeThreshold: 10, + withNativeDrag: true, excludedClosestSelector: `.${SWIPE_DISABLED_CLASS_NAME}`, onSwipe(e, direction, offsets) { diff --git a/src/util/url.ts b/src/util/url.ts index b3d4f07b..359cfc77 100644 --- a/src/util/url.ts +++ b/src/util/url.ts @@ -108,3 +108,7 @@ export function getExplorerTokenUrl(chain: ApiChain, slug?: string, address?: st ? getTokenExplorerBaseUrl(chain, isTestnet).replace('{address}', address) : `https://coinmarketcap.com/currencies/${slug}/`; } + +export function isTelegramUrl(url: string) { + return url.startsWith('https://t.me/'); +}