mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-19 01:04:43 +00:00
Merge branch 'mweb' of https://github.com/cake-tech/cake_wallet into mweb-bg-sync-2
This commit is contained in:
commit
e51d6ea8c0
39 changed files with 452 additions and 104 deletions
|
@ -7,7 +7,14 @@ class ElectrumBalance extends Balance {
|
|||
required this.confirmed,
|
||||
required this.unconfirmed,
|
||||
required this.frozen,
|
||||
}) : super(confirmed, unconfirmed);
|
||||
this.secondConfirmed = 0,
|
||||
this.secondUnconfirmed = 0,
|
||||
}) : super(
|
||||
confirmed,
|
||||
unconfirmed,
|
||||
secondAvailable: secondConfirmed,
|
||||
secondAdditional: secondUnconfirmed,
|
||||
);
|
||||
|
||||
static ElectrumBalance? fromJSON(String? jsonSource) {
|
||||
if (jsonSource == null) {
|
||||
|
@ -25,6 +32,8 @@ class ElectrumBalance extends Balance {
|
|||
int confirmed;
|
||||
int unconfirmed;
|
||||
final int frozen;
|
||||
int secondConfirmed = 0;
|
||||
int secondUnconfirmed = 0;
|
||||
|
||||
@override
|
||||
String get formattedAvailableBalance => bitcoinAmountToString(amount: confirmed - frozen);
|
||||
|
@ -38,6 +47,22 @@ class ElectrumBalance extends Balance {
|
|||
return frozenFormatted == '0.0' ? '' : frozenFormatted;
|
||||
}
|
||||
|
||||
String toJSON() =>
|
||||
json.encode({'confirmed': confirmed, 'unconfirmed': unconfirmed, 'frozen': frozen});
|
||||
@override
|
||||
String get formattedSecondAvailableBalance => bitcoinAmountToString(amount: secondConfirmed ?? 0);
|
||||
|
||||
@override
|
||||
String get formattedSecondAdditionalBalance =>
|
||||
bitcoinAmountToString(amount: secondUnconfirmed ?? 0);
|
||||
|
||||
@override
|
||||
String get formattedFullAvailableBalance =>
|
||||
bitcoinAmountToString(amount: confirmed + (secondConfirmed ?? 0) - frozen);
|
||||
|
||||
String toJSON() => json.encode({
|
||||
'confirmed': confirmed,
|
||||
'unconfirmed': unconfirmed,
|
||||
'frozen': frozen,
|
||||
'secondConfirmed': secondConfirmed,
|
||||
'secondUnconfirmed': secondUnconfirmed
|
||||
});
|
||||
}
|
||||
|
|
|
@ -884,7 +884,7 @@ abstract class ElectrumWalletBase
|
|||
|
||||
final totalAmount = amount + fee;
|
||||
|
||||
if (totalAmount > balance[currency]!.confirmed) {
|
||||
if (totalAmount > (balance[currency]!.confirmed + balance[currency]!.secondConfirmed)) {
|
||||
throw BitcoinTransactionWrongBalanceException();
|
||||
}
|
||||
|
||||
|
|
|
@ -244,9 +244,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
print("STARTING SYNC - MWEB ENABLED: $mwebEnabled");
|
||||
syncStatus = SyncronizingSyncStatus();
|
||||
await subscribeForUpdates();
|
||||
await updateTransactions();
|
||||
await updateFeeRates();
|
||||
|
||||
await updateFeeRates();
|
||||
_feeRatesTimer?.cancel();
|
||||
_feeRatesTimer =
|
||||
Timer.periodic(const Duration(minutes: 1), (timer) async => await updateFeeRates());
|
||||
|
@ -265,74 +264,70 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
}
|
||||
|
||||
await waitForMwebAddresses();
|
||||
|
||||
await getStub();
|
||||
await processMwebUtxos();
|
||||
await updateTransactions();
|
||||
await updateUnspent();
|
||||
await updateBalance();
|
||||
|
||||
_syncTimer?.cancel();
|
||||
// delay the timer by a second so we don't overrride the restoreheight if one is set
|
||||
Timer(const Duration(seconds: 2), () async {
|
||||
_syncTimer = Timer.periodic(const Duration(milliseconds: 1500), (timer) async {
|
||||
if (syncStatus is FailedSyncStatus) return;
|
||||
_syncTimer = Timer.periodic(const Duration(milliseconds: 1500), (timer) async {
|
||||
if (syncStatus is FailedSyncStatus) return;
|
||||
|
||||
final nodeHeight =
|
||||
await electrumClient.getCurrentBlockChainTip() ?? 0; // current block height of our node
|
||||
final resp = await _stub.status(StatusRequest());
|
||||
final nodeHeight =
|
||||
await electrumClient.getCurrentBlockChainTip() ?? 0; // current block height of our node
|
||||
final resp = await _stub.status(StatusRequest());
|
||||
|
||||
if (resp.blockHeaderHeight < nodeHeight) {
|
||||
int h = resp.blockHeaderHeight;
|
||||
syncStatus = SyncingSyncStatus(nodeHeight - h, h / nodeHeight);
|
||||
} else if (resp.mwebHeaderHeight < nodeHeight) {
|
||||
int h = resp.mwebHeaderHeight;
|
||||
syncStatus = SyncingSyncStatus(nodeHeight - h, h / nodeHeight);
|
||||
} else if (resp.mwebUtxosHeight < nodeHeight) {
|
||||
syncStatus = SyncingSyncStatus(1, 0.999);
|
||||
} else {
|
||||
// prevent unnecessary reaction triggers:
|
||||
if (syncStatus is! SyncedSyncStatus) {
|
||||
syncStatus = SyncedSyncStatus();
|
||||
}
|
||||
|
||||
if (resp.mwebUtxosHeight > walletInfo.restoreHeight) {
|
||||
await walletInfo.updateRestoreHeight(resp.mwebUtxosHeight);
|
||||
await checkMwebUtxosSpent();
|
||||
// update the confirmations for each transaction:
|
||||
for (final transaction in transactionHistory.transactions.values) {
|
||||
if (transaction.isPending) continue;
|
||||
int txHeight = transaction.height ?? resp.mwebUtxosHeight;
|
||||
final confirmations = (resp.mwebUtxosHeight - txHeight) + 1;
|
||||
if (transaction.confirmations == confirmations) continue;
|
||||
transaction.confirmations = confirmations;
|
||||
transactionHistory.addOne(transaction);
|
||||
}
|
||||
await transactionHistory.save();
|
||||
if (resp.blockHeaderHeight < nodeHeight) {
|
||||
int h = resp.blockHeaderHeight;
|
||||
syncStatus = SyncingSyncStatus(nodeHeight - h, h / nodeHeight);
|
||||
} else if (resp.mwebHeaderHeight < nodeHeight) {
|
||||
int h = resp.mwebHeaderHeight;
|
||||
syncStatus = SyncingSyncStatus(nodeHeight - h, h / nodeHeight);
|
||||
} else if (resp.mwebUtxosHeight < nodeHeight) {
|
||||
syncStatus = SyncingSyncStatus(1, 0.999);
|
||||
} else {
|
||||
// prevent unnecessary reaction triggers:
|
||||
if (syncStatus is! SyncedSyncStatus) {
|
||||
syncStatus = SyncedSyncStatus();
|
||||
}
|
||||
|
||||
if (resp.mwebUtxosHeight > walletInfo.restoreHeight) {
|
||||
await walletInfo.updateRestoreHeight(resp.mwebUtxosHeight);
|
||||
await checkMwebUtxosSpent();
|
||||
// update the confirmations for each transaction:
|
||||
for (final transaction in transactionHistory.transactions.values) {
|
||||
if (transaction.isPending) continue;
|
||||
int txHeight = transaction.height ?? resp.mwebUtxosHeight;
|
||||
final confirmations = (resp.mwebUtxosHeight - txHeight) + 1;
|
||||
if (transaction.confirmations == confirmations) continue;
|
||||
transaction.confirmations = confirmations;
|
||||
transactionHistory.addOne(transaction);
|
||||
}
|
||||
await transactionHistory.save();
|
||||
}
|
||||
});
|
||||
|
||||
// setup a watch dog to restart the sync process if it gets stuck:
|
||||
List<double> lastFewProgresses = [];
|
||||
Timer.periodic(const Duration(seconds: 10), (timer) async {
|
||||
if (syncStatus is! SyncingSyncStatus) return;
|
||||
if (syncStatus.progress() > 0.98) return;
|
||||
lastFewProgresses.add(syncStatus.progress());
|
||||
if (lastFewProgresses.length < 4) return;
|
||||
// limit list size to 4:
|
||||
while(lastFewProgresses.length > 4) {
|
||||
lastFewProgresses.removeAt(0);
|
||||
}
|
||||
// if the progress is the same over the last 40 seconds, restart the sync:
|
||||
if (lastFewProgresses.every((p) => p == lastFewProgresses.first)) {
|
||||
print("mweb syncing is stuck, restarting...");
|
||||
await stopSync();
|
||||
startSync();
|
||||
timer.cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// setup a watch dog to restart the sync process if it gets stuck:
|
||||
List<double> lastFewProgresses = [];
|
||||
Timer.periodic(const Duration(seconds: 10), (timer) async {
|
||||
if (syncStatus is! SyncingSyncStatus) return;
|
||||
if (syncStatus.progress() > 0.98) return;
|
||||
lastFewProgresses.add(syncStatus.progress());
|
||||
if (lastFewProgresses.length < 4) return;
|
||||
// limit list size to 4:
|
||||
while (lastFewProgresses.length > 4) {
|
||||
lastFewProgresses.removeAt(0);
|
||||
}
|
||||
// if the progress is the same over the last 40 seconds, restart the sync:
|
||||
if (lastFewProgresses.every((p) => p == lastFewProgresses.first)) {
|
||||
print("mweb syncing is stuck, restarting...");
|
||||
await stopSync();
|
||||
startSync();
|
||||
timer.cancel();
|
||||
}
|
||||
});
|
||||
// this runs in the background and processes new utxos as they come in:
|
||||
processMwebUtxos();
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -678,14 +673,19 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
|
||||
int confirmed = balance.confirmed;
|
||||
int unconfirmed = balance.unconfirmed;
|
||||
int confirmedMweb = 0;
|
||||
int unconfirmedMweb = 0;
|
||||
try {
|
||||
mwebUtxosBox.values.forEach((utxo) {
|
||||
if (utxo.height > 0) {
|
||||
confirmed += utxo.value.toInt();
|
||||
confirmedMweb += utxo.value.toInt();
|
||||
} else {
|
||||
unconfirmed += utxo.value.toInt();
|
||||
unconfirmedMweb += utxo.value.toInt();
|
||||
}
|
||||
});
|
||||
if (/*confirmedMweb > 0 &&*/ unconfirmedMweb > 0) {
|
||||
unconfirmedMweb = -1 * (confirmedMweb - unconfirmedMweb);
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
// update unspent balances:
|
||||
|
@ -735,7 +735,13 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
}
|
||||
}
|
||||
|
||||
return ElectrumBalance(confirmed: confirmed, unconfirmed: unconfirmed, frozen: balance.frozen);
|
||||
return ElectrumBalance(
|
||||
confirmed: confirmed,
|
||||
unconfirmed: unconfirmed,
|
||||
frozen: balance.frozen,
|
||||
secondConfirmed: confirmedMweb,
|
||||
secondUnconfirmed: unconfirmedMweb,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -869,7 +875,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
final addresses = <String>{};
|
||||
transaction.inputAddresses?.forEach((id) async {
|
||||
final utxo = mwebUtxosBox.get(id);
|
||||
await mwebUtxosBox.delete(id);
|
||||
// await mwebUtxosBox.delete(id);
|
||||
if (utxo == null) return;
|
||||
final addressRecord = walletAddresses.allAddresses
|
||||
.firstWhere((addressRecord) => addressRecord.address == utxo.address);
|
||||
|
|
|
@ -122,6 +122,10 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
Future<String> getChangeAddress({List<BitcoinOutput>? outputs, UtxoDetails? utxoDetails}) async {
|
||||
// use regular change address on peg in, otherwise use mweb for change address:
|
||||
|
||||
if (!mwebEnabled) {
|
||||
return super.getChangeAddress();
|
||||
}
|
||||
|
||||
if (outputs != null && utxoDetails != null) {
|
||||
// check if this is a PEGIN:
|
||||
bool outputsToMweb = false;
|
||||
|
@ -134,6 +138,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
outputsToMweb = true;
|
||||
}
|
||||
}
|
||||
// TODO: this doesn't respect coin control because it doesn't know which available inputs are selected
|
||||
utxoDetails.availableInputs.forEach((element) {
|
||||
if (element.address.contains("mweb")) {
|
||||
comesFromMweb = true;
|
||||
|
@ -144,6 +149,11 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
if (isPegIn && mwebEnabled) {
|
||||
return super.getChangeAddress();
|
||||
}
|
||||
|
||||
// use regular change address if it's not an mweb tx:
|
||||
if (!comesFromMweb && !outputsToMweb) {
|
||||
return super.getChangeAddress();
|
||||
}
|
||||
}
|
||||
|
||||
if (mwebEnabled) {
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
abstract class Balance {
|
||||
const Balance(this.available, this.additional);
|
||||
const Balance(this.available, this.additional, {this.secondAvailable, this.secondAdditional});
|
||||
|
||||
final int available;
|
||||
|
||||
final int additional;
|
||||
|
||||
final int? secondAvailable;
|
||||
final int? secondAdditional;
|
||||
|
||||
String get formattedAvailableBalance;
|
||||
|
||||
String get formattedAdditionalBalance;
|
||||
|
||||
String get formattedUnAvailableBalance => '';
|
||||
String get formattedSecondAvailableBalance => '';
|
||||
String get formattedSecondAdditionalBalance => '';
|
||||
String get formattedFullAvailableBalance => '';
|
||||
String get formattedFullUnAvailableBalance => '';
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ void restoreWalletFromKeysSync(
|
|||
int nettype = 0,
|
||||
int restoreHeight = 0}) {
|
||||
txhistory = null;
|
||||
final newWptr = spendKey != ""
|
||||
var newWptr = (spendKey != "")
|
||||
? monero.WalletManager_createDeterministicWalletFromSpendKey(
|
||||
wmPtr,
|
||||
path: path,
|
||||
|
@ -149,6 +149,32 @@ void restoreWalletFromKeysSync(
|
|||
message: monero.Wallet_errorString(newWptr));
|
||||
}
|
||||
|
||||
// CW-712 - Try to restore deterministic wallet first, if the view key doesn't
|
||||
// match the view key provided
|
||||
if (spendKey != "") {
|
||||
final viewKeyRestored = monero.Wallet_secretViewKey(newWptr);
|
||||
if (viewKey != viewKeyRestored && viewKey != "") {
|
||||
monero.WalletManager_closeWallet(wmPtr, newWptr, false);
|
||||
File(path).deleteSync();
|
||||
File(path+".keys").deleteSync();
|
||||
newWptr = monero.WalletManager_createWalletFromKeys(
|
||||
wmPtr,
|
||||
path: path,
|
||||
password: password,
|
||||
restoreHeight: restoreHeight,
|
||||
addressString: address,
|
||||
viewKeyString: viewKey,
|
||||
spendKeyString: spendKey,
|
||||
nettype: 0,
|
||||
);
|
||||
final status = monero.Wallet_status(newWptr);
|
||||
if (status != 0) {
|
||||
throw WalletRestoreFromKeysException(
|
||||
message: monero.Wallet_errorString(newWptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wptr = newWptr;
|
||||
|
||||
openedWalletsByPath[path] = wptr!;
|
||||
|
|
|
@ -140,7 +140,7 @@ void restoreWalletFromKeysSync(
|
|||
int nettype = 0,
|
||||
int restoreHeight = 0}) {
|
||||
txhistory = null;
|
||||
final newWptr = spendKey != ""
|
||||
var newWptr = (spendKey != "")
|
||||
? wownero.WalletManager_createDeterministicWalletFromSpendKey(
|
||||
wmPtr,
|
||||
path: path,
|
||||
|
@ -165,7 +165,31 @@ void restoreWalletFromKeysSync(
|
|||
throw WalletRestoreFromKeysException(
|
||||
message: wownero.Wallet_errorString(newWptr));
|
||||
}
|
||||
|
||||
// CW-712 - Try to restore deterministic wallet first, if the view key doesn't
|
||||
// match the view key provided
|
||||
if (spendKey != "") {
|
||||
final viewKeyRestored = wownero.Wallet_secretViewKey(newWptr);
|
||||
if (viewKey != viewKeyRestored && viewKey != "") {
|
||||
wownero.WalletManager_closeWallet(wmPtr, newWptr, false);
|
||||
File(path).deleteSync();
|
||||
File(path+".keys").deleteSync();
|
||||
newWptr = wownero.WalletManager_createWalletFromKeys(
|
||||
wmPtr,
|
||||
path: path,
|
||||
password: password,
|
||||
restoreHeight: restoreHeight,
|
||||
addressString: address,
|
||||
viewKeyString: viewKey,
|
||||
spendKeyString: spendKey,
|
||||
nettype: 0,
|
||||
);
|
||||
final status = wownero.Wallet_status(newWptr);
|
||||
if (status != 0) {
|
||||
throw WalletRestoreFromKeysException(
|
||||
message: wownero.Wallet_errorString(newWptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
wptr = newWptr;
|
||||
|
||||
openedWalletsByPath[path] = wptr!;
|
||||
|
|
|
@ -131,7 +131,7 @@ class CryptoBalanceWidget extends StatelessWidget {
|
|||
builder: (_) {
|
||||
if (dashboardViewModel.getMoneroError != null) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16,0,16,16),
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
title: "Invalid monero bindings",
|
||||
subTitle: dashboardViewModel.getMoneroError.toString(),
|
||||
|
@ -146,13 +146,12 @@ class CryptoBalanceWidget extends StatelessWidget {
|
|||
builder: (_) {
|
||||
if (dashboardViewModel.getWowneroError != null) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16,0,16,16),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
title: "Invalid wownero bindings",
|
||||
subTitle: dashboardViewModel.getWowneroError.toString(),
|
||||
onTap: () {},
|
||||
)
|
||||
);
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
title: "Invalid wownero bindings",
|
||||
subTitle: dashboardViewModel.getWowneroError.toString(),
|
||||
onTap: () {},
|
||||
));
|
||||
}
|
||||
return Container();
|
||||
},
|
||||
|
@ -273,6 +272,18 @@ class CryptoBalanceWidget extends StatelessWidget {
|
|||
currency: balance.asset,
|
||||
hasAdditionalBalance:
|
||||
dashboardViewModel.balanceViewModel.hasAdditionalBalance,
|
||||
hasSecondAdditionalBalance:
|
||||
dashboardViewModel.balanceViewModel.hasSecondAdditionalBalance,
|
||||
hasSecondAvailableBalance:
|
||||
dashboardViewModel.balanceViewModel.hasSecondAvailableBalance,
|
||||
secondAdditionalBalance: balance.secondAdditionalBalance,
|
||||
secondAdditionalFiatBalance: balance.fiatSecondAdditionalBalance,
|
||||
secondAvailableBalance: balance.secondAvailableBalance,
|
||||
secondAvailableFiatBalance: balance.fiatSecondAvailableBalance,
|
||||
secondAdditionalBalanceLabel:
|
||||
'${dashboardViewModel.balanceViewModel.secondAdditionalBalanceLabel}',
|
||||
secondAvailableBalanceLabel:
|
||||
'${dashboardViewModel.balanceViewModel.secondAvailableBalanceLabel}',
|
||||
isTestnet: dashboardViewModel.isTestnet,
|
||||
);
|
||||
});
|
||||
|
@ -286,16 +297,15 @@ class CryptoBalanceWidget extends StatelessWidget {
|
|||
if (dashboardViewModel.isMoneroWalletBrokenReasons.isNotEmpty) ...[
|
||||
SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
customBorder: 30,
|
||||
title: "This wallet has encountered an issue",
|
||||
subTitle: "Here are the things that you should note:\n - "
|
||||
+dashboardViewModel.isMoneroWalletBrokenReasons.join("\n - ")
|
||||
+"\n\nPlease restart your wallet and if it doesn't help contact our support.",
|
||||
onTap: () {},
|
||||
)
|
||||
)
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
customBorder: 30,
|
||||
title: "This wallet has encountered an issue",
|
||||
subTitle: "Here are the things that you should note:\n - " +
|
||||
dashboardViewModel.isMoneroWalletBrokenReasons.join("\n - ") +
|
||||
"\n\nPlease restart your wallet and if it doesn't help contact our support.",
|
||||
onTap: () {},
|
||||
))
|
||||
],
|
||||
if (dashboardViewModel.showSilentPaymentsCard) ...[
|
||||
SizedBox(height: 10),
|
||||
|
@ -494,10 +504,18 @@ class BalanceRowWidget extends StatelessWidget {
|
|||
required this.additionalBalanceLabel,
|
||||
required this.additionalBalance,
|
||||
required this.additionalFiatBalance,
|
||||
required this.secondAvailableBalanceLabel,
|
||||
required this.secondAvailableBalance,
|
||||
required this.secondAvailableFiatBalance,
|
||||
required this.secondAdditionalBalanceLabel,
|
||||
required this.secondAdditionalBalance,
|
||||
required this.secondAdditionalFiatBalance,
|
||||
required this.frozenBalance,
|
||||
required this.frozenFiatBalance,
|
||||
required this.currency,
|
||||
required this.hasAdditionalBalance,
|
||||
required this.hasSecondAvailableBalance,
|
||||
required this.hasSecondAdditionalBalance,
|
||||
required this.isTestnet,
|
||||
super.key,
|
||||
});
|
||||
|
@ -508,10 +526,18 @@ class BalanceRowWidget extends StatelessWidget {
|
|||
final String additionalBalanceLabel;
|
||||
final String additionalBalance;
|
||||
final String additionalFiatBalance;
|
||||
final String secondAvailableBalanceLabel;
|
||||
final String secondAvailableBalance;
|
||||
final String secondAvailableFiatBalance;
|
||||
final String secondAdditionalBalanceLabel;
|
||||
final String secondAdditionalBalance;
|
||||
final String secondAdditionalFiatBalance;
|
||||
final String frozenBalance;
|
||||
final String frozenFiatBalance;
|
||||
final CryptoCurrency currency;
|
||||
final bool hasAdditionalBalance;
|
||||
final bool hasSecondAvailableBalance;
|
||||
final bool hasSecondAdditionalBalance;
|
||||
final bool isTestnet;
|
||||
|
||||
// void _showBalanceDescription(BuildContext context) {
|
||||
|
@ -759,6 +785,94 @@ class BalanceRowWidget extends StatelessWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
if (hasSecondAvailableBalance)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 24),
|
||||
Text(
|
||||
'${secondAvailableBalanceLabel}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
AutoSizeText(
|
||||
secondAvailableBalance,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.assetTitleColor,
|
||||
height: 1,
|
||||
),
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
if (!isTestnet)
|
||||
Text(
|
||||
'${secondAvailableFiatBalance}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (hasSecondAdditionalBalance)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 24),
|
||||
Text(
|
||||
'${secondAdditionalBalanceLabel}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
AutoSizeText(
|
||||
secondAdditionalBalance,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.assetTitleColor,
|
||||
height: 1,
|
||||
),
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
if (!isTestnet)
|
||||
Text(
|
||||
'${secondAdditionalFiatBalance}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
@ -35,7 +38,7 @@ class AddressList extends StatelessWidget {
|
|||
separatorBuilder: (context, _) => const HorizontalSectionDivider(),
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: addressListViewModel.items.length,
|
||||
itemCount: min(addressListViewModel.items.length, 100),// TODO: don't show all 1000 mweb addresses
|
||||
itemBuilder: (context, index) {
|
||||
final item = addressListViewModel.items[index];
|
||||
Widget cell = Container();
|
||||
|
|
|
@ -21,10 +21,14 @@ class BalanceRecord {
|
|||
const BalanceRecord(
|
||||
{required this.availableBalance,
|
||||
required this.additionalBalance,
|
||||
required this.secondAvailableBalance,
|
||||
required this.secondAdditionalBalance,
|
||||
required this.frozenBalance,
|
||||
required this.fiatAvailableBalance,
|
||||
required this.fiatAdditionalBalance,
|
||||
required this.fiatFrozenBalance,
|
||||
required this.fiatSecondAvailableBalance,
|
||||
required this.fiatSecondAdditionalBalance,
|
||||
required this.asset,
|
||||
required this.formattedAssetTitle});
|
||||
final String fiatAdditionalBalance;
|
||||
|
@ -33,6 +37,10 @@ class BalanceRecord {
|
|||
final String additionalBalance;
|
||||
final String availableBalance;
|
||||
final String frozenBalance;
|
||||
final String secondAvailableBalance;
|
||||
final String secondAdditionalBalance;
|
||||
final String fiatSecondAdditionalBalance;
|
||||
final String fiatSecondAvailableBalance;
|
||||
final CryptoCurrency asset;
|
||||
final String formattedAssetTitle;
|
||||
}
|
||||
|
@ -158,6 +166,26 @@ abstract class BalanceViewModelBase with Store {
|
|||
}
|
||||
}
|
||||
|
||||
@computed
|
||||
String get secondAvailableBalanceLabel {
|
||||
switch (wallet.type) {
|
||||
case WalletType.litecoin:
|
||||
return S.current.mweb_confirmed;
|
||||
default:
|
||||
return S.current.confirmed;
|
||||
}
|
||||
}
|
||||
|
||||
@computed
|
||||
String get secondAdditionalBalanceLabel {
|
||||
switch (wallet.type) {
|
||||
case WalletType.litecoin:
|
||||
return S.current.mweb_unconfirmed;
|
||||
default:
|
||||
return S.current.unconfirmed;
|
||||
}
|
||||
}
|
||||
|
||||
@computed
|
||||
bool get hasMultiBalance => appStore.wallet!.type == WalletType.haven;
|
||||
|
||||
|
@ -207,6 +235,17 @@ abstract class BalanceViewModelBase with Store {
|
|||
return walletBalance.formattedAdditionalBalance;
|
||||
}
|
||||
|
||||
@computed
|
||||
String get secondAdditionalBalance {
|
||||
final walletBalance = _walletBalance;
|
||||
|
||||
if (displayMode == BalanceDisplayMode.hiddenBalance) {
|
||||
return '---';
|
||||
}
|
||||
|
||||
return walletBalance.formattedSecondAdditionalBalance;
|
||||
}
|
||||
|
||||
@computed
|
||||
String get availableFiatBalance {
|
||||
final walletBalance = _walletBalance;
|
||||
|
@ -243,9 +282,13 @@ abstract class BalanceViewModelBase with Store {
|
|||
availableBalance: '---',
|
||||
additionalBalance: '---',
|
||||
frozenBalance: '---',
|
||||
secondAvailableBalance: '---',
|
||||
secondAdditionalBalance: '---',
|
||||
fiatAdditionalBalance: isFiatDisabled ? '' : '---',
|
||||
fiatAvailableBalance: isFiatDisabled ? '' : '---',
|
||||
fiatFrozenBalance: isFiatDisabled ? '' : '---',
|
||||
fiatSecondAvailableBalance: isFiatDisabled ? '' : '---',
|
||||
fiatSecondAdditionalBalance: isFiatDisabled ? '' : '---',
|
||||
asset: key,
|
||||
formattedAssetTitle: _formatterAsset(key)));
|
||||
}
|
||||
|
@ -274,24 +317,46 @@ abstract class BalanceViewModelBase with Store {
|
|||
' ' +
|
||||
_getFiatBalance(price: price, cryptoAmount: getFormattedFrozenBalance(value)));
|
||||
|
||||
final secondAdditionalFiatBalance = isFiatDisabled
|
||||
? ''
|
||||
: (fiatCurrency.toString() +
|
||||
' ' +
|
||||
_getFiatBalance(price: price, cryptoAmount: value.formattedSecondAdditionalBalance));
|
||||
|
||||
final secondAvailableFiatBalance = isFiatDisabled
|
||||
? ''
|
||||
: (fiatCurrency.toString() +
|
||||
' ' +
|
||||
_getFiatBalance(price: price, cryptoAmount: value.formattedSecondAvailableBalance));
|
||||
|
||||
return MapEntry(
|
||||
key,
|
||||
BalanceRecord(
|
||||
availableBalance: value.formattedAvailableBalance,
|
||||
additionalBalance: value.formattedAdditionalBalance,
|
||||
frozenBalance: getFormattedFrozenBalance(value),
|
||||
secondAvailableBalance: value.formattedSecondAvailableBalance,
|
||||
secondAdditionalBalance: value.formattedSecondAdditionalBalance,
|
||||
fiatAdditionalBalance: additionalFiatBalance,
|
||||
fiatAvailableBalance: availableFiatBalance,
|
||||
fiatFrozenBalance: frozenFiatBalance,
|
||||
fiatSecondAvailableBalance: secondAvailableFiatBalance,
|
||||
fiatSecondAdditionalBalance: secondAdditionalFiatBalance,
|
||||
asset: key,
|
||||
formattedAssetTitle: _formatterAsset(key)));
|
||||
});
|
||||
}
|
||||
|
||||
@computed
|
||||
bool get hasAdditionalBalance => _hasAdditionBalanceForWalletType(wallet.type);
|
||||
bool get hasAdditionalBalance => _hasAdditionalBalanceForWalletType(wallet.type);
|
||||
|
||||
bool _hasAdditionBalanceForWalletType(WalletType type) {
|
||||
@computed
|
||||
bool get hasSecondAdditionalBalance => _hasSecondAdditionalBalanceForWalletType(wallet.type);
|
||||
|
||||
@computed
|
||||
bool get hasSecondAvailableBalance => _hasSecondAvailableBalanceForWalletType(wallet.type);
|
||||
|
||||
bool _hasAdditionalBalanceForWalletType(WalletType type) {
|
||||
switch (type) {
|
||||
case WalletType.ethereum:
|
||||
case WalletType.polygon:
|
||||
|
@ -303,6 +368,20 @@ abstract class BalanceViewModelBase with Store {
|
|||
}
|
||||
}
|
||||
|
||||
bool _hasSecondAdditionalBalanceForWalletType(WalletType type) {
|
||||
if (wallet.type == WalletType.litecoin /*&& settingsStore.mwebEnabled*/) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _hasSecondAvailableBalanceForWalletType(WalletType type) {
|
||||
if (wallet.type == WalletType.litecoin /*&& settingsStore.mwebEnabled*/) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@computed
|
||||
List<BalanceRecord> get formattedBalances {
|
||||
final balance = balances.values.toList();
|
||||
|
|
|
@ -217,7 +217,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
|||
PendingTransaction? pendingTransaction;
|
||||
|
||||
@computed
|
||||
String get balance => wallet.balance[selectedCryptoCurrency]!.formattedAvailableBalance;
|
||||
String get balance => wallet.balance[selectedCryptoCurrency]!.formattedFullAvailableBalance;
|
||||
|
||||
@computed
|
||||
bool get isFiatDisabled => balanceViewModel.isFiatDisabled;
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": " ضوء مونيرو",
|
||||
"moonpay_alert_text": "يجب أن تكون قيمة المبلغ أكبر من أو تساوي ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "المزيد من الخيارات",
|
||||
"mweb_confirmed": "أكد MWEB",
|
||||
"mweb_unconfirmed": "غير مؤكد MWEB",
|
||||
"name": "ﻢﺳﺍ",
|
||||
"nano_current_rep": "الممثل الحالي",
|
||||
"nano_gpt_thanks_message": "شكرا لاستخدام nanogpt! تذكر أن تعود إلى المتصفح بعد اكتمال معاملتك!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "Лека тема Monero",
|
||||
"moonpay_alert_text": "Сумата трябва да бъде най-малко ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Още настройки",
|
||||
"mweb_confirmed": "Потвърден MWeb",
|
||||
"mweb_unconfirmed": "Непотвърден mweb",
|
||||
"name": "Име",
|
||||
"nano_current_rep": "Настоящ представител",
|
||||
"nano_gpt_thanks_message": "Благодаря, че използвахте Nanogpt! Не забравяйте да се върнете обратно към браузъра, след като транзакцията ви приключи!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "Světlé téma Monero",
|
||||
"moonpay_alert_text": "Částka musí být větší nebo rovna ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Více možností",
|
||||
"mweb_confirmed": "Potvrzený mweb",
|
||||
"mweb_unconfirmed": "Nepotvrzené mWeb",
|
||||
"name": "název",
|
||||
"nano_current_rep": "Současný zástupce",
|
||||
"nano_gpt_thanks_message": "Děkujeme za používání Nanogpt! Nezapomeňte se po dokončení transakce vydat zpět do prohlížeče!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "Monero Light-Thema",
|
||||
"moonpay_alert_text": "Der Wert des Betrags muss größer oder gleich ${minAmount} ${fiatCurrency} sein",
|
||||
"more_options": "Weitere Optionen",
|
||||
"mweb_confirmed": "Bestätigt MWeb",
|
||||
"mweb_unconfirmed": "Unbestätigter MWeb",
|
||||
"name": "Name",
|
||||
"nano_current_rep": "Aktueller Vertreter",
|
||||
"nano_gpt_thanks_message": "Danke, dass du Nanogpt benutzt hast! Denken Sie daran, nach Abschluss Ihrer Transaktion zurück zum Browser zu gehen!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "Monero Light Theme",
|
||||
"moonpay_alert_text": "Value of the amount must be more or equal to ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "More Options",
|
||||
"mweb_confirmed": "Confirmed MWEB",
|
||||
"mweb_unconfirmed": "Unconfirmed MWEB",
|
||||
"name": "Name",
|
||||
"nano_current_rep": "Current Representative",
|
||||
"nano_gpt_thanks_message": "Thanks for using NanoGPT! Remember to head back to the browser after your transaction completes!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "Tema ligero de Monero",
|
||||
"moonpay_alert_text": "El valor de la cantidad debe ser mayor o igual a ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Más Opciones",
|
||||
"mweb_confirmed": "Confirmado mweb",
|
||||
"mweb_unconfirmed": "Mweb no confirmado",
|
||||
"name": "Nombre",
|
||||
"nano_current_rep": "Representante actual",
|
||||
"nano_gpt_thanks_message": "¡Gracias por usar nanogpt! ¡Recuerde regresar al navegador después de que se complete su transacción!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "Thème de lumière Monero",
|
||||
"moonpay_alert_text": "Le montant doit être au moins égal à ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Plus d'options",
|
||||
"mweb_confirmed": "Confirmé MWEB",
|
||||
"mweb_unconfirmed": "Mweb non confirmé",
|
||||
"name": "Nom",
|
||||
"nano_current_rep": "Représentant actuel",
|
||||
"nano_gpt_thanks_message": "Merci d'avoir utilisé Nanogpt! N'oubliez pas de retourner au navigateur une fois votre transaction terminée!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "Jigon Hasken Monero",
|
||||
"moonpay_alert_text": "Darajar adadin dole ne ya zama fiye ko daidai da ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Ƙarin Zaɓuɓɓuka",
|
||||
"mweb_confirmed": "Tabbatar da Mweb",
|
||||
"mweb_unconfirmed": "Myconfired",
|
||||
"name": "Suna",
|
||||
"nano_current_rep": "Wakilin Yanzu",
|
||||
"nano_gpt_thanks_message": "Na gode da amfani da Nanogpt! Ka tuna da komawa zuwa mai bincike bayan ma'amalar ka ta cika!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "मोनेरो लाइट थीम",
|
||||
"moonpay_alert_text": "राशि का मूल्य अधिक है या करने के लिए बराबर होना चाहिए ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "और विकल्प",
|
||||
"mweb_confirmed": "MWEB की पुष्टि की",
|
||||
"mweb_unconfirmed": "अपुष्ट MWEB",
|
||||
"name": "नाम",
|
||||
"nano_current_rep": "वर्तमान प्रतिनिधि",
|
||||
"nano_gpt_thanks_message": "Nanogpt का उपयोग करने के लिए धन्यवाद! अपने लेन -देन के पूरा होने के बाद ब्राउज़र पर वापस जाना याद रखें!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "Monero lagana tema",
|
||||
"moonpay_alert_text": "Vrijednost iznosa mora biti veća ili jednaka ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Više opcija",
|
||||
"mweb_confirmed": "Potvrđen MWeb",
|
||||
"mweb_unconfirmed": "Nepotvrđeni mWeb",
|
||||
"name": "Ime",
|
||||
"nano_current_rep": "Trenutni predstavnik",
|
||||
"nano_gpt_thanks_message": "Hvala što ste koristili nanogpt! Ne zaboravite da se vratite u preglednik nakon što vam se transakcija završi!",
|
||||
|
|
|
@ -387,6 +387,8 @@
|
|||
"monero_light_theme": "Monero պայծառ տեսք",
|
||||
"moonpay_alert_text": "Գումարի արժեքը պետք է լինի հավասար կամ ավելի քան ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Այլ տարբերակներ",
|
||||
"mweb_confirmed": "Հաստատված MWEB",
|
||||
"mweb_unconfirmed": "Չկարգավորված Mweb",
|
||||
"name": "Անուն",
|
||||
"nano_current_rep": "Ընթացիկ ներկայացուցիչ",
|
||||
"nano_gpt_thanks_message": "Շնորհակալություն NanoGPT-ն օգտագործելու համար: Հիշեք վերադառնալ դիտարկիչ ձեր փոխանցումն ավարտելուց հետո",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "Tema Cahaya Monero",
|
||||
"moonpay_alert_text": "Nilai jumlah harus lebih atau sama dengan ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Opsi Lainnya",
|
||||
"mweb_confirmed": "Mengkonfirmasi mWeb",
|
||||
"mweb_unconfirmed": "MWEB yang belum dikonfirmasi",
|
||||
"name": "Nama",
|
||||
"nano_current_rep": "Perwakilan saat ini",
|
||||
"nano_gpt_thanks_message": "Terima kasih telah menggunakan Nanogpt! Ingatlah untuk kembali ke browser setelah transaksi Anda selesai!",
|
||||
|
|
|
@ -397,6 +397,8 @@
|
|||
"monero_light_theme": "Tema leggero Monero",
|
||||
"moonpay_alert_text": "Il valore dell'importo deve essere maggiore o uguale a ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Altre opzioni",
|
||||
"mweb_confirmed": "MWeb confermato",
|
||||
"mweb_unconfirmed": "MWeb non confermato",
|
||||
"name": "Nome",
|
||||
"nano_current_rep": "Rappresentante attuale",
|
||||
"nano_gpt_thanks_message": "Grazie per aver usato il nanogpt! Ricorda di tornare al browser dopo il completamento della transazione!",
|
||||
|
|
|
@ -397,6 +397,8 @@
|
|||
"monero_light_theme": "モネロ ライト テーマ",
|
||||
"moonpay_alert_text": "金額の値は以上でなければなりません ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "その他のオプション",
|
||||
"mweb_confirmed": "確認されたMWEB",
|
||||
"mweb_unconfirmed": "未確認のMWEB",
|
||||
"name": "名前",
|
||||
"nano_current_rep": "現在の代表",
|
||||
"nano_gpt_thanks_message": "NanoGptを使用してくれてありがとう!トランザクションが完了したら、ブラウザに戻ることを忘れないでください!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "모네로 라이트 테마",
|
||||
"moonpay_alert_text": "금액은 다음보다 크거나 같아야합니다 ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "추가 옵션",
|
||||
"mweb_confirmed": "확인 mweb",
|
||||
"mweb_unconfirmed": "확인되지 않은 mweb",
|
||||
"name": "이름",
|
||||
"nano_current_rep": "현재 대표",
|
||||
"nano_gpt_thanks_message": "Nanogpt를 사용해 주셔서 감사합니다! 거래가 완료된 후 브라우저로 돌아가는 것을 잊지 마십시오!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "Monero Light အပြင်အဆင်",
|
||||
"moonpay_alert_text": "ပမာဏ၏တန်ဖိုးသည် ${minAmount} ${fiatCurrency} နှင့် ပိုနေရမည်",
|
||||
"more_options": "နောက်ထပ် ရွေးချယ်စရာများ",
|
||||
"mweb_confirmed": "အတည်ပြုလိုက် mweb",
|
||||
"mweb_unconfirmed": "အတည်မပြုနိုင်သော mweb",
|
||||
"name": "နာမည်",
|
||||
"nano_current_rep": "လက်ရှိကိုယ်စားလှယ်",
|
||||
"nano_gpt_thanks_message": "nanogpt ကိုသုံးပြီးကျေးဇူးတင်ပါတယ် သင်၏ငွေပေးငွေယူပြီးနောက် browser သို့ပြန်သွားရန်သတိရပါ။",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "Monero Light-thema",
|
||||
"moonpay_alert_text": "Waarde van het bedrag moet meer of gelijk zijn aan ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Meer opties",
|
||||
"mweb_confirmed": "Bevestigde MWEB",
|
||||
"mweb_unconfirmed": "Onbevestigde MWEB",
|
||||
"name": "Naam",
|
||||
"nano_current_rep": "Huidige vertegenwoordiger",
|
||||
"nano_gpt_thanks_message": "Bedankt voor het gebruik van Nanogpt! Vergeet niet om terug te gaan naar de browser nadat uw transactie is voltooid!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "Lekki motyw Monero",
|
||||
"moonpay_alert_text": "Wartość kwoty musi być większa lub równa ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Więcej opcji",
|
||||
"mweb_confirmed": "Potwierdził MWEB",
|
||||
"mweb_unconfirmed": "Niepotwierdzone MWEB",
|
||||
"name": "Nazwa",
|
||||
"nano_current_rep": "Obecny przedstawiciel",
|
||||
"nano_gpt_thanks_message": "Dzięki za użycie Nanogpt! Pamiętaj, aby wrócić do przeglądarki po zakończeniu transakcji!",
|
||||
|
|
|
@ -397,6 +397,8 @@
|
|||
"monero_light_theme": "Monero Light Theme",
|
||||
"moonpay_alert_text": "O valor do montante deve ser maior ou igual a ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Mais opções",
|
||||
"mweb_confirmed": "MWEB confirmado",
|
||||
"mweb_unconfirmed": "MWEB não confirmado",
|
||||
"name": "Nome",
|
||||
"nano_current_rep": "Representante atual",
|
||||
"nano_gpt_thanks_message": "Obrigado por usar o Nanogpt! Lembre -se de voltar para o navegador após a conclusão da transação!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "Светлая тема Monero",
|
||||
"moonpay_alert_text": "Сумма должна быть больше или равна ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Дополнительные параметры",
|
||||
"mweb_confirmed": "Подтверждено MWEB",
|
||||
"mweb_unconfirmed": "Неподтвержденная MWEB",
|
||||
"name": "Имя",
|
||||
"nano_current_rep": "Нынешний представитель",
|
||||
"nano_gpt_thanks_message": "Спасибо за использование Nanogpt! Не забудьте вернуться в браузер после завершения транзакции!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "ธีมแสง Monero",
|
||||
"moonpay_alert_text": "มูลค่าของจำนวนต้องมากกว่าหรือเท่ากับ ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "ตัวเลือกเพิ่มเติม",
|
||||
"mweb_confirmed": "MWEB ยืนยันแล้ว",
|
||||
"mweb_unconfirmed": "mweb ที่ไม่ได้รับการยืนยัน",
|
||||
"name": "ชื่อ",
|
||||
"nano_current_rep": "ตัวแทนปัจจุบัน",
|
||||
"nano_gpt_thanks_message": "ขอบคุณที่ใช้ Nanogpt! อย่าลืมกลับไปที่เบราว์เซอร์หลังจากการทำธุรกรรมของคุณเสร็จสิ้น!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "Monero Light Theme",
|
||||
"moonpay_alert_text": "Ang halaga ay dapat na higit pa o katumbas ng ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Higit pang mga Pagpipilian",
|
||||
"mweb_confirmed": "Nakumpirma na MWeb",
|
||||
"mweb_unconfirmed": "Hindi nakumpirma si Mweb",
|
||||
"name": "Pangalan",
|
||||
"nano_current_rep": "Kasalukuyang Representative",
|
||||
"nano_gpt_thanks_message": "Salamat sa paggamit ng NanoGPT! Tandaan na bumalik sa browser matapos makumpleto ang iyong transaksyon!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "Monero Hafif Tema",
|
||||
"moonpay_alert_text": "Tutar ${minAmount} ${fiatCurrency} miktarına eşit veya daha fazla olmalıdır",
|
||||
"more_options": "Daha Fazla Seçenek",
|
||||
"mweb_confirmed": "Onaylanmış mweb",
|
||||
"mweb_unconfirmed": "Doğrulanmamış mweb",
|
||||
"name": "İsim",
|
||||
"nano_current_rep": "Mevcut temsilci",
|
||||
"nano_gpt_thanks_message": "Nanogpt kullandığınız için teşekkürler! İşleminiz tamamlandıktan sonra tarayıcıya geri dönmeyi unutmayın!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "Легка тема Monero",
|
||||
"moonpay_alert_text": "Значення суми має бути більшим або дорівнювати ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Більше параметрів",
|
||||
"mweb_confirmed": "Підтвердив Mweb",
|
||||
"mweb_unconfirmed": "Неперевірений MWEB",
|
||||
"name": "Ім'я",
|
||||
"nano_current_rep": "Поточний представник",
|
||||
"nano_gpt_thanks_message": "Дякуємо за використання наногпта! Не забудьте повернутися до браузера після завершення транзакції!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "مونیرو لائٹ تھیم",
|
||||
"moonpay_alert_text": "رقم کی قدر ${minAmount} ${fiatCurrency} کے برابر یا زیادہ ہونی چاہیے۔",
|
||||
"more_options": "مزید زرائے",
|
||||
"mweb_confirmed": "تصدیق شدہ MWEB",
|
||||
"mweb_unconfirmed": "غیر مصدقہ MWEB",
|
||||
"name": "ﻡﺎﻧ",
|
||||
"nano_current_rep": "موجودہ نمائندہ",
|
||||
"nano_gpt_thanks_message": "نانوگپٹ استعمال کرنے کا شکریہ! اپنے لین دین کی تکمیل کے بعد براؤزر کی طرف واپس جانا یاد رکھیں!",
|
||||
|
|
|
@ -140,8 +140,8 @@
|
|||
"confirm": "Xác nhận",
|
||||
"confirm_delete_template": "Thao tác này sẽ xóa mẫu này. Bạn có muốn tiếp tục không?",
|
||||
"confirm_delete_wallet": "Thao tác này sẽ xóa ví này. Bạn có muốn tiếp tục không?",
|
||||
"confirm_fee_deduction": "Xác nhận Khấu trừ Phí",
|
||||
"confirm_fee_dedction_content": "Bạn có đồng ý trừ phí từ đầu ra không?",
|
||||
"confirm_fee_deduction": "Xác nhận Khấu trừ Phí",
|
||||
"confirm_sending": "Xác nhận gửi",
|
||||
"confirm_silent_payments_switch_node": "Nút hiện tại của bạn không hỗ trợ thanh toán im lặng\\nCake Wallet sẽ chuyển sang một nút tương thích chỉ để quét",
|
||||
"confirmations": "Xác nhận",
|
||||
|
@ -298,7 +298,7 @@
|
|||
"fiat_balance": "Số dư Fiat",
|
||||
"field_required": "Trường này là bắt buộc",
|
||||
"fill_code": "Vui lòng điền mã xác minh được gửi đến email của bạn",
|
||||
"filter_by": "Lọc theo",
|
||||
"filter_by": "Lọc theo",
|
||||
"first_wallet_text": "Ví tuyệt vời cho Monero, Bitcoin, Ethereum, Litecoin, và Haven",
|
||||
"fixed_pair_not_supported": "Cặp tỷ giá cố định này không được hỗ trợ với các sàn giao dịch đã chọn",
|
||||
"fixed_rate": "Tỷ giá cố định",
|
||||
|
@ -386,6 +386,8 @@
|
|||
"monero_light_theme": "Chủ đề sáng Monero",
|
||||
"moonpay_alert_text": "Giá trị số tiền phải lớn hơn hoặc bằng ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Thêm tùy chọn",
|
||||
"mweb_confirmed": "Xác nhận MWEB",
|
||||
"mweb_unconfirmed": "MWEB chưa được xác nhận",
|
||||
"name": "Tên",
|
||||
"nano_current_rep": "Đại diện hiện tại",
|
||||
"nano_gpt_thanks_message": "Cảm ơn bạn đã sử dụng NanoGPT! Hãy nhớ quay lại trình duyệt sau khi giao dịch của bạn hoàn tất!",
|
||||
|
@ -398,7 +400,7 @@
|
|||
"new_subaddress_label_name": "Tên nhãn",
|
||||
"new_subaddress_title": "Địa chỉ mới",
|
||||
"new_template": "Mẫu mới",
|
||||
"new_wallet": "Ví mới",
|
||||
"new_wallet": "Ví mới",
|
||||
"newConnection": "Kết nối mới",
|
||||
"no_cards_found": "Không tìm thấy thẻ",
|
||||
"no_id_needed": "Không cần ID!",
|
||||
|
@ -498,7 +500,7 @@
|
|||
"red_dark_theme": "Chủ đề tối đỏ",
|
||||
"red_light_theme": "Chủ đề sáng đỏ",
|
||||
"redeemed": "Đã đổi",
|
||||
"refund_address": "Địa chỉ hoàn tiền",
|
||||
"refund_address": "Địa chỉ hoàn tiền",
|
||||
"reject": "Từ chối",
|
||||
"remaining": "còn lại",
|
||||
"remove": "Gỡ bỏ",
|
||||
|
@ -598,7 +600,7 @@
|
|||
"seedtype": "Loại hạt giống",
|
||||
"seedtype_legacy": "Di sản (25 từ)",
|
||||
"seedtype_polyseed": "Polyseed (16 từ)",
|
||||
"seedtype_wownero": "Wownero (14 từ)",
|
||||
"seedtype_wownero": "Wownero (14 từ)",
|
||||
"select_backup_file": "Chọn tệp sao lưu",
|
||||
"select_buy_provider_notice": "Chọn nhà cung cấp mua ở trên. Bạn có thể bỏ qua màn hình này bằng cách thiết lập nhà cung cấp mua mặc định trong cài đặt ứng dụng.",
|
||||
"select_destination": "Vui lòng chọn đích cho tệp sao lưu.",
|
||||
|
@ -698,7 +700,7 @@
|
|||
"support_description_guides": "Tài liệu và hỗ trợ cho các vấn đề phổ biến",
|
||||
"support_description_live_chat": "Miễn phí và nhanh chóng! Các đại diện hỗ trợ được đào tạo sẵn sàng hỗ trợ",
|
||||
"support_description_other_links": "Tham gia cộng đồng của chúng tôi hoặc liên hệ với chúng tôi hoặc các đối tác của chúng tôi qua các phương pháp khác",
|
||||
"support_title_guides": "Hướng dẫn Cake Wallet",
|
||||
"support_title_guides": "Hướng dẫn Cake Wallet",
|
||||
"support_title_live_chat": "Hỗ trợ trực tiếp",
|
||||
"support_title_other_links": "Liên kết hỗ trợ khác",
|
||||
"sweeping_wallet": "Quét ví",
|
||||
|
@ -798,7 +800,7 @@
|
|||
"trongrid_history": "Lịch sử TronGrid",
|
||||
"trusted": "Đã tin cậy",
|
||||
"tx_commit_exception_no_dust_on_change": "Giao dịch bị từ chối với số tiền này. Với số tiền này bạn có thể gửi ${min} mà không cần đổi tiền lẻ hoặc ${max} trả lại tiền lẻ.",
|
||||
"tx_commit_failed": "Giao dịch không thành công. Vui lòng liên hệ với hỗ trợ.",
|
||||
"tx_commit_failed": "Giao dịch không thành công. Vui lòng liên hệ với hỗ trợ.",
|
||||
"tx_invalid_input": "Bạn đang sử dụng loại đầu vào sai cho loại thanh toán này",
|
||||
"tx_no_dust_exception": "Giao dịch bị từ chối vì gửi một số tiền quá nhỏ. Vui lòng thử tăng số tiền.",
|
||||
"tx_not_enough_inputs_exception": "Không đủ đầu vào có sẵn. Vui lòng chọn thêm dưới Coin Control",
|
||||
|
@ -897,4 +899,4 @@
|
|||
"you_will_get": "Chuyển đổi thành",
|
||||
"you_will_send": "Chuyển đổi từ",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
|
@ -397,6 +397,8 @@
|
|||
"monero_light_theme": "Monero Light Akori",
|
||||
"moonpay_alert_text": "Iye owó kò gbọ́dọ̀ kéré ju ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Ìyàn àfikún",
|
||||
"mweb_confirmed": "Jẹrisi Mweb",
|
||||
"mweb_unconfirmed": "Ajopo Mweb",
|
||||
"name": "Oruko",
|
||||
"nano_current_rep": "Aṣoju lọwọlọwọ",
|
||||
"nano_gpt_thanks_message": "O ṣeun fun lilo Nonnogt! Ranti lati tẹle pada si ẹrọ lilọ kiri ayelujara lẹhin iṣowo rẹ pari!",
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
"monero_light_theme": "门罗币浅色主题",
|
||||
"moonpay_alert_text": "金额的价值必须大于或等于 ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "更多选项",
|
||||
"mweb_confirmed": "确认的MWEB",
|
||||
"mweb_unconfirmed": "未经证实的MWEB",
|
||||
"name": "姓名",
|
||||
"nano_current_rep": "当前代表",
|
||||
"nano_gpt_thanks_message": "感谢您使用Nanogpt!事务完成后,请记住回到浏览器!",
|
||||
|
|
Loading…
Reference in a new issue