Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-994-mweb-enhancements

This commit is contained in:
Matthew Fosse 2025-04-24 12:44:14 -07:00
commit 16acb00caa
109 changed files with 5026 additions and 2068 deletions

View file

@ -42,6 +42,14 @@ android {
disable 'InvalidPackage'
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
namespace "com.cakewallet.cake_wallet"
defaultConfig {
@ -73,7 +81,6 @@ android {
buildTypes {
release {
signingConfig signingConfigs.release
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
@ -92,6 +99,7 @@ dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
}
configurations {
implementation.exclude module:'proto-google-common-protos'

View file

@ -6,4 +6,97 @@
-keep class io.flutter.** { *; }
-keep class io.flutter.plugins.** { *; }
-dontwarn io.flutter.embedding.**
-dontwarn com.google.android.play.core.splitcompat.SplitCompatApplication
-dontwarn com.google.android.play.core.splitcompat.SplitCompatApplication
# start reown
-dontwarn com.github.luben.zstd.BufferPool
-dontwarn com.github.luben.zstd.ZstdInputStream
-dontwarn com.github.luben.zstd.ZstdOutputStream
-dontwarn com.google.api.client.http.GenericUrl
-dontwarn com.google.api.client.http.HttpHeaders
-dontwarn com.google.api.client.http.HttpRequest
-dontwarn com.google.api.client.http.HttpRequestFactory
-dontwarn com.google.api.client.http.HttpResponse
-dontwarn com.google.api.client.http.HttpTransport
-dontwarn com.google.api.client.http.javanet.NetHttpTransport$Builder
-dontwarn com.google.api.client.http.javanet.NetHttpTransport
-dontwarn java.awt.Color
-dontwarn java.awt.Dimension
-dontwarn java.awt.Graphics2D
-dontwarn java.awt.Graphics
-dontwarn java.awt.Image
-dontwarn java.awt.Point
-dontwarn java.awt.Polygon
-dontwarn java.awt.Shape
-dontwarn java.awt.color.ColorSpace
-dontwarn java.awt.geom.AffineTransform
-dontwarn java.awt.image.BufferedImage
-dontwarn java.awt.image.ColorModel
-dontwarn java.awt.image.ComponentColorModel
-dontwarn java.awt.image.ComponentSampleModel
-dontwarn java.awt.image.DataBuffer
-dontwarn java.awt.image.DataBufferByte
-dontwarn java.awt.image.DataBufferInt
-dontwarn java.awt.image.DataBufferUShort
-dontwarn java.awt.image.ImageObserver
-dontwarn java.awt.image.MultiPixelPackedSampleModel
-dontwarn java.awt.image.Raster
-dontwarn java.awt.image.RenderedImage
-dontwarn java.awt.image.SampleModel
-dontwarn java.awt.image.SinglePixelPackedSampleModel
-dontwarn java.awt.image.WritableRaster
-dontwarn java.beans.BeanInfo
-dontwarn java.beans.FeatureDescriptor
-dontwarn java.beans.IntrospectionException
-dontwarn java.beans.Introspector
-dontwarn java.beans.PropertyDescriptor
-dontwarn java.lang.reflect.InaccessibleObjectException
-dontwarn javax.imageio.IIOImage
-dontwarn javax.imageio.ImageIO
-dontwarn javax.imageio.ImageWriteParam
-dontwarn javax.imageio.ImageWriter
-dontwarn javax.imageio.metadata.IIOMetadata
-dontwarn javax.imageio.stream.ImageOutputStream
-dontwarn javax.swing.JComponent
-dontwarn javax.swing.JFileChooser
-dontwarn javax.swing.JFrame
-dontwarn javax.swing.JPanel
-dontwarn javax.swing.ProgressMonitor
-dontwarn javax.swing.SwingUtilities
-dontwarn org.brotli.dec.BrotliInputStream
-dontwarn org.joda.time.Instant
-dontwarn org.objectweb.asm.AnnotationVisitor
-dontwarn org.objectweb.asm.Attribute
-dontwarn org.objectweb.asm.ClassReader
-dontwarn org.objectweb.asm.ClassVisitor
-dontwarn org.objectweb.asm.FieldVisitor
-dontwarn org.objectweb.asm.Label
-dontwarn org.objectweb.asm.MethodVisitor
-dontwarn org.objectweb.asm.Type
-dontwarn org.tukaani.xz.ARMOptions
-dontwarn org.tukaani.xz.ARMThumbOptions
-dontwarn org.tukaani.xz.DeltaOptions
-dontwarn org.tukaani.xz.FilterOptions
-dontwarn org.tukaani.xz.FinishableOutputStream
-dontwarn org.tukaani.xz.FinishableWrapperOutputStream
-dontwarn org.tukaani.xz.IA64Options
-dontwarn org.tukaani.xz.LZMA2InputStream
-dontwarn org.tukaani.xz.LZMA2Options
-dontwarn org.tukaani.xz.LZMAInputStream
-dontwarn org.tukaani.xz.LZMAOutputStream
-dontwarn org.tukaani.xz.MemoryLimitException
-dontwarn org.tukaani.xz.PowerPCOptions
-dontwarn org.tukaani.xz.SPARCOptions
-dontwarn org.tukaani.xz.SingleXZInputStream
-dontwarn org.tukaani.xz.UnsupportedOptionsException
-dontwarn org.tukaani.xz.X86Options
-dontwarn org.tukaani.xz.XZ
-dontwarn org.tukaani.xz.XZInputStream
-dontwarn org.tukaani.xz.XZOutputStream
-dontwarn us.hebi.matlab.mat.ejml.Mat5Ejml
-dontwarn us.hebi.matlab.mat.format.Mat5
-dontwarn us.hebi.matlab.mat.format.Mat5File
-dontwarn us.hebi.matlab.mat.types.Array
-dontwarn us.hebi.matlab.mat.types.MatFile$Entry
-dontwarn us.hebi.matlab.mat.types.MatFile
# end reown

View file

@ -24,6 +24,10 @@
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<application
android:name=".Application"
@ -35,6 +39,10 @@
android:versionName="__versionName__"
android:requestLegacyExternalStorage="true"
android:extractNativeLibs="true">
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="dataSync"
android:exported="false" />
<activity
android:name=".MainActivity"
android:launchMode="singleInstance"

View file

@ -2,6 +2,7 @@ allprojects {
repositories {
google()
mavenCentral()
maven { url "https://jitpack.io" }
}
}

View file

@ -256,8 +256,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
Future<void> stopSync() async {
if (isBackgroundSyncRunning) {
printV("Stopping background sync");
await save();
monero.Wallet_store(wptr!);
monero.Wallet_stopBackgroundSync(wptr!, '');
monero_wallet.store();
isBackgroundSyncRunning = false;
}
await save();
@ -268,9 +269,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
Future<void> stopBackgroundSync(String password) async {
if (isBackgroundSyncRunning) {
printV("Stopping background sync");
await save();
monero.Wallet_store(wptr!);
monero.Wallet_stopBackgroundSync(wptr!, password);
await save();
monero.Wallet_store(wptr!);
isBackgroundSyncRunning = false;
}
}

View file

@ -9,7 +9,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.0'
classpath 'com.android.tools.build:gradle:8.7.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

View file

@ -171,37 +171,85 @@ class SolanaWalletClient {
if (programId == SystemProgramConst.programId) {
// For native solana transactions
if (instruction.accounts.length < 2) continue;
final senderIndex = instruction.accounts[0];
final receiverIndex = instruction.accounts[1];
sender = message.accountKeys[senderIndex].address;
receiver = message.accountKeys[receiverIndex].address;
if (txResponse.version == TransactionType.legacy) {
// For legacy transfers, the fee payer (index 0) is the sender.
sender = message.accountKeys[0].address;
final feeForTx = fee / SolanaUtils.lamportsPerSol;
final senderPreBalance = meta.preBalances[0];
final senderPostBalance = meta.postBalances[0];
final feeForTx = fee / SolanaUtils.lamportsPerSol;
final preBalances = meta.preBalances;
final postBalances = meta.postBalances;
// The loss on the sender's account would include both the transfer amount and the fee.
// So we would subtract the fee to calculate the actual amount that was transferred (in lamports).
final transferLamports = (senderPreBalance - senderPostBalance) - BigInt.from(fee);
final amountInString =
(((preBalances[senderIndex] - postBalances[senderIndex]) / BigInt.from(1e9))
.toDouble() -
feeForTx)
.toStringAsFixed(6);
// Next, we attempt to find the receiver by comparing the balance changes.
// (The index 0 is for the sender so we skip it.)
bool foundReceiver = false;
for (int i = 1; i < meta.preBalances.length; i++) {
// The increase in balance on the receiver account should correspond to the transfer amount we calculated earlieer.
final pre = meta.preBalances[i];
final post = meta.postBalances[i];
if ((post - pre) == transferLamports) {
receiver = message.accountKeys[i].address;
foundReceiver = true;
break;
}
}
final amount = double.parse(amountInString);
if (!foundReceiver) {
// Optionally (and rarely), if no account shows the exact expected change,
// we set the receiver address to unknown.
receiver = "unknown";
}
return SolanaTransactionModel(
isOutgoingTx: sender == walletAddress,
from: sender,
to: receiver,
id: signature,
amount: amount.abs(),
programId: SystemProgramConst.programId.address,
tokenSymbol: 'SOL',
blockTimeInInt: blockTime?.toInt() ?? 0,
fee: feeForTx,
);
final amount = transferLamports / BigInt.from(1e9);
return SolanaTransactionModel(
isOutgoingTx: sender == walletAddress,
from: sender,
to: receiver,
id: signature,
amount: amount.abs(),
programId: SystemProgramConst.programId.address,
tokenSymbol: 'SOL',
blockTimeInInt: blockTime?.toInt() ?? 0,
fee: feeForTx,
);
} else {
if (instruction.accounts.length < 2) continue;
final senderIndex = instruction.accounts[0];
final receiverIndex = instruction.accounts[1];
sender = message.accountKeys[senderIndex].address;
receiver = message.accountKeys[receiverIndex].address;
final feeForTx = fee / SolanaUtils.lamportsPerSol;
final preBalances = meta.preBalances;
final postBalances = meta.postBalances;
final amountInString =
(((preBalances[senderIndex] - postBalances[senderIndex]) / BigInt.from(1e9))
.toDouble() -
feeForTx)
.toStringAsFixed(6);
final amount = double.parse(amountInString);
return SolanaTransactionModel(
isOutgoingTx: sender == walletAddress,
from: sender,
to: receiver,
id: signature,
amount: amount.abs(),
programId: SystemProgramConst.programId.address,
tokenSymbol: 'SOL',
blockTimeInInt: blockTime?.toInt() ?? 0,
fee: feeForTx,
);
}
} else if (programId == SPLTokenProgramConst.tokenProgramId) {
// For SPL Token transactions
if (instruction.accounts.length < 2) continue;
@ -842,6 +890,7 @@ class SolanaWalletClient {
}) async {
/// Sign the transaction with the owner's private key.
final ownerSignature = ownerPrivateKey.sign(transaction.serializeMessage());
transaction.addSignature(ownerPrivateKey.publicKey().toAddress(), ownerSignature);
/// Serialize the transaction.

View file

@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
platform :ios, '12.0'
platform :ios, '13.0'
source 'https://github.com/CocoaPods/Specs.git'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
@ -43,7 +43,7 @@ post_install do |installer|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0'
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',

View file

@ -501,7 +501,7 @@
"$(PROJECT_DIR)",
);
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -649,7 +649,7 @@
"$(PROJECT_DIR)",
);
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -690,7 +690,7 @@
"$(PROJECT_DIR)",
);
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",

View file

@ -1,26 +1,101 @@
import 'dart:async';
import 'dart:math';
import 'dart:io';
import 'package:cake_wallet/core/key_service.dart';
import 'package:cake_wallet/core/wallet_loading_service.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/utils/feature_flag.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
import 'package:cw_core/sync_status.dart';
import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:shared_preferences/shared_preferences.dart';
class BackgroundSync {
final FlutterLocalNotificationsPlugin _notificationsPlugin = FlutterLocalNotificationsPlugin();
bool _isInitialized = false;
Future<void> _initializeNotifications() async {
if (_isInitialized) return;
const androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher');
const iosSettings = DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
const initializationSettings = InitializationSettings(
android: androidSettings,
iOS: iosSettings,
);
await _notificationsPlugin.initialize(initializationSettings);
_isInitialized = true;
}
Future<bool> requestPermissions() async {
if (Platform.isIOS || Platform.isMacOS) {
return await _notificationsPlugin
.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
) ?? false;
} else if (Platform.isAndroid) {
return await _notificationsPlugin
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
?.areNotificationsEnabled() ?? false;
}
return false;
}
Future<void> showNotification(String title, String content) async {
await _initializeNotifications();
final hasPermission = await requestPermissions();
if (!hasPermission) {
printV('Notification permissions not granted');
return;
}
const androidDetails = AndroidNotificationDetails(
'transactions',
'Transactions',
channelDescription: 'Channel for notifications about transactions',
importance: Importance.defaultImportance,
priority: Priority.defaultPriority,
);
const iosDetails = DarwinNotificationDetails();
const notificationDetails = NotificationDetails(
android: androidDetails,
iOS: iosDetails,
);
await _notificationsPlugin.show(
DateTime.now().millisecondsSinceEpoch.hashCode,
title,
content,
notificationDetails,
);
}
Future<void> sync() async {
printV("Background sync started");
await _syncMonero();
await _syncWallets();
printV("Background sync completed");
}
Future<void> _syncMonero() async {
Future<void> _syncWallets() async {
final walletLoadingService = getIt.get<WalletLoadingService>();
final walletListViewModel = getIt.get<WalletListViewModel>();
final settingsStore = getIt.get<SettingsStore>();
@ -28,10 +103,10 @@ class BackgroundSync {
final List<WalletListItem> moneroWallets = walletListViewModel.wallets
.where((element) => !element.isHardware)
.where((element) => [WalletType.monero].contains(element.type))
.where((element) => ![WalletType.haven, WalletType.decred].contains(element.type))
.toList();
for (int i = 0; i < moneroWallets.length; i++) {
final wallet = await walletLoadingService.load(moneroWallets[i].type, moneroWallets[i].name);
final wallet = await walletLoadingService.load(moneroWallets[i].type, moneroWallets[i].name, isBackground: true);
int syncedTicks = 0;
final keyService = getIt.get<KeyService>();
@ -75,7 +150,7 @@ class BackgroundSync {
} else {
syncedTicks = 0;
}
if (kDebugMode) {
if (FeatureFlag.hasDevOptions) {
if (syncStatus is SyncingSyncStatus) {
final blocksLeft = syncStatus.blocksLeft;
printV("$blocksLeft Blocks Left");
@ -100,6 +175,27 @@ class BackgroundSync {
}
}
}
final txs = wallet.transactionHistory;
final sortedTxs = txs.transactions.values.toList()..sort((a, b) => a.date.compareTo(b.date));
final sharedPreferences = await SharedPreferences.getInstance();
for (final tx in sortedTxs) {
final lastTriggerString = sharedPreferences.getString(PreferencesKey.backgroundSyncLastTrigger(wallet.name));
final lastTriggerDate = lastTriggerString != null
? DateTime.parse(lastTriggerString)
: DateTime.now();
final keys = sharedPreferences.getKeys();
if (tx.date.isBefore(lastTriggerDate)) {
printV("w: ${wallet.name}, tx: ${tx.date} is before $lastTriggerDate (lastTriggerString: $lastTriggerString) (k: ${keys.length})");
continue;
}
await sharedPreferences.setString(PreferencesKey.backgroundSyncLastTrigger(wallet.name), tx.date.add(Duration(minutes: 1)).toIso8601String());
final action = tx.direction == TransactionDirection.incoming ? "Received" : "Sent";
if (sharedPreferences.getBool(PreferencesKey.backgroundSyncNotificationsEnabled) ?? false) {
await showNotification("$action ${wallet.currency.fullName} in ${wallet.name}", "${tx.amountFormatted()}");
}
printV("${wallet.currency.fullName} in ${wallet.name}: TX: ${tx.date} ${tx.amount} ${tx.direction}");
}
wallet.id;
await wallet.stopBackgroundSync(await keyService.getWalletPassword(walletName: wallet.name));
await wallet.close(shouldCleanup: true);
}

View file

@ -265,16 +265,24 @@ class $BackupService {
{String keychainSalt = secrets.backupKeychainSalt}) async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
final wallets = await Future.wait(walletInfoSource.values.map((walletInfo) async {
return {
'name': walletInfo.name,
'type': walletInfo.type.toString(),
'password': await keyService.getWalletPassword(walletName: walletInfo.name)
};
try {
return {
'name': walletInfo.name,
'type': walletInfo.type.toString(),
'password': await keyService.getWalletPassword(walletName: walletInfo.name)
};
} catch (e) {
return {
'name': walletInfo.name,
'type': walletInfo.type.toString(),
'password': ''
};
}
}));
final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
final backupPassword = await _secureStorage.read(key: backupPasswordKey);
final data = utf8.encode(
json.encode({'wallets': wallets, backupPasswordKey: backupPassword}));
json.encode({'wallets': wallets, backupPasswordKey: backupPassword, '_all': await _secureStorage.readAll()}));
final encrypted = await _encryptV2(Uint8List.fromList(data), '$keychainSalt$password');
return encrypted;

View file

@ -1,5 +0,0 @@
abstract class ChainService {
String getNamespace();
String getChainId();
List<String> getEvents();
}

View file

@ -1,304 +0,0 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:typed_data';
import 'package:cake_wallet/core/wallet_connect/eth_transaction_model.dart';
import 'package:cake_wallet/core/wallet_connect/chain_service/eth/evm_chain_id.dart';
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
import 'package:cake_wallet/core/wallet_connect/models/connection_model.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/connection_widget.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/web3_request_modal.dart';
import 'package:cake_wallet/src/screens/wallet_connect/utils/string_parsing.dart';
import 'package:convert/convert.dart';
import 'package:eth_sig_util/eth_sig_util.dart';
import 'package:eth_sig_util/util/utils.dart';
import 'package:http/http.dart' as http;
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
import 'package:web3dart/web3dart.dart';
import '../chain_service.dart';
import '../../wallet_connect_key_service.dart';
class EvmChainServiceImpl implements ChainService {
final AppStore appStore;
final BottomSheetService bottomSheetService;
final Web3Wallet wallet;
final WalletConnectKeyService wcKeyService;
static const namespace = 'eip155';
static const pSign = 'personal_sign';
static const eSign = 'eth_sign';
static const eSignTransaction = 'eth_signTransaction';
static const eSignTypedData = 'eth_signTypedData_v4';
static const eSendTransaction = 'eth_sendTransaction';
final EVMChainId reference;
final Web3Client ethClient;
EvmChainServiceImpl({
required this.reference,
required this.appStore,
required this.wcKeyService,
required this.bottomSheetService,
required this.wallet,
Web3Client? web3Client,
}) : ethClient = web3Client ??
Web3Client(
appStore.settingsStore.getCurrentNode(appStore.wallet!.type).uri.toString(),
http.Client(),
) {
for (final String event in getEvents()) {
wallet.registerEventEmitter(chainId: getChainId(), event: event);
}
wallet.registerRequestHandler(
chainId: getChainId(),
method: pSign,
handler: personalSign,
);
wallet.registerRequestHandler(
chainId: getChainId(),
method: eSign,
handler: ethSign,
);
wallet.registerRequestHandler(
chainId: getChainId(),
method: eSignTransaction,
handler: ethSignTransaction,
);
wallet.registerRequestHandler(
chainId: getChainId(),
method: eSendTransaction,
handler: ethSignTransaction,
);
wallet.registerRequestHandler(
chainId: getChainId(),
method: eSignTypedData,
handler: ethSignTypedData,
);
}
@override
String getNamespace() {
return namespace;
}
@override
String getChainId() {
return reference.chain();
}
@override
List<String> getEvents() {
return ['chainChanged', 'accountsChanged'];
}
Future<String?> requestAuthorization(String? text) async {
// Show the bottom sheet
final bool? isApproved = await bottomSheetService.queueBottomSheet(
widget: Web3RequestModal(
child: ConnectionWidget(
title: S.current.signTransaction,
info: [
ConnectionModel(
text: text,
),
],
),
),
) as bool?;
if (isApproved != null && isApproved == false) {
return 'User rejected signature';
}
return null;
}
Future<String> personalSign(String topic, dynamic parameters) async {
log('received personal sign request: $parameters');
final String message;
if (parameters[0] == null) {
message = '';
} else {
message = parameters[0].toString().utf8Message;
}
final String? authError = await requestAuthorization(message);
if (authError != null) {
return authError;
}
try {
// Load the private key
final List<ChainKeyModel> keys = wcKeyService
.getKeysForChain(appStore.wallet!);
final Credentials credentials = EthPrivateKey.fromHex(keys[0].privateKey);
final String signature = hex.encode(
credentials.signPersonalMessageToUint8List(Uint8List.fromList(utf8.encode(message))),
);
return '0x$signature';
} catch (e) {
log(e.toString());
bottomSheetService.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(
message: '${S.current.errorGettingCredentials} ${e.toString()}',
),
);
return 'Failed: Error while getting credentials';
}
}
Future<String> ethSign(String topic, dynamic parameters) async {
log('received eth sign request: $parameters');
final String message;
if (parameters[1] == null) {
message = '';
} else {
message = parameters[1].toString().utf8Message;
}
final String? authError = await requestAuthorization(message);
if (authError != null) {
return authError;
}
try {
// Load the private key
final List<ChainKeyModel> keys = wcKeyService
.getKeysForChain(appStore.wallet!);
final EthPrivateKey credentials = EthPrivateKey.fromHex(keys[0].privateKey);
final String signature = hex.encode(
credentials.signPersonalMessageToUint8List(
Uint8List.fromList(utf8.encode(message)),
chainId: getChainIdBasedOnWalletType(appStore.wallet!.type),
),
);
log(signature);
return '0x$signature';
} catch (e) {
log('error: ${e.toString()}');
bottomSheetService.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(message: '${S.current.error}: ${e.toString()}'),
);
return 'Failed';
}
}
Future<String> ethSignTransaction(String topic, dynamic parameters) async {
log('received eth sign transaction request: $parameters');
final paramsData = parameters[0] as Map<String, dynamic>;
final message = _convertToReadable(paramsData);
final String? authError = await requestAuthorization(message);
if (authError != null) {
return authError;
}
// Load the private key
final List<ChainKeyModel> keys = wcKeyService
.getKeysForChain(appStore.wallet!);
final Credentials credentials = EthPrivateKey.fromHex(keys[0].privateKey);
WCEthereumTransactionModel ethTransaction =
WCEthereumTransactionModel.fromJson(parameters[0] as Map<String, dynamic>);
final transaction = Transaction(
from: EthereumAddress.fromHex(ethTransaction.from),
to: EthereumAddress.fromHex(ethTransaction.to),
maxGas: ethTransaction.gasLimit != null ? int.tryParse(ethTransaction.gasLimit ?? "") : null,
gasPrice: ethTransaction.gasPrice != null
? EtherAmount.inWei(BigInt.parse(ethTransaction.gasPrice ?? ""))
: null,
value: EtherAmount.inWei(BigInt.parse(ethTransaction.value)),
data: hexToBytes(ethTransaction.data ?? ""),
nonce: ethTransaction.nonce != null ? int.tryParse(ethTransaction.nonce ?? "") : null,
);
try {
final result = await ethClient.sendTransaction(
credentials,
transaction,
chainId: getChainIdBasedOnWalletType(appStore.wallet!.type),
);
log('Result: $result');
bottomSheetService.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(
message: S.current.awaitDAppProcessing,
isError: false,
),
);
return result;
} catch (e) {
log('An error has occurred while signing transaction: ${e.toString()}');
bottomSheetService.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(
message: '${S.current.errorSigningTransaction}: ${e.toString()}',
),
);
return 'Failed';
}
}
Future<String> ethSignTypedData(String topic, dynamic parameters) async {
log('received eth sign typed data request: $parameters');
final String? data = parameters[1] as String?;
final String? authError = await requestAuthorization(data);
if (authError != null) {
return authError;
}
final List<ChainKeyModel> keys = wcKeyService
.getKeysForChain(appStore.wallet!);
return EthSigUtil.signTypedData(
privateKey: keys[0].privateKey,
jsonData: data ?? '',
version: TypedDataVersion.V4,
);
}
String _convertToReadable(Map<String, dynamic> data) {
final tokenName = getTokenNameBasedOnWalletType(appStore.wallet!.type);
String gas = int.parse((data['gas'] as String).substring(2), radix: 16).toString();
String value = data['value'] != null
? (int.parse((data['value'] as String).substring(2), radix: 16) / 1e18).toString() +
' $tokenName'
: '0 $tokenName';
String from = data['from'] as String;
String to = data['to'] as String;
return '''
Gas: $gas\n
Value: $value\n
From: $from\n
To: $to
''';
}
}

View file

@ -1,28 +0,0 @@
class SolanaSignMessage {
final String pubkey;
final String message;
SolanaSignMessage({
required this.pubkey,
required this.message,
});
factory SolanaSignMessage.fromJson(Map<String, dynamic> json) {
return SolanaSignMessage(
pubkey: json['pubkey'] as String,
message: json['message'] as String,
);
}
Map<String, dynamic> toJson() {
return <String, dynamic>{
'pubkey': pubkey,
'message': message,
};
}
@override
String toString() {
return 'SolanaSignMessage(pubkey: $pubkey, message: $message)';
}
}

View file

@ -1,106 +0,0 @@
class SolanaSignTransaction {
final String? feePayer;
final String? recentBlockhash;
final String transaction;
final List<SolanaInstruction>? instructions;
SolanaSignTransaction({
required this.feePayer,
required this.recentBlockhash,
required this.instructions,
required this.transaction,
});
factory SolanaSignTransaction.fromJson(Map<String, dynamic> json) {
return SolanaSignTransaction(
feePayer:json['feePayer'] !=null ? json['feePayer'] as String: null,
recentBlockhash: json['recentBlockhash']!=null? json['recentBlockhash'] as String: null,
instructions:json['instructions']!=null? (json['instructions'] as List<dynamic>)
.map((e) => SolanaInstruction.fromJson(e as Map<String, dynamic>))
.toList(): null,
transaction: json['transaction'] as String,
);
}
Map<String, dynamic> toJson() {
return {
'feePayer': feePayer,
'recentBlockhash': recentBlockhash,
'instructions': instructions,
'transaction': transaction,
};
}
@override
String toString() {
return 'SolanaSignTransaction(feePayer: $feePayer, recentBlockhash: $recentBlockhash, instructions: $instructions, transaction: $transaction)';
}
}
class SolanaInstruction {
final String programId;
final List<SolanaKeyMetadata> keys;
final List<int> data;
SolanaInstruction({
required this.programId,
required this.keys,
required this.data,
});
factory SolanaInstruction.fromJson(Map<String, dynamic> json) {
return SolanaInstruction(
programId: json['programId'] as String,
keys: (json['keys'] as List<dynamic>)
.map((e) => SolanaKeyMetadata.fromJson(e as Map<String, dynamic>))
.toList(),
data: (json['data'] as List<dynamic>).map((e) => e as int).toList(),
);
}
Map<String, dynamic> toJson() {
return <String, dynamic>{
'programId': programId,
'keys': keys,
'data': data,
};
}
@override
String toString() {
return 'SolanaInstruction(programId: $programId, keys: $keys, data: $data)';
}
}
class SolanaKeyMetadata {
final String pubkey;
final bool isSigner;
final bool isWritable;
SolanaKeyMetadata({
required this.pubkey,
required this.isSigner,
required this.isWritable,
});
factory SolanaKeyMetadata.fromJson(Map<String, dynamic> json) {
return SolanaKeyMetadata(
pubkey: json['pubkey'] as String,
isSigner: json['isSigner'] as bool,
isWritable: json['isWritable'] as bool,
);
}
Map<String, dynamic> toJson() {
return <String, dynamic>{
'pubkey': pubkey,
'isSigner': isSigner,
'isWritable': isWritable,
};
}
@override
String toString() {
return 'SolanaKeyMetadata(pubkey: $pubkey, isSigner: $isSigner, isWritable: $isWritable)';
}
}

View file

@ -1,30 +0,0 @@
import 'solana_chain_service.dart';
enum SolanaChainId {
mainnet,
// testnet,
// devnet,
}
extension SolanaChainIdX on SolanaChainId {
String chain() {
String name = '';
switch (this) {
case SolanaChainId.mainnet:
name = '4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ';
// solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp
break;
// case SolanaChainId.devnet:
// name = '8E9rvCKLFQia2Y35HXjjpWzj8weVo44K';
// // solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1
// break;
// case SolanaChainId.testnet:
// name = '';
// // solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z
// break;
}
return '${SolanaChainServiceImpl.namespace}:$name';
}
}

View file

@ -1,170 +0,0 @@
import 'dart:convert';
import 'dart:developer';
import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cake_wallet/core/wallet_connect/chain_service/solana/entities/solana_sign_message.dart';
import 'package:cake_wallet/core/wallet_connect/chain_service/solana/solana_chain_id.dart';
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart';
import 'package:cake_wallet/core/wallet_connect/models/connection_model.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/connection_widget.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/web3_request_modal.dart';
import 'package:cw_core/solana_rpc_http_service.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:on_chain/solana/solana.dart';
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
import '../chain_service.dart';
import '../../wallet_connect_key_service.dart';
import 'entities/solana_sign_transaction.dart';
class SolanaChainServiceImpl implements ChainService {
final BottomSheetService bottomSheetService;
final Web3Wallet wallet;
final WalletConnectKeyService wcKeyService;
static const namespace = 'solana';
static const solSignTransaction = 'solana_signTransaction';
static const solSignMessage = 'solana_signMessage';
final SolanaChainId reference;
final SolanaRPC solanaProvider;
final SolanaPrivateKey? ownerPrivateKey;
SolanaChainServiceImpl({
required this.reference,
required this.wcKeyService,
required this.bottomSheetService,
required this.wallet,
required this.ownerPrivateKey,
required String formattedRPCUrl,
SolanaRPC? solanaProvider,
}) : solanaProvider = solanaProvider ?? SolanaRPC(SolanaRPCHTTPService(url: formattedRPCUrl)) {
for (final String event in getEvents()) {
wallet.registerEventEmitter(chainId: getChainId(), event: event);
}
wallet.registerRequestHandler(
chainId: getChainId(),
method: solSignTransaction,
handler: solanaSignTransaction,
);
wallet.registerRequestHandler(
chainId: getChainId(),
method: solSignMessage,
handler: solanaSignMessage,
);
}
@override
String getNamespace() {
return namespace;
}
@override
String getChainId() {
return reference.chain();
}
@override
List<String> getEvents() {
return ['chainChanged', 'accountsChanged'];
}
Future<String?> requestAuthorization(String? text) async {
// Show the bottom sheet
final bool? isApproved = await bottomSheetService.queueBottomSheet(
widget: Web3RequestModal(
child: ConnectionWidget(
title: S.current.signTransaction,
info: [
ConnectionModel(
text: text,
),
],
),
),
) as bool?;
if (isApproved != null && isApproved == false) {
return 'User rejected signature';
}
return null;
}
Future<String> solanaSignTransaction(String topic, dynamic parameters) async {
log('received solana sign transaction request $parameters');
final solanaSignTx = SolanaSignTransaction.fromJson(parameters as Map<String, dynamic>);
final String? authError = await requestAuthorization('Confirm request to sign transaction?');
if (authError != null) {
return authError;
}
try {
// Convert transaction string to bytes
List<int> transactionBytes = base64Decode(solanaSignTx.transaction);
final message = SolanaTransactionUtils.deserializeMessageLegacy(transactionBytes);
final sign = ownerPrivateKey!.sign(message.serialize());
final signature = solanaProvider.request(
SolanaRPCSendTransaction(
encodedTransaction: Base58Encoder.encode(sign),
commitment: Commitment.confirmed,
),
);
bottomSheetService.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(
message: S.current.awaitDAppProcessing,
isError: false,
),
);
return signature;
} catch (e) {
log('An error has occurred while signing transaction: ${e.toString()}');
bottomSheetService.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(
message: '${S.current.errorSigningTransaction}: ${e.toString()}',
),
);
return 'Failed';
}
}
Future<String> solanaSignMessage(String topic, dynamic parameters) async {
log('received solana sign message request: $parameters');
final solanaSignMessage = SolanaSignMessage.fromJson(parameters as Map<String, dynamic>);
final String? authError = await requestAuthorization('Confirm request to sign message?');
if (authError != null) {
return authError;
}
List<int>? sign;
try {
sign = ownerPrivateKey!.sign(Base58Decoder.decode(solanaSignMessage.message));
} catch (e) {
printV(e);
}
if (sign == null) {
return '';
}
final signature = Base58Encoder.encode(sign);
return signature;
}
}

View file

@ -1,60 +0,0 @@
class WCEthereumTransactionModel {
final String from;
final String to;
final String value;
final String? nonce;
final String? gasPrice;
final String? maxFeePerGas;
final String? maxPriorityFeePerGas;
final String? gas;
final String? gasLimit;
final String? data;
WCEthereumTransactionModel({
required this.from,
required this.to,
required this.value,
this.nonce,
this.gasPrice,
this.maxFeePerGas,
this.maxPriorityFeePerGas,
this.gas,
this.gasLimit,
this.data,
});
factory WCEthereumTransactionModel.fromJson(Map<String, dynamic> json) {
return WCEthereumTransactionModel(
from: json['from'] as String,
to: json['to'] as String,
value: json['value'] as String,
nonce: json['nonce'] as String?,
gasPrice: json['gasPrice'] as String?,
maxFeePerGas: json['maxFeePerGas'] as String?,
maxPriorityFeePerGas: json['maxPriorityFeePerGas'] as String?,
gas: json['gas'] as String?,
gasLimit: json['gasLimit'] as String?,
data: json['data'] as String?,
);
}
Map<String, dynamic> toJson() {
return {
'from': from,
'to': to,
'value': value,
'nonce': nonce,
'gasPrice': gasPrice,
'maxFeePerGas': maxFeePerGas,
'maxPriorityFeePerGas': maxPriorityFeePerGas,
'gas': gas,
'gasLimit': gasLimit,
'data': data,
};
}
@override
String toString() {
return 'EthereumTransactionModel(from: $from, to: $to, nonce: $nonce, gasPrice: $gasPrice, maxFeePerGas: $maxFeePerGas, maxPriorityFeePerGas: $maxPriorityFeePerGas, gas: $gas, gasLimit: $gasLimit, value: $value, data: $data)';
}
}

View file

@ -1,16 +0,0 @@
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
class AuthRequestModel {
final String iss;
final AuthRequest request;
AuthRequestModel({
required this.iss,
required this.request,
});
@override
String toString() {
return 'AuthRequestModel(iss: $iss, request: $request)';
}
}

View file

@ -1,16 +0,0 @@
class ChainKeyModel {
final List<String> chains;
final String privateKey;
final String publicKey;
ChainKeyModel({
required this.chains,
required this.privateKey,
required this.publicKey,
});
@override
String toString() {
return 'ChainKeyModel(chains: $chains, privateKey: $privateKey, publicKey: $publicKey)';
}
}

View file

@ -1,14 +0,0 @@
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
class SessionRequestModel {
final ProposalData request;
SessionRequestModel({
required this.request,
});
@override
String toString() {
return 'SessionRequestModel(request: $request)';
}
}

View file

@ -1,416 +0,0 @@
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:typed_data';
import 'package:cake_wallet/core/wallet_connect/chain_service/eth/evm_chain_id.dart';
import 'package:cake_wallet/core/wallet_connect/chain_service/eth/evm_chain_service.dart';
import 'package:cake_wallet/core/wallet_connect/wallet_connect_key_service.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/core/wallet_connect/models/auth_request_model.dart';
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
import 'package:cake_wallet/core/wallet_connect/models/session_request_model.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/solana/solana.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/connection_request_widget.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/web3_request_modal.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:eth_sig_util/eth_sig_util.dart';
import 'package:flutter/material.dart';
import 'package:mobx/mobx.dart';
import 'package:on_chain/solana/solana.dart' hide Store;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
import 'chain_service/solana/solana_chain_id.dart';
import 'chain_service/solana/solana_chain_service.dart';
import 'wc_bottom_sheet_service.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
part 'web3wallet_service.g.dart';
class Web3WalletService = Web3WalletServiceBase with _$Web3WalletService;
abstract class Web3WalletServiceBase with Store {
final AppStore appStore;
final SharedPreferences sharedPreferences;
final BottomSheetService _bottomSheetHandler;
final WalletConnectKeyService walletKeyService;
late Web3Wallet _web3Wallet;
@observable
bool isInitialized;
/// The list of requests from the dapp
/// Potential types include, but aren't limited to:
/// [SessionProposalEvent], [AuthRequest]
@observable
ObservableList<PairingInfo> pairings;
@observable
ObservableList<SessionData> sessions;
@observable
ObservableList<StoredCacao> auth;
Web3WalletServiceBase(
this._bottomSheetHandler, this.walletKeyService, this.appStore, this.sharedPreferences)
: pairings = ObservableList<PairingInfo>(),
sessions = ObservableList<SessionData>(),
auth = ObservableList<StoredCacao>(),
isInitialized = false;
@action
void create() {
// Create the web3wallet client
_web3Wallet = Web3Wallet(
core: Core(projectId: secrets.walletConnectProjectId),
metadata: const PairingMetadata(
name: 'Cake Wallet',
description: 'Cake Wallet',
url: 'https://cakewallet.com',
icons: ['https://cakewallet.com/assets/image/cake_logo.png'],
),
);
// Setup our accounts
List<ChainKeyModel> chainKeys = walletKeyService.getKeys(appStore.wallet!);
for (final chainKey in chainKeys) {
for (final chainId in chainKey.chains) {
_web3Wallet.registerAccount(
chainId: chainId,
accountAddress: chainKey.publicKey,
);
}
}
// Setup our listeners
log('Created instance of web3wallet');
_web3Wallet.core.pairing.onPairingInvalid.subscribe(_onPairingInvalid);
_web3Wallet.core.pairing.onPairingCreate.subscribe(_onPairingCreate);
_web3Wallet.core.pairing.onPairingDelete.subscribe(_onPairingDelete);
_web3Wallet.core.pairing.onPairingExpire.subscribe(_onPairingDelete);
_web3Wallet.pairings.onSync.subscribe(_onPairingsSync);
_web3Wallet.onSessionProposal.subscribe(_onSessionProposal);
_web3Wallet.onSessionProposalError.subscribe(_onSessionProposalError);
_web3Wallet.onSessionConnect.subscribe(_onSessionConnect);
_web3Wallet.onAuthRequest.subscribe(_onAuthRequest);
}
@action
Future<void> init() async {
// Await the initialization of the web3wallet
log('Intializing web3wallet');
if (!isInitialized) {
try {
await _web3Wallet.init();
log('Initialized');
isInitialized = true;
} catch (e) {
log('Experimentallllll: $e');
isInitialized = false;
}
}
_refreshPairings();
final newSessions = _web3Wallet.sessions.getAll();
sessions.addAll(newSessions);
final newAuthRequests = _web3Wallet.completeRequests.getAll();
auth.addAll(newAuthRequests);
if (isEVMCompatibleChain(appStore.wallet!.type)) {
for (final cId in EVMChainId.values) {
EvmChainServiceImpl(
reference: cId,
appStore: appStore,
wcKeyService: walletKeyService,
bottomSheetService: _bottomSheetHandler,
wallet: _web3Wallet,
);
}
}
if (appStore.wallet!.type == WalletType.solana) {
for (final cId in SolanaChainId.values) {
final node = appStore.settingsStore.getCurrentNode(appStore.wallet!.type);
String formattedUrl;
String protocolUsed = node.isSSL ? "https" : "http";
if (node.uriRaw == 'rpc.ankr.com') {
String ankrApiKey = secrets.ankrApiKey;
formattedUrl = '$protocolUsed://${node.uriRaw}/$ankrApiKey';
} else if (node.uriRaw == 'solana-mainnet.core.chainstack.com') {
String chainStackApiKey = secrets.chainStackApiKey;
formattedUrl = '$protocolUsed://${node.uriRaw}/$chainStackApiKey';
} else {
formattedUrl = '$protocolUsed://${node.uriRaw}';
}
SolanaChainServiceImpl(
reference: cId,
formattedRPCUrl: formattedUrl,
wcKeyService: walletKeyService,
bottomSheetService: _bottomSheetHandler,
wallet: _web3Wallet,
ownerPrivateKey: SolanaPrivateKey.fromSeedHex(solana!.getPrivateKey(appStore.wallet!)),
);
}
}
}
@action
FutureOr<void> onDispose() {
log('web3wallet dispose');
_web3Wallet.core.pairing.onPairingInvalid.unsubscribe(_onPairingInvalid);
_web3Wallet.pairings.onSync.unsubscribe(_onPairingsSync);
_web3Wallet.onSessionProposal.unsubscribe(_onSessionProposal);
_web3Wallet.onSessionProposalError.unsubscribe(_onSessionProposalError);
_web3Wallet.onSessionConnect.unsubscribe(_onSessionConnect);
_web3Wallet.onAuthRequest.unsubscribe(_onAuthRequest);
_web3Wallet.core.pairing.onPairingDelete.unsubscribe(_onPairingDelete);
_web3Wallet.core.pairing.onPairingExpire.unsubscribe(_onPairingDelete);
isInitialized = false;
}
Web3Wallet getWeb3Wallet() {
return _web3Wallet;
}
void _onPairingsSync(StoreSyncEvent? args) {
if (args != null) {
_refreshPairings();
}
}
void _onPairingDelete(PairingEvent? event) {
_refreshPairings();
}
Future<void> _onSessionProposalError(SessionProposalErrorEvent? args) async {
log(args.toString());
}
void _onSessionProposal(SessionProposalEvent? args) async {
if (args != null) {
final chaindIdNamespace = getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type);
final Widget modalWidget = Web3RequestModal(
child: ConnectionRequestWidget(
chaindIdNamespace: chaindIdNamespace,
wallet: _web3Wallet,
sessionProposal: SessionRequestModel(request: args.params),
),
);
// show the bottom sheet
final bool? isApproved = await _bottomSheetHandler.queueBottomSheet(
widget: modalWidget,
) as bool?;
if (isApproved != null && isApproved) {
_web3Wallet.approveSession(
id: args.id,
namespaces: args.params.generatedNamespaces!,
);
} else {
_web3Wallet.rejectSession(
id: args.id,
reason: Errors.getSdkError(
Errors.USER_REJECTED,
),
);
}
}
}
@action
void _onPairingInvalid(PairingInvalidEvent? args) {
log('Pairing Invalid Event: $args');
_bottomSheetHandler.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(message: '${S.current.pairingInvalidEvent}: $args'),
);
}
@action
Future<void> pairWithUri(Uri uri) async {
try {
log('Pairing with URI: $uri');
await _web3Wallet.pair(uri: uri);
} on WalletConnectError catch (e) {
_bottomSheetHandler.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(message: e.message),
);
} catch (e) {
_bottomSheetHandler.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(message: e.toString()),
);
}
}
@action
void _refreshPairings() {
printV('Refreshing pairings');
pairings.clear();
final allPairings = _web3Wallet.pairings.getAll();
final keyForWallet = getKeyForStoringTopicsForWallet();
if (keyForWallet.isEmpty) return;
final currentTopicsForWallet = getPairingTopicsForWallet(keyForWallet);
final filteredPairings =
allPairings.where((pairing) => currentTopicsForWallet.contains(pairing.topic)).toList();
pairings.addAll(filteredPairings);
}
void _onPairingCreate(PairingEvent? args) {
log('Pairing Create Event: $args');
}
@action
Future<void> _onSessionConnect(SessionConnect? args) async {
if (args != null) {
log('Session Connected $args');
await savePairingTopicToLocalStorage(args.session.pairingTopic);
sessions.add(args.session);
_refreshPairings();
}
}
@action
Future<void> _onAuthRequest(AuthRequest? args) async {
if (args != null) {
final chaindIdNamespace = getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type);
List<ChainKeyModel> chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
// Create the message to be signed
final String iss = 'did:pkh:$chaindIdNamespace:${chainKeys.first.publicKey}';
final Widget modalWidget = Web3RequestModal(
child: ConnectionRequestWidget(
chaindIdNamespace: chaindIdNamespace,
wallet: _web3Wallet,
authRequest: AuthRequestModel(iss: iss, request: args),
),
);
final bool? isAuthenticated = await _bottomSheetHandler.queueBottomSheet(
widget: modalWidget,
) as bool?;
if (isAuthenticated != null && isAuthenticated) {
final String message = _web3Wallet.formatAuthMessage(
iss: iss,
cacaoPayload: CacaoRequestPayload.fromPayloadParams(
args.payloadParams,
),
);
final String sig = EthSigUtil.signPersonalMessage(
message: Uint8List.fromList(message.codeUnits),
privateKey: chainKeys.first.privateKey,
);
await _web3Wallet.respondAuthRequest(
id: args.id,
iss: iss,
signature: CacaoSignature(
t: CacaoSignature.EIP191,
s: sig,
),
);
} else {
await _web3Wallet.respondAuthRequest(
id: args.id,
iss: iss,
error: Errors.getSdkError(
Errors.USER_REJECTED_AUTH,
),
);
}
}
}
@action
Future<void> disconnectSession(String topic) async {
final session = sessions.firstWhere((element) => element.pairingTopic == topic);
await _web3Wallet.core.pairing.disconnect(topic: topic);
await _web3Wallet.disconnectSession(
topic: session.topic, reason: Errors.getSdkError(Errors.USER_DISCONNECTED));
}
@action
List<SessionData> getSessionsForPairingInfo(PairingInfo pairing) {
return sessions.where((element) => element.pairingTopic == pairing.topic).toList();
}
String getKeyForStoringTopicsForWallet() {
List<ChainKeyModel> chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
if (chainKeys.isEmpty) {
return '';
}
final keyForPairingTopic =
PreferencesKey.walletConnectPairingTopicsListForWallet(chainKeys.first.publicKey);
return keyForPairingTopic;
}
List<String> getPairingTopicsForWallet(String key) {
// Get the JSON-encoded string from shared preferences
final jsonString = sharedPreferences.getString(key);
// If the string is null, return an empty list
if (jsonString == null) {
return [];
}
// Decode the JSON string to a list of strings
final List<dynamic> jsonList = jsonDecode(jsonString) as List<dynamic>;
// Cast each item to a string
return jsonList.map((item) => item as String).toList();
}
Future<void> savePairingTopicToLocalStorage(String pairingTopic) async {
// Get key specific to the current wallet
final key = getKeyForStoringTopicsForWallet();
if (key.isEmpty) return;
// Get all pairing topics attached to this key
final pairingTopicsForWallet = getPairingTopicsForWallet(key);
printV(pairingTopicsForWallet);
bool isPairingTopicAlreadySaved = pairingTopicsForWallet.contains(pairingTopic);
printV('Is Pairing Topic Saved: $isPairingTopicAlreadySaved');
if (!isPairingTopicAlreadySaved) {
// Update the list with the most recent pairing topic
pairingTopicsForWallet.add(pairingTopic);
// Convert the list of updated pairing topics to a JSON-encoded string
final jsonString = jsonEncode(pairingTopicsForWallet);
// Save the encoded string to shared preferences
await sharedPreferences.setString(key, jsonString);
}
}
}

View file

@ -52,8 +52,11 @@ class WalletLoadingService {
}
}
Future<WalletBase> load(WalletType type, String name, {String? password}) async {
Future<WalletBase> load(WalletType type, String name, {String? password, bool isBackground = false}) async {
try {
if (!isBackground) {
await sharedPreferences.setString(PreferencesKey.backgroundSyncLastTrigger(name), DateTime.now().toIso8601String());
}
final walletService = walletServiceFactory.call(type);
final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
final wallet = await walletService.openWallet(name, walletPassword);

View file

@ -20,9 +20,6 @@ import 'package:cake_wallet/core/new_wallet_type_arguments.dart';
import 'package:cake_wallet/core/secure_storage.dart';
import 'package:cake_wallet/core/selectable_option.dart';
import 'package:cake_wallet/core/totp_request_details.dart';
import 'package:cake_wallet/core/wallet_connect/wallet_connect_key_service.dart';
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
import 'package:cake_wallet/core/wallet_creation_service.dart';
import 'package:cake_wallet/core/wallet_loading_service.dart';
import 'package:cake_wallet/core/yat_service.dart';
@ -33,10 +30,16 @@ import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/hardware_wallet/require_hardware_wallet_connection.dart';
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
import 'package:cake_wallet/haven/cw_haven.dart';
import 'package:cake_wallet/src/screens/dev/monero_background_sync.dart';
import 'package:cake_wallet/src/screens/dev/moneroc_call_profiler.dart';
import 'package:cake_wallet/src/screens/dev/shared_preferences_page.dart';
import 'package:cake_wallet/src/screens/settings/background_sync_page.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/key_service/wallet_connect_key_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/walletkit_service.dart';
import 'package:cake_wallet/view_model/dev/monero_background_sync.dart';
import 'package:cake_wallet/view_model/dev/shared_preferences.dart';
import 'package:cake_wallet/view_model/link_view_model.dart';
import 'package:cake_wallet/tron/tron.dart';
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
@ -265,6 +268,8 @@ import 'buy/kryptonim/kryptonim.dart';
import 'buy/meld/meld_buy_provider.dart';
import 'src/screens/buy/buy_sell_page.dart';
import 'cake_pay/cake_pay_payment_credantials.dart';
import 'package:cake_wallet/view_model/dev/background_sync_logs_view_model.dart';
import 'package:cake_wallet/src/screens/dev/background_sync_logs_page.dart';
final getIt = GetIt.instance;
@ -635,11 +640,15 @@ Future<void> setup({
getIt.registerLazySingleton<WalletConnectKeyService>(() => KeyServiceImpl());
getIt.registerLazySingleton<Web3WalletService>(() {
final Web3WalletService web3WalletService = Web3WalletService(getIt.get<BottomSheetService>(),
getIt.get<WalletConnectKeyService>(), appStore, getIt.get<SharedPreferences>());
web3WalletService.create();
return web3WalletService;
getIt.registerLazySingleton<WalletKitService>(() {
final WalletKitService walletKitService = WalletKitService(
getIt.get<BottomSheetService>(),
getIt.get<WalletConnectKeyService>(),
appStore,
getIt.get<SharedPreferences>(),
);
walletKitService.create();
return walletKitService;
});
getIt.registerFactory(() => BalancePage(
@ -878,9 +887,8 @@ Future<void> setup({
nanoAccountCreationViewModel:
getIt.get<NanoAccountEditOrCreateViewModel>(param1: account)));
getIt.registerFactory(() {
return DisplaySettingsViewModel(getIt.get<SettingsStore>());
});
getIt.registerFactory(() =>
DisplaySettingsViewModel(getIt.get<SettingsStore>()));
getIt.registerFactory(() =>
SilentPaymentsSettingsViewModel(getIt.get<SettingsStore>(), getIt.get<AppStore>().wallet!));
@ -888,22 +896,20 @@ Future<void> setup({
getIt.registerFactory(
() => MwebSettingsViewModel(getIt.get<SettingsStore>(), getIt.get<AppStore>().wallet!));
getIt.registerFactory(() {
return PrivacySettingsViewModel(getIt.get<SettingsStore>(), getIt.get<AppStore>().wallet!);
});
getIt.registerFactory(() =>
PrivacySettingsViewModel(getIt.get<SettingsStore>(), getIt.get<AppStore>().wallet!));
getIt.registerFactory(() => TrocadorExchangeProvider());
getIt.registerFactory(() => TrocadorProvidersViewModel(
getIt.get<SettingsStore>(), getIt.get<TrocadorExchangeProvider>()));
getIt.registerFactory(() {
return OtherSettingsViewModel(getIt.get<SettingsStore>(), getIt.get<AppStore>().wallet!,
getIt.get<SendViewModel>());});
getIt.registerFactory(() =>
OtherSettingsViewModel(getIt.get<SettingsStore>(), getIt.get<AppStore>().wallet!,
getIt.get<SendViewModel>()));
getIt.registerFactory(() {
return SecuritySettingsViewModel(getIt.get<SettingsStore>());
});
getIt.registerFactory(() =>
SecuritySettingsViewModel(getIt.get<SettingsStore>()));
getIt.registerFactory(() => WalletSeedViewModel(getIt.get<AppStore>().wallet!));
@ -911,6 +917,8 @@ Future<void> setup({
getIt.registerFactory(() => DevMoneroBackgroundSync(getIt.get<AppStore>().wallet!));
getIt.registerFactory(() => DevSharedPreferences());
getIt.registerFactoryParam<WalletSeedPage, bool, void>((bool isWalletCreated, _) =>
WalletSeedPage(getIt.get<WalletSeedViewModel>(), isNewWalletCreated: isWalletCreated));
@ -1115,8 +1123,9 @@ Future<void> setup({
return zano!.createZanoWalletService(_walletInfoSource);
case WalletType.decred:
return decred!.createDecredWalletService(_walletInfoSource, _unspentCoinsInfoSource);
case WalletType.none:
case WalletType.haven:
return HavenWalletService(_walletInfoSource);
case WalletType.none:
throw Exception('Unexpected token: ${param1.toString()} for generating of WalletService');
}
});
@ -1439,7 +1448,8 @@ Future<void> setup({
});
getIt.registerFactory(
() => WalletConnectConnectionsView(web3walletService: getIt.get<Web3WalletService>()));
() => WalletConnectConnectionsView(walletKitService: getIt.get<WalletKitService>()),
);
getIt.registerFactory(() => NFTViewModel(appStore, getIt.get<BottomSheetService>()));
getIt.registerFactory<TorPage>(() => TorPage(getIt.get<AppStore>()));
@ -1449,6 +1459,14 @@ Future<void> setup({
getIt.registerFactory(() => SeedVerificationPage(getIt.get<WalletSeedViewModel>()));
getIt.registerFactory(() => DevMoneroBackgroundSyncPage(getIt.get<DevMoneroBackgroundSync>()));
getIt.registerFactory(() => DevMoneroCallProfilerPage());
getIt.registerFactory(() => DevSharedPreferencesPage(getIt.get<DevSharedPreferences>()));
getIt.registerFactory(() => BackgroundSyncLogsViewModel());
getIt.registerFactory(() => DevBackgroundSyncLogsPage(getIt.get<BackgroundSyncLogsViewModel>()));
_isSetupFinished = true;
}

View file

@ -105,4 +105,6 @@ class PreferencesKey {
static const walletConnectPairingTopicsList = 'wallet_connect_pairing_topics_list';
static String walletConnectPairingTopicsListForWallet(String publicKey) =>
'${PreferencesKey.walletConnectPairingTopicsList}_${publicKey}';
static String backgroundSyncLastTrigger(String walletId) => 'background_sync_last_trigger_${walletId}';
static const backgroundSyncNotificationsEnabled = 'background_sync_notifications_enabled';
}

View file

@ -41,8 +41,8 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
static const exchanging = TradeState(raw: 'exchanging', title: 'Exchanging');
static const sending = TradeState(raw: 'sending', title: 'Sending');
static const success = TradeState(raw: 'success', title: 'Success');
static TradeState deserialize({required String raw}) {
static TradeState deserialize({required String raw}) {
switch (raw) {
case '1':
return unpaid;
@ -138,7 +138,7 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
case 'awaiting':
return awaiting;
default:
throw Exception('Unexpected token: $raw in TradeState deserialize');
return TradeState(raw: raw, title: raw);
}
}

View file

@ -1,348 +1,78 @@
part of 'haven.dart';
import 'dart:io';
class CWHavenAccountList extends HavenAccountList {
CWHavenAccountList(this._wallet);
import 'package:cw_core/balance.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:hive/hive.dart';
final Object _wallet;
class HavenWalletService extends WalletService {
final Box<WalletInfo> walletInfoSource;
HavenWalletService(this.walletInfoSource);
@override
@computed
ObservableList<Account> get accounts {
final havenWallet = _wallet as HavenWallet;
final accounts = havenWallet.walletAddresses.accountList.accounts
.map((acc) => Account(id: acc.id, label: acc.label))
.toList();
return ObservableList<Account>.of(accounts);
}
WalletType getType() => WalletType.haven;
@override
void update(Object wallet) {
final havenWallet = wallet as HavenWallet;
havenWallet.walletAddresses.accountList.update();
}
Future<void> remove(String wallet) async {
final path = await pathForWalletDir(name: wallet, type: WalletType.haven);
@override
void refresh(Object wallet) {
final havenWallet = wallet as HavenWallet;
havenWallet.walletAddresses.accountList.refresh();
}
final file = Directory(path);
final isExist = file.existsSync();
@override
List<Account> getAll(Object wallet) {
final havenWallet = wallet as HavenWallet;
return havenWallet.walletAddresses.accountList
.getAll()
.map((acc) => Account(id: acc.id, label: acc.label))
.toList();
}
@override
Future<void> addAccount(Object wallet, {required String label}) async {
final havenWallet = wallet as HavenWallet;
await havenWallet.walletAddresses.accountList.addAccount(label: label);
}
@override
Future<void> setLabelAccount(Object wallet,
{required int accountIndex, required String label}) async {
final havenWallet = wallet as HavenWallet;
await havenWallet.walletAddresses.accountList
.setLabelAccount(accountIndex: accountIndex, label: label);
}
}
class CWHavenSubaddressList extends MoneroSubaddressList {
CWHavenSubaddressList(this._wallet);
final Object _wallet;
@override
@computed
ObservableList<Subaddress> get subaddresses {
final havenWallet = _wallet as HavenWallet;
final subAddresses = havenWallet.walletAddresses.subaddressList.subaddresses
.map((sub) => Subaddress(id: sub.id, address: sub.address, label: sub.label))
.toList();
return ObservableList<Subaddress>.of(subAddresses);
}
@override
void update(Object wallet, {required int accountIndex}) {
final havenWallet = wallet as HavenWallet;
havenWallet.walletAddresses.subaddressList.update(accountIndex: accountIndex);
}
@override
void refresh(Object wallet, {required int accountIndex}) {
final havenWallet = wallet as HavenWallet;
havenWallet.walletAddresses.subaddressList.refresh(accountIndex: accountIndex);
}
@override
List<Subaddress> getAll(Object wallet) {
final havenWallet = wallet as HavenWallet;
return havenWallet.walletAddresses.subaddressList
.getAll()
.map((sub) => Subaddress(id: sub.id, label: sub.label, address: sub.address))
.toList();
}
@override
Future<void> addSubaddress(Object wallet,
{required int accountIndex, required String label}) async {
final havenWallet = wallet as HavenWallet;
await havenWallet.walletAddresses.subaddressList
.addSubaddress(accountIndex: accountIndex, label: label);
}
@override
Future<void> setLabelSubaddress(Object wallet,
{required int accountIndex, required int addressIndex, required String label}) async {
final havenWallet = wallet as HavenWallet;
await havenWallet.walletAddresses.subaddressList
.setLabelSubaddress(accountIndex: accountIndex, addressIndex: addressIndex, label: label);
}
}
class CWHavenWalletDetails extends HavenWalletDetails {
CWHavenWalletDetails(this._wallet);
final Object _wallet;
@computed
@override
Account get account {
final havenWallet = _wallet as HavenWallet;
final acc = havenWallet.walletAddresses.account as monero_account.Account;
return Account(id: acc.id, label: acc.label);
}
@computed
@override
HavenBalance get balance {
final havenWallet = _wallet as HavenWallet;
final balance = havenWallet.balance;
throw Exception('Unimplemented');
//return HavenBalance(
// fullBalance: balance.fullBalance,
// unlockedBalance: balance.unlockedBalance);
}
}
class CWHaven extends Haven {
@override
HavenAccountList getAccountList(Object wallet) {
return CWHavenAccountList(wallet);
}
@override
MoneroSubaddressList getSubaddressList(Object wallet) {
return CWHavenSubaddressList(wallet);
}
@override
TransactionHistoryBase getTransactionHistory(Object wallet) {
final havenWallet = wallet as HavenWallet;
return havenWallet.transactionHistory;
}
@override
HavenWalletDetails getMoneroWalletDetails(Object wallet) {
return CWHavenWalletDetails(wallet);
}
@override
int getHeightByDate({required DateTime date}) => getHavenHeightByDate(date: date);
@override
Future<int> getCurrentHeight() => getHavenCurrentHeight();
@override
TransactionPriority getDefaultTransactionPriority() {
return MoneroTransactionPriority.automatic;
}
@override
TransactionPriority deserializeMoneroTransactionPriority({required int raw}) {
return MoneroTransactionPriority.deserialize(raw: raw);
}
@override
List<TransactionPriority> getTransactionPriorities() {
return MoneroTransactionPriority.all;
}
@override
List<String> getMoneroWordList(String language) {
switch (language.toLowerCase()) {
case 'english':
return EnglishMnemonics.words;
case 'chinese (simplified)':
return ChineseSimplifiedMnemonics.words;
case 'dutch':
return DutchMnemonics.words;
case 'german':
return GermanMnemonics.words;
case 'japanese':
return JapaneseMnemonics.words;
case 'portuguese':
return PortugueseMnemonics.words;
case 'russian':
return RussianMnemonics.words;
case 'spanish':
return SpanishMnemonics.words;
case 'french':
return FrenchMnemonics.words;
case 'italian':
return ItalianMnemonics.words;
default:
return EnglishMnemonics.words;
if (isExist) {
await file.delete(recursive: true);
}
final walletInfo = walletInfoSource.values
.firstWhere((info) => info.id == WalletBase.idFor(wallet, getType()));
await walletInfoSource.delete(walletInfo.key);
}
@override
WalletCredentials createHavenRestoreWalletFromKeysCredentials(
{required String name,
required String spendKey,
required String viewKey,
required String address,
required String password,
required String language,
required int height}) {
return HavenRestoreWalletFromKeysCredentials(
name: name,
spendKey: spendKey,
viewKey: viewKey,
address: address,
password: password,
language: language,
height: height);
Future<WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>> create(
WalletCredentials credentials,
{bool? isTestnet}) {
throw UnimplementedError();
}
@override
WalletCredentials createHavenRestoreWalletFromSeedCredentials(
{required String name,
required String password,
required int height,
required String mnemonic}) {
return HavenRestoreWalletFromSeedCredentials(
name: name, password: password, height: height, mnemonic: mnemonic);
Future<bool> isWalletExit(String name) {
throw UnimplementedError();
}
@override
WalletCredentials createHavenNewWalletCredentials(
{required String name, required String language, String? password}) {
return HavenNewWalletCredentials(name: name, password: password, language: language);
Future<WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>> openWallet(
String name, String password) {
throw UnimplementedError();
}
@override
Map<String, String> getKeys(Object wallet) {
final havenWallet = wallet as HavenWallet;
final keys = havenWallet.keys;
return <String, String>{
'privateSpendKey': keys.privateSpendKey,
'privateViewKey': keys.privateViewKey,
'publicSpendKey': keys.publicSpendKey,
'publicViewKey': keys.publicViewKey
};
Future<void> rename(String currentName, String password, String newName) {
throw UnimplementedError();
}
@override
Object createHavenTransactionCreationCredentials(
{required List<Output> outputs,
required TransactionPriority priority,
required String assetType}) {
return HavenTransactionCreationCredentials(
outputs: outputs
.map((out) => OutputInfo(
fiatAmount: out.fiatAmount,
cryptoAmount: out.cryptoAmount,
address: out.address,
note: out.note,
sendAll: out.sendAll,
extractedAddress: out.extractedAddress,
isParsedAddress: out.isParsedAddress,
formattedCryptoAmount: out.formattedCryptoAmount))
.toList(),
priority: priority as MoneroTransactionPriority,
assetType: assetType);
Future<WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>>
restoreFromHardwareWallet(WalletCredentials credentials) {
throw UnimplementedError();
}
@override
String formatterMoneroAmountToString({required int amount}) {
return moneroAmountToString(amount: amount);
Future<WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>>
restoreFromKeys(WalletCredentials credentials, {bool? isTestnet}) {
throw UnimplementedError();
}
@override
double formatterMoneroAmountToDouble({required int amount}) {
return moneroAmountToDouble(amount: amount);
Future<WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>>
restoreFromSeed(WalletCredentials credentials, {bool? isTestnet}) {
throw UnimplementedError();
}
@override
int formatterMoneroParseAmount({required String amount}) {
return moneroParseAmount(amount: amount);
}
@override
Account getCurrentAccount(Object wallet) {
final havenWallet = wallet as HavenWallet;
final acc = havenWallet.walletAddresses.account as monero_account.Account;
return Account(id: acc.id, label: acc.label);
}
@override
void setCurrentAccount(Object wallet, int id, String label) {
final havenWallet = wallet as HavenWallet;
havenWallet.walletAddresses.account = monero_account.Account(id: id, label: label);
}
@override
void onStartup() {
monero_wallet_api.onStartup();
}
@override
int getTransactionInfoAccountId(TransactionInfo tx) {
final havenTransactionInfo = tx as HavenTransactionInfo;
return havenTransactionInfo.accountIndex;
}
@override
Future<void> backupHavenSeeds(Box<HavenSeedStore> havenSeedStore) async {
final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
final wallets = walletInfoSource.values
.where((element) => element.type == WalletType.haven);
for (var w in wallets) {
final walletService = HavenWalletService(walletInfoSource);
final flutterSecureStorage = secureStorageShared;
final keyService = KeyService(flutterSecureStorage);
final password = await keyService.getWalletPassword(walletName: w.name);
final wallet = await walletService.openWallet(w.name, password);
await havenSeedStore.add(HavenSeedStore(id: wallet.id, seed: wallet.seed));
wallet.close();
}
await havenSeedStore.flush();
}
@override
WalletService createHavenWalletService(Box<WalletInfo> walletInfoSource) {
return HavenWalletService(walletInfoSource);
}
@override
String getTransactionAddress(Object wallet, int accountIndex, int addressIndex) {
final havenWallet = wallet as HavenWallet;
return havenWallet.getTransactionAddress(accountIndex, addressIndex);
}
@override
CryptoCurrency assetOfTransaction(TransactionInfo tx) {
final transaction = tx as HavenTransactionInfo;
final asset = CryptoCurrency.fromString(transaction.assetType);
return asset;
}
@override
List<AssetRate> getAssetRate() =>
getRate().map((rate) => AssetRate(rate.getAssetType(), rate.getRate())).toList();
}

View file

@ -1,6 +1,5 @@
import 'dart:async';
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/hardware_wallet/require_hardware_wallet_connection.dart';
import 'package:cake_wallet/entities/load_current_wallet.dart';
@ -8,6 +7,7 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/store/authentication_store.dart';
import 'package:cake_wallet/store/settings_store.dart';
@ -71,7 +71,7 @@ void startAuthenticationStateChange(
buttonAction: () => Navigator.of(context).pop()),
);
await loadCurrentWallet();
getIt.get<BottomSheetService>().resetCurrentSheet();
getIt.get<BottomSheetService>().showNext();
await navigatorKey.currentState!
.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
},

View file

@ -1,5 +1,7 @@
import 'package:cake_wallet/core/wallet_connect/chain_service/eth/evm_chain_id.dart';
import 'package:cake_wallet/core/wallet_connect/chain_service/solana/solana_chain_id.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/chain_service/eth/evm_chain_id.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/chain_service/eth/evm_supported_methods.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/chain_service/solana/solana_chain_id.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/chain_service/solana/solana_supported_methods.dart';
import 'package:cw_core/wallet_type.dart';
bool isEVMCompatibleChain(WalletType walletType) {
@ -47,6 +49,19 @@ String getChainNameSpaceAndIdBasedOnWalletType(WalletType walletType) {
}
}
List<String> getChainSupportedMethodsOnWalletType(WalletType walletType) {
switch (walletType) {
case WalletType.ethereum:
return EVMSupportedMethods.values.map((e) => e.name).toList();
case WalletType.polygon:
return EVMSupportedMethods.values.map((e) => e.name).toList();
case WalletType.solana:
return SolanaSupportedMethods.values.map((e) => e.name).toList();
default:
return [];
}
}
int getChainIdBasedOnWalletType(WalletType walletType) {
switch (walletType) {
case WalletType.polygon:

View file

@ -4,7 +4,6 @@ import 'package:cake_wallet/core/new_wallet_arguments.dart';
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/core/new_wallet_type_arguments.dart';
import 'package:cake_wallet/core/totp_request_details.dart';
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/contact_record.dart';
import 'package:cake_wallet/entities/qr_view_data.dart';
@ -37,6 +36,8 @@ import 'package:cake_wallet/src/screens/dashboard/pages/transactions_page.dart';
import 'package:cake_wallet/src/screens/dashboard/sign_page.dart';
import 'package:cake_wallet/src/screens/dev/monero_background_sync.dart';
import 'package:cake_wallet/src/screens/dev/moneroc_call_profiler.dart';
import 'package:cake_wallet/src/screens/dev/shared_preferences_page.dart';
import 'package:cake_wallet/src/screens/dev/background_sync_logs_page.dart';
import 'package:cake_wallet/src/screens/disclaimer/disclaimer_page.dart';
import 'package:cake_wallet/src/screens/exchange/exchange_page.dart';
import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart';
@ -106,6 +107,7 @@ import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
import 'package:cake_wallet/src/screens/ur/animated_ur_page.dart';
import 'package:cake_wallet/src/screens/wallet/wallet_edit_page.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/walletkit_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart';
import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart';
import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart';
@ -777,7 +779,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.walletConnectConnectionsListing:
return MaterialPageRoute<void>(
builder: (_) => WalletConnectConnectionsView(
web3walletService: getIt.get<Web3WalletService>(),
walletKitService: getIt.get<WalletKitService>(),
launchUri: settings.arguments as Uri?,
));
@ -836,6 +838,15 @@ Route<dynamic> createRoute(RouteSettings settings) {
return MaterialPageRoute<void>(
builder: (_) => getIt.get<DevMoneroBackgroundSyncPage>(),
);
case Routes.devSharedPreferences:
return MaterialPageRoute<void>(
builder: (_) => getIt.get<DevSharedPreferencesPage>(),
);
case Routes.devBackgroundSyncLogs:
return MaterialPageRoute<void>(
builder: (_) => getIt.get<DevBackgroundSyncLogsPage>(),
);
case Routes.devMoneroCallProfiler:
return MaterialPageRoute<void>(

View file

@ -111,8 +111,12 @@ class Routes {
static const importNFTPage = '/import_nft_page';
static const torPage = '/tor_page';
static const backgroundSync = '/background_sync';
static const devMoneroBackgroundSync = '/dev/monero_background_sync';
static const devMoneroCallProfiler = '/dev/monero_call_profiler';
static const devSharedPreferences = '/dev/shared_preferences';
static const devBackgroundSyncLogs = '/dev/background_sync_logs';
static const signPage = '/sign_page';
static const connectDevices = '/device/connect';
static const urqrAnimatedPage = '/urqr/animated_page';

View file

@ -490,11 +490,19 @@ class BuySellPage extends BasePage {
return DesktopExchangeCardsSection(
firstExchangeCard: fiatExchangeCard,
secondExchangeCard: cryptoExchangeCard,
onBuyTap: () => null,
onSellTap: () =>
buySellViewModel.isBuyAction ? buySellViewModel.changeBuySellAction() : null,
isBuySellOption: true,
);
} else {
return DesktopExchangeCardsSection(
firstExchangeCard: cryptoExchangeCard,
secondExchangeCard: fiatExchangeCard,
onBuyTap: () =>
!buySellViewModel.isBuyAction ? buySellViewModel.changeBuySellAction() : null,
onSellTap: () => null,
isBuySellOption: true,
);
}
},

View file

@ -1,10 +1,10 @@
import 'dart:async';
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/cake_features_page.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/bottom_sheet/bottom_sheet_listener_widget.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
import 'package:cake_wallet/src/widgets/gradient_background.dart';
import 'package:cake_wallet/src/widgets/haven_wallet_removal_popup.dart';
import 'package:cake_wallet/src/widgets/services_updates_widget.dart';

View file

@ -1,4 +1,3 @@
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
@ -8,7 +7,8 @@ import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sideba
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar/side_menu_item.dart';
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/bottom_sheet/bottom_sheet_listener_widget.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
import 'package:cake_wallet/src/widgets/services_updates_widget.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/desktop_sidebar_view_model.dart';

View file

@ -0,0 +1,314 @@
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/view_model/dev/background_sync_logs_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:intl/intl.dart';
class DevBackgroundSyncLogsPage extends BasePage {
final BackgroundSyncLogsViewModel viewModel;
DevBackgroundSyncLogsPage(this.viewModel) {
viewModel.loadLogs();
}
@override
String? get title => "[dev] background sync logs";
@override
Widget? trailing(BuildContext context) {
return IconButton(
icon: Icon(Icons.refresh),
onPressed: () => viewModel.loadLogs(),
);
}
@override
Widget body(BuildContext context) {
return Observer(
builder: (_) {
if (viewModel.isLoading) {
return Center(child: CircularProgressIndicator());
}
if (viewModel.error != null) {
return Center(child: Text("Error: ${viewModel.error}"));
}
if (viewModel.logData == null) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("No logs loaded"),
SizedBox(height: 16),
ElevatedButton(
onPressed: () => viewModel.loadLogs(),
child: Text("Load Logs"),
),
],
),
);
}
return DefaultTabController(
length: 2,
child: Column(
children: [
TabBar(
tabs: [
Tab(text: "Logs (${viewModel.logs.length})"),
Tab(text: "Sessions (${viewModel.sessions.length})"),
],
),
Expanded(
child: TabBarView(
children: [
_buildLogsTab(context),
_buildSessionsTab(context),
],
),
),
_buildActionButtons(context),
],
),
);
},
);
}
Widget _buildLogsTab(BuildContext context) {
final logs = viewModel.logs;
if (logs.isEmpty) {
return Center(child: Text("No logs available"));
}
final dateFormat = DateFormat('yyyy-MM-dd HH:mm:ss.SSS');
return ListView.builder(
itemCount: logs.length,
itemBuilder: (context, index) {
final log = logs[index];
return ListTile(
title: Text(
log.message,
style: TextStyle(
fontSize: 14,
fontFamily: 'Monospace',
),
),
subtitle: Text(
'${dateFormat.format(log.timestamp)} | ${log.level}' +
(log.sessionId != null ? ' | Session: ${log.sessionId}' : ''),
style: TextStyle(
fontSize: 12,
color: _getLevelColor(log.level),
),
),
dense: true,
onTap: () {
Clipboard.setData(ClipboardData(text: log.message));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Log message copied to clipboard')),
);
},
onLongPress: () {
Clipboard.setData(ClipboardData(
text: '${dateFormat.format(log.timestamp)} [${log.level}] ${log.message}'));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Full log entry copied to clipboard')),
);
},
tileColor: index % 2 == 0 ? Colors.transparent : Colors.black.withOpacity(0.03),
);
},
);
}
Widget _buildSessionsTab(BuildContext context) {
final sessions = viewModel.sessions;
if (sessions.isEmpty) {
return Center(child: Text("No sessions available"));
}
final dateFormat = DateFormat('yyyy-MM-dd HH:mm:ss');
return ListView.builder(
itemCount: sessions.length,
itemBuilder: (context, index) {
final session = sessions[index];
final isActive = session.endTime == null;
return ExpansionTile(
title: Text(
session.name,
style: TextStyle(
fontWeight: FontWeight.bold,
color: isActive ? Colors.green : null,
),
),
subtitle: Text(
'ID: ${session.id} | Started: ${dateFormat.format(session.startTime)}',
style: TextStyle(fontSize: 12),
),
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Start: ${session.startTime.toString()}'),
if (session.endTime != null)
Text('End: ${session.endTime.toString()}'),
if (session.duration != null)
Text('Duration: ${_formatDuration(session.duration!)}'),
SizedBox(height: 8),
_buildSessionLogs(context, session.id),
],
),
),
],
);
},
);
}
Widget _buildSessionLogs(BuildContext context, int sessionId) {
final sessionLogs = viewModel.logs
.where((log) => log.sessionId == sessionId)
.toList();
if (sessionLogs.isEmpty) {
return Text('No logs for this session');
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Session Logs (${sessionLogs.length}):',
style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(height: 8),
Container(
height: 200,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.05),
borderRadius: BorderRadius.circular(4),
),
child: ListView.builder(
itemCount: sessionLogs.length,
itemBuilder: (context, index) {
final log = sessionLogs[index];
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
child: Text(
'[${log.level}] ${log.message}',
style: TextStyle(
fontSize: 12,
fontFamily: 'Monospace',
color: _getLevelColor(log.level),
),
),
);
},
),
),
],
);
}
Widget _buildActionButtons(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton.icon(
icon: Icon(Icons.refresh),
label: Text('Refresh'),
onPressed: () => viewModel.loadLogs(),
),
ElevatedButton.icon(
icon: Icon(Icons.copy),
label: Text('Copy All'),
onPressed: () => _copyAllLogs(context),
),
ElevatedButton.icon(
icon: Icon(Icons.delete),
label: Text('Clear'),
onPressed: () => _confirmClearLogs(context),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
),
),
],
),
);
}
void _copyAllLogs(BuildContext context) {
if (viewModel.logData == null) return;
final buffer = StringBuffer();
final dateFormat = DateFormat('yyyy-MM-dd HH:mm:ss.SSS');
for (final log in viewModel.logs) {
buffer.writeln('${dateFormat.format(log.timestamp)} [${log.level}] ${log.message}');
}
Clipboard.setData(ClipboardData(text: buffer.toString()));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('All logs copied to clipboard')),
);
}
void _confirmClearLogs(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Clear Logs'),
content: Text('Are you sure you want to clear the logs display?'),
actions: <Widget>[
TextButton(
child: Text('Cancel'),
onPressed: () => Navigator.of(context).pop(),
),
TextButton(
child: Text('Clear'),
style: TextButton.styleFrom(foregroundColor: Colors.red),
onPressed: () {
viewModel.clearLogs();
Navigator.of(context).pop();
},
),
],
);
},
);
}
Color _getLevelColor(String level) {
switch (level.toLowerCase()) {
case 'error':
return Colors.red;
case 'warning':
return Colors.orange;
case 'info':
return Colors.blue;
case 'debug':
return Colors.green;
case 'trace':
return Colors.purple;
default:
return Colors.grey;
}
}
String _formatDuration(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, '0');
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return '${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds';
}
}

View file

@ -0,0 +1,404 @@
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/view_model/dev/shared_preferences.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
class DevSharedPreferencesPage extends BasePage {
final DevSharedPreferences viewModel;
DevSharedPreferencesPage(this.viewModel);
@override
String? get title => "[dev] shared preferences";
@override
Widget? trailing(BuildContext context) {
return IconButton(
icon: Icon(Icons.add),
onPressed: () => _showCreateDialog(context),
);
}
@override
Widget body(BuildContext context) {
return Observer(
builder: (_) {
if (viewModel.sharedPreferences == null) {
return Center(child: Text("No shared preferences found"));
}
final keys = viewModel.keys;
Map<String, dynamic> values = {};
for (final key in keys) {
values[key] = viewModel.get(key);
}
Map<String, PreferenceType> types = {};
for (final key in keys) {
types[key] = viewModel.getPreferenceType(key);
}
return ListView.builder(
itemCount: keys.length,
itemBuilder: (context, index) {
final key = keys[index];
final type = types[key]!;
return ListTile(
onTap: () {
Clipboard.setData(ClipboardData(text: key + ": " + values[key].toString()));
},
onLongPress: () {
_showEditDialog(context, key, type, values[key]);
},
title: switch (type) {
PreferenceType.bool => Text(key, style: TextStyle(color: Colors.blue)),
PreferenceType.int => Text(key, style: TextStyle(color: Colors.green)),
PreferenceType.double => Text(key, style: TextStyle(color: Colors.yellow)),
PreferenceType.listString => Text(key, style: TextStyle(color: Colors.purple)),
PreferenceType.string => Text(key),
PreferenceType.unknown => Text(key),
},
subtitle: switch (type) {
PreferenceType.bool => Text("bool: ${values[key]}"),
PreferenceType.int => Text("int: ${values[key]}"),
PreferenceType.double => Text("double: ${values[key]}"),
PreferenceType.listString => values[key].isEmpty as bool ? Text("listString: []") : Text("listString:\n- ${values[key].join("\n- ")}"),
PreferenceType.string => Text("string: ${values[key]}"),
PreferenceType.unknown => Text("UNKNOWN(${values[key].runtimeType}): ${values[key]}"),
},
);
},
);
},
);
}
void _showEditDialog(BuildContext context, String key, PreferenceType type, dynamic currentValue) {
dynamic newValue = currentValue;
bool isListString = type == PreferenceType.listString;
List<String> listItems = isListString ? List<String>.from(currentValue as Iterable<dynamic>) : [];
TextEditingController textController = TextEditingController(
text: isListString ? '' : currentValue?.toString() ?? '');
showDialog(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text('Edit $key'),
content: SizedBox(
width: double.maxFinite,
height: double.maxFinite,
child: SingleChildScrollView(
child: _buildDialogContent(
type,
newValue,
listItems,
textController,
(value) => setState(() => newValue = value),
(items) => setState(() => listItems = items),
),
),
),
actions: <Widget>[
TextButton(
child: Text('Delete'),
style: TextButton.styleFrom(foregroundColor: Colors.red),
onPressed: () {
_showDeleteConfirmation(context, key);
},
),
TextButton(
child: Text('Cancel'),
onPressed: () => Navigator.of(context).pop(),
),
TextButton(
child: Text('Save'),
onPressed: () async {
if (_validateAndUpdateValue(
context,
type,
textController,
listItems,
(value) => newValue = value
)) {
await viewModel.set(key, type, newValue);
Navigator.of(context).pop();
}
},
),
],
);
},
);
},
);
}
void _showDeleteConfirmation(BuildContext context, String key) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Delete Preference'),
content: Text('Are you sure you want to delete "$key"?'),
actions: <Widget>[
TextButton(
child: Text('Cancel'),
onPressed: () => Navigator.of(context).pop(),
),
TextButton(
child: Text('Delete'),
style: TextButton.styleFrom(foregroundColor: Colors.red),
onPressed: () {
viewModel.delete(key);
Navigator.of(context).pop();
Navigator.of(context).pop();
},
),
],
);
},
);
}
Widget _buildDialogContent(
PreferenceType type,
dynamic value,
List<String> listItems,
TextEditingController textController,
Function(dynamic) onValueChanged,
Function(List<String>) onListChanged,
) {
return switch (type) {
PreferenceType.bool => _buildBoolEditor(value as bool, onValueChanged),
PreferenceType.int => _buildNumberEditor(textController, 'Integer value', true),
PreferenceType.double => _buildNumberEditor(textController, 'Double value', false),
PreferenceType.string => _buildTextEditor(textController),
PreferenceType.listString => _buildListEditor(listItems, textController, onListChanged),
PreferenceType.unknown => Text('Cannot edit unknown type'),
};
}
Widget _buildBoolEditor(bool value, Function(bool) onChanged) {
return CheckboxListTile(
title: Text('Value'),
value: value,
onChanged: (newValue) {
if (newValue != null) onChanged(newValue);
},
);
}
Widget _buildTextEditor(TextEditingController controller) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: controller,
decoration: InputDecoration(labelText: 'String value'),
maxLines: null,
),
],
);
}
Widget _buildNumberEditor(TextEditingController controller, String label, bool isInteger) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: controller,
decoration: InputDecoration(labelText: label),
keyboardType: isInteger
? TextInputType.number
: TextInputType.numberWithOptions(decimal: true),
inputFormatters: isInteger
? [FilteringTextInputFormatter.digitsOnly]
: [FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d*$'))],
),
],
);
}
Widget _buildListEditor(
List<String> items,
TextEditingController controller,
Function(List<String>) onListChanged,
) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: 200,
child: ReorderableListView(
shrinkWrap: true,
children: [
for (int i = 0; i < items.length; i++)
ListTile(
key: Key('$i'),
title: Text(items[i]),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
final newList = List<String>.from(items);
newList.removeAt(i);
onListChanged(newList);
},
),
)
],
onReorder: (int oldIndex, int newIndex) {
final newList = List<String>.from(items);
if (oldIndex < newIndex) {
newIndex -= 1;
}
final item = newList.removeAt(oldIndex);
newList.insert(newIndex, item);
onListChanged(newList);
},
),
),
Row(
children: [
Expanded(
child: TextField(
controller: controller,
decoration: InputDecoration(labelText: 'New item'),
),
),
IconButton(
icon: Icon(Icons.add),
onPressed: () {
if (controller.text.isNotEmpty) {
final newList = List<String>.from(items);
newList.add(controller.text);
onListChanged(newList);
controller.clear();
}
},
),
],
),
],
);
}
bool _validateAndUpdateValue(
BuildContext context,
PreferenceType type,
TextEditingController controller,
List<String> listItems,
Function(dynamic) setNewValue,
) {
switch (type) {
case PreferenceType.int:
if (controller.text.isNotEmpty) {
try {
setNewValue(int.parse(controller.text));
} catch (e) {
_showErrorMessage(context, 'Invalid integer value');
return false;
}
}
break;
case PreferenceType.double:
if (controller.text.isNotEmpty) {
try {
setNewValue(double.parse(controller.text));
} catch (e) {
_showErrorMessage(context, 'Invalid double value');
return false;
}
}
break;
case PreferenceType.string:
setNewValue(controller.text);
break;
case PreferenceType.listString:
setNewValue(listItems);
break;
default:
break;
}
return true;
}
void _showErrorMessage(BuildContext context, String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
}
void _showCreateDialog(BuildContext context) {
PreferenceType selectedType = PreferenceType.string;
TextEditingController keyController = TextEditingController();
showDialog(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text('Create Preference'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: keyController,
decoration: InputDecoration(labelText: 'Preference Key'),
),
SizedBox(height: 16),
DropdownButtonFormField<PreferenceType>(
value: selectedType,
decoration: InputDecoration(labelText: 'Type'),
items: [
DropdownMenuItem(value: PreferenceType.string, child: Text('String')),
DropdownMenuItem(value: PreferenceType.bool, child: Text('Boolean')),
DropdownMenuItem(value: PreferenceType.int, child: Text('Integer')),
DropdownMenuItem(value: PreferenceType.double, child: Text('Double')),
DropdownMenuItem(value: PreferenceType.listString, child: Text('List of Strings')),
],
onChanged: (value) {
if (value != null) {
setState(() {
selectedType = value;
});
}
},
),
],
),
),
actions: <Widget>[
TextButton(
child: Text('Cancel'),
onPressed: () => Navigator.of(context).pop(),
),
TextButton(
child: Text('Create'),
onPressed: () {
if (keyController.text.isEmpty) {
_showErrorMessage(context, 'Key cannot be empty');
return;
}
viewModel.set(keyController.text, selectedType, switch (selectedType) {
PreferenceType.bool => false,
PreferenceType.int => 0,
PreferenceType.double => 0.0,
PreferenceType.string => '',
PreferenceType.listString => [],
PreferenceType.unknown => null,
});
Navigator.of(context).pop();
},
),
],
);
},
);
},
);
}
}

View file

@ -1,15 +1,22 @@
import 'package:cake_wallet/src/screens/exchange/widgets/mobile_exchange_cards_section.dart';
import 'package:flutter/material.dart';
class DesktopExchangeCardsSection extends StatelessWidget {
final Widget firstExchangeCard;
final Widget secondExchangeCard;
const DesktopExchangeCardsSection({
Key? key,
required this.firstExchangeCard,
required this.secondExchangeCard,
this.isBuySellOption = false,
this.onBuyTap,
this.onSellTap,
}) : super(key: key);
final Widget firstExchangeCard;
final Widget secondExchangeCard;
final bool isBuySellOption;
final VoidCallback? onBuyTap;
final VoidCallback? onSellTap;
@override
Widget build(BuildContext context) {
return FocusTraversalGroup(
@ -18,7 +25,18 @@ class DesktopExchangeCardsSection extends StatelessWidget {
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 55, left: 24, right: 24),
child: firstExchangeCard,
child: Column(
children: [
if (isBuySellOption)
Column(
children: [
const SizedBox(height: 16),
BuySellOptionButtons(onBuyTap: onBuyTap, onSellTap: onSellTap),
],
),
firstExchangeCard,
],
),
),
Padding(
padding: EdgeInsets.only(top: 29, left: 24, right: 24),

View file

@ -38,6 +38,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
static const fourPinLength = 4;
final _gridViewKey = GlobalKey();
final _key = GlobalKey<ScaffoldState>();
late final FocusNode _focusNode;
int pinLength;
String pin;
@ -54,7 +55,17 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
pin = '';
title = S.current.enter_your_pin;
_aspectRatio = 0;
WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
_focusNode = FocusNode();
WidgetsBinding.instance.addPostFrameCallback((_) {
_focusNode.requestFocus();
_afterLayout(_);
});
}
@override
void dispose() {
_focusNode.dispose();
super.dispose();
}
void setTitle(String title) => setState(() => this.title = title);
@ -120,8 +131,8 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
);
return KeyboardListener(
focusNode: FocusNode(),
autofocus: true,
focusNode: _focusNode,
autofocus: false,
onKeyEvent: (keyEvent) {
if (keyEvent is KeyDownEvent) {
if (keyEvent.logicalKey.keyLabel == "Backspace") {
@ -144,8 +155,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color:
Theme.of(context).extension<CakeTextTheme>()!.titleColor)),
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor)),
Spacer(flex: 8),
Container(
width: 180,
@ -162,7 +172,9 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
shape: BoxShape.circle,
color: isFilled
? Theme.of(context).extension<CakeTextTheme>()!.titleColor
: Theme.of(context).extension<PinCodeTheme>()!.indicatorsColor
: Theme.of(context)
.extension<PinCodeTheme>()!
.indicatorsColor
.withOpacity(0.25),
));
}),
@ -225,7 +237,8 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
child: TextButton(
onPressed: () => _pop(),
style: TextButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.background,
backgroundColor:
Theme.of(context).colorScheme.background,
shape: CircleBorder(),
),
child: deleteIconImage,
@ -250,7 +263,9 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
style: TextStyle(
fontSize: 25.0,
fontWeight: FontWeight.w600,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor)),
color: Theme.of(context)
.extension<CakeTextTheme>()!
.titleColor)),
),
);
}),

View file

@ -12,6 +12,7 @@ import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:permission_handler/permission_handler.dart';
class BackgroundSyncPage extends BasePage {
BackgroundSyncPage(this.dashboardViewModel);
@ -28,30 +29,30 @@ class BackgroundSyncPage extends BasePage {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (dashboardViewModel.hasBatteryOptimization)
Observer(builder: (context) {
return SettingsSwitcherCell(
title: S.current.unrestricted_background_service,
value: !dashboardViewModel.batteryOptimizationEnabled,
onValueChange: (_, bool value) {
dashboardViewModel.disableBatteryOptimization();
},
);
}),
Observer(builder: (context) {
return SettingsSwitcherCell(
title: S.current.background_sync,
value: dashboardViewModel.backgroundSyncEnabled,
onValueChange: (dashboardViewModel.batteryOptimizationEnabled && dashboardViewModel.hasBatteryOptimization) ? (_, bool value) {
unawaited(showPopUp(context: context, builder: (context) => AlertWithOneAction(
alertTitle: S.current.background_sync,
alertContent: S.current.unrestricted_background_service_notice,
buttonText: S.current.ok,
buttonAction: () => Navigator.of(context).pop(),
)));
} : (_, bool value) {
onValueChange: (_, bool value) async {
if (value) {
dashboardViewModel.enableBackgroundSync();
if (dashboardViewModel.batteryOptimizationEnabled) {
await showPopUp(context: context, builder: (context) => AlertWithOneAction(
alertTitle: S.current.background_sync,
alertContent: S.current.unrestricted_background_service_notice,
buttonText: S.current.ok,
buttonAction: () => Navigator.of(context).pop(),
));
await dashboardViewModel.disableBatteryOptimization();
for (var i = 0; i < 4 * 60; i++) {
await Future.delayed(Duration(milliseconds: 250));
if (!dashboardViewModel.batteryOptimizationEnabled) {
await dashboardViewModel.enableBackgroundSync();
return;
}
}
} else {
dashboardViewModel.enableBackgroundSync();
}
} else {
dashboardViewModel.disableBackgroundSync();
}
@ -68,22 +69,58 @@ class BackgroundSyncPage extends BasePage {
dashboardViewModel.setSyncMode(syncMode);
});
}),
// Observer(builder: (context) {
// return SettingsSwitcherCell(
// title: S.current.background_sync_on_battery,
// value: dashboardViewModel.backgroundSyncOnBattery,
// onValueChange: (_, bool value) =>
// dashboardViewModel.setBackgroundSyncOnBattery(value),
// );
// }),
// Observer(builder: (context) {
// return SettingsSwitcherCell(
// title: S.current.background_sync_on_data,
// value: dashboardViewModel.backgroundSyncOnData,
// onValueChange: (_, bool value) => dashboardViewModel.setBackgroundSyncOnData(value),
// );
// }),
if (dashboardViewModel.hasBgsyncNetworkConstraints)
Observer(builder: (context) {
return SettingsSwitcherCell(
title: S.current.background_sync_on_unmetered_network,
value: dashboardViewModel.backgroundSyncNetworkUnmetered,
onValueChange: (_, bool value) => dashboardViewModel.setBackgroundSyncNetworkUnmetered(value),
);
}),
if (dashboardViewModel.hasBgsyncBatteryNotLowConstraints)
Observer(builder: (context) {
return SettingsSwitcherCell(
title: S.current.background_sync_on_battery_low,
value: !dashboardViewModel.backgroundSyncBatteryNotLow,
onValueChange: (_, bool value) => dashboardViewModel.setBackgroundSyncBatteryNotLow(!value),
);
}),
if (dashboardViewModel.hasBgsyncChargingConstraints)
Observer(builder: (context) {
return SettingsSwitcherCell(
title: S.current.background_sync_on_charging,
value: dashboardViewModel.backgroundSyncCharging,
onValueChange: (_, bool value) => dashboardViewModel.setBackgroundSyncCharging(value),
);
}),
if (dashboardViewModel.hasBgsyncDeviceIdleConstraints)
Observer(builder: (context) {
return SettingsSwitcherCell(
title: S.current.background_sync_on_device_idle,
value: dashboardViewModel.backgroundSyncDeviceIdle,
onValueChange: (_, bool value) => dashboardViewModel.setBackgroundSyncDeviceIdle(value),
);
}),
Observer(builder: (context) {
return SettingsSwitcherCell(
title: S.current.new_transactions_notifications,
value: dashboardViewModel.backgroundSyncNotificationsEnabled,
onValueChange: (_, bool value) {
try {
dashboardViewModel.setBackgroundSyncNotificationsEnabled(value);
} catch (e) {
showPopUp(context: context, builder: (context) => AlertWithOneAction(
alertTitle: S.current.error,
alertContent: S.current.notification_permission_denied,
buttonText: S.current.ok,
buttonAction: () {
Navigator.of(context).pop();
},
));
}
},
);
}),
],
),
);

View file

@ -49,7 +49,7 @@ class ConnectionSyncPage extends BasePage {
title: S.current.manage_nodes,
handler: (context) => Navigator.of(context).pushNamed(Routes.manageNodes),
),
if (dashboardViewModel.hasBackgroundSync && Platform.isAndroid && FeatureFlag.isBackgroundSyncEnabled) ...[
if (Platform.isAndroid && FeatureFlag.isBackgroundSyncEnabled) ...[
SettingsCellWithArrow(
title: S.current.background_sync,
handler: (context) => Navigator.of(context).pushNamed(Routes.backgroundSync),

View file

@ -6,12 +6,10 @@ import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/settings/widgets/setting_priority_picker_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_version_cell.dart';
import 'package:cake_wallet/utils/feature_flag.dart';
import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@ -77,6 +75,18 @@ class OtherSettingsPage extends BasePage {
handler: (BuildContext context) =>
Navigator.of(context).pushNamed(Routes.devMoneroCallProfiler),
),
if (FeatureFlag.hasDevOptions)
SettingsCellWithArrow(
title: '[dev] shared preferences',
handler: (BuildContext context) =>
Navigator.of(context).pushNamed(Routes.devSharedPreferences),
),
if (FeatureFlag.hasDevOptions)
SettingsCellWithArrow(
title: '[dev] background sync logs',
handler: (BuildContext context) =>
Navigator.of(context).pushNamed(Routes.devBackgroundSyncLogs),
),
Spacer(),
SettingsVersionCell(
title: S.of(context).version(_otherSettingsViewModel.currentVersion)),

View file

@ -97,6 +97,7 @@ class UnspentCoinsListFormState extends State<UnspentCoinsListForm> {
void _showSavingDataAlert() {
showDialog<void>(
context: context,
useRootNavigator: false,
builder: (BuildContext context) {
return AlertWithNoAction(
alertContent: 'Updating, please wait…',

View file

@ -6,11 +6,13 @@ class BottomSheetQueueItemModel {
final Widget widget;
final bool isModalDismissible;
final Completer<dynamic> completer;
final int closeAfter;
BottomSheetQueueItemModel({
required this.widget,
required this.completer,
this.isModalDismissible = false,
this.closeAfter = 0,
});
@override

View file

@ -1,10 +1,10 @@
class ConnectionModel {
class WCConnectionModel {
final String? title;
final String? text;
final List<String>? elements;
final Map<String, void Function()>? elementActions;
ConnectionModel({
WCConnectionModel({
this.title,
this.text,
this.elements,
@ -13,6 +13,6 @@ class ConnectionModel {
@override
String toString() {
return 'WalletConnectRequestModel(title: $title, text: $text, elements: $elements, elementActions: $elementActions)';
return 'WCConnectionModel(title: $title, text: $text, elements: $elements, elementActions: $elementActions)';
}
}

View file

@ -1,19 +1,24 @@
import 'dart:async';
import 'package:cake_wallet/core/wallet_connect/models/bottom_sheet_queue_item_model.dart';
import 'dart:collection';
import 'package:cake_wallet/src/screens/wallet_connect/models/bottom_sheet_queue_item_model.dart';
import 'package:flutter/material.dart';
enum WCBottomSheetResult { reject, one, all }
abstract class BottomSheetService {
abstract final ValueNotifier<BottomSheetQueueItemModel?> currentSheet;
Future<dynamic> queueBottomSheet({
required Widget widget,
bool isModalDismissible = false,
int closeAfter = 0,
});
void resetCurrentSheet();
void showNext();
}
class BottomSheetServiceImpl implements BottomSheetService {
Queue<BottomSheetQueueItemModel> queue = Queue<BottomSheetQueueItemModel>();
@override
final ValueNotifier<BottomSheetQueueItemModel?> currentSheet = ValueNotifier(null);
@ -21,6 +26,7 @@ class BottomSheetServiceImpl implements BottomSheetService {
@override
Future<dynamic> queueBottomSheet({
required Widget widget,
int closeAfter = 0,
bool isModalDismissible = false,
}) async {
// Create the bottom sheet queue item
@ -28,16 +34,28 @@ class BottomSheetServiceImpl implements BottomSheetService {
final queueItem = BottomSheetQueueItemModel(
widget: widget,
completer: completer,
closeAfter: closeAfter,
isModalDismissible: isModalDismissible,
);
currentSheet.value = queueItem;
// If the current sheet it null, set it to the queue item
if (currentSheet.value == null) {
currentSheet.value = queueItem;
} else {
// Otherwise, add it to the queue
queue.add(queueItem);
}
// Return the future
return await completer.future;
}
@override
void resetCurrentSheet() {
currentSheet.value = null;
void showNext() {
if (queue.isEmpty) {
currentSheet.value = null;
} else {
currentSheet.value = queue.removeFirst();
}
}
}

View file

@ -1,5 +1,3 @@
import 'package:cake_wallet/core/wallet_connect/chain_service/eth/evm_chain_service.dart';
enum EVMChainId {
ethereum,
polygon,
@ -30,6 +28,6 @@ extension EVMChainIdX on EVMChainId {
break;
}
return '${EvmChainServiceImpl.namespace}:$name';
return 'eip155:$name';
}
}

View file

@ -0,0 +1,581 @@
import 'dart:convert';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:eth_sig_util/eth_sig_util.dart';
import 'package:eth_sig_util/util/utils.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:reown_walletkit/reown_walletkit.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/chain_service/eth/evm_chain_id.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/chain_service/eth/evm_supported_methods.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/key_service/wallet_connect_key_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/models/wc_connection_model.dart';
import 'package:cake_wallet/src/screens/wallet_connect/utils/eth_utils.dart';
import 'package:cake_wallet/src/screens/wallet_connect/utils/method_utils.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
class EvmChainServiceImpl {
Map<String, dynamic Function(String, dynamic)> get sessionRequestHandlers => {
EVMSupportedMethods.ethSign.name: ethSign,
EVMSupportedMethods.ethSignTransaction.name: ethSignTransaction,
EVMSupportedMethods.ethSignTypedData.name: ethSignTypedData,
EVMSupportedMethods.ethSignTypedDataV4.name: ethSignTypedDataV4,
};
Map<String, dynamic Function(String, dynamic)> get methodRequestHandlers => {
EVMSupportedMethods.personalSign.name: personalSign,
EVMSupportedMethods.ethSendTransaction.name: ethSendTransaction,
};
EvmChainServiceImpl({
required this.reference,
required this.appStore,
required this.wcKeyService,
required this.bottomSheetService,
required this.walletKit,
Web3Client? web3Client,
}) : ethClient = web3Client ??
Web3Client(
appStore.settingsStore.getCurrentNode(appStore.wallet!.type).uri.toString(),
http.Client(),
) {
for (final event in EventsConstants.allEvents) {
walletKit.registerEventEmitter(
chainId: getChainId(),
event: event,
);
}
for (var handler in methodRequestHandlers.entries) {
walletKit.registerRequestHandler(
chainId: getChainId(),
method: handler.key,
handler: handler.value,
);
}
for (var handler in sessionRequestHandlers.entries) {
walletKit.registerRequestHandler(
chainId: getChainId(),
method: handler.key,
handler: handler.value,
);
}
walletKit.onSessionRequest.subscribe(_onSessionRequest);
}
final AppStore appStore;
final EVMChainId reference;
final Web3Client ethClient;
final ReownWalletKit walletKit;
final WalletConnectKeyService wcKeyService;
final BottomSheetService bottomSheetService;
String getChainId() => reference.chain();
Future<void> personalSign(String topic, dynamic parameters) async {
debugPrint('personalSign request: $parameters');
final pRequest = walletKit.pendingRequests.getAll().last;
final address = EthUtils.getAddressFromSessionRequest(pRequest);
final data = EthUtils.getDataFromSessionRequest(pRequest);
final message = EthUtils.getUtf8Message(data.toString());
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
final isApproved = await MethodsUtils.requestApproval(
message,
method: pRequest.method,
chainId: pRequest.chainId,
address: address,
transportType: pRequest.transportType.name,
verifyContext: pRequest.verifyContext,
);
if (isApproved) {
try {
// Load the private key
final keys = wcKeyService.getKeysForChain(appStore.wallet!);
final credentials = EthPrivateKey.fromHex(keys[0].privateKey);
final signature = credentials.signPersonalMessageToUint8List(
utf8.encode(message),
);
final signedTx = bytesToHex(signature, include0x: true);
isValidSignature(signedTx, message, credentials.address.hex);
response = response.copyWith(result: signedTx);
} catch (e) {
debugPrint('personalSign error $e');
final error = Errors.getSdkError(Errors.MALFORMED_REQUEST_PARAMS);
response = response.copyWith(
error: JsonRpcError(code: error.code, message: error.message),
);
}
} else {
final error = Errors.getSdkError(Errors.USER_REJECTED);
response = response.copyWith(
error: JsonRpcError(code: error.code, message: error.message),
);
}
_handleResponseForTopic(topic, response);
}
Future<void> ethSign(String topic, dynamic parameters) async {
debugPrint('ethSign request: $parameters');
final pRequest = walletKit.pendingRequests.getAll().last;
final address = EthUtils.getAddressFromSessionRequest(pRequest);
final data = EthUtils.getDataFromSessionRequest(pRequest);
final message = EthUtils.getUtf8Message(data.toString());
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
final isApproved = await MethodsUtils.requestApproval(
message,
method: pRequest.method,
chainId: pRequest.chainId,
address: address,
transportType: pRequest.transportType.name,
verifyContext: pRequest.verifyContext,
);
if (isApproved) {
try {
// Load the private key
final keys = wcKeyService.getKeysForChain(appStore.wallet!);
final credentials = EthPrivateKey.fromHex(keys[0].privateKey);
final signature = credentials.signPersonalMessageToUint8List(
utf8.encode(message),
);
final signedTx = bytesToHex(signature, include0x: true);
isValidSignature(signedTx, message, credentials.address.hex);
response = response.copyWith(result: signedTx);
} catch (e) {
debugPrint('ethSign error $e');
final error = Errors.getSdkError(Errors.MALFORMED_REQUEST_PARAMS);
response = response.copyWith(
error: JsonRpcError(code: error.code, message: error.message),
);
}
} else {
final error = Errors.getSdkError(Errors.USER_REJECTED).toSignError();
response = response.copyWith(
error: JsonRpcError(code: error.code, message: error.message),
);
}
_handleResponseForTopic(topic, response);
}
Future<void> ethSignTypedData(String topic, dynamic parameters) async {
debugPrint('ethSignTypedData request: $parameters');
final pRequest = walletKit.pendingRequests.getAll().last;
final address = EthUtils.getAddressFromSessionRequest(pRequest);
final data = EthUtils.getDataFromSessionRequest(pRequest) as String;
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
final isApproved = await MethodsUtils.requestApproval(
data,
method: pRequest.method,
chainId: pRequest.chainId,
address: address,
transportType: pRequest.transportType.name,
verifyContext: pRequest.verifyContext,
);
if (isApproved) {
try {
final keys = wcKeyService.getKeysForChain(appStore.wallet!);
final signature = EthSigUtil.signTypedData(
privateKey: keys[0].privateKey,
jsonData: data,
version: TypedDataVersion.V4,
);
response = response.copyWith(result: signature);
} catch (e) {
debugPrint('ethSignTypedData error $e');
final error = Errors.getSdkError(Errors.MALFORMED_REQUEST_PARAMS);
response = response.copyWith(
error: JsonRpcError(code: error.code, message: error.message),
);
}
} else {
final error = Errors.getSdkError(Errors.USER_REJECTED).toSignError();
response = response.copyWith(
error: JsonRpcError(code: error.code, message: error.message),
);
}
_handleResponseForTopic(topic, response);
}
Future<void> ethSignTypedDataV4(String topic, dynamic parameters) async {
debugPrint('ethSignTypedDataV4 request: $parameters');
final permitRequestMessage = await extractPermitData(parameters);
final pRequest = walletKit.pendingRequests.getAll().last;
final address = EthUtils.getAddressFromSessionRequest(pRequest);
final data = EthUtils.getDataFromSessionRequest(pRequest) as String;
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
final isApproved = await MethodsUtils.requestApproval(
permitRequestMessage,
method: pRequest.method,
chainId: pRequest.chainId,
address: address,
transportType: pRequest.transportType.name,
verifyContext: pRequest.verifyContext,
);
if (isApproved) {
try {
final keys = wcKeyService.getKeysForChain(appStore.wallet!);
final signature = EthSigUtil.signTypedData(
privateKey: keys[0].privateKey,
jsonData: data,
version: TypedDataVersion.V4,
);
response = response.copyWith(result: signature);
} catch (e) {
debugPrint('ethSignTypedDataV4 error $e');
final error = Errors.getSdkError(Errors.MALFORMED_REQUEST_PARAMS);
response = response.copyWith(
error: JsonRpcError(code: error.code, message: error.message),
);
}
} else {
response = response.copyWith(
error: JsonRpcError(code: 5002, message: S.current.user_rejected_method),
);
}
_handleResponseForTopic(topic, response);
}
Future<void> ethSignTransaction(String topic, dynamic parameters) async {
debugPrint('ethSignTransaction request: $parameters');
final SessionRequest pRequest = walletKit.pendingRequests.getAll().last;
final data = EthUtils.getTransactionFromSessionRequest(pRequest);
if (data == null) return;
final address = EthUtils.getAddressFromSessionRequest(pRequest);
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
final transaction = await _approveTransaction(
data,
method: pRequest.method,
chainId: pRequest.chainId,
address: address,
transportType: pRequest.transportType.name,
verifyContext: pRequest.verifyContext,
);
if (transaction is Transaction) {
try {
// Load the private key
final keys = wcKeyService.getKeysForChain(appStore.wallet!);
final credentials = EthPrivateKey.fromHex(keys[0].privateKey);
final chainId = getChainId().split(':').last;
final signature = await ethClient.signTransaction(
credentials,
transaction,
chainId: int.parse(chainId),
);
// Sign the transaction
final signedTx = bytesToHex(signature, include0x: true);
response = response.copyWith(result: signedTx);
} on RPCError catch (e) {
debugPrint('ethSignTransaction error $e');
response = response.copyWith(
error: JsonRpcError(code: e.errorCode, message: e.message),
);
} catch (e) {
debugPrint('ethSignTransaction error $e');
final error = Errors.getSdkError(Errors.MALFORMED_REQUEST_PARAMS);
response = response.copyWith(
error: JsonRpcError(code: error.code, message: error.message),
);
}
} else {
response = response.copyWith(error: transaction as JsonRpcError);
}
_handleResponseForTopic(topic, response);
}
Future<void> ethSendTransaction(String topic, dynamic parameters) async {
debugPrint('ethSendTransaction request: $parameters');
final SessionRequest pRequest = walletKit.pendingRequests.getAll().last;
final data = EthUtils.getTransactionFromSessionRequest(pRequest);
if (data == null) return;
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
final transaction = await _approveTransaction(
data,
method: pRequest.method,
chainId: pRequest.chainId,
transportType: pRequest.transportType.name,
verifyContext: pRequest.verifyContext,
);
if (transaction is Transaction) {
try {
// Load the private key
final keys = wcKeyService.getKeysForChain(appStore.wallet!);
final credentials = EthPrivateKey.fromHex(keys[0].privateKey);
final chainId = getChainId().split(':').last;
final signedTx = await ethClient.sendTransaction(
credentials,
transaction,
chainId: int.parse(chainId),
);
response = response.copyWith(result: signedTx);
} on RPCError catch (e) {
debugPrint('ethSendTransaction error $e');
response = response.copyWith(
error: JsonRpcError(code: e.errorCode, message: e.message),
);
} catch (e) {
debugPrint('ethSendTransaction error $e');
final error = Errors.getSdkError(Errors.MALFORMED_REQUEST_PARAMS);
response = response.copyWith(
error: JsonRpcError(code: error.code, message: error.message),
);
}
} else {
response = response.copyWith(error: transaction as JsonRpcError);
}
_handleResponseForTopic(topic, response);
}
void _handleResponseForTopic(String topic, JsonRpcResponse<dynamic> response) async {
final session = walletKit.sessions.get(topic);
try {
await walletKit.respondSessionRequest(
topic: topic,
response: response,
);
MethodsUtils.handleRedirect(
topic,
session!.peer.metadata.redirect,
response.error?.message,
response.error == null,
);
} on ReownSignError catch (error) {
MethodsUtils.handleRedirect(
topic,
session!.peer.metadata.redirect,
error.message,
);
}
}
Future<dynamic> _approveTransaction(
Map<String, dynamic> transactionJson, {
String? title,
String? method,
String? chainId,
String? address,
VerifyContext? verifyContext,
required String transportType,
}) async {
Transaction transaction = transactionJson.toTransaction();
final gasPrice = await ethClient.getGasPrice();
try {
final gasLimit = await ethClient.estimateGas(
sender: transaction.from,
to: transaction.to,
value: transaction.value,
data: transaction.data,
gasPrice: gasPrice,
);
transaction = transaction.copyWith(
gasPrice: gasPrice,
maxGas: gasLimit.toInt(),
);
} on RPCError catch (e) {
return JsonRpcError(code: e.errorCode, message: e.message);
}
final gweiGasPrice = (transaction.gasPrice?.getInWei ?? BigInt.zero) / BigInt.from(1000000000);
final amount = (transaction.value?.getInWei ?? BigInt.zero) / BigInt.from(1e18);
final txMessageText = '${S.current.value}: ${amount.toStringAsFixed(9)} ETH\n'
'${S.current.from}: ${transaction.from?.hex}\n'
'${S.current.to}: ${transaction.to?.hex}';
if (await MethodsUtils.requestApproval(
txMessageText,
title: title,
method: method,
chainId: chainId,
address: address,
transportType: transportType,
verifyContext: verifyContext,
extraModels: [
WCConnectionModel(
title: S.current.gas_price,
elements: ['${gweiGasPrice.toStringAsFixed(2)} GWEI'],
),
],
)) {
return transaction;
}
return JsonRpcError(code: 5002, message: S.current.user_rejected_method);
}
void _onSessionRequest(SessionRequestEvent? args) async {
if (args != null && args.chainId == getChainId()) {
debugPrint('_onSessionRequest ${args.toString()}');
final handler = sessionRequestHandlers[args.method];
if (handler != null) {
await handler(args.topic, args.params);
}
}
}
bool isValidSignature(String hexSignature, String message, String hexAddress) {
try {
debugPrint('isValidSignature: $hexSignature, $message, $hexAddress');
final recoveredAddress = EthSigUtil.recoverPersonalSignature(
signature: hexSignature,
message: utf8.encode(message),
);
debugPrint('recoveredAddress: $recoveredAddress');
final recoveredAddress2 = EthSigUtil.recoverSignature(
signature: hexSignature,
message: utf8.encode(message),
);
debugPrint('recoveredAddress2: $recoveredAddress2');
final isValid = recoveredAddress == hexAddress;
return isValid;
} catch (e) {
return false;
}
}
Future<String> extractPermitData(dynamic data) async {
if (data is List && data.length >= 2) {
final typedData = jsonDecode(data[1] as String) as Map<String, dynamic>;
// Extracting domain details.
final domain = typedData['domain'] ?? {} as Map<String, dynamic>;
final domainName = domain['name']?.toString() ?? '';
final verifyingContract = domain['verifyingContract']?.toString() ?? '';
final chainId = domain['chainId']?.toString() ?? '';
final chainName = getChainNameBasedOnWalletType(appStore.wallet!.type);
// Get the primary type.
final primaryType = typedData['primaryType']?.toString() ?? '';
// Extracting message details.
final message = typedData['message'] ?? {} as Map<String, dynamic>;
final details = message['details'] ?? {} as Map<String, dynamic>;
final amount = details['amount']?.toString() ?? '';
final expirationRaw = details['expiration']?.toString() ?? '';
final nonce = details['nonce']?.toString() ?? '';
final tokenAddress = details['token']?.toString() ?? '';
final token = await getTokenDetails(tokenAddress, chainName);
final spender = message['spender']?.toString() ?? '';
final sigDeadlineRaw = message['sigDeadline']?.toString() ?? '';
// Converting expiration and sigDeadline from Unix time (seconds) to DateTime.
DateTime? expirationDate;
DateTime? sigDeadlineDate;
try {
if (expirationRaw.isNotEmpty) {
final int expirationInt = int.parse(expirationRaw);
expirationDate = DateTime.fromMillisecondsSinceEpoch(expirationInt * 1000);
}
if (sigDeadlineRaw.isNotEmpty) {
final int sigDeadlineInt = int.parse(sigDeadlineRaw);
sigDeadlineDate = DateTime.fromMillisecondsSinceEpoch(sigDeadlineInt * 1000);
}
} catch (e) {
// Parsing failed; we leave dates as null.
}
final permitData = {
'domainName': domainName,
'chainId': chainId,
'verifyingContract': verifyingContract,
'primaryType': primaryType,
'token': token,
'amount': amount,
'expiration': expirationDate,
'nonce': nonce,
'spender': spender,
'sigDeadline': sigDeadlineDate,
};
return 'Domain: ${permitData['domainName']}'
'Chain ID: ${permitData['chainId']}'
'Verifying Contract: ${permitData['verifyingContract']}'
'Primary Type: ${permitData['primaryType']}'
'Token: ${permitData['token']}'
'Expiration: ${permitData['expiration'] != null ? permitData['expiration'] : 'N/A'}'
'Spender: ${permitData['spender']}'
'Signature Deadline: ${permitData['sigDeadline'] != null ? permitData['sigDeadline'] : 'N/A'}';
}
return '';
}
Future<String> getTokenDetails(String contractAddress, String chainName) async {
final uri = Uri.https(
'deep-index.moralis.io',
'/api/v2.2/erc20/metadata',
{
"chain": chainName,
"addresses": contractAddress,
},
);
final response = await http.get(
uri,
headers: {
"Accept": "application/json",
"X-API-Key": secrets.moralisApiKey,
},
);
final decodedResponse = jsonDecode(response.body)[0] as Map<String, dynamic>;
final symbol = (decodedResponse['symbol'] ?? '') as String;
final name = decodedResponse['name'] ?? '';
return '$name ($symbol)';
}
}

View file

@ -0,0 +1,31 @@
enum EVMSupportedMethods {
ethSign,
ethSignTransaction,
ethSignTypedData,
ethSignTypedDataV4,
switchChain,
addChain,
personalSign,
ethSendTransaction;
String get name {
switch (this) {
case ethSign:
return 'eth_sign';
case ethSignTransaction:
return 'eth_signTransaction';
case ethSignTypedData:
return 'eth_signTypedData';
case ethSignTypedDataV4:
return 'eth_signTypedData_v4';
case switchChain:
return 'wallet_switchEthereumChain';
case addChain:
return 'wallet_addEthereumChain';
case personalSign:
return 'personal_sign';
case ethSendTransaction:
return 'eth_sendTransaction';
}
}
}

View file

@ -0,0 +1,22 @@
enum SolanaChainId { mainnet, devnet, testnet }
extension SolanaChainIdX on SolanaChainId {
String chain() {
String name = '';
switch (this) {
case SolanaChainId.mainnet:
name = '4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ';
// '5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';
break;
case SolanaChainId.devnet:
name = 'EtWTRABZaYq6iMfeYKouRu166VU2xqa1';
break;
case SolanaChainId.testnet:
name = '4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z';
break;
}
return 'solana:$name';
}
}

View file

@ -0,0 +1,287 @@
import 'dart:convert';
import 'package:blockchain_utils/base58/base58.dart';
import 'package:blockchain_utils/blockchain_utils.dart' as blockchain_utils;
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/chain_service/solana/solana_supported_methods.dart';
import 'package:flutter/material.dart';
import 'package:on_chain/solana/solana.dart';
import 'package:reown_walletkit/reown_walletkit.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/chain_service/solana/solana_chain_id.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/key_service/wallet_connect_key_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/utils/method_utils.dart';
import 'package:cake_wallet/store/app_store.dart';
class SolanaChainService {
Map<String, dynamic Function(String, dynamic)> get solanaRequestHandlers => {
SolanaSupportedMethods.solSignMessage.name: solanaSignMessage,
SolanaSupportedMethods.solSignTransaction.name: solanaSignTransaction,
SolanaSupportedMethods.solSignAllTransaction.name: solanaSignAllTransaction,
};
SolanaChainService({
required this.appStore,
required this.bottomSheetService,
required this.walletKit,
required this.wcKeyService,
required this.reference,
}) {
for (var handler in solanaRequestHandlers.entries) {
walletKit.registerRequestHandler(
chainId: getChainId(),
method: handler.key,
handler: handler.value,
);
}
}
final AppStore appStore;
final BottomSheetService bottomSheetService;
final ReownWalletKit walletKit;
final WalletConnectKeyService wcKeyService;
final SolanaChainId reference;
String getChainId() => reference.chain();
Future<void> solanaSignMessage(String topic, dynamic parameters) async {
debugPrint('solanaSignMessage request: $parameters');
final pRequest = walletKit.pendingRequests.getAll().last;
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
try {
final params = parameters as Map<String, dynamic>;
final message = params['message'].toString();
final privateKey = _getSolanaPrivateKey();
// it's sent as base58 encoded from the dapp
final base58Decoded = base58.decode(message);
final decodedMessage = utf8.decode(base58Decoded);
final isApproved = await MethodsUtils.requestApproval(
decodedMessage,
method: pRequest.method,
chainId: pRequest.chainId,
address: privateKey.publicKey().toAddress().address,
transportType: pRequest.transportType.name,
);
if (isApproved) {
final signedBytes = await privateKey.sign(base58Decoded);
final signature = blockchain_utils.Base58Encoder.encode(signedBytes);
response = response.copyWith(result: {'signature': signature});
} else {
final error = Errors.getSdkError(Errors.USER_REJECTED);
response = response.copyWith(
error: JsonRpcError(code: error.code, message: error.message),
);
}
//
} catch (e) {
debugPrint('solanaSignMessage error $e');
final error = Errors.getSdkError(Errors.MALFORMED_REQUEST_PARAMS);
response = response.copyWith(
error: JsonRpcError(code: error.code, message: error.message),
);
}
await walletKit.respondSessionRequest(topic: topic, response: response);
_handleResponseForTopic(topic, response);
}
Future<void> solanaSignTransaction(String topic, dynamic parameters) async {
debugPrint('solanaSignTransaction: ${jsonEncode(parameters)}');
final pRequest = walletKit.pendingRequests.getAll().last;
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
try {
final params = parameters as Map<String, dynamic>;
final privateKey = _getSolanaPrivateKey();
final beautifiedTrx = const JsonEncoder.withIndent(' ').convert(params);
SolanaTransaction unSignedTransaction;
if (params.containsKey('transaction')) {
final transaction = params['transaction'] as String;
final transactionBytes = base64.decode(transaction);
unSignedTransaction = SolanaTransaction.deserialize(transactionBytes);
} else {
final feePayer = params['feePayer'].toString();
final recentBlockHash = params['recentBlockhash'].toString();
final instructionsList = params['instructions'] as List<dynamic>;
final instructions = instructionsList.map((json) {
return (json as Map<String, dynamic>).toInstruction();
}).toList();
unSignedTransaction = SolanaTransaction(
payerKey: SolAddress(feePayer),
instructions: instructions,
recentBlockhash: SolAddress(recentBlockHash),
);
}
final isApproved = await MethodsUtils.requestApproval(
beautifiedTrx,
method: pRequest.method,
chainId: pRequest.chainId,
address: privateKey.publicKey().toAddress().address,
transportType: pRequest.transportType.name,
);
if (isApproved) {
final signedTx = await privateKey.sign(unSignedTransaction.serializeMessage());
final signature = Base58Encoder.encode(signedTx.toList(growable: false));
response = response.copyWith(result: {'signature': signature});
} else {
final error = Errors.getSdkError(Errors.USER_REJECTED);
response = response.copyWith(
error: JsonRpcError(code: error.code, message: error.message),
);
}
} catch (e, s) {
debugPrint('solanaSignTransaction error $e, $s');
final error = Errors.getSdkError(Errors.MALFORMED_REQUEST_PARAMS);
response = response.copyWith(
error: JsonRpcError(code: error.code, message: error.message),
);
}
await walletKit.respondSessionRequest(topic: topic, response: response);
_handleResponseForTopic(topic, response);
}
Future<void> solanaSignAllTransaction(String topic, dynamic parameters) async {
debugPrint('solanaSignAllTransaction: ${jsonEncode(parameters)}');
final pRequest = walletKit.pendingRequests.getAll().last;
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
try {
final params = parameters as Map<String, dynamic>;
final beautifiedTrx = const JsonEncoder.withIndent(' ').convert(params);
final privateKey = _getSolanaPrivateKey();
final isApproved = await MethodsUtils.requestApproval(
beautifiedTrx,
method: pRequest.method,
chainId: pRequest.chainId,
address: privateKey.publicKey().toAddress().address,
transportType: pRequest.transportType.name,
);
if (isApproved) {
if (params.containsKey('transactions')) {
final transactions = params['transactions'] as List<String>;
List<String> signedTransactions = [];
for (var transaction in transactions) {
final transactionBytes = base64.decode(transaction);
final unsignedTx = SolanaTransaction.deserialize(transactionBytes);
final serializedTx = await privateKey.sign(unsignedTx.serializeMessage());
unsignedTx.addSignature(privateKey.publicKey().toAddress(), serializedTx);
final reEncodedTx = unsignedTx.serializeString(
encoding: TransactionSerializeEncoding.base64,
);
signedTransactions.add(reEncodedTx);
}
response = response.copyWith(result: {'transactions': signedTransactions});
}
} else {
final error = Errors.getSdkError(Errors.USER_REJECTED);
response = response.copyWith(
error: JsonRpcError(code: error.code, message: error.message),
);
}
} catch (e, s) {
debugPrint('solanaSignAllTransactions error $e, $s');
final error = Errors.getSdkError(Errors.MALFORMED_REQUEST_PARAMS);
response = response.copyWith(
error: JsonRpcError(code: error.code, message: error.message),
);
}
await walletKit.respondSessionRequest(topic: topic, response: response);
_handleResponseForTopic(topic, response);
}
SolanaPrivateKey _getSolanaPrivateKey() {
final keys = wcKeyService.getKeysForChain(appStore.wallet!);
return SolanaPrivateKey.fromSeedHex(keys[0].privateKey);
}
void _handleResponseForTopic(String topic, JsonRpcResponse<dynamic> response) async {
final session = walletKit.sessions.get(topic);
try {
await walletKit.respondSessionRequest(topic: topic, response: response);
MethodsUtils.handleRedirect(
topic,
session!.peer.metadata.redirect,
response.error?.message,
);
} on ReownSignError catch (error) {
if (error.message.contains('No matching key')) {
MethodsUtils.handleRedirect(
topic,
session!.peer.metadata.redirect,
'${S.current.error_while_processing} ${S.current.youCanGoBackToYourDapp}',
);
} else {
MethodsUtils.handleRedirect(
topic,
session!.peer.metadata.redirect,
error.message,
);
}
}
}
}
extension on Map<String, dynamic> {
TransactionInstruction toInstruction() {
final programId = this['programId'] as String;
final data = (this['data'] as List).map((e) => e as int).toList();
// final data58 = base58.encode(Uint8List.fromList(data));
// final dataBytes = ByteArray.fromBase58(data58);
final keys = this['keys'] as List;
return TransactionInstruction.fromBytes(
programId: SolAddress(programId),
instructionBytes: data,
keys: keys.map((k) {
final kParams = (k as Map<String, dynamic>);
return AccountMeta(
publicKey:
SolanaPublicKey.fromBytes(base58.decode(kParams['pubkey'] as String)).toAddress(),
isWritable: kParams['isWritable'] as bool,
isSigner: kParams['isSigner'] as bool,
);
}).toList(),
);
}
}

View file

@ -0,0 +1,16 @@
enum SolanaSupportedMethods {
solSignMessage,
solSignTransaction,
solSignAllTransaction;
String get name {
switch (this) {
case solSignMessage:
return 'solana_signMessage';
case solSignTransaction:
return 'solana_signTransaction';
case solSignAllTransaction:
return 'solana_signAllTransactions';
}
}
}

View file

@ -0,0 +1,37 @@
import 'dart:convert';
class ChainKeyModel {
final List<String> chains;
final String privateKey;
final String publicKey;
ChainKeyModel({
required this.chains,
required this.privateKey,
required this.publicKey,
});
String get namespace {
if (chains.isNotEmpty) {
return chains.first.split(':').first;
}
return '';
}
Map<String, dynamic> toJson() => {
'chains': chains,
'privateKey': privateKey,
'publicKey': privateKey,
};
factory ChainKeyModel.fromJson(Map<String, dynamic> json) {
return ChainKeyModel(
chains: (json['chains'] as List).map((e) => '$e').toList(),
privateKey: json['privateKey'] as String,
publicKey: json['publicKey'] as String,
);
}
@override
String toString() => jsonEncode(toJson());
}

View file

@ -1,8 +1,8 @@
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/solana/solana.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/key_service/chain_key_model.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart';

View file

@ -0,0 +1,623 @@
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:cw_core/wallet_type.dart';
import 'package:eth_sig_util/util/utils.dart';
import 'package:flutter/material.dart';
import 'package:mobx/mobx.dart';
import 'package:reown_walletkit/reown_walletkit.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/chain_service/eth/evm_chain_id.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/chain_service/eth/evm_chain_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/key_service/chain_key_model.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/key_service/wallet_connect_key_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/utils/eth_utils.dart';
import 'package:cake_wallet/src/screens/wallet_connect/utils/method_utils.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/wc_connection_request_widget.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/bottom_sheet/bottom_sheet_message_display_widget.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/wc_request_widget.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/wc_session_auth_request_widget.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'bottom_sheet_service.dart';
import 'chain_service/solana/solana_chain_id.dart';
import 'chain_service/solana/solana_chain_service.dart';
part 'walletkit_service.g.dart';
class WalletKitService = WalletKitServiceBase with _$WalletKitService;
abstract class WalletKitServiceBase with Store {
WalletKitServiceBase(
this._bottomSheetHandler,
this.walletKeyService,
this.appStore,
this.sharedPreferences,
) : pairings = ObservableList<PairingInfo>(),
sessions = ObservableList<SessionData>(),
auth = ObservableList<PendingSessionAuthRequest>(),
isInitialized = false;
final AppStore appStore;
final SharedPreferences sharedPreferences;
final BottomSheetService _bottomSheetHandler;
final WalletConnectKeyService walletKeyService;
late ReownWalletKit _walletKit;
@observable
bool isInitialized;
/// The list of requests from the dapp
/// Potential types include, but aren't limited to:
/// [SessionProposalEvent], [SessionAuthRequest]
@observable
ObservableList<PairingInfo> pairings;
@observable
ObservableList<SessionData> sessions;
@observable
ObservableList<PendingSessionAuthRequest> auth;
@action
void create() {
// Create the walletkit client
_walletKit = ReownWalletKit(
core: ReownCore(
projectId: secrets.walletConnectProjectId,
),
metadata: const PairingMetadata(
name: 'Cake Wallet',
description: 'Cake Wallet',
url: 'https://cakewallet.com',
icons: ['https://cakewallet.com/assets/image/cake_logo.png'],
),
);
_walletKit.core.addLogListener(_logListener);
// Setup our listeners
log('Created instance of walletKit');
_walletKit.core.pairing.onPairingInvalid.subscribe(_onPairingInvalid);
_walletKit.core.pairing.onPairingCreate.subscribe(_onPairingCreate);
_walletKit.core.relayClient.onRelayClientError.subscribe(_onRelayClientError);
_walletKit.core.relayClient.onRelayClientMessage.subscribe(_onRelayClientMessage);
_walletKit.onSessionProposal.subscribe(_onSessionProposal);
_walletKit.onSessionProposalError.subscribe(_onSessionProposalError);
_walletKit.onSessionConnect.subscribe(_onSessionConnect);
_walletKit.onSessionAuthRequest.subscribe(_onSessionAuthRequest);
_walletKit.pairings.onSync.subscribe(_onPairingsSync);
_walletKit.core.pairing.onPairingDelete.subscribe(_onPairingDelete);
_walletKit.core.pairing.onPairingExpire.subscribe(_onPairingDelete);
// Setup our accounts
List<ChainKeyModel> chainKeys = walletKeyService.getKeys(appStore.wallet!);
for (final chainKey in chainKeys) {
for (final chainId in chainKey.chains) {
final chainNameSpace = getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type);
if (chainNameSpace == chainId) {
final account = '$chainId:${chainKey.publicKey}';
debugPrint('registerAccount $account');
_walletKit.registerAccount(
chainId: chainId,
accountAddress: chainKey.publicKey,
);
}
}
}
}
void _logListener(String event) {
debugPrint('[WalletKit] $event');
}
@action
Future<void> init() async {
// Await the initialization of walletKit
debugPrint('Intializing walletKit');
if (!isInitialized) {
try {
await _walletKit.init();
debugPrint('Initialized');
isInitialized = true;
} catch (e) {
debugPrint('init Error: ${e.toString()}');
isInitialized = false;
}
}
await _emitEvent();
_refreshPairings();
final newSessions = _walletKit.sessions.getAll();
sessions.addAll(newSessions);
final newAuthRequests = _walletKit.sessionAuthRequests.getAll();
auth.addAll(newAuthRequests);
if (isEVMCompatibleChain(appStore.wallet!.type)) {
for (final cId in EVMChainId.values) {
EvmChainServiceImpl(
reference: cId,
appStore: appStore,
wcKeyService: walletKeyService,
bottomSheetService: _bottomSheetHandler,
walletKit: _walletKit,
);
}
}
if (appStore.wallet!.type == WalletType.solana) {
for (final cId in SolanaChainId.values) {
SolanaChainService(
reference: cId,
appStore: appStore,
wcKeyService: walletKeyService,
bottomSheetService: _bottomSheetHandler,
walletKit: _walletKit,
);
}
}
}
@action
Future<void> _emitEvent() async {
final isOnline = _walletKit.core.connectivity.isOnline.value;
if (!isOnline) {
await Future.delayed(const Duration(milliseconds: 500));
_emitEvent();
return;
}
final sessions = _walletKit.sessions.getAll();
for (var session in sessions) {
final chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
for (var chain in chainKeys) {
for (var chainID in chain.chains) {
try {
final events = NamespaceUtils.getNamespacesEventsForChain(
chainId: chainID,
namespaces: session.namespaces,
);
if (events.contains('accountsChanged')) {
final chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
_walletKit.emitSessionEvent(
topic: session.topic,
chainId: chainID,
event: SessionEventParams(
name: 'accountsChanged',
data: [chainKeys.first.publicKey],
),
);
}
} catch (_) {}
}
}
}
}
@action
FutureOr<void> onDispose() {
log('walletKit dispose');
_walletKit.core.removeLogListener(_logListener);
_walletKit.core.pairing.onPairingInvalid.unsubscribe(_onPairingInvalid);
_walletKit.core.pairing.onPairingCreate.unsubscribe(_onPairingCreate);
_walletKit.core.relayClient.onRelayClientError.unsubscribe(_onRelayClientError);
_walletKit.core.relayClient.onRelayClientMessage.unsubscribe(_onRelayClientMessage);
_walletKit.onSessionProposal.unsubscribe(_onSessionProposal);
_walletKit.onSessionProposalError.unsubscribe(_onSessionProposalError);
_walletKit.onSessionConnect.unsubscribe(_onSessionConnect);
_walletKit.onSessionAuthRequest.unsubscribe(_onSessionAuthRequest);
_walletKit.pairings.onSync.unsubscribe(_onPairingsSync);
_walletKit.core.pairing.onPairingDelete.unsubscribe(_onPairingDelete);
_walletKit.core.pairing.onPairingExpire.unsubscribe(_onPairingDelete);
isInitialized = false;
}
ReownWalletKit get walletKit => _walletKit;
void _onRelayClientMessage(MessageEvent? event) async {
if (event != null) {
final jsonObject = await EthUtils.decodeMessageEvent(event);
debugPrint('_onRelayClientMessage $jsonObject');
if (jsonObject is JsonRpcRequest) {
debugPrint(jsonObject.id.toString());
debugPrint(jsonObject.method);
if (jsonObject.method == 'wc_sessionDelete') {
await disconnectSession(topic: event.topic);
}
}
}
}
void _onPairingsSync(StoreSyncEvent? args) {
if (args != null) {
_refreshPairings();
}
}
void _onPairingDelete(PairingEvent? event) {
_refreshPairings();
}
@action
Future<void> _onSessionProposal(SessionProposalEvent? args) async {
debugPrint('_onSessionProposal ${jsonEncode(args?.params)}');
if (args != null) {
final proposer = args.params.proposer;
final result = (await _bottomSheetHandler.queueBottomSheet(
widget: WCRequestWidget(
verifyContext: args.verifyContext,
child: WCConnectionRequestWidget(
proposalData: args.params,
verifyContext: args.verifyContext,
requester: proposer,
walletKeyService: walletKeyService,
walletKit: walletKit,
appStore: appStore,
),
),
)) ??
WCBottomSheetResult.reject;
if (result != WCBottomSheetResult.reject) {
try {
await _walletKit.approveSession(
id: args.id,
namespaces: NamespaceUtils.regenerateNamespacesWithChains(
args.params.generatedNamespaces!,
),
sessionProperties: args.params.sessionProperties,
);
} on ReownSignError catch (error) {
MethodsUtils.handleRedirect(
'',
proposer.metadata.redirect,
error.message,
);
}
} else {
final error = Errors.getSdkError(Errors.USER_REJECTED).toSignError();
await _walletKit.rejectSession(id: args.id, reason: error);
await _walletKit.core.pairing.disconnect(topic: args.params.pairingTopic);
MethodsUtils.handleRedirect(
'',
proposer.metadata.redirect,
error.message,
);
}
}
}
@action
Future<void> _onSessionProposalError(SessionProposalErrorEvent? args) async {
debugPrint('_onSessionProposalError $args');
if (args != null) {
String errorMessage = args.error.message;
if (args.error.code == 5100) {
errorMessage =
errorMessage.replaceFirst('${S.current.requested}:', '\n\n${S.current.requested}:');
errorMessage =
errorMessage.replaceFirst('${S.current.supported}:', '\n\n${S.current.supported}:');
}
MethodsUtils.goBackModal(
title: S.current.error,
message: errorMessage,
success: false,
);
}
}
@action
Future<void> _onSessionConnect(SessionConnect? args) async {
if (args != null) {
final session = jsonEncode(args.session.toJson());
debugPrint('_onSessionConnect $session');
await savePairingTopicToLocalStorage(args.session.pairingTopic);
sessions.add(args.session);
_refreshPairings();
MethodsUtils.handleRedirect(
args.session.topic,
args.session.peer.metadata.redirect,
'',
true,
);
}
}
@action
void _onRelayClientError(ErrorEvent? args) {
debugPrint('_onRelayClientError ${args?.error}');
// _bottomSheetHandler.queueBottomSheet(
// isModalDismissible: true,
// widget: BottomSheetMessageDisplayWidget(
// message: "WC RelayClient Error: ${args?.error}",
// ),
// );
}
@action
void _onPairingInvalid(PairingInvalidEvent? args) {
debugPrint('_onPairingInvalid $args');
_bottomSheetHandler.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(
message: '${S.current.pairingInvalidEvent}: $args',
),
);
}
@action
void _onPairingCreate(PairingEvent? args) {
debugPrint('_onPairingCreate $args');
}
Future<void> _onSessionAuthRequest(SessionAuthRequest? args) async {
if (args != null) {
final SessionAuthPayload authPayload = args.authPayload;
final jsonPyaload = jsonEncode(authPayload.toJson());
debugPrint('_onSessionAuthRequest $jsonPyaload');
final chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
final supportedChains = chainKeys.first.chains;
final supportedMethods = getChainSupportedMethodsOnWalletType(appStore.wallet!.type);
final newAuthPayload = AuthSignature.populateAuthPayload(
authPayload: authPayload,
chains: supportedChains.toList(),
methods: supportedMethods.toList(),
);
final cacaoRequestPayload = CacaoRequestPayload.fromSessionAuthPayload(
newAuthPayload,
);
final List<Map<String, dynamic>> formattedMessages = [];
for (var chain in newAuthPayload.chains) {
final chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
final iss = 'did:pkh:$chain:${chainKeys.first.publicKey}';
final message = _walletKit.formatAuthMessage(
iss: iss,
cacaoPayload: cacaoRequestPayload,
);
formattedMessages.add({iss: message});
}
final WCBottomSheetResult result = (await _bottomSheetHandler.queueBottomSheet(
widget: WCSessionAuthRequestWidget(
child: WCConnectionRequestWidget(
sessionAuthPayload: newAuthPayload,
verifyContext: args.verifyContext,
requester: args.requester,
walletKeyService: walletKeyService,
walletKit: _walletKit,
appStore: appStore,
),
),
) as WCBottomSheetResult?) ??
WCBottomSheetResult.reject;
if (result != WCBottomSheetResult.reject) {
final chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
final privateKey = '0x${chainKeys.first.privateKey}';
final credentials = EthPrivateKey.fromHex(privateKey);
//
final messageToSign = formattedMessages.length;
final count = (result == WCBottomSheetResult.one) ? 1 : messageToSign;
//
final List<Cacao> cacaos = [];
for (var i = 0; i < count; i++) {
final iss = formattedMessages[i].keys.first;
final message = formattedMessages[i].values.first as String;
final signature = credentials.signPersonalMessageToUint8List(
Uint8List.fromList(message.codeUnits),
);
final hexSignature = bytesToHex(signature, include0x: true);
cacaos.add(
AuthSignature.buildAuthObject(
requestPayload: cacaoRequestPayload,
signature: CacaoSignature(t: CacaoSignature.EIP191, s: hexSignature),
iss: iss,
),
);
}
//
try {
final session = await _walletKit.approveSessionAuthenticate(
id: args.id,
auths: cacaos,
);
debugPrint('_onSessionAuthRequest - approveSessionAuthenticate $session');
MethodsUtils.handleRedirect(
session.topic,
session.session?.peer.metadata.redirect,
'',
true,
);
} on ReownSignError catch (error) {
MethodsUtils.handleRedirect(
args.topic,
args.requester.metadata.redirect,
error.message,
);
}
} else {
final error = Errors.getSdkError(Errors.USER_REJECTED_AUTH);
await _walletKit.rejectSessionAuthenticate(
id: args.id,
reason: error.toSignError(),
);
MethodsUtils.handleRedirect(
args.topic,
args.requester.metadata.redirect,
error.message,
);
}
}
}
@action
Future<void> deletePairing({required String topic}) async {
final topicSessions = sessions.where((element) => element.pairingTopic == topic);
await _walletKit.core.pairing.disconnect(topic: topic);
for (var session in topicSessions) {
await _walletKit.disconnectSession(
topic: session.topic,
reason: Errors.getSdkError(Errors.USER_DISCONNECTED).toSignError(),
);
}
}
@action
Future<void> disconnectSession({required String topic}) async {
await walletKit.disconnectSession(
topic: topic,
reason: Errors.getSdkError(Errors.USER_DISCONNECTED).toSignError(),
);
}
@action
Future<void> updateSession({
required String topic,
required Map<String, Namespace> namespaces,
}) async {
await walletKit.updateSession(topic: topic, namespaces: namespaces);
}
@action
Future<void> extendSession({required String topic}) async {
await walletKit.extendSession(topic: topic);
}
@action
Future<void> pairWithUri(Uri uri) async {
try {
debugPrint('pairWithUri - Pairing with URI: $uri');
await _walletKit.pair(uri: uri);
} on ReownSignError catch (e) {
_bottomSheetHandler.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(message: e.message),
);
} catch (e) {
_bottomSheetHandler.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(message: e.toString()),
);
}
}
@action
void _refreshPairings() {
debugPrint('_refreshPairings - Refreshing pairings');
pairings.clear();
final allPairings = _walletKit.pairings.getAll();
final keyForWallet = getKeyForStoringTopicsForWallet();
if (keyForWallet.isEmpty) return;
final currentTopicsForWallet = getPairingTopicsForWallet(keyForWallet);
final filteredPairings = allPairings.where(
(pairing) {
bool isInCurrentTopics = currentTopicsForWallet.contains(pairing.topic);
bool isActive = pairing.active;
return isInCurrentTopics && isActive;
},
).toList();
pairings.addAll(filteredPairings);
}
@action
List<SessionData> getSessionsForPairingInfo(PairingInfo pairing) {
return sessions.where((element) => element.pairingTopic == pairing.topic).toList();
}
String getKeyForStoringTopicsForWallet() {
List<ChainKeyModel> chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
if (chainKeys.isEmpty) {
return '';
}
final keyForPairingTopic =
PreferencesKey.walletConnectPairingTopicsListForWallet(chainKeys.first.publicKey);
return keyForPairingTopic;
}
List<String> getPairingTopicsForWallet(String key) {
// Get the JSON-encoded string from shared preferences
final jsonString = sharedPreferences.getString(key);
// If the string is null, return an empty list
if (jsonString == null) {
return [];
}
// Decode the JSON string to a list of strings
final List<dynamic> jsonList = jsonDecode(jsonString) as List<dynamic>;
// Cast each item to a string
return jsonList.map((item) => item as String).toList();
}
Future<void> savePairingTopicToLocalStorage(String pairingTopic) async {
// Get key specific to the current wallet
final key = getKeyForStoringTopicsForWallet();
if (key.isEmpty) return;
// Get all pairing topics attached to this key
final pairingTopicsForWallet = getPairingTopicsForWallet(key);
bool isPairingTopicAlreadySaved = pairingTopicsForWallet.contains(pairingTopic);
debugPrint('Is Pairing Topic Saved: $isPairingTopicAlreadySaved');
if (!isPairingTopicAlreadySaved) {
// Update the list with the most recent pairing topic
pairingTopicsForWallet.add(pairingTopic);
// Convert the list of updated pairing topics to a JSON-encoded string
final jsonString = jsonEncode(pairingTopicsForWallet);
// Save the encoded string to shared preferences
await sharedPreferences.setString(key, jsonString);
}
}
}

View file

@ -0,0 +1,88 @@
import 'dart:convert';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/walletkit_service.dart';
import 'package:convert/convert.dart';
import 'package:flutter/foundation.dart';
import 'package:reown_walletkit/reown_walletkit.dart';
class EthUtils {
static String getUtf8Message(String maybeHex) {
if (maybeHex.startsWith('0x')) {
final List<int> decoded = hex.decode(
maybeHex.substring(2),
);
return utf8.decode(decoded);
}
return maybeHex;
}
static String? getAddressFromSessionRequest(SessionRequest request) {
try {
final paramsList = List<String?>.from((request.params as List));
if (request.method == 'personal_sign') {
// for `personal_sign` first value in params has to be always the message
paramsList.removeAt(0);
}
return paramsList.firstWhere((p) {
try {
EthereumAddress.fromHex(p ?? '');
return true;
} catch (e) {
return false;
}
});
} catch (e) {
debugPrint(e.toString());
return null;
}
}
static dynamic getDataFromSessionRequest(SessionRequest request) {
try {
final paramsList = List.from((request.params as List));
if (request.method == 'personal_sign') {
return paramsList.first;
}
return paramsList.firstWhere((p) {
final address = getAddressFromSessionRequest(request);
return p != address;
});
} catch (e) {
debugPrint('getDataFromSessionRequest $e');
return null;
}
}
static Map<String, dynamic>? getTransactionFromSessionRequest(
SessionRequest request,
) {
try {
final param = (request.params as List<dynamic>).first;
return param as Map<String, dynamic>;
} catch (e) {
debugPrint('getTransactionFromSessionRequest $e');
return null;
}
}
static Future<dynamic> decodeMessageEvent(MessageEvent event) async {
final walletKit = getIt<WalletKitService>().walletKit;
final payloadString = await walletKit.core.crypto.decode(
event.topic,
event.message,
);
if (payloadString == null) return null;
final data = jsonDecode(payloadString) as Map<String, dynamic>;
if (data.containsKey('method')) {
return JsonRpcRequest.fromJson(data);
} else {
return JsonRpcResponse.fromJson(data);
}
}
}

View file

@ -0,0 +1,139 @@
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/models/wc_connection_model.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/walletkit_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/wc_connection_widget.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/wc_request_widget.dart';
import 'package:flutter/material.dart';
import 'package:reown_walletkit/reown_walletkit.dart';
class MethodsUtils {
static final walletKit = getIt.get<WalletKitService>().walletKit;
static final bottomSheetService = getIt.get<BottomSheetService>();
static Future<bool> requestApproval(
String text, {
String? title,
String? method,
String? chainId,
String? address,
required String transportType,
List<WCConnectionModel> extraModels = const [],
VerifyContext? verifyContext,
}) async {
final WCBottomSheetResult result = (await bottomSheetService.queueBottomSheet(
widget: WCRequestWidget(
verifyContext: verifyContext,
child: WCConnectionWidget(
title: title ?? S.current.approve_request,
info: [
WCConnectionModel(
title: '${S.current.method}: $method\n'
'${S.current.transport_type}: ${transportType.toUpperCase()}\n'
'${S.current.chain_id}: $chainId\n'
'${S.current.address}: $address\n\n'
'${S.current.message}:',
elements: [text],
),
...extraModels,
],
),
),
) as WCBottomSheetResult?) ??
WCBottomSheetResult.reject;
return result != WCBottomSheetResult.reject;
}
static void handleRedirect(
String topic,
Redirect? redirect, [
String? error,
bool success = false,
]) {
debugPrint('handleRedirect topic: $topic, redirect: $redirect, error: $error');
openApp(
topic,
redirect,
onFail: (e) => goBackModal(
title: success ? S.current.success : S.current.error,
message: error,
success: success,
),
);
}
static void openApp(
String topic,
Redirect? redirect, {
int delay = 100,
Function(ReownSignError? error)? onFail,
}) async {
await Future.delayed(Duration(milliseconds: delay));
try {
await walletKit.redirectToDapp(
topic: topic,
redirect: redirect,
);
} on ReownSignError catch (e) {
onFail?.call(e);
}
}
static void goBackModal({
String? title,
String? message,
bool success = true,
}) async {
await bottomSheetService.queueBottomSheet(
closeAfter: success ? 3 : 0,
widget: GoBackModalWidget(
isSuccess: success,
title: title,
message: message,
),
);
}
}
class GoBackModalWidget extends StatelessWidget {
const GoBackModalWidget({
required this.isSuccess,
this.message,
this.title,
super.key,
});
final bool isSuccess;
final String? title;
final String? message;
@override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).colorScheme.background,
height: 280.0,
width: double.infinity,
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Icon(
isSuccess ? Icons.check_circle_sharp : Icons.error_outline_sharp,
color: isSuccess ? Colors.green[100] : Colors.red[100],
size: 80.0,
),
Text(
title ?? S.current.connected,
style: TextStyle(
color: Theme.of(context).appBarTheme.titleTextStyle!.color!,
fontSize: 18.0,
fontWeight: FontWeight.w600,
),
),
Text(message ?? S.current.youCanGoBackToYourDapp),
],
),
);
}
}

View file

@ -1,71 +1,76 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/connection_widget.dart';
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
import '../../../../core/wallet_connect/models/connection_model.dart';
import 'package:cake_wallet/src/screens/wallet_connect/models/wc_connection_model.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/wc_connection_widget.dart';
import 'package:flutter/material.dart';
import 'package:reown_walletkit/reown_walletkit.dart';
class ConnectionWidgetBuilder {
static List<ConnectionWidget> buildFromRequiredNamespaces(
Map<String, RequiredNamespace> requiredNamespaces,
static List<WCConnectionWidget> buildFromRequiredNamespaces(
Map<String, Namespace> generatedNamespaces,
) {
final List<ConnectionWidget> views = [];
for (final key in requiredNamespaces.keys) {
RequiredNamespace ns = requiredNamespaces[key]!;
final List<ConnectionModel> models = [];
// If the chains property is present, add the chain data to the models
if (ns.chains != null) {
models.add(ConnectionModel(title: S.current.chains, elements: ns.chains!));
}
models.add(ConnectionModel(title: S.current.methods, elements: ns.methods));
models.add(ConnectionModel(title: S.current.events, elements: ns.events));
final List<WCConnectionWidget> views = [];
for (final key in generatedNamespaces.keys) {
final namespaces = generatedNamespaces[key]!;
final chains = NamespaceUtils.getChainsFromAccounts(namespaces.accounts);
views.add(ConnectionWidget(title: key, info: models));
final List<WCConnectionModel> models = [];
// If the chains property is present, add the chain data to the models
models.add(WCConnectionModel(title: S.current.chains, elements: chains));
models.add(WCConnectionModel(title: S.current.methods, elements: namespaces.methods));
if (namespaces.events.isNotEmpty) {
models.add(WCConnectionModel(title: S.current.events, elements: namespaces.events));
}
views.add(WCConnectionWidget(title: key, info: models));
}
return views;
}
static List<ConnectionWidget> buildFromNamespaces(
static List<WCConnectionWidget> buildFromNamespaces(
String topic,
Map<String, Namespace> namespaces,
Web3Wallet web3wallet,
BuildContext context,
) {
final List<ConnectionWidget> views = [];
final List<WCConnectionWidget> views = [];
for (final key in namespaces.keys) {
final Namespace ns = namespaces[key]!;
final List<ConnectionModel> models = [];
final ns = namespaces[key]!;
final List<WCConnectionModel> models = [];
// If the chains property is present, add the chain data to the models
models.add(
ConnectionModel(
title: S.current.chains,
elements: ns.accounts,
),
);
models.add(ConnectionModel(
title: S.current.methods,
elements: ns.methods,
));
models.add(WCConnectionModel(title: S.current.accounts, elements: ns.accounts));
models.add(WCConnectionModel(title: S.current.methods, elements: ns.methods));
Map<String, void Function()> actions = {};
for (final String event in ns.events) {
actions[event] = () async {
final String chainId = NamespaceUtils.isValidChainId(key)
? key
: NamespaceUtils.getChainFromAccount(ns.accounts.first);
await web3wallet.emitSessionEvent(
topic: topic,
chainId: chainId,
event: SessionEventParams(name: event, data: '${S.current.event}: $event'),
);
};
if (ns.events.isNotEmpty) {
models.add(WCConnectionModel(title: S.current.events, elements: ns.events));
}
models.add(
ConnectionModel(title: S.current.events, elements: ns.events, elementActions: actions),
);
views.add(ConnectionWidget(title: key, info: models));
views.add(WCConnectionWidget(title: key, info: models));
}
return views;
}
static Map<String, Namespace> updateNamespaces(
Map<String, Namespace> currentNamespaces,
String namespace,
List<String> newChains,
) {
final updatedNamespaces = Map<String, Namespace>.from(currentNamespaces);
final accounts = currentNamespaces[namespace]!.accounts;
final address = NamespaceUtils.getAccount(accounts.first);
final newAccounts = newChains.map((c) => '$c:$address').toList();
final newNamespaces = currentNamespaces[namespace]!.copyWith(
chains: NamespaceUtils.getChainsFromAccounts(accounts)..addAll(newChains),
accounts: List<String>.from(accounts)..addAll(newAccounts),
);
updatedNamespaces[namespace] = newNamespaces;
return updatedNamespaces;
}
}

View file

@ -1,20 +1,6 @@
import 'dart:convert';
import 'dart:math';
import 'package:convert/convert.dart';
extension StringParsing on String {
String get utf8Message {
if (startsWith('0x')) {
final List<int> decoded = hex.decode(
substring(2),
);
return utf8.decode(decoded);
}
return this;
}
String safeSubString(int start, int end) {
return this.substring(0, min(this.toString().length, 12));
}

View file

@ -1,7 +1,6 @@
import 'dart:developer';
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/walletkit_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/enter_wallet_connect_uri_widget.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
@ -9,19 +8,19 @@ import 'package:cake_wallet/utils/device_info.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
import 'package:reown_walletkit/reown_walletkit.dart';
import 'package:cake_wallet/entities/qr_scanner.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/utils/permission_handler.dart';
import 'widgets/pairing_item_widget.dart';
import 'widgets/wc_pairing_item_widget.dart';
import 'wc_pairing_detail_page.dart';
class WalletConnectConnectionsView extends StatelessWidget {
final Web3WalletService web3walletService;
final WalletKitService walletKitService;
WalletConnectConnectionsView({required this.web3walletService, Uri? launchUri, Key? key})
WalletConnectConnectionsView({required this.walletKitService, Uri? launchUri, Key? key})
: super(key: key) {
_triggerPairingFromDeeplink(launchUri);
}
@ -39,42 +38,38 @@ class WalletConnectConnectionsView extends StatelessWidget {
final uriData = Uri.parse(uri);
await web3walletService.pairWithUri(uriData);
await walletKitService.pairWithUri(uriData);
}
@override
Widget build(BuildContext context) {
return WCPairingsWidget(web3walletService: web3walletService);
return WCPairingsWidget(walletKitService: walletKitService);
}
}
class WCPairingsWidget extends BasePage {
WCPairingsWidget({required this.web3walletService, Key? key})
: web3wallet = web3walletService.getWeb3Wallet();
WCPairingsWidget({required this.walletKitService, Key? key})
: walletKit = walletKitService.walletKit;
final Web3Wallet web3wallet;
final Web3WalletService web3walletService;
final ReownWalletKit walletKit;
final WalletKitService walletKitService;
@override
String get title => S.current.walletConnect;
Future<void> _onScanQrCode(BuildContext context, Web3Wallet web3Wallet) async {
Future<void> _onScanQrCode(BuildContext context, ReownWalletKit web3Wallet) async {
final String? uri;
if (DeviceInfo.instance.isMobile) {
bool isCameraPermissionGranted =
await PermissionHandler.checkPermission(Permission.camera, context);
await PermissionHandler.checkPermission(Permission.camera, context);
if (!isCameraPermissionGranted) return;
uri = await presentQRScanner(context);
} else {
uri = await _showEnterWalletConnectURIPopUp(context);
}
if (uri == null) return _invalidUriToast(context, S.current.nullURIError);
log('_onFoundUri: $uri');
final Uri uriData = Uri.parse(uri);
await web3walletService.pairWithUri(uriData);
await _handleWalletConnectURI(uri, context);
}
Future<String?> _showEnterWalletConnectURIPopUp(BuildContext context) async {
@ -87,6 +82,17 @@ class WCPairingsWidget extends BasePage {
return walletConnectURI;
}
Future<void> _handleWalletConnectURI(
String? walletConnectURI,
BuildContext context,
) async {
if (walletConnectURI == null) return _invalidUriToast(context, S.current.nullURIError);
log('_onFoundUri: $walletConnectURI');
final Uri uriData = Uri.parse(walletConnectURI);
await walletKitService.pairWithUri(uriData);
}
Future<void> _invalidUriToast(BuildContext context, String message) async {
await showPopUp<void>(
context: context,
@ -126,15 +132,30 @@ class WCPairingsWidget extends BasePage {
text: S.current.newConnection,
color: Theme.of(context).primaryColor,
textColor: Colors.white,
onPressed: () => _onScanQrCode(context, web3wallet),
onPressed: () => _onScanQrCode(context, walletKit),
),
SizedBox(height: 4),
TextButton(
onPressed: () async {
final uri = await _showEnterWalletConnectURIPopUp(context);
await _handleWalletConnectURI(uri, context);
},
child: Text(
'Click to paste WalletConnect Link',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
),
),
],
),
),
SizedBox(height: 48),
SizedBox(height: 16),
Expanded(
child: Visibility(
visible: web3walletService.pairings.isEmpty,
visible: walletKitService.pairings.isEmpty,
child: Center(
child: Text(
S.current.activeConnectionsPrompt,
@ -147,10 +168,10 @@ class WCPairingsWidget extends BasePage {
),
),
replacement: ListView.builder(
itemCount: web3walletService.pairings.length,
itemCount: walletKitService.pairings.length,
itemBuilder: (BuildContext context, int index) {
final pairing = web3walletService.pairings[index];
return PairingItemWidget(
final pairing = walletKitService.pairings[index];
return WCPairingItemWidget(
key: ValueKey(pairing.topic),
pairing: pairing,
onTap: () {
@ -159,7 +180,7 @@ class WCPairingsWidget extends BasePage {
MaterialPageRoute(
builder: (context) => WalletConnectPairingDetailsPage(
pairing: pairing,
web3walletService: web3walletService,
walletKitService: walletKitService,
),
),
);

View file

@ -1,24 +1,22 @@
import 'dart:developer';
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/walletkit_service.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
import 'package:reown_walletkit/reown_walletkit.dart';
import 'utils/namespace_model_builder.dart';
class WalletConnectPairingDetailsPage extends StatefulWidget {
final PairingInfo pairing;
final Web3WalletService web3walletService;
final WalletKitService walletKitService;
const WalletConnectPairingDetailsPage({
required this.pairing,
required this.web3walletService,
required this.walletKitService,
super.key,
});
@ -33,7 +31,9 @@ class WalletConnectPairingDetailsPageState extends State<WalletConnectPairingDet
void initState() {
super.initState();
initDateTime();
initSessions();
WidgetsBinding.instance.addPostFrameCallback((_) {
initSessions();
});
}
void initDateTime() {
@ -46,13 +46,13 @@ class WalletConnectPairingDetailsPageState extends State<WalletConnectPairingDet
}
void initSessions() {
List<SessionData> sessions = widget.web3walletService.getSessionsForPairingInfo(widget.pairing);
List<SessionData> sessions = widget.walletKitService.getSessionsForPairingInfo(widget.pairing);
for (final SessionData session in sessions) {
List<Widget> namespaceWidget = ConnectionWidgetBuilder.buildFromNamespaces(
session.topic,
session.namespaces,
widget.web3walletService.getWeb3Wallet(),
context,
);
// Loop through and add the namespace widgets, but put 20 pixels between each one
for (int i = 0; i < namespaceWidget.length; i++) {
@ -61,6 +61,59 @@ class WalletConnectPairingDetailsPageState extends State<WalletConnectPairingDet
sessionWidgets.add(const SizedBox(height: 20.0));
}
}
sessionWidgets.add(const SizedBox.square(dimension: 10.0));
sessionWidgets.add(
PrimaryButton(
onPressed: () async {
try {
await widget.walletKitService.extendSession(
topic: session.topic,
);
} catch (e) {
debugPrint('${e.toString()}');
}
},
text: S.current.extend_session,
color: Theme.of(context).primaryColor,
textColor: Colors.white,
),
);
sessionWidgets.add(const SizedBox.square(dimension: 10.0));
sessionWidgets.add(
PrimaryButton(
onPressed: () async {
try {
await widget.walletKitService.updateSession(
topic: session.topic,
namespaces: session.namespaces,
);
} catch (e) {
debugPrint('${e.toString()}');
}
},
text: S.current.update_session,
color: Theme.of(context).primaryColor,
textColor: Colors.white,
),
);
sessionWidgets.add(const SizedBox.square(dimension: 10.0));
sessionWidgets.add(
PrimaryButton(
onPressed: () async {
try {
await widget.walletKitService.disconnectSession(
topic: session.topic,
);
} catch (e) {
debugPrint('${e.toString()}');
}
},
text: S.current.disconnect_session,
color: Theme.of(context).primaryColor,
textColor: Colors.white,
),
);
}
}
@ -70,7 +123,7 @@ class WalletConnectPairingDetailsPageState extends State<WalletConnectPairingDet
widget.pairing,
expiryDate,
sessionWidgets,
widget.web3walletService,
widget.walletKitService,
);
}
}
@ -80,13 +133,13 @@ class WCCDetailsWidget extends BasePage {
this.pairing,
this.expiryDate,
this.sessionWidgets,
this.web3walletService,
this.walletKitService,
);
final PairingInfo pairing;
final String expiryDate;
final List<Widget> sessionWidgets;
final Web3WalletService web3walletService;
final WalletKitService walletKitService;
@override
Widget body(BuildContext context) {
@ -141,7 +194,7 @@ class WCCDetailsWidget extends BasePage {
const SizedBox(height: 20.0),
PrimaryButton(
onPressed: () =>
_onDeleteButtonPressed(context, pairing.peerMetadata!.name, web3walletService),
_onDeleteButtonPressed(context, pairing.peerMetadata!.name, walletKitService),
text: S.current.delete,
color: Theme.of(context).primaryColor,
textColor: Colors.white,
@ -154,7 +207,10 @@ class WCCDetailsWidget extends BasePage {
}
Future<void> _onDeleteButtonPressed(
BuildContext context, String dAppName, Web3WalletService web3walletService) async {
BuildContext context,
String dAppName,
WalletKitService walletKitService,
) async {
bool confirmed = false;
await showPopUp<void>(
@ -175,11 +231,13 @@ class WCCDetailsWidget extends BasePage {
);
if (confirmed) {
try {
await web3walletService.disconnectSession(pairing.topic);
await walletKitService.deletePairing(topic: pairing.topic);
Navigator.of(context).pop();
if (Navigator.canPop(context)) {
Navigator.pop(context);
}
} catch (e) {
log(e.toString());
debugPrint(e.toString());
}
}
}

View file

@ -0,0 +1,100 @@
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/models/bottom_sheet_queue_item_model.dart';
import 'package:flutter/material.dart';
class BottomSheetListener extends StatefulWidget {
final BottomSheetService bottomSheetService;
final Widget child;
const BottomSheetListener({
required this.bottomSheetService,
required this.child,
super.key,
});
@override
BottomSheetListenerState createState() => BottomSheetListenerState();
}
class BottomSheetListenerState extends State<BottomSheetListener> {
@override
void initState() {
super.initState();
widget.bottomSheetService.currentSheet.addListener(_showBottomSheet);
}
@override
void dispose() {
widget.bottomSheetService.currentSheet.removeListener(_showBottomSheet);
super.dispose();
}
Future<void> _showBottomSheet() async {
if (widget.bottomSheetService.currentSheet.value != null) {
BottomSheetQueueItemModel item = widget.bottomSheetService.currentSheet.value!;
final value = await showModalBottomSheet(
context: context,
isDismissible: item.isModalDismissible,
backgroundColor: Color.fromARGB(0, 0, 0, 0),
isScrollControlled: true,
constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.9),
builder: (context) {
if (item.closeAfter > 0) {
Future.delayed(Duration(seconds: item.closeAfter), () {
try {
if (!mounted) return;
if (Navigator.canPop(context)) {
Navigator.pop(context);
}
} catch (e, s) {
debugPrint('[$runtimeType] close $e $s');
}
});
}
return Material(
color: Theme.of(context).colorScheme.background,
borderRadius: BorderRadius.all(Radius.circular(16)),
child: Padding(
padding: EdgeInsets.only(
top: 16,
left: 16,
right: 16,
bottom: MediaQuery.of(context).viewInsets.bottom + 24,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
IconButton(
color: Theme.of(context).appBarTheme.titleTextStyle!.color!,
padding: const EdgeInsets.all(0.0),
visualDensity: VisualDensity.compact,
onPressed: () {
if (Navigator.canPop(context)) {
Navigator.pop(context);
}
},
icon: const Icon(Icons.close_sharp),
),
],
),
Flexible(child: item.widget),
],
),
),
);
},
);
if (!item.completer.isCompleted) {
item.completer.complete(value);
}
widget.bottomSheetService.showNext();
}
}
@override
Widget build(BuildContext context) => widget.child;
}

View file

@ -1,4 +1,5 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:flutter/material.dart';
class BottomSheetMessageDisplayWidget extends StatelessWidget {
@ -18,7 +19,7 @@ class BottomSheetMessageDisplayWidget extends StatelessWidget {
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
color: Colors.white,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
),
SizedBox(height: 8),
@ -30,7 +31,7 @@ class BottomSheetMessageDisplayWidget extends StatelessWidget {
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Colors.white,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
),
),

View file

@ -1,180 +0,0 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter/material.dart';
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import '../../../../core/wallet_connect/models/auth_request_model.dart';
import '../../../../core/wallet_connect/models/connection_model.dart';
import '../../../../core/wallet_connect/models/session_request_model.dart';
import '../utils/namespace_model_builder.dart';
import 'connection_widget.dart';
class ConnectionRequestWidget extends StatefulWidget {
const ConnectionRequestWidget({
required this.wallet,
required this.chaindIdNamespace,
this.authRequest,
this.sessionProposal,
Key? key,
}) : super(key: key);
final Web3Wallet wallet;
final String chaindIdNamespace;
final AuthRequestModel? authRequest;
final SessionRequestModel? sessionProposal;
@override
State<ConnectionRequestWidget> createState() => _ConnectionRequestWidgetState();
}
class _ConnectionRequestWidgetState extends State<ConnectionRequestWidget> {
ConnectionMetadata? metadata;
@override
void initState() {
super.initState();
// Get the connection metadata
metadata = widget.authRequest?.request.requester ?? widget.sessionProposal?.request.proposer;
}
@override
Widget build(BuildContext context) {
if (metadata == null) {
return Text(
S.current.error,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
);
}
return _ConnectionMetadataDisplayWidget(
metadata: metadata,
wallet: widget.wallet,
authRequest: widget.authRequest,
sessionProposal: widget.sessionProposal,
chaindIdNamespace: widget.chaindIdNamespace,
);
}
}
class _ConnectionMetadataDisplayWidget extends StatelessWidget {
const _ConnectionMetadataDisplayWidget({
required this.wallet,
required this.metadata,
required this.sessionProposal,
required this.chaindIdNamespace,
this.authRequest,
});
final ConnectionMetadata? metadata;
final Web3Wallet wallet;
final String chaindIdNamespace;
final AuthRequestModel? authRequest;
final SessionRequestModel? sessionProposal;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Color.fromARGB(255, 18, 18, 19),
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Text(
metadata!.metadata.name,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
textAlign: TextAlign.center,
),
Text(
S.current.wouoldLikeToConnect,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
Text(
metadata!.metadata.url,
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
Visibility(
visible: authRequest != null,
child: _AuthRequestWidget(
wallet: wallet,
authRequest: authRequest,
chaindIdNamespace: chaindIdNamespace,
),
//If authRequest is null, sessionProposal is not null.
replacement: _SessionProposalWidget(sessionProposal: sessionProposal!),
),
],
),
);
}
}
class _AuthRequestWidget extends StatelessWidget {
const _AuthRequestWidget({
required this.wallet,
required this.chaindIdNamespace,
this.authRequest,
});
final Web3Wallet wallet;
final String chaindIdNamespace;
final AuthRequestModel? authRequest;
@override
Widget build(BuildContext context) {
final model = ConnectionModel(
text: wallet.formatAuthMessage(
iss: 'did:pkh:$chaindIdNamespace:${authRequest!.iss}',
cacaoPayload: CacaoRequestPayload.fromPayloadParams(
authRequest!.request.payloadParams,
),
),
);
return ConnectionWidget(
title: S.current.message,
info: [model],
);
}
}
class _SessionProposalWidget extends StatelessWidget {
const _SessionProposalWidget({required this.sessionProposal});
final SessionRequestModel sessionProposal;
@override
Widget build(BuildContext context) {
// Create the connection models using the required and optional namespaces provided by the proposal data
// The key is the title and the list of values is the data
final List<ConnectionWidget> views = ConnectionWidgetBuilder.buildFromRequiredNamespaces(
sessionProposal.request.requiredNamespaces,
);
return Column(children: views);
}
}

View file

@ -1,5 +1,6 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -29,14 +30,14 @@ class _EnterWallectConnectURIWrapperWidgetState extends State<EnterWalletConnect
@override
Widget build(BuildContext context) {
return _EnterWalletConnectURIWidget(
return EnterWalletConnectURIWidget(
controller: controller,
);
}
}
class _EnterWalletConnectURIWidget extends BaseAlertDialog {
_EnterWalletConnectURIWidget({
class EnterWalletConnectURIWidget extends BaseAlertDialog {
EnterWalletConnectURIWidget({
required this.controller,
});
@ -57,18 +58,25 @@ class _EnterWalletConnectURIWidget extends BaseAlertDialog {
@override
Widget content(BuildContext context) {
return Card(
color: Theme.of(context).dialogBackgroundColor,
elevation: 0.0,
margin: EdgeInsets.zero,
child: Column(
children: [
SizedBox(height: 8),
Text(
S.current.copyWalletConnectLink,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodySmall,
),
SizedBox(height: 16),
TextField(
controller: controller,
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white),
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
decoration: InputDecoration(
suffixIcon: Container(
width: 24,
@ -79,14 +87,13 @@ class _EnterWalletConnectURIWidget extends BaseAlertDialog {
child: InkWell(
onTap: () => _pasteWalletConnectURI(),
child: Container(
padding: EdgeInsets.all(8),
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(6)),
),
child: Image.asset(
'assets/images/paste_ios.png',
color:
Theme.of(context).extension<SendPageTheme>()!.textFieldButtonIconColor,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
),
),
@ -99,7 +106,7 @@ class _EnterWalletConnectURIWidget extends BaseAlertDialog {
),
),
hintStyle: TextStyle(
color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
fontWeight: FontWeight.w500,
fontSize: 14,
),

View file

@ -1,64 +0,0 @@
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:flutter/material.dart';
import '../../../../../core/wallet_connect/models/bottom_sheet_queue_item_model.dart';
class BottomSheetListener extends StatefulWidget {
final BottomSheetService bottomSheetService;
final Widget child;
const BottomSheetListener({
required this.child,
required this.bottomSheetService,
super.key,
});
@override
BottomSheetListenerState createState() => BottomSheetListenerState();
}
class BottomSheetListenerState extends State<BottomSheetListener> {
@override
void initState() {
super.initState();
widget.bottomSheetService.currentSheet.addListener(_showBottomSheet);
}
@override
void dispose() {
widget.bottomSheetService.currentSheet.removeListener(_showBottomSheet);
super.dispose();
}
Future<void> _showBottomSheet() async {
if (widget.bottomSheetService.currentSheet.value != null) {
BottomSheetQueueItemModel item = widget.bottomSheetService.currentSheet.value!;
final value = await showModalBottomSheet(
context: context,
isDismissible: item.isModalDismissible,
backgroundColor: Color.fromARGB(0, 0, 0, 0),
isScrollControlled: true,
constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.9),
builder: (context) {
return Container(
decoration: const BoxDecoration(
color: Color.fromARGB(255, 18, 18, 19),
borderRadius: BorderRadius.all(Radius.circular(16)),
),
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.all(16),
child: item.widget,
);
},
);
if (!item.completer.isCompleted) {
item.completer.complete(value);
}
widget.bottomSheetService.resetCurrentSheet();
}
}
@override
Widget build(BuildContext context) => widget.child;
}

View file

@ -1,48 +0,0 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:flutter/material.dart';
class Web3RequestModal extends StatelessWidget {
const Web3RequestModal({required this.child, this.onAccept, this.onReject, super.key});
final Widget child;
final VoidCallback? onAccept;
final VoidCallback? onReject;
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
child,
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
child: PrimaryButton(
onPressed: onReject ?? () => Navigator.of(context).pop(false),
text: S.current.reject,
color: Theme.of(context).colorScheme.error,
textColor: Theme.of(context).colorScheme.onError,
),
),
const SizedBox(width: 16),
Expanded(
child: PrimaryButton(
onPressed: onAccept ?? () => Navigator.of(context).pop(true),
text: S.current.approve,
color: Theme.of(context).primaryColor,
textColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
),
],
),
],
),
);
}
}

View file

@ -1,11 +1,11 @@
import 'package:cake_wallet/src/screens/wallet_connect/models/wc_connection_model.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:flutter/material.dart';
import '../../../../core/wallet_connect/models/connection_model.dart';
class ConnectionItemWidget extends StatelessWidget {
const ConnectionItemWidget({required this.model, Key? key}) : super(key: key);
class WCConnectionItemWidget extends StatelessWidget {
const WCConnectionItemWidget({required this.model, Key? key}) : super(key: key);
final ConnectionModel model;
final WCConnectionModel model;
@override
Widget build(BuildContext context) {
@ -52,7 +52,7 @@ class ConnectionItemWidget extends StatelessWidget {
class _NoModelElementWidget extends StatelessWidget {
const _NoModelElementWidget({required this.model});
final ConnectionModel model;
final WCConnectionModel model;
@override
Widget build(BuildContext context) {
@ -73,7 +73,7 @@ class _ModelElementWidget extends StatelessWidget {
required this.modelElement,
});
final ConnectionModel model;
final WCConnectionModel model;
final String modelElement;
@override

View file

@ -0,0 +1,100 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/key_service/wallet_connect_key_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/models/wc_connection_model.dart';
import 'package:cake_wallet/src/screens/wallet_connect/utils/namespace_model_builder.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/wc_connection_widget.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:flutter/material.dart';
import 'package:reown_walletkit/reown_walletkit.dart';
class WCConnectionRequestWidget extends StatelessWidget {
WCConnectionRequestWidget({
this.sessionAuthPayload,
this.proposalData,
this.requester,
this.verifyContext,
required this.walletKeyService,
required this.walletKit,
required this.appStore,
});
final SessionAuthPayload? sessionAuthPayload;
final ProposalData? proposalData;
final ConnectionMetadata? requester;
final VerifyContext? verifyContext;
final WalletConnectKeyService walletKeyService;
final AppStore appStore;
final ReownWalletKit walletKit;
@override
Widget build(BuildContext context) {
if (requester == null) {
return Text(S.current.error.toUpperCase());
}
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 8),
Text(
'${requester!.metadata.name} ${S.current.wouoldLikeToConnect}',
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
(sessionAuthPayload != null)
? _buildSessionAuthRequestView()
: _buildSessionProposalView(context),
],
),
);
}
Widget _buildSessionAuthRequestView() {
final cacaoPayload = CacaoRequestPayload.fromSessionAuthPayload(
sessionAuthPayload!,
);
final List<WCConnectionModel> messagesModels = [];
for (var chain in sessionAuthPayload!.chains) {
final chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
final iss = 'did:pkh:$chain:${chainKeys.first.publicKey}';
final message = walletKit.formatAuthMessage(
iss: iss,
cacaoPayload: cacaoPayload,
);
messagesModels.add(
WCConnectionModel(
title: '${S.current.message} ${messagesModels.length + 1}',
elements: [message],
),
);
}
return WCConnectionWidget(
title: '${messagesModels.length} ${S.current.messages}',
info: messagesModels,
);
}
Widget _buildSessionProposalView(BuildContext context) {
// Create the connection models using the required and optional namespaces provided by the proposal data
final views = ConnectionWidgetBuilder.buildFromRequiredNamespaces(
proposalData!.generatedNamespaces ?? {},
);
return Column(children: views);
}
}

View file

@ -1,17 +1,17 @@
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/src/screens/wallet_connect/models/wc_connection_model.dart';
import 'package:flutter/material.dart';
import '../../../../core/wallet_connect/models/connection_model.dart';
import 'connection_item_widget.dart';
import 'wc_connection_item_widget.dart';
class ConnectionWidget extends StatelessWidget {
const ConnectionWidget({required this.title, required this.info, super.key});
class WCConnectionWidget extends StatelessWidget {
const WCConnectionWidget({required this.title, required this.info, super.key});
final String title;
final List<ConnectionModel> info;
final List<WCConnectionModel> info;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).primaryColorLight,
@ -23,7 +23,7 @@ class ConnectionWidget extends StatelessWidget {
children: [
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context) .colorScheme.background,
borderRadius: BorderRadius.circular(8),
),
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
@ -32,12 +32,12 @@ class ConnectionWidget extends StatelessWidget {
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
color: Theme.of(context).appBarTheme.titleTextStyle!.color!
),
),
),
const SizedBox(height: 8),
...info.map((e) => ConnectionItemWidget(model: e)),
...info.map((e) => WCConnectionItemWidget(model: e)),
],
),
);

View file

@ -3,10 +3,10 @@ import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
import 'package:flutter/material.dart';
import 'package:walletconnect_flutter_v2/apis/core/pairing/utils/pairing_models.dart';
import 'package:reown_walletkit/reown_walletkit.dart';
class PairingItemWidget extends StatelessWidget {
const PairingItemWidget({required this.pairing, required this.onTap, super.key});
class WCPairingItemWidget extends StatelessWidget {
const WCPairingItemWidget({required this.pairing, required this.onTap, super.key});
final PairingInfo pairing;
final void Function() onTap;
@ -14,6 +14,7 @@ class PairingItemWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
PairingMetadata? metadata = pairing.peerMetadata;
if (metadata == null) {
return SizedBox.shrink();
}

View file

@ -0,0 +1,79 @@
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/wc_verify_context_widget.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:flutter/material.dart';
import 'package:reown_walletkit/reown_walletkit.dart';
class WCRequestWidget extends StatelessWidget {
WCRequestWidget({
required this.child,
this.verifyContext,
this.onAccept,
this.onReject,
});
final Widget child;
final VerifyContext? verifyContext;
final VoidCallback? onAccept;
final VoidCallback? onReject;
@override
Widget build(BuildContext context) {
final currentTheme = getIt.get<SettingsStore>().currentTheme;
return Column(
mainAxisSize: MainAxisSize.min,
children: [
WCVerifyContextWidget(
currentTheme: currentTheme,
verifyContext: verifyContext,
),
const SizedBox(height: 8),
Flexible(
child: SingleChildScrollView(child: child),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
child: PrimaryButton(
onPressed: onReject ??
() {
if (Navigator.canPop(context)) {
Navigator.of(context).pop(WCBottomSheetResult.reject);
}
},
text: S.current.reject,
color: Theme.of(context).colorScheme.error,
textColor: Theme.of(context).colorScheme.onError,
),
),
const SizedBox(width: 16),
Expanded(
child: PrimaryButton(
onPressed: onAccept ??
() {
if (Navigator.canPop(context)) {
Navigator.of(context).pop(WCBottomSheetResult.one);
}
},
text: S.current.approve,
color: Theme.of(context).primaryColor,
textColor: currentTheme.type == ThemeType.dark
? Theme.of(context).extension<DashboardPageTheme>()!.textColor
: Theme.of(context).extension<CakeTextTheme>()!.buttonTextColor,
),
),
],
),
],
);
}
}

View file

@ -0,0 +1,61 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:flutter/material.dart';
class WCSessionAuthRequestWidget extends StatelessWidget {
const WCSessionAuthRequestWidget({super.key, required this.child});
final Widget child;
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: SingleChildScrollView(child: child),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
PrimaryButton(
onPressed: () {
if (Navigator.canPop(context)) {
Navigator.of(context).pop(WCBottomSheetResult.reject);
}
},
text: S.current.cancel,
color: Theme.of(context).colorScheme.error,
textColor: Theme.of(context).colorScheme.onError,
),
const SizedBox(width: 8),
PrimaryButton(
onPressed: () {
if (Navigator.canPop(context)) {
Navigator.of(context).pop(WCBottomSheetResult.one);
}
},
text: S.current.sign_one,
color: Theme.of(context).primaryColor,
textColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
const SizedBox(width: 8),
PrimaryButton(
onPressed: () {
if (Navigator.canPop(context)) {
Navigator.of(context).pop(WCBottomSheetResult.all);
}
},
text: S.current.sign_all,
color: Theme.of(context).secondaryHeaderColor,
textColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
],
),
],
);
}
}

View file

@ -0,0 +1,137 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:flutter/material.dart';
import 'package:reown_walletkit/reown_walletkit.dart';
class WCVerifyContextWidget extends StatelessWidget {
const WCVerifyContextWidget({
super.key,
required this.verifyContext,
required this.currentTheme,
});
final VerifyContext? verifyContext;
final ThemeBase currentTheme;
@override
Widget build(BuildContext context) {
if (verifyContext == null) {
return const SizedBox.shrink();
}
if (verifyContext!.validation.scam) {
return VerifyBanner(
color: Theme.of(context).colorScheme.error,
origin: verifyContext!.origin,
title: S.current.security_risk,
text: S.current.security_risk_description,
);
}
if (verifyContext!.validation.invalid) {
return VerifyBanner(
color: Theme.of(context).colorScheme.error,
origin: verifyContext!.origin,
title: S.current.domain_mismatch,
text: S.current.domain_mismatch_description,
);
}
if (verifyContext!.validation.valid) {
return VerifyHeader(
iconColor: currentTheme.type == ThemeType.dark
? Theme.of(context).extension<DashboardPageTheme>()!.textColor
: Theme.of(context).extension<CakeTextTheme>()!.buttonTextColor,
title: verifyContext!.origin,
);
}
return VerifyBanner(
color: Colors.orange,
origin: verifyContext!.origin,
title: S.current.cannot_verify,
text: S.current.cannot_verify_description,
);
}
}
class VerifyHeader extends StatelessWidget {
const VerifyHeader({
super.key,
required this.iconColor,
required this.title,
});
final Color iconColor;
final String title;
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.shield_outlined,
color: iconColor,
),
const SizedBox(width: 8),
Text(
title,
style: TextStyle(
color: iconColor,
fontWeight: FontWeight.bold,
),
),
],
);
}
}
class VerifyBanner extends StatelessWidget {
const VerifyBanner({
super.key,
required this.origin,
required this.title,
required this.text,
required this.color,
});
final String origin, title, text;
final Color color;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(
origin,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
const SizedBox.square(dimension: 8.0),
Container(
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: color.withOpacity(0.2),
borderRadius: const BorderRadius.all(Radius.circular(12.0)),
),
child: Column(
children: [
VerifyHeader(
iconColor: color,
title: title,
),
const SizedBox(height: 4.0),
Text(
text,
textAlign: TextAlign.center,
style: TextStyle(
color: color,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
);
}
}

View file

@ -1,7 +1,8 @@
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/walletkit_service.dart';
import 'package:cake_wallet/utils/exception_handler.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/wallet_type.dart';
@ -46,9 +47,9 @@ abstract class AppStoreBase with Store {
this.wallet!.setExceptionHandler(ExceptionHandler.onError);
if (isWalletConnectCompatibleChain(wallet.type)) {
await getIt.get<Web3WalletService>().onDispose();
getIt.get<Web3WalletService>().create();
await getIt.get<Web3WalletService>().init();
await getIt.get<WalletKitService>().onDispose();
getIt.get<WalletKitService>().create();
await getIt.get<WalletKitService>().init();
}
getIt.get<SharedPreferences>().setString(PreferencesKey.currentWalletName, wallet.name);
getIt

View file

@ -51,6 +51,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_daemon/flutter_daemon.dart';
import 'package:http/http.dart' as http;
import 'package:mobx/mobx.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../themes/theme_base.dart';
@ -180,7 +181,7 @@ abstract class DashboardViewModelBase with Store {
isShowThirdYatIntroduction = false;
unawaited(isBackgroundSyncEnabled());
unawaited(isBatteryOptimizationEnabled());
unawaited(_loadConstraints());
final _wallet = wallet;
if (_wallet.type == WalletType.monero) {
@ -536,6 +537,88 @@ abstract class DashboardViewModelBase with Store {
return resp;
}
@observable
late bool backgroundSyncNotificationsEnabled = sharedPreferences.getBool(PreferencesKey.backgroundSyncNotificationsEnabled) ?? false;
@action
Future<void> setBackgroundSyncNotificationsEnabled(bool value) async {
if (!value) {
backgroundSyncNotificationsEnabled = false;
sharedPreferences.setBool(PreferencesKey.backgroundSyncNotificationsEnabled, false);
return;
}
PermissionStatus permissionStatus = await Permission.notification.status;
if (permissionStatus != PermissionStatus.granted) {
final resp = await Permission.notification.request();
if (resp == PermissionStatus.denied) {
throw Exception("Notification permission denied");
}
}
backgroundSyncNotificationsEnabled = value;
await sharedPreferences.setBool(PreferencesKey.backgroundSyncNotificationsEnabled, value);
}
bool get hasBgsyncNetworkConstraints => Platform.isAndroid;
bool get hasBgsyncBatteryNotLowConstraints => Platform.isAndroid;
bool get hasBgsyncChargingConstraints => Platform.isAndroid;
bool get hasBgsyncDeviceIdleConstraints => Platform.isAndroid;
@observable
bool backgroundSyncNetworkUnmetered = false;
@observable
bool backgroundSyncBatteryNotLow = false;
@observable
bool backgroundSyncCharging = false;
@observable
bool backgroundSyncDeviceIdle = false;
Future<void> _loadConstraints() async {
backgroundSyncNetworkUnmetered = await FlutterDaemon().getNetworkType();
backgroundSyncBatteryNotLow = await FlutterDaemon().getBatteryNotLow();
backgroundSyncCharging = await FlutterDaemon().getRequiresCharging();
backgroundSyncDeviceIdle = await FlutterDaemon().getDeviceIdle();
}
@action
Future<void> setBackgroundSyncNetworkUnmetered(bool value) async {
backgroundSyncNetworkUnmetered = value;
await FlutterDaemon().setNetworkType(value);
if (await isBackgroundSyncEnabled()) {
await enableBackgroundSync();
}
}
@action
Future<void> setBackgroundSyncBatteryNotLow(bool value) async {
backgroundSyncBatteryNotLow = value;
await FlutterDaemon().setBatteryNotLow(value);
if (await isBackgroundSyncEnabled()) {
await enableBackgroundSync();
}
}
@action
Future<void> setBackgroundSyncCharging(bool value) async {
backgroundSyncCharging = value;
await FlutterDaemon().setRequiresCharging(value);
if (await isBackgroundSyncEnabled()) {
await enableBackgroundSync();
}
}
@action
Future<void> setBackgroundSyncDeviceIdle(bool value) async {
backgroundSyncDeviceIdle = value;
await FlutterDaemon().setDeviceIdle(value);
if (await isBackgroundSyncEnabled()) {
await enableBackgroundSync();
}
}
bool get hasBatteryOptimization => Platform.isAndroid;
@observable

View file

@ -1,10 +1,11 @@
import 'dart:convert';
import 'dart:developer';
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:cake_wallet/entities/solana_nft_asset_model.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/bottom_sheet/bottom_sheet_message_display_widget.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:http/http.dart' as http;
import 'package:mobx/mobx.dart';
@ -121,7 +122,7 @@ abstract class NFTViewModelBase with Store {
bottomSheetService.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(
message: e.toString(),
message: S.current.moralis_nft_error,
),
);
}

View file

@ -0,0 +1,44 @@
import 'package:flutter_daemon/flutter_daemon.dart';
import 'package:mobx/mobx.dart';
part 'background_sync_logs_view_model.g.dart';
class BackgroundSyncLogsViewModel = BackgroundSyncLogsViewModelBase with _$BackgroundSyncLogsViewModel;
abstract class BackgroundSyncLogsViewModelBase with Store {
final FlutterDaemon _daemon = FlutterDaemon();
@observable
LogData? logData;
@observable
bool isLoading = false;
@observable
String? error;
@computed
List<LogEntry> get logs => logData?.logs ?? [];
@computed
List<LogSession> get sessions => logData?.sessions ?? [];
@action
Future<void> loadLogs() async {
isLoading = true;
error = null;
try {
logData = await _daemon.getLogs();
} catch (e) {
error = e.toString();
} finally {
isLoading = false;
}
}
@action
Future<void> clearLogs() async {
await _daemon.clearLogs();
await loadLogs();
}
}

View file

@ -0,0 +1,92 @@
import 'package:mobx/mobx.dart';
import 'package:shared_preferences/shared_preferences.dart';
part 'shared_preferences.g.dart';
class DevSharedPreferences = DevSharedPreferencesBase with _$DevSharedPreferences;
enum PreferenceType {
unknown,
string,
int,
double,
bool,
listString
}
abstract class DevSharedPreferencesBase with Store {
DevSharedPreferencesBase() {
SharedPreferences.getInstance().then((value) {
sharedPreferences = value;
});
}
@observable
SharedPreferences? sharedPreferences;
@computed
List<String> get keys => (sharedPreferences?.getKeys().toList()?..sort()) ?? [];
@action
Future<void> delete(String key) async {
if (sharedPreferences == null) {
return;
}
await sharedPreferences!.remove(key);
}
dynamic get(String key) {
if (sharedPreferences == null) {
return null;
}
return sharedPreferences!.get(key);
}
Future<void> set(String key, PreferenceType type, dynamic value) async {
if (sharedPreferences == null) {
return;
}
switch (type) {
case PreferenceType.string:
await sharedPreferences!.setString(key, value as String);
break;
case PreferenceType.bool:
await sharedPreferences!.setBool(key, value as bool);
break;
case PreferenceType.int:
await sharedPreferences!.setInt(key, value as int);
break;
case PreferenceType.double:
await sharedPreferences!.setDouble(key, value as double);
break;
case PreferenceType.listString:
await sharedPreferences!.setStringList(key, List<String>.from(value as Iterable<dynamic>));
break;
default:
throw Exception("Unknown preference type: $type");
}
}
PreferenceType getPreferenceType(String key) {
if (sharedPreferences == null) {
return PreferenceType.unknown;
}
final value = sharedPreferences!.get(key);
if (value is String) {
return PreferenceType.string;
}
if (value is bool) {
return PreferenceType.bool;
}
if (value is int) {
return PreferenceType.int;
}
if (value is double) {
return PreferenceType.double;
}
if (value is List<String>) {
return PreferenceType.listString;
}
return PreferenceType.unknown;
}
}

View file

@ -14,6 +14,7 @@ import 'package:cake_wallet/entities/evm_transaction_error_fees_handler.dart';
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/entities/parsed_address.dart';
import 'package:cake_wallet/entities/template.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/entities/wallet_contact.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
@ -52,6 +53,7 @@ import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:shared_preferences/shared_preferences.dart';
part 'send_view_model.g.dart';
@ -587,6 +589,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
transactionNote: note,
));
}
final sharedPreferences = await SharedPreferences.getInstance();
await sharedPreferences.setString(PreferencesKey.backgroundSyncLastTrigger(wallet.name), DateTime.now().add(Duration(minutes: 1)).toIso8601String());
state = TransactionCommitted();
} catch (e) {

View file

@ -54,7 +54,7 @@ dependencies:
basic_utils: ^5.6.1
get_it: ^7.2.0
# connectivity: ^3.0.3
connectivity_plus: ^5.0.2
connectivity_plus: ^6.1.3
keyboard_actions: ^4.0.1
another_flushbar: ^1.12.29
archive: ^4.0.3
@ -83,18 +83,18 @@ dependencies:
version: 1.0.0
flutter_plugin_android_lifecycle: 2.0.23
path_provider_android: ^2.2.1
shared_preferences_android: ^2.4.8
url_launcher_android: 6.3.14
url_launcher_linux: 3.1.1 # https://github.com/flutter/flutter/issues/153083
sensitive_clipboard:
git:
url: https://github.com/MrCyjaneK/sensitive_clipboard
ref: 288c7ee2d63b459bc735f7dc89321b29a1f12fae
walletconnect_flutter_v2: ^2.1.4
eth_sig_util: ^0.0.9
ens_dart:
git:
url: https://github.com/cake-tech/ens_dart.git
ref: main
url: https://github.com/MrCyjaneK/ens_dart.git
ref: 9fa09b9db69b8645d5d50a844652aa570451d101
fluttertoast: 8.2.12
# tor:
# git:
@ -103,7 +103,10 @@ dependencies:
socks5_proxy: ^1.0.4
flutter_svg: ^2.0.9
polyseed: ^0.0.7
nostr_tools: ^1.0.9
nostr_tools:
git:
url: https://github.com/MrCyjaneK/nostr_tools.git
ref: 089d5a2dd751429a040ba10fb24fcbae564053e5
ledger_flutter_plus:
git:
url: https://github.com/vespr-wallet/ledger-flutter-plus
@ -113,6 +116,7 @@ dependencies:
git:
url: https://github.com/cake-tech/on_chain.git
ref: cake-update-v2
reown_walletkit: ^1.1.2
blockchain_utils:
git:
url: https://github.com/cake-tech/blockchain_utils
@ -120,7 +124,8 @@ dependencies:
flutter_daemon:
git:
url: https://github.com/MrCyjaneK/flutter_daemon
ref: 5c369e0e69e6f459357b9802bc694a221397298a
ref: 6d5270d64b5dd588fce12fd0a0c7314c37e6cff1
flutter_local_notifications: ^19.0.0
dev_dependencies:
flutter_test:
@ -161,6 +166,7 @@ dependency_overrides:
git:
url: https://github.com/vespr-wallet/ledger-flutter-plus
ref: c2e341d8038f1108690ad6f80f7b4b7156aacc76
web_socket_channel: ^3.0.2
flutter_icons:
image_path: "assets/images/app_logo.png"

View file

@ -53,6 +53,7 @@
"anonpay_description": "توليد ${type}. يمكن للمستلم ${method} بأي عملة مشفرة مدعومة ، وستتلقى أموالاً في هذه",
"apk_update": "تحديث APK",
"approve": "ﺪﻤﺘﻌﻳ",
"approve_request": "الموافقة على الطلب",
"arrive_in_this_address": "سيصل ${currency} ${tag}إلى هذا العنوان",
"ascending": "تصاعدي",
"ask_each_time": "اسأل في كل مرة",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "في انتظار تأكيد الدفع",
"background_sync": "مزامنة الخلفية",
"background_sync_mode": "وضع مزامنة الخلفية",
"background_sync_on_battery_low": "تزامن على البطارية المنخفضة",
"background_sync_on_charging": "تزامن فقط عند الشحن",
"background_sync_on_device_idle": "تزامن فقط عند عدم استخدام الجهاز",
"background_sync_on_unmetered_network": "تتطلب شبكة غير مستوفاة",
"backup": "نسخ الاحتياطي",
"backup_file": "ملف النسخ الاحتياطي",
"backup_password": "كلمة مرور النسخ الاحتياطي",
@ -116,9 +121,12 @@
"camera_consent": ".ﻞﻴﺻﺎﻔﺘﻟﺍ ﻰﻠﻋ ﻝﻮﺼﺤﻠﻟ ﻢﻬﺑ ﺔﺻﺎﺨﻟﺍ ﺔﻴﺻﻮﺼﺨﻟﺍ ﺔﺳﺎﻴﺳ ﻦﻣ ﻖﻘﺤﺘﻟﺍ ﻰﺟﺮﻳ .${provider} ﻝﻮﻠ",
"camera_permission_is_required": ".ﺍﺮﻴﻣﺎﻜﻟﺍ ﻥﺫﺇ ﺏﻮﻠﻄﻣ",
"cancel": "إلغاء",
"cannot_verify": "لا يمكن التحقق",
"cannot_verify_description": "لا يمكن التحقق من هذا المجال. تحقق من الطلب بعناية قبل الموافقة.",
"card_address": "العنوان:",
"cardholder_agreement": "اتفاقية حامل البطاقة",
"cards": "البطاقات",
"chain_id": "معرف سلسلة",
"chains": "ﻞﺳﻼﺴﻟﺍ",
"change": "تغير",
"change_backup_password_alert": "لن تكون ملفات النسخ الاحتياطي السابقة متاحة للاستيراد بكلمة مرور نسخ احتياطي جديدة. سيتم استخدام كلمة مرور النسخ الاحتياطي الجديدة لملفات النسخ الاحتياطي الجديدة فقط. هل أنت متأكد أنك تريد تغيير كلمة المرور الاحتياطية؟",
@ -174,6 +182,7 @@
"connect_yats": "توصيل Yats",
"connect_your_hardware_wallet": "قم بتوصيل محفظة الأجهزة الخاصة بك باستخدام Bluetooth أو USB",
"connect_your_hardware_wallet_ios": "قم بتوصيل محفظة الأجهزة الخاصة بك باستخدام Bluetooth",
"connected": "متصل",
"connection_sync": "الاتصال والمزامنة",
"connectWalletPrompt": "ﺕﻼﻣﺎﻌﻤﻟﺍ ءﺍﺮﺟﻹ WalletConnect ﻊﻣ ﻚﺘﻈﻔﺤﻣ ﻞﻴﺻﻮﺘﺑ ﻢﻗ",
"contact": "تواصل",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "تعطيل تحسين البطارية",
"disableBatteryOptimizationDescription": "هل تريد تعطيل تحسين البطارية من أجل جعل الخلفية مزامنة تعمل بحرية وسلاسة؟",
"disabled": "معطلة",
"disconnect_session": "فصل الجلسة",
"discount": "وفر ${value}٪",
"display_settings": "اعدادات العرض",
"displayable": "قابل للعرض",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "لا تشارك هذه مع أي شخص آخر ، بما في ذلك الدعم.\n\nيمكن أن تتم سرقة أموالك!",
"do_not_show_me": "لا ترني هذا مجددا",
"domain_looks_up": "ﻝﺎﺠﻤﻟﺍ ﺚﺤﺑ ﺕﺎﻴﻠﻤﻋ",
"domain_mismatch": "عدم تطابق المجال",
"domain_mismatch_description": "يحتوي هذا الموقع على مجال لا يتطابق مع مرسل هذا الطلب. قد تؤدي الموافقة على فقدان الأموال.",
"donation_link_details": "تفاصيل رابط التبرع",
"e_sign_consent": "الموافقة على التوقيع الإلكتروني",
"edit": "تعديل",
@ -298,6 +310,7 @@
"error_text_template": "لا يمكن أن يحتوي اسم القالب وعنوانه على رموز ` , \"\nويجب أن يتراوح طولها بين 1 و 106 حرفًا",
"error_text_wallet_name": "يمكن أن يحتوي اسم المحفظة على أحرف وأرقام ورموز _ - فقط\nويجب أن يتراوح طولها بين حرف واحد و 33 حرفًا",
"error_text_xmr": "لا يمكن أن تتجاوز قيمة XMR الرصيد المتاح.\nيجب أن يكون عدد الكسور أقل من أو يساوي 12",
"error_while_processing": "حدث خطأ أثناء التنقل",
"errorGettingCredentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻰﻠﻋ ﻝﻮﺼﺤﻟﺍ ءﺎﻨﺛﺃ ﺄﻄﺧ ﺙﺪﺣ :ﻞﺸﻓ",
"errorSigningTransaction": "ﺔﻠﻣﺎﻌﻤﻟﺍ ﻊﻴﻗﻮﺗ ءﺎﻨﺛﺃ ﺄﻄﺧ ﺙﺪﺣ",
"estimated": "مُقدَّر",
@ -323,6 +336,7 @@
"export_backup": "تصدير نسخة احتياطية",
"export_logs": "سجلات التصدير",
"export_outputs": "مخرجات التصدير",
"extend_session": "تمديد الجلسة",
"extra_id": "معرف إضافي:",
"extracted_address_content": "سوف ترسل الأموال إلى\n${recipient_name}",
"failed_authentication": "${state_error} فشل المصادقة.",
@ -344,10 +358,12 @@
"forgot_password": "هل نسيت كلمة السر",
"freeze": "تجميد",
"frequently_asked_questions": "الأسئلة الشائعة",
"from": "من",
"frozen": "مجمدة",
"frozen_balance": "التوازن المجمد",
"full_balance": "الرصيد الكامل",
"gas_exceeds_allowance": "الغاز المطلوب بالمعاملة يتجاوز البدل.",
"gas_price": "سعر الغاز",
"generate_name": "توليد الاسم",
"generating_gift_card": "يتم توليد بطاقة هدية",
"generating_transaction": "توليد معاملة",
@ -440,6 +456,8 @@
"memo": "مذكرة:",
"message": "ﺔﻟﺎﺳﺭ",
"message_verified": "تم التحقق من الرسالة بنجاح",
"messages": "رسائل",
"method": "طريقة",
"methods": " ﻕﺮﻃُ",
"min_amount": "الحد الأدنى: ${value}",
"min_value": "الحد الأدنى: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "موضوع مونيرو الظلام",
"monero_light_theme": " ضوء مونيرو",
"moonpay_alert_text": "يجب أن تكون قيمة المبلغ أكبر من أو تساوي ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "حدث خطأ أثناء جلب NFTs. يرجى التحقق من اتصال الإنترنت الخاص بك وحاول مرة أخرى.",
"more_options": "المزيد من الخيارات",
"multiple_addresses_detected": "عناوين متعددة تم اكتشافها",
"mweb_confirmed": "أكد MWEB",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "تسمية",
"new_subaddress_title": "عنوان جديد",
"new_template": "قالب جديد",
"new_transactions_notifications": "إرسال إشعارات حول المعاملات الجديدة",
"new_wallet": "إنشاء محفظة جديدة",
"newConnection": "ﺪﻳﺪﺟ ﻝﺎﺼﺗﺍ",
"no_cards_found": "لم يتم العثور على بطاقات",
@ -492,6 +512,7 @@
"normal": "طبيعي",
"note_optional": "ملاحظة (اختياري)",
"note_tap_to_change": "ملاحظة (انقر للتغيير)",
"notification_permission_denied": "تم رفض إذن الإخطار بشكل جيد ، يرجى تمكينه يدويًا في الإعدادات",
"nullURIError": "ﻍﺭﺎﻓ (URI) ﻢﻈﺘﻨﻤﻟﺍ ﺩﺭﺍﻮﻤﻟﺍ ﻑﺮﻌﻣ",
"offer_expires_in": "ينتهي العرض في:",
"offline": "غير متصل على الانترنت",
@ -589,6 +610,7 @@
"rep_warning_sub": "لا يبدو أن ممثلك في وضع جيد. اضغط هنا لاختيار واحدة جديدة",
"repeat_wallet_password": "كرر كلمة مرور المحفظة",
"repeated_password_is_incorrect": "كلمة المرور المتكررة غير صحيحة. يرجى تكرار كلمة مرور المحفظة مرة أخرى.",
"requested": "مطلوب",
"require_for_adding_contacts": "تتطلب إضافة جهات اتصال",
"require_for_all_security_and_backup_settings": "مطلوب لجميع إعدادات الأمان والنسخ الاحتياطي",
"require_for_assessing_wallet": "تتطلب الوصول إلى المحفظة",
@ -650,6 +672,8 @@
"second_intro_content": "Yat الخاص بك هو عنوان تعبيري فريد يحل محل جميع العناوين السداسية العشرية الطويلة لجميع عملاتك.",
"second_intro_title": "عنوان تعبيري ايموجي واحد يحكمهم جميعا!",
"security_and_backup": "الأمان والنسخ الاحتياطي",
"security_risk": "خطر الأمن",
"security_risk_description": "تم وضع علامة على هذا المجال على أنه غير آمن من قبل مقدمي الأمان المتعددين. اترك على الفور لحماية أصولك.",
"seed_alert_back": "العودة إلى الوراء",
"seed_alert_content": "السييد هي الطريقة الوحيدة لاسترداد محفظتك. هل كتبتها؟",
"seed_alert_title": "انتباه",
@ -764,7 +788,9 @@
"show_keys": "اظهار السييد / المفاتيح",
"show_market_place": "إظهار السوق",
"show_seed": "عرض السييد",
"sign_all": "قم بتوقيع الكل",
"sign_message": "تسجيل رسالة",
"sign_one": "وقع واحد",
"sign_up": "اشتراك",
"sign_verify_message": "تسجيل / تحقق",
"sign_verify_message_sub": "قم بتوقيع أو التحقق من رسالة باستخدام المفتاح الخاص بك",
@ -798,6 +824,7 @@
"subaddress_title": "قائمة العناوين الفرعية",
"subaddresses": "العناوين الفرعية",
"submit_request": "تقديم طلب",
"success": "نجاح",
"successful": "ﺢﺟﺎﻧ",
"support_description_guides": "توثيق ودعم القضايا المشتركة",
"support_description_live_chat": "حرة وسريعة! ممثلو الدعم المدربين متاحون للمساعدة",
@ -805,6 +832,7 @@
"support_title_guides": "مستندات محفظة كعكة",
"support_title_live_chat": "الدعم المباشر",
"support_title_other_links": "روابط دعم أخرى",
"supported": "مدعوم",
"swap": "تبديل",
"sweeping_wallet": "كنس المحفظة",
"sweeping_wallet_alert": "لن يستغرق هذا وقتًا طويلاً. لا تترك هذه الشاشة وإلا فقد يتم فقد أموال سويبت",
@ -837,6 +865,7 @@
"thorchain_taproot_address_not_supported": "لا يدعم مزود Thorchain عناوين Taproot. يرجى تغيير العنوان أو تحديد مزود مختلف.",
"time": "${minutes}د ${seconds}س",
"tip": "بقشيش:",
"to": "ل",
"today": "اليوم",
"token_contract_address": "عنوان عقد الرمز",
"token_decimal": "رمز عشري",
@ -904,6 +933,7 @@
"transaction_sent_notice": "إذا لم تستمر الشاشة بعد دقيقة واحدة ، فتحقق من مستكشف البلوك والبريد الإلكتروني.",
"transactions": "المعاملات",
"transactions_by_date": "المعاملات حسب التاريخ",
"transport_type": "نوع النقل",
"trongrid_history": "تاريخ ترونغريد",
"trusted": "موثوق به",
"tx_commit_exception_no_dust_on_change": "يتم رفض المعاملة مع هذا المبلغ. باستخدام هذه العملات المعدنية ، يمكنك إرسال ${min} دون تغيير أو ${max} الذي يعيد التغيير.",
@ -932,6 +962,7 @@
"unspent_coins_details_title": "تفاصيل العملات الغير المنفقة",
"unspent_coins_title": "العملات الغير المنفقة",
"unsupported_asset": ".ﻡﻮﻋﺪﻣ ﻞﺻﺃ ﻉﻮﻧ ﻦﻣ ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻭﺃ ءﺎﺸﻧﺇ ﻰﺟﺮﻳ .ﻞﺻﻷﺍ ﺍﺬﻬﻟ ءﺍﺮﺟﻹﺍ ﺍﺬﻫ ﻢﻋﺪﻧ ﻻ ﻦﺤﻧ",
"update_session": "جلسة التحديث",
"uptime": "مدة التشغيل",
"upto": "حتى ${value}",
"usb": "USB",
@ -941,6 +972,7 @@
"use_ssl": "استخدم SSL",
"use_suggested": "استخدام المقترح",
"use_testnet": "استخدم testnet",
"user_rejected_method": "طريقة رفض المستخدم",
"value": "قيمة",
"value_type": "نوع القيمة",
"variable_pair_not_supported": "هذا الزوج المتغير غير مدعوم في التبادلات المحددة",
@ -1024,5 +1056,6 @@
"you_will_get": "حول الى",
"you_will_receive_estimated_amount": "سوف تتلقى(ooded )",
"you_will_send": "تحويل من",
"youCanGoBackToYourDapp": "يمكنك العودة إلى DAPP الخاص بك الآن",
"yy": "YY"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "Генерирайте ${type}. Получателят може да ${method} с всяка поддържана криптовалута и вие ще получите средства в този портфейл.",
"apk_update": "APK ъпдейт",
"approve": "Одобряване",
"approve_request": "Одобрете искане",
"arrive_in_this_address": "${currency} ${tag}ще отидат на този адрес",
"ascending": "Възходящ",
"ask_each_time": "Питайте всеки път",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "Чака се потвърждение на плащането",
"background_sync": "Фон Синхх",
"background_sync_mode": "Режим на синхронизиране на фона",
"background_sync_on_battery_low": "Синхронизирайте на ниска батерия",
"background_sync_on_charging": "Синхронизирайте само при зареждане",
"background_sync_on_device_idle": "Синхронизирайте само когато устройството не се използва",
"background_sync_on_unmetered_network": "Изисквайте незадоволена мрежа",
"backup": "Резервно копие",
"backup_file": "Резервно копие",
"backup_password": "Парола за възстановяване",
@ -116,9 +121,12 @@
"camera_consent": "Вашият фотоапарат ще бъде използван за заснемане на изображение с цел идентификация от ${provider}. Моля, проверете тяхната политика за поверителност за подробности.",
"camera_permission_is_required": "Изисква се разрешение за камерата.\nМоля, активирайте го от настройките на приложението.",
"cancel": "Откажи",
"cannot_verify": "Не може да провери",
"cannot_verify_description": "Този домейн не може да бъде проверен. Проверете внимателно заявката, преди да одобрите.",
"card_address": "Адрес:",
"cardholder_agreement": "Съгласие за картодържец",
"cards": "Карти",
"chain_id": "Идентификационен номер на веригата",
"chains": "Вериги",
"change": "Промени",
"change_backup_password_alert": "Предишните резервни копия не могат да бъдат импортирани с новата парола. Те ще се използва само за нови такива. Are you sure that you want to change backup password?",
@ -174,6 +182,7 @@
"connect_yats": "Добавете Yats",
"connect_your_hardware_wallet": "Свържете хардуерния си портфейл с помощта на Bluetooth или USB",
"connect_your_hardware_wallet_ios": "Свържете хардуерния си портфейл с помощта на Bluetooth",
"connected": "Свързани",
"connection_sync": "Свързване и синхронизиране",
"connectWalletPrompt": "Свържете портфейла си с WalletConnect, за да извършвате транзакции",
"contact": "Контакт",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "Деактивирайте оптимизацията на батерията",
"disableBatteryOptimizationDescription": "Искате ли да деактивирате оптимизацията на батерията, за да направите синхронизирането на фона да работи по -свободно и гладко?",
"disabled": "Деактивирано",
"disconnect_session": "Изключете сесията",
"discount": "Спестете ${value}%",
"display_settings": "Настройки на екрана",
"displayable": "Възможност за показване",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "Не споделяйте това с никого, дори и отдел поддръжка.\n\nПарите Ви могат и ще бъдат откраднати!",
"do_not_show_me": "Не показвай повече това",
"domain_looks_up": "Търсене на домейни",
"domain_mismatch": "Несъответствие на домейна",
"domain_mismatch_description": "Този уебсайт има домейн, който не съответства на подателя на тази заявка. Одобряването може да доведе до загуба на средства.",
"donation_link_details": "Подробности за връзката за дарение",
"e_sign_consent": "E-Sign съгласие",
"edit": "Промени",
@ -298,6 +310,7 @@
"error_text_template": "Имената на шаблони и адреси не могат да съдържат ` , ' \" \nи трябва да са между 1 и 106 символа.",
"error_text_wallet_name": "Името на портфейла може да съдържа само букви, цифри, и символите _ и - \n и трябва да е между 1 и 33 символа",
"error_text_xmr": "XMR сумата не може да надхвърля наличния баланс.\nБроят на цифрите след десетичната запетая може да бъде най-много 12",
"error_while_processing": "Възникна грешка при приемане",
"errorGettingCredentials": "Неуспешно: Грешка при получаване на идентификационни данни",
"errorSigningTransaction": "Възникна грешка при подписване на транзакция",
"estimated": "Изчислено",
@ -323,6 +336,7 @@
"export_backup": "Експортиране на резервно копие",
"export_logs": "Експортни дневници",
"export_outputs": "Експортни резултати",
"extend_session": "Удължаване на сесията",
"extra_id": "Допълнително ID:",
"extracted_address_content": "Ще изпратите средства на \n${recipient_name}",
"failed_authentication": "Неуспешно удостоверяване. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "Забравена парола",
"freeze": "Замразяване",
"frequently_asked_questions": "Често задавани въпроси",
"from": "От",
"frozen": "Замразени",
"frozen_balance": "Замразен баланс",
"full_balance": "Пълен баланс",
"gas_exceeds_allowance": "Газът, изискван от транзакцията, надвишава надбавката.",
"gas_price": "Цена на газ",
"generate_name": "Генериране на име",
"generating_gift_card": "Създаване на Gift Card",
"generating_transaction": "Генериране на транзакция",
@ -440,6 +456,8 @@
"memo": "Мемо:",
"message": "Съобщение",
"message_verified": "Съобщението беше успешно проверено",
"messages": "Съобщения",
"method": "Метод",
"methods": "Методи",
"min_amount": "Мин: ${value}",
"min_value": "Мин: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "Тъмна тема Monero",
"monero_light_theme": "Лека тема Monero",
"moonpay_alert_text": "Сумата трябва да бъде най-малко ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "Възникна грешка при извличането на NFT. Моля, проверете вашата интернет връзка и опитайте отново.",
"more_options": "Още настройки",
"multiple_addresses_detected": "Открити множество адреси",
"mweb_confirmed": "Потвърден MWeb",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "Име на Label",
"new_subaddress_title": "Нов адрес",
"new_template": "Нов шаблон",
"new_transactions_notifications": "Изпратете известия за нови транзакции",
"new_wallet": "Нов портфейл",
"newConnection": "Нова връзка",
"no_cards_found": "Не са намерени карти",
@ -492,6 +512,7 @@
"normal": "нормално",
"note_optional": "Бележка (не е задължително)",
"note_tap_to_change": "Бележка (натиснете за промяна)",
"notification_permission_denied": "Разрешението за уведомяване е отказано, моля, моля, активирайте го в настройки",
"nullURIError": "URI е нула",
"offer_expires_in": "Предложението изтича след: ",
"offline": "Офлайн",
@ -589,6 +610,7 @@
"rep_warning_sub": "Вашият представител изглежда не е в добро състояние. Докоснете тук, за да изберете нов",
"repeat_wallet_password": "Повторете паролата на портфейла",
"repeated_password_is_incorrect": "Многократната парола е неправилна. Моля, повторете отново паролата за портфейла.",
"requested": "Поискано",
"require_for_adding_contacts": "Изисква се за добавяне на контакти",
"require_for_all_security_and_backup_settings": "Изисква се за всички настройки за сигурност и архивиране",
"require_for_assessing_wallet": "Изискване за достъп до портфейла",
@ -650,6 +672,8 @@
"second_intro_content": "Вашият Yat е уникален адрес във формата на емоджи, който играе ролята на всички Ваши дълги шестнайсетични портфейли за всяка валута.",
"second_intro_title": "Един емоджи адрес, обединяващ всички останали.",
"security_and_backup": "Сигурност и резервни копия",
"security_risk": "Риск за сигурността",
"security_risk_description": "Този домейн се маркира като опасен от множество доставчици на сигурност. Оставете незабавно, за да защитите активите си.",
"seed_alert_back": "Назад",
"seed_alert_content": "Seed-ът е единственият начин да възстановите портфейла си. Записахте ли го?",
"seed_alert_title": "Внимание",
@ -764,7 +788,9 @@
"show_keys": "Покажи seed/keys",
"show_market_place": "Покажи пазар",
"show_seed": "Покажи seed",
"sign_all": "Подпишете всички",
"sign_message": "Съобщение за подписване",
"sign_one": "Подпишете един",
"sign_up": "Регистрация",
"sign_verify_message": "Подпишете / проверете",
"sign_verify_message_sub": "Подпишете или проверете съобщение с помощта на вашия личен ключ",
@ -798,6 +824,7 @@
"subaddress_title": "Лист от подадреси",
"subaddresses": "Подадреси",
"submit_request": "изпращане на заявка",
"success": "Успех",
"successful": "Успешен",
"support_description_guides": "Документация и подкрепа за общи проблеми",
"support_description_live_chat": "Безплатно и бързо! Обучени представители на подкрепата са на разположение за подпомагане",
@ -805,6 +832,7 @@
"support_title_guides": "Документи за портфейл за торта",
"support_title_live_chat": "Подкрепа на живо",
"support_title_other_links": "Други връзки за поддръжка",
"supported": "Поддържано",
"swap": "Разметка",
"sweeping_wallet": "Метещ портфейл",
"sweeping_wallet_alert": "Това не трябва да отнема много време. Не оставяйте този екран или пометените средства могат да бъдат загубени.",
@ -837,6 +865,7 @@
"thorchain_taproot_address_not_supported": "Доставчикът на Thorchain не поддържа адреси на TapRoot. Моля, променете адреса или изберете друг доставчик.",
"time": "${minutes} мин ${seconds} сек",
"tip": "Tip:",
"to": "Да",
"today": "Днес",
"token_contract_address": "Адрес на токен договор",
"token_decimal": "Токен десетичен",
@ -904,6 +933,7 @@
"transaction_sent_notice": "Ако процесът продължи повече от 1 минута, проверете някой block explorer и своя имейл.",
"transactions": "Транзакции",
"transactions_by_date": "Транзакции по дата",
"transport_type": "Тип транспорт",
"trongrid_history": "Trongrid History",
"trusted": "Надежден",
"tx_commit_exception_no_dust_on_change": "Сделката се отхвърля с тази сума. С тези монети можете да изпратите ${min} без промяна или ${max}, която връща промяна.",
@ -932,6 +962,7 @@
"unspent_coins_details_title": "Подробности за неизползваните монети",
"unspent_coins_title": "Неизползвани монети",
"unsupported_asset": "Не поддържаме това действие за този актив. Моля, създайте или преминете към портфейл от поддържан тип актив.",
"update_session": "Сесия за актуализиране",
"uptime": "Време за работа",
"upto": "до ${value}",
"usb": "USB",
@ -941,6 +972,7 @@
"use_ssl": "Използване на SSL",
"use_suggested": "Използване на предложеното",
"use_testnet": "Използвайте TestNet",
"user_rejected_method": "Отхвърлен метод на потребителя",
"value": "Стойност",
"value_type": "Тип стойност",
"variable_pair_not_supported": "Този variable pair не се поддържа от избраната борса",
@ -1024,5 +1056,6 @@
"you_will_get": "Обръщане в",
"you_will_receive_estimated_amount": "Ще получите(прогнозно )",
"you_will_send": "Обръщане от",
"youCanGoBackToYourDapp": "Можете да се върнете при вашия Dapp сега",
"yy": "гг"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "Vygenerujte ${type}. Příjemce může ${method} s jakoukoli podporovanou kryptoměnou a vy obdržíte prostředky v této peněžence.",
"apk_update": "aktualizace APK",
"approve": "Schvalovat",
"approve_request": "Schválit žádost",
"arrive_in_this_address": "${currency} ${tag}přijde na tuto adresu",
"ascending": "Vzestupné",
"ask_each_time": "Zeptejte se pokaždé",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "Čeká se na potvrzení platby",
"background_sync": "Synchronizace pozadí",
"background_sync_mode": "Režim synchronizace pozadí",
"background_sync_on_battery_low": "Synchronizace na nízké baterii",
"background_sync_on_charging": "Synchronizovat pouze při nabíjení",
"background_sync_on_device_idle": "Synchronizujte pouze tehdy, když se zařízení nepoužívá",
"background_sync_on_unmetered_network": "Vyžadovat nemetrovou síť",
"backup": "Záloha",
"backup_file": "Soubor se zálohou",
"backup_password": "Heslo pro zálohy",
@ -116,9 +121,12 @@
"camera_consent": "Váš fotoaparát použije k pořízení snímku pro účely identifikace ${provider}. Podrobnosti najdete v jejich Zásadách ochrany osobních údajů.",
"camera_permission_is_required": "Vyžaduje se povolení fotoaparátu.\nPovolte jej v nastavení aplikace.",
"cancel": "Zrušit",
"cannot_verify": "Nelze ověřit",
"cannot_verify_description": "Tuto doménu nelze ověřit. Před schválením pečlivě zkontrolujte požadavek.",
"card_address": "Adresa:",
"cardholder_agreement": "Smlouva držitele karty",
"cards": "Karty",
"chain_id": "ID řetězce",
"chains": "Řetězy",
"change": "Změnit",
"change_backup_password_alert": "Vaše předchozí soubory se zálohami nebude možné naimportovat s novým heslem. Nové heslo bude použito pouze pro nové zálohy. Opravdu chcete změnit heslo pro zálohy?",
@ -174,6 +182,7 @@
"connect_yats": "Připojit Yaty",
"connect_your_hardware_wallet": "Připojte hardwarovou peněženku pomocí Bluetooth nebo USB",
"connect_your_hardware_wallet_ios": "Připojte hardwarovou peněženku pomocí Bluetooth",
"connected": "Připojeno",
"connection_sync": "Připojení a synch.",
"connectWalletPrompt": "Propojte svou peněženku s WalletConnect a provádějte transakce",
"contact": "Kontakt",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "Zakázat optimalizaci baterie",
"disableBatteryOptimizationDescription": "Chcete deaktivovat optimalizaci baterie, aby se synchronizovala pozadí volně a hladce?",
"disabled": "Zakázáno",
"disconnect_session": "Odpojit relace",
"discount": "Ušetříte ${value}%",
"display_settings": "Nastavení zobrazení",
"displayable": "Zobrazitelné",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "Toto nesdílejte s nikým jiným, ani s podporou.\n\nJinak mohou být Vaše prostředky ukradeny!",
"do_not_show_me": "Příště nezobrazovat",
"domain_looks_up": "Vyhledávání domén",
"domain_mismatch": "Neshoda domény",
"domain_mismatch_description": "Tento web má doménu, která neodpovídá odesílateli této žádosti. Schválení může vést ke ztrátě finančních prostředků.",
"donation_link_details": "Podrobnosti odkazu na darování",
"e_sign_consent": "E-Sign souhlas",
"edit": "Upravit",
@ -298,6 +310,7 @@
"error_text_template": "Jméno šablony a adresa nemohou obsahovat symboly ` , ' \" \na musí mít délku 1 až 106 znaků",
"error_text_wallet_name": "Jméno peněženky může obsahovat pouze písmena, čísla, symbol _ \na musí mít délku 1 až 33 znaků",
"error_text_xmr": "Hodnota XMR nemůže překročit dostupný zůstatek.\nPočet desetinných míst musí být menší, nebo roven 12",
"error_while_processing": "Při převádění došlo k chybě",
"errorGettingCredentials": "Selhalo: Chyba při získávání přihlašovacích údajů",
"errorSigningTransaction": "Při podepisování transakce došlo k chybě",
"estimated": "Odhadováno",
@ -323,6 +336,7 @@
"export_backup": "Exportovat zálohu",
"export_logs": "Vývozní protokoly",
"export_outputs": "Vývozní výstupy",
"extend_session": "Prodloužit relaci",
"extra_id": "Extra ID:",
"extracted_address_content": "Prostředky budete posílat na\n${recipient_name}",
"failed_authentication": "Ověřování selhalo. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "Zapomenuté heslo",
"freeze": "Zmrazit",
"frequently_asked_questions": "Často kladené otázky",
"from": "Z",
"frozen": "Zmraženo",
"frozen_balance": "Zmrazená rovnováha",
"full_balance": "Celkový zůstatek",
"gas_exceeds_allowance": "Plyn vyžadovaný transakcí přesahuje příspěvek.",
"gas_price": "Cena plynu",
"generate_name": "Generovat jméno",
"generating_gift_card": "Generuji dárkovou kartu",
"generating_transaction": "Generování transakce",
@ -440,6 +456,8 @@
"memo": "Memo:",
"message": "Zpráva",
"message_verified": "Zpráva byla úspěšně ověřena",
"messages": "Zprávy",
"method": "Metoda",
"methods": "Metody",
"min_amount": "Min: ${value}",
"min_value": "Min: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "Tmavé téma Monero",
"monero_light_theme": "Světlé téma Monero",
"moonpay_alert_text": "Částka musí být větší nebo rovna ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "Při načítání NFT došlo k chybě. Laskavě zkontrolujte připojení k internetu a zkuste to znovu.",
"more_options": "Více možností",
"multiple_addresses_detected": "Detekované více adres",
"mweb_confirmed": "Potvrzený mweb",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "Popisek",
"new_subaddress_title": "Nová adresa",
"new_template": "Nová šablona",
"new_transactions_notifications": "Zašlete oznámení o nových transakcích",
"new_wallet": "Nová peněženka",
"newConnection": "Nové připojení",
"no_cards_found": "Žádné karty nenalezeny",
@ -492,6 +512,7 @@
"normal": "Normální",
"note_optional": "Poznámka (nepovinné)",
"note_tap_to_change": "Poznámka (poklepáním upravit)",
"notification_permission_denied": "Oznámení o oznámení bylo oprávněně zamítnuto, prosím ručně jej povolte v nastavení",
"nullURIError": "URI je nulové",
"offer_expires_in": "Nabídka vyprší: ",
"offline": "Offline",
@ -589,6 +610,7 @@
"rep_warning_sub": "Zdá se, že váš zástupce není v dobrém stavu. Klepnutím zde vyberte nový",
"repeat_wallet_password": "Opakujte heslo peněženky",
"repeated_password_is_incorrect": "Opakované heslo je nesprávné. Znovu opakujte heslo peněženky.",
"requested": "Požadováno",
"require_for_adding_contacts": "Vyžadovat pro přidání kontaktů",
"require_for_all_security_and_backup_settings": "Vyžadovat všechna nastavení zabezpečení a zálohování",
"require_for_assessing_wallet": "Vyžadovat pro přístup k peněžence",
@ -650,6 +672,8 @@
"second_intro_content": "Váš Yat je jediná unikátní emoji adresa, která nahrazuje všechny Vaše dlouhé hexadecimální adresy pro všechny Vaše měny.",
"second_intro_title": "Jedna emoji adresa vládne všem",
"security_and_backup": "Bezpečnost a zálohy",
"security_risk": "Bezpečnostní riziko",
"security_risk_description": "Tato doména je označena jako nebezpečná více poskytovateli zabezpečení. Okamžitě nechte chránit vaše aktiva.",
"seed_alert_back": "Zpět",
"seed_alert_content": "Tento seed představuje jedinou možnost, jak obnovit peněženku. Zapsali jste si ho?",
"seed_alert_title": "Pozor",
@ -764,7 +788,9 @@
"show_keys": "Zobrazit seed/klíče",
"show_market_place": "Zobrazit trh",
"show_seed": "Zobrazit seed",
"sign_all": "Podepište všechny",
"sign_message": "Podepsat zprávu",
"sign_one": "Podepsat jeden",
"sign_up": "Registrovat se",
"sign_verify_message": "Podepsat / ověřit",
"sign_verify_message_sub": "Podepište nebo ověřte zprávu pomocí soukromého klíče",
@ -798,6 +824,7 @@
"subaddress_title": "Seznam subadres",
"subaddresses": "Subadresy",
"submit_request": "odeslat požadavek",
"success": "Úspěch",
"successful": "Úspěšný",
"support_description_guides": "Dokumentace a podpora běžných otázek",
"support_description_live_chat": "Zdarma a rychle! K dispozici jsou zástupci vyškolených podpůrných podpory",
@ -805,6 +832,7 @@
"support_title_guides": "Dokumenty peněženky dortu",
"support_title_live_chat": "Živá podpora",
"support_title_other_links": "Další odkazy na podporu",
"supported": "Podporováno",
"swap": "Swap",
"sweeping_wallet": "Zametací peněženka",
"sweeping_wallet_alert": "To by nemělo trvat dlouho. Nenechávejte tuto obrazovku, jinak mohou být ztraceny prostředky.",
@ -837,6 +865,7 @@
"thorchain_taproot_address_not_supported": "Poskytovatel Thorchain nepodporuje adresy Taproot. Změňte adresu nebo vyberte jiného poskytovatele.",
"time": "${minutes}m ${seconds}s",
"tip": "Spropitné:",
"to": "Na",
"today": "Dnes",
"token_contract_address": "Adresa tokenové smlouvy",
"token_decimal": "Token v desítkové soustavě",
@ -904,6 +933,7 @@
"transaction_sent_notice": "Pokud proces nepokročí během 1 minuty, zkontrolujte block explorer a svůj e-mail.",
"transactions": "Transakce",
"transactions_by_date": "Transakce podle data",
"transport_type": "Typ transportu",
"trongrid_history": "Trongridní historie",
"trusted": "Důvěřovat",
"tx_commit_exception_no_dust_on_change": "Transakce je zamítnuta s touto částkou. S těmito mincemi můžete odeslat ${min} bez změny nebo ${max}, které se vrátí změna.",
@ -932,6 +962,7 @@
"unspent_coins_details_title": "Podrobnosti o neutracených mincích",
"unspent_coins_title": "Neutracené mince",
"unsupported_asset": "Tuto akci u tohoto díla nepodporujeme. Vytvořte nebo přepněte na peněženku podporovaného typu aktiv.",
"update_session": "Aktualizační relace",
"uptime": "Uptime",
"upto": "až ${value}",
"usb": "USB",
@ -941,6 +972,7 @@
"use_ssl": "Použít SSL",
"use_suggested": "Použít doporučený",
"use_testnet": "Použijte testNet",
"user_rejected_method": "Metoda odmítnutá uživatele",
"value": "Hodnota",
"value_type": "Typ hodnoty",
"variable_pair_not_supported": "Tento pár s tržním kurzem není ve zvolené směnárně podporován",
@ -1024,5 +1056,6 @@
"you_will_get": "Směnit na",
"you_will_receive_estimated_amount": "Obdržíte(odhadovaný )",
"you_will_send": "Směnit z",
"youCanGoBackToYourDapp": "Nyní se můžete vrátit do svého dappu",
"yy": "YY"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "Generieren Sie ${type}. Der Empfänger kann ${method} mit jeder unterstützten Kryptowährung verwenden, und Sie erhalten Geld in dieser Wallet.",
"apk_update": "APK-Update",
"approve": "Genehmigen",
"approve_request": "Anfrage genehmigen",
"arrive_in_this_address": "${currency} ${tag} wird an dieser Adresse ankommen",
"ascending": "Aufsteigend",
"ask_each_time": "Jedes Mal fragen",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "Warten auf Zahlungsbestätigung",
"background_sync": "Hintergrundsynchronisation",
"background_sync_mode": "Hintergrundsynchronisierungsmodus",
"background_sync_on_battery_low": "Synchronisieren Sie einen niedrigen Akku",
"background_sync_on_charging": "Nur beim Laden synchronisieren",
"background_sync_on_device_idle": "Nur dann synchronisieren, wenn das Gerät nicht verwendet wird",
"background_sync_on_unmetered_network": "Erfordern ein nicht modisches Netzwerk",
"backup": "Sicherung",
"backup_file": "Sicherungsdatei",
"backup_password": "Passwort sichern",
@ -116,9 +121,12 @@
"camera_consent": "Mit Ihrer Kamera wird bis zum ${provider} ein Bild zur Identifizierung aufgenommen. Weitere Informationen finden Sie in deren Datenschutzbestimmungen.",
"camera_permission_is_required": "Eine Kameraerlaubnis ist erforderlich.\nBitte aktivieren Sie es in den App-Einstellungen.",
"cancel": "Abbrechen",
"cannot_verify": "Kann nicht überprüfen",
"cannot_verify_description": "Diese Domäne kann nicht verifiziert werden. Überprüfen Sie die Anfrage vor der Genehmigung sorgfältig.",
"card_address": "Adresse:",
"cardholder_agreement": "Karteninhabervertrag",
"cards": "Karten",
"chain_id": "Ketten -ID",
"chains": "Blockchains",
"change": "Ändern",
"change_backup_password_alert": "Ihre vorherigen Sicherungsdateien können nicht mit einem neuen Sicherungskennwort importiert werden. Das neue Sicherungskennwort wird nur für neue Sicherungsdateien verwendet. Sind Sie sicher, dass Sie das Sicherungskennwort ändern möchten?",
@ -174,6 +182,7 @@
"connect_yats": "Yats verbinden",
"connect_your_hardware_wallet": "Verbinden Sie Ihre Hardware-Wallet über Bluetooth oder USB",
"connect_your_hardware_wallet_ios": "Verbinden Sie Ihre Hardware-Wallet über Bluetooth",
"connected": "Verbunden",
"connection_sync": "Verbindung und Synchronisierung",
"connectWalletPrompt": "Verbinden Sie Ihr Wallet mit WalletConnect, um Transaktionen durchzuführen",
"contact": "Kontakt",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "Batterieoptimierung deaktivieren",
"disableBatteryOptimizationDescription": "Möchten Sie die Batterieoptimierung deaktivieren, um die Hintergrundsynchronisierung reibungsloser zu gestalten?",
"disabled": "Deaktiviert",
"disconnect_session": "Sitzung trennen",
"discount": "${value} % sparen",
"display_settings": "Anzeigeeinstellungen",
"displayable": "Anzeigebar",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "Teilen Sie diese nicht mit anderen, einschließlich Support.\n\nIhr Geld kann und wird gestohlen werden!",
"do_not_show_me": "Zeig mir das nicht noch einmal",
"domain_looks_up": "Domain-Suchen",
"domain_mismatch": "Domänenfehlanpassung",
"domain_mismatch_description": "Diese Website hat eine Domain, die nicht mit dem Absender dieser Anfrage übereinstimmt. Die Genehmigung kann zum Verlust von Geldern führen.",
"donation_link_details": "Details zum Spendenlink",
"e_sign_consent": "E-Sign-Zustimmung",
"edit": "Bearbeiten",
@ -298,6 +310,7 @@
"error_text_template": "Vorlagenname und Adresse dürfen nicht die Zeichen ` , ' \" enthalten\nund müssen zwischen 1 und 106 Zeichen lang sein",
"error_text_wallet_name": "Der Wallet-Name darf nur Buchstaben, Zahlen und _- Symbole enthalten\nund muss zwischen 1 und 33 Zeichen lang sein",
"error_text_xmr": "Der XMR-Wert darf das verfügbare Guthaben nicht überschreiten.\nDie Anzahl der Nachkommastellen muss kleiner oder gleich 12 sein",
"error_while_processing": "Ein Fehler beim Proceessing trat ein Fehler auf",
"errorGettingCredentials": "Fehlgeschlagen: Fehler beim Abrufen der Anmeldeinformationen",
"errorSigningTransaction": "Beim Signieren der Transaktion ist ein Fehler aufgetreten",
"estimated": "Geschätzt",
@ -323,6 +336,7 @@
"export_backup": "Sicherung exportieren",
"export_logs": "Exportprotokolle",
"export_outputs": "Exportausgaben",
"extend_session": "Sitzung verlängern",
"extra_id": "Extra ID:",
"extracted_address_content": "Sie senden Geld an\n${recipient_name}",
"failed_authentication": "Authentifizierung fehlgeschlagen. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "Passwort vergessen",
"freeze": "Einfrieren",
"frequently_asked_questions": "Häufig gestellte Fragen",
"from": "Aus",
"frozen": "Gefroren",
"frozen_balance": "Gefrorenes Guthaben",
"full_balance": "Gesamtguthaben",
"gas_exceeds_allowance": "Die durch Transaktion erforderliche Gas übertrifft die Zulage.",
"gas_price": "Gaspreis",
"generate_name": "Namen generieren",
"generating_gift_card": "Geschenkkarte wird erstellt",
"generating_transaction": "Transaktion erzeugen",
@ -440,6 +456,8 @@
"memo": "Memo:",
"message": "Nachricht",
"message_verified": "Die Nachricht wurde erfolgreich überprüft",
"messages": "Nachrichten",
"method": "Verfahren",
"methods": "Methoden",
"min_amount": "Min: ${value}",
"min_value": "Min: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "Dunkles Monero-Thema",
"monero_light_theme": "Monero Light-Thema",
"moonpay_alert_text": "Der Wert des Betrags muss größer oder gleich ${minAmount} ${fiatCurrency} sein",
"moralis_nft_error": "Ein Fehler trat beim Abrufen von NFTs auf. Bitte überprüfen Sie Ihre Internetverbindung und versuchen Sie es erneut.",
"more_options": "Weitere Optionen",
"multiple_addresses_detected": "Mehrere Adressen erkannt",
"mweb_confirmed": "Bestätigt MWeb",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "Bezeichnung",
"new_subaddress_title": "Neue Adresse",
"new_template": "neue Vorlage",
"new_transactions_notifications": "Senden Sie Benachrichtigungen über neue Transaktionen",
"new_wallet": "Neue Wallet",
"newConnection": "Neue Verbindung",
"no_cards_found": "Keine Karten gefunden",
@ -492,6 +512,7 @@
"normal": "Normal",
"note_optional": "Bemerkung (optional)",
"note_tap_to_change": "Bemerkung (zum Ändern tippen)",
"notification_permission_denied": "Die Benachrichtigungsgenehmigung wurde verweigert verweigert. Bitte ermöglichen Sie dies manuell in Einstellungen",
"nullURIError": "URI ist null",
"offer_expires_in": "Angebot läuft ab in: ",
"offline": "offline",
@ -535,8 +556,8 @@
"please_choose_one": "Bitte wählen Sie einen",
"please_fill_totp": "Bitte geben Sie den 8-stelligen Code ein, der auf Ihrem anderen Gerät vorhanden ist",
"please_make_selection": "Bitte treffen Sie unten eine Auswahl zum Erstellen oder Wiederherstellen Ihrer Wallet.",
"please_reference_document": "Bitte verweisen Sie auf die folgenden Dokumente, um weitere Informationen zu erhalten.",
"Please_reference_document": "Weitere Informationen finden Sie in den Dokumenten unten.",
"please_reference_document": "Bitte verweisen Sie auf die folgenden Dokumente, um weitere Informationen zu erhalten.",
"please_select": "Bitte auswählen:",
"please_select_backup_file": "Bitte wählen Sie die Sicherungsdatei und geben Sie das Sicherungskennwort ein.",
"please_try_to_connect_to_another_node": "Bitte versuchen Sie, sich mit einem anderen Knoten zu verbinden",
@ -590,6 +611,7 @@
"rep_warning_sub": "Ihr Vertreter scheint nicht gut zu sein. Tippen Sie hier, um eine neue auszuwählen",
"repeat_wallet_password": "Wiederholen Sie das Walletkennwort",
"repeated_password_is_incorrect": "Wiederholtes Passwort ist falsch. Bitte wiederholen Sie das Walletkennwort erneut.",
"requested": "Angefordert",
"require_for_adding_contacts": "Erforderlich zum Hinzufügen von Kontakten",
"require_for_all_security_and_backup_settings": "Für alle Sicherheits- und Sicherungseinstellungen erforderlich",
"require_for_assessing_wallet": "Für den Zugriff auf die Wallet erforderlich",
@ -651,6 +673,8 @@
"second_intro_content": "Ihr Yat ist eine einzige eindeutige Emoji-Adresse, die alle Ihre langen hexadezimalen Adressen für alle Ihre Währungen ersetzt.",
"second_intro_title": "Eine Emoji-Adresse, um sie alle zu beherrschen",
"security_and_backup": "Sicherheit und Datensicherung",
"security_risk": "Sicherheitsrisiko",
"security_risk_description": "Diese Domäne wird von mehreren Sicherheitsanbietern als unsicher gekennzeichnet. Gehen Sie sofort auf, um Ihr Vermögen zu schützen.",
"seed_alert_back": "Zurückgehen",
"seed_alert_content": "Der Seed ist der einzige Weg, Ihre Wallet wiederherzustellen. Haben Sie ihn aufgeschrieben?",
"seed_alert_title": "Achtung",
@ -765,7 +789,9 @@
"show_keys": "Seed/Schlüssel anzeigen",
"show_market_place": "Marktplatz anzeigen",
"show_seed": "Seed zeigen",
"sign_all": "Alle unterschreiben",
"sign_message": "Nachricht unterschreiben",
"sign_one": "Unterschreiben",
"sign_up": "Anmelden",
"sign_verify_message": "Zeichen / überprüfen",
"sign_verify_message_sub": "Unterschreiben oder überprüfen Sie eine Nachricht mit Ihrem privaten Schlüssel",
@ -799,6 +825,7 @@
"subaddress_title": "Unteradressenliste",
"subaddresses": "Unteradressen",
"submit_request": "Eine Anfrage stellen",
"success": "Erfolg",
"successful": "Erfolgreich",
"support_description_guides": "Dokumentation und Hilfe für bekannte Probleme",
"support_description_live_chat": "Kostenlos und schnell! Ausgebildete Mitarbeiter stehen zur Unterstützung bereit, um zu helfen",
@ -806,6 +833,7 @@
"support_title_guides": "Cake Wallet Docs",
"support_title_live_chat": "Live Support",
"support_title_other_links": "Andere Support-Links",
"supported": "Unterstützt",
"swap": "Tauschen",
"sweeping_wallet": "Wallet leeren",
"sweeping_wallet_alert": "Das sollte nicht lange dauern. VERLASSEN SIE DIESEN BILDSCHIRM NICHT, ANDERNFALLS KÖNNEN DIE GELDER VERLOREN GEHEN",
@ -838,6 +866,7 @@
"thorchain_taproot_address_not_supported": "Der Thorchain-Anbieter unterstützt keine Taproot-Adressen. Bitte ändern Sie die Adresse oder wählen Sie einen anderen Anbieter aus.",
"time": "${minutes}m ${seconds}s",
"tip": "Hinweis:",
"to": "Zu",
"today": "Heute",
"token_contract_address": "Token-Contract-Adresse",
"token_decimal": "Token-Dezimalzahl",
@ -905,6 +934,7 @@
"transaction_sent_notice": "Wenn der Bildschirm nach 1 Minute nicht weitergeht, überprüfen Sie einen Block-Explorer und Ihre E-Mail.",
"transactions": "Transaktionen",
"transactions_by_date": "Transaktionen nach Datum",
"transport_type": "Transporttyp",
"trongrid_history": "Trongrid-Historie",
"trusted": "Vertrauenswürdige",
"tx_commit_exception_no_dust_on_change": "Die Transaktion wird diesen Betrag abgelehnt. Mit diesen Münzen können Sie ${min} ohne Veränderung oder ${max} senden, die Änderungen zurückgeben.",
@ -934,6 +964,7 @@
"unspent_coins_details_title": "Details zu nicht ausgegebenen Coins",
"unspent_coins_title": "Nicht ausgegebene Coins",
"unsupported_asset": "Wir unterstützen diese Aktion für dieses Asset nicht. Bitte erstellen Sie eine Wallet eines unterstützten Asset-Typs oder wechseln Sie zu einer Wallet.",
"update_session": "Sitzung aktualisieren",
"uptime": "Betriebszeit",
"upto": "bis zu ${value}",
"usb": "USB",
@ -943,6 +974,7 @@
"use_ssl": "SSL verwenden",
"use_suggested": "Vorgeschlagen verwenden",
"use_testnet": "TESTNET verwenden",
"user_rejected_method": "Benutzerverletzte Methode",
"value": "Wert",
"value_type": "Werttyp",
"variable_pair_not_supported": "Dieses Variablenpaar wird von den ausgewählten Börsen nicht unterstützt",
@ -1027,5 +1059,6 @@
"you_will_get": "Konvertieren zu",
"you_will_receive_estimated_amount": "Sie erhalten(geschätzt )",
"you_will_send": "Konvertieren von",
"youCanGoBackToYourDapp": "Sie können jetzt zu Ihrem Dapp zurückkehren",
"yy": "YY"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "Generate ${type}. The recipient can ${method} with any supported cryptocurrency, and you will receive funds in this wallet.",
"apk_update": "APK update",
"approve": "Approve",
"approve_request": "Approve Request",
"arrive_in_this_address": "${currency} ${tag}will arrive in this address",
"ascending": "Ascending",
"ask_each_time": "Ask each time",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "Awaiting Payment Confirmation",
"background_sync": "Background sync",
"background_sync_mode": "Background sync mode",
"background_sync_on_battery_low": "Synchronize on low battery",
"background_sync_on_charging": "Synchronize only when charging",
"background_sync_on_device_idle": "Synchronize only when device is not being used",
"background_sync_on_unmetered_network": "Require unmetred network",
"backup": "Backup",
"backup_file": "Backup file",
"backup_password": "Backup password",
@ -116,9 +121,12 @@
"camera_consent": "Your camera will be used to capture an image for identification purposes by ${provider}. Please check their Privacy Policy for details.",
"camera_permission_is_required": "Camera permission is required. \nPlease enable it from app settings.",
"cancel": "Cancel",
"cannot_verify": "Cannot Verify",
"cannot_verify_description": "This domain cannot be verified. Check the request carefully before approving.",
"card_address": "Address:",
"cardholder_agreement": "Cardholder Agreement",
"cards": "Cards",
"chain_id": "Chain ID",
"chains": "Chains",
"change": "Change",
"change_backup_password_alert": "Your previous backup files will be not available to import with new backup password. New backup password will be used only for new backup files. Are you sure that you want to change backup password?",
@ -174,6 +182,7 @@
"connect_yats": "Connect Yats",
"connect_your_hardware_wallet": "Connect your hardware wallet using Bluetooth or USB",
"connect_your_hardware_wallet_ios": "Connect your hardware wallet using Bluetooth",
"connected": "Connected",
"connection_sync": "Connection and sync",
"connectWalletPrompt": "Connect your wallet with WalletConnect to make transactions",
"contact": "Contact",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "Disable Battery Optimization",
"disableBatteryOptimizationDescription": "Do you want to disable battery optimization in order to make background sync run more freely and smoothly?",
"disabled": "Disabled",
"disconnect_session": "Disconnect Session",
"discount": "Save ${value}%",
"display_settings": "Display settings",
"displayable": "Displayable",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "Do not share these with anyone else, including support.\n\nYour funds can and will be stolen!",
"do_not_show_me": "Do not show me this again",
"domain_looks_up": "Domain lookups",
"domain_mismatch": "Domain Mismatch",
"domain_mismatch_description": "This website has a domain that does not match the sender of this request. Approving may lead to loss of funds.",
"donation_link_details": "Donation link details",
"e_sign_consent": "E-Sign Consent",
"edit": "Edit",
@ -298,6 +310,7 @@
"error_text_template": "Template name and address can't contain ` , ' \" symbols\nand must be between 1 and 106 characters long",
"error_text_wallet_name": "Wallet name can only contain letters, numbers, _ - symbols \nand must be between 1 and 33 characters long",
"error_text_xmr": "XMR value can't exceed available balance.\nThe number of fraction digits must be less or equal to 12",
"error_while_processing": "An error occurred while proceessing",
"errorGettingCredentials": "Failed: Error while getting credentials",
"errorSigningTransaction": "An error has occured while signing transaction",
"estimated": "Estimated",
@ -323,6 +336,7 @@
"export_backup": "Export backup",
"export_logs": "Export logs",
"export_outputs": "Export outputs",
"extend_session": "Extend Session",
"extra_id": "Extra ID:",
"extracted_address_content": "You will be sending funds to\n${recipient_name}",
"failed_authentication": "Failed authentication. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "Forgot Password",
"freeze": "Freeze",
"frequently_asked_questions": "Frequently asked questions",
"from": "From",
"frozen": "Frozen",
"frozen_balance": "Frozen Balance",
"full_balance": "Full Balance",
"gas_exceeds_allowance": "Gas required by transaction exceeds allowance.",
"gas_price": "Gas price",
"generate_name": "Generate Name",
"generating_gift_card": "Generating Gift Card",
"generating_transaction": "Generating transaction",
@ -440,6 +456,8 @@
"memo": "Memo:",
"message": "Message",
"message_verified": "The message was successfully verified",
"messages": "Messages",
"method": "Method",
"methods": "Methods",
"min_amount": "Min: ${value}",
"min_value": "Min: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "Monero Dark Theme",
"monero_light_theme": "Monero Light Theme",
"moonpay_alert_text": "Value of the amount must be more or equal to ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "An error occurred while fetching NFTs. Kindly check your internet connection and try again.",
"more_options": "More Options",
"multiple_addresses_detected": "Multiple addresses detected",
"mweb_confirmed": "Confirmed MWEB",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "Label name",
"new_subaddress_title": "New address",
"new_template": "New Template",
"new_transactions_notifications": "Send notifications about new transactions",
"new_wallet": "New Wallet",
"newConnection": "New Connection",
"no_cards_found": "No cards found",
@ -492,6 +512,7 @@
"normal": "Normal",
"note_optional": "Note (optional)",
"note_tap_to_change": "Note (tap to change)",
"notification_permission_denied": "Notification permission got permamently denied, please manually enable it in settings",
"nullURIError": "URI is null",
"offer_expires_in": "Offer expires in: ",
"offline": "Offline",
@ -590,6 +611,7 @@
"rep_warning_sub": "Your representative does not appear to be in good standing. Tap here to select a new one",
"repeat_wallet_password": "Repeat the wallet password",
"repeated_password_is_incorrect": "Repeated password is incorrect. Please repeat the wallet password again.",
"requested": "Requested",
"require_for_adding_contacts": "Require for adding contacts",
"require_for_all_security_and_backup_settings": "Require for all security and backup settings",
"require_for_assessing_wallet": "Require for accessing wallet",
@ -651,6 +673,8 @@
"second_intro_content": "Your Yat is a single unique emoji address that replaces all of your long hexadecimal addresses for all of your currencies.",
"second_intro_title": "One emoji address to rule them all",
"security_and_backup": "Security and backup",
"security_risk": "Security Risk",
"security_risk_description": "This domain is flagged as unsafe by multiple security providers. Leave immediately to protect your assets.",
"seed_alert_back": "Go back",
"seed_alert_content": "The seed is the only way to recover your wallet. Have you written it down?",
"seed_alert_title": "Attention",
@ -765,7 +789,9 @@
"show_keys": "Show seed/keys",
"show_market_place": "Show Marketplace",
"show_seed": "Show seed",
"sign_all": "Sign All",
"sign_message": "Sign Message",
"sign_one": "Sign One",
"sign_up": "Sign Up",
"sign_verify_message": "Sign / Verify",
"sign_verify_message_sub": "Sign or verify a message using your private key",
@ -799,6 +825,7 @@
"subaddress_title": "Subaddress list",
"subaddresses": "Subaddresses",
"submit_request": "submit a request",
"success": "Success",
"successful": "Successful",
"support_description_guides": "Documentation and support for common issues",
"support_description_live_chat": "Free and fast! Trained support representatives are available to assist",
@ -806,6 +833,7 @@
"support_title_guides": "Cake Wallet docs",
"support_title_live_chat": "Live support",
"support_title_other_links": "Other support links",
"supported": "Supported",
"swap": "Swap",
"sweeping_wallet": "Sweeping wallet",
"sweeping_wallet_alert": "This shouldnt take long. DO NOT LEAVE THIS SCREEN OR THE SWEPT FUNDS MAY BE LOST.",
@ -838,6 +866,7 @@
"thorchain_taproot_address_not_supported": "The ThorChain provider does not support Taproot addresses. Please change the address or select a different provider.",
"time": "${minutes}m ${seconds}s",
"tip": "Tip:",
"to": "To",
"today": "Today",
"token_contract_address": "Token contract address",
"token_decimal": "Token decimal",
@ -905,6 +934,7 @@
"transaction_sent_notice": "If the screen doesnt proceed after 1 minute, check a block explorer and your email.",
"transactions": "Transactions",
"transactions_by_date": "Transactions by date",
"transport_type": "Transport Type",
"trongrid_history": "TronGrid history",
"trusted": "Trusted",
"tx_commit_exception_no_dust_on_change": "The transaction is rejected with this amount. With these coins you can send ${min} without change or ${max} that returns change.",
@ -933,6 +963,7 @@
"unspent_coins_details_title": "Unspent coins details",
"unspent_coins_title": "Unspent coins",
"unsupported_asset": "We don't support this action for this asset. Please create or switch to a wallet of a supported asset type.",
"update_session": "Update Session",
"uptime": "Uptime",
"upto": "up to ${value}",
"usb": "USB",
@ -942,6 +973,7 @@
"use_ssl": "Use SSL",
"use_suggested": "Use Suggested",
"use_testnet": "Use Testnet",
"user_rejected_method": "User rejected method",
"value": "Value",
"value_type": "Value Type",
"variable_pair_not_supported": "This variable pair is not supported with the selected exchanges",
@ -1025,5 +1057,6 @@
"you_will_get": "Convert to",
"you_will_receive_estimated_amount": "You will receive (estimated)",
"you_will_send": "Convert from",
"youCanGoBackToYourDapp": "You can go back to your dApp now",
"yy": "YY"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "Genera ${type}. El destinatario puede ${method} con cualquier criptomoneda admitida, y recibirá fondos en esta billetera.",
"apk_update": "Actualización de APK",
"approve": "Aprobar",
"approve_request": "Aprobar la solicitud",
"arrive_in_this_address": "${currency} ${tag}llegará a esta dirección",
"ascending": "Ascendente",
"ask_each_time": "Pregunta cada vez",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "Esperando confirmación de pago",
"background_sync": "Sincronización en segundo plano",
"background_sync_mode": "Modo de sincronización en segundo plano",
"background_sync_on_battery_low": "Sincronizar con batería baja",
"background_sync_on_charging": "Sincronizar solo al cargar",
"background_sync_on_device_idle": "Sincronizar solo cuando el dispositivo no se usa",
"background_sync_on_unmetered_network": "Requerir una red no metida",
"backup": "Apoyo",
"backup_file": "Archivo de respaldo",
"backup_password": "Contraseña de respaldo",
@ -116,9 +121,12 @@
"camera_consent": "Su cámara será utilizada para capturar una imagen con fines de identificación por ${provider}. Consulta tu Política de privacidad para obtener más detalles.",
"camera_permission_is_required": "Se requiere permiso de la cámara.\nHabilítalo desde la configuración de la aplicación.",
"cancel": "Cancelar",
"cannot_verify": "No se puede verificar",
"cannot_verify_description": "Este dominio no se puede verificar. Verifique la solicitud cuidadosamente antes de aprobar.",
"card_address": "Dirección:",
"cardholder_agreement": "Acuerdo del titular de la tarjeta",
"cards": "Cartas",
"chain_id": "ID de cadena",
"chains": "Cadenas",
"change": "Cambio",
"change_backup_password_alert": "Tus archivos de respaldo anteriores no estarán disponibles para importar con la nueva contraseña de respaldo. La nueva contraseña de respaldo se utilizará solo para los nuevos archivos de respaldo. ¿Está seguro de que desea cambiar la contraseña de respaldo?",
@ -174,6 +182,7 @@
"connect_yats": "Conectar Yats",
"connect_your_hardware_wallet": "Conecta tu billetera de hardware con Bluetooth o USB",
"connect_your_hardware_wallet_ios": "Conecta tu billetera de hardware con Bluetooth",
"connected": "Conectado",
"connection_sync": "Conexión y sincronización",
"connectWalletPrompt": "Conecte tu billetera con WalletConnect para realizar transacciones",
"contact": "Contacto",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "Deshabilitar la optimización de la batería",
"disableBatteryOptimizationDescription": "¿Desea deshabilitar la optimización de la batería para que la sincronización de fondo se ejecute más libremente y sin problemas?",
"disabled": "Desactivado",
"disconnect_session": "Desconectar la sesión",
"discount": "Ahorra ${value}%",
"display_settings": "Configuración de pantalla",
"displayable": "Visualizable",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "No compartas estos con nadie más, incluido el soporte.\n\n¡Tus fondos pueden ser y serán robados!",
"do_not_show_me": "no me muestres esto otra vez",
"domain_looks_up": "Búsquedas de dominio",
"domain_mismatch": "Desajuste de dominio",
"domain_mismatch_description": "Este sitio web tiene un dominio que no coincide con el remitente de esta solicitud. La aprobación puede conducir a la pérdida de fondos.",
"donation_link_details": "Detalles del enlace de donación",
"e_sign_consent": "Consentimiento de firma electrónica",
"edit": "Editar",
@ -298,6 +310,7 @@
"error_text_template": "El nombre y la dirección de la plantilla no pueden contener símbolos ` , '\" \ny debe tener entre 1 y 106 caracteres de longitud",
"error_text_wallet_name": "El nombre de la billetera solo puede contener letras, números , _ - símbolos\ny debe tener entre 1 y 33 caracteres de longitud",
"error_text_xmr": "El valor XMR no puede exceder el saldo disponible.\nTEl número de dígitos de fracción debe ser menor o igual a 12",
"error_while_processing": "Se produjo un error mientras procesaba",
"errorGettingCredentials": "Error: error al obtener las credenciales",
"errorSigningTransaction": "Se ha producido un error al firmar la transacción.",
"estimated": "Estimado",
@ -323,6 +336,7 @@
"export_backup": "Exportar copia de seguridad",
"export_logs": "Registros de exportación",
"export_outputs": "Exportaciones de exportación",
"extend_session": "Extender la sesión",
"extra_id": "ID adicional:",
"extracted_address_content": "Enviará fondos a\n${recipient_name}",
"failed_authentication": "Autenticación fallida. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "Olvidé mi contraseña",
"freeze": "Congelar",
"frequently_asked_questions": "Preguntas frecuentes",
"from": "De",
"frozen": "Congelada",
"frozen_balance": "Equilibrio congelado",
"full_balance": "Balance completo",
"gas_exceeds_allowance": "El gas requerido por la transacción excede la asignación.",
"gas_price": "Precio de gas",
"generate_name": "Generar nombre",
"generating_gift_card": "Generando tarjeta de regalo",
"generating_transaction": "Generación de transacciones",
@ -440,6 +456,8 @@
"memo": "Memorándum:",
"message": "Mensaje",
"message_verified": "El mensaje fue verificado con éxito",
"messages": "Mensajes",
"method": "Método",
"methods": "Métodos",
"min_amount": "Mínimo: ${value}",
"min_value": "Min: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "Tema oscuro de Monero",
"monero_light_theme": "Tema ligero de Monero",
"moonpay_alert_text": "El valor de la cantidad debe ser mayor o igual a ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "Se produjo un error al alcanzar las NFT. Por favor, consulte su conexión a Internet y vuelva a intentarlo.",
"more_options": "Más Opciones",
"multiple_addresses_detected": "Múltiples direcciones detectadas",
"mweb_confirmed": "Confirmado mweb",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "Nombre de etiqueta",
"new_subaddress_title": "Nueva direccion",
"new_template": "Nueva plantilla",
"new_transactions_notifications": "Enviar notificaciones sobre nuevas transacciones",
"new_wallet": "Nueva billetera",
"newConnection": "Nueva conexión",
"no_cards_found": "No se encuentran cartas",
@ -492,6 +512,7 @@
"normal": "Normal",
"note_optional": "Nota (opcional)",
"note_tap_to_change": "Nota (toque para cambiar)",
"notification_permission_denied": "El permiso de notificación se negó de manera permanente, por favor, habilite manualmente en la configuración",
"nullURIError": "URI es nula",
"offer_expires_in": "Oferta expira en: ",
"offline": "fuera de línea",
@ -590,6 +611,7 @@
"rep_warning_sub": "Tu representante no parece estar en buena posición. Toca aquí para seleccionar uno nuevo",
"repeat_wallet_password": "Repite la contraseña de billetera",
"repeated_password_is_incorrect": "La contraseña repetida es incorrecta. Repite la contraseña de la billetera nuevamente.",
"requested": "Solicitado",
"require_for_adding_contacts": "Requerido para agregar contactos",
"require_for_all_security_and_backup_settings": "Requerido para todas las configuraciones de seguridad y copia de seguridad",
"require_for_assessing_wallet": "Requerido para acceder a la billetera",
@ -651,6 +673,8 @@
"second_intro_content": "Tu Yat es una única dirección emoji única que reemplaza todas tus direcciones hexadecimales largas para todas tus monedas.",
"second_intro_title": "Una dirección de emoji para gobernarlos a todos",
"security_and_backup": "Seguridad y respaldo",
"security_risk": "Riesgo de seguridad",
"security_risk_description": "Este dominio es marcado como inseguro por múltiples proveedores de seguridad. Deje inmediatamente para proteger sus activos.",
"seed_alert_back": "Regresa",
"seed_alert_content": "La semilla es la única forma de recuperar su billetera. ¿Lo has escrito?",
"seed_alert_title": "Atención",
@ -765,7 +789,9 @@
"show_keys": "Mostrar semilla/claves",
"show_market_place": "Mostrar mercado",
"show_seed": "Mostrar semilla",
"sign_all": "Firmar todo",
"sign_message": "Mensaje de firma",
"sign_one": "Firmar",
"sign_up": "Registrarse",
"sign_verify_message": "Firmar / verificar",
"sign_verify_message_sub": "Firmar o verificar un mensaje usando su clave privada",
@ -799,6 +825,7 @@
"subaddress_title": "Lista de subdirecciones",
"subaddresses": "Subdirecciones",
"submit_request": "presentar una solicitud",
"success": "Éxito",
"successful": "Exitoso",
"support_description_guides": "Documentación y apoyo para problemas comunes",
"support_description_live_chat": "¡GRATIS y RÁPIDO! Los representantes de apoyo capacitado están disponibles para ayudar",
@ -806,6 +833,7 @@
"support_title_guides": "Documentos de billetera de pastel",
"support_title_live_chat": "Soporte en tiempo real",
"support_title_other_links": "Otros enlaces de soporte",
"supported": "Compatible",
"swap": "Intercambio",
"sweeping_wallet": "Barrer billetera (gastar todos los fondos disponibles)",
"sweeping_wallet_alert": "Esto no debería llevar mucho tiempo. NO DEJES ESTA PANTALLA O SE PUEDEN PERDER LOS FONDOS BARRIDOS",
@ -838,6 +866,7 @@
"thorchain_taproot_address_not_supported": "El proveedor de Thorchain no admite las direcciones de Taproot. Cambia la dirección o selecciona un proveedor diferente.",
"time": "${minutes}m ${seconds}s",
"tip": "Consejo:",
"to": "A",
"today": "Hoy",
"token_contract_address": "Dirección de contrato de token",
"token_decimal": "Token decimal",
@ -905,6 +934,7 @@
"transaction_sent_notice": "Si la pantalla no continúa después de 1 minuto, revisa un explorador de bloques y tu correo electrónico.",
"transactions": "Transacciones",
"transactions_by_date": "Transacciones por fecha",
"transport_type": "Tipo de transporte",
"trongrid_history": "Historia trongrid",
"trusted": "de confianza",
"tx_commit_exception_no_dust_on_change": "La transacción se rechaza con esta cantidad. Con estas monedas puede enviar ${min} sin cambios o ${max} que devuelve el cambio.",
@ -933,6 +963,7 @@
"unspent_coins_details_title": "Detalles de monedas no gastadas",
"unspent_coins_title": "Monedas no gastadas",
"unsupported_asset": "No admitimos esta acción para este activo. Cree o cambie a una billetera de un tipo de activo admitido.",
"update_session": "Sesión de actualización",
"uptime": "Tiempo de actividad",
"upto": "hasta ${value}",
"usb": "USB",
@ -942,6 +973,7 @@
"use_ssl": "Utiliza SSL",
"use_suggested": "Usar sugerido",
"use_testnet": "Usar TestNet",
"user_rejected_method": "Método rechazado por el usuario",
"value": "Valor",
"value_type": "Tipo de valor",
"variable_pair_not_supported": "Este par de variables no es compatible con los intercambios seleccionados",
@ -1025,5 +1057,6 @@
"you_will_get": "Convertir a",
"you_will_receive_estimated_amount": "Recibirá(estimado )",
"you_will_send": "Convertir de",
"youCanGoBackToYourDapp": "Puedes volver a tu dapp ahora",
"yy": "YY"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "Générez ${type}. Le destinataire peut ${method} avec n'importe quelle crypto-monnaie prise en charge, et vous recevrez des fonds dans ce portefeuille (wallet).",
"apk_update": "Mise à jour d'APK",
"approve": "Approuver",
"approve_request": "Approuver la demande",
"arrive_in_this_address": "${currency} ${tag}arrivera à cette adresse",
"ascending": "Ascendant",
"ask_each_time": "Demander à chaque fois",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "En attente de confirmation de paiement",
"background_sync": "Synchronisation de fond",
"background_sync_mode": "Mode de synchronisation en arrière-plan",
"background_sync_on_battery_low": "Synchroniser sur une batterie basse",
"background_sync_on_charging": "Synchroniser uniquement lors de la charge",
"background_sync_on_device_idle": "Synchroniser uniquement lorsque l'appareil n'est pas utilisé",
"background_sync_on_unmetered_network": "Exiger un réseau non métallique",
"backup": "Sauvegarde",
"backup_file": "Fichier de sauvegarde",
"backup_password": "Mot de passe de sauvegarde",
@ -116,9 +121,12 @@
"camera_consent": "Votre appareil photo sera utilisé pour capturer une image à des fins d'identification par ${provider}. Veuillez consulter leur politique de confidentialité pour plus de détails.",
"camera_permission_is_required": "L'autorisation de la caméra est requise.\nVeuillez l'activer à partir des paramètres de l'application.",
"cancel": "Annuler",
"cannot_verify": "Ne peut pas vérifier",
"cannot_verify_description": "Ce domaine ne peut pas être vérifié. Vérifiez attentivement la demande avant d'approuver.",
"card_address": "Adresse:",
"cardholder_agreement": "Contrat de titulaire de carte",
"cards": "Cartes",
"chain_id": "Chaîne ID",
"chains": "Chaînes",
"change": "Changer",
"change_backup_password_alert": "Vos fichiers de sauvegarde précédents ne pourront pas être importés avec le nouveau mot de passe de sauvegarde. Le nouveau mot de passe ne sera utilisé que pour les nouveaux fichiers de sauvegarde. Êtes vous certain de vouloir modifier le mot de passe de sauvegarde ?",
@ -174,6 +182,7 @@
"connect_yats": "Connecter Yats",
"connect_your_hardware_wallet": "Connectez votre portefeuille matériel à l'aide de Bluetooth ou USB",
"connect_your_hardware_wallet_ios": "Connectez votre portefeuille matériel à l'aide de Bluetooth",
"connected": "Connecté",
"connection_sync": "Connexion et synchronisation",
"connectWalletPrompt": "Connectez votre portefeuille (wallet) avec WalletConnect pour effectuer des transactions",
"contact": "Contact",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "Désactiver l'optimisation de la batterie",
"disableBatteryOptimizationDescription": "Voulez-vous désactiver l'optimisation de la batterie afin de faire fonctionner la synchronisation d'arrière-plan plus librement et en douceur?",
"disabled": "Désactivé",
"disconnect_session": "Débrancher la session",
"discount": "Économisez ${value}%",
"display_settings": "Paramètres d'affichage",
"displayable": "Visible",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "Ne les partagez avec personne, y compris avec l'assistance.\n\nVos fonds seraient inmanquablement volés !",
"do_not_show_me": "Ne plus me montrer ceci à l'avenir",
"domain_looks_up": "Résolution de nom",
"domain_mismatch": "Décalage du domaine",
"domain_mismatch_description": "Ce site Web a un domaine qui ne correspond pas à l'expéditeur de cette demande. L'approbation peut entraîner une perte de fonds.",
"donation_link_details": "Détails du lien de don",
"e_sign_consent": "Consentement de signature électronique",
"edit": "Modifier",
@ -298,6 +310,7 @@
"error_text_template": "Le nom du modèle et l'adresse ne peuvent pas contenir les symboles ` , ' \"\net leur longueur doit être comprise entre 1 et 106 caractères",
"error_text_wallet_name": "Le nom du portefeuille (wallet) ne peut contenir que des lettres et des chiffres\net sa longueur doit être comprise entre 1 et 15 caractères",
"error_text_xmr": "La valeur de XMR dépasse le solde disponible.\nLa partie décimale doit comporter au plus 12 chiffres",
"error_while_processing": "Une erreur s'est produite lors de la procédure",
"errorGettingCredentials": "Échec : erreur lors de l'obtention des informations d'identification",
"errorSigningTransaction": "Une erreur s'est produite lors de la signature de la transaction",
"estimated": "Estimé",
@ -323,6 +336,7 @@
"export_backup": "Exporter la sauvegarde",
"export_logs": "Journaux d'exportation",
"export_outputs": "Exportation des sorties",
"extend_session": "Prolonger la séance",
"extra_id": "ID supplémentaire :",
"extracted_address_content": "Vous allez envoyer des fonds à\n${recipient_name}",
"failed_authentication": "Échec d'authentification. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "Mot de passe oublié",
"freeze": "Geler",
"frequently_asked_questions": "Foire aux questions",
"from": "Depuis",
"frozen": "Gelées",
"frozen_balance": "Équilibre gelé",
"full_balance": "Solde Complet",
"gas_exceeds_allowance": "Le gaz requis par la transaction dépasse l'allocation.",
"gas_price": "Prix du gaz",
"generate_name": "Générer un nom",
"generating_gift_card": "Génération d'une carte-cadeau",
"generating_transaction": "Transaction de génération",
@ -440,6 +456,8 @@
"memo": "Mémo :",
"message": "Message",
"message_verified": "Le message a été vérifié avec succès",
"messages": "Messages",
"method": "Méthode",
"methods": "Méthodes",
"min_amount": "Min : ${value}",
"min_value": "Min: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "Thème sombre Monero",
"monero_light_theme": "Thème de lumière Monero",
"moonpay_alert_text": "Le montant doit être au moins égal à ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "Une erreur s'est produite tout en récupérant les NFT. Veuillez vérifier votre connexion Internet et réessayer.",
"more_options": "Plus d'options",
"multiple_addresses_detected": "Plusieurs adresses détectées",
"mweb_confirmed": "Confirmé MWEB",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "Nom",
"new_subaddress_title": "Nouvelle adresse",
"new_template": "Nouveau Modèle",
"new_transactions_notifications": "Envoyer des notifications sur les nouvelles transactions",
"new_wallet": "Nouveau Portefeuille (Wallet)",
"newConnection": "Nouvelle connexion",
"no_cards_found": "Pas de cartes trouvées",
@ -492,6 +512,7 @@
"normal": "Normal",
"note_optional": "Note (optionnelle)",
"note_tap_to_change": "Note (appuyez pour changer)",
"notification_permission_denied": "L'autorisation de notification a été refusée permanente, veuillez l'activer manuellement dans les paramètres",
"nullURIError": "L'URI est nul",
"offer_expires_in": "L'Offre expire dans: ",
"offline": "Hors ligne",
@ -589,6 +610,7 @@
"rep_warning_sub": "Votre représentant ne semble pas être en règle. Appuyez ici pour en sélectionner un nouveau",
"repeat_wallet_password": "Répétez le mot de passe du portefeuille",
"repeated_password_is_incorrect": "Le mot de passe répété est incorrect. Veuillez répéter le mot de passe du portefeuille.",
"requested": "Demandé",
"require_for_adding_contacts": "Requis pour ajouter des contacts",
"require_for_all_security_and_backup_settings": "Exiger pour tous les paramètres de sécurité et de sauvegarde",
"require_for_assessing_wallet": "Nécessaire pour accéder au portefeuille",
@ -650,6 +672,8 @@
"second_intro_content": "Votre Yat est une seule et unique adresse emoji qui remplace toutes vos longues adresses hexadécimales pour toutes vos cryptomonnaies.",
"second_intro_title": "Une adresse emoji pour les gouverner toutes",
"security_and_backup": "Sécurité et sauvegarde",
"security_risk": "Risque de sécurité",
"security_risk_description": "Ce domaine est signalé comme dangereux par plusieurs fournisseurs de sécurité. Laissez immédiatement pour protéger vos actifs.",
"seed_alert_back": "Retour",
"seed_alert_content": "La phrase secrète (seed) est la seule façon de restaurer votre portefeuille (wallet). L'avez-vous correctement écrite ?",
"seed_alert_title": "Attention",
@ -764,7 +788,9 @@
"show_keys": "Visualiser la phrase secrète (seed) et les clefs",
"show_market_place": "Afficher la place de marché",
"show_seed": "Visualiser la phrase secrète (seed)",
"sign_all": "Signer tout",
"sign_message": "Signer le message",
"sign_one": "Signer un",
"sign_up": "S'inscrire",
"sign_verify_message": "Signe / vérifier",
"sign_verify_message_sub": "Signez ou vérifiez un message en utilisant votre clé privée",
@ -798,6 +824,7 @@
"subaddress_title": "Liste des sous-adresses",
"subaddresses": "Sous-adresses",
"submit_request": "soumettre une requête",
"success": "Succès",
"successful": "Réussi",
"support_description_guides": "Documentation et support pour les problèmes communs",
"support_description_live_chat": "GRATUIT ET RAPIDE ! Des représentants de soutien formé sont disponibles pour aider",
@ -805,6 +832,7 @@
"support_title_guides": "Docs de portefeuille à gâteau",
"support_title_live_chat": "Support en direct",
"support_title_other_links": "Autres liens d'assistance",
"supported": "Soutenu",
"swap": "Échanger",
"sweeping_wallet": "Portefeuille (wallet) de consolidation",
"sweeping_wallet_alert": "Cela ne devrait pas prendre longtemps. NE QUITTEZ PAS CET ÉCRAN OU LES FONDS TRANSFÉRÉS POURRAIENT ÊTRE PERDUS.",
@ -837,6 +865,7 @@
"thorchain_taproot_address_not_supported": "Le fournisseur de Thorchain ne prend pas en charge les adresses de tapoot. Veuillez modifier l'adresse ou sélectionner un autre fournisseur.",
"time": "${minutes}m ${seconds}s",
"tip": "Pourboire:",
"to": "À",
"today": "Aujourd'hui",
"token_contract_address": "Adresse du contrat de token",
"token_decimal": "Décimales de token",
@ -904,6 +933,7 @@
"transaction_sent_notice": "Si l'écran ne continue pas après 1 minute, vérifiez un explorateur de blocs et votre e-mail.",
"transactions": "Transactions",
"transactions_by_date": "Transactions par date",
"transport_type": "Type de transport",
"trongrid_history": "Histoire de la trongride",
"trusted": "de confiance",
"tx_commit_exception_no_dust_on_change": "La transaction est rejetée avec ce montant. Avec ces pièces, vous pouvez envoyer ${min} sans changement ou ${max} qui renvoie le changement.",
@ -932,6 +962,7 @@
"unspent_coins_details_title": "Détails des pièces (coins) non dépensées",
"unspent_coins_title": "Pièces (coins) non dépensées",
"unsupported_asset": "Nous ne prenons pas en charge cette action pour cet élément. Veuillez créer ou passer à un portefeuille d'un type d'actif pris en charge.",
"update_session": "Mettre à jour la session",
"uptime": "Durée de la baisse",
"upto": "jusqu'à ${value}",
"usb": "USB",
@ -941,6 +972,7 @@
"use_ssl": "Utiliser SSL",
"use_suggested": "Suivre la suggestion",
"use_testnet": "Utiliser TestNet",
"user_rejected_method": "Méthode rejetée par l'utilisateur",
"value": "Valeur",
"value_type": "Type de valeur",
"variable_pair_not_supported": "Cette paire variable n'est pas prise en charge avec les échanges sélectionnés",
@ -1024,5 +1056,6 @@
"you_will_get": "Convertir vers",
"you_will_receive_estimated_amount": "Vous recevrez ( estimé )",
"you_will_send": "Convertir depuis",
"youCanGoBackToYourDapp": "Vous pouvez retourner à votre Dapp maintenant",
"yy": "AA"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "Ƙirƙirar ${type}. Maƙiyantun mai nasara zai iya ${method} da duk abubuwan da ke samun lambar waya, kuma zaku samu kuɗin dama a wannan kashi.",
"apk_update": "apk sabunta",
"approve": "Amincewa",
"approve_request": "Amince da bukata",
"arrive_in_this_address": "${currency} ${tag} zai je wurin wannan adireshi",
"ascending": "Hau",
"ask_each_time": "Tambaya kowane lokaci",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "Ana jiran Tabbacin Biyan Kuɗi",
"background_sync": "Tunawa da Setc",
"background_sync_mode": "Yanayin Sync",
"background_sync_on_battery_low": "Aiki tare a kan baturin",
"background_sync_on_charging": "Aiki tare kawai lokacin caji",
"background_sync_on_device_idle": "Aiki tare kawai lokacin da ba a amfani da na'urar",
"background_sync_on_unmetered_network": "Bukatar cibiyar sadarwar da ba ta dace ba",
"backup": "Ajiyayyen",
"backup_file": "Ajiyayyen fayil",
"backup_password": "Ajiyayyen kalmar sirri",
@ -116,9 +121,12 @@
"camera_consent": "Za a yi amfani da kyamarar ku don ɗaukar hoto don dalilai na tantancewa ta ${provider}. Da fatan za a duba Manufar Sirri don cikakkun bayanai.",
"camera_permission_is_required": "Ana buƙatar izinin kyamara.\nDa fatan za a kunna shi daga saitunan app.",
"cancel": "Soke",
"cannot_verify": "Ba zai iya tabbatarwa",
"cannot_verify_description": "Ba za a iya tabbatar da wannan yanki ba. Duba buƙatun a hankali kafin amincewa.",
"card_address": "Adireshin:",
"cardholder_agreement": "Yarjejeniyar mai katin",
"cards": "Katuna",
"chain_id": "ID na ID",
"chains": "Sarkoki",
"change": "Canja",
"change_backup_password_alert": "Fayilolin madadin ku na baya ba za su kasance don shigo da sabon kalmar sirri ta madadin ba. Sabuwar kalmar sirri ta ajiya za a yi amfani da ita kawai don sabbin fayilolin madadin. Shin kun tabbata cewa kuna son canza kalmar wucewa?",
@ -174,6 +182,7 @@
"connect_yats": "Haɗa Yats",
"connect_your_hardware_wallet": "Haɗa Wallake Wallware ɗinku ta Bluetooth ko USB",
"connect_your_hardware_wallet_ios": "Haɗa kayan aikinku ta Bluetooth",
"connected": "Wanda aka haɗa",
"connection_sync": "Haɗi da daidaitawa",
"connectWalletPrompt": "Haɗa walat ɗin ku tare da WalletConnect don yin ma'amala",
"contact": "Tuntuɓar",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "Kashe ingantawa baturi",
"disableBatteryOptimizationDescription": "Shin kana son kashe ingantawa baturi don yin setnc bankwali gudu da yar kyauta da kyau?",
"disabled": "tsaya",
"disconnect_session": "Cire haɗin",
"discount": "Ajiye ${value}%",
"display_settings": "Nuni saituna",
"displayable": "Ana iya nunawa",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "Kada ku raba waɗannan ga kowa, gami da tallafi.\n\nZa a iya sace kuɗin ku kuma za a sace!",
"do_not_show_me": "Kar ka sake nuna min wannan",
"domain_looks_up": "Binciken yanki",
"domain_mismatch": "Yankin zalunci",
"domain_mismatch_description": "Wannan rukunin yanar gizon yana da yanki wanda bai dace da aika wannan bukatar ba. Yarda na iya haifar da asarar kudade.",
"donation_link_details": "Bayanin hanyar sadaka",
"e_sign_consent": "Izinin Alamar E-Sign",
"edit": "Gyara",
@ -298,6 +310,7 @@
"error_text_template": "Sunan na tushe da adireshin ba zai iya ɗaukar ` , ' \" haruffa\nkuma ya zama tsakanin 1 zuwa 106 haruffa",
"error_text_wallet_name": "Sunan hujja kawai zai iya ɗauka ne haruffa, lambobi, _ - haruffa\nkuma ya zama tsakanin 1 zuwa 33 haruffa",
"error_text_xmr": "XMR adadin ba zai iya wuce available balance.\nAdadin haruffan gaba zai kamata ya zama ko ƙasa daga na 12",
"error_while_processing": "Kuskure ya faru yayin bincike",
"errorGettingCredentials": "Ba a yi nasara ba: Kuskure yayin samun takaddun shaida",
"errorSigningTransaction": "An sami kuskure yayin sanya hannu kan ciniki",
"estimated": "Kiyasta",
@ -323,6 +336,7 @@
"export_backup": "Ajiyayyen fitarwa",
"export_logs": "Injin fitarwa",
"export_outputs": "Fitarwar fitarwa",
"extend_session": "Mika zaman",
"extra_id": "Karin ID:",
"extracted_address_content": "Za ku aika da kudade zuwa\n${recipient_name}",
"failed_authentication": "Binne wajen shiga. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "Manta Kalmar wucewa",
"freeze": "Daskare",
"frequently_asked_questions": "Tambayoyin da ake yawan yi",
"from": "Daga",
"frozen": "Daskararre",
"frozen_balance": "Daidaituwa mai sanyi",
"full_balance": "DUKAN KUDI",
"gas_exceeds_allowance": "Gas da ake buƙata ta hanyar ma'amala ya wuce izini.",
"gas_price": "Farashin gas",
"generate_name": "Ƙirƙirar Suna",
"generating_gift_card": "Samar da Katin Kyauta",
"generating_transaction": "Ma'amala samar da ma'amala",
@ -440,6 +456,8 @@
"memo": "Memo:",
"message": "Sako",
"message_verified": "An yi nasarar tabbatar da sakon",
"messages": "Manegiya",
"method": "Hanya",
"methods": "Hanyoyin",
"min_amount": "Min: ${value}",
"min_value": "Min: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "Monero Dark Jigo",
"monero_light_theme": "Jigon Hasken Monero",
"moonpay_alert_text": "Darajar adadin dole ne ya zama fiye ko daidai da ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "Kuskuren ya faru yayin da ake kawo NFFTs. Da fatan za a duba haɗin intanet ɗinka kuma sake gwadawa.",
"more_options": "Ƙarin Zaɓuɓɓuka",
"multiple_addresses_detected": "An gano adiresoshin da aka gano",
"mweb_confirmed": "Tabbatar da Mweb",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "Lakabin suna",
"new_subaddress_title": "Adireshin sabuwa",
"new_template": "Sabon Samfura",
"new_transactions_notifications": "Aika sanarwa game da sababbin ma'amaloli",
"new_wallet": "Sabuwar Wallet",
"newConnection": "Sabuwar Haɗi",
"no_cards_found": "Babu katunan da aka samo",
@ -492,6 +512,7 @@
"normal": "Na al'ada",
"note_optional": "Bayani (optional)",
"note_tap_to_change": "Bayani (tap don canja)",
"notification_permission_denied": "Izinin sanarwar da aka samu an ƙaryata game da shi, don Allah a kunna shi a cikin saiti",
"nullURIError": "URI banza ne",
"offer_expires_in": "tayin zai ƙare a:",
"offline": "Offline",
@ -591,6 +612,7 @@
"rep_warning_sub": "Wakilinku bai bayyana ya kasance cikin kyakkyawan yanayi ba. Matsa nan don zaɓar sabon",
"repeat_wallet_password": "Maimaita kalmar sirri",
"repeated_password_is_incorrect": "Maimaita kalmar sirri ba daidai ba ce. Da fatan za a sake maimaita kalmar sirri.",
"requested": "Nema",
"require_for_adding_contacts": "Bukatar ƙara lambobin sadarwa",
"require_for_all_security_and_backup_settings": "Bukatar duk tsaro da saitunan wariyar ajiya",
"require_for_assessing_wallet": "Bukatar samun damar walat",
@ -652,6 +674,8 @@
"second_intro_content": "Your Yat adireshi ne na musamman na Emoji guda ɗaya wanda ke maye gurbin duk dogayen adiresoshin ku na hexadecimal na duk kudaden ku.",
"second_intro_title": "Adireshin emoji ɗaya don sarrafa su duka",
"security_and_backup": "Tsaro da madadin",
"security_risk": "Hadarin tsaro",
"security_risk_description": "An yiwa wannan yanki a matsayin marasa tsaro da masu ba da izini na tsaro. Bar nan da nan don kare kadarorin ku.",
"seed_alert_back": "juya baya",
"seed_alert_content": "Irin ita ce kawai hanya don dawo da walat ɗin ku. Kun rubuta shi?",
"seed_alert_title": "Hankali",
@ -766,7 +790,9 @@
"show_keys": "Nuna iri/maɓallai",
"show_market_place": "Nuna dan kasuwa",
"show_seed": "Nuna iri",
"sign_all": "Shiga All",
"sign_message": "Sa hannu",
"sign_one": "Alamar daya",
"sign_up": "Shiga",
"sign_verify_message": "Sa hannu / Tabbatar",
"sign_verify_message_sub": "Shiga ko tabbatar da saƙo ta amfani da Maɓallinku na sirri",
@ -800,6 +826,7 @@
"subaddress_title": "Jagorar subaddress",
"subaddresses": "Subaddresses",
"submit_request": "gabatar da bukata",
"success": "Nasara",
"successful": "Nasara",
"support_description_guides": "Tallafi da tallafi don batutuwa na yau da kullun",
"support_description_live_chat": "Kyauta da sauri! An horar da wakilan tallafi na tallafi don taimakawa",
@ -807,6 +834,7 @@
"support_title_guides": "Docs Bakin",
"support_title_live_chat": "Tallafi na Live",
"support_title_other_links": "Sauran hanyoyin tallafi",
"supported": "Goyan baya",
"swap": "Musya",
"sweeping_wallet": "Kashi na kasa",
"sweeping_wallet_alert": "Wannan ba zai samu lokacin mai tsaski. KADA KA SAMU KUNGIYARAN KUHON, ZAMAN DADIN BANKUNCI ZAI HAŘA",
@ -839,6 +867,7 @@
"thorchain_taproot_address_not_supported": "Mai ba da tallafi na ThorChain baya goyan bayan adreshin taproot. Da fatan za a canza adireshin ko zaɓi mai bayarwa daban.",
"time": "${minutes}m ${seconds}s",
"tip": "Tukwici:",
"to": "Zuwa",
"today": "Yau",
"token_contract_address": "Adireshin kwangilar Token",
"token_decimal": "Alamar ƙima",
@ -906,6 +935,7 @@
"transaction_sent_notice": "Idan allon bai ci gaba ba bayan minti 1, duba mai binciken toshewa da imel ɗin ku.",
"transactions": "Ma'amaloli",
"transactions_by_date": "Ma'amaloli ta kwanan wata",
"transport_type": "Nau'in sufuri",
"trongrid_history": "Tarihin Trongrid",
"trusted": "Amintacce",
"tx_commit_exception_no_dust_on_change": "An ƙi ma'amala da wannan adadin. Tare da waɗannan tsabar kudi Zaka iya aika ${min}, ba tare da canji ba ko ${max} wanda ya dawo canzawa.",
@ -934,6 +964,7 @@
"unspent_coins_details_title": "Bayanan tsabar kudi da ba a kashe ba",
"unspent_coins_title": "Tsabar da ba a kashe ba",
"unsupported_asset": "Ba mu goyi bayan wannan aikin don wannan kadara. Da fatan za a ƙirƙira ko canza zuwa walat na nau'in kadara mai tallafi.",
"update_session": "Zaman gaba",
"uptime": "Sama",
"upto": "har zuwa ${value}",
"usb": "Alib",
@ -943,6 +974,7 @@
"use_ssl": "Yi amfani da SSL",
"use_suggested": "Amfani da Shawarwari",
"use_testnet": "Amfani da gwaji",
"user_rejected_method": "Mai amfani da hanya",
"value": "Daraja",
"value_type": "Nau'in darajar",
"variable_pair_not_supported": "Ba a samun goyan bayan wannan m biyu tare da zaɓaɓɓun musayar",
@ -1026,5 +1058,6 @@
"you_will_get": "Maida zuwa",
"you_will_receive_estimated_amount": "Za ku (karɓi )",
"you_will_send": "Maida daga",
"youCanGoBackToYourDapp": "Kuna iya komawa zuwa DPP ɗinku yanzu",
"yy": "YY"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "${type} उत्पन्न करें। प्राप्तकर्ता किसी भी समर्थित क्रिप्टोकरेंसी के साथ ${method} कर सकता है, और आपको इस वॉलेट में धन प्राप्त होगा।",
"apk_update": "APK अद्यतन",
"approve": "मंज़ूरी देना",
"approve_request": "अनुरोध को स्वीकृत करें",
"arrive_in_this_address": "${currency} ${tag}इस पते पर पहुंचेंगे",
"ascending": "आरोही",
"ask_each_time": "हर बार पूछें",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "भुगतान की पुष्टि की प्रतीक्षा में",
"background_sync": "पृष्ठभूमि सिंक",
"background_sync_mode": "बैकग्राउंड सिंक मोड",
"background_sync_on_battery_low": "कम बैटरी पर सिंक्रनाइज़ करें",
"background_sync_on_charging": "चार्ज करते समय केवल सिंक्रनाइज़ करें",
"background_sync_on_device_idle": "केवल तब सिंक्रनाइज़ करें जब डिवाइस का उपयोग नहीं किया जा रहा है",
"background_sync_on_unmetered_network": "अनमेट्रेड नेटवर्क की आवश्यकता है",
"backup": "बैकअप",
"backup_file": "बैकअपफ़ाइल",
"backup_password": "बैकअप पासवर्ड",
@ -116,9 +121,12 @@
"camera_consent": "आपके कैमरे का उपयोग ${provider} द्वारा पहचान उद्देश्यों के लिए एक छवि कैप्चर करने के लिए किया जाएगा। विवरण के लिए कृपया उनकी गोपनीयता नीति जांचें।",
"camera_permission_is_required": "कैमरे की अनुमति आवश्यक है.\nकृपया इसे ऐप सेटिंग से सक्षम करें।",
"cancel": "रद्द करना",
"cannot_verify": "सत्यापित नहीं कर सकते",
"cannot_verify_description": "इस डोमेन को सत्यापित नहीं किया जा सकता है। अनुमोदन से पहले अनुरोध को ध्यान से देखें।",
"card_address": "पता:",
"cardholder_agreement": "कार्डधारक अनुबंध",
"cards": "कार्ड",
"chain_id": "चेन आईडी",
"chains": "चेन",
"change": "परिवर्तन",
"change_backup_password_alert": "आपकी पिछली बैकअप फाइलें नए बैकअप पासवर्ड के साथ आयात करने के लिए उपलब्ध नहीं होंगी। नए बैकअप पासवर्ड का उपयोग केवल नई बैकअप फ़ाइलों के लिए किया जाएगा। क्या आप वाकई बैकअप पासवर्ड बदलना चाहते हैं?",
@ -174,6 +182,7 @@
"connect_yats": "कनेक्ट Yats",
"connect_your_hardware_wallet": "ब्लूटूथ या यूएसबी का उपयोग करके अपने हार्डवेयर वॉलेट को कनेक्ट करें",
"connect_your_hardware_wallet_ios": "ब्लूटूथ का उपयोग करके अपने हार्डवेयर वॉलेट को कनेक्ट करें",
"connected": "जुड़े हुए",
"connection_sync": "कनेक्शन और सिंक",
"connectWalletPrompt": "लेन-देन करने के लिए अपने वॉलेट को वॉलेटकनेक्ट से कनेक्ट करें",
"contact": "संपर्क करें",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "बैटरी अनुकूलन अक्षम करें",
"disableBatteryOptimizationDescription": "क्या आप बैकग्राउंड सिंक को अधिक स्वतंत्र और सुचारू रूप से चलाने के लिए बैटरी ऑप्टिमाइज़ेशन को अक्षम करना चाहते हैं?",
"disabled": "अक्षम",
"disconnect_session": "सत्र को डिस्कनेक्ट करें",
"discount": "${value}% बचाएं",
"display_settings": "प्रदर्शन सेटिंग्स",
"displayable": "प्रदर्शन योग्य",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "समर्थन सहित, इन्हें किसी और के साथ साझा न करें।\n\nआपके धन की चोरी हो सकती है और होगी!",
"do_not_show_me": "मुझे यह फिर न दिखाएं",
"domain_looks_up": "डोमेन लुकअप",
"domain_mismatch": "डोमेन बेमेल",
"domain_mismatch_description": "इस वेबसाइट में एक डोमेन है जो इस अनुरोध के प्रेषक से मेल नहीं खाता है। अनुमोदन से धन की हानि हो सकती है।",
"donation_link_details": "दान लिंक विवरण",
"e_sign_consent": "ई-साइन सहमति",
"edit": "संपादित करें",
@ -298,6 +310,7 @@
"error_text_template": "टेम्प्लेट का नाम और पता नहीं हो सकता ` , ' \" प्रतीकों\nऔर 1 और 106 वर्णों के बीच लंबा होना चाहिए",
"error_text_wallet_name": "वॉलेट नाम में केवल अक्षर, संख्याएं, _ - प्रतीक हो सकते हैं\nऔर 1 और 33 वर्णों के बीच लंबा होना चाहिए",
"error_text_xmr": "एक्सएमआर मूल्य उपलब्ध शेष राशि से अधिक नहीं हो सकता.\nअंश अंकों की संख्या 12 से कम या इसके बराबर होनी चाहिए",
"error_while_processing": "प्रोकसिंग करते समय एक त्रुटि हुई",
"errorGettingCredentials": "विफल: क्रेडेंशियल प्राप्त करते समय त्रुटि",
"errorSigningTransaction": "लेन-देन पर हस्ताक्षर करते समय एक त्रुटि उत्पन्न हुई है",
"estimated": "अनुमानित",
@ -323,6 +336,7 @@
"export_backup": "निर्यात बैकअप",
"export_logs": "निर्यात लॉग",
"export_outputs": "निर्यात आउटपुट",
"extend_session": "सत्र का विस्तार करें",
"extra_id": "अतिरिक्त आईडी:",
"extracted_address_content": "आपको धनराशि भेजी जाएगी\n${recipient_name}",
"failed_authentication": "प्रमाणीकरण विफल. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "पासवर्ड भूल गए",
"freeze": "फ्रीज",
"frequently_asked_questions": "अक्सर पूछे जाने वाले प्रश्न",
"from": "से",
"frozen": "जमा हुआ",
"frozen_balance": "जमे हुए संतुलन",
"full_balance": "पूर्ण संतुलन",
"gas_exceeds_allowance": "लेनदेन द्वारा आवश्यक गैस भत्ता से अधिक है।",
"gas_price": "गैस की कीमत",
"generate_name": "नाम जनरेट करें",
"generating_gift_card": "गिफ्ट कार्ड जनरेट कर रहा है",
"generating_transaction": "सृजन लेन -देन",
@ -440,6 +456,8 @@
"memo": "ज्ञापन:",
"message": "संदेश",
"message_verified": "संदेश को सफलतापूर्वक सत्यापित किया गया था",
"messages": "संदेशों",
"method": "तरीका",
"methods": "तरीकों",
"min_amount": "न्यूनतम: ${value}",
"min_value": "मिन: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "मोनेरो डार्क थीम",
"monero_light_theme": "मोनेरो लाइट थीम",
"moonpay_alert_text": "राशि का मूल्य अधिक है या करने के लिए बराबर होना चाहिए ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "एनएफटी लाने के दौरान एक त्रुटि हुई। कृपया अपने इंटरनेट कनेक्शन की जाँच करें और फिर से प्रयास करें।",
"more_options": "और विकल्प",
"multiple_addresses_detected": "कई पते का पता चला",
"mweb_confirmed": "MWEB की पुष्टि की",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "लेबल का नाम",
"new_subaddress_title": "नया पता",
"new_template": "नया टेम्पलेट",
"new_transactions_notifications": "नए लेनदेन के बारे में सूचनाएं भेजें",
"new_wallet": "नया बटुआ",
"newConnection": "नया कनेक्शन",
"no_cards_found": "कोई कार्ड नहीं मिला",
@ -492,6 +512,7 @@
"normal": "सामान्य",
"note_optional": "नोट (वैकल्पिक)",
"note_tap_to_change": "नोट (टैप टू चेंज)",
"notification_permission_denied": "अधिसूचना की अनुमति को पारगम्य रूप से अस्वीकार कर दिया गया, कृपया इसे मैन्युअल रूप से सेटिंग्स में सक्षम करें",
"nullURIError": "यूआरआई शून्य है",
"offer_expires_in": "में ऑफर समाप्त हो रहा है: ",
"offline": "ऑफ़लाइन",
@ -591,6 +612,7 @@
"rep_warning_sub": "आपका प्रतिनिधि अच्छी स्थिति में नहीं दिखाई देता है। एक नया चयन करने के लिए यहां टैप करें",
"repeat_wallet_password": "वॉलेट पासवर्ड दोहराएं",
"repeated_password_is_incorrect": "बार -बार पासवर्ड गलत है। कृपया फिर से वॉलेट पासवर्ड दोहराएं।",
"requested": "अनुरोधित",
"require_for_adding_contacts": "संपर्क जोड़ने के लिए आवश्यकता है",
"require_for_all_security_and_backup_settings": "सभी सुरक्षा और बैकअप सेटिंग्स की आवश्यकता है",
"require_for_assessing_wallet": "वॉलेट तक पहुँचने के लिए आवश्यकता है",
@ -652,6 +674,8 @@
"second_intro_content": "आपका Yat एक अद्वितीय इमोजी पता है जो आपकी सभी मुद्राओं के लिए आपके सभी लंबे हेक्साडेसिमल पतों को बदल देता है।",
"second_intro_title": "उन सभी पर राज करने के लिए एक इमोजी पता",
"security_and_backup": "सुरक्षा और बैकअप",
"security_risk": "सुरक्षा मे जोखिम",
"security_risk_description": "इस डोमेन को कई सुरक्षा प्रदाताओं द्वारा असुरक्षित के रूप में चिह्नित किया जाता है। अपनी संपत्ति की रक्षा के लिए तुरंत छोड़ दें।",
"seed_alert_back": "वापस जाओ",
"seed_alert_content": "बीज आपके बटुए को पुनर्प्राप्त करने का एकमात्र तरीका है। क्या आपने इसे लिखा है?",
"seed_alert_title": "ध्यान",
@ -766,7 +790,9 @@
"show_keys": "बीज / कुंजियाँ दिखाएँ",
"show_market_place": "बाज़ार दिखाएँ",
"show_seed": "बीज दिखाओ",
"sign_all": "साइन इन करें",
"sign_message": "हस्ताक्षर संदेश",
"sign_one": "साइन वन",
"sign_up": "साइन अप करें",
"sign_verify_message": "हस्ताक्षर / सत्यापित करें",
"sign_verify_message_sub": "अपनी निजी कुंजी का उपयोग करके किसी संदेश पर हस्ताक्षर या सत्यापित करें",
@ -800,6 +826,7 @@
"subaddress_title": "उपखंड सूची",
"subaddresses": "उप पते",
"submit_request": "एक अनुरोध सबमिट करें",
"success": "सफलता",
"successful": "सफल",
"support_description_guides": "सामान्य मुद्दों के लिए प्रलेखन और समर्थन",
"support_description_live_chat": "मुक्त और तेजी से! प्रशिक्षित सहायता प्रतिनिधि सहायता के लिए उपलब्ध हैं",
@ -807,6 +834,7 @@
"support_title_guides": "केक बटुए डॉक्स",
"support_title_live_chat": "लाइव सहायता",
"support_title_other_links": "अन्य समर्थन लिंक",
"supported": "का समर्थन किया",
"swap": "बदलना",
"sweeping_wallet": "स्वीपिंग वॉलेट",
"sweeping_wallet_alert": "इसमें अधिक समय नहीं लगना चाहिए। इस स्क्रीन को न छोड़ें या स्वैप्ट फंड खो सकते हैं",
@ -839,6 +867,7 @@
"thorchain_taproot_address_not_supported": "थोरचेन प्रदाता टैपरोट पते का समर्थन नहीं करता है। कृपया पता बदलें या एक अलग प्रदाता का चयन करें।",
"time": "${minutes}m ${seconds}s",
"tip": "टिप:",
"to": "को",
"today": "आज",
"token_contract_address": "टोकन अनुबंध पता",
"token_decimal": "सांकेतिक दशमलव",
@ -906,6 +935,7 @@
"transaction_sent_notice": "अगर 1 मिनट के बाद भी स्क्रीन आगे नहीं बढ़ती है, तो ब्लॉक एक्सप्लोरर और अपना ईमेल देखें।",
"transactions": "लेन-देन",
"transactions_by_date": "तारीख से लेन-देन",
"transport_type": "परिवहन प्रकार",
"trongrid_history": "ट्रॉन्ग्रिड का इतिहास",
"trusted": "भरोसा",
"tx_commit_exception_no_dust_on_change": "लेनदेन को इस राशि से खारिज कर दिया जाता है। इन सिक्कों के साथ आप चेंज या ${min} के बिना ${max} को भेज सकते हैं जो परिवर्तन लौटाता है।",
@ -934,6 +964,7 @@
"unspent_coins_details_title": "अव्ययित सिक्कों का विवरण",
"unspent_coins_title": "खर्च न किए गए सिक्के",
"unsupported_asset": "हम इस संपत्ति के लिए इस कार्रवाई का समर्थन नहीं करते हैं. कृपया समर्थित परिसंपत्ति प्रकार का वॉलेट बनाएं या उस पर स्विच करें।",
"update_session": "अद्यतन सत्र",
"uptime": "अपटाइम",
"upto": "${value} तक",
"usb": "USB",
@ -943,6 +974,7 @@
"use_ssl": "उपयोग SSL",
"use_suggested": "सुझाए गए का प्रयोग करें",
"use_testnet": "टेस्टनेट का उपयोग करें",
"user_rejected_method": "उपयोगकर्ता अस्वीकार विधि",
"value": "कीमत",
"value_type": "मान प्रकार",
"variable_pair_not_supported": "यह परिवर्तनीय जोड़ी चयनित एक्सचेंजों के साथ समर्थित नहीं है",
@ -1026,5 +1058,6 @@
"you_will_get": "में बदलें",
"you_will_receive_estimated_amount": "आपको#अनुमानित ( प्राप्त होगा)",
"you_will_send": "से रूपांतरित करें",
"youCanGoBackToYourDapp": "अब आप अपने DAPP पर वापस जा सकते हैं",
"yy": "वाईवाई"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "Generiraj ${type}. Primatelj može ${method} s bilo kojom podržanom kriptovalutom, a vi ćete primiti sredstva u ovaj novčanik.",
"apk_update": "APK ažuriranje",
"approve": "Odobriti",
"approve_request": "Odobriti zahtjev",
"arrive_in_this_address": "${currency} ${tag}će stići na ovu adresu",
"ascending": "Uzlazni",
"ask_each_time": "Pitajte svaki put",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "Čeka se potvrda plaćanja",
"background_sync": "Sinkronizacija pozadine",
"background_sync_mode": "Sinkronizacija u pozadini",
"background_sync_on_battery_low": "Sinkronizirati na niskoj bateriji",
"background_sync_on_charging": "Sinkronizirati samo prilikom punjenja",
"background_sync_on_device_idle": "Sinkronizirati samo kada se uređaj ne koristi",
"background_sync_on_unmetered_network": "Zahtijevaju nezadovoljnu mrežu",
"backup": "Sigurnosna kopija",
"backup_file": "Sigurnosna kopija datoteke",
"backup_password": "Lozinka za sigurnosnu kopiju",
@ -116,9 +121,12 @@
"camera_consent": "Vaš će fotoaparat koristiti za snimanje slike u svrhu identifikacije od strane ${provider}. Pojedinosti potražite u njihovoj politici privatnosti.",
"camera_permission_is_required": "Potrebno je dopuštenje kamere.\nOmogućite ga u postavkama aplikacije.",
"cancel": "Poništi",
"cannot_verify": "Ne može provjeriti",
"cannot_verify_description": "Ova se domena ne može provjeriti. Pažljivo provjerite zahtjev prije odobrenja.",
"card_address": "Adresa:",
"cardholder_agreement": "Ugovor s vlasnikom kartice",
"cards": "Kartice",
"chain_id": "Lanac",
"chains": "Lanci",
"change": "Promijeni",
"change_backup_password_alert": "Nećemo moći uvesti Vaše prethodne datoteke sigurnosne kopije s novom lozinkom za sigurnosnu kopiju. Novu lozinku za sigurnosnu kopiju moći ćete koristiti samo za nove datoteke sigurnosne kopije. Jeste li sigurni da želite promijeniti lozinku za sigurnosnu kopiju?",
@ -174,6 +182,7 @@
"connect_yats": "Povežite Yats",
"connect_your_hardware_wallet": "Spojite svoj hardverski novčanik pomoću Bluetooth -a ili USB -a",
"connect_your_hardware_wallet_ios": "Spojite svoj hardverski novčanik pomoću Bluetooth -a",
"connected": "Povezan",
"connection_sync": "Povezivanje i sinkronizacija",
"connectWalletPrompt": "Povežite svoj novčanik s WalletConnectom za obavljanje transakcija",
"contact": "Kontakt",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "Onemogući optimizaciju baterije",
"disableBatteryOptimizationDescription": "Želite li onemogućiti optimizaciju baterije kako bi se pozadinska sinkronizacija radila slobodnije i glatko?",
"disabled": "Onemogućeno",
"disconnect_session": "Odspojite sesiju",
"discount": "Uštedite ${value}%",
"display_settings": "Postavke zaslona",
"displayable": "Dostupno za prikaz",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "Nemojte ih dijeliti ni s kim, uključujući podršku.\n\nVaša sredstva mogu i bit će ukradena!",
"do_not_show_me": "Ne pokazuj mi ovo više",
"domain_looks_up": "Pretraga domena",
"domain_mismatch": "Neusklađenost domena",
"domain_mismatch_description": "Ova web stranica ima domenu koja ne odgovara pošiljatelju ovog zahtjeva. Odobrenje može dovesti do gubitka sredstava.",
"donation_link_details": "Detalji veza za donacije",
"e_sign_consent": "E-Sign pristanak",
"edit": "Uredi",
@ -298,6 +310,7 @@
"error_text_template": "Ime i adresa predloška ne smiju sadržavati znakove ` , ' \" \ni moraju biti dužine između 1 i 106 znakova",
"error_text_wallet_name": "Naziv novčanika može sadržavati samo slova, brojeve, _ - simbole\ni mora imati između 1 i 33 znaka",
"error_text_xmr": "XMR vrijednost ne smije biti veća od raspoloživog iznosa.\nBroj decimala smije biti 12 ili manji.",
"error_while_processing": "Došlo je do pogreške tijekom prožimanja",
"errorGettingCredentials": "Neuspješno: Pogreška prilikom dobivanja vjerodajnica",
"errorSigningTransaction": "Došlo je do pogreške prilikom potpisivanja transakcije",
"estimated": "procijenjen",
@ -323,6 +336,7 @@
"export_backup": "Izvezi sigurnosnu kopiju",
"export_logs": "Izvozni trupci",
"export_outputs": "Izvoz izlaza",
"extend_session": "Proširiti sesiju",
"extra_id": "Dodatni ID:",
"extracted_address_content": "Poslat ćete sredstva primatelju\n${recipient_name}",
"failed_authentication": "Autentifikacija neuspješna. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "Zaboravljena lozinka",
"freeze": "Zamrznuti",
"frequently_asked_questions": "Često postavljana pitanja",
"from": "Iz",
"frozen": "Smrznuto",
"frozen_balance": "Smrznuta ravnoteža",
"full_balance": "Pun iznos",
"gas_exceeds_allowance": "Plin potreban transakcijom premašuje dodatak.",
"gas_price": "Cijena plina",
"generate_name": "Generiraj ime",
"generating_gift_card": "Generiranje darovne kartice",
"generating_transaction": "Generiranje transakcije",
@ -440,6 +456,8 @@
"memo": "Memo:",
"message": "Poruka",
"message_verified": "Poruka je uspješno provjerena",
"messages": "Poruke",
"method": "Metoda",
"methods": "Metode",
"min_amount": "Minimalno: ${value}",
"min_value": "Min.: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "Monero tamna tema",
"monero_light_theme": "Monero lagana tema",
"moonpay_alert_text": "Vrijednost iznosa mora biti veća ili jednaka ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "Došlo je do pogreške tijekom dohvaćanja NFT -a. Ljubazno provjerite internetsku vezu i pokušajte ponovo.",
"more_options": "Više opcija",
"multiple_addresses_detected": "Otkrivene više adresa",
"mweb_confirmed": "Potvrđen MWeb",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "Oznaka",
"new_subaddress_title": "Nova adresa",
"new_template": "novi predložak",
"new_transactions_notifications": "Pošaljite obavijesti o novim transakcijama",
"new_wallet": "Novi novčanik",
"newConnection": "Nova veza",
"no_cards_found": "Nisu pronađene kartice",
@ -492,6 +512,7 @@
"normal": "Normalno",
"note_optional": "Poruka (nije obvezno)",
"note_tap_to_change": "Poruka (dodirnite za promjenu)",
"notification_permission_denied": "Dozvola za obavijest ostalo je odbijeno, molimo vas da ga ručno omogućite u postavkama",
"nullURIError": "URI je nula",
"offer_expires_in": "Ponuda istječe za: ",
"offline": "izvan mreže",
@ -589,6 +610,7 @@
"rep_warning_sub": "Čini se da vaš predstavnik nije u dobrom stanju. Dodirnite ovdje za odabir novog",
"repeat_wallet_password": "Ponovite lozinku za novčanik",
"repeated_password_is_incorrect": "Ponovljena lozinka je netočna. Molimo ponovite lozinku za novčanik.",
"requested": "Tražen",
"require_for_adding_contacts": "Zahtijeva za dodavanje kontakata",
"require_for_all_security_and_backup_settings": "Zahtijeva za sve postavke sigurnosti i sigurnosne kopije",
"require_for_assessing_wallet": "Potreban za pristup novčaniku",
@ -650,6 +672,8 @@
"second_intro_content": "Vaš Yat jedinstvena je adresa emojija koja zamjenjuje sve vaše duge heksadecimalne adrese za sve vaše valute.",
"second_intro_title": "Jedna adresa emojija koja će svima njima vladati",
"security_and_backup": "Sigurnost i sigurnosna kopija",
"security_risk": "Sigurnosni rizik",
"security_risk_description": "Ova je domena označena kao nesigurna od strane više pružatelja usluga sigurnosti. Ostavite odmah da zaštitite svoju imovinu.",
"seed_alert_back": "Vrati se natrag",
"seed_alert_content": "Pristupni izraz jedini je način za oporavak novčanika. Jeste li ga zapisali?",
"seed_alert_title": "Upozorenje",
@ -764,7 +788,9 @@
"show_keys": "Prikaži pristupni izraz/ključ",
"show_market_place": "Prikaži tržište",
"show_seed": "Prikaži pristupni izraz",
"sign_all": "Potpisati sve",
"sign_message": "Poruka",
"sign_one": "Potpisati jedan",
"sign_up": "Prijavite se",
"sign_verify_message": "Potpisati / provjeriti",
"sign_verify_message_sub": "Potpišite ili provjerite poruku pomoću privatnog ključa",
@ -798,6 +824,7 @@
"subaddress_title": "Lista podadresa",
"subaddresses": "Podadrese",
"submit_request": "podnesi zahtjev",
"success": "Uspjeh",
"successful": "Uspješno",
"support_description_guides": "Dokumentacija i podrška za uobičajena pitanja",
"support_description_live_chat": "Besplatno i brzo! Obučeni predstavnici podrške dostupni su za pomoć",
@ -805,6 +832,7 @@
"support_title_guides": "Dokumenti s kolačem kolača",
"support_title_live_chat": "Podrška uživo",
"support_title_other_links": "Ostale veze za podršku",
"supported": "Potpomognut",
"swap": "Mijenjati",
"sweeping_wallet": "Čisti novčanik",
"sweeping_wallet_alert": "Ovo ne bi trebalo dugo trajati. NE NAPUŠTAJTE OVAJ ZASLON INAČE SE POBREŠENA SREDSTVA MOGU IZGUBITI",
@ -837,6 +865,7 @@
"thorchain_taproot_address_not_supported": "Thorchain pružatelj ne podržava Taproot adrese. Promijenite adresu ili odaberite drugog davatelja usluga.",
"time": "${minutes}m ${seconds}s",
"tip": "Savjet:",
"to": "Do",
"today": "Danas",
"token_contract_address": "Adresa ugovora tokena",
"token_decimal": "Token decimalni",
@ -904,6 +933,7 @@
"transaction_sent_notice": "Ako se zaslon ne nastavi nakon 1 minute, provjerite block explorer i svoju e-poštu.",
"transactions": "Transakcije",
"transactions_by_date": "Transakcije prema datumu",
"transport_type": "Transportni tip",
"trongrid_history": "Povijest Trongrida",
"trusted": "vjerovao",
"tx_commit_exception_no_dust_on_change": "Transakcija se odbija s tim iznosom. Pomoću ovih kovanica možete poslati ${min} bez promjene ili ${max} koja vraća promjenu.",
@ -932,6 +962,7 @@
"unspent_coins_details_title": "Nepotrošeni detalji o novčićima",
"unspent_coins_title": "Nepotrošeni novčići",
"unsupported_asset": "Ne podržavamo ovu radnju za ovaj materijal. Izradite ili prijeđite na novčanik podržane vrste sredstava.",
"update_session": "Sesija ažuriranja",
"uptime": "Radno vrijeme",
"upto": "do ${value}",
"usb": "USB",
@ -941,6 +972,7 @@
"use_ssl": "Koristi SSL",
"use_suggested": "Koristite predloženo",
"use_testnet": "Koristite TestNet",
"user_rejected_method": "Korisnik odbijena metoda",
"value": "Vrijednost",
"value_type": "Tipa vrijednosti",
"variable_pair_not_supported": "Ovaj par varijabli nije podržan s odabranim burzama",
@ -1024,5 +1056,6 @@
"you_will_get": "Razmijeni u",
"you_will_receive_estimated_amount": "Primit ćete(procijenjeno )",
"you_will_send": "Razmijeni iz",
"youCanGoBackToYourDapp": "Sada se možete vratiti na svoj dapp",
"yy": "GG"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "${type} ստեղծել: Ստացողը կարող է ${method} ցանկացած աջակցվող կրիպտոարժույթով, և դուք կստանաք միջոցներ այս դրամապանակում։",
"apk_update": "APK թարմացում",
"approve": "Հաստատել",
"approve_request": "Հաստատում է հայցը",
"arrive_in_this_address": "${currency} ${tag}կժամանի այս հասցեում",
"ascending": "Աճող",
"ask_each_time": "Հարցնել ամեն անգամ",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "Վճարման հաստատման սպասում",
"background_sync": "Ֆոնային համաժամեցում",
"background_sync_mode": "Հետին պլանի համաժամացման ռեժիմ",
"background_sync_on_battery_low": "Համաժամեցրեք ցածր մարտկոցի վրա",
"background_sync_on_charging": "Համաժամացրեք միայն լիցքավորելու ժամանակ",
"background_sync_on_device_idle": "Համաժամացրեք միայն այն ժամանակ, երբ սարքը չի օգտագործվում",
"background_sync_on_unmetered_network": "Պահանջում են չմշակված ցանց",
"backup": "Կրկնօրինակ",
"backup_file": "Կրկնօրինակի ֆայլ",
"backup_password": "Կրկնօրինակի գաղտնաբառ",
@ -116,9 +121,12 @@
"camera_consent": "Ձեր տեսախցիկը կօգտագործվի ${provider}-ի կողմից ինքնությունը հաստատելու նպատակով: Խնդրում ենք ծանոթանալ նրանց Գաղտնիության Քաղաքականության հետ:",
"camera_permission_is_required": "Տեսախցիկի թույլտվություն է պահանջվում: \nԽնդրում ենք այն ակտիվացնել հավելվածի կարգավորումներից:",
"cancel": "Չեղարկել",
"cannot_verify": "Չի կարող հաստատել",
"cannot_verify_description": "Այս տիրույթը հնարավոր չէ ստուգել: Հաստատելուց առաջ ուշադիր ստուգեք հարցումը:",
"card_address": "Հասցե։",
"cardholder_agreement": "Քարտապանի Պայմանագիր",
"cards": "Քարտեր",
"chain_id": "Շղթայի ID",
"chains": "Շղթաներ",
"change": "Փոփոխել",
"change_backup_password_alert": "Ձեր նախորդ կրկնօրինակ ֆայլերը չեն հասանելի լինի ներմուծել նոր կրկնօրինակի գաղտնաբառով: Նոր կրկնօրինակի գաղտնաբառը կօգտագործվի միայն նոր կրկնօրինակ ֆայլերի համար: Վստահ եք, որ ցանկանում եք փոխել կրկնօրինակի գաղտնաբառը?",
@ -174,6 +182,7 @@
"connect_yats": "Միացրեք Yat-ները",
"connect_your_hardware_wallet": "Միացրեք ձեր ապարատային դրամապանակը Bluetooth-ի կամ USB-ի միջոցով",
"connect_your_hardware_wallet_ios": "Միացրեք ձեր ապարատային դրամապանակը Bluetooth-ի միջոցով",
"connected": "Միացված",
"connection_sync": "Կապ և սինխրոնիզացիա",
"connectWalletPrompt": "Միացրեք ձեր դրամապանակը WalletConnect-ի միջոցով գործարքներ կատարելու համար",
"contact": "Կոնտակտ",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "Անջատել մարտկոցի օպտիմիզացիան",
"disableBatteryOptimizationDescription": "Դուք ցանկանում եք անջատել մարտկոցի օպտիմիզացիան ֆոնային համաժամացման ավելի ազատ և հարթ ընթացքի համար?",
"disabled": "Անջատված",
"disconnect_session": "Անջատել նստաշրջանը",
"discount": "Խնայեք ${value}%",
"display_settings": "Ցուցադրման կարգավորումներ",
"displayable": "Ցուցադրվող",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "Մի կիսեք այս տեղեկատվությունը որևէ մեկի հետ, այդ թվում նաև աջակցության հետ: \n\nՁեր միջոցները կարող են գողանալ կորցնել!",
"do_not_show_me": "Մի ցուցադրեք ինձ նորից",
"domain_looks_up": "Դոմեյնի որոնում",
"domain_mismatch": "Դոմենի անհամապատասխանություն",
"domain_mismatch_description": "Այս կայքը ունի տիրույթ, որը չի համապատասխանում այս խնդրանքի ուղարկողին: Հաստատումը կարող է հանգեցնել միջոցների կորստի:",
"donation_link_details": "Նվիրատվության հղումի մանրամասներ",
"e_sign_consent": "Էլեկտրոնային ստորագրության համաձայնություն",
"edit": "Խմբագրել",
@ -298,6 +310,7 @@
"error_text_template": "Տեսակի անունը և հասցեն չեն կարող պարունակել , '' \" նշանները\nև պետք է լինի 1-ից 106 նիշ երկարությամբ",
"error_text_wallet_name": "Գաղտնաբառը կարող է պարունակել միայն տառեր, թվեր, _ - նշաններ\nև պետք է լինի 1-ից 33 նիշ երկարությամբ",
"error_text_xmr": "XMR արժեքը չի կարող գերազանցել հասանելի մնացորդը:\nԿոտորակային թվերի քանակը պետք է լինի 12-ից պակաս կամ հավասար",
"error_while_processing": "Նախագծման ժամանակ սխալ է տեղի ունեցել",
"errorGettingCredentials": "Սխալ. ծանրաբեռնված վստահագրեր ստանալիս",
"errorSigningTransaction": "Սխալ է տեղի ունեցել գործարքը ստորագրելիս",
"estimated": "Գնահատված",
@ -323,6 +336,7 @@
"export_backup": "Արտահանել կրկնօրինակը",
"export_logs": "Արտահանման տեղեկամատյաններ",
"export_outputs": "Արտահանման արդյունքներ",
"extend_session": "Ընդլայնված նիստ",
"extra_id": "Լրացուցիչ ID",
"extracted_address_content": "Դուք կուղարկեք գումար ${recipient_name}",
"failed_authentication": "Վավերացումը ձախողվեց. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "Մոռացել եմ գաղտնաբառը",
"freeze": "Կասեցնել",
"frequently_asked_questions": "Հաճախ տրվող հարցեր",
"from": "Դեպի",
"frozen": "Կասեցված",
"frozen_balance": "Սառեցված հավասարակշռություն",
"full_balance": "Լրիվ մնացորդ",
"gas_exceeds_allowance": "Գործարքով պահանջվող գազը գերազանցում է նպաստը:",
"gas_price": "Գազի գին",
"generate_name": "Գեներացնել անուն",
"generating_gift_card": "Գեներացնում է նվեր քարտ",
"generating_transaction": "Ստեղծող գործարք",
@ -440,6 +456,8 @@
"memo": "Մեմո:",
"message": "Հաղորդագրություն",
"message_verified": "Հաղորդագրությունը հաջողությամբ հաստատվեց",
"messages": "Հաղորդագրություններ",
"method": "Մեթոդ",
"methods": "Մեթոդներ",
"min_amount": "Նվազը: ${value}",
"min_value": "Նվազը: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "Monero մութ տեսք",
"monero_light_theme": "Monero պայծառ տեսք",
"moonpay_alert_text": "Գումարի արժեքը պետք է լինի հավասար կամ ավելի քան ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "NFT- ները հանելիս սխալ է տեղի ունեցել: Սիրով ստուգեք ձեր ինտերնետային կապը եւ կրկին փորձեք:",
"more_options": "Այլ տարբերակներ",
"multiple_addresses_detected": "Հայտնաբերվել են բազմաթիվ հասցեներ",
"mweb_confirmed": "Հաստատված MWEB",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "Պիտակի անուն",
"new_subaddress_title": "Նոր հասցե",
"new_template": "Նոր նմուշ",
"new_transactions_notifications": "Ուղարկեք ծանուցումներ նոր գործարքների վերաբերյալ",
"new_wallet": "Նոր դրամապանակ",
"newConnection": "Նոր կապ",
"no_cards_found": "Ոչ մի քարտ չի գտնվել",
@ -491,6 +511,7 @@
"normal": "Նորմալ",
"note_optional": "Նշում (ոչ պարտադիր)",
"note_tap_to_change": "Նշում (սեղմեք փոխելու համար)",
"notification_permission_denied": "Տեղեկացման թույլտվությունը թափանցում է, խնդրում ենք ձեռքով միացնել այն պարամետրերում",
"nullURIError": "URI-ն դատարկ է",
"offer_expires_in": "Առաջարկը վաղեմության է հասնում ",
"offline": "Անցանց",
@ -588,6 +609,7 @@
"rep_warning_sub": "Ձեր ներկայացուցիչը չի հայտնվում լավ վիճակում։ Սեղմեք այստեղ նոր ներկայացուցիչ ընտրելու համար",
"repeat_wallet_password": "Վերականգնել դրամապանակի գաղտնաբառ",
"repeated_password_is_incorrect": "Վերականգնված գաղտնաբառը սխալ է։ Խնդրում ենք վերականգնել դրամապանակի գաղտնաբառը",
"requested": "Պահանջել է",
"require_for_adding_contacts": "Պահանջվում է կոնտակտներ ավելացնելու համար",
"require_for_all_security_and_backup_settings": "Պահանջվում է բոլոր անվտանգության և կրկնօրինակման կարգավորումների համար",
"require_for_assessing_wallet": "Պահանջվում է դրամապանակ մուտք գործելու համար",
@ -649,6 +671,8 @@
"second_intro_content": "Ձեր Yat-ը միակ եզակի էմոջի հասցե է, որը փոխարինում է ձեր բոլոր արժույթների համար ձեր բոլոր երկար հեքսադեցիմալ հասցեները",
"second_intro_title": "Մի էմոջի հասցե, որը կառավարում է դրանք բոլորը",
"security_and_backup": "Անվտանգություն և կրկնօրինակ",
"security_risk": "Անվտանգության ռիսկ",
"security_risk_description": "Այս տիրույթը դրոշմված է որպես անվտանգության ոչ անվտանգ `բազմաթիվ անվտանգության մատակարարների կողմից: Անմիջապես թողեք ձեր ակտիվները պաշտպանելու համար:",
"seed_alert_back": "Վերադառնալ",
"seed_alert_content": "Սերմը վերականգնելու ձեր դրամապանակի միակ միջոցն է։ Դուք արդեն գրի եք առել այն?",
"seed_alert_title": "Ուշադրություն",
@ -762,7 +786,9 @@
"show_keys": "Ցուցադրել բանալիներ",
"show_market_place": "Ցուցադրել շուկան",
"show_seed": "Ցուցադրել սերմ",
"sign_all": "Ստորագրեք բոլորը",
"sign_message": "Կնքել հաղորդագրություն",
"sign_one": "Ստորագրել մեկը",
"sign_up": "Գրանցվել",
"sign_verify_message": "Նշեք / ստուգեք",
"sign_verify_message_sub": "Կնքել կամ ստուգել հաղորդագրությունը ձեր գախտնի բանալիով",
@ -796,6 +822,7 @@
"subaddress_title": "Ենթահասցեների ցանկ",
"subaddresses": "Ենթահասցեներ",
"submit_request": "Ուղարկել հարցում",
"success": "Հաջողություն",
"successful": "Հաջողված",
"support_description_guides": "Տարածված խնդիրների փաստաթղթավորում և աջակցություն",
"support_description_live_chat": "Անվճար և արագ աջակցություն! Պատրաստված մասնագետները պատրաստ են օգնել",
@ -803,6 +830,7 @@
"support_title_guides": "Տորթ դրամապանակի փաստաթղթեր",
"support_title_live_chat": "Անմիջական աջակցություն",
"support_title_other_links": "Այլ աջակցության հղումներ",
"supported": "Աջակցել",
"swap": "Փոխանակել",
"sweeping_wallet": "Դրամապանակը մաքրվում է",
"sweeping_wallet_alert": "Սա չի տևի երկար։ Խնդրում ենք չլքել այս էկրանը կամ մաքրված միջոցները կկորչեն։",
@ -835,6 +863,7 @@
"thorchain_taproot_address_not_supported": "ThorChain մատակարարը չի աջակցում Taproot հասցեները: Խնդրում ենք փոխել հասցեն կամ ընտրել այլ մատակարար:",
"time": "${minutes}ր ${seconds}վ",
"tip": "Թեյավճար",
"to": "Դեպի",
"today": "Այսօր",
"token_contract_address": "Token-ի պայմանագրի հասցե",
"token_decimal": "Token-ի տասանիշ",
@ -902,6 +931,7 @@
"transaction_sent_notice": "Եթե էկրանը 1 րոպեի ընթացքում չի թարմանում, խնդրում ենք ստուգել բլոկի բացահայտիչը և Ձեր էլ. փոստը",
"transactions": "Փոխանցումներ",
"transactions_by_date": "Փոխանցումներ ամսաթվով",
"transport_type": "Տրանսպորտի տեսակը",
"trongrid_history": "TronGrid պատմություն",
"trusted": "Վստահելի",
"tx_commit_exception_no_dust_on_change": "Փոխանցումը մերժվել է այս գումարով: Այս արժույթներով կարող եք ուղարկել ${min} առանց փոփոխության կամ ${max} որը վերադարձնում է փոփոխությունը",
@ -930,6 +960,7 @@
"unspent_coins_details_title": "Չծախսված արժույթների մանրամասները",
"unspent_coins_title": "Չծախսված արժույթներ",
"unsupported_asset": "Մենք չենք աջակցում այս գործողությունը այս ակտիվի համար։ Խնդրում ենք ստեղծել կամ անցնել աջակցվող ակտիվի տեսակին համապատասխան դրամապանակի։",
"update_session": "Թարմացրեք նիստը",
"uptime": "Աշխատանքային ժամանակ",
"upto": "մինչև ${value}",
"usb": "USB",
@ -939,6 +970,7 @@
"use_ssl": "Օգտագործել SSL",
"use_suggested": "Օգտագործել առաջարկվածը",
"use_testnet": "Օգտագործել Testnet",
"user_rejected_method": "Օգտագործողի մերժված մեթոդը",
"value": "Արժեք",
"value_type": "Արժեքի տեսակ",
"variable_pair_not_supported": "Այս փոփոխականի զույգը չի աջակցվում ընտրված բորսաների հետ",
@ -1022,5 +1054,6 @@
"you_will_get": "Ստացեք",
"you_will_receive_estimated_amount": "Դուք կստանաք ( գնահատված )",
"you_will_send": "Փոխանակեք",
"youCanGoBackToYourDapp": "Այժմ կարող եք վերադառնալ ձեր DAPP- ին",
"yy": "ՏՏ"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "Hasilkan ${type}. Penerima dapat ${method} dengan cryptocurrency apa pun yang didukung, dan Anda akan menerima dana di dompet ini.",
"apk_update": "Pembaruan APK",
"approve": "Menyetujui",
"approve_request": "Menyetujui permintaan",
"arrive_in_this_address": "${currency} ${tag} akan tiba di alamat ini",
"ascending": "Naik",
"ask_each_time": "Tanyakan setiap kali",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "Menunggu Konfirmasi Pembayaran",
"background_sync": "Sinkronisasi Latar Belakang",
"background_sync_mode": "Mode Sinkronisasi Latar Belakang",
"background_sync_on_battery_low": "Sinkronisasi pada baterai rendah",
"background_sync_on_charging": "Menyinkronkan hanya saat pengisian",
"background_sync_on_device_idle": "Menyinkronkan hanya jika perangkat tidak digunakan",
"background_sync_on_unmetered_network": "Membutuhkan jaringan yang belum diproduksi",
"backup": "Cadangan",
"backup_file": "File cadangan",
"backup_password": "Kata sandi cadangan",
@ -116,9 +121,12 @@
"camera_consent": "Kamera Anda akan digunakan untuk mengambil gambar untuk tujuan identifikasi oleh ${provider}. Silakan periksa Kebijakan Privasi mereka untuk detailnya.",
"camera_permission_is_required": "Izin kamera diperlukan.\nSilakan aktifkan dari pengaturan aplikasi.",
"cancel": "Batal",
"cannot_verify": "Tidak dapat memverifikasi",
"cannot_verify_description": "Domain ini tidak dapat diverifikasi. Periksa permintaan dengan cermat sebelum menyetujui.",
"card_address": "Alamat:",
"cardholder_agreement": "Persetujuan Pemegang Kartu",
"cards": "Kartu",
"chain_id": "ID Rantai",
"chains": "Rantai",
"change": "Ubah",
"change_backup_password_alert": "File cadangan sebelumnya tidak akan tersedia untuk diimpor dengan kata sandi cadangan baru. Kata sandi cadangan baru hanya akan digunakan untuk file cadangan baru. Apakah Anda yakin ingin mengubah kata sandi cadangan?",
@ -174,6 +182,7 @@
"connect_yats": "Hubungkan Yats",
"connect_your_hardware_wallet": "Hubungkan dompet perangkat keras Anda menggunakan Bluetooth atau USB",
"connect_your_hardware_wallet_ios": "Hubungkan dompet perangkat keras Anda menggunakan Bluetooth",
"connected": "Terhubung",
"connection_sync": "Koneksi dan sinkronisasi",
"connectWalletPrompt": "Hubungkan dompet Anda dengan WalletConnect untuk melakukan transaksi",
"contact": "Kontak",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "Nonaktifkan optimasi baterai",
"disableBatteryOptimizationDescription": "Apakah Anda ingin menonaktifkan optimasi baterai untuk membuat sinkronisasi latar belakang berjalan lebih bebas dan lancar?",
"disabled": "Dinonaktifkan",
"disconnect_session": "Sesi Putuskan sambungan",
"discount": "Hemat ${value}%",
"display_settings": "Pengaturan tampilan",
"displayable": "Dapat ditampilkan",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "Jangan berikan ini pada siapapun, termasuk dukungan.\n\nDana Anda bisa dan akan dicuri!",
"do_not_show_me": "Jangan tampilkan ini lagi",
"domain_looks_up": "Pencarian domain",
"domain_mismatch": "Ketidakcocokan Domain",
"domain_mismatch_description": "Situs web ini memiliki domain yang tidak cocok dengan pengirim permintaan ini. Menyetujui dapat menyebabkan hilangnya dana.",
"donation_link_details": "Detail tautan donasi",
"e_sign_consent": "E-Sign Consent",
"edit": "Edit",
@ -298,6 +310,7 @@
"error_text_template": "Nama template dan alamat tidak boleh berisi simbol ` , ' \"\ndan harus antara 1 dan 106 karakter panjang",
"error_text_wallet_name": "Nama dompet hanya dapat berisi huruf, angka, _ - simbol\ndan harus antara 1 dan 33 karakter panjang",
"error_text_xmr": "Nilai XMR tidak boleh melebihi saldo yang tersedia.\nJumlah digit pecahan harus kurang atau sama dengan 12",
"error_while_processing": "Terjadi kesalahan saat prosedur",
"errorGettingCredentials": "Gagal: Terjadi kesalahan saat mendapatkan kredensial",
"errorSigningTransaction": "Terjadi kesalahan saat menandatangani transaksi",
"estimated": "Diperkirakan",
@ -323,6 +336,7 @@
"export_backup": "Ekspor cadangan",
"export_logs": "Log ekspor",
"export_outputs": "Ekspor output",
"extend_session": "Perpanjang sesi",
"extra_id": "ID tambahan:",
"extracted_address_content": "Anda akan mengirim dana ke\n${recipient_name}",
"failed_authentication": "Otentikasi gagal. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "Lupa Kata Sandi",
"freeze": "Freeze",
"frequently_asked_questions": "Pertanyaan yang sering diajukan",
"from": "Dari",
"frozen": "Dibekukan",
"frozen_balance": "Keseimbangan beku",
"full_balance": "Saldo Penuh",
"gas_exceeds_allowance": "Gas yang dibutuhkan oleh transaksi melebihi tunjangan.",
"gas_price": "Harga gas",
"generate_name": "Hasilkan Nama",
"generating_gift_card": "Membuat Kartu Hadiah",
"generating_transaction": "Menghasilkan transaksi",
@ -440,6 +456,8 @@
"memo": "Memo:",
"message": "Pesan",
"message_verified": "Pesan itu berhasil diverifikasi",
"messages": "Pesan",
"method": "Metode",
"methods": "Metode",
"min_amount": "Min: ${value}",
"min_value": "Min: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "Tema Gelap Monero",
"monero_light_theme": "Tema Cahaya Monero",
"moonpay_alert_text": "Nilai jumlah harus lebih atau sama dengan ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "Terjadi kesalahan saat mengambil NFT. Mohon periksa koneksi internet Anda dan coba lagi.",
"more_options": "Opsi Lainnya",
"multiple_addresses_detected": "Banyak alamat terdeteksi",
"mweb_confirmed": "Mengkonfirmasi mWeb",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "Nama label",
"new_subaddress_title": "Alamat baru",
"new_template": "Template Baru",
"new_transactions_notifications": "Kirim pemberitahuan tentang transaksi baru",
"new_wallet": "Dompet Baru",
"newConnection": "Koneksi Baru",
"no_cards_found": "Tidak ada kartu yang ditemukan",
@ -492,6 +512,7 @@
"normal": "Normal",
"note_optional": "Catatan (opsional)",
"note_tap_to_change": "Catatan (tap untuk mengubah)",
"notification_permission_denied": "Izin pemberitahuan ditolak secara permanen, mohon aktifkan secara manual dalam pengaturan",
"nullURIError": "URI adalah nol",
"offer_expires_in": "Penawaran kedaluwarsa dalam: ",
"offline": "Offline",
@ -591,6 +612,7 @@
"rep_warning_sub": "Perwakilan Anda tampaknya tidak bereputasi baik. Ketuk di sini untuk memilih yang baru",
"repeat_wallet_password": "Ulangi Kata Sandi Dompet",
"repeated_password_is_incorrect": "Kata sandi yang diulang tidak benar. Harap ulangi kata sandi dompet lagi.",
"requested": "Diminta",
"require_for_adding_contacts": "Membutuhkan untuk menambahkan kontak",
"require_for_all_security_and_backup_settings": "Memerlukan untuk semua pengaturan keamanan dan pencadangan",
"require_for_assessing_wallet": "Diperlukan untuk mengakses dompet",
@ -653,6 +675,8 @@
"second_intro_content": "Yat Anda adalah satu alamat emoji yang unik yang menggantikan semua alamat heksadesimal panjang Anda untuk semua mata uang Anda.",
"second_intro_title": "Satu alamat emoji untuk menguasainya semua",
"security_and_backup": "Keamanan dan cadangan",
"security_risk": "Risiko keamanan",
"security_risk_description": "Domain ini ditandai sebagai tidak aman oleh beberapa penyedia keamanan. Segera pergi untuk melindungi aset Anda.",
"seed_alert_back": "Kembali",
"seed_alert_content": "Seed adalah satu-satunya cara untuk mengembalikan dompet Anda. Apakah Anda sudah menuliskannya?",
"seed_alert_title": "Perhatian",
@ -767,7 +791,9 @@
"show_keys": "Tampilkan seed/kunci",
"show_market_place": "Tampilkan Pasar",
"show_seed": "Tampilkan seed",
"sign_all": "Menandatangani semua",
"sign_message": "Pesan tanda",
"sign_one": "Tanda satu",
"sign_up": "Daftar",
"sign_verify_message": "Tanda / verifikasi",
"sign_verify_message_sub": "Menandatangani atau memverifikasi pesan menggunakan kunci pribadi Anda",
@ -801,6 +827,7 @@
"subaddress_title": "Daftar sub-alamat",
"subaddresses": "Sub-alamat",
"submit_request": "kirim permintaan",
"success": "Kesuksesan",
"successful": "Berhasil",
"support_description_guides": "Dokumentasi dan dukungan untuk masalah umum",
"support_description_live_chat": "Gratis dan Cepat! Perwakilan dukungan terlatih tersedia untuk membantu",
@ -808,6 +835,7 @@
"support_title_guides": "DOKS DOKO CAKE",
"support_title_live_chat": "Dukungan langsung",
"support_title_other_links": "Tautan dukungan lainnya",
"supported": "Didukung",
"swap": "Menukar",
"sweeping_wallet": "Dompet menyapu",
"sweeping_wallet_alert": "Ini seharusnya tidak memakan waktu lama. Jangan tinggalkan layar ini atau dana swept mungkin hilang.",
@ -840,6 +868,7 @@
"thorchain_taproot_address_not_supported": "Penyedia Thorchain tidak mendukung alamat Taproot. Harap ubah alamatnya atau pilih penyedia yang berbeda.",
"time": "${minutes}m ${seconds}s",
"tip": "Tip:",
"to": "Ke",
"today": "Hari ini",
"token_contract_address": "Alamat kontrak token",
"token_decimal": "Desimal token",
@ -907,6 +936,7 @@
"transaction_sent_notice": "Jika layar tidak bergerak setelah 1 menit, periksa block explorer dan email Anda.",
"transactions": "Transaksi",
"transactions_by_date": "Transaksi berdasarkan tanggal",
"transport_type": "Jenis transportasi",
"trongrid_history": "Sejarah Trongrid",
"trusted": "Dipercayai",
"tx_commit_exception_no_dust_on_change": "Transaksi ditolak dengan jumlah ini. Dengan koin ini Anda dapat mengirim ${min} tanpa perubahan atau ${max} yang mengembalikan perubahan.",
@ -935,6 +965,7 @@
"unspent_coins_details_title": "Rincian koin yang tidak terpakai",
"unspent_coins_title": "Koin yang tidak terpakai",
"unsupported_asset": "Kami tidak mendukung tindakan ini untuk aset ini. Harap buat atau alihkan ke dompet dari jenis aset yang didukung.",
"update_session": "Perbarui sesi",
"uptime": "Uptime",
"upto": "hingga ${value}",
"usb": "USB",
@ -944,6 +975,7 @@
"use_ssl": "Gunakan SSL",
"use_suggested": "Gunakan yang Disarankan",
"use_testnet": "Gunakan TestNet",
"user_rejected_method": "Metode yang ditolak pengguna",
"value": "Nilai",
"value_type": "Jenis Nilai",
"variable_pair_not_supported": "Pasangan variabel ini tidak didukung dengan bursa yang dipilih",
@ -1027,5 +1059,6 @@
"you_will_get": "Konversi ke",
"you_will_receive_estimated_amount": "Anda akan menerima(estimasi )",
"you_will_send": "Konversi dari",
"youCanGoBackToYourDapp": "Anda dapat kembali ke dapp Anda sekarang",
"yy": "YY"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "Genera ${type}. Il destinatario può ${method} con qualsiasi criptovaluta supportata, e riceverai fondi in questo portafoglio.",
"apk_update": "Aggiornamento APK",
"approve": "Approvare",
"approve_request": "Approvare la richiesta",
"arrive_in_this_address": "${currency} ${tag}arriverà a questo indirizzo",
"ascending": "Ascendente",
"ask_each_time": "Chiedi ogni volta",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "In attesa di conferma del pagamento",
"background_sync": "Sincronizzazione in background",
"background_sync_mode": "Modalità di sincronizzazione in background",
"background_sync_on_battery_low": "Sincronizza sulla batteria bassa",
"background_sync_on_charging": "Sincronizzare solo quando si carica",
"background_sync_on_device_idle": "Sincronizzare solo quando il dispositivo non viene utilizzato",
"background_sync_on_unmetered_network": "Richiedono una rete non riservata",
"backup": "Backup",
"backup_file": "Backup file",
"backup_password": "Backup password",
@ -116,9 +121,12 @@
"camera_consent": "La tua fotocamera verrà utilizzata per acquisire un'immagine a scopo identificativo da ${provider}. Si prega di controllare la loro Informativa sulla privacy per i dettagli.",
"camera_permission_is_required": "È richiesta l'autorizzazione della fotocamera.\nAbilitalo dalle impostazioni dell'app.",
"cancel": "Cancella",
"cannot_verify": "Non può verificare",
"cannot_verify_description": "Questo dominio non può essere verificato. Controlla attentamente la richiesta prima di approvare.",
"card_address": "Indirizzo:",
"cardholder_agreement": "Contratto del titolare della carta",
"cards": "Carte",
"chain_id": "ID catena",
"chains": "Catene",
"change": "Cambia",
"change_backup_password_alert": "I tuoi file di backup precedenti non potranno essere importati con la nuova password di backup. La nuova password di backup verrà usata soltanto per i nuovi file di backup. Sei sicuro di voler cambiare la tua password di backup?",
@ -174,6 +182,7 @@
"connect_yats": "Connetti Yats",
"connect_your_hardware_wallet": "Collega il tuo portafoglio hardware tramite Bluetooth o USB",
"connect_your_hardware_wallet_ios": "Collega il tuo portafoglio hardware tramite Bluetooth",
"connected": "Collegato",
"connection_sync": "Connessione e sincronizzazione",
"connectWalletPrompt": "Collega il tuo portafoglio con WalletConnect per effettuare transazioni",
"contact": "Contatta",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "Disabilita l'ottimizzazione della batteria",
"disableBatteryOptimizationDescription": "Vuoi disabilitare l'ottimizzazione della batteria per migliorare la sincronizzazione in background?",
"disabled": "Disabilitato",
"disconnect_session": "Sessione di disconnessione",
"discount": "Risparmia ${value}%",
"display_settings": "Impostazioni di visualizzazione",
"displayable": "Visualizzabile",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "Non condividerli con nessun altro, incluso il supporto.\n\nI tuoi fondi possono essere e saranno rubati!",
"do_not_show_me": "Non mostrarmelo di nuovo",
"domain_looks_up": "Cerca domini",
"domain_mismatch": "Dominio Mismatch",
"domain_mismatch_description": "Questo sito Web ha un dominio che non corrisponde al mittente di questa richiesta. L'approvazione può comportare la perdita di fondi.",
"donation_link_details": "Dettagli del link di donazione",
"e_sign_consent": "Consenso alla firma elettronica",
"edit": "Modifica",
@ -298,6 +310,7 @@
"error_text_template": "Il nome del modello e l'indirizzo non possono contenere i simboli ` , ' \" \ne devono avere una lunghezza compresa tra 1 e 106 caratteri",
"error_text_wallet_name": "Il nome del portafoglio può contenere solo lettere, numeri, _ - simboli\ne deve avere una lunghezza compresa tra 1 e 33 caratteri",
"error_text_xmr": "Il valore in XMR non può eccedere il saldo disponibile.\nIl numero delle cifre decimali deve essere inferiore o uguale a 12",
"error_while_processing": "Si è verificato un errore durante la promozione",
"errorGettingCredentials": "Non riuscito: errore durante il recupero delle credenziali",
"errorSigningTransaction": "Si è verificato un errore durante la firma della transazione",
"estimated": "Stimato",
@ -323,6 +336,7 @@
"export_backup": "Esporta backup",
"export_logs": "Esporta log",
"export_outputs": "Esporta output",
"extend_session": "Estendere la sessione",
"extra_id": "Extra ID:",
"extracted_address_content": "Invierai i tuoi fondi a\n${recipient_name}",
"failed_authentication": "Autenticazione fallita. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "Password dimenticata",
"freeze": "Congela",
"frequently_asked_questions": "Domande frequenti",
"from": "Da",
"frozen": "Congelato",
"frozen_balance": "Saldo Congelato",
"full_balance": "Saldo Completo",
"gas_exceeds_allowance": "Il Gas richiesto dalla transazione supera il limite consentito.",
"gas_price": "Prezzo del gas",
"generate_name": "Genera nome",
"generating_gift_card": "Generazione carta regalo",
"generating_transaction": "Generazione di transazione",
@ -440,6 +456,8 @@
"memo": "Memo:",
"message": "Messaggio",
"message_verified": "Il messaggio è stato verificato con successo",
"messages": "Messaggi",
"method": "Metodo",
"methods": "Metodi",
"min_amount": "Min: ${value}",
"min_value": "Min: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "Tema scuro Monero",
"monero_light_theme": "Tema chiaro Monero",
"moonpay_alert_text": "Il valore dell'importo deve essere maggiore o uguale a ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "Si è verificato un errore durante il recupero di NFT. Si prega di controllare la tua connessione Internet e riprovare.",
"more_options": "Altre opzioni",
"multiple_addresses_detected": "Più indirizzi rilevati",
"mweb_confirmed": "MWeb confermato",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "Nome etichetta",
"new_subaddress_title": "Nuovo indirizzo",
"new_template": "Nuovo modello",
"new_transactions_notifications": "Invia notifiche su nuove transazioni",
"new_wallet": "Nuovo portafoglio",
"newConnection": "Nuova connessione",
"no_cards_found": "Nessuna carta trovata",
@ -492,6 +512,7 @@
"normal": "Normale",
"note_optional": "Nota (opzionale)",
"note_tap_to_change": "Nota (clicca per cambiare)",
"notification_permission_denied": "L'autorizzazione alla notifica è stata negato per via per via per via per via per via per via per via per via, per favore, abilitalo manualmente",
"nullURIError": "L'URI è nullo",
"offer_expires_in": "L'offerta termina tra: ",
"offline": "Offline",
@ -590,6 +611,7 @@
"rep_warning_sub": "Il tuo rappresentante non sembra essere in regola. Tocca qui per selezionarne uno nuovo",
"repeat_wallet_password": "Ripeti la password del portafoglio",
"repeated_password_is_incorrect": "La password ripetuta non è corretta. Si prega di ripetere di nuovo la password del portafoglio.",
"requested": "Richiesto",
"require_for_adding_contacts": "Richiedi per l'aggiunta di contatti",
"require_for_all_security_and_backup_settings": "Richiedi per tutte le impostazioni di sicurezza e backup",
"require_for_assessing_wallet": "Richiedi per l'accesso al portafoglio",
@ -651,6 +673,8 @@
"second_intro_content": "Il tuo Yat è un unico indirizzo emoji univoco che sostituisce i lunghi indirizzi per tutte le tue valute.",
"second_intro_title": "Un indirizzo emoji per domarli tutti",
"security_and_backup": "Sicurezza e backup",
"security_risk": "Rischio di sicurezza",
"security_risk_description": "Questo dominio è contrassegnato come non sicuro da più fornitori di sicurezza. Lascia immediatamente per proteggere le tue risorse.",
"seed_alert_back": "Torna indietro",
"seed_alert_content": "Il seme è l'unico modo per recuperare il tuo portafoglio. L'hai trascritto?",
"seed_alert_title": "Attenzione",
@ -765,7 +789,9 @@
"show_keys": "Mostra seme/chiavi",
"show_market_place": "Mostra mercato",
"show_seed": "Mostra seme",
"sign_all": "Firma tutto",
"sign_message": "Firma messaggio",
"sign_one": "Segna uno",
"sign_up": "Registrati",
"sign_verify_message": "Firmare / verificare",
"sign_verify_message_sub": "Firma o verifica un messaggio utilizzando la chiave privata",
@ -799,6 +825,7 @@
"subaddress_title": "Lista sottoindirizzi",
"subaddresses": "Sottoindirizzi",
"submit_request": "invia una richiesta",
"success": "Successo",
"successful": "Riuscito",
"support_description_guides": "Documentazione e supporto per problemi comuni",
"support_description_live_chat": "Gratuito e veloce! I rappresentanti di supporto qualificati sono disponibili per assistervi",
@ -806,6 +833,7 @@
"support_title_guides": "Documentazione Cake Wallet",
"support_title_live_chat": "Supporto in tempo reale",
"support_title_other_links": "Altri collegamenti di supporto",
"supported": "Supportato",
"swap": "Scambio",
"sweeping_wallet": "Svuota portafoglio",
"sweeping_wallet_alert": "Questo non dovrebbe richiedere molto tempo. NON LASCIARE QUESTA SCHERMATA O I FONDI DA TRASFERIRE POTREBBERO ANDARE PERSI",
@ -838,6 +866,7 @@
"thorchain_taproot_address_not_supported": "Il provider di Thorchain non supporta gli indirizzi di TapRoot. Si prega di modificare l'indirizzo o selezionare un fornitore diverso.",
"time": "${minutes}m ${seconds}s",
"tip": "Suggerimento:",
"to": "A",
"today": "Oggi",
"token_contract_address": "Indirizzo del contratto token",
"token_decimal": "Decimale del token",
@ -905,6 +934,7 @@
"transaction_sent_notice": "Se la schermata non procede dopo 1 minuto, controlla un block explorer e la tua email.",
"transactions": "Transazioni",
"transactions_by_date": "Transazioni per data",
"transport_type": "Tipo di trasporto",
"trongrid_history": "Cronologia TronGrid",
"trusted": "Fidato",
"tx_commit_exception_no_dust_on_change": "La transazione viene respinta con questo importo. Con queste monete è possibile inviare ${min} senza modifiche o ${max} che restituisce il cambiamento.",
@ -933,6 +963,7 @@
"unspent_coins_details_title": "Dettagli sulle monete non spese",
"unspent_coins_title": "Monete non spese",
"unsupported_asset": "Non supportiamo questa azione per questa risorsa. Crea o passa a un portafoglio di un tipo di asset supportato.",
"update_session": "Sessione di aggiornamento",
"uptime": "Uptime",
"upto": "fino a ${value}",
"usb": "USB",
@ -942,6 +973,7 @@
"use_ssl": "Usa SSL",
"use_suggested": "Usa suggerito",
"use_testnet": "Usa TestNet",
"user_rejected_method": "Metodo respinto dall'utente",
"value": "Valore",
"value_type": "Tipo di valore",
"variable_pair_not_supported": "Questa coppia di variabili non è supportata con gli scambi selezionati",
@ -1026,5 +1058,6 @@
"you_will_get": "Converti a",
"you_will_receive_estimated_amount": "Riceverai(stimato )",
"you_will_send": "Conveti da",
"youCanGoBackToYourDapp": "Puoi tornare al tuo DApp ora",
"yy": "YY"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "${type} を生成します。受取人はサポートされている任意の暗号通貨で ${method} でき、あなたはこのウォレットで資金を受け取ります。",
"apk_update": "APKアップデート",
"approve": "承認する",
"approve_request": "リクエストを承認します",
"arrive_in_this_address": "${currency} ${tag}はこの住所に到着します",
"ascending": "上昇",
"ask_each_time": "毎回尋ねてください",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "支払い確認を待っています",
"background_sync": "背景同期",
"background_sync_mode": "バックグラウンド同期モード",
"background_sync_on_battery_low": "低いバッテリーで同期します",
"background_sync_on_charging": "充電の場合にのみ同期します",
"background_sync_on_device_idle": "デバイスが使用されていない場合にのみ同期します",
"background_sync_on_unmetered_network": "未成年のネットワークが必要です",
"backup": "バックアップ",
"backup_file": "バックアップファイル",
"backup_password": "バックアップパスワード",
@ -116,9 +121,12 @@
"camera_consent": "あなたのカメラは、${provider}_ までに識別目的で画像を撮影するために使用されます。詳細については、プライバシー ポリシーをご確認ください。",
"camera_permission_is_required": "カメラの許可が必要です。\nアプリの設定から有効にしてください。",
"cancel": "キャンセル",
"cannot_verify": "確認できません",
"cannot_verify_description": "このドメインを検証することはできません。承認する前に、リクエストを注意深く確認してください。",
"card_address": "住所:",
"cardholder_agreement": "カード所有者契約",
"cards": "カード",
"chain_id": "チェーンID",
"chains": "チェーン",
"change": "変化する",
"change_backup_password_alert": "以前のバックアップファイルは、新しいバックアップパスワードでインポートできなくなります。 新しいバックアップパスワードは、新しいバックアップファイルにのみ使用されます。 バックアップパスワードを変更してもよろしいですか?",
@ -174,6 +182,7 @@
"connect_yats": "Yatsを接続します",
"connect_your_hardware_wallet": "BluetoothまたはUSBを使用して、ハードウェアウォレットを接続します",
"connect_your_hardware_wallet_ios": "Bluetoothを使用してハードウェアウォレットを接続します",
"connected": "接続",
"connection_sync": "接続と同期",
"connectWalletPrompt": "ウォレットを WalletConnect に接続して取引を行う",
"contact": "接触",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "バッテリーの最適化を無効にします",
"disableBatteryOptimizationDescription": "バックグラウンドシンクをより自由かつスムーズに実行するために、バッテリーの最適化を無効にしたいですか?",
"disabled": "無効",
"disconnect_session": "セッションを切断します",
"discount": "${value}%を節約",
"display_settings": "表示設定",
"displayable": "表示可能",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "サポートを含め、これらを他の誰とも共有しないでください。\n\nあなたの資金は盗まれる可能性があります!",
"do_not_show_me": "また僕にこれを見せないでください",
"domain_looks_up": "ドメイン検索",
"domain_mismatch": "ドメインの不一致",
"domain_mismatch_description": "このWebサイトには、このリクエストの送信者と一致しないドメインがあります。承認すると、資金の損失につながる可能性があります。",
"donation_link_details": "寄付リンクの詳細",
"e_sign_consent": "電子署名の同意",
"edit": "編集",
@ -298,6 +310,7 @@
"error_text_template": "テンプレートの名前とアドレスに含めることはできません ` , ' \" シンボル\n1〜106文字の長さである必要があります",
"error_text_wallet_name": "ウォレット名には、文字、数字、_-記号のみを含めることができます\n長さは1〜33文字である必要があります",
"error_text_xmr": "XMR値は利用可能な残高を超えることはできません.\n小数桁数は12以下でなければなりません",
"error_while_processing": "処理中にエラーが発生しました",
"errorGettingCredentials": "失敗: 認証情報の取得中にエラーが発生しました",
"errorSigningTransaction": "トランザクションの署名中にエラーが発生しました",
"estimated": "推定",
@ -323,6 +336,7 @@
"export_backup": "バックアップのエクスポート",
"export_logs": "ログをエクスポートします",
"export_outputs": "エクスポート出力",
"extend_session": "セッションを拡張します",
"extra_id": "追加ID:",
"extracted_address_content": "に送金します\n${recipient_name}",
"failed_authentication": "認証失敗. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "パスワードを忘れた",
"freeze": "氷結",
"frequently_asked_questions": "よくある質問",
"from": "から",
"frozen": "凍った",
"frozen_balance": "凍結バランス",
"full_balance": "フルバランス",
"gas_exceeds_allowance": "取引に必要なガスは、手当を超えています。",
"gas_price": "ガス価格",
"generate_name": "名前の生成",
"generated_gift_card": "ギフトカードの生成",
"generating_gift_card": "ギフトカードの生成",
@ -441,6 +457,8 @@
"memo": "メモ:",
"message": "メッセージ",
"message_verified": "メッセージは正常に検証されました",
"messages": "メッセージ",
"method": "方法",
"methods": "メソッド",
"min_amount": "最小: ${value}",
"min_value": "分: ${value} ${currency}",
@ -453,6 +471,7 @@
"monero_dark_theme": "モネロダークテーマ",
"monero_light_theme": "モネロ ライト テーマ",
"moonpay_alert_text": "金額の値は以上でなければなりません ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "NFTの取得中にエラーが発生しました。インターネット接続を確認して、もう一度やり直してください。",
"more_options": "その他のオプション",
"multiple_addresses_detected": "複数のアドレスが検出されました",
"mweb_confirmed": "確認されたMWEB",
@ -469,6 +488,7 @@
"new_subaddress_label_name": "ラベル名",
"new_subaddress_title": "新しいアドレス",
"new_template": "新しいテンプレート",
"new_transactions_notifications": "新しいトランザクションに関する通知を送信します",
"new_wallet": "新しいウォレット",
"newConnection": "新しい接続",
"no_cards_found": "カードは見つかりません",
@ -493,6 +513,7 @@
"normal": "普通",
"note_optional": "注(オプション)",
"note_tap_to_change": "注(タップして変更)",
"notification_permission_denied": "通知の許可はまったく拒否されました。設定で手動で有効にしてください",
"nullURIError": "URIがnullです",
"offer_expires_in": "で有効期限が切れます: ",
"offline": "オフライン",
@ -590,6 +611,7 @@
"rep_warning_sub": "あなたの代表者は良好な状態ではないようです。ここをタップして、新しいものを選択します",
"repeat_wallet_password": "ウォレットパスワードを繰り返します",
"repeated_password_is_incorrect": "繰り返しパスワードが正しくありません。ウォレットのパスワードをもう一度繰り返してください。",
"requested": "リクエスト",
"require_for_adding_contacts": "連絡先の追加に必要",
"require_for_all_security_and_backup_settings": "すべてのセキュリティおよびバックアップ設定に必須",
"require_for_assessing_wallet": "ウォレットにアクセスするために必要です",
@ -651,6 +673,8 @@
"second_intro_content": "Yatは、すべての通貨のすべての長い16進アドレスを置き換える単一の一意の絵文字アドレスです。",
"second_intro_title": "それらすべてを支配する1つの絵文字アドレス",
"security_and_backup": "セキュリティとバックアップ",
"security_risk": "セキュリティリスク",
"security_risk_description": "このドメインは、複数のセキュリティプロバイダーによって安全でないとフラグが付けられています。あなたの資産を保護するためにすぐに出発します。",
"seed_alert_back": "戻る",
"seed_alert_content": "種子はあなたの財布を回復する唯一の方法です。 書き留めましたか?",
"seed_alert_title": "注意",
@ -765,7 +789,9 @@
"show_keys": "シード/キーを表示する",
"show_market_place": "マーケットプレイスを表示",
"show_seed": "シードを表示",
"sign_all": "すべてに署名します",
"sign_message": "署名メッセージ",
"sign_one": "1つに署名します",
"sign_up": "サインアップ",
"sign_verify_message": "署名 /検証",
"sign_verify_message_sub": "秘密鍵を使用してメッセージに署名または確認します",
@ -799,6 +825,7 @@
"subaddress_title": "サブアドレス一覧",
"subaddresses": "サブアドレス",
"submit_request": "リクエストを送信する",
"success": "成功",
"successful": "成功",
"support_description_guides": "一般的な問題のドキュメントとサポート",
"support_description_live_chat": "無料で速い!訓練されたサポート担当者が支援することができます",
@ -806,6 +833,7 @@
"support_title_guides": "ケーキウォレットドキュメント",
"support_title_live_chat": "ライブサポート",
"support_title_other_links": "その他のサポートリンク",
"supported": "サポート",
"swap": "スワップ",
"sweeping_wallet": "スイープウォレット",
"sweeping_wallet_alert": "これには時間がかかりません。この画面から離れないでください。そうしないと、スイープ ファンドが失われる可能性があります",
@ -838,6 +866,7 @@
"thorchain_taproot_address_not_supported": "Thorchainプロバイダーは、TapRootアドレスをサポートしていません。アドレスを変更するか、別のプロバイダーを選択してください。",
"time": "${minutes}m ${seconds}s",
"tip": "ヒント: ",
"to": "に",
"today": "今日",
"token_contract_address": "トークンコントラクトアドレス",
"token_decimal": "トークン10進数",
@ -905,6 +934,7 @@
"transaction_sent_notice": "1分経っても画面が進まない場合は、ブロックエクスプローラーとメールアドレスを確認してください。",
"transactions": "取引",
"transactions_by_date": "日付ごとの取引",
"transport_type": "輸送タイプ",
"trongrid_history": "トロンリッドの歴史",
"trusted": "信頼できる",
"tx_commit_exception_no_dust_on_change": "この金額ではトランザクションは拒否されます。 これらのコインを使用すると、おつりなしの ${min} またはおつりを返す ${max} を送信できます。",
@ -933,6 +963,7 @@
"unspent_coins_details_title": "未使用のコインの詳細",
"unspent_coins_title": "未使用のコイン",
"unsupported_asset": "このアセットに対するこのアクションはサポートされていません。サポートされているアセットタイプのウォレットを作成するか、ウォレットに切り替えてください。",
"update_session": "セッションを更新します",
"uptime": "稼働時間",
"upto": "up up ${value}",
"usb": "USB",
@ -942,6 +973,7 @@
"use_ssl": "SSLを使用する",
"use_suggested": "推奨を使用",
"use_testnet": "テストネットを使用します",
"user_rejected_method": "ユーザーは拒否された方法",
"value": "価値",
"value_type": "値タイプ",
"variable_pair_not_supported": "この変数ペアは、選択した取引所ではサポートされていません",
@ -1025,5 +1057,6 @@
"you_will_get": "に変換",
"you_will_receive_estimated_amount": "あなたは(推定)を受け取ります",
"you_will_send": "から変換",
"youCanGoBackToYourDapp": "あなたは今あなたのダップに戻ることができます",
"yy": "YY"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "${type} 생성. 수신자는 지원되는 모든 암호화폐로 ${method}할 수 있으며 이 지갑에서 자금을 받게 됩니다.",
"apk_update": "APK 업데이트",
"approve": "승인하다",
"approve_request": "요청을 승인하십시오",
"arrive_in_this_address": "${currency} ${tag}이(가) 이 주소로 도착합니다",
"ascending": "오름차순",
"ask_each_time": "매번 물어보십시오",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "결제 확인 대기 중",
"background_sync": "배경 동기화",
"background_sync_mode": "백그라운드 동기화 모드",
"background_sync_on_battery_low": "낮은 배터리에서 동기화하십시오",
"background_sync_on_charging": "충전 할 때만 동기화하십시오",
"background_sync_on_device_idle": "장치를 사용하지 않을 때만 동기화하십시오",
"background_sync_on_unmetered_network": "충족되지 않은 네트워크가 필요합니다",
"backup": "지원",
"backup_file": "백업 파일",
"backup_password": "백업 비밀번호",
@ -116,9 +121,12 @@
"camera_consent": "귀하의 카메라는 ${provider}의 식별 목적으로 이미지를 캡처하는 데 사용됩니다. 자세한 내용은 해당 개인정보 보호정책을 확인하세요.",
"camera_permission_is_required": "카메라 권한이 필요합니다.\n앱 설정에서 활성화해 주세요.",
"cancel": "취소",
"cannot_verify": "확인할 수 없습니다",
"cannot_verify_description": "이 도메인은 확인할 수 없습니다. 승인하기 전에 요청을주의 깊게 확인하십시오.",
"card_address": "주소:",
"cardholder_agreement": "카드 소유자 계약",
"cards": "카드",
"chain_id": "체인 ID",
"chains": "쇠사슬",
"change": "변화",
"change_backup_password_alert": "이전 백업 파일은 새 백업 암호로 가져올 수 없습니다. 새 백업 암호는 새 백업 파일에만 사용됩니다. 백업 비밀번호를 변경 하시겠습니까?",
@ -174,6 +182,7 @@
"connect_yats": "야츠 연결",
"connect_your_hardware_wallet": "Bluetooth 또는 USB를 사용하여 하드웨어 지갑을 연결하십시오",
"connect_your_hardware_wallet_ios": "Bluetooth를 사용하여 하드웨어 지갑을 연결하십시오",
"connected": "연결",
"connection_sync": "연결 및 동기화",
"connectWalletPrompt": "거래를 하려면 WalletConnect에 지갑을 연결하세요.",
"contact": "접촉",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "배터리 최적화를 비활성화합니다",
"disableBatteryOptimizationDescription": "백그라운드 동기화를보다 자유롭고 매끄럽게 실행하기 위해 배터리 최적화를 비활성화하고 싶습니까?",
"disabled": "장애가 있는",
"disconnect_session": "분리 세션",
"discount": "${value}% 절약",
"display_settings": "디스플레이 설정",
"displayable": "표시 가능",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "지원을 포함하여 다른 사람과 이러한 정보를 공유하지 마십시오.\n\n귀하의 자금은 도난당할 수 있고 도난당할 수 있습니다!",
"do_not_show_me": "나를 다시 표시하지 않음",
"domain_looks_up": "도메인 조회",
"domain_mismatch": "도메인 불일치",
"domain_mismatch_description": "이 웹 사이트에는이 요청의 발신자와 일치하지 않는 도메인이 있습니다. 승인은 자금 손실로 이어질 수 있습니다.",
"donation_link_details": "기부 링크 세부정보",
"e_sign_consent": "전자 서명 동의",
"edit": "편집하다",
@ -298,6 +310,7 @@
"error_text_template": "템플릿 이름과 주소는 포함 할 수 없습니다 ` , ' \" 기호 \n1 ~ 106 자 사이 여야합니다",
"error_text_wallet_name": "지갑 이름은 문자, 숫자, _ - 기호만 포함할 수 있습니다.\n1~33자 사이여야 합니다.",
"error_text_xmr": "XMR 값은 사용 가능한 잔액을 초과 할 수 없습니다.\n소수 자릿수는 12 이하 여야합니다",
"error_while_processing": "전환하는 동안 오류가 발생했습니다",
"errorGettingCredentials": "실패: 자격 증명을 가져오는 중 오류가 발생했습니다.",
"errorSigningTransaction": "거래에 서명하는 동안 오류가 발생했습니다.",
"estimated": "예상",
@ -323,6 +336,7 @@
"export_backup": "백업 내보내기",
"export_logs": "내보내기 로그",
"export_outputs": "내보내기 출력",
"extend_session": "세션을 확장하십시오",
"extra_id": "추가 ID:",
"extracted_address_content": "당신은에 자금을 보낼 것입니다\n${recipient_name}",
"failed_authentication": "인증 실패. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "비밀번호 찾기",
"freeze": "얼다",
"frequently_asked_questions": "자주 묻는 질문",
"from": "에서",
"frozen": "겨울 왕국",
"frozen_balance": "냉동 균형",
"full_balance": "풀 밸런스",
"gas_exceeds_allowance": "거래에 필요한 가스는 수당을 초과합니다.",
"gas_price": "가스 가격",
"generate_name": "이름 생성",
"generating_gift_card": "기프트 카드 생성 중",
"generating_transaction": "거래 생성",
@ -440,6 +456,8 @@
"memo": "메모:",
"message": "메시지",
"message_verified": "메시지가 성공적으로 확인되었습니다",
"messages": "메시지",
"method": "방법",
"methods": "행동 양식",
"min_amount": "최소: ${value}",
"min_value": "최소: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "모네로 다크 테마",
"monero_light_theme": "모네로 라이트 테마",
"moonpay_alert_text": "금액은 다음보다 크거나 같아야합니다 ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "NFT를 가져 오는 동안 오류가 발생했습니다. 인터넷 연결을 친절하게 확인하고 다시 시도하십시오.",
"more_options": "추가 옵션",
"multiple_addresses_detected": "여러 주소가 감지되었습니다",
"mweb_confirmed": "확인 mweb",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "라벨 이름",
"new_subaddress_title": "새 주소",
"new_template": "새 템플릿",
"new_transactions_notifications": "새로운 거래에 대한 알림을 보냅니다",
"new_wallet": "새 월렛",
"newConnection": "새로운 연결",
"no_cards_found": "카드를 찾지 못했습니다",
@ -492,6 +512,7 @@
"normal": "정상",
"note_optional": "참고 (선택 사항)",
"note_tap_to_change": "메모 (변경하려면 탭하세요)",
"notification_permission_denied": "알림 허가가 부패하게 거부되었습니다. 설정에서 수동으로 활성화하십시오.",
"nullURIError": "URI가 null입니다.",
"offer_expires_in": "쿠폰 만료일: ",
"offline": "오프라인",
@ -589,6 +610,7 @@
"rep_warning_sub": "귀하의 대표는 양호한 상태가 아닌 것 같습니다. 새 것을 선택하려면 여기를 탭하십시오",
"repeat_wallet_password": "지갑 암호를 반복하십시오",
"repeated_password_is_incorrect": "반복 된 비밀번호가 올바르지 않습니다. 지갑 암호를 다시 반복하십시오.",
"requested": "요청",
"require_for_adding_contacts": "연락처 추가에 필요",
"require_for_all_security_and_backup_settings": "모든 보안 및 백업 설정에 필요",
"require_for_assessing_wallet": "지갑 접근을 위해 필요",
@ -650,6 +672,8 @@
"second_intro_content": "귀하의 Yat는 귀하의 모든 통화에 대해 긴 16진수 주소를 모두 대체하는 고유한 단일 이모지 주소입니다.",
"second_intro_title": "그들을 모두 지배하는 하나의 이모티콘 주소",
"security_and_backup": "보안 및 백업",
"security_risk": "보안 위험",
"security_risk_description": "이 도메인은 여러 보안 제공 업체가 안전하지 않은 것으로 표시됩니다. 자산을 보호하기 위해 즉시 떠나십시오.",
"seed_alert_back": "돌아 가기",
"seed_alert_content": "씨앗은 지갑을 복구하는 유일한 방법입니다. 적어 보셨나요?",
"seed_alert_title": "주의",
@ -764,7 +788,9 @@
"show_keys": "시드 / 키 표시",
"show_market_place": "마켓플레이스 표시",
"show_seed": "종자 표시",
"sign_all": "모두 서명하십시오",
"sign_message": "서명 메시지",
"sign_one": "하나를 서명하십시오",
"sign_up": "가입",
"sign_verify_message": "메시지에 서명하거나 확인하십시오",
"sign_verify_message_sub": "개인 키를 사용하여 메시지에 서명하거나 확인하십시오",
@ -798,6 +824,7 @@
"subaddress_title": "하위 주소 목록",
"subaddresses": "하위 주소",
"submit_request": "요청을 제출",
"success": "성공",
"successful": "성공적인",
"support_description_guides": "일반적인 문제에 대한 문서화 및 지원",
"support_description_live_chat": "자유롭고 빠릅니다! 훈련 된 지원 담당자가 지원할 수 있습니다",
@ -805,6 +832,7 @@
"support_title_guides": "케이크 지갑 문서",
"support_title_live_chat": "실시간 지원",
"support_title_other_links": "다른 지원 링크",
"supported": "지원",
"swap": "교환",
"sweeping_wallet": "스위핑 지갑",
"sweeping_wallet_alert": "오래 걸리지 않습니다. 이 화면을 떠나지 마십시오. 그렇지 않으면 스웹트 자금이 손실될 수 있습니다.",
@ -837,6 +865,7 @@
"thorchain_taproot_address_not_supported": "Thorchain 제공 업체는 Taproot 주소를 지원하지 않습니다. 주소를 변경하거나 다른 공급자를 선택하십시오.",
"time": "${minutes}m ${seconds}s",
"tip": "팁:",
"to": "에게",
"today": "오늘",
"token_contract_address": "토큰 계약 주소",
"token_decimal": "토큰 십진수",
@ -904,6 +933,7 @@
"transaction_sent_notice": "1분 후에도 화면이 진행되지 않으면 블록 익스플로러와 이메일을 확인하세요.",
"transactions": "업무",
"transactions_by_date": "날짜 별 거래",
"transport_type": "운송 유형",
"trongrid_history": "트롱 트리드 역사",
"trusted": "신뢰할 수 있는",
"tx_commit_exception_no_dust_on_change": "이 금액으로 거래가 거부되었습니다. 이 코인을 사용하면 거스름돈 없이 ${min}를 보내거나 거스름돈을 반환하는 ${max}를 보낼 수 있습니다.",
@ -932,6 +962,7 @@
"unspent_coins_details_title": "사용하지 않은 동전 세부 정보",
"unspent_coins_title": "사용하지 않은 동전",
"unsupported_asset": "이 저작물에 대해 이 작업을 지원하지 않습니다. 지원되는 자산 유형의 지갑을 생성하거나 전환하십시오.",
"update_session": "업데이트 세션",
"uptime": "가동 시간",
"upto": "최대 ${value}",
"usb": "USB",
@ -941,6 +972,7 @@
"use_ssl": "SSL 사용",
"use_suggested": "추천 사용",
"use_testnet": "TestNet을 사용하십시오",
"user_rejected_method": "사용자 거부 방법",
"value": "값",
"value_type": "가치 유형",
"variable_pair_not_supported": "이 변수 쌍은 선택한 교환에서 지원되지 않습니다.",
@ -1024,6 +1056,7 @@
"you_will_get": "로 변환하다",
"you_will_receive_estimated_amount": "(추정 )을 받게됩니다.",
"you_will_send": "다음에서 변환",
"youCanGoBackToYourDapp": "이제 DAPP로 돌아갈 수 있습니다",
"YY": "YY",
"yy": "YY"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "${type} ကို ဖန်တီးပါ။ လက်ခံသူက ${method} ကို ပံ့ပိုးပေးထားသည့် cryptocurrency တစ်ခုခုဖြင့် လုပ်ဆောင်နိုင်ပြီး၊ သင်သည် ဤပိုက်ဆံအိတ်တွင် ရံပုံငွေများ ရရှိမည်ဖြစ်သည်။",
"apk_update": "APK အပ်ဒိတ်",
"approve": "လက်မခံပါ။",
"approve_request": "တောင်းဆိုမှုကိုအတည်ပြု",
"arrive_in_this_address": "${currency} ${tag}ဤလိပ်စာသို့ ရောက်ရှိပါမည်။",
"ascending": "တက်",
"ask_each_time": "တစ်ခုချင်းစီကိုအချိန်မေးပါ",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "ငွေပေးချေမှု အတည်ပြုချက်ကို စောင့်မျှော်နေပါသည်။",
"background_sync": "နောက်ခံထပ်တူပြုခြင်း",
"background_sync_mode": "နောက်ခံထပ်တူပြုခြင်း mode ကို",
"background_sync_on_battery_low": "အနိမ့်ဘက်ထရီအပေါ်တစ်ပြိုင်တည်းချိန်ကိုက်",
"background_sync_on_charging": "အားသွင်းသည့်အခါသာထပ်တူပြုခြင်း",
"background_sync_on_device_idle": "စက်ကိုအသုံးမပြုသည့်စက်ကိုသာတစ်ပြိုင်တည်းချိန်ကိုက်ပါ",
"background_sync_on_unmetered_network": "unmetred ကွန်ယက်လိုအပ်သည်",
"backup": "မိတ္တူ",
"backup_file": "အရန်ဖိုင်",
"backup_password": "စကားဝှက်ကို အရန်သိမ်းဆည်းပါ။",
@ -116,9 +121,12 @@
"camera_consent": "မှတ်ပုံတင်ခြင်းရည်ရွယ်ချက်များအတွက် ${provider} တွင် သင့်ကင်မရာကို အသုံးပြုပါမည်။ အသေးစိတ်အတွက် ၎င်းတို့၏ ကိုယ်ရေးကိုယ်တာမူဝါဒကို စစ်ဆေးပါ။",
"camera_permission_is_required": "ကင်မရာခွင့်ပြုချက် လိုအပ်ပါသည်။\nအက်ပ်ဆက်တင်များမှ ၎င်းကိုဖွင့်ပါ။",
"cancel": "မလုပ်တော့",
"cannot_verify": "အတည်ပြုလို့မရပါ",
"cannot_verify_description": "ဒီဒိုမိန်းကိုအတည်မပြုနိုင်ပါ။ အတည်ပြုခြင်းမပြုမီတောင်းဆိုမှုကိုဂရုတစိုက်စစ်ဆေးပါ။",
"card_address": "လိပ်စာ-",
"cardholder_agreement": "ကတ်ကိုင်ဆောင်သူ သဘောတူညီချက်",
"cards": "ကတ်များ",
"chain_id": "Chain ID Chain ID",
"chains": "ဆွဲကြိုး",
"change": "ပြောင်းလဲပါ။",
"change_backup_password_alert": "အရန်စကားဝှက်အသစ်ဖြင့် သင်၏ယခင်မိတ္တူဖိုင်များကို တင်သွင်းရန် မရနိုင်ပါ။ အရန်စကားဝှက်အသစ်ကို အရန်ဖိုင်အသစ်အတွက်သာ အသုံးပြုပါမည်။ အရန်စကားဝှက်ကို ပြောင်းလိုသည်မှာ သေချာပါသလား။",
@ -174,6 +182,7 @@
"connect_yats": "Yats ကိုချိတ်ဆက်ပါ။",
"connect_your_hardware_wallet": "သင်၏ hardware ပိုက်ဆံအိတ်ကို Bluetooth သို့မဟုတ် USB ကို သုံး. ချိတ်ဆက်ပါ",
"connect_your_hardware_wallet_ios": "သင်၏ hardware ပိုက်ဆံအိတ်ကို Bluetooth ကို အသုံးပြု. ချိတ်ဆက်ပါ",
"connected": "ချိတ်ဆက်ထားသော",
"connection_sync": "ချိတ်ဆက်မှုနှင့် ထပ်တူပြုခြင်း။",
"connectWalletPrompt": "အရောင်းအဝယ်ပြုလုပ်ရန် သင့်ပိုက်ဆံအိတ်ကို WalletConnect နှင့် ချိတ်ဆက်ပါ။",
"contact": "ဆက်သွယ်ရန်",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "ဘက်ထရီ optimization ကိုပိတ်ပါ",
"disableBatteryOptimizationDescription": "နောက်ခံထပ်တူပြုခြင်းနှင့်ချောချောမွေ့မွေ့ပြုလုပ်နိုင်ရန်ဘက်ထရီ optimization ကိုသင်ပိတ်ထားလိုပါသလား။",
"disabled": "မသန်စွမ်း",
"disconnect_session": "session ကိုအဆက်ပြတ်",
"discount": "${value}% ချွေတာ",
"display_settings": "ပြသရန် ဆက်တင်များ",
"displayable": "ပြသနိုင်သည်။",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "ပံ့ပိုးကူညီမှုအပါအဝင် ဤအရာများကို အခြားမည်သူနှင့်မျှ မမျှဝေပါနှင့်။\n\nသင့်ငွေများကို ခိုးယူခံရနိုင်သည်!",
"do_not_show_me": "ဒါကို ထပ်မပြနဲ့",
"domain_looks_up": "ဒိုမိန်းရှာဖွေမှုများ",
"domain_mismatch": "ဒိုမိန်းမတိုက်ဆိုင်",
"domain_mismatch_description": "ဤ 0 က်ဘ်ဆိုက်တွင်ဤတောင်းဆိုမှုကိုပေးပို့သူနှင့်မကိုက်ညီသောဒိုမိန်းရှိသည်။ အတည်ပြုခြင်းသည်ရန်ပုံငွေများဆုံးရှုံးမှုကိုဖြစ်ပေါ်စေနိုင်သည်။",
"donation_link_details": "လှူဒါန်းရန်လင့်ခ်အသေးစိတ်",
"e_sign_consent": "E-Sign သဘောတူညီချက်",
"edit": "တည်းဖြတ်ပါ။",
@ -298,6 +310,7 @@
"error_text_template": "နမူနာပုံစံအမည်နှင့် လိပ်စာတွင် ` , ' \" သင်္ကေတများ မပါဝင်နိုင်ပါ\nနှင့် စာလုံးအရှည် 1 နှင့် 106 ကြား ရှိရမည်",
"error_text_wallet_name": "ပိုက်ဆံအိတ်အမည်တွင် စာလုံးများ၊ နံပါတ်များ၊ _ - သင်္ကေတများသာ ပါဝင်နိုင်သည် \n နှင့် စာလုံးအရှည် 1 နှင့် 33 ကြားရှိရမည်",
"error_text_xmr": "XMR တန်ဖိုးသည် ရနိုင်သောလက်ကျန်ကို ကျော်လွန်၍မရပါ။\nအပိုင်းကိန်းဂဏန်းများ သည် 12 နှင့် လျော့နည်းရမည်",
"error_while_processing": "procesing နေစဉ်အမှားတစ်ခုဖြစ်ပွားခဲ့သည်",
"errorGettingCredentials": "မအောင်မြင်ပါ- အထောက်အထားများ ရယူနေစဉ် အမှားအယွင်း",
"errorSigningTransaction": "ငွေပေးငွေယူ လက်မှတ်ထိုးစဉ် အမှားအယွင်းတစ်ခု ဖြစ်ပေါ်ခဲ့သည်။",
"estimated": "ခန့်မှန်း",
@ -323,6 +336,7 @@
"export_backup": "အရန်ကူးထုတ်ရန်",
"export_logs": "ပို့ကုန်မှတ်တမ်းများ",
"export_outputs": "ပို့ကုန်ထုတ်ကုန်များ",
"extend_session": "session တစ်ခုတိုးချဲ့",
"extra_id": "အပို ID-",
"extracted_address_content": "သင်သည် \n${recipient_name} သို့ ရန်ပုံငွေများ ပေးပို့ပါမည်",
"failed_authentication": "အထောက်အထားစိစစ်ခြင်း မအောင်မြင်ပါ။. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "စကားဝှက်မေ့နေပါသလား",
"freeze": "အေးခဲ",
"frequently_asked_questions": "မေးလေ့ရှိသောမေးခွန်းများ",
"from": "မှ",
"frozen": "ဖြူဖြူ",
"frozen_balance": "လက်ကျန်ငွေ",
"full_balance": "Balance အပြည့်",
"gas_exceeds_allowance": "ငွေပေးငွေယူမှလိုအပ်သောဓာတ်ငွေ့ထောက်ပံ့ကြေးကျော်လွန်။",
"gas_price": "ဓာတ်ငွေ့စျေးနှုန်း",
"generate_name": "အမည်ဖန်တီးပါ။",
"generating_gift_card": "လက်ဆောင်ကတ်ထုတ်ပေးခြင်း။",
"generating_transaction": "ငွေပေးငွေယူကိုထုတ်လုပ်",
@ -440,6 +456,8 @@
"memo": "မှတ်စုတို:",
"message": "မက်ဆေ့ချ်",
"message_verified": "မက်ဆေ့ခ်ျကိုအောင်မြင်စွာအတည်ပြုခဲ့သည်",
"messages": "မက်ဆေ့ခ်ျ",
"method": "နည်းလမ်း",
"methods": "နည်းလမ်းများ",
"min_amount": "အနည်းဆုံး- ${value}",
"min_value": "အနည်းဆုံး- ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "Monero Dark အပြင်အဆင်",
"monero_light_theme": "Monero Light အပြင်အဆင်",
"moonpay_alert_text": "ပမာဏ၏တန်ဖိုးသည် ${minAmount} ${fiatCurrency} နှင့် ပိုနေရမည်",
"moralis_nft_error": "nfts ရယူနေစဉ်အမှားတစ်ခုဖြစ်ပွားခဲ့သည်။ သင်၏အင်တာနက်ဆက်သွယ်မှုကိုကြင်နာစွာစစ်ဆေးပြီးထပ်ကြိုးစားပါ။",
"more_options": "နောက်ထပ် ရွေးချယ်စရာများ",
"multiple_addresses_detected": "အများအပြားလိပ်စာများရှာဖွေတွေ့ရှိ",
"mweb_confirmed": "အတည်ပြုလိုက် mweb",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "အညွှန်းအမည်",
"new_subaddress_title": "လိပ်စာအသစ်",
"new_template": "ပုံစံအသစ်",
"new_transactions_notifications": "အသစ်သောအရောင်းအဝယ်အကြောင်းသတိပေးချက်များပေးပို့ပါ",
"new_wallet": "ပိုက်ဆံအိတ်အသစ်",
"newConnection": "ချိတ်ဆက်မှုအသစ်",
"no_cards_found": "ကဒ်များမရှိပါ",
@ -492,6 +512,7 @@
"normal": "ပုံမှန်",
"note_optional": "မှတ်ချက် (ချန်လှပ်ထားနိုင်သည်)",
"note_tap_to_change": "မှတ်ချက် (ပြောင်းလဲရန် တို့ပါ)",
"notification_permission_denied": "အသိပေးချက်ခွင့်ပြုချက်ကိုအစက်အပြောက်ကိုငြင်းဆိုခဲ့သည်, ကျေးဇူးပြု. ၎င်းကိုချိန်ညှိချက်များတွင်လက်ဖြင့်ပြုလုပ်ပါ",
"nullURIError": "URI သည် null ဖြစ်သည်။",
"offer_expires_in": "ကမ်းလှမ်းချက် သက်တမ်းကုန်သည်:",
"offline": "အော့ဖ်လိုင်း",
@ -589,6 +610,7 @@
"rep_warning_sub": "သင်၏ကိုယ်စားလှယ်သည်ကောင်းမွန်သောရပ်တည်မှုတွင်မဖြစ်သင့်ပါ။ အသစ်တစ်ခုကိုရွေးချယ်ရန်ဤနေရာတွင်အသာပုတ်ပါ",
"repeat_wallet_password": "ပိုက်ဆံအိတ်စကားဝှက်ကိုပြန်လုပ်ပါ",
"repeated_password_is_incorrect": "ထပ်ခါတလဲလဲစကားဝှက်မမှန်ကန်ပါ ကျေးဇူးပြုပြီးပိုက်ဆံအိတ်စကားဝှက်ကိုပြန်လုပ်ပါ။",
"requested": "တောင်းဆိုခဲ့သည်",
"require_for_adding_contacts": "အဆက်အသွယ်များထည့်ရန် လိုအပ်သည်။",
"require_for_all_security_and_backup_settings": "လုံခြုံရေးနှင့် အရန်ဆက်တင်များအားလုံးအတွက် လိုအပ်ပါသည်။",
"require_for_assessing_wallet": "ပိုက်ဆံအိတ်ကို ဝင်သုံးရန် လိုအပ်သည်။",
@ -650,6 +672,8 @@
"second_intro_content": "သင်၏ Yat သည် သင့်ငွေကြေးအားလုံးအတွက် သင်၏ ရှည်လျားသော ဆဋ္ဌမကိန်းဂဏန်းများအားလုံးကို အစားထိုးသည့် တစ်မူထူးခြားသော အီမိုဂျီလိပ်စာတစ်ခုဖြစ်သည်။",
"second_intro_title": "၎င်းတို့အားလုံးကို အုပ်ချုပ်ရန် အီမိုဂျီလိပ်စာတစ်ခု",
"security_and_backup": "လုံခြုံရေးနှင့် မိတ္တူ",
"security_risk": "လုံခြုံရေးအန္တရာယ်",
"security_risk_description": "ဒီဒိုမိန်းကိုလုံခြုံရေးပံ့ပိုးပေးသူတွေရဲ့လုံခြုံမှုမရှိဘူး။ သင်၏ပိုင်ဆိုင်မှုများကိုကာကွယ်ရန်ချက်ချင်းချန်ထားပါ။",
"seed_alert_back": "ပြန်သွားသည်",
"seed_alert_content": "မျိုးစေ့သည် သင့်ပိုက်ဆံအိတ်ကို ပြန်လည်ရယူရန် တစ်ခုတည်းသောနည်းလမ်းဖြစ်သည်။ ရေးပြီးပြီလား။",
"seed_alert_title": "အာရုံ",
@ -764,7 +788,9 @@
"show_keys": "မျိုးစေ့ /သော့များကို ပြပါ။",
"show_market_place": "စျေးကွက်ကိုပြသပါ။",
"show_seed": "မျိုးစေ့ကိုပြပါ။",
"sign_all": "အားလုံးလက်မှတ်ထိုးပါ",
"sign_message": "လက်မှတ်စာ",
"sign_one": "လက်မှတ်ထိုးပါ",
"sign_up": "ဆိုင်းအပ်",
"sign_verify_message": "လက်မှတ်ထိုး / အတည်ပြုရန်",
"sign_verify_message_sub": "သင်၏ကိုယ်ပိုင်သော့ကို သုံး. မက်ဆေ့ခ်ျကိုလက်မှတ်ထိုးပါ",
@ -798,6 +824,7 @@
"subaddress_title": "လိပ်စာစာရင်း",
"subaddresses": "လိပ်စာများ",
"submit_request": "တောင်းဆိုချက်တစ်ခုတင်ပြပါ။",
"success": "အောင်မြင်ခြင်း",
"successful": "အောင်မြင်တယ်။",
"support_description_guides": "ဘုံပြ issues နာများအတွက်စာရွက်စာတမ်းများနှင့်ထောက်ခံမှု",
"support_description_live_chat": "အခမဲ့နှင့်အစာရှောင်ခြင်း! လေ့ကျင့်ထားသောထောက်ခံသူကိုယ်စားလှယ်များသည်ကူညီနိုင်သည်",
@ -805,6 +832,7 @@
"support_title_guides": "ကိတ်မုန့်ပိုက်ဆံအိတ်များ",
"support_title_live_chat": "တိုက်ရိုက်ပံ့ပိုးမှု",
"support_title_other_links": "အခြားအထောက်အပံ့လင့်များ",
"supported": "ထောက်ပံ့ခဲ့သည်",
"swap": "လဲလှယ်",
"sweeping_wallet": "ိုက်ဆံအိတ် တံမြက်လှည်း",
"sweeping_wallet_alert": "ဒါက ကြာကြာမခံသင့်ပါဘူး။ ဤစခရင်ကို ချန်မထားပါနှင့် သို့မဟုတ် ထုတ်ယူထားသော ရန်ပုံငွေများ ဆုံးရှုံးနိုင်သည်",
@ -837,6 +865,7 @@
"thorchain_taproot_address_not_supported": "Thorchain Provider သည် Taproot လိပ်စာများကိုမထောက်ခံပါ။ ကျေးဇူးပြု. လိပ်စာကိုပြောင်းပါသို့မဟုတ်အခြားပံ့ပိုးပေးသူကိုရွေးချယ်ပါ။",
"time": "${minutes}m ${seconds}s",
"tip": "အကြံပြုချက်-",
"to": "သို့",
"today": "ဒီနေ့",
"token_contract_address": "တိုကင်စာချုပ်လိပ်စာ",
"token_decimal": "တိုကင်ဒဿမ",
@ -904,6 +933,7 @@
"transaction_sent_notice": "မျက်နှာပြင်သည် ၁ မိနစ်အကြာတွင် ဆက်လက်မလုပ်ဆောင်ပါက၊ ပိတ်ဆို့ရှာဖွေသူနှင့် သင့်အီးမေးလ်ကို စစ်ဆေးပါ။",
"transactions": "ငွေပေးငွေယူ",
"transactions_by_date": "ရက်စွဲအလိုက် ငွေလွှဲမှုများ",
"transport_type": "သယ်ယူပို့ဆောင်ရေးအမျိုးအစား",
"trongrid_history": "Trongrid သမိုင်း",
"trusted": "ယုံတယ်။",
"tx_commit_exception_no_dust_on_change": "အဆိုပါငွေပေးငွေယူကဒီပမာဏနှင့်အတူပယ်ချခံရသည်။ ဤဒင်္ဂါးပြားများနှင့်အတူပြောင်းလဲမှုကိုပြန်လည်ပြောင်းလဲခြင်းသို့မဟုတ် ${min} မပါဘဲ ${max} ပေးပို့နိုင်သည်။",
@ -932,6 +962,7 @@
"unspent_coins_details_title": "အသုံးမဝင်သော အကြွေစေ့အသေးစိတ်များ",
"unspent_coins_title": "အသုံးမဝင်သော အကြွေစေ့များ",
"unsupported_asset": "ဤပိုင်ဆိုင်မှုအတွက် ဤလုပ်ဆောင်ချက်ကို ကျွန်ုပ်တို့ မပံ့ပိုးပါ။ ကျေးဇူးပြု၍ ပံ့ပိုးပေးထားသော ပိုင်ဆိုင်မှုအမျိုးအစား၏ ပိုက်ဆံအိတ်ကို ဖန်တီးပါ သို့မဟုတ် ပြောင်းပါ။",
"update_session": "update session ကို",
"uptime": "အထက်က",
"upto": "${value} အထိ",
"usb": "ယူအက်စ်ဘီ",
@ -941,6 +972,7 @@
"use_ssl": "SSL ကိုသုံးပါ။",
"use_suggested": "အကြံပြုထားသည်ကို အသုံးပြုပါ။",
"use_testnet": "testnet ကိုသုံးပါ",
"user_rejected_method": "အသုံးပြုသူသည်နည်းလမ်းကိုငြင်းပယ်ခဲ့သည်",
"value": "အဘိုး",
"value_type": "Value အမျိုးအစား",
"variable_pair_not_supported": "ရွေးချယ်ထားသော ဖလှယ်မှုများဖြင့် ဤပြောင်းလဲနိုင်သောအတွဲကို ပံ့ပိုးမထားပါ။",
@ -1024,5 +1056,6 @@
"you_will_get": "သို့ပြောင်းပါ။",
"you_will_receive_estimated_amount": "သင် ( ခန့်မှန်းခြေ ) လက်ခံရရှိလိမ့်မည်",
"you_will_send": "မှပြောင်းပါ။",
"youCanGoBackToYourDapp": "သငျသညျယခုသင်၏ dapp ကိုပြန်သွားနိုင်ပါတယ်",
"yy": "YY"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "Genereer ${type}. De ontvanger kan ${method} gebruiken met elke ondersteunde cryptocurrency en u ontvangt geld in deze portemonnee",
"apk_update": "APK-update",
"approve": "Goedkeuren",
"approve_request": "Het verzoek goedkeuren",
"arrive_in_this_address": "${currency} ${tag}komt aan op dit adres",
"ascending": "Stijgend",
"ask_each_time": "Vraag het elke keer",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "In afwachting van betalingsbevestiging",
"background_sync": "Achtergrondsynchronisatie",
"background_sync_mode": "Achtergrondsynchronisatiemodus",
"background_sync_on_battery_low": "Synchroniseren op lage batterij",
"background_sync_on_charging": "Synchroniseer alleen bij het opladen",
"background_sync_on_device_idle": "Synchroniseer alleen wanneer het apparaat niet wordt gebruikt",
"background_sync_on_unmetered_network": "Vereist een onvermekte netwerk",
"backup": "Back-up",
"backup_file": "Backup bestand",
"backup_password": "Reservewachtwoord",
@ -116,9 +121,12 @@
"camera_consent": "Uw camera wordt gebruikt om vóór ${provider} een beeld vast te leggen voor identificatiedoeleinden. Raadpleeg hun privacybeleid voor meer informatie.",
"camera_permission_is_required": "Cameratoestemming is vereist.\nSchakel dit in via de app-instellingen.",
"cancel": "Annuleer",
"cannot_verify": "Kan niet verifiëren",
"cannot_verify_description": "Dit domein kan niet worden geverifieerd. Controleer het verzoek zorgvuldig voordat u het goedkeurt.",
"card_address": "Adres:",
"cardholder_agreement": "Kaarthouderovereenkomst",
"cards": "Kaarten",
"chain_id": "Keten -ID",
"chains": "Ketens",
"change": "Verandering",
"change_backup_password_alert": "Uw vorige back-upbestanden kunnen niet worden geïmporteerd met een nieuw back-upwachtwoord. Het nieuwe back-upwachtwoord wordt alleen gebruikt voor nieuwe back-upbestanden. Weet u zeker dat u het back-upwachtwoord wilt wijzigen?",
@ -174,6 +182,7 @@
"connect_yats": "Verbind Yats",
"connect_your_hardware_wallet": "Sluit uw hardware -portemonnee aan met Bluetooth of USB",
"connect_your_hardware_wallet_ios": "Sluit uw hardware -portemonnee aan met Bluetooth",
"connected": "Aangesloten",
"connection_sync": "Verbinding en synchronisatie",
"connectWalletPrompt": "Verbind uw portemonnee met WalletConnect om transacties uit te voeren",
"contact": "Contact",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "Schakel de batterijoptimalisatie uit",
"disableBatteryOptimizationDescription": "Wilt u de optimalisatie van de batterij uitschakelen om achtergrondsynchronisatie te laten werken, vrijer en soepeler?",
"disabled": "Gehandicapt",
"disconnect_session": "Koppel de sessie los",
"discount": "Bespaar ${value}%",
"display_settings": "Weergave-instellingen",
"displayable": "Weer te geven",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "Deel deze met niemand anders, ook niet met support.\n\nUw geld kan en zal worden gestolen!",
"do_not_show_me": "laat me dit niet opnieuw zien",
"domain_looks_up": "Domein opzoeken",
"domain_mismatch": "Domein mismatch",
"domain_mismatch_description": "Deze website heeft een domein dat niet overeenkomt met de afzender van dit verzoek. Goedkeuring kan leiden tot verlies van fondsen.",
"donation_link_details": "Details van de donatielink",
"e_sign_consent": "Toestemming e-ondertekenen",
"edit": "Bewerk",
@ -298,6 +310,7 @@
"error_text_template": "Sjabloonnaam en -adres mogen niet bevatten ` , ' \" symbolen\nen moet tussen de 1 en 106 tekens lang zijn",
"error_text_wallet_name": "Naam portemonnee kan alleen letters, cijfers , _ - symbolen bevatten\nen moet tussen de 1 en 33 tekens lang zijn",
"error_text_xmr": "XMR-waarde kan het beschikbare saldo niet overschrijden.\nHet aantal breukcijfers moet kleiner zijn dan of gelijk zijn aan 12",
"error_while_processing": "Er is een fout opgetreden tijdens het procederen",
"errorGettingCredentials": "Mislukt: fout bij het ophalen van inloggegevens",
"errorSigningTransaction": "Er is een fout opgetreden tijdens het ondertekenen van de transactie",
"estimated": "Geschatte",
@ -323,6 +336,7 @@
"export_backup": "Back-up exporteren",
"export_logs": "Exporteer logboeken",
"export_outputs": "Exportuitgangen exporteren",
"extend_session": "Sessie verlengen",
"extra_id": "Extra ID:",
"extracted_address_content": "U stuurt geld naar\n${recipient_name}",
"failed_authentication": "Mislukte authenticatie. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "Wachtwoord vergeten",
"freeze": "Bevriezen",
"frequently_asked_questions": "Veelgestelde vragen",
"from": "Van",
"frozen": "Bevroren",
"frozen_balance": "Bevroren balans",
"full_balance": "Volledig saldo",
"gas_exceeds_allowance": "Gas vereist door transactie overschrijdt de vergoeding.",
"gas_price": "Gasprijs",
"generate_name": "Naam genereren",
"generating_gift_card": "Cadeaubon genereren",
"generating_transaction": "Transactie genereren",
@ -440,6 +456,8 @@
"memo": "Memo:",
"message": "Bericht",
"message_verified": "Het bericht is succesvol geverifieerd",
"messages": "Berichten",
"method": "Methode",
"methods": "Methoden",
"min_amount": "Min: ${value}",
"min_value": "Min: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "Monero donker thema",
"monero_light_theme": "Monero Light-thema",
"moonpay_alert_text": "Waarde van het bedrag moet meer of gelijk zijn aan ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "Er is een fout opgetreden bij het ophalen van NFT's. Controleer uw internetverbinding vriendelijk en probeer het opnieuw.",
"more_options": "Meer opties",
"multiple_addresses_detected": "Meerdere adressen gedetecteerd",
"mweb_confirmed": "Bevestigde MWEB",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "Label naam",
"new_subaddress_title": "Nieuw adres",
"new_template": "Nieuwe sjabloon",
"new_transactions_notifications": "Stuur meldingen over nieuwe transacties",
"new_wallet": "Nieuwe portemonnee",
"newConnection": "Nieuwe verbinding",
"no_cards_found": "Geen kaarten gevonden",
@ -492,6 +512,7 @@
"normal": "Normaal",
"note_optional": "Opmerking (optioneel)",
"note_tap_to_change": "Opmerking (tik om te wijzigen)",
"notification_permission_denied": "Meldingstoestemming is permanent geweigerd, schakel het handmatig in instellingen in",
"nullURIError": "URI is nul",
"offer_expires_in": "Aanbieding verloopt over: ",
"offline": "Offline",
@ -589,6 +610,7 @@
"rep_warning_sub": "Uw vertegenwoordiger lijkt niet goed te staan. Tik hier om een nieuwe te selecteren",
"repeat_wallet_password": "Herhaal het Wallet -wachtwoord",
"repeated_password_is_incorrect": "Herhaald wachtwoord is onjuist. Herhaal het Wallet -wachtwoord opnieuw.",
"requested": "Gevraagd",
"require_for_adding_contacts": "Vereist voor het toevoegen van contacten",
"require_for_all_security_and_backup_settings": "Vereist voor alle beveiligings- en back-upinstellingen",
"require_for_assessing_wallet": "Vereist voor toegang tot portemonnee",
@ -650,6 +672,8 @@
"second_intro_content": "Je Yat is een enkel uniek emoji-adres dat al je lange hexadecimale adressen vervangt voor al je valuta's.",
"second_intro_title": "Eén emoji-adres om ze allemaal te regeren",
"security_and_backup": "Beveiliging en back-up",
"security_risk": "Beveiligingsrisico",
"security_risk_description": "Dit domein wordt door meerdere beveiligingsproviders gemarkeerd als onveilig. Vertrek onmiddellijk om uw vermogen te beschermen.",
"seed_alert_back": "Ga terug",
"seed_alert_content": "Het zaad is de enige manier om uw portemonnee te herstellen. Heb je het opgeschreven?",
"seed_alert_title": "Aandacht",
@ -764,7 +788,9 @@
"show_keys": "Toon zaad/sleutels",
"show_market_place": "Toon Marktplaats",
"show_seed": "Toon zaad",
"sign_all": "Teken alles",
"sign_message": "Aanmeldingsbericht",
"sign_one": "Ondertekenen een",
"sign_up": "Aanmelden",
"sign_verify_message": "Teken of verifieer bericht",
"sign_verify_message_sub": "Teken of verifieer een bericht met uw privésleutel",
@ -798,6 +824,7 @@
"subaddress_title": "Subadreslijst",
"subaddresses": "Subadressen",
"submit_request": "een verzoek indienen",
"success": "Succes",
"successful": "Succesvol",
"support_description_guides": "Documentatie en ondersteuning voor gemeenschappelijke problemen",
"support_description_live_chat": "Gratis en snel! Getrainde ondersteuningsvertegenwoordigers zijn beschikbaar om te helpen",
@ -805,6 +832,7 @@
"support_title_guides": "Cake -portemonnee documenten",
"support_title_live_chat": "Live ondersteuning",
"support_title_other_links": "Andere ondersteuningslinks",
"supported": "Ondersteund",
"swap": "Ruil",
"sweeping_wallet": "Vegende portemonnee",
"sweeping_wallet_alert": "Dit duurt niet lang. VERLAAT DIT SCHERM NIET, ANDERS KAN HET SWEPT-GELD VERLOREN WORDEN",
@ -837,6 +865,7 @@
"thorchain_taproot_address_not_supported": "De Thorchain -provider ondersteunt geen Taprooot -adressen. Wijzig het adres of selecteer een andere provider.",
"time": "${minutes}m ${seconds}s",
"tip": "Tip:",
"to": "Naar",
"today": "Vandaag",
"token_contract_address": "Token contractadres",
"token_decimal": "Token decimaal",
@ -904,6 +933,7 @@
"transaction_sent_notice": "Als het scherm na 1 minuut niet verder gaat, controleer dan een blokverkenner en je e-mail.",
"transactions": "Transacties",
"transactions_by_date": "Transacties op datum",
"transport_type": "Transporttype",
"trongrid_history": "Trongrid geschiedenis",
"trusted": "vertrouwd",
"tx_commit_exception_no_dust_on_change": "De transactie wordt afgewezen met dit bedrag. Met deze munten kunt u ${min} verzenden zonder verandering of ${max} die wijziging retourneert.",
@ -932,6 +962,7 @@
"unspent_coins_details_title": "Details van niet-uitgegeven munten",
"unspent_coins_title": "Ongebruikte munten",
"unsupported_asset": "We ondersteunen deze actie niet voor dit item. Maak of schakel over naar een portemonnee van een ondersteund activatype.",
"update_session": "Updatesessie",
"uptime": "Uptime",
"upto": "tot ${value}",
"usb": "USB",
@ -941,6 +972,7 @@
"use_ssl": "Gebruik SSL",
"use_suggested": "Gebruik aanbevolen",
"use_testnet": "Gebruik testnet",
"user_rejected_method": "Gebruiker afgewezen methode",
"value": "Waarde",
"value_type": "Waarde type",
"variable_pair_not_supported": "Dit variabelenpaar wordt niet ondersteund met de geselecteerde uitwisselingen",
@ -1025,5 +1057,6 @@
"you_will_get": "Converteren naar",
"you_will_receive_estimated_amount": "U ontvangt(geschat )",
"you_will_send": "Converteren van",
"youCanGoBackToYourDapp": "U kunt nu terug naar uw DApp gaan",
"yy": "JJ"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "Wygeneruj ${type}. Odbiorca może ${method} z dowolną obsługiwaną kryptowalutą, a Ty otrzymasz środki w tym portfelu.",
"apk_update": "Aktualizacja APK",
"approve": "Zatwierdzić",
"approve_request": "Zatwierdzić żądanie",
"arrive_in_this_address": "${currency} ${tag}dotrze na ten adres",
"ascending": "Wznoszący się",
"ask_each_time": "Zapytaj za każdym razem",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "Oczekiwanie na potwierdzenie płatności",
"background_sync": "Synchronizacja w tle",
"background_sync_mode": "Tryb synchronizacji w tle",
"background_sync_on_battery_low": "Synchronizować na niskiej baterii",
"background_sync_on_charging": "Synchronizować tylko podczas ładowania",
"background_sync_on_device_idle": "Synchronizować tylko wtedy, gdy urządzenie nie jest używane",
"background_sync_on_unmetered_network": "Wymagaj niezametrowanej sieci",
"backup": "Kopia zapasowa",
"backup_file": "Plik kopii zapasowej",
"backup_password": "Hasło kpoii zapasowej",
@ -116,9 +121,12 @@
"camera_consent": "Twój aparat zostanie użyty do przechwycenia obrazu w celach identyfikacyjnych przez ${provider}. Aby uzyskać szczegółowe informacje, sprawdź ich Politykę prywatności.",
"camera_permission_is_required": "Wymagane jest pozwolenie na korzystanie z aparatu.\nWłącz tę funkcję w ustawieniach aplikacji.",
"cancel": "Anuluj",
"cannot_verify": "Nie można zweryfikować",
"cannot_verify_description": "Tę domeny nie można zweryfikować. Przed zatwierdzeniem sprawdź prośbę.",
"card_address": "Adres:",
"cardholder_agreement": "Umowa posiadacza karty",
"cards": "Karty",
"chain_id": "Identyfikator łańcucha",
"chains": "Łańcuchy",
"change": "Zmień",
"change_backup_password_alert": "Twoje poprzednie pliki kopii zapasowej nie będą dostępne do zaimportowania z nowym hasłem kopii zapasowej. Nowe hasło kopii zapasowej będzie używane tylko dla nowych plików kopii zapasowych. Czy na pewno chcesz zmienić hasło zapasowe?",
@ -174,6 +182,7 @@
"connect_yats": "Połącz Yats",
"connect_your_hardware_wallet": "Podłącz portfel sprzętowy za pomocą Bluetooth lub USB",
"connect_your_hardware_wallet_ios": "Podłącz portfel sprzętowy za pomocą Bluetooth",
"connected": "Połączony",
"connection_sync": "Połączenie i synchronizacja",
"connectWalletPrompt": "Połącz swój portfel z WalletConnect, aby dokonywać transakcji",
"contact": "Kontakt",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "Wyłącz optymalizację baterii",
"disableBatteryOptimizationDescription": "Czy chcesz wyłączyć optymalizację baterii, aby synchronizacja tła działała swobodniej i płynnie?",
"disabled": "Wyłączone",
"disconnect_session": "Odłącz sesję",
"discount": "Zaoszczędź ${value}%",
"display_settings": "Ustawienia wyświetlania",
"displayable": "Wyświetlane",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "NIE udostępniaj ich nikomu innemu, w tym pomocy technicznej.\n\nJeśli to zrobisz twoje środki prawdopodobnie zostaną skradzione!",
"do_not_show_me": "Nie pokazuj mi tego ponownie",
"domain_looks_up": "Wyszukiwanie domen",
"domain_mismatch": "Niedopasowanie domeny",
"domain_mismatch_description": "Ta strona ma domenę, która nie pasuje do nadawcy tego żądania. Zatwierdzenie może prowadzić do utraty funduszy.",
"donation_link_details": "Szczegóły linku darowizny",
"e_sign_consent": "Zgoda na podpis elektroniczny",
"edit": "Edytuj",
@ -298,6 +310,7 @@
"error_text_template": "Nazwa i adres szablonu nie mogą zawierać ` , ' \" symbolika\ni musi mieć od 1 do 106 znaków",
"error_text_wallet_name": "Nazwa portfela może zawierać tylko litery, cyfry lub symbole _ - \ni musi mieć od 1 do 33 znaków",
"error_text_xmr": "Wartość XMR nie może przekraczać dostępnego salda.\nLiczba cyfr dziesiętnych musi być mniejsza lub równa 12",
"error_while_processing": "Wystąpił błąd podczas przeróbki",
"errorGettingCredentials": "Niepowodzenie: Błąd podczas uzyskiwania poświadczeń",
"errorSigningTransaction": "Wystąpił błąd podczas podpisywania transakcji",
"estimated": "Oszacowano",
@ -323,6 +336,7 @@
"export_backup": "Eksportuj kopię zapasową",
"export_logs": "Eksportuj dzienniki",
"export_outputs": "Eksportuj wyjscia",
"extend_session": "Rozszerzyć sesję",
"extra_id": "Dodatkowy ID:",
"extracted_address_content": "Wysyłasz środki na\n${recipient_name}",
"failed_authentication": "Nieudane uwierzytelnienie. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "Zapomniałem hasła",
"freeze": "Zamróź",
"frequently_asked_questions": "Często zadawane pytania",
"from": "Z",
"frozen": "Zamrożone",
"frozen_balance": "Mrożona równowaga",
"full_balance": "Pełne saldo",
"gas_exceeds_allowance": "Gaz wymagany przez transakcję przekracza dodatek.",
"gas_price": "Cena gazu",
"generate_name": "Wygeneruj nazwę",
"generating_gift_card": "Generowanie karty podarunkowej",
"generating_transaction": "Generowanie transakcji",
@ -440,6 +456,8 @@
"memo": "Notatka:",
"message": "Wiadomość",
"message_verified": "Wiadomość została pomyślnie zweryfikowana",
"messages": "Wiadomości",
"method": "Metoda",
"methods": "Metody",
"min_amount": "Min: ${value}",
"min_value": "Min: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "Ciemny motyw Monero",
"monero_light_theme": "Lekki motyw Monero",
"moonpay_alert_text": "Wartość kwoty musi być większa lub równa ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "Wystąpił błąd podczas pobierania NFT. Uprzejmie sprawdź swoje połączenie internetowe i spróbuj ponownie.",
"more_options": "Więcej opcji",
"multiple_addresses_detected": "Wykryto wiele adresów",
"mweb_confirmed": "Potwierdzone MWEB",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "Etykieta nazwy adresu",
"new_subaddress_title": "Nowy adres",
"new_template": "Nowy szablon",
"new_transactions_notifications": "Wyślij powiadomienia o nowych transakcjach",
"new_wallet": "Nowy portfel",
"newConnection": "Nowe połączenie",
"no_cards_found": "Nie znaleziono żadnych kart",
@ -492,6 +512,7 @@
"normal": "Normalna",
"note_optional": "Notatka (opcjonalnie)",
"note_tap_to_change": "Notatka (dotknij, aby zmienić)",
"notification_permission_denied": "Zezwolenie na powiadomienie zostało odrzucone, prosimy ręcznie włączyć go w ustawieniach",
"nullURIError": "URI ma wartość zerową",
"offer_expires_in": "Oferta wygasa za ",
"offline": "Offline",
@ -589,6 +610,7 @@
"rep_warning_sub": "Twój przedstawiciel nie wydaje się mieć dobrej opinii. Stuknij tutaj, aby wybrać nowy",
"repeat_wallet_password": "Powtórz hasło portfela",
"repeated_password_is_incorrect": "Powtarzane hasło jest nieprawidłowe. Powtórz ponownie hasło portfela.",
"requested": "Wymagany",
"require_for_adding_contacts": "Wymagane do dodania kontaktów",
"require_for_all_security_and_backup_settings": "Wymagaj dla wszystkich ustawień zabezpieczeń i kopii zapasowych",
"require_for_assessing_wallet": "Wymagaj dostępu do portfela",
@ -650,6 +672,8 @@
"second_intro_content": "Twój Yat to jeden unikalny adres emoji, który zastępuje wszystkie Twoje długie adresy szesnastkowe dla wszystkich Twoich walut.",
"second_intro_title": "Jeden adres emoji, aby zarzadzać wszystkimi walutami",
"security_and_backup": "Bezpieczeństwo i kopia zapasowa",
"security_risk": "Ryzyko bezpieczeństwa",
"security_risk_description": "Ta domena jest oznaczona jako niebezpieczna przez wielu dostawców bezpieczeństwa. Odejdź natychmiast, aby chronić swoje aktywa.",
"seed_alert_back": "Wróć",
"seed_alert_content": "Fraza Seed to jedyny sposób na odzyskanie portfela. Zapisałeś ją?",
"seed_alert_title": "Uwaga",
@ -764,7 +788,9 @@
"show_keys": "Pokaż seed/klucze",
"show_market_place": "Pokaż rynek",
"show_seed": "Pokaż frazę seed",
"sign_all": "Podpisz wszystkie",
"sign_message": "Podpisuj wiadomość",
"sign_one": "Podpisz jeden",
"sign_up": "Zarejestruj się",
"sign_verify_message": "Podpisz lub zweryfikuj wiadomość",
"sign_verify_message_sub": "Podpisz lub zweryfikuj wiadomość za pomocą klucza prywatnego",
@ -798,6 +824,7 @@
"subaddress_title": "Lista podadresów",
"subaddresses": "Podadresy",
"submit_request": "Złóż wniosek",
"success": "Sukces",
"successful": "Udany",
"support_description_guides": "Dokumentacja i wsparcie dla typowych problemów",
"support_description_live_chat": "Darmowe i szybkie! Do pomocy są dostępni przeszkoleni przedstawiciele wsparcia",
@ -805,6 +832,7 @@
"support_title_guides": "Dokumenty Cake Wallet",
"support_title_live_chat": "Wsparcie na żywo",
"support_title_other_links": "Inne linki wsparcia",
"supported": "Utrzymany",
"swap": "Wymiana",
"sweeping_wallet": "Zamiatanie portfela",
"sweeping_wallet_alert": "To nie powinno zająć dużo czasu. NIE WYCHODŹ Z TEGO EKRANU, W PRZECIWNYM WYPADKU MOŻE ZOSTAĆ UTRACONA ŚRODKI",
@ -837,6 +865,7 @@
"thorchain_taproot_address_not_supported": "Dostawca Thorchain nie obsługuje adresów TAPROOT. Zmień adres lub wybierz innego dostawcę.",
"time": "${minutes}m ${seconds}s",
"tip": "tip:",
"to": "Do",
"today": "Dzisiaj",
"token_contract_address": "Adres kontraktu tokena",
"token_decimal": "Token dziesiętny",
@ -904,6 +933,7 @@
"transaction_sent_notice": "Jeśli ekran nie zmieni się po 1 minucie, sprawdź eksplorator bloków i swój e-mail.",
"transactions": "Transakcje",
"transactions_by_date": "Transakcje według daty",
"transport_type": "Typ transportu",
"trongrid_history": "Historia Trongrida",
"trusted": "Zaufany",
"tx_commit_exception_no_dust_on_change": "Transakcja została odrzucana z tą kwotą. Za pomocą tych monet możesz wysłać ${min} bez reszty lub ${max}, które zwrócą resztę.",
@ -932,6 +962,7 @@
"unspent_coins_details_title": "Szczegóły niewydanych monet",
"unspent_coins_title": "Niewydane monety",
"unsupported_asset": "Nie obsługujemy tego działania w przypadku tego zasobu. Utwórz lub przełącz się na portfel obsługiwanego typu aktywów.",
"update_session": "Aktualizacja sesji",
"uptime": "Czas online",
"upto": "do ${value}",
"usb": "USB",
@ -941,6 +972,7 @@
"use_ssl": "Użyj SSL",
"use_suggested": "Użyj sugerowane",
"use_testnet": "Użyj testne",
"user_rejected_method": "Metoda odrzucona użytkownika",
"value": "Wartość",
"value_type": "Typ wartości",
"variable_pair_not_supported": "Ta para zmiennych nie jest obsługiwana na wybranych giełdach",
@ -1024,5 +1056,6 @@
"you_will_get": "Konwertuj na",
"you_will_receive_estimated_amount": "Otrzymasz(oszacowane )",
"you_will_send": "Konwertuj z",
"youCanGoBackToYourDapp": "Możesz teraz wrócić do swojego dapp",
"yy": "RR"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "Gere ${type}. O destinatário pode ${method} com qualquer criptomoeda suportada e você receberá fundos nesta carteira.",
"apk_update": "Atualização de APK",
"approve": "Aprovar",
"approve_request": "Aprovar solicitação",
"arrive_in_this_address": "${currency} ${tag}chegará neste endereço",
"ascending": "Ascendente",
"ask_each_time": "Pergunte cada vez",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "Aguardando confirmação de pagamento",
"background_sync": "Sincronização de fundo",
"background_sync_mode": "Modo de sincronização em segundo plano",
"background_sync_on_battery_low": "Sincronizar com bateria baixa",
"background_sync_on_charging": "Sincronize apenas ao carregar",
"background_sync_on_device_idle": "Sincronize apenas quando o dispositivo não está sendo usado",
"background_sync_on_unmetered_network": "Requer rede não meta",
"backup": "Cópia de segurança",
"backup_file": "Arquivo de backup",
"backup_password": "Senha de backup",
@ -116,9 +121,12 @@
"camera_consent": "Sua câmera será usada para capturar uma imagem para fins de identificação por ${provider}. Por favor, verifique a Política de Privacidade para obter detalhes.",
"camera_permission_is_required": "É necessária permissão da câmera.\nAtive-o nas configurações do aplicativo.",
"cancel": "Cancelar",
"cannot_verify": "Não pode verificar",
"cannot_verify_description": "Este domínio não pode ser verificado. Verifique a solicitação com cuidado antes de aprovar.",
"card_address": "Endereço:",
"cardholder_agreement": "Acordo do titular do cartão",
"cards": "Cartões",
"chain_id": "ID da cadeia",
"chains": "Correntes",
"change": "Mudar",
"change_backup_password_alert": "Seus arquivos de backup anteriores não estarão disponíveis para importação com a nova senha de backup. A nova senha de backup será usada apenas para novos arquivos de backup. Tem certeza que deseja alterar a senha de backup?",
@ -174,6 +182,7 @@
"connect_yats": "Connect Yats",
"connect_your_hardware_wallet": "Conecte sua carteira de hardware usando Bluetooth ou USB",
"connect_your_hardware_wallet_ios": "Conecte sua carteira de hardware usando o Bluetooth",
"connected": "Conectado",
"connection_sync": "Conexão e sincronização",
"connectWalletPrompt": "Conecte sua carteira ao WalletConnect para fazer transações",
"contact": "Contato",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "Desative a otimização da bateria",
"disableBatteryOptimizationDescription": "Deseja desativar a otimização da bateria para fazer a sincronização de fundo funcionar de forma mais livre e suave?",
"disabled": "Desabilitado",
"disconnect_session": "Desconecte a sessão",
"discount": "Economize ${value}%",
"display_settings": "Configurações de exibição",
"displayable": "Exibível",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "Não os compartilhe com mais ninguém, incluindo suporte.\n\nSeus fundos podem e serão roubados!",
"do_not_show_me": "não me mostre isso novamente",
"domain_looks_up": "Pesquisas de domínio",
"domain_mismatch": "Incompatibilidade de domínio",
"domain_mismatch_description": "Este site possui um domínio que não corresponde ao remetente desta solicitação. A aprovação pode levar à perda de fundos.",
"donation_link_details": "Detalhes do link de doação",
"e_sign_consent": "Consentimento de assinatura eletrônica",
"edit": "Editar",
@ -298,6 +310,7 @@
"error_text_template": "O nome e o endereço do modelo não podem conter os símbolos ` , ' \" \ne deve ter entre 1 e 106 caracteres",
"error_text_wallet_name": "O nome da carteira só pode conter letras, números, _ - símbolos\ne deve ter entre 1 e 33 caracteres",
"error_text_xmr": "A quantia em XMR não pode exceder o saldo disponível.\nTO número de dígitos decimais deve ser menor ou igual a 12",
"error_while_processing": "Ocorreu um erro ao procurar",
"errorGettingCredentials": "Falha: Erro ao obter credenciais",
"errorSigningTransaction": "Ocorreu um erro ao assinar a transação",
"estimated": "Estimado",
@ -323,6 +336,7 @@
"export_backup": "Backup de exportação",
"export_logs": "Exportar logs",
"export_outputs": "Saídas de exportação",
"extend_session": "Estender sessão",
"extra_id": "ID extra:",
"extracted_address_content": "Você enviará fundos para\n${recipient_name}",
"failed_authentication": "Falha na autenticação. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "Esqueci a senha",
"freeze": "Congelar",
"frequently_asked_questions": "Perguntas frequentes",
"from": "De",
"frozen": "Congeladas",
"frozen_balance": "Equilíbrio congelado",
"full_balance": "Saldo total",
"gas_exceeds_allowance": "O gás exigido pela transação excede o subsídio.",
"gas_price": "Preço do gás",
"generate_name": "Gerar nome",
"generating_gift_card": "Gerando Cartão Presente",
"generating_transaction": "Gerando transação",
@ -441,6 +457,8 @@
"memo": "Memorando:",
"message": "Mensagem",
"message_verified": "A mensagem foi verificada com sucesso",
"messages": "Mensagens",
"method": "Método",
"methods": "Métodos",
"min_amount": "Mínimo: ${valor}",
"min_value": "Mín: ${value} ${currency}",
@ -453,6 +471,7 @@
"monero_dark_theme": "Monero Tema Escuro",
"monero_light_theme": "Monero Light Theme",
"moonpay_alert_text": "O valor do montante deve ser maior ou igual a ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "Ocorreu um erro ao buscar NFTs. Por favor, verifique sua conexão com a Internet e tente novamente.",
"more_options": "Mais opções",
"multiple_addresses_detected": "Vários endereços detectados",
"mweb_confirmed": "MWEB confirmado",
@ -469,6 +488,7 @@
"new_subaddress_label_name": "Nome",
"new_subaddress_title": "Novo endereço",
"new_template": "Novo modelo",
"new_transactions_notifications": "Envie notificações sobre novas transações",
"new_wallet": "Nova carteira",
"newConnection": "Nova conexão",
"no_cards_found": "Nenhum cartão encontrado",
@ -493,6 +513,7 @@
"normal": "Normal",
"note_optional": "Nota (opcional)",
"note_tap_to_change": "Nota (toque para alterar)",
"notification_permission_denied": "A permissão de notificação foi negada com permamer, por favor, ativá -la manualmente em configurações",
"nullURIError": "URI é nulo",
"offer_expires_in": "A oferta expira em: ",
"offline": "offline",
@ -591,6 +612,7 @@
"rep_warning_sub": "Seu representante não parece estar em boa posição. Toque aqui para selecionar um novo",
"repeat_wallet_password": "Repita a senha da carteira",
"repeated_password_is_incorrect": "A senha repetida está incorreta. Repita a senha da carteira novamente.",
"requested": "Solicitado",
"require_for_adding_contacts": "Requer para adicionar contatos",
"require_for_all_security_and_backup_settings": "Exigir todas as configurações de segurança e backup",
"require_for_assessing_wallet": "Requer para acessar a carteira",
@ -652,6 +674,8 @@
"second_intro_content": "Seu Yat é um endereço de emoji único e exclusivo que substitui todos os seus endereços hexadecimais longos para todas as suas moedas.",
"second_intro_title": "Um endereço de emoji para governar todos eles",
"security_and_backup": "Segurança e backup",
"security_risk": "Risco de segurança",
"security_risk_description": "Esse domínio é sinalizado como inseguro por vários provedores de segurança. Saia imediatamente para proteger seus ativos.",
"seed_alert_back": "Volte",
"seed_alert_content": "A semente é a única forma de recuperar sua carteira. Você escreveu isso?",
"seed_alert_title": "Atenção",
@ -766,7 +790,9 @@
"show_keys": "Mostrar semente/chaves",
"show_market_place": "Mostrar mercado",
"show_seed": "Mostrar semente",
"sign_all": "Assine tudo",
"sign_message": "Mensagem de assinar",
"sign_one": "Assine um",
"sign_up": "Inscrever-se",
"sign_verify_message": "Assinar ou verificar mensagem",
"sign_verify_message_sub": "Assine ou verifique uma mensagem usando sua chave privada",
@ -800,6 +826,7 @@
"subaddress_title": "Sub-endereços",
"subaddresses": "Sub-endereços",
"submit_request": "enviar um pedido",
"success": "Sucesso",
"successful": "Bem-sucedido",
"support_description_guides": "Documentação e suporte para problemas comuns",
"support_description_live_chat": "Livre e rápido! Representantes de suporte treinado estão disponíveis para ajudar",
@ -807,6 +834,7 @@
"support_title_guides": "Documentos da carteira de bolo",
"support_title_live_chat": "Apoio ao vivo",
"support_title_other_links": "Outros links de suporte",
"supported": "Suportado",
"swap": "Trocar",
"sweeping_wallet": "Carteira varrendo",
"sweeping_wallet_alert": "To nie powinno zająć dużo czasu. NIE WYCHODŹ Z TEGO EKRANU, W PRZECIWNYM WYPADKU MOŻE ZOSTAĆ UTRACONA ŚRODKI",
@ -839,6 +867,7 @@
"thorchain_taproot_address_not_supported": "O provedor de Thorchain não suporta endereços de raiz de Tap. Altere o endereço ou selecione um provedor diferente.",
"time": "${minutes}m ${seconds}s",
"tip": "Dica:",
"to": "Para",
"today": "Hoje",
"token_contract_address": "Endereço do contrato de token",
"token_decimal": "Token decimal",
@ -906,6 +935,7 @@
"transaction_sent_notice": "Se a tela não prosseguir após 1 minuto, verifique um explorador de blocos e seu e-mail.",
"transactions": "Transações",
"transactions_by_date": "Transações por data",
"transport_type": "Tipo de transporte",
"trongrid_history": "História de Trongrid",
"trusted": "confiável",
"tx_commit_exception_no_dust_on_change": "A transação é rejeitada com esse valor. Com essas moedas, você pode enviar ${min} sem alteração ou ${max} que retorna alterações.",
@ -934,6 +964,7 @@
"unspent_coins_details_title": "Detalhes de moedas não gastas",
"unspent_coins_title": "Moedas não gastas",
"unsupported_asset": "Não oferecemos suporte a esta ação para este recurso. Crie ou mude para uma carteira de um tipo de ativo compatível.",
"update_session": "Sessão de atualização",
"uptime": "Tempo de atividade",
"upto": "até ${value}",
"usb": "USB",
@ -943,6 +974,7 @@
"use_ssl": "Use SSL",
"use_suggested": "Uso sugerido",
"use_testnet": "Use testNet",
"user_rejected_method": "Método rejeitado pelo usuário",
"value": "Valor",
"value_type": "Tipo de valor",
"variable_pair_not_supported": "Este par de variáveis não é compatível com as trocas selecionadas",
@ -1027,5 +1059,6 @@
"you_will_get": "Converter para",
"you_will_receive_estimated_amount": "Você receberá(estimado )",
"you_will_send": "Converter de",
"youCanGoBackToYourDapp": "Você pode voltar para o seu dapp agora",
"yy": "aa"
}

View file

@ -53,6 +53,7 @@
"anonpay_description": "Создайте ${type}. Получатель может использовать ${method} с любой поддерживаемой криптовалютой, и вы получите средства на этот кошелек.",
"apk_update": "Обновление APK",
"approve": "Утвердить",
"approve_request": "Утвердить запрос",
"arrive_in_this_address": "${currency} ${tag}придет на этот адрес",
"ascending": "Восходящий",
"ask_each_time": "Спросите каждый раз",
@ -72,6 +73,10 @@
"awaiting_payment_confirmation": "Ожидается подтверждения платежа",
"background_sync": "Фоновая синхронизация",
"background_sync_mode": "Режим фоновой синхронизации",
"background_sync_on_battery_low": "Синхронизировать на низкой батареи",
"background_sync_on_charging": "Синхронизировать только при зарядке",
"background_sync_on_device_idle": "Синхронизировать только тогда, когда устройство не используется",
"background_sync_on_unmetered_network": "Требуется незамеченная сеть",
"backup": "Резервная копия",
"backup_file": "Файл резервной копии",
"backup_password": "Пароль резервной копии",
@ -116,9 +121,12 @@
"camera_consent": "Ваша камера будет использоваться для захвата изображения в целях идентификации ${provider}. Пожалуйста, ознакомьтесь с их Политикой конфиденциальности для получения подробной информации.",
"camera_permission_is_required": "Требуется разрешение камеры.\nПожалуйста, включите его в настройках приложения.",
"cancel": "Отменить",
"cannot_verify": "Не может проверить",
"cannot_verify_description": "Этот домен не может быть проверен. Тщательно проверьте запрос, прежде чем утверждать.",
"card_address": "Адрес:",
"cardholder_agreement": "Соглашение с держателем карты",
"cards": "Карты",
"chain_id": "Цепочка",
"chains": "Цепи",
"change": "Изменить",
"change_backup_password_alert": "Ваши предыдущие файлы резервных копий будут недоступны для импорта с новым паролем резервной копии. Новый пароль резервной копии будет использоваться только для новых файлов резервных копий. Вы уверены, что хотите изменить пароль резервной копии?",
@ -174,6 +182,7 @@
"connect_yats": "Подключить Yats",
"connect_your_hardware_wallet": "Подключите свой аппаратный кошелек с помощью Bluetooth или USB",
"connect_your_hardware_wallet_ios": "Подключите свой аппаратный кошелек с помощью Bluetooth",
"connected": "Подключенный",
"connection_sync": "Подключение и синхронизация",
"connectWalletPrompt": "Подключите свой кошелек к WalletConnect для совершения транзакций.",
"contact": "Контакт",
@ -244,6 +253,7 @@
"disableBatteryOptimization": "Отключить оптимизацию батареи",
"disableBatteryOptimizationDescription": "Вы хотите отключить оптимизацию батареи, чтобы сделать фона синхронизации более свободно и плавно?",
"disabled": "Отключено",
"disconnect_session": "Отключить сеанс",
"discount": "Сэкономьте ${value}%",
"display_settings": "Настройки отображения",
"displayable": "Отображаемый",
@ -252,6 +262,8 @@
"do_not_share_warning_text": "Не сообщайте их никому, включая техподдержку.\n\nВаши средства могут и будут украдены!",
"do_not_show_me": "Не показывай мне это больше",
"domain_looks_up": "Поиск доменов",
"domain_mismatch": "Несоответствие домена",
"domain_mismatch_description": "Этот веб -сайт имеет домен, который не соответствует отправителю этого запроса. Утверждение может привести к потере средств.",
"donation_link_details": "Информация о ссылке для пожертвований",
"e_sign_consent": "Согласие электронной подписи",
"edit": "Редактировать",
@ -298,6 +310,7 @@
"error_text_template": "Имя и адрес шаблона не может содержать ` , ' \" символы\nи должно быть от 1 до 106 символов в длину",
"error_text_wallet_name": "Имя кошелька может содержать только буквы, цифры, _ - символы\nи должно быть от 1 до 33 символов в длину",
"error_text_xmr": "Значение XMR не может превышать доступный баланс.\nКоличество цифр после запятой должно быть меньше или равно 12",
"error_while_processing": "Произошла ошибка во время выплаты",
"errorGettingCredentials": "Не удалось: ошибка при получении учетных данных.",
"errorSigningTransaction": "Произошла ошибка при подписании транзакции",
"estimated": "Примерно",
@ -323,6 +336,7 @@
"export_backup": "Экспорт резервной копии",
"export_logs": "Экспортные журналы",
"export_outputs": "Экспортные выходы",
"extend_session": "Продлить сессию",
"extra_id": "Дополнительный ID:",
"extracted_address_content": "Вы будете отправлять средства\n${recipient_name}",
"failed_authentication": "Ошибка аутентификации. ${state_error}",
@ -344,10 +358,12 @@
"forgot_password": "Забыли пароль",
"freeze": "Заморозить",
"frequently_asked_questions": "Часто задаваемые вопросы",
"from": "От",
"frozen": "Заморожено",
"frozen_balance": "Замороженный баланс",
"full_balance": "Весь баланс",
"gas_exceeds_allowance": "Газ, требуемый в результате транзакции, превышает пособие.",
"gas_price": "Цена газа",
"generate_name": "Создать имя",
"generating_gift_card": "Создание подарочной карты",
"generating_transaction": "Генерирующая транзакция",
@ -440,6 +456,8 @@
"memo": "Памятка:",
"message": "Сообщение",
"message_verified": "Сообщение было успешно проверено",
"messages": "Сообщения",
"method": "Метод",
"methods": "Методы",
"min_amount": "Минимум: ${value}",
"min_value": "Мин: ${value} ${currency}",
@ -452,6 +470,7 @@
"monero_dark_theme": "Темная тема Monero",
"monero_light_theme": "Светлая тема Monero",
"moonpay_alert_text": "Сумма должна быть больше или равна ${minAmount} ${fiatCurrency}",
"moralis_nft_error": "Произошла ошибка при получении NFT. Пожалуйста, проверьте подключение к Интернету и попробуйте еще раз.",
"more_options": "Дополнительные параметры",
"multiple_addresses_detected": "Обнаружено несколько адресов",
"mweb_confirmed": "Подтверждено MWEB",
@ -468,6 +487,7 @@
"new_subaddress_label_name": "Имя",
"new_subaddress_title": "Новый адрес",
"new_template": "Новый шаблон",
"new_transactions_notifications": "Отправить уведомления о новых транзакциях",
"new_wallet": "Новый кошелёк",
"newConnection": "Новое соединение",
"no_cards_found": "Карт не найдено",
@ -492,6 +512,7 @@
"normal": "Нормальный",
"note_optional": "Примечание (необязательно)",
"note_tap_to_change": "Примечание (нажмите для изменения)",
"notification_permission_denied": "Разрешение уведомления было отклонено, пожалуйста, вручную включить его в настройках",
"nullURIError": "URI имеет значение null",
"offer_expires_in": "Предложение истекает через: ",
"offline": "Не в сети",
@ -590,6 +611,7 @@
"rep_warning_sub": "Ваш представитель, похоже, не в хорошей репутации. Нажмите здесь, чтобы выбрать новый",
"repeat_wallet_password": "Повторите пароль кошелька",
"repeated_password_is_incorrect": "Повторный пароль неверен. Пожалуйста, повторите пароль кошелька снова.",
"requested": "Запрошен",
"require_for_adding_contacts": "Требовать добавления контактов",
"require_for_all_security_and_backup_settings": "Требовать все настройки безопасности и резервного копирования",
"require_for_assessing_wallet": "Требовать для доступа к кошельку",
@ -651,6 +673,8 @@
"second_intro_content": "Ваш Yat - это единственный уникальный адрес эмодзи, который заменяет длинные шестнадцатеричные адреса для всех ваших валют.",
"second_intro_title": "Один адрес эмодзи для управления остальными адресами",
"security_and_backup": "Безопасность и резервное копирование",
"security_risk": "Риск безопасности",
"security_risk_description": "Этот домен помечен как небезопасен несколькими поставщиками безопасности. Оставьте немедленно, чтобы защитить ваши активы.",
"seed_alert_back": "Назад",
"seed_alert_content": "Мнемоническая фраза - единственный способ восстановить ваш кошелек. Вы записали ее?",
"seed_alert_title": "Внимание",
@ -765,7 +789,9 @@
"show_keys": "Показать мнемоническую фразу/ключи",
"show_market_place": "Показать торговую площадку",
"show_seed": "Показать мнемоническую фразу",
"sign_all": "Подписать все",
"sign_message": "Сообщение о знаке",
"sign_one": "Подписать один",
"sign_up": "Зарегистрироваться",
"sign_verify_message": "Подписать или проверить сообщение",
"sign_verify_message_sub": "Подписать или проверить сообщение, используя свой закрытый ключ",
@ -799,6 +825,7 @@
"subaddress_title": "Список субадресов",
"subaddresses": "Субадреса",
"submit_request": "отправить запрос",
"success": "Успех",
"successful": "Успешный",
"support_description_guides": "Документация и поддержка общих вопросов",
"support_description_live_chat": "Бесплатно и быстро! Обученные представители поддержки доступны для оказания помощи",
@ -806,6 +833,7 @@
"support_title_guides": "Корт кошелек документов",
"support_title_live_chat": "Живая поддержка",
"support_title_other_links": "Другие ссылки на поддержку",
"supported": "Поддерживается",
"swap": "Менять",
"sweeping_wallet": "Подметание кошелька",
"sweeping_wallet_alert": "Это не должно занять много времени. НЕ ПОКИДАЙТЕ ЭТОТ ЭКРАН, ИНАЧЕ ВЫЧИСЛЕННЫЕ СРЕДСТВА МОГУТ БЫТЬ ПОТЕРЯНЫ",
@ -838,6 +866,7 @@
"thorchain_taproot_address_not_supported": "Поставщик Thorchain не поддерживает адреса taproot. Пожалуйста, измените адрес или выберите другого поставщика.",
"time": "${minutes}мин ${seconds}сек",
"tip": "Совет:",
"to": "К",
"today": "Сегодня",
"token_contract_address": "Адрес контракта токена",
"token_decimal": "Десятичный токен",
@ -905,6 +934,7 @@
"transaction_sent_notice": "Если экран не отображается через 1 минуту, проверьте обозреватель блоков и свою электронную почту.",
"transactions": "Транзакции",
"transactions_by_date": "Сортировать по дате",
"transport_type": "Транспортный тип",
"trongrid_history": "История Тронгрида",
"trusted": "доверенный",
"tx_commit_exception_no_dust_on_change": "Транзакция отклоняется с этой суммой. С этими монетами вы можете отправлять ${min} без изменения или ${max}, которые возвращают изменение.",
@ -933,6 +963,7 @@
"unspent_coins_details_title": "Сведения о неизрасходованных монетах",
"unspent_coins_title": "Неизрасходованные монеты",
"unsupported_asset": "Мы не поддерживаем это действие для этого объекта. Пожалуйста, создайте или переключитесь на кошелек поддерживаемого типа активов.",
"update_session": "Обновление сессии",
"uptime": "Время безотказной работы",
"upto": "до ${value}",
"usb": "USB",
@ -942,6 +973,7 @@
"use_ssl": "Использовать SSL",
"use_suggested": "Использовать предложенный",
"use_testnet": "Используйте Testnet",
"user_rejected_method": "Пользователь отклонил метод",
"value": "Ценить",
"value_type": "Тип значения",
"variable_pair_not_supported": "Эта пара переменных не поддерживается выбранными биржами.",
@ -1025,5 +1057,6 @@
"you_will_get": "Конвертировать в",
"you_will_receive_estimated_amount": "Вы получите(Оценку )",
"you_will_send": "Конвертировать из",
"youCanGoBackToYourDapp": "Вы можете вернуться к своему даппу сейчас",
"yy": "ГГ"
}

Some files were not shown because too many files have changed in this diff Show more