Handle evm amounts (#721)
* update presendPageParsing to handle address with amounts * adding method to correctly navigate to send usdc or usdt path based on address params * adding unsupportive token message at top of page stablecoin params page * handling prefilled amount * adding supported tokens translation * fix margin
This commit is contained in:
@@ -9,6 +9,7 @@ import { useNavigation } from '@react-navigation/native';
|
||||
import {
|
||||
navigateToSendUsingClipboard,
|
||||
getQRImage,
|
||||
resolveExternalChainNavigation,
|
||||
} from '../../../../functions';
|
||||
import handlePreSendPageParsing from '../../../../functions/sendBitcoin/handlePreSendPageParsing';
|
||||
import { ThemeText } from '../../../../functions/CustomElements';
|
||||
@@ -387,10 +388,11 @@ export default function HalfModalSendOptions({
|
||||
return;
|
||||
}
|
||||
if (parsed.isExternalChain) {
|
||||
navigate.replace('SelectStablecoinParamsScreen', {
|
||||
address: parsed.address,
|
||||
chainFamily: parsed.chainFamily,
|
||||
});
|
||||
const { method, screen, params } = resolveExternalChainNavigation(
|
||||
parsed,
|
||||
'notHome',
|
||||
);
|
||||
navigate[method](screen, params);
|
||||
return;
|
||||
}
|
||||
navigate.replace('ConfirmPaymentScreen', {
|
||||
@@ -428,10 +430,11 @@ export default function HalfModalSendOptions({
|
||||
}
|
||||
|
||||
if (response.isExternalChain) {
|
||||
navigate.replace('SelectStablecoinParamsScreen', {
|
||||
address: response.address,
|
||||
chainFamily: response.chainFamily,
|
||||
});
|
||||
const { method, screen, params } = resolveExternalChainNavigation(
|
||||
response,
|
||||
'notHome',
|
||||
);
|
||||
navigate[method](screen, params);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import CustomSearchInput from '../../../../functions/CustomElements/searchInput';
|
||||
import { crashlyticsLogReport } from '../../../../functions/crashlyticsLogs';
|
||||
import handlePreSendPageParsing from '../../../../functions/sendBitcoin/handlePreSendPageParsing';
|
||||
import { resolveExternalChainNavigation } from '../../../../functions';
|
||||
import { keyboardNavigate } from '../../../../functions/customNavigation';
|
||||
import ThemeIcon from '../../../../functions/CustomElements/themeIcon';
|
||||
|
||||
@@ -120,6 +121,14 @@ export default function ManualEnterSendAddress(props) {
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (response.isExternalChain) {
|
||||
const { method, screen, params } = resolveExternalChainNavigation(
|
||||
response,
|
||||
'notHome',
|
||||
);
|
||||
navigate[method](screen, params);
|
||||
return;
|
||||
}
|
||||
navigate.replace('ConfirmPaymentScreen', {
|
||||
btcAdress: response.btcAdress,
|
||||
});
|
||||
|
||||
@@ -15,7 +15,11 @@ import {
|
||||
import formatBalanceAmount from './formatNumber';
|
||||
|
||||
import copyToClipboard from './copyToClipboard';
|
||||
import { navigateToSendUsingClipboard, getQRImage } from './sendBitcoin';
|
||||
import {
|
||||
navigateToSendUsingClipboard,
|
||||
getQRImage,
|
||||
resolveExternalChainNavigation,
|
||||
} from './sendBitcoin';
|
||||
import numberConverter from './numberConverter';
|
||||
import { createAccountMnemonic } from './seed';
|
||||
import { normalizeNumber } from './normalizeNumber';
|
||||
@@ -37,6 +41,7 @@ export {
|
||||
copyToClipboard,
|
||||
navigateToSendUsingClipboard,
|
||||
getQRImage,
|
||||
resolveExternalChainNavigation,
|
||||
numberConverter,
|
||||
normalizeNumber,
|
||||
};
|
||||
|
||||
@@ -7,6 +7,92 @@ const EVM_REGEX = /^0x[0-9a-fA-F]{40}$/;
|
||||
const TRON_REGEX = /^T[1-9A-HJ-NP-Za-km-z]{33}$/;
|
||||
const SOLANA_REGEX = /^[1-9A-HJ-NP-Za-km-z]{43,44}$/;
|
||||
|
||||
// URI scheme regexes
|
||||
const EIP681_REGEX =
|
||||
/^ethereum:(0x[0-9a-fA-F]{40})(?:@\d+)?(?:\/([^?]*))?(?:\?(.*))?$/i;
|
||||
const SOLANA_URI_REGEX = /^solana:([1-9A-HJ-NP-Za-km-z]{32,44})(?:\?(.*))?$/;
|
||||
const TRON_URI_REGEX = /^tron:(T[1-9A-HJ-NP-Za-km-z]{33})(?:\?(.*))?$/;
|
||||
|
||||
const EVM_TOKEN_MAP = {
|
||||
// Ethereum
|
||||
'0xdac17f958d2ee523a2206206994597c13d831ec7': {
|
||||
asset: 'USDT',
|
||||
chain: 'ethereum',
|
||||
chainLabel: 'Ethereum',
|
||||
},
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48': {
|
||||
asset: 'USDC',
|
||||
chain: 'ethereum',
|
||||
chainLabel: 'Ethereum',
|
||||
},
|
||||
// Arbitrum
|
||||
'0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9': {
|
||||
asset: 'USDT',
|
||||
chain: 'arbitrum',
|
||||
chainLabel: 'Arbitrum',
|
||||
},
|
||||
'0xaf88d065e77c8cc2239327c5edb3a432268e5831': {
|
||||
asset: 'USDC',
|
||||
chain: 'arbitrum',
|
||||
chainLabel: 'Arbitrum',
|
||||
},
|
||||
// Base
|
||||
'0x833589fcd6edb6e08f4c7c32d4f71b54bda02913': {
|
||||
asset: 'USDC',
|
||||
chain: 'base',
|
||||
chainLabel: 'Base',
|
||||
},
|
||||
// Optimism
|
||||
'0x94b008aa00579c1307b0ef2c499ad98a8ce58e58': {
|
||||
asset: 'USDT',
|
||||
chain: 'optimism',
|
||||
chainLabel: 'Optimism',
|
||||
},
|
||||
'0x0b2c639c533813f4aa9d7837caf62653d097ff85': {
|
||||
asset: 'USDC',
|
||||
chain: 'optimism',
|
||||
chainLabel: 'Optimism',
|
||||
},
|
||||
// Polygon
|
||||
'0xc2132d05d31c914a87c6611c10748aeb04b58e8f': {
|
||||
asset: 'USDT',
|
||||
chain: 'polygon',
|
||||
chainLabel: 'Polygon',
|
||||
},
|
||||
'0x3c499c542cef5e3811e1192ce70d8cc03d5c3359': {
|
||||
asset: 'USDC',
|
||||
chain: 'polygon',
|
||||
chainLabel: 'Polygon',
|
||||
},
|
||||
};
|
||||
|
||||
// Solana SPL token mints
|
||||
const SOLANA_TOKEN_MAP = {
|
||||
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v: {
|
||||
asset: 'USDC',
|
||||
chain: 'solana',
|
||||
chainLabel: 'Solana',
|
||||
},
|
||||
};
|
||||
|
||||
// Tron TRC-20 contracts
|
||||
const TRON_TOKEN_MAP = {
|
||||
TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t: {
|
||||
asset: 'USDT',
|
||||
chain: 'tron',
|
||||
chainLabel: 'Tron',
|
||||
},
|
||||
};
|
||||
|
||||
function parseQueryString(qs) {
|
||||
if (!qs) return {};
|
||||
return qs.split('&').reduce((acc, pair) => {
|
||||
const [k, v] = pair.split('=');
|
||||
if (k) acc[decodeURIComponent(k)] = decodeURIComponent(v ?? '');
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
export default function handlePreSendPageParsing(data) {
|
||||
try {
|
||||
if (!data) throw new Error(i18next.t('errormessages.invalidData'));
|
||||
@@ -32,6 +118,108 @@ export default function handlePreSendPageParsing(data) {
|
||||
};
|
||||
}
|
||||
|
||||
// ethereum:0xAddress[?token=0xContract&amount=X]
|
||||
const evmMatch = EIP681_REGEX.exec(trimmed);
|
||||
if (evmMatch) {
|
||||
const recipient = evmMatch[1];
|
||||
const params = parseQueryString(evmMatch[3]);
|
||||
const tokenContract = params.token ? params.token.toLowerCase() : null;
|
||||
const amount =
|
||||
params.amount && Number(params.amount) > 0
|
||||
? String(Number(params.amount))
|
||||
: null;
|
||||
|
||||
if (tokenContract) {
|
||||
const resolvedToken = EVM_TOKEN_MAP[tokenContract] ?? null;
|
||||
return {
|
||||
didWork: true,
|
||||
error: null,
|
||||
isExternalChain: true,
|
||||
address: recipient,
|
||||
chainFamily: 'EVM',
|
||||
resolvedToken,
|
||||
prefillAmount: amount,
|
||||
unsupportedTokenAddress: resolvedToken ? null : tokenContract,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
didWork: true,
|
||||
error: null,
|
||||
isExternalChain: true,
|
||||
address: recipient,
|
||||
chainFamily: 'EVM',
|
||||
};
|
||||
}
|
||||
|
||||
// solana: URI (Solana Pay)
|
||||
const solanaUriMatch = SOLANA_URI_REGEX.exec(trimmed);
|
||||
if (solanaUriMatch) {
|
||||
const recipient = solanaUriMatch[1];
|
||||
const params = parseQueryString(solanaUriMatch[2]);
|
||||
const splToken = params['token'] ?? params['spl-token'] ?? null;
|
||||
const amount =
|
||||
params.amount && Number(params.amount) > 0
|
||||
? String(Number(params.amount))
|
||||
: null;
|
||||
|
||||
console.log(solanaUriMatch, recipient, params, splToken, amount);
|
||||
|
||||
if (splToken) {
|
||||
const resolvedToken = SOLANA_TOKEN_MAP[splToken] ?? null;
|
||||
return {
|
||||
didWork: true,
|
||||
error: null,
|
||||
isExternalChain: true,
|
||||
address: recipient,
|
||||
chainFamily: 'Solana',
|
||||
resolvedToken,
|
||||
prefillAmount: amount,
|
||||
unsupportedTokenAddress: resolvedToken ? null : splToken,
|
||||
};
|
||||
}
|
||||
return {
|
||||
didWork: true,
|
||||
error: null,
|
||||
isExternalChain: true,
|
||||
address: recipient,
|
||||
chainFamily: 'Solana',
|
||||
};
|
||||
}
|
||||
|
||||
// tron: URI
|
||||
const tronUriMatch = TRON_URI_REGEX.exec(trimmed);
|
||||
if (tronUriMatch) {
|
||||
const recipient = tronUriMatch[1];
|
||||
const params = parseQueryString(tronUriMatch[2]);
|
||||
const splToken = params['token'] ?? params['spl-token'] ?? null;
|
||||
const amount =
|
||||
params.amount && Number(params.amount) > 0
|
||||
? String(Number(params.amount))
|
||||
: null;
|
||||
|
||||
if (splToken) {
|
||||
const resolvedToken = TRON_TOKEN_MAP[splToken] ?? null;
|
||||
return {
|
||||
didWork: true,
|
||||
error: null,
|
||||
isExternalChain: true,
|
||||
address: recipient,
|
||||
chainFamily: 'Tron',
|
||||
resolvedToken,
|
||||
prefillAmount: amount,
|
||||
unsupportedTokenAddress: resolvedToken ? null : splToken,
|
||||
};
|
||||
}
|
||||
return {
|
||||
didWork: true,
|
||||
error: null,
|
||||
isExternalChain: true,
|
||||
address: recipient,
|
||||
chainFamily: 'Tron',
|
||||
};
|
||||
}
|
||||
|
||||
if (WEBSITE_REGEX.test(data)) {
|
||||
if (IS_BLITZ_URL_REGEX.test(data))
|
||||
throw new Error(i18next.t('errormessages.invalidData'));
|
||||
|
||||
@@ -2,6 +2,7 @@ import { getImageFromLibrary } from '../imagePickerWrapper';
|
||||
import getClipboardText from '../getClipboardText';
|
||||
import handlePreSendPageParsing from './handlePreSendPageParsing';
|
||||
import { detectQRCode } from '../detectQrCode';
|
||||
import i18next from 'i18next';
|
||||
|
||||
async function navigateToSendUsingClipboard(navigate, callLocation, from, t) {
|
||||
const response = await getClipboardText();
|
||||
@@ -30,16 +31,11 @@ async function navigateToSendUsingClipboard(navigate, callLocation, from, t) {
|
||||
}
|
||||
|
||||
if (preParsingResponse.isExternalChain) {
|
||||
if (from === 'home')
|
||||
navigate.navigate('SelectStablecoinParamsScreen', {
|
||||
address: preParsingResponse.address,
|
||||
chainFamily: preParsingResponse.chainFamily,
|
||||
});
|
||||
else
|
||||
navigate.replace('SelectStablecoinParamsScreen', {
|
||||
address: preParsingResponse.address,
|
||||
chainFamily: preParsingResponse.chainFamily,
|
||||
});
|
||||
const { method, screen, params } = resolveExternalChainNavigation(
|
||||
preParsingResponse,
|
||||
from,
|
||||
);
|
||||
navigate[method](screen, params);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -114,6 +110,9 @@ async function getQRImage() {
|
||||
isExternalChain: true,
|
||||
address: preParsingResponse.address,
|
||||
chainFamily: preParsingResponse.chainFamily,
|
||||
resolvedToken: preParsingResponse.resolvedToken,
|
||||
prefillAmount: preParsingResponse.prefillAmount,
|
||||
unsupportedTokenAddress: preParsingResponse.unsupportedTokenAddress,
|
||||
didWork: true,
|
||||
error: '',
|
||||
};
|
||||
@@ -127,4 +126,50 @@ function formatStablecoinAmount(rawAmount, decimals = 2) {
|
||||
return value.toFixed(decimals);
|
||||
}
|
||||
|
||||
export { navigateToSendUsingClipboard, getQRImage, formatStablecoinAmount };
|
||||
function resolveExternalChainNavigation(parsedResult, from) {
|
||||
const method = from === 'home' ? 'navigate' : 'replace';
|
||||
|
||||
if (parsedResult.resolvedToken) {
|
||||
return {
|
||||
method,
|
||||
screen: 'StablecoinSendScreen',
|
||||
params: {
|
||||
address: parsedResult.address,
|
||||
chain: parsedResult.resolvedToken.chain,
|
||||
chainLabel: parsedResult.resolvedToken.chainLabel,
|
||||
asset: parsedResult.resolvedToken.asset,
|
||||
...(parsedResult.prefillAmount != null
|
||||
? { prefillAmount: parsedResult.prefillAmount }
|
||||
: {}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (parsedResult.unsupportedTokenAddress) {
|
||||
return {
|
||||
method,
|
||||
screen: 'SelectStablecoinParamsScreen',
|
||||
params: {
|
||||
address: parsedResult.address,
|
||||
chainFamily: parsedResult.chainFamily,
|
||||
unsupportedTokenMessage: i18next.t('errormessages.usdcUsdtTokensOnly'),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
method,
|
||||
screen: 'SelectStablecoinParamsScreen',
|
||||
params: {
|
||||
address: parsedResult.address,
|
||||
chainFamily: parsedResult.chainFamily,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export {
|
||||
navigateToSendUsingClipboard,
|
||||
getQRImage,
|
||||
formatStablecoinAmount,
|
||||
resolveExternalChainNavigation,
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@ import { useGlobalThemeContext } from '../../../context-store/theme';
|
||||
import { useGlobalInsets } from '../../../context-store/insetsProvider';
|
||||
import { Image } from 'expo-image';
|
||||
import { HIDDEN_OPACITY, INSET_WINDOW_WIDTH } from '../../constants/theme';
|
||||
import ThemeIcon from '../../functions/CustomElements/themeIcon';
|
||||
|
||||
const EVM_CHAINS = ['Base', 'Ethereum', 'Arbitrum', 'Optimism', 'Polygon'];
|
||||
const TRON_ASSETS = [{ id: 'USDT', label: 'USDT', icon: ICONS.usdtLogo }];
|
||||
@@ -26,7 +27,7 @@ const SOLANA_ASSETS = [{ id: 'USDC', label: 'USDC', icon: ICONS.usdcLogo }];
|
||||
export default function SelectStablecoinParamsScreen() {
|
||||
const navigate = useNavigation();
|
||||
const route = useRoute();
|
||||
const { address, chainFamily } = route.params;
|
||||
const { address, chainFamily, unsupportedTokenMessage } = route.params;
|
||||
const { t } = useTranslation();
|
||||
const { backgroundOffset, backgroundColor } = GetThemeColors();
|
||||
const { theme, darkModeType } = useGlobalThemeContext();
|
||||
@@ -75,6 +76,21 @@ export default function SelectStablecoinParamsScreen() {
|
||||
: 'wallet.stablecoinSend.selectChain',
|
||||
)}
|
||||
/>
|
||||
{!!unsupportedTokenMessage && (
|
||||
<View
|
||||
style={[
|
||||
{ backgroundColor: backgroundOffset },
|
||||
styles.unsupportedTokenBanner,
|
||||
]}
|
||||
>
|
||||
<ThemeIcon iconName={'TriangleAlert'} />
|
||||
|
||||
<ThemeText
|
||||
styles={styles.unsupportedTokenBannerText}
|
||||
content={unsupportedTokenMessage}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
<View style={styles.innerContainer}>
|
||||
<ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
@@ -164,6 +180,20 @@ const styles = StyleSheet.create({
|
||||
section: {
|
||||
gap: 8,
|
||||
},
|
||||
unsupportedTokenBanner: {
|
||||
width: INSET_WINDOW_WIDTH,
|
||||
marginBottom: CONTENT_KEYBOARD_OFFSET,
|
||||
...CENTER,
|
||||
padding: 16,
|
||||
borderRadius: 12,
|
||||
alignItems: 'center',
|
||||
gap: 10,
|
||||
},
|
||||
unsupportedTokenBannerText: {
|
||||
fontSize: SIZES.small,
|
||||
textAlign: 'center',
|
||||
includeFontPadding: false,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: SIZES.medium,
|
||||
opacity: HIDDEN_OPACITY,
|
||||
|
||||
@@ -28,7 +28,7 @@ import Reanimated, {
|
||||
useSharedValue,
|
||||
} from 'react-native-reanimated';
|
||||
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
||||
import { getQRImage } from '../../functions';
|
||||
import { getQRImage, resolveExternalChainNavigation } from '../../functions';
|
||||
import { GlobalThemeView, ThemeText } from '../../functions/CustomElements';
|
||||
import { backArrow } from '../../constants/styles';
|
||||
import FullLoadingScreen from '../../functions/CustomElements/loadingScreen';
|
||||
@@ -130,17 +130,11 @@ export default function SendPaymentHome({ pageViewPage, from }) {
|
||||
}
|
||||
|
||||
if (response.isExternalChain) {
|
||||
if (from === 'home')
|
||||
navigate.navigate('SelectStablecoinParamsScreen', {
|
||||
address: response.address,
|
||||
chainFamily: response.chainFamily,
|
||||
});
|
||||
else
|
||||
navigate.replace('SelectStablecoinParamsScreen', {
|
||||
address: response.address,
|
||||
chainFamily: response.chainFamily,
|
||||
});
|
||||
|
||||
const { method, screen, params } = resolveExternalChainNavigation(
|
||||
response,
|
||||
from,
|
||||
);
|
||||
navigate[method](screen, params);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -221,17 +215,11 @@ export default function SendPaymentHome({ pageViewPage, from }) {
|
||||
}
|
||||
|
||||
if (response.isExternalChain) {
|
||||
if (from === 'home')
|
||||
navigate.navigate('SelectStablecoinParamsScreen', {
|
||||
address: response.address,
|
||||
chainFamily: response.chainFamily,
|
||||
});
|
||||
else
|
||||
navigate.replace('SelectStablecoinParamsScreen', {
|
||||
address: response.address,
|
||||
chainFamily: response.chainFamily,
|
||||
});
|
||||
|
||||
const { method, screen, params } = resolveExternalChainNavigation(
|
||||
response,
|
||||
from,
|
||||
);
|
||||
navigate[method](screen, params);
|
||||
isPhotoeLibraryOpen.current = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ function formatCountdown(ms) {
|
||||
export default function StablecoinSendScreen() {
|
||||
const navigate = useNavigation();
|
||||
const route = useRoute();
|
||||
const { address, chain, chainLabel, asset, selectedPaymentMethod } =
|
||||
const { address, chain, chainLabel, asset, selectedPaymentMethod, prefillAmount } =
|
||||
route.params;
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -90,7 +90,9 @@ export default function StablecoinSendScreen() {
|
||||
const { swapUSDPriceDollars, poolInfoRef } = useFlashnet();
|
||||
|
||||
const [screenMode, setScreenMode] = useState('EDIT_AMOUNT'); // 'EDIT_AMOUNT' | 'CONFIRM_PAYMENT'
|
||||
const [rawInput, setRawInput] = useState('');
|
||||
const [rawInput, setRawInput] = useState(
|
||||
prefillAmount != null ? String(prefillAmount) : '',
|
||||
);
|
||||
const [inputDenomination, setInputDenomination] = useState('fiat');
|
||||
console.log(rawInput);
|
||||
const [description, setDescription] = useState('');
|
||||
|
||||
@@ -2274,7 +2274,8 @@
|
||||
"paymentError": "Bei der Verarbeitung Ihrer Zahlung ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut. Wenn es weiterhin nicht funktioniert, schließen Sie die App richtig und öffnen Sie sie erneut, bevor Sie es noch einmal versuchen.",
|
||||
"paymentFeeError": "Wir konnten die Zahlungsgebühr nicht abrufen. Bitte versuchen Sie es erneut. Wenn das Problem weiterhin besteht, schließen Sie die App und öffnen Sie sie erneut, bevor Sie es noch einmal versuchen.",
|
||||
"priceImpact": "Bei dieser hohen Zahlung kann sich der endgültige Betrag in USD noch verändern.",
|
||||
"removingImageError": "Bild konnte nicht entfernt werden. Bitte versuchen Sie es erneut."
|
||||
"removingImageError": "Bild konnte nicht entfernt werden. Bitte versuchen Sie es erneut.",
|
||||
"usdcUsdtTokensOnly": "Nur USDT- und USDC-Token werden unterstützt"
|
||||
},
|
||||
"loadingScreen": {
|
||||
"message1": "Bitte schließen Sie die App nicht.",
|
||||
|
||||
@@ -2275,7 +2275,8 @@
|
||||
"paymentError": "Something went wrong while processing your payment. Please try again. If it still doesn’t work, close the app and reopen it before trying again.",
|
||||
"paymentFeeError": "We couldn’t retrieve the payment fee. Please try again. If the issue continues, close the app and reopen it before trying again.",
|
||||
"priceImpact": "This payment is large, so the final amount you receive in Dollars may change.",
|
||||
"removingImageError": "Unable to remove image. Please try again."
|
||||
"removingImageError": "Unable to remove image. Please try again.",
|
||||
"usdcUsdtTokensOnly": "Only USDT and USDC tokens are supported"
|
||||
},
|
||||
"loadingScreen": {
|
||||
"message1": "Please don't close the app",
|
||||
|
||||
@@ -2134,7 +2134,8 @@
|
||||
"paymentFeeError": "No pudimos obtener la tarifa de pago. Inténtalo de nuevo. Si el problema continúa, cierra la aplicación y vuelve a abrirla antes de intentarlo nuevamente.",
|
||||
"priceImpact": "Este pago es grande, por lo que el monto final que recibas en dólares puede cambiar.",
|
||||
"removingImageError": "No se pudo eliminar la imagen. Inténtalo de nuevo.",
|
||||
"bitcoinInvoiceError": "Hubo un problema al generar tu dirección de Bitcoin. Por favor, inténtalo de nuevo."
|
||||
"bitcoinInvoiceError": "Hubo un problema al generar tu dirección de Bitcoin. Por favor, inténtalo de nuevo.",
|
||||
"usdcUsdtTokensOnly": "Solo se admiten los tokens USDT y USDC"
|
||||
},
|
||||
"loadingScreen": {
|
||||
"message1": "Por favor no cierres la aplicación",
|
||||
|
||||
@@ -2272,7 +2272,8 @@
|
||||
"paymentError": "Un problème s'est produit lors du traitement de votre paiement. Veuillez réessayer. Si cela ne fonctionne toujours pas, fermez l'application et rouvrez-la avant de réessayer.",
|
||||
"paymentFeeError": "Nous n'avons pas pu récupérer les frais de paiement. Veuillez réessayer. Si le problème persiste, fermez l'application et rouvrez-la avant de réessayer.",
|
||||
"priceImpact": "Ce paiement est important, le montant final que vous recevrez en dollars peut donc changer.",
|
||||
"removingImageError": "Impossible de supprimer l'image. Veuillez réessayer."
|
||||
"removingImageError": "Impossible de supprimer l'image. Veuillez réessayer.",
|
||||
"usdcUsdtTokensOnly": "Seuls les tokens USDT et USDC sont pris en charge"
|
||||
},
|
||||
"loadingScreen": {
|
||||
"message1": "Ne fermez pas l'application",
|
||||
|
||||
@@ -2272,7 +2272,8 @@
|
||||
"paymentError": "Si è verificato un errore durante l'elaborazione del pagamento. Riprova. Se continua a non funzionare, chiudi l'app e riaprila prima di riprovare.",
|
||||
"paymentFeeError": "Non siamo riusciti a recuperare la commissione di pagamento. Riprova. Se il problema persiste, chiudi l'app e riaprila prima di riprovare.",
|
||||
"priceImpact": "Questo pagamento è elevato, quindi l'importo finale che riceverai in dollari potrebbe cambiare.",
|
||||
"removingImageError": "Impossibile rimuovere l'immagine. Riprova."
|
||||
"removingImageError": "Impossibile rimuovere l'immagine. Riprova.",
|
||||
"usdcUsdtTokensOnly": "Sono supportati solo i token USDT e USDC"
|
||||
},
|
||||
"loadingScreen": {
|
||||
"message1": "Non chiudere l'app",
|
||||
|
||||
@@ -2272,7 +2272,8 @@
|
||||
"paymentError": "Ocorreu um erro ao processar seu pagamento. Tente novamente. Se ainda não funcionar, feche o app e abra-o novamente antes de tentar de novo.",
|
||||
"paymentFeeError": "Não foi possível recuperar a taxa de pagamento. Tente novamente. Se o problema continuar, feche o app e abra-o novamente antes de tentar de novo.",
|
||||
"priceImpact": "Este pagamento é grande, portanto o valor final que você receber em dólares pode mudar.",
|
||||
"removingImageError": "Não foi possível remover a imagem. Tente novamente."
|
||||
"removingImageError": "Não foi possível remover a imagem. Tente novamente.",
|
||||
"usdcUsdtTokensOnly": "Apenas os tokens USDT e USDC são suportados"
|
||||
},
|
||||
"loadingScreen": {
|
||||
"message1": "Por favor, não feche o aplicativo",
|
||||
|
||||
@@ -2280,7 +2280,8 @@
|
||||
"paymentError": "Ошибка обработки платежа. Перезапустите приложение и попробуйте снова.",
|
||||
"paymentFeeError": "Не удалось получить комиссию. Перезапустите приложение.",
|
||||
"priceImpact": "Этот платёж является крупным, поэтому окончательная сумма, которую вы получите в долларах, может измениться.",
|
||||
"removingImageError": "Не удалось удалить изображение. Пожалуйста, попробуйте снова."
|
||||
"removingImageError": "Не удалось удалить изображение. Пожалуйста, попробуйте снова.",
|
||||
"usdcUsdtTokensOnly": "Поддерживаются только токены USDT и USDC"
|
||||
},
|
||||
"loadingScreen": {
|
||||
"message1": "Пожалуйста, не закрывайте приложение",
|
||||
|
||||
@@ -2272,7 +2272,8 @@
|
||||
"paymentError": "Något gick fel när vi behandlade din betalning. Vänligen försök igen. Om det fortfarande inte fungerar stänger du appen och öppnar den igen innan du försöker igen.",
|
||||
"paymentFeeError": "Vi kunde inte hämta betalningsavgiften. Vänligen försök igen. Om problemet kvarstår ska du stänga appen och öppna den igen innan du försöker igen.",
|
||||
"priceImpact": "Den här betalningen är stor, så det slutliga beloppet du får i dollar kan förändras.",
|
||||
"removingImageError": "Kunde inte ta bort bilden. Försök igen."
|
||||
"removingImageError": "Kunde inte ta bort bilden. Försök igen.",
|
||||
"usdcUsdtTokensOnly": "Endast USDT- och USDC-token stöds"
|
||||
},
|
||||
"loadingScreen": {
|
||||
"message1": "Stäng inte appen, snälla",
|
||||
|
||||
Reference in New Issue
Block a user