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 934d204d..e611ff17 100644 Binary files a/src/styles/brilliant-icons.woff and b/src/styles/brilliant-icons.woff differ diff --git a/src/styles/brilliant-icons.woff2 b/src/styles/brilliant-icons.woff2 index 5f324372..40103ee3 100644 Binary files a/src/styles/brilliant-icons.woff2 and b/src/styles/brilliant-icons.woff2 differ 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/'); +}