Merge branch 'main' into CW-867-investigate-issues-with-wownero-2

This commit is contained in:
cyan 2025-01-06 12:38:17 +01:00 committed by GitHub
commit 83e0729430
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
71 changed files with 502 additions and 395 deletions

View file

@ -1,5 +1,7 @@
- -
uri: ethereum.publicnode.com uri: ethereum-rpc.publicnode.com
useSSL: true
isDefault: true
- -
uri: eth.llamarpc.com uri: eth.llamarpc.com
- -

View file

@ -1,7 +1,9 @@
- -
uri: polygon-rpc.com uri: polygon-rpc.com
- -
uri: polygon-bor.publicnode.com uri: polygon-bor-rpc.publicnode.com
useSSL: true
isDefault: true
- -
uri: polygon.llamarpc.com uri: polygon.llamarpc.com
- -

View file

@ -1,3 +1,2 @@
Support Monero Ledger UI enhancements
Bug fixes Bug fixes
New designs and better user experience

View file

@ -1,5 +1,4 @@
Support Monero Ledger Bitcoin and Litecoin enhancements
Prepare for Haven removal Solana and Nano fixes/improvements
Improve Ethereum and Polygon sending process UI enhancements
Bug fixes Bug fixes
New designs and better user experience

View file

@ -4,7 +4,6 @@ import 'dart:io';
import 'dart:isolate'; import 'dart:isolate';
import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:cw_bitcoin/litecoin_wallet_addresses.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_bitcoin/bitcoin_wallet.dart'; import 'package:cw_bitcoin/bitcoin_wallet.dart';
import 'package:cw_bitcoin/litecoin_wallet.dart'; import 'package:cw_bitcoin/litecoin_wallet.dart';
@ -991,6 +990,9 @@ abstract class ElectrumWalletBase
@override @override
Future<PendingTransaction> createTransaction(Object credentials) async { Future<PendingTransaction> createTransaction(Object credentials) async {
try { try {
// start by updating unspent coins
await updateAllUnspents();
final outputs = <BitcoinOutput>[]; final outputs = <BitcoinOutput>[];
final transactionCredentials = credentials as BitcoinTransactionCredentials; final transactionCredentials = credentials as BitcoinTransactionCredentials;
final hasMultiDestination = transactionCredentials.outputs.length > 1; final hasMultiDestination = transactionCredentials.outputs.length > 1;

View file

@ -349,8 +349,10 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
type: addressPageType, type: addressPageType,
network: network, network: network,
); );
_addresses.add(address); Future.delayed(Duration.zero, () {
Future.delayed(Duration.zero, () => updateAddressesByMatch()); _addresses.add(address);
updateAddressesByMatch();
});
return address; return address;
} }

View file

@ -4,7 +4,7 @@ import 'package:cw_core/monero_amount_format.dart';
class MoneroBalance extends Balance { class MoneroBalance extends Balance {
MoneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0}) MoneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
: formattedUnconfirmedBalance = moneroAmountToString(amount: fullBalance - unlockedBalance), : formattedUnconfirmedBalance = moneroAmountToString(amount: fullBalance - unlockedBalance),
formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance - frozenBalance), formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance),
formattedFrozenBalance = moneroAmountToString(amount: frozenBalance), formattedFrozenBalance = moneroAmountToString(amount: frozenBalance),
super(unlockedBalance, fullBalance); super(unlockedBalance, fullBalance);

View file

@ -99,8 +99,8 @@ class Node extends HiveObject with Keyable {
case WalletType.polygon: case WalletType.polygon:
case WalletType.solana: case WalletType.solana:
case WalletType.tron: case WalletType.tron:
return Uri.parse( return Uri.parse(
"http${isSSL ? "s" : ""}://$uriRaw${path!.startsWith("/") ? path : "/$path"}"); "http${isSSL ? "s" : ""}://$uriRaw${path!.startsWith("/") ? path : "/$path"}");
case WalletType.none: case WalletType.none:
throw Exception('Unexpected type ${type.toString()} for Node uri'); throw Exception('Unexpected type ${type.toString()} for Node uri');
} }
@ -152,6 +152,7 @@ class Node extends HiveObject with Keyable {
return requestMoneroNode(); return requestMoneroNode();
case WalletType.nano: case WalletType.nano:
case WalletType.banano: case WalletType.banano:
return requestNanoNode();
case WalletType.bitcoin: case WalletType.bitcoin:
case WalletType.litecoin: case WalletType.litecoin:
case WalletType.bitcoinCash: case WalletType.bitcoinCash:
@ -198,14 +199,16 @@ class Node extends HiveObject with Keyable {
); );
client.close(); client.close();
if (( if ((response.body.contains("400 Bad Request") // Some other generic error
response.body.contains("400 Bad Request") // Some other generic error ||
|| response.body.contains("plain HTTP request was sent to HTTPS port") // Cloudflare response.body.contains("plain HTTP request was sent to HTTPS port") // Cloudflare
|| response.headers["location"] != null // Generic reverse proxy ||
|| response.body.contains("301 Moved Permanently") // Poorly configured generic reverse proxy response.headers["location"] != null // Generic reverse proxy
) && !(useSSL??false) ||
) { response.body
.contains("301 Moved Permanently") // Poorly configured generic reverse proxy
) &&
!(useSSL ?? false)) {
final oldUseSSL = useSSL; final oldUseSSL = useSSL;
useSSL = true; useSSL = true;
try { try {
@ -271,6 +274,35 @@ class Node extends HiveObject with Keyable {
} }
} }
Future<bool> requestNanoNode() async {
try {
final response = await http.post(
uri,
headers: {
"Content-Type": "application/json",
"nano-app": "cake-wallet"
},
body: jsonEncode(
{
"action": "account_balance",
"account": "nano_38713x95zyjsqzx6nm1dsom1jmm668owkeb9913ax6nfgj15az3nu8xkx579",
},
),
);
final data = await jsonDecode(response.body);
if (response.statusCode != 200 ||
data["error"] != null ||
data["balance"] == null ||
data["receivable"] == null) {
throw Exception(
"Error while trying to get balance! ${data["error"] != null ? data["error"] : ""}");
}
return true;
} catch (_) {
return false;
}
}
Future<bool> requestEthereumServer() async { Future<bool> requestEthereumServer() async {
try { try {
final response = await http.get( final response = await http.get(

View file

@ -4,7 +4,7 @@ import 'package:cw_core/wownero_amount_format.dart';
class WowneroBalance extends Balance { class WowneroBalance extends Balance {
WowneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0}) WowneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
: formattedUnconfirmedBalance = wowneroAmountToString(amount: fullBalance - unlockedBalance), : formattedUnconfirmedBalance = wowneroAmountToString(amount: fullBalance - unlockedBalance),
formattedUnlockedBalance = wowneroAmountToString(amount: unlockedBalance - frozenBalance), formattedUnlockedBalance = wowneroAmountToString(amount: unlockedBalance),
formattedFrozenBalance = formattedFrozenBalance =
wowneroAmountToString(amount: frozenBalance), wowneroAmountToString(amount: frozenBalance),
super(unlockedBalance, fullBalance); super(unlockedBalance, fullBalance);

View file

@ -29,7 +29,6 @@ import 'package:cw_evm/evm_chain_transaction_model.dart';
import 'package:cw_evm/evm_chain_transaction_priority.dart'; import 'package:cw_evm/evm_chain_transaction_priority.dart';
import 'package:cw_evm/evm_chain_wallet_addresses.dart'; import 'package:cw_evm/evm_chain_wallet_addresses.dart';
import 'package:cw_evm/evm_ledger_credentials.dart'; import 'package:cw_evm/evm_ledger_credentials.dart';
import 'package:flutter/foundation.dart';
import 'package:hex/hex.dart'; import 'package:hex/hex.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
@ -348,7 +347,7 @@ abstract class EVMChainWalletBase
final CryptoCurrency transactionCurrency = final CryptoCurrency transactionCurrency =
balance.keys.firstWhere((element) => element.title == _credentials.currency.title); balance.keys.firstWhere((element) => element.title == _credentials.currency.title);
final erc20Balance = balance[transactionCurrency]!; final currencyBalance = balance[transactionCurrency]!;
BigInt totalAmount = BigInt.zero; BigInt totalAmount = BigInt.zero;
BigInt estimatedFeesForTransaction = BigInt.zero; BigInt estimatedFeesForTransaction = BigInt.zero;
int exponent = transactionCurrency is Erc20Token ? transactionCurrency.decimal : 18; int exponent = transactionCurrency is Erc20Token ? transactionCurrency.decimal : 18;
@ -385,7 +384,7 @@ abstract class EVMChainWalletBase
estimatedGasUnitsForTransaction = gasFeesModel.estimatedGasUnits; estimatedGasUnitsForTransaction = gasFeesModel.estimatedGasUnits;
maxFeePerGasForTransaction = gasFeesModel.maxFeePerGas; maxFeePerGasForTransaction = gasFeesModel.maxFeePerGas;
if (erc20Balance.balance < totalAmount) { if (currencyBalance.balance < totalAmount) {
throw EVMChainTransactionCreationException(transactionCurrency); throw EVMChainTransactionCreationException(transactionCurrency);
} }
} else { } else {
@ -398,7 +397,7 @@ abstract class EVMChainWalletBase
} }
if (output.sendAll && transactionCurrency is Erc20Token) { if (output.sendAll && transactionCurrency is Erc20Token) {
totalAmount = erc20Balance.balance; totalAmount = currencyBalance.balance;
} }
final gasFeesModel = await calculateActualEstimatedFeeForCreateTransaction( final gasFeesModel = await calculateActualEstimatedFeeForCreateTransaction(
@ -413,14 +412,15 @@ abstract class EVMChainWalletBase
maxFeePerGasForTransaction = gasFeesModel.maxFeePerGas; maxFeePerGasForTransaction = gasFeesModel.maxFeePerGas;
if (output.sendAll && transactionCurrency is! Erc20Token) { if (output.sendAll && transactionCurrency is! Erc20Token) {
totalAmount = (erc20Balance.balance - estimatedFeesForTransaction); totalAmount = (currencyBalance.balance - estimatedFeesForTransaction);
if (estimatedFeesForTransaction > erc20Balance.balance) {
throw EVMChainTransactionFeesException();
}
} }
if (erc20Balance.balance < totalAmount) { // check the fees on the base currency (Eth/Polygon)
if (estimatedFeesForTransaction > balance[currency]!.balance) {
throw EVMChainTransactionFeesException();
}
if (currencyBalance.balance < totalAmount) {
throw EVMChainTransactionCreationException(transactionCurrency); throw EVMChainTransactionCreationException(transactionCurrency);
} }
} }

View file

@ -126,8 +126,10 @@ Future<bool> setupNodeSync(
if (status != 0) { if (status != 0) {
final error = monero.Wallet_errorString(wptr!); final error = monero.Wallet_errorString(wptr!);
printV("error: $error"); if (error != "no tx keys found for this txid") {
throw SetupWalletException(message: error); printV("error: $error");
throw SetupWalletException(message: error);
}
} }
if (kDebugMode) { if (kDebugMode) {

View file

@ -7,7 +7,6 @@ import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/account.dart'; import 'package:cw_core/account.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_core/monero_balance.dart'; import 'package:cw_core/monero_balance.dart';
import 'package:cw_core/monero_transaction_priority.dart'; import 'package:cw_core/monero_transaction_priority.dart';
import 'package:cw_core/monero_wallet_keys.dart'; import 'package:cw_core/monero_wallet_keys.dart';
@ -28,7 +27,6 @@ import 'package:cw_monero/api/transaction_history.dart' as transaction_history;
import 'package:cw_monero/api/wallet.dart' as monero_wallet; import 'package:cw_monero/api/wallet.dart' as monero_wallet;
import 'package:cw_monero/api/wallet_manager.dart'; import 'package:cw_monero/api/wallet_manager.dart';
import 'package:cw_monero/exceptions/monero_transaction_creation_exception.dart'; import 'package:cw_monero/exceptions/monero_transaction_creation_exception.dart';
import 'package:cw_monero/exceptions/monero_transaction_no_inputs_exception.dart';
import 'package:cw_monero/ledger.dart'; import 'package:cw_monero/ledger.dart';
import 'package:cw_monero/monero_transaction_creation_credentials.dart'; import 'package:cw_monero/monero_transaction_creation_credentials.dart';
import 'package:cw_monero/monero_transaction_history.dart'; import 'package:cw_monero/monero_transaction_history.dart';
@ -58,8 +56,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
required String password}) required String password})
: balance = ObservableMap<CryptoCurrency, MoneroBalance>.of({ : balance = ObservableMap<CryptoCurrency, MoneroBalance>.of({
CryptoCurrency.xmr: MoneroBalance( CryptoCurrency.xmr: MoneroBalance(
fullBalance: monero_wallet.getFullBalance(accountIndex: 0), fullBalance: monero_wallet.getFullBalance(accountIndex: 0),
unlockedBalance: monero_wallet.getFullBalance(accountIndex: 0)) unlockedBalance: monero_wallet.getUnlockedBalance(accountIndex: 0),
)
}), }),
_isTransactionUpdating = false, _isTransactionUpdating = false,
_hasSyncAfterStartup = false, _hasSyncAfterStartup = false,
@ -265,6 +264,14 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
return str; return str;
} }
bool needExportOutputs(int amount) {
// viewOnlyBalance - balance that we can spend
// TODO(mrcyjanek): remove hasUnknownKeyImages when we cleanup coin control
return (monero.Wallet_viewOnlyBalance(wptr!,
accountIndex: walletAddresses.account!.id) < amount) ||
monero.Wallet_hasUnknownKeyImages(wptr!);
}
@override @override
Future<PendingTransaction> createTransaction(Object credentials) async { Future<PendingTransaction> createTransaction(Object credentials) async {
final _credentials = credentials as MoneroTransactionCreationCredentials; final _credentials = credentials as MoneroTransactionCreationCredentials;
@ -273,7 +280,6 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
final hasMultiDestination = outputs.length > 1; final hasMultiDestination = outputs.length > 1;
final unlockedBalance = monero_wallet.getUnlockedBalance( final unlockedBalance = monero_wallet.getUnlockedBalance(
accountIndex: walletAddresses.account!.id); accountIndex: walletAddresses.account!.id);
var allInputsAmount = 0;
PendingTransactionDescription pendingTransactionDescription; PendingTransactionDescription pendingTransactionDescription;
@ -287,11 +293,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
for (final utx in unspentCoins) { for (final utx in unspentCoins) {
if (utx.isSending) { if (utx.isSending) {
allInputsAmount += utx.value;
inputs.add(utx.keyImage!); inputs.add(utx.keyImage!);
} }
} }
final spendAllCoins = inputs.length == unspentCoins.length;
if (hasMultiDestination) { if (hasMultiDestination) {
if (outputs.any( if (outputs.any(
@ -303,8 +307,6 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
final int totalAmount = outputs.fold( final int totalAmount = outputs.fold(
0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)); 0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0));
final estimatedFee =
calculateEstimatedFee(_credentials.priority, totalAmount);
if (unlockedBalance < totalAmount) { if (unlockedBalance < totalAmount) {
throw MoneroTransactionCreationException( throw MoneroTransactionCreationException(
'You do not have enough XMR to send this amount.'); 'You do not have enough XMR to send this amount.');
@ -334,8 +336,6 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
output.isParsedAddress ? output.extractedAddress : output.address; output.isParsedAddress ? output.extractedAddress : output.address;
final amount = final amount =
output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.'); output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.');
final formattedAmount =
output.sendAll ? null : output.formattedCryptoAmount;
// if ((formattedAmount != null && unlockedBalance < formattedAmount) || // if ((formattedAmount != null && unlockedBalance < formattedAmount) ||
// (formattedAmount == null && unlockedBalance <= 0)) { // (formattedAmount == null && unlockedBalance <= 0)) {
@ -345,8 +345,6 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
// 'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.'); // 'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
// } // }
final estimatedFee =
calculateEstimatedFee(_credentials.priority, formattedAmount);
if (inputs.isEmpty) MoneroTransactionCreationException( if (inputs.isEmpty) MoneroTransactionCreationException(
'No inputs selected'); 'No inputs selected');
pendingTransactionDescription = pendingTransactionDescription =
@ -742,26 +740,16 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
Future<void> _askForUpdateTransactionHistory() async => Future<void> _askForUpdateTransactionHistory() async =>
await updateTransactions(); await updateTransactions();
int _getFullBalance() =>
monero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id);
int _getUnlockedBalance() => monero_wallet.getUnlockedBalance( int _getUnlockedBalance() => monero_wallet.getUnlockedBalance(
accountIndex: walletAddresses.account!.id); accountIndex: walletAddresses.account!.id);
int _getFrozenBalance() { int _getFrozenBalance() {
var frozenBalance = 0; var frozenBalance = 0;
unspentCoinsInfo.values.forEach((info) { for (var coin in unspentCoinsInfo.values.where((element) =>
unspentCoins.forEach((element) { element.walletId == id && element.accountIndex == walletAddresses.account!.id)) {
if (element.hash == info.hash && if (coin.isFrozen && !coin.isSending) frozenBalance += coin.value;
element.vout == info.vout && }
info.isFrozen &&
element.value == info.value && info.walletId == id &&
info.accountIndex == walletAddresses.account!.id) {
if (element.isFrozen && !element.isSending) frozenBalance+= element.value;
}
});
});
return frozenBalance; return frozenBalance;
} }

View file

@ -54,12 +54,12 @@ class NanoClient {
} }
} }
Map<String, String> getHeaders() { Map<String, String> getHeaders(String host) {
final headers = Map<String, String>.from(CAKE_HEADERS); final headers = Map<String, String>.from(CAKE_HEADERS);
if (_node!.uri.host == "rpc.nano.to") { if (host == "rpc.nano.to") {
headers["key"] = nano_secrets.nano2ApiKey; headers["key"] = nano_secrets.nano2ApiKey;
} }
if (_node!.uri.host == "nano.nownodes.io") { if (host == "nano.nownodes.io") {
headers["api-key"] = nano_secrets.nanoNowNodesApiKey; headers["api-key"] = nano_secrets.nanoNowNodesApiKey;
} }
return headers; return headers;
@ -68,7 +68,7 @@ class NanoClient {
Future<NanoBalance> getBalance(String address) async { Future<NanoBalance> getBalance(String address) async {
final response = await http.post( final response = await http.post(
_node!.uri, _node!.uri,
headers: getHeaders(), headers: getHeaders(_node!.uri.host),
body: jsonEncode( body: jsonEncode(
{ {
"action": "account_balance", "action": "account_balance",
@ -95,7 +95,7 @@ class NanoClient {
try { try {
final response = await http.post( final response = await http.post(
_node!.uri, _node!.uri,
headers: getHeaders(), headers: getHeaders(_node!.uri.host),
body: jsonEncode( body: jsonEncode(
{ {
"action": "account_info", "action": "account_info",
@ -116,7 +116,7 @@ class NanoClient {
try { try {
final response = await http.post( final response = await http.post(
_node!.uri, _node!.uri,
headers: CAKE_HEADERS, headers: getHeaders(_node!.uri.host),
body: jsonEncode( body: jsonEncode(
{ {
"action": "block_info", "action": "block_info",
@ -183,7 +183,7 @@ class NanoClient {
Future<String> requestWork(String hash) async { Future<String> requestWork(String hash) async {
final response = await http.post( final response = await http.post(
_powNode!.uri, _powNode!.uri,
headers: getHeaders(), headers: getHeaders(_powNode!.uri.host),
body: json.encode( body: json.encode(
{ {
"action": "work_generate", "action": "work_generate",
@ -226,7 +226,7 @@ class NanoClient {
final processResponse = await http.post( final processResponse = await http.post(
_node!.uri, _node!.uri,
headers: getHeaders(), headers: getHeaders(_node!.uri.host),
body: processBody, body: processBody,
); );
@ -425,7 +425,7 @@ class NanoClient {
}); });
final processResponse = await http.post( final processResponse = await http.post(
_node!.uri, _node!.uri,
headers: getHeaders(), headers: getHeaders(_node!.uri.host),
body: processBody, body: processBody,
); );
@ -441,7 +441,7 @@ class NanoClient {
required String privateKey, required String privateKey,
}) async { }) async {
final receivableResponse = await http.post(_node!.uri, final receivableResponse = await http.post(_node!.uri,
headers: getHeaders(), headers: getHeaders(_node!.uri.host),
body: jsonEncode({ body: jsonEncode({
"action": "receivable", "action": "receivable",
"account": destinationAddress, "account": destinationAddress,
@ -493,7 +493,7 @@ class NanoClient {
Future<List<NanoTransactionModel>> fetchTransactions(String address) async { Future<List<NanoTransactionModel>> fetchTransactions(String address) async {
try { try {
final response = await http.post(_node!.uri, final response = await http.post(_node!.uri,
headers: getHeaders(), headers: getHeaders(_node!.uri.host),
body: jsonEncode({ body: jsonEncode({
"action": "account_history", "action": "account_history",
"account": address, "account": address,
@ -509,15 +509,16 @@ class NanoClient {
.map<NanoTransactionModel>((transaction) => NanoTransactionModel.fromJson(transaction)) .map<NanoTransactionModel>((transaction) => NanoTransactionModel.fromJson(transaction))
.toList(); .toList();
} catch (e) { } catch (e) {
printV(e); printV("error fetching transactions: $e");
return []; rethrow;
} }
} }
Future<List<N2Node>> getN2Reps() async { Future<List<N2Node>> getN2Reps() async {
final uri = Uri.parse(N2_REPS_ENDPOINT);
final response = await http.post( final response = await http.post(
Uri.parse(N2_REPS_ENDPOINT), uri,
headers: CAKE_HEADERS, headers: getHeaders(uri.host),
body: jsonEncode({"action": "reps"}), body: jsonEncode({"action": "reps"}),
); );
try { try {
@ -531,9 +532,10 @@ class NanoClient {
} }
Future<int> getRepScore(String rep) async { Future<int> getRepScore(String rep) async {
final uri = Uri.parse(N2_REPS_ENDPOINT);
final response = await http.post( final response = await http.post(
Uri.parse(N2_REPS_ENDPOINT), uri,
headers: CAKE_HEADERS, headers: getHeaders(uri.host),
body: jsonEncode({ body: jsonEncode({
"action": "rep_info", "action": "rep_info",
"account": rep, "account": rep,

View file

@ -379,16 +379,18 @@ class SolanaWalletClient {
required double solBalance, required double solBalance,
required double fee, required double fee,
}) async { }) async {
final rent = return true;
await _client!.getMinimumBalanceForMintRentExemption(commitment: Commitment.confirmed); // TODO: this is not doing what the name inclines
// final rent =
final rentInSol = (rent / lamportsPerSol).toDouble(); // await _client!.getMinimumBalanceForMintRentExemption(commitment: Commitment.confirmed);
//
final remnant = solBalance - (inputAmount + fee); // final rentInSol = (rent / lamportsPerSol).toDouble();
//
if (remnant > rentInSol) return true; // final remnant = solBalance - (inputAmount + fee);
//
return false; // if (remnant > rentInSol) return true;
//
// return false;
} }
Future<PendingSolanaTransaction> _signNativeTokenTransaction({ Future<PendingSolanaTransaction> _signNativeTokenTransaction({
@ -479,6 +481,9 @@ class SolanaWalletClient {
final destinationOwner = Ed25519HDPublicKey.fromBase58(destinationAddress); final destinationOwner = Ed25519HDPublicKey.fromBase58(destinationAddress);
final mint = Ed25519HDPublicKey.fromBase58(tokenMint); final mint = Ed25519HDPublicKey.fromBase58(tokenMint);
// Input by the user
final amount = (inputAmount * math.pow(10, tokenDecimals)).toInt();
ProgramAccount? associatedRecipientAccount; ProgramAccount? associatedRecipientAccount;
ProgramAccount? associatedSenderAccount; ProgramAccount? associatedSenderAccount;
@ -501,18 +506,48 @@ class SolanaWalletClient {
} }
try { try {
associatedRecipientAccount ??= await _client!.createAssociatedTokenAccount( if (associatedRecipientAccount == null) {
mint: mint, final derivedAddress = await findAssociatedTokenAddress(
owner: destinationOwner, owner: destinationOwner,
funder: ownerKeypair, mint: mint,
); );
final instruction = AssociatedTokenAccountInstruction.createAccount(
mint: mint,
address: derivedAddress,
owner: destinationOwner,
funder: ownerKeypair.publicKey,
);
final _signedTx = await _signTransactionInternal(
message: Message.only(instruction),
signers: [ownerKeypair],
commitment: commitment,
latestBlockhash: await _getLatestBlockhash(commitment),
);
await sendTransaction(
signedTransaction: _signedTx,
commitment: commitment,
);
associatedRecipientAccount = ProgramAccount(
pubkey: derivedAddress.toBase58(),
account: Account(
owner: destinationOwner.toBase58(),
lamports: 0,
executable: false,
rentEpoch: BigInt.zero,
data: null,
),
);
await Future.delayed(Duration(seconds: 5));
}
} catch (e) { } catch (e) {
throw SolanaCreateAssociatedTokenAccountException(e.toString()); throw SolanaCreateAssociatedTokenAccountException(e.toString());
} }
// Input by the user
final amount = (inputAmount * math.pow(10, tokenDecimals)).toInt();
final instruction = TokenInstruction.transfer( final instruction = TokenInstruction.transfer(
source: Ed25519HDPublicKey.fromBase58(associatedSenderAccount.pubkey), source: Ed25519HDPublicKey.fromBase58(associatedSenderAccount.pubkey),
destination: Ed25519HDPublicKey.fromBase58(associatedRecipientAccount.pubkey), destination: Ed25519HDPublicKey.fromBase58(associatedRecipientAccount.pubkey),
@ -550,10 +585,14 @@ class SolanaWalletClient {
latestBlockhash: latestBlockhash, latestBlockhash: latestBlockhash,
); );
sendTx() async => await sendTransaction( sendTx() async {
await Future.delayed(Duration(seconds: 3));
return await sendTransaction(
signedTransaction: signedTx, signedTransaction: signedTx,
commitment: commitment, commitment: commitment,
); );
}
final pendingTransaction = PendingSolanaTransaction( final pendingTransaction = PendingSolanaTransaction(
amount: inputAmount, amount: inputAmount,

View file

@ -33,7 +33,6 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:solana/base58.dart'; import 'package:solana/base58.dart';
import 'package:solana/metaplex.dart' as metaplex; import 'package:solana/metaplex.dart' as metaplex;
import 'package:solana/solana.dart'; import 'package:solana/solana.dart';
import 'package:solana/src/crypto/ed25519_hd_keypair.dart';
part 'solana_wallet.g.dart'; part 'solana_wallet.g.dart';

View file

@ -272,7 +272,7 @@ SPEC CHECKSUMS:
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6 universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1 wakelock_plus: 373cfe59b235a6dd5837d0fb88791d2f13a90d56
workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6 workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6
PODFILE CHECKSUM: e448f662d4c41f0c0b1ccbb78afd57dbf895a597 PODFILE CHECKSUM: e448f662d4c41f0c0b1ccbb78afd57dbf895a597

View file

@ -149,7 +149,8 @@ class CWBitcoin extends Bitcoin {
} }
@override @override
Future<int> estimateFakeSendAllTxAmount(Object wallet, TransactionPriority priority) async { Future<int> estimateFakeSendAllTxAmount(Object wallet, TransactionPriority priority,
{UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any}) async {
try { try {
final sk = ECPrivate.random(); final sk = ECPrivate.random();
final electrumWallet = wallet as ElectrumWallet; final electrumWallet = wallet as ElectrumWallet;
@ -173,6 +174,7 @@ class CWBitcoin extends Bitcoin {
? priority as LitecoinTransactionPriority ? priority as LitecoinTransactionPriority
: priority as BitcoinTransactionPriority, : priority as BitcoinTransactionPriority,
), ),
coinTypeToSpendFrom: coinTypeToSpendFrom,
); );
return estimatedTx.amount; return estimatedTx.amount;

View file

@ -51,6 +51,8 @@ class RobinhoodBuyProvider extends BuyProvider {
switch (wallet.type) { switch (wallet.type) {
case WalletType.ethereum: case WalletType.ethereum:
case WalletType.polygon: case WalletType.polygon:
case WalletType.solana:
case WalletType.tron:
return await wallet.signMessage(message); return await wallet.signMessage(message);
case WalletType.litecoin: case WalletType.litecoin:
case WalletType.bitcoin: case WalletType.bitcoin:
@ -78,8 +80,7 @@ class RobinhoodBuyProvider extends BuyProvider {
if (response.statusCode == 200) { if (response.statusCode == 200) {
return (jsonDecode(response.body) as Map<String, dynamic>)['connectId'] as String; return (jsonDecode(response.body) as Map<String, dynamic>)['connectId'] as String;
} else { } else {
throw Exception( throw Exception('Provider currently unavailable. Status: ${response.statusCode}');
'Provider currently unavailable. Status: ${response.statusCode} ${response.body}');
} }
} }
@ -120,13 +121,13 @@ class RobinhoodBuyProvider extends BuyProvider {
try { try {
final uri = await requestProviderUrl(); final uri = await requestProviderUrl();
await launchUrl(uri, mode: LaunchMode.externalApplication); await launchUrl(uri, mode: LaunchMode.externalApplication);
} catch (_) { } catch (e) {
await showPopUp<void>( await showPopUp<void>(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return AlertWithOneAction( return AlertWithOneAction(
alertTitle: "Robinhood Connect", alertTitle: "Robinhood Connect",
alertContent: S.of(context).buy_provider_unavailable, alertContent: e.toString(),
buttonText: S.of(context).ok, buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop()); buttonAction: () => Navigator.of(context).pop());
}); });

View file

@ -230,6 +230,7 @@ class CakePayApi {
var headers = { var headers = {
'accept': 'application/json; charset=UTF-8', 'accept': 'application/json; charset=UTF-8',
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Api-Key $apiKey', 'Authorization': 'Api-Key $apiKey',
}; };
@ -240,7 +241,7 @@ class CakePayApi {
'Failed to fetch vendors: statusCode - ${response.statusCode}, queryParams -$queryParams, response - ${response.body}'); 'Failed to fetch vendors: statusCode - ${response.statusCode}, queryParams -$queryParams, response - ${response.body}');
} }
final bodyJson = json.decode(response.body); final bodyJson = json.decode(utf8.decode(response.bodyBytes));
if (bodyJson is List<dynamic> && bodyJson.isEmpty) { if (bodyJson is List<dynamic> && bodyJson.isEmpty) {
return []; return [];

View file

@ -1,5 +1,3 @@
import 'dart:convert';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
class CakePayCard { class CakePayCard {
@ -38,17 +36,11 @@ class CakePayCard {
}); });
factory CakePayCard.fromJson(Map<String, dynamic> json) { factory CakePayCard.fromJson(Map<String, dynamic> json) {
final name = stripHtmlIfNeeded(json['name'] as String? ?? ''); final name = stripHtmlIfNeeded(json['name'] as String? ?? '');
final decodedName = fixEncoding(name);
final description = stripHtmlIfNeeded(json['description'] as String? ?? ''); final description = stripHtmlIfNeeded(json['description'] as String? ?? '');
final decodedDescription = fixEncoding(description);
final termsAndConditions = stripHtmlIfNeeded(json['terms_and_conditions'] as String? ?? ''); final termsAndConditions = stripHtmlIfNeeded(json['terms_and_conditions'] as String? ?? '');
final decodedTermsAndConditions = fixEncoding(termsAndConditions);
final howToUse = stripHtmlIfNeeded(json['how_to_use'] as String? ?? ''); final howToUse = stripHtmlIfNeeded(json['how_to_use'] as String? ?? '');
final decodedHowToUse = fixEncoding(howToUse);
final fiatCurrency = FiatCurrency.deserialize(raw: json['currency_code'] as String? ?? ''); final fiatCurrency = FiatCurrency.deserialize(raw: json['currency_code'] as String? ?? '');
@ -59,10 +51,10 @@ class CakePayCard {
return CakePayCard( return CakePayCard(
id: json['id'] as int? ?? 0, id: json['id'] as int? ?? 0,
name: decodedName, name: name,
description: decodedDescription, description: description,
termsAndConditions: decodedTermsAndConditions, termsAndConditions: termsAndConditions,
howToUse: decodedHowToUse, howToUse: howToUse,
expiryAndValidity: json['expiry_and_validity'] as String?, expiryAndValidity: json['expiry_and_validity'] as String?,
cardImageUrl: json['card_image_url'] as String?, cardImageUrl: json['card_image_url'] as String?,
country: json['country'] as String?, country: json['country'] as String?,
@ -79,13 +71,4 @@ class CakePayCard {
static String stripHtmlIfNeeded(String text) { static String stripHtmlIfNeeded(String text) {
return text.replaceAll(RegExp(r'<[^>]*>|&[^;]+;'), ' '); return text.replaceAll(RegExp(r'<[^>]*>|&[^;]+;'), ' ');
} }
static String fixEncoding(String text) {
try {
final bytes = latin1.encode(text);
return utf8.decode(bytes, allowMalformed: true);
} catch (_) {
return text;
}
}
} }

View file

@ -1,5 +1,3 @@
import 'dart:convert';
import 'cake_pay_card.dart'; import 'cake_pay_card.dart';
class CakePayVendor { class CakePayVendor {
@ -21,7 +19,6 @@ class CakePayVendor {
factory CakePayVendor.fromJson(Map<String, dynamic> json, String country) { factory CakePayVendor.fromJson(Map<String, dynamic> json, String country) {
final name = stripHtmlIfNeeded(json['name'] as String); final name = stripHtmlIfNeeded(json['name'] as String);
final decodedName = fixEncoding(name);
var cardsJson = json['cards'] as List?; var cardsJson = json['cards'] as List?;
CakePayCard? cardForVendor; CakePayCard? cardForVendor;
@ -36,7 +33,7 @@ class CakePayVendor {
return CakePayVendor( return CakePayVendor(
id: json['id'] as int, id: json['id'] as int,
name: decodedName, name: name,
unavailable: json['unavailable'] as bool? ?? false, unavailable: json['unavailable'] as bool? ?? false,
cakeWarnings: json['cake_warnings'] as String?, cakeWarnings: json['cake_warnings'] as String?,
country: country, country: country,
@ -47,9 +44,4 @@ class CakePayVendor {
static String stripHtmlIfNeeded(String text) { static String stripHtmlIfNeeded(String text) {
return text.replaceAll(RegExp(r'<[^>]*>|&[^;]+;'), ' '); return text.replaceAll(RegExp(r'<[^>]*>|&[^;]+;'), ' ');
} }
static String fixEncoding(String text) {
final bytes = latin1.encode(text);
return utf8.decode(bytes, allowMalformed: true);
}
} }

View file

@ -35,8 +35,8 @@ const publicBitcoinTestnetElectrumUri =
'$publicBitcoinTestnetElectrumAddress:$publicBitcoinTestnetElectrumPort'; '$publicBitcoinTestnetElectrumAddress:$publicBitcoinTestnetElectrumPort';
const cakeWalletLitecoinElectrumUri = 'ltc-electrum.cakewallet.com:50002'; const cakeWalletLitecoinElectrumUri = 'ltc-electrum.cakewallet.com:50002';
const havenDefaultNodeUri = 'nodes.havenprotocol.org:443'; const havenDefaultNodeUri = 'nodes.havenprotocol.org:443';
const ethereumDefaultNodeUri = 'ethereum.publicnode.com'; const ethereumDefaultNodeUri = 'ethereum-rpc.publicnode.com';
const polygonDefaultNodeUri = 'polygon-bor.publicnode.com'; const polygonDefaultNodeUri = 'polygon-bor-rpc.publicnode.com';
const cakeWalletBitcoinCashDefaultNodeUri = 'bitcoincash.stackwallet.com:50002'; const cakeWalletBitcoinCashDefaultNodeUri = 'bitcoincash.stackwallet.com:50002';
const nanoDefaultNodeUri = 'nano.nownodes.io'; const nanoDefaultNodeUri = 'nano.nownodes.io';
const nanoDefaultPowNodeUri = 'rpc.nano.to'; const nanoDefaultPowNodeUri = 'rpc.nano.to';
@ -360,6 +360,18 @@ Future<void> defaultSettingsMigration(
'solana-rpc.publicnode.com:443', 'solana-rpc.publicnode.com:443',
], ],
); );
_updateNode(
nodes: nodes,
currentUri: "ethereum.publicnode.com",
newUri: "ethereum-rpc.publicnode.com",
useSSL: true,
);
_updateNode(
nodes: nodes,
currentUri: "polygon-bor.publicnode.com",
newUri: "polygon-bor-rpc.publicnode.com",
useSSL: true,
);
break; break;
default: default:
break; break;
@ -375,6 +387,24 @@ Future<void> defaultSettingsMigration(
await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version); await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version);
} }
void _updateNode({
required Box<Node> nodes,
required String currentUri,
String? newUri,
bool? useSSL,
}) {
for (Node node in nodes.values) {
if (node.uriRaw == currentUri) {
if (newUri != null) {
node.uriRaw = newUri;
}
if (useSSL != null) {
node.useSSL = useSSL;
}
}
}
}
Future<void> _backupHavenSeeds(Box<HavenSeedStore> havenSeedStore) async { Future<void> _backupHavenSeeds(Box<HavenSeedStore> havenSeedStore) async {
final future = haven?.backupHavenSeeds(havenSeedStore); final future = haven?.backupHavenSeeds(havenSeedStore);
if (future != null) { if (future != null) {
@ -475,7 +505,7 @@ Future<void> updateNanoNodeList({required Box<Node> nodes}) async {
]; ];
// add new nodes: // add new nodes:
for (final node in nodeList) { for (final node in nodeList) {
if (listOfNewEndpoints.contains(node.uriRaw)) { if (listOfNewEndpoints.contains(node.uriRaw) && !nodes.values.contains(node)) {
await nodes.add(node); await nodes.add(node);
} }
} }

View file

@ -244,7 +244,9 @@ class AddressResolver {
if (unstoppableDomains.any((domain) => name.trim() == domain)) { if (unstoppableDomains.any((domain) => name.trim() == domain)) {
if (settingsStore.lookupsUnstoppableDomains) { if (settingsStore.lookupsUnstoppableDomains) {
final address = await fetchUnstoppableDomainAddress(text, ticker); final address = await fetchUnstoppableDomainAddress(text, ticker);
return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text); if (address.isNotEmpty) {
return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text);
}
} }
} }
@ -260,6 +262,7 @@ class AddressResolver {
if (formattedName.contains(".")) { if (formattedName.contains(".")) {
if (settingsStore.lookupsOpenAlias) { if (settingsStore.lookupsOpenAlias) {
final txtRecord = await OpenaliasRecord.lookupOpenAliasRecord(formattedName); final txtRecord = await OpenaliasRecord.lookupOpenAliasRecord(formattedName);
if (txtRecord != null) { if (txtRecord != null) {
final record = await OpenaliasRecord.fetchAddressAndName( final record = await OpenaliasRecord.fetchAddressAndName(
formattedName: formattedName, ticker: ticker.toLowerCase(), txtRecord: txtRecord); formattedName: formattedName, ticker: ticker.toLowerCase(), txtRecord: txtRecord);

View file

@ -391,6 +391,12 @@ class CWMonero extends Monero {
return moneroWallet.exportOutputsUR(all); return moneroWallet.exportOutputsUR(all);
} }
@override
bool needExportOutputs(Object wallet, int amount) {
final moneroWallet = wallet as MoneroWallet;
return moneroWallet.needExportOutputs(amount);
}
@override @override
void monerocCheck() { void monerocCheck() {
checkIfMoneroCIsFine(); checkIfMoneroCIsFine();

View file

@ -312,6 +312,10 @@ class BuySellPage extends BasePage {
reaction((_) => buySellViewModel.isReadyToTrade, (bool isReady) { reaction((_) => buySellViewModel.isReadyToTrade, (bool isReady) {
if (isReady) { if (isReady) {
if (buySellViewModel.skipIsReadyToTradeReaction) {
buySellViewModel.skipIsReadyToTradeReaction = false;
return;
}
if (cryptoAmountController.text.isNotEmpty && if (cryptoAmountController.text.isNotEmpty &&
cryptoAmountController.text != S.current.fetching) { cryptoAmountController.text != S.current.fetching) {
buySellViewModel.changeCryptoAmount(amount: cryptoAmountController.text); buySellViewModel.changeCryptoAmount(amount: cryptoAmountController.text);

View file

@ -14,6 +14,7 @@ import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/unspent_coin_type.dart'; import 'package:cw_core/unspent_coin_type.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
class BalanceRowWidget extends StatelessWidget { class BalanceRowWidget extends StatelessWidget {
@ -76,14 +77,21 @@ class BalanceRowWidget extends StatelessWidget {
), ),
color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor, color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
), ),
child: Container( child: TextButton(
margin: const EdgeInsets.only(top: 16, left: 24, right: 8, bottom: 16), onPressed: () => Fluttertoast.showToast(
child: Column( msg: S.current.show_balance_toast,
crossAxisAlignment: CrossAxisAlignment.start, backgroundColor: Color.fromRGBO(0, 0, 0, 0.85),
children: [ ),
GestureDetector( onLongPress: () => dashboardViewModel.balanceViewModel.switchBalanceValue(),
onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(), style: TextButton.styleFrom(
child: Row( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
),
child: Container(
margin: const EdgeInsets.only(top: 10, left: 12, right: 12, bottom: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
@ -159,7 +167,7 @@ class BalanceRowWidget extends StatelessWidget {
], ],
), ),
SizedBox( SizedBox(
width: min(MediaQuery.of(context).size.width * 0.2, 100), //width: min(MediaQuery.of(context).size.width * 0.2, 100),
child: Center( child: Center(
child: Column( child: Column(
children: [ children: [
@ -201,22 +209,16 @@ class BalanceRowWidget extends StatelessWidget {
), ),
], ],
), ),
), //),
if (frozenBalance.isNotEmpty) if (frozenBalance.isNotEmpty)
GestureDetector( Column(
behavior: HitTestBehavior.opaque,
onTap: hasAdditionalBalance
? () => _showBalanceDescription(
context, S.of(context).unavailable_balance_description)
: null,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox(height: 26), SizedBox(height: 26),
Row( Row(
children: [ children: [
Text( Text(
S.of(context).unavailable_balance, S.of(context).frozen_balance,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
@ -227,14 +229,6 @@ class BalanceRowWidget extends StatelessWidget {
height: 1, height: 1,
), ),
), ),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Icon(Icons.help_outline,
size: 16,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor),
),
], ],
), ),
SizedBox(height: 8), SizedBox(height: 8),
@ -266,11 +260,8 @@ class BalanceRowWidget extends StatelessWidget {
), ),
], ],
), ),
), if (hasAdditionalBalance)
if (hasAdditionalBalance) Column(
GestureDetector(
onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox(height: 24), SizedBox(height: 24),
@ -313,8 +304,8 @@ class BalanceRowWidget extends StatelessWidget {
), ),
], ],
), ),
), ],
], ),
), ),
), ),
), ),
@ -330,12 +321,20 @@ class BalanceRowWidget extends StatelessWidget {
), ),
color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor, color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
), ),
child: Container( child: TextButton(
onPressed: () => Fluttertoast.showToast(
msg: S.current.show_balance_toast,
backgroundColor: Color.fromRGBO(0, 0, 0, 0.85),
),
onLongPress: () => dashboardViewModel.balanceViewModel.switchBalanceValue(),
style: TextButton.styleFrom(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Container( Container(
margin: const EdgeInsets.only(top: 16, left: 24, right: 8, bottom: 16), margin: const EdgeInsets.only(top: 10, left: 12, right: 12, bottom: 10),
child: Stack( child: Stack(
children: [ children: [
if (currency == CryptoCurrency.ltc) if (currency == CryptoCurrency.ltc)
@ -343,7 +342,6 @@ class BalanceRowWidget extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
Container( Container(
padding: EdgeInsets.only(right: 16, top: 0),
child: Column( child: Column(
children: [ children: [
Container( Container(
@ -374,80 +372,77 @@ class BalanceRowWidget extends StatelessWidget {
], ],
), ),
if (hasSecondAvailableBalance) if (hasSecondAvailableBalance)
GestureDetector( Row(
onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(), children: [
child: Row( Column(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
Column( children: [
crossAxisAlignment: CrossAxisAlignment.start, GestureDetector(
children: [ behavior: HitTestBehavior.opaque,
GestureDetector( onTap: () => launchUrl(
behavior: HitTestBehavior.opaque, Uri.parse(
onTap: () => launchUrl( "https://docs.cakewallet.com/cryptos/litecoin#mweb"),
Uri.parse( mode: LaunchMode.externalApplication,
"https://docs.cakewallet.com/cryptos/litecoin.html#mweb"), ),
mode: LaunchMode.externalApplication, child: Row(
), children: [
child: Row( Text(
children: [ '${secondAvailableBalanceLabel}',
Text( textAlign: TextAlign.center,
'${secondAvailableBalanceLabel}', style: TextStyle(
textAlign: TextAlign.center, fontSize: 12,
style: TextStyle( fontFamily: 'Lato',
fontSize: 12, fontWeight: FontWeight.w400,
fontFamily: 'Lato', color: Theme.of(context)
fontWeight: FontWeight.w400, .extension<BalancePageTheme>()!
.labelTextColor,
height: 1,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Icon(Icons.help_outline,
size: 16,
color: Theme.of(context) color: Theme.of(context)
.extension<BalancePageTheme>()! .extension<BalancePageTheme>()!
.labelTextColor, .labelTextColor),
height: 1, )
), ],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Icon(Icons.help_outline,
size: 16,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor),
)
],
),
), ),
SizedBox(height: 8), ),
AutoSizeText( SizedBox(height: 8),
secondAvailableBalance, AutoSizeText(
secondAvailableBalance,
style: TextStyle(
fontSize: 24,
fontFamily: 'Lato',
fontWeight: FontWeight.w900,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.assetTitleColor,
height: 1,
),
maxLines: 1,
textAlign: TextAlign.center,
),
SizedBox(height: 6),
if (!isTestnet)
Text(
'${secondAvailableFiatBalance}',
textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 24, fontSize: 16,
fontFamily: 'Lato', fontFamily: 'Lato',
fontWeight: FontWeight.w900, fontWeight: FontWeight.w500,
color: Theme.of(context) color: Theme.of(context)
.extension<BalancePageTheme>()! .extension<BalancePageTheme>()!
.assetTitleColor, .textColor,
height: 1, height: 1,
), ),
maxLines: 1,
textAlign: TextAlign.center,
), ),
SizedBox(height: 6), ],
if (!isTestnet) ),
Text( ],
'${secondAvailableFiatBalance}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontFamily: 'Lato',
fontWeight: FontWeight.w500,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.textColor,
height: 1,
),
),
],
),
],
),
), ),
], ],
), ),
@ -515,7 +510,7 @@ class BalanceRowWidget extends StatelessWidget {
), ),
IntrinsicHeight( IntrinsicHeight(
child: Container( child: Container(
padding: EdgeInsets.symmetric(horizontal: 24), padding: EdgeInsets.symmetric(horizontal: 12),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [

View file

@ -20,7 +20,8 @@ class SeedVerificationPage extends BasePage {
builder: (context) { builder: (context) {
return Padding( return Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: walletSeedViewModel.isVerificationComplete child: walletSeedViewModel.isVerificationComplete ||
walletSeedViewModel.verificationIndices.isEmpty
? SeedVerificationSuccessView( ? SeedVerificationSuccessView(
imageColor: titleColor(context), imageColor: titleColor(context),
) )

View file

@ -4,6 +4,7 @@ import 'package:cake_wallet/entities/contact_record.dart';
import 'package:cake_wallet/core/execution_state.dart'; import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/entities/template.dart'; import 'package:cake_wallet/entities/template.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart'; import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
@ -412,6 +413,20 @@ class SendPage extends BasePage {
} }
} }
if (sendViewModel.wallet.type == WalletType.monero) {
int amount = 0;
for (var item in sendViewModel.outputs) {
amount += item.formattedCryptoAmount;
}
if (monero!.needExportOutputs(sendViewModel.wallet, amount)) {
await Navigator.of(context).pushNamed(Routes.urqrAnimatedPage, arguments: 'export-outputs');
await Future.delayed(Duration(seconds: 1)); // wait for monero to refresh the state
}
if (monero!.needExportOutputs(sendViewModel.wallet, amount)) {
return;
}
}
final check = sendViewModel.shouldDisplayTotp(); final check = sendViewModel.shouldDisplayTotp();
authService.authenticateAction( authService.authenticateAction(
context, context,

View file

@ -215,6 +215,7 @@ class ExceptionHandler {
"input stream error", "input stream error",
"invalid signature", "invalid signature",
"invalid password", "invalid password",
"NetworkImage._loadAsync",
// Temporary ignored, More context: Flutter secure storage reads the values as null some times // Temporary ignored, More context: Flutter secure storage reads the values as null some times
// probably when the device was locked and then opened on Cake // probably when the device was locked and then opened on Cake
// this is solved by a restart of the app // this is solved by a restart of the app

View file

@ -1,7 +1,9 @@
import 'package:flutter/foundation.dart';
class FeatureFlag { class FeatureFlag {
static const bool isCakePayEnabled = false; static const bool isCakePayEnabled = false;
static const bool isExolixEnabled = true; static const bool isExolixEnabled = true;
static const bool isInAppTorEnabled = false; static const bool isInAppTorEnabled = false;
static const bool isBackgroundSyncEnabled = false; static const bool isBackgroundSyncEnabled = false;
static const int verificationWordsCount = 2; static const int verificationWordsCount = kDebugMode ? 0 : 2;
} }

View file

@ -149,6 +149,9 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
@observable @observable
BuySellQuotLoadingState buySellQuotState; BuySellQuotLoadingState buySellQuotState;
@observable
bool skipIsReadyToTradeReaction = false;
@computed @computed
bool get isReadyToTrade { bool get isReadyToTrade {
final hasSelectedQuote = selectedQuote != null; final hasSelectedQuote = selectedQuote != null;
@ -266,6 +269,7 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
} }
void onTapChoseProvider(BuildContext context) async { void onTapChoseProvider(BuildContext context) async {
skipIsReadyToTradeReaction = true;
final initialQuotes = List<Quote>.from(sortedRecommendedQuotes + sortedQuotes); final initialQuotes = List<Quote>.from(sortedRecommendedQuotes + sortedQuotes);
await calculateBestRate(); await calculateBestRate();
final newQuotes = (sortedRecommendedQuotes + sortedQuotes); final newQuotes = (sortedRecommendedQuotes + sortedQuotes);

View file

@ -20,7 +20,8 @@ part 'balance_view_model.g.dart';
class BalanceRecord { class BalanceRecord {
const BalanceRecord( const BalanceRecord(
{required this.availableBalance, {
required this.availableBalance,
required this.additionalBalance, required this.additionalBalance,
required this.secondAvailableBalance, required this.secondAvailableBalance,
required this.secondAdditionalBalance, required this.secondAdditionalBalance,
@ -148,26 +149,18 @@ abstract class BalanceViewModelBase with Store {
@computed @computed
String get availableBalanceLabel { String get availableBalanceLabel {
switch (wallet.type) {
case WalletType.monero: if (displayMode == BalanceDisplayMode.hiddenBalance) {
case WalletType.wownero: return S.current.show_balance;
case WalletType.haven: }
case WalletType.ethereum: else {
case WalletType.polygon: return S.current.xmr_available_balance;
case WalletType.nano:
case WalletType.banano:
case WalletType.solana:
case WalletType.tron:
case WalletType.bitcoin:
case WalletType.litecoin:
case WalletType.bitcoinCash:
case WalletType.none:
return S.current.xmr_available_balance;
} }
} }
@computed @computed
String get additionalBalanceLabel { String get additionalBalanceLabel {
switch (wallet.type) { switch (wallet.type) {
case WalletType.haven: case WalletType.haven:
case WalletType.ethereum: case WalletType.ethereum:
@ -203,98 +196,35 @@ abstract class BalanceViewModelBase with Store {
} }
} }
@computed
bool get hasMultiBalance => appStore.wallet!.type == WalletType.haven;
@computed
String get availableBalance {
final walletBalance = _walletBalance;
if (displayMode == BalanceDisplayMode.hiddenBalance) {
return '---';
}
return walletBalance.formattedAvailableBalance;
}
@computed
String get frozenBalance {
final walletBalance = _walletBalance;
if (displayMode == BalanceDisplayMode.hiddenBalance) {
return '---';
}
return getFormattedFrozenBalance(walletBalance);
}
@computed
String get frozenFiatBalance {
final walletBalance = _walletBalance;
final fiatCurrency = settingsStore.fiatCurrency;
if (displayMode == BalanceDisplayMode.hiddenBalance) {
return '---';
}
return _getFiatBalance(price: price, cryptoAmount: getFormattedFrozenBalance(walletBalance)) +
' ${fiatCurrency.toString()}';
}
@computed @computed
String get additionalBalance { String get additionalBalance {
final walletBalance = _walletBalance; final walletBalance = _walletBalance;
if (displayMode == BalanceDisplayMode.hiddenBalance) { if (displayMode == BalanceDisplayMode.hiddenBalance) {
return '---'; return '0.0';
} }
return walletBalance.formattedAdditionalBalance; return walletBalance.formattedAdditionalBalance;
} }
@computed
String get availableFiatBalance {
final walletBalance = _walletBalance;
final fiatCurrency = settingsStore.fiatCurrency;
if (displayMode == BalanceDisplayMode.hiddenBalance) {
return '---';
}
return _getFiatBalance(price: price, cryptoAmount: walletBalance.formattedAvailableBalance) +
' ${fiatCurrency.toString()}';
}
@computed
String get additionalFiatBalance {
final walletBalance = _walletBalance;
final fiatCurrency = settingsStore.fiatCurrency;
if (displayMode == BalanceDisplayMode.hiddenBalance) {
return '---';
}
return _getFiatBalance(price: price, cryptoAmount: walletBalance.formattedAdditionalBalance) +
' ${fiatCurrency.toString()}';
}
@computed @computed
Map<CryptoCurrency, BalanceRecord> get balances { Map<CryptoCurrency, BalanceRecord> get balances {
return wallet.balance.map((key, value) { return wallet.balance.map((key, value) {
if (displayMode == BalanceDisplayMode.hiddenBalance) { if (displayMode == BalanceDisplayMode.hiddenBalance) {
final fiatCurrency = settingsStore.fiatCurrency;
return MapEntry( return MapEntry(
key, key,
BalanceRecord( BalanceRecord(
availableBalance: '---', availableBalance: '●●●●●●',
additionalBalance: '---', additionalBalance: additionalBalance,
frozenBalance: '', frozenBalance: '',
secondAvailableBalance: '---', secondAvailableBalance: '●●●●●●',
secondAdditionalBalance: '---', secondAdditionalBalance: '●●●●●●',
fiatAdditionalBalance: isFiatDisabled ? '' : '---', fiatAdditionalBalance: isFiatDisabled ? '' : '${fiatCurrency.toString()} ●●●●●',
fiatAvailableBalance: isFiatDisabled ? '' : '---', fiatAvailableBalance: isFiatDisabled ? '' : '${fiatCurrency.toString()} ●●●●●',
fiatFrozenBalance: isFiatDisabled ? '' : '---', fiatFrozenBalance: isFiatDisabled ? '' : '',
fiatSecondAvailableBalance: isFiatDisabled ? '' : '---', fiatSecondAvailableBalance: isFiatDisabled ? '' : '${fiatCurrency.toString()} ●●●●●',
fiatSecondAdditionalBalance: isFiatDisabled ? '' : '---', fiatSecondAdditionalBalance: isFiatDisabled ? '' : '${fiatCurrency.toString()} ●●●●●',
asset: key, asset: key,
formattedAssetTitle: _formatterAsset(key))); formattedAssetTitle: _formatterAsset(key)));
} }
@ -374,16 +304,11 @@ abstract class BalanceViewModelBase with Store {
bool _hasAdditionalBalanceForWalletType(WalletType type) { bool _hasAdditionalBalanceForWalletType(WalletType type) {
switch (type) { switch (type) {
case WalletType.ethereum: case WalletType.monero:
case WalletType.polygon: case WalletType.wownero:
case WalletType.solana:
case WalletType.tron:
case WalletType.bitcoin:
case WalletType.bitcoinCash:
case WalletType.litecoin:
return false;
default:
return true; return true;
default:
return false;
} }
} }
@ -468,8 +393,6 @@ abstract class BalanceViewModelBase with Store {
return balance; return balance;
} }
@computed
CryptoCurrency get currency => appStore.wallet!.currency;
@observable @observable
bool isShowCard; bool isShowCard;

View file

@ -641,7 +641,7 @@ abstract class DashboardViewModelBase with Store {
transactions.clear(); transactions.clear();
transactions = ObservableList.of( transactions.addAll(
wallet.transactionHistory.transactions.values.map( wallet.transactionHistory.transactions.values.map(
(transaction) => TransactionListItem( (transaction) => TransactionListItem(
transaction: transaction, transaction: transaction,
@ -703,7 +703,7 @@ abstract class DashboardViewModelBase with Store {
monero!.getTransactionInfoAccountId(tx) == monero!.getCurrentAccount(wallet).id) monero!.getTransactionInfoAccountId(tx) == monero!.getCurrentAccount(wallet).id)
.toList(); .toList();
transactions = ObservableList.of( transactions.addAll(
_accountTransactions.map( _accountTransactions.map(
(transaction) => TransactionListItem( (transaction) => TransactionListItem(
transaction: transaction, transaction: transaction,
@ -723,7 +723,7 @@ abstract class DashboardViewModelBase with Store {
wow.wownero!.getCurrentAccount(wallet).id) wow.wownero!.getCurrentAccount(wallet).id)
.toList(); .toList();
transactions = ObservableList.of( transactions.addAll(
_accountTransactions.map( _accountTransactions.map(
(transaction) => TransactionListItem( (transaction) => TransactionListItem(
transaction: transaction, transaction: transaction,

View file

@ -9,6 +9,7 @@ import 'package:cake_wallet/exchange/provider/stealth_ex_exchange_provider.dart'
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/sync_status.dart'; import 'package:cw_core/sync_status.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/unspent_coin_type.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
@ -122,7 +123,8 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
depositAmount = ''; depositAmount = '';
receiveAmount = ''; receiveAmount = '';
receiveAddress = ''; receiveAddress = '';
depositAddress = depositCurrency == wallet.currency ? wallet.walletAddresses.addressForExchange : ''; depositAddress =
depositCurrency == wallet.currency ? wallet.walletAddresses.addressForExchange : '';
provider = providersForCurrentPair().first; provider = providersForCurrentPair().first;
final initialProvider = provider; final initialProvider = provider;
provider!.checkIsAvailable().then((bool isAvailable) { provider!.checkIsAvailable().then((bool isAvailable) {
@ -157,8 +159,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
wallet.type == WalletType.bitcoinCash; wallet.type == WalletType.bitcoinCash;
bool get hideAddressAfterExchange => bool get hideAddressAfterExchange =>
wallet.type == WalletType.monero || wallet.type == WalletType.monero || wallet.type == WalletType.wownero;
wallet.type == WalletType.wownero;
bool _useTorOnly; bool _useTorOnly;
final Box<Trade> trades; final Box<Trade> trades;
@ -167,17 +168,17 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
final SharedPreferences sharedPreferences; final SharedPreferences sharedPreferences;
List<ExchangeProvider> get _allProviders => [ List<ExchangeProvider> get _allProviders => [
ChangeNowExchangeProvider(settingsStore: _settingsStore), ChangeNowExchangeProvider(settingsStore: _settingsStore),
SideShiftExchangeProvider(), SideShiftExchangeProvider(),
SimpleSwapExchangeProvider(), SimpleSwapExchangeProvider(),
ThorChainExchangeProvider(tradesStore: trades), ThorChainExchangeProvider(tradesStore: trades),
if (FeatureFlag.isExolixEnabled) ExolixExchangeProvider(), if (FeatureFlag.isExolixEnabled) ExolixExchangeProvider(),
QuantexExchangeProvider(), QuantexExchangeProvider(),
LetsExchangeExchangeProvider(), LetsExchangeExchangeProvider(),
StealthExExchangeProvider(), StealthExExchangeProvider(),
TrocadorExchangeProvider( TrocadorExchangeProvider(
useTorOnly: _useTorOnly, providerStates: _settingsStore.trocadorProviderStates), useTorOnly: _useTorOnly, providerStates: _settingsStore.trocadorProviderStates),
]; ];
@observable @observable
ExchangeProvider? provider; ExchangeProvider? provider;
@ -613,8 +614,10 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
isReceiveAmountEntered = false; isReceiveAmountEntered = false;
depositAmount = ''; depositAmount = '';
receiveAmount = ''; receiveAmount = '';
depositAddress = depositCurrency == wallet.currency ? wallet.walletAddresses.addressForExchange : ''; depositAddress =
receiveAddress = receiveCurrency == wallet.currency ? wallet.walletAddresses.addressForExchange : ''; depositCurrency == wallet.currency ? wallet.walletAddresses.addressForExchange : '';
receiveAddress =
receiveCurrency == wallet.currency ? wallet.walletAddresses.addressForExchange : '';
isDepositAddressEnabled = !(depositCurrency == wallet.currency); isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isFixedRateMode = false; isFixedRateMode = false;
_onPairChange(); _onPairChange();
@ -640,7 +643,12 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
wallet.type == WalletType.bitcoinCash) { wallet.type == WalletType.bitcoinCash) {
final priority = _settingsStore.priority[wallet.type]!; final priority = _settingsStore.priority[wallet.type]!;
final amount = await bitcoin!.estimateFakeSendAllTxAmount(wallet, priority); final amount = await bitcoin!.estimateFakeSendAllTxAmount(
wallet,
priority,
coinTypeToSpendFrom:
wallet.type == WalletType.litecoin ? UnspentCoinType.nonMweb : UnspentCoinType.any,
);
changeDepositAmount(amount: bitcoin!.formatterBitcoinAmountToString(amount: amount)); changeDepositAmount(amount: bitcoin!.formatterBitcoinAmountToString(amount: amount));
} }

View file

@ -394,7 +394,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
if (wallet.isHardwareWallet) state = IsAwaitingDeviceResponseState(); if (wallet.isHardwareWallet) state = IsAwaitingDeviceResponseState();
pendingTransaction = await wallet.createTransaction(_credentials()); pendingTransaction = await wallet.createTransaction(_credentials(provider));
if (provider is ThorChainExchangeProvider) { if (provider is ThorChainExchangeProvider) {
final outputCount = pendingTransaction?.outputCount ?? 0; final outputCount = pendingTransaction?.outputCount ?? 0;
@ -522,7 +522,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
void setTransactionPriority(TransactionPriority priority) => void setTransactionPriority(TransactionPriority priority) =>
_settingsStore.priority[wallet.type] = priority; _settingsStore.priority[wallet.type] = priority;
Object _credentials() { Object _credentials([ExchangeProvider? provider]) {
final priority = _settingsStore.priority[wallet.type]; final priority = _settingsStore.priority[wallet.type];
if (priority == null && if (priority == null &&
@ -535,7 +535,6 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
switch (wallet.type) { switch (wallet.type) {
case WalletType.bitcoin: case WalletType.bitcoin:
case WalletType.litecoin:
case WalletType.bitcoinCash: case WalletType.bitcoinCash:
return bitcoin!.createBitcoinTransactionCredentials( return bitcoin!.createBitcoinTransactionCredentials(
outputs, outputs,
@ -543,6 +542,14 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
feeRate: customBitcoinFeeRate, feeRate: customBitcoinFeeRate,
coinTypeToSpendFrom: coinTypeToSpendFrom, coinTypeToSpendFrom: coinTypeToSpendFrom,
); );
case WalletType.litecoin:
return bitcoin!.createBitcoinTransactionCredentials(
outputs,
priority: priority!,
feeRate: customBitcoinFeeRate,
// if it's an exchange flow then disable sending from mweb coins
coinTypeToSpendFrom: provider != null ? UnspentCoinType.nonMweb : coinTypeToSpendFrom,
);
case WalletType.monero: case WalletType.monero:
return monero! return monero!

View file

@ -29,6 +29,7 @@ abstract class WalletSeedViewModelBase with Store {
List<String> get seedSplit => seed.split(RegExp(r'\s+')); List<String> get seedSplit => seed.split(RegExp(r'\s+'));
int get columnCount => seedSplit.length <= 16 ? 2 : 3; int get columnCount => seedSplit.length <= 16 ? 2 : 3;
double get columnAspectRatio => seedSplit.length <= 16 ? 1.8 : 2.8; double get columnAspectRatio => seedSplit.length <= 16 ? 1.8 : 2.8;
/// The indices of the seed to be verified. /// The indices of the seed to be verified.
@ -60,8 +61,10 @@ abstract class WalletSeedViewModelBase with Store {
bool isVerificationComplete = false; bool isVerificationComplete = false;
void setupSeedVerification() { void setupSeedVerification() {
generateRandomIndices(); if (verificationWordCount != 0) {
generateOptions(); generateRandomIndices();
generateOptions();
}
} }
/// Generate the indices of the seeds to be verified. /// Generate the indices of the seeds to be verified.

View file

@ -40,11 +40,11 @@ static void my_application_activate(GApplication* application) {
if (use_header_bar) { if (use_header_bar) {
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
gtk_widget_show(GTK_WIDGET(header_bar)); gtk_widget_show(GTK_WIDGET(header_bar));
gtk_header_bar_set_title(header_bar, "cake_wallet"); gtk_header_bar_set_title(header_bar, "Cake Wallet");
gtk_header_bar_set_show_close_button(header_bar, TRUE); gtk_header_bar_set_show_close_button(header_bar, TRUE);
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
} else { } else {
gtk_window_set_title(window, "cake_wallet"); gtk_window_set_title(window, "Cake Wallet");
} }
gtk_window_set_default_size(window, 1280, 720); gtk_window_set_default_size(window, 1280, 720);

View file

@ -730,6 +730,8 @@
"shared_seed_wallet_groups": "مجموعات محفظة البذور المشتركة", "shared_seed_wallet_groups": "مجموعات محفظة البذور المشتركة",
"show": "يعرض", "show": "يعرض",
"show_address_book_popup": "عرض \"إضافة إلى كتاب العناوين\" المنبثقة بعد الإرسال", "show_address_book_popup": "عرض \"إضافة إلى كتاب العناوين\" المنبثقة بعد الإرسال",
"show_balance": "اضغط لفترة طويلة لإظهار التوازن",
"show_balance_toast": "اضغط لفترة طويلة لإخفاء أو إظهار التوازن",
"show_details": "اظهر التفاصيل", "show_details": "اظهر التفاصيل",
"show_keys": "اظهار السييد / المفاتيح", "show_keys": "اظهار السييد / المفاتيح",
"show_market_place": "إظهار السوق", "show_market_place": "إظهار السوق",

View file

@ -730,6 +730,8 @@
"shared_seed_wallet_groups": "Споделени групи за портфейли за семена", "shared_seed_wallet_groups": "Споделени групи за портфейли за семена",
"show": "Показване", "show": "Показване",
"show_address_book_popup": "Показване на изскачането на „Добавяне към адресната книга“ след изпращане", "show_address_book_popup": "Показване на изскачането на „Добавяне към адресната книга“ след изпращане",
"show_balance": "Дълго натиснете, за да покажете баланса",
"show_balance_toast": "Дълго натискане, за да се скрие или покаже баланс",
"show_details": "Показване на подробностите", "show_details": "Показване на подробностите",
"show_keys": "Покажи seed/keys", "show_keys": "Покажи seed/keys",
"show_market_place": "Покажи пазар", "show_market_place": "Покажи пазар",

View file

@ -730,6 +730,8 @@
"shared_seed_wallet_groups": "Skupiny sdílených semen", "shared_seed_wallet_groups": "Skupiny sdílených semen",
"show": "Show", "show": "Show",
"show_address_book_popup": "Po odeslání zobrazíte vyskakovací okno „Přidat do adresáře“", "show_address_book_popup": "Po odeslání zobrazíte vyskakovací okno „Přidat do adresáře“",
"show_balance": "Dlouhý stisknutí zobrazí rovnováhu",
"show_balance_toast": "Dlouhý stiskněte pro skrytí nebo zobrazení rovnováhy",
"show_details": "Zobrazit detaily", "show_details": "Zobrazit detaily",
"show_keys": "Zobrazit seed/klíče", "show_keys": "Zobrazit seed/klíče",
"show_market_place": "Zobrazit trh", "show_market_place": "Zobrazit trh",

View file

@ -511,8 +511,8 @@
"placeholder_transactions": "Ihre Transaktionen werden hier angezeigt", "placeholder_transactions": "Ihre Transaktionen werden hier angezeigt",
"please_fill_totp": "Bitte geben Sie den 8-stelligen Code ein, der auf Ihrem anderen Gerät vorhanden ist", "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_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": "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": "Bitte auswählen:",
"please_select_backup_file": "Bitte wählen Sie die Sicherungsdatei und geben Sie das Sicherungskennwort ein.", "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", "please_try_to_connect_to_another_node": "Bitte versuchen Sie, sich mit einem anderen Knoten zu verbinden",
@ -731,6 +731,8 @@
"shared_seed_wallet_groups": "Gemeinsame Walletsseed Gruppen", "shared_seed_wallet_groups": "Gemeinsame Walletsseed Gruppen",
"show": "Zeigen", "show": "Zeigen",
"show_address_book_popup": "Popup \"zum Adressbuch hinzufügen\" nach dem Senden anzeigen", "show_address_book_popup": "Popup \"zum Adressbuch hinzufügen\" nach dem Senden anzeigen",
"show_balance": "Lange Presse, um das Gleichgewicht zu zeigen",
"show_balance_toast": "Lange Presse, um sich zu verbergen oder Gleichgewicht zu zeigen",
"show_details": "Details anzeigen", "show_details": "Details anzeigen",
"show_keys": "Seed/Schlüssel anzeigen", "show_keys": "Seed/Schlüssel anzeigen",
"show_market_place": "Marktplatz anzeigen", "show_market_place": "Marktplatz anzeigen",
@ -989,4 +991,4 @@
"you_will_get": "Konvertieren zu", "you_will_get": "Konvertieren zu",
"you_will_send": "Konvertieren von", "you_will_send": "Konvertieren von",
"yy": "YY" "yy": "YY"
} }

View file

@ -730,6 +730,8 @@
"shared_seed_wallet_groups": "Shared Seed Wallet Groups", "shared_seed_wallet_groups": "Shared Seed Wallet Groups",
"show": "Show", "show": "Show",
"show_address_book_popup": "Show 'Add to Address Book' popup after sending", "show_address_book_popup": "Show 'Add to Address Book' popup after sending",
"show_balance": "Long Press to Show Balance",
"show_balance_toast": "Long press to hide or show balance",
"show_details": "Show Details", "show_details": "Show Details",
"show_keys": "Show seed/keys", "show_keys": "Show seed/keys",
"show_market_place": "Show Marketplace", "show_market_place": "Show Marketplace",

View file

@ -731,6 +731,8 @@
"shared_seed_wallet_groups": "Grupos de billetera de semillas compartidas", "shared_seed_wallet_groups": "Grupos de billetera de semillas compartidas",
"show": "Espectáculo", "show": "Espectáculo",
"show_address_book_popup": "Mostrar ventana emergente 'Agregar a la libreta de direcciones' después de enviar", "show_address_book_popup": "Mostrar ventana emergente 'Agregar a la libreta de direcciones' después de enviar",
"show_balance": "Prensa larga para mostrar equilibrio",
"show_balance_toast": "Prensa larga para esconder o mostrar equilibrio",
"show_details": "Mostrar detalles", "show_details": "Mostrar detalles",
"show_keys": "Mostrar semilla/claves", "show_keys": "Mostrar semilla/claves",
"show_market_place": "Mostrar mercado", "show_market_place": "Mostrar mercado",

View file

@ -730,6 +730,8 @@
"shared_seed_wallet_groups": "Groupes de portefeuilles partagés", "shared_seed_wallet_groups": "Groupes de portefeuilles partagés",
"show": "Montrer", "show": "Montrer",
"show_address_book_popup": "Afficher la popup `` Ajouter au carnet d'adresses '' après avoir envoyé", "show_address_book_popup": "Afficher la popup `` Ajouter au carnet d'adresses '' après avoir envoyé",
"show_balance": "Longue presse pour montrer l'équilibre",
"show_balance_toast": "Longue appuyez sur pour masquer ou afficher l'équilibre",
"show_details": "Afficher les détails", "show_details": "Afficher les détails",
"show_keys": "Visualiser la phrase secrète (seed) et les clefs", "show_keys": "Visualiser la phrase secrète (seed) et les clefs",
"show_market_place": "Afficher la place de marché", "show_market_place": "Afficher la place de marché",

View file

@ -732,6 +732,8 @@
"shared_seed_wallet_groups": "Raba ƙungiya walat", "shared_seed_wallet_groups": "Raba ƙungiya walat",
"show": "Nuna", "show": "Nuna",
"show_address_book_popup": "Nuna 'ƙara don magance littafin' Popup bayan aikawa", "show_address_book_popup": "Nuna 'ƙara don magance littafin' Popup bayan aikawa",
"show_balance": "Dogon latsawa don nuna ma'auni",
"show_balance_toast": "Latsa latsawa don ɓoye ko nuna ma'auni",
"show_details": "Nuna Cikakkun bayanai", "show_details": "Nuna Cikakkun bayanai",
"show_keys": "Nuna iri/maɓallai", "show_keys": "Nuna iri/maɓallai",
"show_market_place": "Nuna dan kasuwa", "show_market_place": "Nuna dan kasuwa",

View file

@ -732,6 +732,8 @@
"shared_seed_wallet_groups": "साझा बीज बटुए समूह", "shared_seed_wallet_groups": "साझा बीज बटुए समूह",
"show": "दिखाओ", "show": "दिखाओ",
"show_address_book_popup": "भेजने के बाद 'एड एड्रेस बुक' पॉपअप दिखाएं", "show_address_book_popup": "भेजने के बाद 'एड एड्रेस बुक' पॉपअप दिखाएं",
"show_balance": "बैलेंस दिखाने के लिए लॉन्ग प्रेस",
"show_balance_toast": "बैलेंस को छिपाने या दिखाने के लिए लॉन्ग प्रेस",
"show_details": "विवरण दिखाएं", "show_details": "विवरण दिखाएं",
"show_keys": "बीज / कुंजियाँ दिखाएँ", "show_keys": "बीज / कुंजियाँ दिखाएँ",
"show_market_place": "बाज़ार दिखाएँ", "show_market_place": "बाज़ार दिखाएँ",

View file

@ -730,6 +730,8 @@
"shared_seed_wallet_groups": "Zajedničke grupe za sjeme novčanika", "shared_seed_wallet_groups": "Zajedničke grupe za sjeme novčanika",
"show": "Pokazati", "show": "Pokazati",
"show_address_book_popup": "Pokažite \"dodaj u adresar\" skočni prozor nakon slanja", "show_address_book_popup": "Pokažite \"dodaj u adresar\" skočni prozor nakon slanja",
"show_balance": "Dugački pritisak za pokazivanje ravnoteže",
"show_balance_toast": "Dugo pritisnite da biste sakrili ili pokazali ravnotežu",
"show_details": "Prikaži pojedinosti", "show_details": "Prikaži pojedinosti",
"show_keys": "Prikaži pristupni izraz/ključ", "show_keys": "Prikaži pristupni izraz/ključ",
"show_market_place": "Prikaži tržište", "show_market_place": "Prikaži tržište",

View file

@ -730,6 +730,8 @@
"shared_seed_wallet_groups": "Համօգտագործված սերմերի դրամապանակների խմբեր", "shared_seed_wallet_groups": "Համօգտագործված սերմերի դրամապանակների խմբեր",
"show": "Ցուցահանդես", "show": "Ցուցահանդես",
"show_address_book_popup": "Show ույց տալ «Ուղարկելուց հետո« Հասցեների գրքի »թռուցիկ", "show_address_book_popup": "Show ույց տալ «Ուղարկելուց հետո« Հասցեների գրքի »թռուցիկ",
"show_balance": "Երկար մամուլ, հավասարակշռությունը ցույց տալու համար",
"show_balance_toast": "Երկար սեղմեք `հավասարակշռությունը թաքցնելու կամ ցույց տալու համար",
"show_details": "Ցուցադրել մանրամասներ", "show_details": "Ցուցադրել մանրամասներ",
"show_keys": "Ցուցադրել բանալիներ", "show_keys": "Ցուցադրել բանալիներ",
"show_market_place": "Ցուցադրել շուկան", "show_market_place": "Ցուցադրել շուկան",

View file

@ -733,6 +733,8 @@
"shared_seed_wallet_groups": "Kelompok dompet benih bersama", "shared_seed_wallet_groups": "Kelompok dompet benih bersama",
"show": "Menunjukkan", "show": "Menunjukkan",
"show_address_book_popup": "Tampilkan popup 'Tambahkan ke Alamat' setelah mengirim", "show_address_book_popup": "Tampilkan popup 'Tambahkan ke Alamat' setelah mengirim",
"show_balance": "PRESS PANJANG UNTUK MENUNJUKKAN Balance",
"show_balance_toast": "Tekan panjang untuk menyembunyikan atau menunjukkan keseimbangan",
"show_details": "Tampilkan Rincian", "show_details": "Tampilkan Rincian",
"show_keys": "Tampilkan seed/kunci", "show_keys": "Tampilkan seed/kunci",
"show_market_place": "Tampilkan Pasar", "show_market_place": "Tampilkan Pasar",

View file

@ -732,6 +732,8 @@
"shared_seed_wallet_groups": "Gruppi di portafoglio di semi condivisi", "shared_seed_wallet_groups": "Gruppi di portafoglio di semi condivisi",
"show": "Spettacolo", "show": "Spettacolo",
"show_address_book_popup": "Mostra il popup \"Aggiungi alla rubrica\" dopo l'invio", "show_address_book_popup": "Mostra il popup \"Aggiungi alla rubrica\" dopo l'invio",
"show_balance": "Lunga stampa per mostrare l'equilibrio",
"show_balance_toast": "A lungo pressa per nascondere o mostrare l'equilibrio",
"show_details": "Mostra dettagli", "show_details": "Mostra dettagli",
"show_keys": "Mostra seme/chiavi", "show_keys": "Mostra seme/chiavi",
"show_market_place": "Mostra mercato", "show_market_place": "Mostra mercato",

View file

@ -731,6 +731,8 @@
"shared_seed_wallet_groups": "共有シードウォレットグループ", "shared_seed_wallet_groups": "共有シードウォレットグループ",
"show": "見せる", "show": "見せる",
"show_address_book_popup": "送信後に「アドレスブックに追加」ポップアップを表示します", "show_address_book_popup": "送信後に「アドレスブックに追加」ポップアップを表示します",
"show_balance": "バランスを示すためにロングプレス",
"show_balance_toast": "バランスを隠したり表示したりするためにロングプレス",
"show_details": "詳細を表示", "show_details": "詳細を表示",
"show_keys": "シード/キーを表示する", "show_keys": "シード/キーを表示する",
"show_market_place": "マーケットプレイスを表示", "show_market_place": "マーケットプレイスを表示",

View file

@ -511,8 +511,8 @@
"placeholder_transactions": "거래가 여기에 표시됩니다", "placeholder_transactions": "거래가 여기에 표시됩니다",
"please_fill_totp": "다른 기기에 있는 8자리 코드를 입력하세요.", "please_fill_totp": "다른 기기에 있는 8자리 코드를 입력하세요.",
"please_make_selection": "아래에서 선택하십시오 지갑 만들기 또는 복구.", "please_make_selection": "아래에서 선택하십시오 지갑 만들기 또는 복구.",
"Please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.",
"please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.", "please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.",
"Please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.",
"please_select": "선택 해주세요:", "please_select": "선택 해주세요:",
"please_select_backup_file": "백업 파일을 선택하고 백업 암호를 입력하십시오.", "please_select_backup_file": "백업 파일을 선택하고 백업 암호를 입력하십시오.",
"please_try_to_connect_to_another_node": "다른 노드에 연결을 시도하십시오", "please_try_to_connect_to_another_node": "다른 노드에 연결을 시도하십시오",
@ -731,6 +731,8 @@
"shared_seed_wallet_groups": "공유 종자 지갑 그룹", "shared_seed_wallet_groups": "공유 종자 지갑 그룹",
"show": "보여주다", "show": "보여주다",
"show_address_book_popup": "전송 후 '주소 책에 추가'팝업을 표시하십시오", "show_address_book_popup": "전송 후 '주소 책에 추가'팝업을 표시하십시오",
"show_balance": "균형을 보여주기 위해 긴 언론",
"show_balance_toast": "균형을 숨기거나 보여주기 위해 긴 누르십시오",
"show_details": "세부정보 표시", "show_details": "세부정보 표시",
"show_keys": "시드 / 키 표시", "show_keys": "시드 / 키 표시",
"show_market_place": "마켓플레이스 표시", "show_market_place": "마켓플레이스 표시",

View file

@ -730,6 +730,8 @@
"shared_seed_wallet_groups": "shared မျိုးစေ့ပိုက်ဆံအိတ်အုပ်စုများ", "shared_seed_wallet_groups": "shared မျိုးစေ့ပိုက်ဆံအိတ်အုပ်စုများ",
"show": "ပြသ", "show": "ပြသ",
"show_address_book_popup": "ပေးပို့ပြီးနောက် 'address book' popup ကိုပြပါ", "show_address_book_popup": "ပေးပို့ပြီးနောက် 'address book' popup ကိုပြပါ",
"show_balance": "ချိန်ခွင်လျှာကိုပြသရန်ရှည်လျားသောစာနယ်ဇင်း",
"show_balance_toast": "ချိန်ခွင်လျှာကိုဖျောက်ရန်သို့မဟုတ်ပြသရန်ရှည်လျားသောစာနယ်ဇင်း",
"show_details": "အသေးစိတ်ပြ", "show_details": "အသေးစိတ်ပြ",
"show_keys": "မျိုးစေ့ /သော့များကို ပြပါ။", "show_keys": "မျိုးစေ့ /သော့များကို ပြပါ။",
"show_market_place": "စျေးကွက်ကိုပြသပါ။", "show_market_place": "စျေးကွက်ကိုပြသပါ။",

View file

@ -730,6 +730,8 @@
"shared_seed_wallet_groups": "Gedeelde zaadportelgroepen", "shared_seed_wallet_groups": "Gedeelde zaadportelgroepen",
"show": "Show", "show": "Show",
"show_address_book_popup": "Toon 'Toevoegen aan adresboek' pop -up na verzenden", "show_address_book_popup": "Toon 'Toevoegen aan adresboek' pop -up na verzenden",
"show_balance": "Lange pers om evenwicht te tonen",
"show_balance_toast": "Lange pers om evenwicht te verbergen of te tonen",
"show_details": "Toon details", "show_details": "Toon details",
"show_keys": "Toon zaad/sleutels", "show_keys": "Toon zaad/sleutels",
"show_market_place": "Toon Marktplaats", "show_market_place": "Toon Marktplaats",

View file

@ -730,6 +730,8 @@
"shared_seed_wallet_groups": "Wspólne grupy portfeli nasion", "shared_seed_wallet_groups": "Wspólne grupy portfeli nasion",
"show": "Pokazywać", "show": "Pokazywać",
"show_address_book_popup": "Pokaż wysypkę „Dodaj do książki” po wysłaniu", "show_address_book_popup": "Pokaż wysypkę „Dodaj do książki” po wysłaniu",
"show_balance": "Długa prasa, aby pokazać równowagę",
"show_balance_toast": "Długa naciśnij, aby ukryć lub pokazać równowagę",
"show_details": "Pokaż szczegóły", "show_details": "Pokaż szczegóły",
"show_keys": "Pokaż seed/klucze", "show_keys": "Pokaż seed/klucze",
"show_market_place": "Pokaż rynek", "show_market_place": "Pokaż rynek",

View file

@ -732,6 +732,8 @@
"shared_seed_wallet_groups": "Grupos de carteira de sementes compartilhados", "shared_seed_wallet_groups": "Grupos de carteira de sementes compartilhados",
"show": "Mostrar", "show": "Mostrar",
"show_address_book_popup": "Mostre pop -up 'Adicionar ao livro de endereços' depois de enviar", "show_address_book_popup": "Mostre pop -up 'Adicionar ao livro de endereços' depois de enviar",
"show_balance": "Pressione há muito tempo para mostrar o equilíbrio",
"show_balance_toast": "Pressione há muito tempo para se esconder ou mostrar equilíbrio",
"show_details": "Mostrar detalhes", "show_details": "Mostrar detalhes",
"show_keys": "Mostrar semente/chaves", "show_keys": "Mostrar semente/chaves",
"show_market_place": "Mostrar mercado", "show_market_place": "Mostrar mercado",

View file

@ -731,6 +731,8 @@
"shared_seed_wallet_groups": "Общие группы кошелька семян", "shared_seed_wallet_groups": "Общие группы кошелька семян",
"show": "Показывать", "show": "Показывать",
"show_address_book_popup": "Покажите всплывающее окно «Добавить в адрес адреса» после отправки", "show_address_book_popup": "Покажите всплывающее окно «Добавить в адрес адреса» после отправки",
"show_balance": "Длинная пресса, чтобы показать баланс",
"show_balance_toast": "Длинная нажавка, чтобы скрыть или показать баланс",
"show_details": "Показать детали", "show_details": "Показать детали",
"show_keys": "Показать мнемоническую фразу/ключи", "show_keys": "Показать мнемоническую фразу/ключи",
"show_market_place": "Показать торговую площадку", "show_market_place": "Показать торговую площадку",

View file

@ -730,6 +730,8 @@
"shared_seed_wallet_groups": "กลุ่มกระเป๋าเงินที่ใช้ร่วมกัน", "shared_seed_wallet_groups": "กลุ่มกระเป๋าเงินที่ใช้ร่วมกัน",
"show": "แสดง", "show": "แสดง",
"show_address_book_popup": "แสดง 'เพิ่มในสมุดรายชื่อ' ป๊อปอัพหลังจากส่ง", "show_address_book_popup": "แสดง 'เพิ่มในสมุดรายชื่อ' ป๊อปอัพหลังจากส่ง",
"show_balance": "กดยาวเพื่อแสดงความสมดุล",
"show_balance_toast": "กดนานเพื่อซ่อนหรือแสดงความสมดุล",
"show_details": "แสดงรายละเอียด", "show_details": "แสดงรายละเอียด",
"show_keys": "แสดงซีด/คีย์", "show_keys": "แสดงซีด/คีย์",
"show_market_place": "แสดงตลาดกลาง", "show_market_place": "แสดงตลาดกลาง",

View file

@ -730,6 +730,8 @@
"shared_seed_wallet_groups": "Ibinahaging mga pangkat ng pitaka ng binhi", "shared_seed_wallet_groups": "Ibinahaging mga pangkat ng pitaka ng binhi",
"show": "Ipakita", "show": "Ipakita",
"show_address_book_popup": "Ipakita ang popup na 'Idagdag sa Address Book' pagkatapos magpadala", "show_address_book_popup": "Ipakita ang popup na 'Idagdag sa Address Book' pagkatapos magpadala",
"show_balance": "Mahabang pindutin upang ipakita ang balanse",
"show_balance_toast": "Mahabang pindutin upang itago o ipakita ang balanse",
"show_details": "Ipakita ang mga detalye", "show_details": "Ipakita ang mga detalye",
"show_keys": "Ipakita ang mga seed/key", "show_keys": "Ipakita ang mga seed/key",
"show_market_place": "Ipakita ang Marketplace", "show_market_place": "Ipakita ang Marketplace",

View file

@ -730,6 +730,8 @@
"shared_seed_wallet_groups": "Paylaşılan tohum cüzdan grupları", "shared_seed_wallet_groups": "Paylaşılan tohum cüzdan grupları",
"show": "Göstermek", "show": "Göstermek",
"show_address_book_popup": "Gönderdikten sonra 'adres defterine ekle' açılır", "show_address_book_popup": "Gönderdikten sonra 'adres defterine ekle' açılır",
"show_balance": "Dengeyi Göstermek İçin Uzun Basın",
"show_balance_toast": "Dengeyi gizlemek veya göstermek için uzun basın",
"show_details": "Detayları Göster", "show_details": "Detayları Göster",
"show_keys": "Tohumları/anahtarları göster", "show_keys": "Tohumları/anahtarları göster",
"show_market_place": "Pazar Yerini Göster", "show_market_place": "Pazar Yerini Göster",

View file

@ -731,6 +731,8 @@
"shared_seed_wallet_groups": "Спільні групи насіннєвих гаманців", "shared_seed_wallet_groups": "Спільні групи насіннєвих гаманців",
"show": "Показувати", "show": "Показувати",
"show_address_book_popup": "Показати спливаюче вікно \"Додати до адресної книги\" після надсилання", "show_address_book_popup": "Показати спливаюче вікно \"Додати до адресної книги\" після надсилання",
"show_balance": "Довга преса, щоб показати рівновагу",
"show_balance_toast": "Довга преса, щоб приховати або показати рівновагу",
"show_details": "Показати деталі", "show_details": "Показати деталі",
"show_keys": "Показати мнемонічну фразу/ключі", "show_keys": "Показати мнемонічну фразу/ключі",
"show_market_place": "Відображати маркетплейс", "show_market_place": "Відображати маркетплейс",

View file

@ -732,6 +732,8 @@
"shared_seed_wallet_groups": "مشترکہ بیج پرس گروپ", "shared_seed_wallet_groups": "مشترکہ بیج پرس گروپ",
"show": "دکھائیں", "show": "دکھائیں",
"show_address_book_popup": "بھیجنے کے بعد 'ایڈریس میں شامل کریں کتاب' پاپ اپ دکھائیں", "show_address_book_popup": "بھیجنے کے بعد 'ایڈریس میں شامل کریں کتاب' پاپ اپ دکھائیں",
"show_balance": "توازن ظاہر کرنے کے لئے طویل پریس",
"show_balance_toast": "توازن چھپانے یا ظاہر کرنے کے لئے طویل پریس",
"show_details": "تفصیلات دکھائیں", "show_details": "تفصیلات دکھائیں",
"show_keys": "بیج / چابیاں دکھائیں۔", "show_keys": "بیج / چابیاں دکھائیں۔",
"show_market_place": "بازار دکھائیں۔", "show_market_place": "بازار دکھائیں۔",

View file

@ -729,6 +729,8 @@
"shared_seed_wallet_groups": "Nhóm ví hạt được chia sẻ", "shared_seed_wallet_groups": "Nhóm ví hạt được chia sẻ",
"show": "Trình diễn", "show": "Trình diễn",
"show_address_book_popup": "Hiển thị cửa sổ bật lên 'Thêm vào sổ địa chỉ' sau khi gửi", "show_address_book_popup": "Hiển thị cửa sổ bật lên 'Thêm vào sổ địa chỉ' sau khi gửi",
"show_balance": "Báo chí dài để hiển thị sự cân bằng",
"show_balance_toast": "Nhấn dài để ẩn hoặc hiển thị sự cân bằng",
"show_details": "Hiển thị chi tiết", "show_details": "Hiển thị chi tiết",
"show_keys": "Hiển thị hạt giống/khóa", "show_keys": "Hiển thị hạt giống/khóa",
"show_market_place": "Hiển thị Thị trường", "show_market_place": "Hiển thị Thị trường",

View file

@ -731,6 +731,8 @@
"shared_seed_wallet_groups": "Awọn ẹgbẹ ti a pin irugbin", "shared_seed_wallet_groups": "Awọn ẹgbẹ ti a pin irugbin",
"show": "Fihan", "show": "Fihan",
"show_address_book_popup": "Fihan 'ṣafikun si Agbejade Iwe' Lẹhin fifiranṣẹ", "show_address_book_popup": "Fihan 'ṣafikun si Agbejade Iwe' Lẹhin fifiranṣẹ",
"show_balance": "Tẹ Tẹ lati ṣafihan iwọntunwọnsi",
"show_balance_toast": "Tẹ Tẹ lati tọju tabi ṣafihan iwọntunwọnsi",
"show_details": "Fi ìsọfúnni kékeré hàn", "show_details": "Fi ìsọfúnni kékeré hàn",
"show_keys": "Wo hóró / àwọn kọ́kọ́rọ́", "show_keys": "Wo hóró / àwọn kọ́kọ́rọ́",
"show_market_place": "Wa Sopọ Pataki", "show_market_place": "Wa Sopọ Pataki",

View file

@ -730,6 +730,8 @@
"shared_seed_wallet_groups": "共享种子钱包组", "shared_seed_wallet_groups": "共享种子钱包组",
"show": "展示", "show": "展示",
"show_address_book_popup": "发送后显示“添加到通讯簿”弹出窗口", "show_address_book_popup": "发送后显示“添加到通讯簿”弹出窗口",
"show_balance": "长印刷以显示平衡",
"show_balance_toast": "长按以隐藏或显示平衡",
"show_details": "显示详细信息", "show_details": "显示详细信息",
"show_keys": "显示种子/密钥", "show_keys": "显示种子/密钥",
"show_market_place": "显示市场", "show_market_place": "显示市场",

View file

@ -15,15 +15,15 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_ANDROID_TYPE=$1 APP_ANDROID_TYPE=$1
MONERO_COM_NAME="Monero.com" MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.19.0" MONERO_COM_VERSION="1.19.1"
MONERO_COM_BUILD_NUMBER=109 MONERO_COM_BUILD_NUMBER=110
MONERO_COM_BUNDLE_ID="com.monero.app" MONERO_COM_BUNDLE_ID="com.monero.app"
MONERO_COM_PACKAGE="com.monero.app" MONERO_COM_PACKAGE="com.monero.app"
MONERO_COM_SCHEME="monero.com" MONERO_COM_SCHEME="monero.com"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.22.0" CAKEWALLET_VERSION="4.22.1"
CAKEWALLET_BUILD_NUMBER=240 CAKEWALLET_BUILD_NUMBER=241
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
CAKEWALLET_SCHEME="cakewallet" CAKEWALLET_SCHEME="cakewallet"

View file

@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_IOS_TYPE=$1 APP_IOS_TYPE=$1
MONERO_COM_NAME="Monero.com" MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.19.0" MONERO_COM_VERSION="1.19.1"
MONERO_COM_BUILD_NUMBER=106 MONERO_COM_BUILD_NUMBER=107
MONERO_COM_BUNDLE_ID="com.cakewallet.monero" MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.22.0" CAKEWALLET_VERSION="4.22.1"
CAKEWALLET_BUILD_NUMBER=287 CAKEWALLET_BUILD_NUMBER=288
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
HAVEN_NAME="Haven" HAVEN_NAME="Haven"

View file

@ -14,8 +14,8 @@ if [ -n "$1" ]; then
fi fi
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="1.12.0" CAKEWALLET_VERSION="1.12.1"
CAKEWALLET_BUILD_NUMBER=41 CAKEWALLET_BUILD_NUMBER=42
if ! [[ " ${TYPES[*]} " =~ " ${APP_LINUX_TYPE} " ]]; then if ! [[ " ${TYPES[*]} " =~ " ${APP_LINUX_TYPE} " ]]; then
echo "Wrong app type." echo "Wrong app type."

View file

@ -16,13 +16,13 @@ if [ -n "$1" ]; then
fi fi
MONERO_COM_NAME="Monero.com" MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.9.0" MONERO_COM_VERSION="1.9.1"
MONERO_COM_BUILD_NUMBER=39 MONERO_COM_BUILD_NUMBER=40
MONERO_COM_BUNDLE_ID="com.cakewallet.monero" MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="1.15.0" CAKEWALLET_VERSION="1.15.1"
CAKEWALLET_BUILD_NUMBER=99 CAKEWALLET_BUILD_NUMBER=100
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then

View file

@ -1,5 +1,5 @@
#define MyAppName "Cake Wallet" #define MyAppName "Cake Wallet"
#define MyAppVersion "0.3.0" #define MyAppVersion "0.3.1"
#define MyAppPublisher "Cake Labs LLC" #define MyAppPublisher "Cake Labs LLC"
#define MyAppURL "https://cakewallet.com/" #define MyAppURL "https://cakewallet.com/"
#define MyAppExeName "CakeWallet.exe" #define MyAppExeName "CakeWallet.exe"

View file

@ -109,7 +109,6 @@ import 'package:cw_bitcoin/electrum.dart';
import 'package:cw_bitcoin/electrum_transaction_info.dart'; import 'package:cw_bitcoin/electrum_transaction_info.dart';
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart'; import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
import 'package:cw_bitcoin/bitcoin_receive_page_option.dart'; import 'package:cw_bitcoin/bitcoin_receive_page_option.dart';
import 'package:cw_bitcoin/bitcoin_wallet.dart';
import 'package:cw_bitcoin/electrum_wallet.dart'; import 'package:cw_bitcoin/electrum_wallet.dart';
import 'package:cw_bitcoin/bitcoin_unspent.dart'; import 'package:cw_bitcoin/bitcoin_unspent.dart';
import 'package:cw_bitcoin/bitcoin_mnemonic.dart'; import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
@ -173,7 +172,8 @@ abstract class Bitcoin {
List<ElectrumSubAddress> getSilentPaymentAddresses(Object wallet); List<ElectrumSubAddress> getSilentPaymentAddresses(Object wallet);
List<ElectrumSubAddress> getSilentPaymentReceivedAddresses(Object wallet); List<ElectrumSubAddress> getSilentPaymentReceivedAddresses(Object wallet);
Future<int> estimateFakeSendAllTxAmount(Object wallet, TransactionPriority priority); Future<int> estimateFakeSendAllTxAmount(Object wallet, TransactionPriority priority,
{UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any});
List<ElectrumSubAddress> getSubAddresses(Object wallet); List<ElectrumSubAddress> getSubAddresses(Object wallet);
String formatterBitcoinAmountToString({required int amount}); String formatterBitcoinAmountToString({required int amount});
@ -387,6 +387,8 @@ abstract class Monero {
String exportOutputsUR(Object wallet, bool all); String exportOutputsUR(Object wallet, bool all);
bool needExportOutputs(Object wallet, int amount);
bool importKeyImagesUR(Object wallet, String ur); bool importKeyImagesUR(Object wallet, String ur);
WalletCredentials createMoneroRestoreWalletFromKeysCredentials({ WalletCredentials createMoneroRestoreWalletFromKeysCredentials({