mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-11-16 17:27:37 +00:00
Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-659-Confirm-Seeds-Display-Correctly
This commit is contained in:
commit
5779d30a48
118 changed files with 2015 additions and 698 deletions
4
.github/workflows/pr_test_build_android.yml
vendored
4
.github/workflows/pr_test_build_android.yml
vendored
|
@ -171,6 +171,10 @@ jobs:
|
|||
echo "const nanoNowNodesApiKey = '${{ secrets.NANO_NOW_NODES_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
|
||||
echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
|
||||
echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
|
||||
echo "const letsExchangeBearerToken = '${{ secrets.LETS_EXCHANGE_TOKEN }}';" >> lib/.secrets.g.dart
|
||||
echo "const letsExchangeAffiliateId = '${{ secrets.LETS_EXCHANGE_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
|
||||
echo "const stealthExBearerToken = '${{ secrets.STEALTH_EX_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
|
||||
echo "const stealthExAdditionalFeePercent = '${{ secrets.STEALTH_EX_ADDITIONAL_FEE_PERCENT }}';" >> lib/.secrets.g.dart
|
||||
|
||||
- name: Rename app
|
||||
run: |
|
||||
|
|
4
.github/workflows/pr_test_build_linux.yml
vendored
4
.github/workflows/pr_test_build_linux.yml
vendored
|
@ -154,6 +154,10 @@ jobs:
|
|||
echo "const nanoNowNodesApiKey = '${{ secrets.NANO_NOW_NODES_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
|
||||
echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
|
||||
echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
|
||||
echo "const letsExchangeBearerToken = '${{ secrets.LETS_EXCHANGE_TOKEN }}';" >> lib/.secrets.g.dart
|
||||
echo "const letsExchangeAffiliateId = '${{ secrets.LETS_EXCHANGE_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
|
||||
echo "const stealthExBearerToken = '${{ secrets.STEALTH_EX_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
|
||||
echo "const stealthExAdditionalFeePercent = '${{ secrets.STEALTH_EX_ADDITIONAL_FEE_PERCENT }}';" >> lib/.secrets.g.dart
|
||||
|
||||
- name: Rename app
|
||||
run: |
|
||||
|
|
5
assets/images/letsexchange_icon.svg
Normal file
5
assets/images/letsexchange_icon.svg
Normal file
|
@ -0,0 +1,5 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M16 1.37854C16 0.764286 16.6636 0.379192 17.1969 0.68395L23 4L29.4961 7.71208C29.8077 7.89012 30 8.22147 30 8.58032V16L23.9923 12.567C23.3774 12.2157 22.6226 12.2157 22.0077 12.567L16 16V8V1.37854ZM2 16V8.58032C2 8.22147 2.19229 7.89012 2.50386 7.71208L8.00772 4.56702C8.62259 4.21566 9.37741 4.21566 9.99228 4.56702L16 8L2 16ZM16 30.6215C16 31.2357 15.3364 31.6208 14.8031 31.3161L9 28L2.50386 24.2879C2.19229 24.1099 2 23.7785 2 23.4197V16L8.00772 19.433C8.62259 19.7843 9.37741 19.7843 9.99228 19.433L16 16V24V30.6215ZM22.0077 27.433C22.6226 27.7843 23.3774 27.7843 23.9923 27.433L29.4961 24.2879C29.8077 24.1099 30 23.7785 30 23.4197V16L16 24L22.0077 27.433Z"
|
||||
fill="#159DFF"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 846 B |
BIN
assets/images/stealthex.png
Normal file
BIN
assets/images/stealthex.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.4 KiB |
|
@ -17,6 +17,3 @@
|
|||
-
|
||||
uri: node.community.rino.io:18081
|
||||
is_default: false
|
||||
-
|
||||
uri: node.moneroworld.com:18089
|
||||
is_default: false
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
Scan and verify messages
|
||||
Synchronization enhancements
|
||||
Bug fixes
|
||||
Enhance auto-address generation for Monero
|
||||
Bug fixes and enhancements
|
|
@ -1,3 +1,4 @@
|
|||
Scan and verify messages
|
||||
Synchronization enhancements
|
||||
Bug fixes
|
||||
Enable BIP39 by default for wallet creation also on Bitcoin/Litecoin (Electrum seed type is still accessible through advanced settings page)
|
||||
Improve fee calculation for Bitcoin to protect against overpaying or underpaying
|
||||
Enhance auto-address generation for Monero
|
||||
Bug fixes and enhancements
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:cryptography/cryptography.dart' as cryptography;
|
||||
import 'package:cw_core/sec_random_native.dart';
|
||||
|
@ -59,11 +60,7 @@ void maskBytes(Uint8List bytes, int bits) {
|
|||
}
|
||||
}
|
||||
|
||||
String bufferToBin(Uint8List data) {
|
||||
final q1 = data.map((e) => e.toRadixString(2).padLeft(8, '0'));
|
||||
final q2 = q1.join('');
|
||||
return q2;
|
||||
}
|
||||
String bufferToBin(Uint8List data) => data.map((e) => e.toRadixString(2).padLeft(8, '0')).join('');
|
||||
|
||||
String encode(Uint8List data) {
|
||||
final dataBitLen = data.length * 8;
|
||||
|
@ -112,17 +109,18 @@ Future<bool> checkIfMnemonicIsElectrum2(String mnemonic) async {
|
|||
Future<String> getMnemonicHash(String mnemonic) async {
|
||||
final hmacSha512 = Hmac(sha512, utf8.encode('Seed version'));
|
||||
final digest = hmacSha512.convert(utf8.encode(normalizeText(mnemonic)));
|
||||
final hx = digest.toString();
|
||||
return hx;
|
||||
return digest.toString();
|
||||
}
|
||||
|
||||
Future<Uint8List> mnemonicToSeedBytes(String mnemonic, {String prefix = segwit}) async {
|
||||
Future<Uint8List> mnemonicToSeedBytes(String mnemonic,
|
||||
{String prefix = segwit, String passphrase = ''}) async {
|
||||
final pbkdf2 =
|
||||
cryptography.Pbkdf2(macAlgorithm: cryptography.Hmac.sha512(), iterations: 2048, bits: 512);
|
||||
final text = normalizeText(mnemonic);
|
||||
// pbkdf2.deriveKey(secretKey: secretKey, nonce: nonce)
|
||||
final passphraseBytes = utf8.encode(normalizeText(passphrase));
|
||||
final key = await pbkdf2.deriveKey(
|
||||
secretKey: cryptography.SecretKey(text.codeUnits), nonce: 'electrum'.codeUnits);
|
||||
secretKey: cryptography.SecretKey(text.codeUnits),
|
||||
nonce: [...'electrum'.codeUnits, ...passphraseBytes]);
|
||||
final bytes = await key.extractBytes();
|
||||
return Uint8List.fromList(bytes);
|
||||
}
|
||||
|
|
|
@ -7,5 +7,6 @@ class MnemonicBip39 {
|
|||
static String generate({int strength = 128}) => bip39.generateMnemonic(strength: strength);
|
||||
|
||||
/// Create root seed from mnemonic
|
||||
static Uint8List toSeed(String mnemonic) => bip39.mnemonicToSeed(mnemonic);
|
||||
static Uint8List toSeed(String mnemonic, {String? passphrase}) =>
|
||||
bip39.mnemonicToSeed(mnemonic, passphrase: passphrase ?? '');
|
||||
}
|
|
@ -115,7 +115,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
break;
|
||||
case DerivationType.electrum:
|
||||
default:
|
||||
seedBytes = await mnemonicToSeedBytes(mnemonic);
|
||||
seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
|
||||
break;
|
||||
}
|
||||
return BitcoinWallet(
|
||||
|
@ -195,7 +195,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
if (mnemonic != null) {
|
||||
switch (walletInfo.derivationInfo!.derivationType) {
|
||||
case DerivationType.electrum:
|
||||
seedBytes = await mnemonicToSeedBytes(mnemonic);
|
||||
seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
|
||||
break;
|
||||
case DerivationType.bip39:
|
||||
default:
|
||||
|
|
|
@ -3,16 +3,18 @@ import 'package:cw_core/wallet_credentials.dart';
|
|||
import 'package:cw_core/wallet_info.dart';
|
||||
|
||||
class BitcoinNewWalletCredentials extends WalletCredentials {
|
||||
BitcoinNewWalletCredentials(
|
||||
{required String name,
|
||||
WalletInfo? walletInfo,
|
||||
String? password,
|
||||
DerivationType? derivationType,
|
||||
String? derivationPath})
|
||||
: super(
|
||||
BitcoinNewWalletCredentials({
|
||||
required String name,
|
||||
WalletInfo? walletInfo,
|
||||
String? password,
|
||||
DerivationType? derivationType,
|
||||
String? derivationPath,
|
||||
String? passphrase,
|
||||
}) : super(
|
||||
name: name,
|
||||
walletInfo: walletInfo,
|
||||
password: password,
|
||||
passphrase: passphrase,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:io';
|
||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_mnemonics_bip39.dart';
|
||||
import 'package:cw_bitcoin/mnemonic_is_incorrect_exception.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart';
|
||||
import 'package:cw_core/encryption_file_utils.dart';
|
||||
|
@ -35,8 +36,21 @@ class BitcoinWalletService extends WalletService<
|
|||
final network = isTestnet == true ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet;
|
||||
credentials.walletInfo?.network = network.value;
|
||||
|
||||
final String mnemonic;
|
||||
switch ( credentials.walletInfo?.derivationInfo?.derivationType) {
|
||||
case DerivationType.bip39:
|
||||
final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
|
||||
|
||||
mnemonic = await MnemonicBip39.generate(strength: strength);
|
||||
break;
|
||||
case DerivationType.electrum:
|
||||
default:
|
||||
mnemonic = await generateElectrumMnemonic();
|
||||
break;
|
||||
}
|
||||
|
||||
final wallet = await BitcoinWalletBase.create(
|
||||
mnemonic: await generateElectrumMnemonic(),
|
||||
mnemonic: mnemonic,
|
||||
password: credentials.password!,
|
||||
passphrase: credentials.passphrase,
|
||||
walletInfo: credentials.walletInfo!,
|
||||
|
|
|
@ -107,22 +107,19 @@ class ElectrumClient {
|
|||
}
|
||||
},
|
||||
onError: (Object error) {
|
||||
socket = null;
|
||||
final errorMsg = error.toString();
|
||||
print(errorMsg);
|
||||
unterminatedString = '';
|
||||
|
||||
final currentHost = socket?.address.host;
|
||||
final isErrorForCurrentHost = errorMsg.contains(" ${currentHost} ");
|
||||
|
||||
if (currentHost != null && isErrorForCurrentHost)
|
||||
_setConnectionStatus(ConnectionStatus.failed);
|
||||
},
|
||||
onDone: () {
|
||||
unterminatedString = '';
|
||||
if (host == socket?.address.host) {
|
||||
socket = null;
|
||||
_setConnectionStatus(ConnectionStatus.disconnected);
|
||||
try {
|
||||
if (host == socket?.address.host) {
|
||||
socket?.destroy();
|
||||
_setConnectionStatus(ConnectionStatus.disconnected);
|
||||
}
|
||||
} catch(e) {
|
||||
print(e.toString());
|
||||
}
|
||||
},
|
||||
cancelOnError: true,
|
||||
|
@ -436,7 +433,6 @@ class ElectrumClient {
|
|||
{required String id, required String method, List<Object> params = const []}) {
|
||||
try {
|
||||
if (socket == null) {
|
||||
_setConnectionStatus(ConnectionStatus.failed);
|
||||
return null;
|
||||
}
|
||||
final subscription = BehaviorSubject<T>();
|
||||
|
@ -453,7 +449,6 @@ class ElectrumClient {
|
|||
Future<dynamic> call(
|
||||
{required String method, List<Object> params = const [], Function(int)? idCallback}) async {
|
||||
if (socket == null) {
|
||||
_setConnectionStatus(ConnectionStatus.failed);
|
||||
return null;
|
||||
}
|
||||
final completer = Completer<dynamic>();
|
||||
|
@ -467,10 +462,9 @@ class ElectrumClient {
|
|||
}
|
||||
|
||||
Future<dynamic> callWithTimeout(
|
||||
{required String method, List<Object> params = const [], int timeout = 4000}) async {
|
||||
{required String method, List<Object> params = const [], int timeout = 5000}) async {
|
||||
try {
|
||||
if (socket == null) {
|
||||
_setConnectionStatus(ConnectionStatus.failed);
|
||||
return null;
|
||||
}
|
||||
final completer = Completer<dynamic>();
|
||||
|
|
|
@ -109,5 +109,4 @@ Map<DerivationType, List<DerivationInfo>> electrum_derivations = {
|
|||
],
|
||||
};
|
||||
|
||||
|
||||
String electrum_path = electrum_derivations[DerivationType.electrum]!.first.derivationPath!;
|
||||
String electrum_path = electrum_derivations[DerivationType.electrum]!.first.derivationPath!;
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'dart:isolate';
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:cw_core/encryption_file_utils.dart';
|
||||
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
@ -44,6 +45,7 @@ import 'package:mobx/mobx.dart';
|
|||
import 'package:rxdart/subjects.dart';
|
||||
import 'package:sp_scanner/sp_scanner.dart';
|
||||
import 'package:hex/hex.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
part 'electrum_wallet.g.dart';
|
||||
|
||||
|
@ -101,6 +103,8 @@ abstract class ElectrumWalletBase
|
|||
);
|
||||
|
||||
reaction((_) => syncStatus, _syncStatusReaction);
|
||||
|
||||
sharedPrefs.complete(SharedPreferences.getInstance());
|
||||
}
|
||||
|
||||
static Bip32Slip10Secp256k1 getAccountHDWallet(CryptoCurrency? currency, BasedUtxoNetwork network,
|
||||
|
@ -137,6 +141,8 @@ abstract class ElectrumWalletBase
|
|||
Bip32Slip10Secp256k1 get sideHd => accountHD.childKey(Bip32KeyIndex(1));
|
||||
|
||||
final EncryptionFileUtils encryptionFileUtils;
|
||||
|
||||
@override
|
||||
final String? passphrase;
|
||||
|
||||
@override
|
||||
|
@ -194,6 +200,13 @@ abstract class ElectrumWalletBase
|
|||
|
||||
bool _isTryingToConnect = false;
|
||||
|
||||
Completer<SharedPreferences> sharedPrefs = Completer();
|
||||
|
||||
Future<bool> checkIfMempoolAPIIsEnabled() async {
|
||||
bool isMempoolAPIEnabled = (await sharedPrefs.future).getBool("use_mempool_fee_api") ?? true;
|
||||
return isMempoolAPIEnabled;
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> setSilentPaymentsScanning(bool active) async {
|
||||
silentPaymentsScanningActive = active;
|
||||
|
@ -263,7 +276,6 @@ abstract class ElectrumWalletBase
|
|||
Future<Isolate>? _isolate;
|
||||
|
||||
void Function(FlutterErrorDetails)? _onError;
|
||||
Timer? _reconnectTimer;
|
||||
Timer? _autoSaveTimer;
|
||||
Timer? _updateFeeRateTimer;
|
||||
static const int _autoSaveInterval = 1;
|
||||
|
@ -416,6 +428,10 @@ abstract class ElectrumWalletBase
|
|||
@override
|
||||
Future<void> startSync() async {
|
||||
try {
|
||||
if (syncStatus is SyncronizingSyncStatus) {
|
||||
return;
|
||||
}
|
||||
|
||||
syncStatus = SyncronizingSyncStatus();
|
||||
|
||||
if (hasSilentPaymentsScanning) {
|
||||
|
@ -446,6 +462,20 @@ abstract class ElectrumWalletBase
|
|||
|
||||
@action
|
||||
Future<void> updateFeeRates() async {
|
||||
if (await checkIfMempoolAPIIsEnabled()) {
|
||||
try {
|
||||
final response =
|
||||
await http.get(Uri.parse("http://mempool.cakewallet.com:8999/api/v1/fees/recommended"));
|
||||
|
||||
final result = json.decode(response.body) as Map<String, num>;
|
||||
final slowFee = result['economyFee']?.toInt() ?? 0;
|
||||
final mediumFee = result['hourFee']?.toInt() ?? 0;
|
||||
final fastFee = result['fastestFee']?.toInt() ?? 0;
|
||||
_feeRates = [slowFee, mediumFee, fastFee];
|
||||
return;
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
final feeRates = await electrumClient.feeRates(network: network);
|
||||
if (feeRates != [0, 0, 0]) {
|
||||
_feeRates = feeRates;
|
||||
|
@ -1059,6 +1089,8 @@ abstract class ElectrumWalletBase
|
|||
});
|
||||
}
|
||||
|
||||
unspentCoins.removeWhere((utxo) => estimatedTx.utxos.any((e) => e.utxo.txHash == utxo.hash));
|
||||
|
||||
await updateBalance();
|
||||
});
|
||||
} catch (e) {
|
||||
|
@ -1453,7 +1485,6 @@ abstract class ElectrumWalletBase
|
|||
// Create a list of available outputs
|
||||
final outputs = <BitcoinOutput>[];
|
||||
for (final out in bundle.originalTransaction.outputs) {
|
||||
|
||||
// Check if the script contains OP_RETURN
|
||||
final script = out.scriptPubKey.script;
|
||||
if (script.contains('OP_RETURN') && memo == null) {
|
||||
|
@ -2029,9 +2060,8 @@ abstract class ElectrumWalletBase
|
|||
|
||||
_isTryingToConnect = true;
|
||||
|
||||
_reconnectTimer?.cancel();
|
||||
_reconnectTimer = Timer(Duration(seconds: 10), () {
|
||||
if (this.syncStatus is! SyncedSyncStatus && this.syncStatus is! SyncedTipSyncStatus) {
|
||||
Timer(Duration(seconds: 5), () {
|
||||
if (this.syncStatus is NotConnectedSyncStatus || this.syncStatus is LostConnectionSyncStatus) {
|
||||
this.electrumClient.connectToUri(
|
||||
node!.uri,
|
||||
useSSL: node!.useSSL ?? false,
|
||||
|
@ -2056,13 +2086,42 @@ abstract class ElectrumWalletBase
|
|||
tx.inputAddresses!.isEmpty ||
|
||||
tx.outputAddresses == null ||
|
||||
tx.outputAddresses!.isEmpty) {
|
||||
tx = ElectrumTransactionInfo.fromElectrumBundle(
|
||||
bundle,
|
||||
walletInfo.type,
|
||||
network,
|
||||
addresses: addressesSet,
|
||||
height: tx.height,
|
||||
);
|
||||
List<String> inputAddresses = [];
|
||||
List<String> outputAddresses = [];
|
||||
|
||||
for (int i = 0; i < bundle.originalTransaction.inputs.length; i++) {
|
||||
final input = bundle.originalTransaction.inputs[i];
|
||||
final inputTransaction = bundle.ins[i];
|
||||
final vout = input.txIndex;
|
||||
final outTransaction = inputTransaction.outputs[vout];
|
||||
final address = addressFromOutputScript(outTransaction.scriptPubKey, network);
|
||||
|
||||
if (address.isNotEmpty) inputAddresses.add(address);
|
||||
}
|
||||
|
||||
for (int i = 0; i < bundle.originalTransaction.outputs.length; i++) {
|
||||
final out = bundle.originalTransaction.outputs[i];
|
||||
final address = addressFromOutputScript(out.scriptPubKey, network);
|
||||
|
||||
if (address.isNotEmpty) outputAddresses.add(address);
|
||||
|
||||
// Check if the script contains OP_RETURN
|
||||
final script = out.scriptPubKey.script;
|
||||
if (script.contains('OP_RETURN')) {
|
||||
final index = script.indexOf('OP_RETURN');
|
||||
if (index + 1 <= script.length) {
|
||||
try {
|
||||
final opReturnData = script[index + 1].toString();
|
||||
final decodedString = utf8.decode(HEX.decode(opReturnData));
|
||||
outputAddresses.add('OP_RETURN:$decodedString');
|
||||
} catch (_) {
|
||||
outputAddresses.add('OP_RETURN:');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tx.inputAddresses = inputAddresses;
|
||||
tx.outputAddresses = outputAddresses;
|
||||
|
||||
transactionHistory.addOne(tx);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:bip39/bip39.dart' as bip39;
|
|||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
||||
import 'package:cw_bitcoin/electrum_derivations.dart';
|
||||
import 'package:cw_core/encryption_file_utils.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
|
@ -36,6 +37,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||
required Uint8List seedBytes,
|
||||
required EncryptionFileUtils encryptionFileUtils,
|
||||
String? passphrase,
|
||||
String? addressPageType,
|
||||
List<BitcoinAddressRecord>? initialAddresses,
|
||||
ElectrumBalance? initialBalance,
|
||||
|
@ -51,6 +53,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
initialBalance: initialBalance,
|
||||
seedBytes: seedBytes,
|
||||
encryptionFileUtils: encryptionFileUtils,
|
||||
passphrase: passphrase,
|
||||
currency: CryptoCurrency.ltc) {
|
||||
walletAddresses = LitecoinWalletAddresses(
|
||||
walletInfo,
|
||||
|
@ -89,7 +92,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
break;
|
||||
case DerivationType.electrum:
|
||||
default:
|
||||
seedBytes = await mnemonicToSeedBytes(mnemonic);
|
||||
seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
|
||||
break;
|
||||
}
|
||||
return LitecoinWallet(
|
||||
|
@ -100,6 +103,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
initialAddresses: initialAddresses,
|
||||
initialBalance: initialBalance,
|
||||
encryptionFileUtils: encryptionFileUtils,
|
||||
passphrase: passphrase,
|
||||
seedBytes: seedBytes,
|
||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||
|
@ -143,6 +147,31 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
);
|
||||
}
|
||||
|
||||
walletInfo.derivationInfo ??= DerivationInfo();
|
||||
|
||||
// set the default if not present:
|
||||
walletInfo.derivationInfo!.derivationPath ??= snp?.derivationPath ?? electrum_path;
|
||||
walletInfo.derivationInfo!.derivationType ??= snp?.derivationType ?? DerivationType.electrum;
|
||||
|
||||
Uint8List? seedBytes = null;
|
||||
final mnemonic = keysData.mnemonic;
|
||||
final passphrase = keysData.passphrase;
|
||||
|
||||
if (mnemonic != null) {
|
||||
switch (walletInfo.derivationInfo?.derivationType) {
|
||||
case DerivationType.bip39:
|
||||
seedBytes = await bip39.mnemonicToSeed(
|
||||
mnemonic,
|
||||
passphrase: passphrase ?? "",
|
||||
);
|
||||
break;
|
||||
case DerivationType.electrum:
|
||||
default:
|
||||
seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return LitecoinWallet(
|
||||
mnemonic: keysData.mnemonic!,
|
||||
password: password,
|
||||
|
@ -150,7 +179,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
unspentCoinsInfo: unspentCoinsInfo,
|
||||
initialAddresses: snp?.addresses,
|
||||
initialBalance: snp?.balance,
|
||||
seedBytes: await mnemonicToSeedBytes(keysData.mnemonic!),
|
||||
seedBytes: seedBytes!,
|
||||
passphrase: passphrase,
|
||||
encryptionFileUtils: encryptionFileUtils,
|
||||
initialRegularAddressIndex: snp?.regularAddressIndex,
|
||||
initialChangeAddressIndex: snp?.changeAddressIndex,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:io';
|
||||
import 'package:cw_bitcoin/bitcoin_mnemonics_bip39.dart';
|
||||
import 'package:cw_core/encryption_file_utils.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
@ -30,8 +31,21 @@ class LitecoinWalletService extends WalletService<
|
|||
|
||||
@override
|
||||
Future<LitecoinWallet> create(BitcoinNewWalletCredentials credentials, {bool? isTestnet}) async {
|
||||
final String mnemonic;
|
||||
switch ( credentials.walletInfo?.derivationInfo?.derivationType) {
|
||||
case DerivationType.bip39:
|
||||
final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
|
||||
|
||||
mnemonic = await MnemonicBip39.generate(strength: strength);
|
||||
break;
|
||||
case DerivationType.electrum:
|
||||
default:
|
||||
mnemonic = await generateElectrumMnemonic();
|
||||
break;
|
||||
}
|
||||
|
||||
final wallet = await LitecoinWalletBase.create(
|
||||
mnemonic: await generateElectrumMnemonic(),
|
||||
mnemonic: mnemonic,
|
||||
password: credentials.password!,
|
||||
passphrase: credentials.passphrase,
|
||||
walletInfo: credentials.walletInfo!,
|
||||
|
|
|
@ -350,6 +350,11 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -736,6 +741,62 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.27.7"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.3"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.2"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shared_preferences_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: "59dc807b94d29d52ddbb1b3c0d3b9d0a67fc535a64e62a5542c8db0513fcb6c2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -944,4 +1005,4 @@ packages:
|
|||
version: "2.2.1"
|
||||
sdks:
|
||||
dart: ">=3.3.0 <4.0.0"
|
||||
flutter: ">=3.16.6"
|
||||
flutter: ">=3.19.0"
|
||||
|
|
|
@ -17,6 +17,7 @@ dependencies:
|
|||
mobx: ^2.0.7+4
|
||||
flutter_mobx: ^2.0.6+1
|
||||
intl: ^0.18.0
|
||||
shared_preferences: ^2.0.15
|
||||
cw_core:
|
||||
path: ../cw_core
|
||||
bitbox:
|
||||
|
|
|
@ -3,5 +3,4 @@ export 'bitcoin_cash_wallet_addresses.dart';
|
|||
export 'bitcoin_cash_wallet_creation_credentials.dart';
|
||||
export 'bitcoin_cash_wallet_service.dart';
|
||||
export 'exceptions/exceptions.dart';
|
||||
export 'mnemonic.dart';
|
||||
export 'bitcoin_cash_address_utils.dart';
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import 'package:bitbox/bitbox.dart' as bitbox;
|
||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||
import 'package:cw_core/encryption_file_utils.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_mnemonics_bip39.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||
import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/encryption_file_utils.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
|
@ -30,6 +31,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
|||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||
required Uint8List seedBytes,
|
||||
required EncryptionFileUtils encryptionFileUtils,
|
||||
String? passphrase,
|
||||
BitcoinAddressType? addressPageType,
|
||||
List<BitcoinAddressRecord>? initialAddresses,
|
||||
ElectrumBalance? initialBalance,
|
||||
|
@ -45,7 +47,8 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
|||
initialBalance: initialBalance,
|
||||
seedBytes: seedBytes,
|
||||
currency: CryptoCurrency.bch,
|
||||
encryptionFileUtils: encryptionFileUtils) {
|
||||
encryptionFileUtils: encryptionFileUtils,
|
||||
passphrase: passphrase) {
|
||||
walletAddresses = BitcoinCashWalletAddresses(
|
||||
walletInfo,
|
||||
initialAddresses: initialAddresses,
|
||||
|
@ -67,6 +70,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
|||
required WalletInfo walletInfo,
|
||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||
required EncryptionFileUtils encryptionFileUtils,
|
||||
String? passphrase,
|
||||
String? addressPageType,
|
||||
List<BitcoinAddressRecord>? initialAddresses,
|
||||
ElectrumBalance? initialBalance,
|
||||
|
@ -79,11 +83,12 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
|||
unspentCoinsInfo: unspentCoinsInfo,
|
||||
initialAddresses: initialAddresses,
|
||||
initialBalance: initialBalance,
|
||||
seedBytes: await MnemonicBip39.toSeed(mnemonic),
|
||||
seedBytes: await MnemonicBip39.toSeed(mnemonic, passphrase: passphrase),
|
||||
encryptionFileUtils: encryptionFileUtils,
|
||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||
addressPageType: P2pkhAddressType.p2pkh,
|
||||
passphrase: passphrase,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -150,11 +155,12 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
|||
}
|
||||
}).toList(),
|
||||
initialBalance: snp?.balance,
|
||||
seedBytes: await MnemonicBip39.toSeed(keysData.mnemonic!),
|
||||
seedBytes: await MnemonicBip39.toSeed(keysData.mnemonic!, passphrase: keysData.passphrase),
|
||||
encryptionFileUtils: encryptionFileUtils,
|
||||
initialRegularAddressIndex: snp?.regularAddressIndex,
|
||||
initialChangeAddressIndex: snp?.changeAddressIndex,
|
||||
addressPageType: P2pkhAddressType.p2pkh,
|
||||
passphrase: keysData.passphrase,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,17 +2,19 @@ import 'package:cw_core/wallet_credentials.dart';
|
|||
import 'package:cw_core/wallet_info.dart';
|
||||
|
||||
class BitcoinCashNewWalletCredentials extends WalletCredentials {
|
||||
BitcoinCashNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password})
|
||||
: super(name: name, walletInfo: walletInfo, password: password);
|
||||
BitcoinCashNewWalletCredentials(
|
||||
{required String name, WalletInfo? walletInfo, String? password, String? passphrase})
|
||||
: super(name: name, walletInfo: walletInfo, password: password, passphrase: passphrase);
|
||||
}
|
||||
|
||||
class BitcoinCashRestoreWalletFromSeedCredentials extends WalletCredentials {
|
||||
BitcoinCashRestoreWalletFromSeedCredentials(
|
||||
{required String name,
|
||||
required String password,
|
||||
required this.mnemonic,
|
||||
WalletInfo? walletInfo})
|
||||
: super(name: name, password: password, walletInfo: walletInfo);
|
||||
BitcoinCashRestoreWalletFromSeedCredentials({
|
||||
required String name,
|
||||
required String password,
|
||||
required this.mnemonic,
|
||||
WalletInfo? walletInfo,
|
||||
String? passphrase,
|
||||
}) : super(name: name, password: password, walletInfo: walletInfo, passphrase: passphrase);
|
||||
|
||||
final String mnemonic;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:bip39/bip39.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_mnemonics_bip39.dart';
|
||||
import 'package:cw_bitcoin_cash/cw_bitcoin_cash.dart';
|
||||
import 'package:cw_core/encryption_file_utils.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
|
@ -9,7 +11,6 @@ import 'package:cw_core/wallet_base.dart';
|
|||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
class BitcoinCashWalletService extends WalletService<
|
||||
|
@ -35,11 +36,12 @@ class BitcoinCashWalletService extends WalletService<
|
|||
final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
|
||||
|
||||
final wallet = await BitcoinCashWalletBase.create(
|
||||
mnemonic: await MnemonicBip39.generate(strength: strength),
|
||||
mnemonic: await MnemonicBip39.generate(strength: strength),
|
||||
password: credentials.password!,
|
||||
walletInfo: credentials.walletInfo!,
|
||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||
passphrase: credentials.passphrase,
|
||||
);
|
||||
await wallet.save();
|
||||
await wallet.init();
|
||||
|
@ -54,11 +56,11 @@ class BitcoinCashWalletService extends WalletService<
|
|||
|
||||
try {
|
||||
final wallet = await BitcoinCashWalletBase.open(
|
||||
password: password,
|
||||
name: name,
|
||||
walletInfo: walletInfo,
|
||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||
password: password,
|
||||
name: name,
|
||||
walletInfo: walletInfo,
|
||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||
);
|
||||
await wallet.init();
|
||||
saveBackup(name);
|
||||
|
@ -66,11 +68,11 @@ class BitcoinCashWalletService extends WalletService<
|
|||
} catch (_) {
|
||||
await restoreWalletFilesFromBackup(name);
|
||||
final wallet = await BitcoinCashWalletBase.open(
|
||||
password: password,
|
||||
name: name,
|
||||
walletInfo: walletInfo,
|
||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||
password: password,
|
||||
name: name,
|
||||
walletInfo: walletInfo,
|
||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||
);
|
||||
await wallet.init();
|
||||
return wallet;
|
||||
|
@ -130,7 +132,9 @@ class BitcoinCashWalletService extends WalletService<
|
|||
mnemonic: credentials.mnemonic,
|
||||
walletInfo: credentials.walletInfo!,
|
||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||
encryptionFileUtils: encryptionFileUtilsFor(isDirect));
|
||||
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||
passphrase: credentials.passphrase
|
||||
);
|
||||
await wallet.save();
|
||||
await wallet.init();
|
||||
return wallet;
|
||||
|
|
|
@ -46,6 +46,8 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
|
|||
|
||||
String? get hexSeed => null;
|
||||
|
||||
String? get passphrase => null;
|
||||
|
||||
Object get keys;
|
||||
|
||||
WalletAddresses get walletAddresses;
|
||||
|
|
|
@ -138,11 +138,17 @@ PendingTransactionDescription createTransactionMultDestSync(
|
|||
int accountIndex = 0,
|
||||
List<String> preferredInputs = const []}) {
|
||||
|
||||
final dstAddrs = outputs.map((e) => e.address).toList();
|
||||
final amounts = outputs.map((e) => monero.Wallet_amountFromString(e.amount)).toList();
|
||||
|
||||
// print("multDest: dstAddrs: $dstAddrs");
|
||||
// print("multDest: amounts: $amounts");
|
||||
|
||||
final txptr = monero.Wallet_createTransactionMultDest(
|
||||
wptr!,
|
||||
dstAddr: outputs.map((e) => e.address).toList(),
|
||||
dstAddr: dstAddrs,
|
||||
isSweepAll: false,
|
||||
amounts: outputs.map((e) => monero.Wallet_amountFromString(e.amount)).toList(),
|
||||
amounts: amounts,
|
||||
mixinCount: 0,
|
||||
pendingTransactionPriority: priorityRaw,
|
||||
subaddr_account: accountIndex,
|
||||
|
@ -307,7 +313,34 @@ class Transaction {
|
|||
confirmations = monero.TransactionInfo_confirmations(txInfo),
|
||||
fee = monero.TransactionInfo_fee(txInfo),
|
||||
description = monero.TransactionInfo_description(txInfo),
|
||||
key = monero.Wallet_getTxKey(wptr!, txid: monero.TransactionInfo_hash(txInfo));
|
||||
key = getTxKey(txInfo);
|
||||
|
||||
static String getTxKey(monero.TransactionInfo txInfo) {
|
||||
final txKey = monero.Wallet_getTxKey(wptr!, txid: monero.TransactionInfo_hash(txInfo));
|
||||
final status = monero.Wallet_status(wptr!);
|
||||
if (status != 0) {
|
||||
return monero.Wallet_errorString(wptr!);
|
||||
}
|
||||
return breakTxKey(txKey);
|
||||
}
|
||||
|
||||
static String breakTxKey(String input) {
|
||||
final x = 64;
|
||||
StringBuffer buffer = StringBuffer();
|
||||
|
||||
for (int i = 0; i < input.length; i += x) {
|
||||
int endIndex = i + x;
|
||||
if (endIndex > input.length) {
|
||||
endIndex = input.length;
|
||||
}
|
||||
buffer.write(input.substring(i, endIndex));
|
||||
if (endIndex != input.length) {
|
||||
buffer.write('\n\n');
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.toString().trim();
|
||||
}
|
||||
|
||||
Transaction.dummy({
|
||||
required this.displayLabel,
|
||||
|
|
|
@ -13,11 +13,9 @@ import 'package:cw_core/monero_transaction_priority.dart';
|
|||
import 'package:cw_core/monero_wallet_keys.dart';
|
||||
import 'package:cw_core/monero_wallet_utils.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/pending_transaction.dart';
|
||||
import 'package:cw_core/sync_status.dart';
|
||||
import 'package:cw_core/transaction_direction.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
|
|
|
@ -9,11 +9,9 @@ import 'package:cw_core/wallet_info.dart';
|
|||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cw_core/get_height_by_date.dart';
|
||||
import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
|
||||
import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager;
|
||||
import 'package:cw_monero/api/wallet_manager.dart';
|
||||
import 'package:cw_monero/monero_wallet.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:polyseed/polyseed.dart';
|
||||
import 'package:monero/monero.dart' as monero;
|
||||
|
@ -120,7 +118,6 @@ class MoneroWalletService extends WalletService<
|
|||
|
||||
@override
|
||||
Future<MoneroWallet> openWallet(String name, String password, {bool? retryOnFailure}) async {
|
||||
MoneroWallet? wallet;
|
||||
try {
|
||||
final path = await pathForWallet(name: name, type: getType());
|
||||
|
||||
|
@ -147,41 +144,10 @@ class MoneroWalletService extends WalletService<
|
|||
await wallet.init();
|
||||
|
||||
return wallet;
|
||||
} catch (e, s) {
|
||||
} catch (e) {
|
||||
// TODO: Implement Exception for wallet list service.
|
||||
|
||||
final bool isBadAlloc = e.toString().contains('bad_alloc') ||
|
||||
(e is WalletOpeningException &&
|
||||
(e.message == 'std::bad_alloc' || e.message.contains('bad_alloc')));
|
||||
|
||||
final bool doesNotCorrespond = e.toString().contains('does not correspond') ||
|
||||
(e is WalletOpeningException && e.message.contains('does not correspond'));
|
||||
|
||||
final bool isMissingCacheFilesIOS = e.toString().contains('basic_string') ||
|
||||
(e is WalletOpeningException && e.message.contains('basic_string'));
|
||||
|
||||
final bool isMissingCacheFilesAndroid = e.toString().contains('input_stream') ||
|
||||
e.toString().contains('input stream error') ||
|
||||
(e is WalletOpeningException &&
|
||||
(e.message.contains('input_stream') || e.message.contains('input stream error')));
|
||||
|
||||
final bool invalidSignature = e.toString().contains('invalid signature') ||
|
||||
(e is WalletOpeningException && e.message.contains('invalid signature'));
|
||||
|
||||
final bool invalidPassword = e.toString().contains('invalid password') ||
|
||||
(e is WalletOpeningException && e.message.contains('invalid password'));
|
||||
|
||||
if (!isBadAlloc &&
|
||||
!doesNotCorrespond &&
|
||||
!isMissingCacheFilesIOS &&
|
||||
!isMissingCacheFilesAndroid &&
|
||||
!invalidSignature &&
|
||||
!invalidPassword &&
|
||||
wallet != null &&
|
||||
wallet.onError != null) {
|
||||
wallet.onError!(FlutterErrorDetails(exception: e, stack: s));
|
||||
}
|
||||
if (invalidPassword || retryOnFailure == false) {
|
||||
if (retryOnFailure == false) {
|
||||
rethrow;
|
||||
}
|
||||
|
||||
|
|
|
@ -463,8 +463,8 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
path: "impls/monero.dart"
|
||||
ref: bcb328a4956105dc182afd0ce2e48fe263f5f20b
|
||||
resolved-ref: bcb328a4956105dc182afd0ce2e48fe263f5f20b
|
||||
ref: 3cb38bee9385faf46b03fd73aab85f3ac4115bf7
|
||||
resolved-ref: 3cb38bee9385faf46b03fd73aab85f3ac4115bf7
|
||||
url: "https://github.com/mrcyjanek/monero_c"
|
||||
source: git
|
||||
version: "0.0.0"
|
||||
|
|
|
@ -25,7 +25,7 @@ dependencies:
|
|||
monero:
|
||||
git:
|
||||
url: https://github.com/mrcyjanek/monero_c
|
||||
ref: bcb328a4956105dc182afd0ce2e48fe263f5f20b # monero_c hash
|
||||
ref: 3cb38bee9385faf46b03fd73aab85f3ac4115bf7 # monero_c hash
|
||||
path: impls/monero.dart
|
||||
mutex: ^3.1.0
|
||||
|
||||
|
|
|
@ -466,21 +466,25 @@ class NanoClient {
|
|||
|
||||
blocks = blocks as Map<String, dynamic>;
|
||||
|
||||
// confirm all receivable blocks:
|
||||
for (final blockHash in blocks.keys) {
|
||||
final block = blocks[blockHash];
|
||||
final String amountRaw = block["amount"] as String;
|
||||
await receiveBlock(
|
||||
blockHash: blockHash,
|
||||
amountRaw: amountRaw,
|
||||
privateKey: privateKey,
|
||||
destinationAddress: destinationAddress,
|
||||
);
|
||||
// a bit of a hack:
|
||||
await Future<void>.delayed(const Duration(seconds: 2));
|
||||
try {
|
||||
// confirm all receivable blocks:
|
||||
for (final blockHash in blocks.keys) {
|
||||
final block = blocks[blockHash];
|
||||
final String amountRaw = block["amount"] as String;
|
||||
await receiveBlock(
|
||||
blockHash: blockHash,
|
||||
amountRaw: amountRaw,
|
||||
privateKey: privateKey,
|
||||
destinationAddress: destinationAddress,
|
||||
);
|
||||
// a bit of a hack:
|
||||
await Future<void>.delayed(const Duration(seconds: 2));
|
||||
}
|
||||
return blocks.keys.length;
|
||||
} catch (_) {
|
||||
// we failed to confirm all receivable blocks for w/e reason (PoW / node outage / etc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return blocks.keys.length;
|
||||
}
|
||||
|
||||
void stop() {}
|
||||
|
|
|
@ -14,8 +14,11 @@ import 'package:bip39/bip39.dart' as bip39;
|
|||
import 'package:nanodart/nanodart.dart';
|
||||
import 'package:nanoutil/nanoutil.dart';
|
||||
|
||||
class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||
NanoRestoreWalletFromSeedCredentials, NanoRestoreWalletFromKeysCredentials, NanoNewWalletCredentials> {
|
||||
class NanoWalletService extends WalletService<
|
||||
NanoNewWalletCredentials,
|
||||
NanoRestoreWalletFromSeedCredentials,
|
||||
NanoRestoreWalletFromKeysCredentials,
|
||||
NanoNewWalletCredentials> {
|
||||
NanoWalletService(this.walletInfoSource, this.isDirect);
|
||||
|
||||
final Box<WalletInfo> walletInfoSource;
|
||||
|
@ -33,8 +36,12 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
|||
String seedKey = NanoSeeds.generateSeed();
|
||||
String mnemonic = NanoDerivations.standardSeedToMnemonic(seedKey);
|
||||
|
||||
// ensure default if not present:
|
||||
credentials.walletInfo!.derivationInfo ??= DerivationInfo(derivationType: DerivationType.nano);
|
||||
// should never happen but just in case:
|
||||
if (credentials.walletInfo!.derivationInfo == null) {
|
||||
credentials.walletInfo!.derivationInfo = DerivationInfo(derivationType: DerivationType.nano);
|
||||
} else if (credentials.walletInfo!.derivationInfo!.derivationType == null) {
|
||||
credentials.walletInfo!.derivationInfo!.derivationType = DerivationType.nano;
|
||||
}
|
||||
|
||||
final wallet = NanoWallet(
|
||||
walletInfo: credentials.walletInfo!,
|
||||
|
@ -86,7 +93,8 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
|||
}
|
||||
|
||||
@override
|
||||
Future<NanoWallet> restoreFromKeys(NanoRestoreWalletFromKeysCredentials credentials, {bool? isTestnet}) async {
|
||||
Future<NanoWallet> restoreFromKeys(NanoRestoreWalletFromKeysCredentials credentials,
|
||||
{bool? isTestnet}) async {
|
||||
if (credentials.seedKey.contains(' ')) {
|
||||
throw Exception("Invalid key!");
|
||||
} else {
|
||||
|
@ -106,6 +114,13 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
|||
}
|
||||
}
|
||||
|
||||
// should never happen but just in case:
|
||||
if (credentials.walletInfo!.derivationInfo == null) {
|
||||
credentials.walletInfo!.derivationInfo = DerivationInfo(derivationType: DerivationType.nano);
|
||||
} else if (credentials.walletInfo!.derivationInfo!.derivationType == null) {
|
||||
credentials.walletInfo!.derivationInfo!.derivationType = DerivationType.nano;
|
||||
}
|
||||
|
||||
final wallet = await NanoWallet(
|
||||
password: credentials.password!,
|
||||
mnemonic: mnemonic ?? credentials.seedKey,
|
||||
|
@ -119,11 +134,13 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
|||
|
||||
@override
|
||||
Future<NanoWallet> restoreFromHardwareWallet(NanoNewWalletCredentials credentials) {
|
||||
throw UnimplementedError("Restoring a Nano wallet from a hardware wallet is not yet supported!");
|
||||
throw UnimplementedError(
|
||||
"Restoring a Nano wallet from a hardware wallet is not yet supported!");
|
||||
}
|
||||
|
||||
@override
|
||||
Future<NanoWallet> restoreFromSeed(NanoRestoreWalletFromSeedCredentials credentials, {bool? isTestnet}) async {
|
||||
Future<NanoWallet> restoreFromSeed(NanoRestoreWalletFromSeedCredentials credentials,
|
||||
{bool? isTestnet}) async {
|
||||
if (credentials.mnemonic.contains(' ')) {
|
||||
if (!bip39.validateMnemonic(credentials.mnemonic)) {
|
||||
throw nm.NanoMnemonicIsIncorrectException();
|
||||
|
|
|
@ -463,8 +463,8 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
path: "impls/monero.dart"
|
||||
ref: bcb328a4956105dc182afd0ce2e48fe263f5f20b
|
||||
resolved-ref: bcb328a4956105dc182afd0ce2e48fe263f5f20b
|
||||
ref: 3cb38bee9385faf46b03fd73aab85f3ac4115bf7
|
||||
resolved-ref: 3cb38bee9385faf46b03fd73aab85f3ac4115bf7
|
||||
url: "https://github.com/mrcyjanek/monero_c"
|
||||
source: git
|
||||
version: "0.0.0"
|
||||
|
|
|
@ -25,7 +25,7 @@ dependencies:
|
|||
monero:
|
||||
git:
|
||||
url: https://github.com/mrcyjanek/monero_c
|
||||
ref: bcb328a4956105dc182afd0ce2e48fe263f5f20b # monero_c hash
|
||||
ref: 3cb38bee9385faf46b03fd73aab85f3ac4115bf7 # monero_c hash
|
||||
path: impls/monero.dart
|
||||
mutex: ^3.1.0
|
||||
|
||||
|
|
|
@ -29,8 +29,9 @@ class CWBitcoin extends Bitcoin {
|
|||
|
||||
@override
|
||||
WalletCredentials createBitcoinNewWalletCredentials(
|
||||
{required String name, WalletInfo? walletInfo, String? password}) =>
|
||||
BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
|
||||
{required String name, WalletInfo? walletInfo, String? password, String? passphrase}) =>
|
||||
BitcoinNewWalletCredentials(
|
||||
name: name, walletInfo: walletInfo, password: password, passphrase: passphrase);
|
||||
|
||||
@override
|
||||
WalletCredentials createBitcoinHardwareWalletCredentials(
|
||||
|
@ -202,8 +203,8 @@ class CWBitcoin extends Bitcoin {
|
|||
await bitcoinWallet.updateAllUnspents();
|
||||
}
|
||||
|
||||
WalletService createBitcoinWalletService(
|
||||
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool alwaysScan, bool isDirect) {
|
||||
WalletService createBitcoinWalletService(Box<WalletInfo> walletInfoSource,
|
||||
Box<UnspentCoinsInfo> unspentCoinSource, bool alwaysScan, bool isDirect) {
|
||||
return BitcoinWalletService(walletInfoSource, unspentCoinSource, alwaysScan, isDirect);
|
||||
}
|
||||
|
||||
|
@ -315,7 +316,7 @@ class CWBitcoin extends Bitcoin {
|
|||
for (DerivationType dType in electrum_derivations.keys) {
|
||||
late Uint8List seedBytes;
|
||||
if (dType == DerivationType.electrum) {
|
||||
seedBytes = await mnemonicToSeedBytes(mnemonic);
|
||||
seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
|
||||
} else if (dType == DerivationType.bip39) {
|
||||
seedBytes = bip39.mnemonicToSeed(mnemonic, passphrase: passphrase ?? '');
|
||||
}
|
||||
|
|
|
@ -15,14 +15,16 @@ class CWBitcoinCash extends BitcoinCash {
|
|||
required String name,
|
||||
WalletInfo? walletInfo,
|
||||
String? password,
|
||||
String? passphrase,
|
||||
}) =>
|
||||
BitcoinCashNewWalletCredentials(name: name, walletInfo: walletInfo, password: password);
|
||||
BitcoinCashNewWalletCredentials(
|
||||
name: name, walletInfo: walletInfo, password: password, passphrase: passphrase);
|
||||
|
||||
@override
|
||||
WalletCredentials createBitcoinCashRestoreWalletFromSeedCredentials(
|
||||
{required String name, required String mnemonic, required String password}) =>
|
||||
{required String name, required String mnemonic, required String password, String? passphrase}) =>
|
||||
BitcoinCashRestoreWalletFromSeedCredentials(
|
||||
name: name, mnemonic: mnemonic, password: password);
|
||||
name: name, mnemonic: mnemonic, password: password, passphrase: passphrase);
|
||||
|
||||
@override
|
||||
TransactionPriority deserializeBitcoinCashTransactionPriority(int raw) =>
|
||||
|
|
|
@ -75,8 +75,10 @@ class WalletCreationService {
|
|||
|
||||
bool get _hasSeedPhraseLengthOption {
|
||||
switch (type) {
|
||||
case WalletType.ethereum:
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.bitcoinCash:
|
||||
case WalletType.ethereum:
|
||||
case WalletType.polygon:
|
||||
case WalletType.solana:
|
||||
case WalletType.tron:
|
||||
|
@ -84,8 +86,6 @@ class WalletCreationService {
|
|||
case WalletType.monero:
|
||||
case WalletType.wownero:
|
||||
case WalletType.none:
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.haven:
|
||||
case WalletType.nano:
|
||||
case WalletType.banano:
|
||||
|
|
34
lib/di.dart
34
lib/di.dart
|
@ -146,7 +146,7 @@ import 'package:cake_wallet/view_model/cake_pay/cake_pay_purchase_view_model.dar
|
|||
import 'package:cake_wallet/view_model/nano_account_list/nano_account_edit_or_create_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/nano_account_list/nano_account_list_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
|
||||
import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
|
||||
|
@ -179,6 +179,7 @@ import 'package:cake_wallet/store/dashboard/trades_store.dart';
|
|||
import 'package:cake_wallet/store/dashboard/transaction_filter_store.dart';
|
||||
import 'package:cake_wallet/store/node_list_store.dart';
|
||||
import 'package:cake_wallet/store/secret_store.dart';
|
||||
import 'package:cake_wallet/store/seed_settings_store.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/store/templates/exchange_template_store.dart';
|
||||
import 'package:cake_wallet/store/templates/send_template_store.dart';
|
||||
|
@ -331,6 +332,7 @@ Future<void> setup({
|
|||
YatStore(appStore: getIt.get<AppStore>(), secureStorage: getIt.get<SecureStorage>())..init());
|
||||
getIt.registerSingleton<AnonpayTransactionsStore>(
|
||||
AnonpayTransactionsStore(anonpayInvoiceInfoSource: _anonpayInvoiceInfoSource));
|
||||
getIt.registerSingleton<SeedSettingsStore>(SeedSettingsStore());
|
||||
|
||||
getIt.registerLazySingleton(() => LedgerViewModel());
|
||||
|
||||
|
@ -361,6 +363,7 @@ Future<void> setup({
|
|||
getIt.get<WalletCreationService>(param1: type),
|
||||
_walletInfoSource,
|
||||
getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
|
||||
getIt.get<SeedSettingsViewModel>(),
|
||||
type: type));
|
||||
|
||||
getIt.registerFactoryParam<WalletUnlockPage, WalletUnlockArguments, bool>((args, closable) {
|
||||
|
@ -422,14 +425,21 @@ Future<void> setup({
|
|||
walletType: args.walletType ?? currentWalletType);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<WalletRestorationFromQRVM, WalletType, void>((WalletType type, _) {
|
||||
return WalletRestorationFromQRVM(getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type), _walletInfoSource, type);
|
||||
});
|
||||
getIt.registerFactoryParam<WalletRestorationFromQRVM, WalletType, void>((WalletType type, _) =>
|
||||
WalletRestorationFromQRVM(
|
||||
getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type),
|
||||
_walletInfoSource,
|
||||
type,
|
||||
getIt.get<SeedSettingsViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletHardwareRestoreViewModel, WalletType, void>((type, _) =>
|
||||
WalletHardwareRestoreViewModel(getIt.get<LedgerViewModel>(), getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
WalletHardwareRestoreViewModel(
|
||||
getIt.get<LedgerViewModel>(),
|
||||
getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type),
|
||||
_walletInfoSource,
|
||||
getIt.get<SeedSettingsViewModel>(),
|
||||
type: type));
|
||||
|
||||
getIt.registerFactory<WalletAddressListViewModel>(() => WalletAddressListViewModel(
|
||||
|
@ -833,7 +843,7 @@ Future<void> setup({
|
|||
|
||||
getIt.registerFactory(() => WalletSeedViewModel(getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactory<SeedTypeViewModel>(() => SeedTypeViewModel(getIt.get<AppStore>()));
|
||||
getIt.registerFactory<SeedSettingsViewModel>(() => SeedSettingsViewModel(getIt.get<AppStore>(), getIt.get<SeedSettingsStore>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletSeedPage, bool, void>((bool isWalletCreated, _) =>
|
||||
WalletSeedPage(getIt.get<WalletSeedViewModel>(), isNewWalletCreated: isWalletCreated));
|
||||
|
@ -1018,12 +1028,12 @@ Future<void> setup({
|
|||
getIt.registerFactory(() => FaqPage(getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, void>((type, _) =>
|
||||
WalletRestoreViewModel(
|
||||
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
WalletRestoreViewModel(getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type),
|
||||
_walletInfoSource, getIt.get<SeedSettingsViewModel>(),
|
||||
type: type));
|
||||
|
||||
getIt.registerFactoryParam<WalletRestorePage, WalletType, void>((type, _) => WalletRestorePage(
|
||||
getIt.get<WalletRestoreViewModel>(param1: type), getIt.get<SeedTypeViewModel>()));
|
||||
getIt.get<WalletRestoreViewModel>(param1: type), getIt.get<SeedSettingsViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletRestoreChooseDerivationViewModel, List<DerivationInfo>, void>(
|
||||
(derivations, _) => WalletRestoreChooseDerivationViewModel(derivationInfos: derivations));
|
||||
|
@ -1275,7 +1285,7 @@ Future<void> setup({
|
|||
|
||||
getIt.registerFactory(
|
||||
() => WalletConnectConnectionsView(web3walletService: getIt.get<Web3WalletService>()));
|
||||
|
||||
|
||||
getIt.registerFactory(() => NFTViewModel(appStore, getIt.get<BottomSheetService>()));
|
||||
getIt.registerFactory<TorPage>(() => TorPage(getIt.get<AppStore>()));
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ const solanaDefaultNodeUri = 'rpc.ankr.com';
|
|||
const tronDefaultNodeUri = 'trx.nownodes.io';
|
||||
const newCakeWalletBitcoinUri = 'btc-electrum.cakewallet.com:50002';
|
||||
const wowneroDefaultNodeUri = 'node3.monerodevs.org:34568';
|
||||
const moneroWorldNodeUri = '.moneroworld.com';
|
||||
|
||||
Future<void> defaultSettingsMigration(
|
||||
{required int version,
|
||||
|
@ -245,6 +246,9 @@ Future<void> defaultSettingsMigration(
|
|||
_fixNodesUseSSLFlag(nodes);
|
||||
await changeDefaultNanoNode(nodes, sharedPreferences);
|
||||
break;
|
||||
case 40:
|
||||
await removeMoneroWorld(sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -488,15 +492,7 @@ Node? getBitcoinCashDefaultElectrumServer({required Box<Node> nodes}) {
|
|||
|
||||
Node getMoneroDefaultNode({required Box<Node> nodes}) {
|
||||
final timeZone = DateTime.now().timeZoneOffset.inHours;
|
||||
var nodeUri = '';
|
||||
|
||||
if (timeZone >= 1) {
|
||||
// Eurasia
|
||||
nodeUri = 'xmr-node-eu.cakewallet.com:18081';
|
||||
} else if (timeZone <= -4) {
|
||||
// America
|
||||
nodeUri = 'xmr-node-usa-east.cakewallet.com:18081';
|
||||
}
|
||||
var nodeUri = newCakeWalletMoneroUri;
|
||||
|
||||
try {
|
||||
return nodes.values.firstWhere((Node node) => node.uriRaw == nodeUri);
|
||||
|
@ -1260,3 +1256,22 @@ Future<void> replaceTronDefaultNode({
|
|||
// If it's not, we switch user to the new default node: NowNodes
|
||||
await changeTronCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
}
|
||||
|
||||
Future<void> removeMoneroWorld(
|
||||
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
|
||||
const cakeWalletMoneroNodeUriPattern = '.moneroworld.com';
|
||||
final currentMoneroNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
|
||||
final currentMoneroNode = nodes.values.firstWhere((node) => node.key == currentMoneroNodeId);
|
||||
final needToReplaceCurrentMoneroNode = currentMoneroNode.uri.toString().contains(cakeWalletMoneroNodeUriPattern);
|
||||
|
||||
nodes.values.forEach((node) async {
|
||||
if (node.type == WalletType.monero &&
|
||||
node.uri.toString().contains(cakeWalletMoneroNodeUriPattern)) {
|
||||
await node.delete();
|
||||
}
|
||||
});
|
||||
|
||||
if (needToReplaceCurrentMoneroNode) {
|
||||
await changeMoneroCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ class LanguageService {
|
|||
'yo': 'nga',
|
||||
'ha': 'hau',
|
||||
'tl': 'phl',
|
||||
'hy': 'arm'
|
||||
'hy': 'arm',
|
||||
};
|
||||
|
||||
static final list = <String, String>{};
|
||||
|
|
|
@ -61,6 +61,7 @@ class PreferencesKey {
|
|||
static const useEtherscan = 'use_etherscan';
|
||||
static const usePolygonScan = 'use_polygonscan';
|
||||
static const useTronGrid = 'use_trongrid';
|
||||
static const useMempoolFeeAPI = 'use_mempool_fee_api';
|
||||
static const defaultNanoRep = 'default_nano_representative';
|
||||
static const defaultBananoRep = 'default_banano_representative';
|
||||
static const lookupsTwitter = 'looks_up_twitter';
|
||||
|
@ -77,6 +78,7 @@ class PreferencesKey {
|
|||
static const exchangeProvidersSelection = 'exchange-providers-selection';
|
||||
static const autoGenerateSubaddressStatusKey = 'auto_generate_subaddress_status';
|
||||
static const moneroSeedType = 'monero_seed_type';
|
||||
static const bitcoinSeedType = 'bitcoin_seed_type';
|
||||
static const clearnetDonationLink = 'clearnet_donation_link';
|
||||
static const onionDonationLink = 'onion_donation_link';
|
||||
static const donationLinkWalletName = 'donation_link_wallet_name';
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cw_core/enumerable_item.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
|
||||
class SeedType extends EnumerableItem<int> with Serializable<int> {
|
||||
const SeedType({required String title, required int raw}) : super(title: title, raw: raw);
|
||||
class MoneroSeedType extends EnumerableItem<int> with Serializable<int> {
|
||||
const MoneroSeedType({required String title, required int raw}) : super(title: title, raw: raw);
|
||||
|
||||
static const all = [SeedType.legacy, SeedType.polyseed];
|
||||
static const all = [MoneroSeedType.legacy, MoneroSeedType.polyseed];
|
||||
|
||||
static const defaultSeedType = polyseed;
|
||||
|
||||
static const legacy = SeedType(raw: 0, title: 'Legacy (25 words)');
|
||||
static const polyseed = SeedType(raw: 1, title: 'Polyseed (16 words)');
|
||||
static const wowneroSeed = SeedType(raw: 2, title: 'Wownero (14 words)');
|
||||
static const legacy = MoneroSeedType(raw: 0, title: 'Legacy (25 words)');
|
||||
static const polyseed = MoneroSeedType(raw: 1, title: 'Polyseed (16 words)');
|
||||
static const wowneroSeed = MoneroSeedType(raw: 2, title: 'Wownero (14 words)');
|
||||
|
||||
static SeedType deserialize({required int raw}) {
|
||||
static MoneroSeedType deserialize({required int raw}) {
|
||||
switch (raw) {
|
||||
case 0:
|
||||
return legacy;
|
||||
|
@ -28,14 +29,39 @@ class SeedType extends EnumerableItem<int> with Serializable<int> {
|
|||
@override
|
||||
String toString() {
|
||||
switch (this) {
|
||||
case SeedType.legacy:
|
||||
case MoneroSeedType.legacy:
|
||||
return S.current.seedtype_legacy;
|
||||
case SeedType.polyseed:
|
||||
case MoneroSeedType.polyseed:
|
||||
return S.current.seedtype_polyseed;
|
||||
case SeedType.wowneroSeed:
|
||||
case MoneroSeedType.wowneroSeed:
|
||||
return S.current.seedtype_wownero;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BitcoinSeedType extends EnumerableItem<int> with Serializable<int> {
|
||||
const BitcoinSeedType(this.type, {required String title, required int raw})
|
||||
: super(title: title, raw: raw);
|
||||
|
||||
final DerivationType type;
|
||||
|
||||
static const all = [BitcoinSeedType.electrum, BitcoinSeedType.bip39];
|
||||
|
||||
static const defaultDerivationType = bip39;
|
||||
|
||||
static const electrum = BitcoinSeedType(DerivationType.electrum, raw: 0, title: 'Electrum');
|
||||
static const bip39 = BitcoinSeedType(DerivationType.bip39, raw: 1, title: 'BIP39');
|
||||
|
||||
static BitcoinSeedType deserialize({required int raw}) {
|
||||
switch (raw) {
|
||||
case 0:
|
||||
return electrum;
|
||||
case 1:
|
||||
return bip39;
|
||||
default:
|
||||
throw Exception('Unexpected token: $raw for SeedType deserialize');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,10 @@ class ExchangeProviderDescription extends EnumerableItem<int> with Serializable<
|
|||
ExchangeProviderDescription(title: 'ThorChain', raw: 8, image: 'assets/images/thorchain.png');
|
||||
static const quantex =
|
||||
ExchangeProviderDescription(title: 'Quantex', raw: 9, image: 'assets/images/quantex.png');
|
||||
static const letsExchange =
|
||||
ExchangeProviderDescription(title: 'LetsExchange', raw: 10, image: 'assets/images/letsexchange_icon.svg');
|
||||
static const stealthEx =
|
||||
ExchangeProviderDescription(title: 'StealthEx', raw: 11, image: 'assets/images/stealthex.png');
|
||||
|
||||
static ExchangeProviderDescription deserialize({required int raw}) {
|
||||
switch (raw) {
|
||||
|
@ -50,6 +54,10 @@ class ExchangeProviderDescription extends EnumerableItem<int> with Serializable<
|
|||
return thorChain;
|
||||
case 9:
|
||||
return quantex;
|
||||
case 10:
|
||||
return letsExchange;
|
||||
case 11:
|
||||
return stealthEx;
|
||||
default:
|
||||
throw Exception('Unexpected token: $raw for ExchangeProviderDescription deserialize');
|
||||
}
|
||||
|
|
292
lib/exchange/provider/letsexchange_exchange_provider.dart
Normal file
292
lib/exchange/provider/letsexchange_exchange_provider.dart
Normal file
|
@ -0,0 +1,292 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
LetsExchangeExchangeProvider() : super(pairList: supportedPairs(_notSupported));
|
||||
|
||||
static const List<CryptoCurrency> _notSupported = [];
|
||||
|
||||
static const apiKey = secrets.letsExchangeBearerToken;
|
||||
static const _baseUrl = 'api.letsexchange.io';
|
||||
static const _infoPath = '/api/v1/info';
|
||||
static const _infoRevertPath = '/api/v1/info-revert';
|
||||
static const _createTransactionPath = '/api/v1/transaction';
|
||||
static const _createTransactionRevertPath = '/api/v1/transaction-revert';
|
||||
static const _getTransactionPath = '/api/v1/transaction';
|
||||
|
||||
static const _affiliateId = secrets.letsExchangeAffiliateId;
|
||||
|
||||
@override
|
||||
String get title => 'LetsExchange';
|
||||
|
||||
@override
|
||||
bool get isAvailable => true;
|
||||
|
||||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => true;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description => ExchangeProviderDescription.letsExchange;
|
||||
|
||||
@override
|
||||
Future<bool> checkIsAvailable() async => true;
|
||||
|
||||
@override
|
||||
Future<Limits> fetchLimits(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final networkFrom = _getNetworkType(from);
|
||||
final networkTo = _getNetworkType(to);
|
||||
|
||||
try {
|
||||
final params = {
|
||||
'from': from.title,
|
||||
'to': to.title,
|
||||
if (networkFrom != null) 'network_from': networkFrom,
|
||||
if (networkTo != null) 'network_to': networkTo,
|
||||
'amount': '1',
|
||||
'affiliate_id': _affiliateId
|
||||
};
|
||||
|
||||
final responseJSON = await _getInfo(params, isFixedRateMode);
|
||||
final min = double.tryParse(responseJSON['min_amount'] as String);
|
||||
final max = double.tryParse(responseJSON['max_amount'] as String);
|
||||
return Limits(min: min, max: max);
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
throw Exception('Failed to fetch limits');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
final networkFrom = _getNetworkType(from);
|
||||
final networkTo = _getNetworkType(to);
|
||||
try {
|
||||
final params = {
|
||||
'from': from.title,
|
||||
'to': to.title,
|
||||
if (networkFrom != null) 'network_from': networkFrom,
|
||||
if (networkTo != null) 'network_to': networkTo,
|
||||
'amount': amount.toString(),
|
||||
'affiliate_id': _affiliateId
|
||||
};
|
||||
|
||||
final responseJSON = await _getInfo(params, isFixedRateMode);
|
||||
|
||||
final amountToGet = double.tryParse(responseJSON['amount'] as String) ?? 0.0;
|
||||
|
||||
return isFixedRateMode ? amount / amountToGet : amountToGet / amount;
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade(
|
||||
{required TradeRequest request,
|
||||
required bool isFixedRateMode,
|
||||
required bool isSendAll}) async {
|
||||
final networkFrom = _getNetworkType(request.fromCurrency);
|
||||
final networkTo = _getNetworkType(request.toCurrency);
|
||||
try {
|
||||
final params = {
|
||||
'from': request.fromCurrency.title,
|
||||
'to': request.toCurrency.title,
|
||||
if (networkFrom != null) 'network_from': networkFrom,
|
||||
if (networkTo != null) 'network_to': networkTo,
|
||||
'amount': isFixedRateMode ? request.toAmount.toString() : request.fromAmount.toString(),
|
||||
'affiliate_id': _affiliateId
|
||||
};
|
||||
|
||||
final responseInfoJSON = await _getInfo(params, isFixedRateMode);
|
||||
final rateId = responseInfoJSON['rate_id'] as String;
|
||||
|
||||
final withdrawalAddress = _normalizeBchAddress(request.toAddress);
|
||||
final returnAddress = _normalizeBchAddress(request.refundAddress);
|
||||
|
||||
final tradeParams = {
|
||||
'coin_from': request.fromCurrency.title,
|
||||
'coin_to': request.toCurrency.title,
|
||||
if (!isFixedRateMode) 'deposit_amount': request.fromAmount.toString(),
|
||||
'withdrawal': withdrawalAddress,
|
||||
if (isFixedRateMode) 'withdrawal_amount': request.toAmount.toString(),
|
||||
'withdrawal_extra_id': '',
|
||||
'return': returnAddress,
|
||||
'rate_id': rateId,
|
||||
if (networkFrom != null) 'network_from': networkFrom,
|
||||
if (networkTo != null) 'network_to': networkTo,
|
||||
'affiliate_id': _affiliateId
|
||||
};
|
||||
|
||||
final headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'Authorization': apiKey
|
||||
};
|
||||
|
||||
final uri = Uri.https(_baseUrl,
|
||||
isFixedRateMode ? _createTransactionRevertPath : _createTransactionPath, tradeParams);
|
||||
final response = await http.post(uri, headers: headers);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('LetsExchange create trade failed: ${response.body}');
|
||||
}
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final id = responseJSON['transaction_id'] as String;
|
||||
final from = responseJSON['coin_from'] as String;
|
||||
final to = responseJSON['coin_to'] as String;
|
||||
final payoutAddress = responseJSON['withdrawal'] as String;
|
||||
final depositAddress = responseJSON['deposit'] as String;
|
||||
final refundAddress = responseJSON['return'] as String;
|
||||
final depositAmount = responseJSON['deposit_amount'] as String;
|
||||
final receiveAmount = responseJSON['withdrawal_amount'] as String;
|
||||
final status = responseJSON['status'] as String;
|
||||
final createdAtString = responseJSON['created_at'] as String;
|
||||
final expiredAtTimestamp = responseJSON['expired_at'] as int;
|
||||
|
||||
final createdAt = DateTime.parse(createdAtString);
|
||||
final expiredAt = DateTime.fromMillisecondsSinceEpoch(expiredAtTimestamp * 1000);
|
||||
|
||||
CryptoCurrency fromCurrency;
|
||||
if (request.fromCurrency.tag != null && request.fromCurrency.title == from) {
|
||||
fromCurrency = request.fromCurrency;
|
||||
} else {
|
||||
fromCurrency = CryptoCurrency.fromString(from);
|
||||
}
|
||||
|
||||
CryptoCurrency toCurrency;
|
||||
if (request.toCurrency.tag != null && request.toCurrency.title == to) {
|
||||
toCurrency = request.toCurrency;
|
||||
} else {
|
||||
toCurrency = CryptoCurrency.fromString(to);
|
||||
}
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: fromCurrency,
|
||||
to: toCurrency,
|
||||
provider: description,
|
||||
inputAddress: depositAddress,
|
||||
payoutAddress: payoutAddress,
|
||||
refundAddress: refundAddress,
|
||||
amount: depositAmount,
|
||||
receiveAmount: receiveAmount,
|
||||
state: TradeState.deserialize(raw: status),
|
||||
createdAt: createdAt,
|
||||
expiredAt: expiredAt,
|
||||
);
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
throw TradeNotCreatedException(description);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> findTradeById({required String id}) async {
|
||||
final headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'Authorization': apiKey
|
||||
};
|
||||
|
||||
final url = Uri.https(_baseUrl, '$_getTransactionPath/$id');
|
||||
final response = await http.get(url, headers: headers);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('LetsExchange fetch trade failed: ${response.body}');
|
||||
}
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final from = responseJSON['coin_from'] as String;
|
||||
final to = responseJSON['coin_to'] as String;
|
||||
final payoutAddress = responseJSON['withdrawal'] as String;
|
||||
final depositAddress = responseJSON['deposit'] as String;
|
||||
final refundAddress = responseJSON['return'] as String;
|
||||
final depositAmount = responseJSON['deposit_amount'] as String;
|
||||
final receiveAmount = responseJSON['withdrawal_amount'] as String;
|
||||
final status = responseJSON['status'] as String;
|
||||
final createdAtString = responseJSON['created_at'] as String;
|
||||
final expiredAtTimestamp = responseJSON['expired_at'] as int;
|
||||
|
||||
final createdAt = DateTime.parse(createdAtString);
|
||||
final expiredAt = DateTime.fromMillisecondsSinceEpoch(expiredAtTimestamp * 1000);
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: CryptoCurrency.fromString(from),
|
||||
to: CryptoCurrency.fromString(to),
|
||||
provider: description,
|
||||
inputAddress: depositAddress,
|
||||
payoutAddress: payoutAddress,
|
||||
refundAddress: refundAddress,
|
||||
amount: depositAmount,
|
||||
receiveAmount: receiveAmount,
|
||||
state: TradeState.deserialize(raw: status),
|
||||
createdAt: createdAt,
|
||||
expiredAt: expiredAt,
|
||||
isRefund: status == 'refund',
|
||||
);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> _getInfo(Map<String, String> params, bool isFixedRateMode) async {
|
||||
final headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'Authorization': apiKey
|
||||
};
|
||||
|
||||
try {
|
||||
final uri = Uri.https(_baseUrl, isFixedRateMode ? _infoRevertPath : _infoPath, params);
|
||||
final response = await http.post(uri, headers: headers);
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('LetsExchange fetch info failed: ${response.body}');
|
||||
}
|
||||
return json.decode(response.body) as Map<String, dynamic>;
|
||||
} catch (e) {
|
||||
throw Exception('LetsExchange failed to fetch info ${e.toString()}');
|
||||
}
|
||||
}
|
||||
|
||||
String? _getNetworkType(CryptoCurrency currency) {
|
||||
if (currency.tag != null && currency.tag!.isNotEmpty) {
|
||||
switch (currency.tag!) {
|
||||
case 'TRX':
|
||||
return 'TRC20';
|
||||
case 'ETH':
|
||||
return 'ERC20';
|
||||
case 'BSC':
|
||||
return 'BEP20';
|
||||
case 'POLY':
|
||||
return 'MATIC';
|
||||
default:
|
||||
return currency.tag!;
|
||||
}
|
||||
}
|
||||
return currency.title;
|
||||
}
|
||||
|
||||
String _normalizeBchAddress(String address) =>
|
||||
address.startsWith('bitcoincash:') ? address.substring(12) : address;
|
||||
}
|
299
lib/exchange/provider/stealth_ex_exchange_provider.dart
Normal file
299
lib/exchange/provider/stealth_ex_exchange_provider.dart
Normal file
|
@ -0,0 +1,299 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class StealthExExchangeProvider extends ExchangeProvider {
|
||||
StealthExExchangeProvider() : super(pairList: supportedPairs(_notSupported));
|
||||
|
||||
static const List<CryptoCurrency> _notSupported = [];
|
||||
|
||||
static final apiKey = secrets.stealthExBearerToken;
|
||||
static final _additionalFeePercent = double.tryParse(secrets.stealthExAdditionalFeePercent);
|
||||
static const _baseUrl = 'https://api.stealthex.io';
|
||||
static const _rangePath = '/v4/rates/range';
|
||||
static const _amountPath = '/v4/rates/estimated-amount';
|
||||
static const _exchangesPath = '/v4/exchanges';
|
||||
|
||||
@override
|
||||
String get title => 'StealthEX';
|
||||
|
||||
@override
|
||||
bool get isAvailable => true;
|
||||
|
||||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => true;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description => ExchangeProviderDescription.stealthEx;
|
||||
|
||||
@override
|
||||
Future<bool> checkIsAvailable() async => true;
|
||||
|
||||
@override
|
||||
Future<Limits> fetchLimits(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final curFrom = isFixedRateMode ? to : from;
|
||||
final curTo = isFixedRateMode ? from : to;
|
||||
|
||||
final headers = {'Authorization': apiKey, 'Content-Type': 'application/json'};
|
||||
final body = {
|
||||
'route': {
|
||||
'from': {'symbol': _getName(curFrom), 'network': _getNetwork(curFrom)},
|
||||
'to': {'symbol': _getName(curTo), 'network': _getNetwork(curTo)}
|
||||
},
|
||||
'estimation': isFixedRateMode ? 'reversed' : 'direct',
|
||||
'rate': isFixedRateMode ? 'fixed' : 'floating',
|
||||
'additional_fee_percent': _additionalFeePercent,
|
||||
};
|
||||
|
||||
try {
|
||||
final response = await http.post(Uri.parse(_baseUrl + _rangePath),
|
||||
headers: headers, body: json.encode(body));
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('StealthEx fetch limits failed: ${response.body}');
|
||||
}
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final min = toDouble(responseJSON['min_amount']);
|
||||
final max = responseJSON['max_amount'] as double?;
|
||||
return Limits(min: min, max: max);
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
throw Exception('StealthEx failed to fetch limits');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
final response = await getEstimatedExchangeAmount(
|
||||
from: from, to: to, amount: amount, isFixedRateMode: isFixedRateMode);
|
||||
final estimatedAmount = response['estimated_amount'] as double? ?? 0.0;
|
||||
return estimatedAmount > 0.0
|
||||
? isFixedRateMode
|
||||
? amount / estimatedAmount
|
||||
: estimatedAmount / amount
|
||||
: 0.0;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade(
|
||||
{required TradeRequest request,
|
||||
required bool isFixedRateMode,
|
||||
required bool isSendAll}) async {
|
||||
String? rateId;
|
||||
String? validUntil;
|
||||
|
||||
try {
|
||||
if (isFixedRateMode) {
|
||||
final response = await getEstimatedExchangeAmount(
|
||||
from: request.fromCurrency,
|
||||
to: request.toCurrency,
|
||||
amount: double.parse(request.toAmount),
|
||||
isFixedRateMode: isFixedRateMode);
|
||||
rateId = response['rate_id'] as String?;
|
||||
validUntil = response['valid_until'] as String?;
|
||||
if (rateId == null) throw TradeNotCreatedException(description);
|
||||
}
|
||||
|
||||
final headers = {'Authorization': apiKey, 'Content-Type': 'application/json'};
|
||||
final body = {
|
||||
'route': {
|
||||
'from': {
|
||||
'symbol': _getName(request.fromCurrency),
|
||||
'network': _getNetwork(request.fromCurrency)
|
||||
},
|
||||
'to': {'symbol': _getName(request.toCurrency), 'network': _getNetwork(request.toCurrency)}
|
||||
},
|
||||
'estimation': isFixedRateMode ? 'reversed' : 'direct',
|
||||
'rate': isFixedRateMode ? 'fixed' : 'floating',
|
||||
if (isFixedRateMode) 'rate_id': rateId,
|
||||
'amount':
|
||||
isFixedRateMode ? double.parse(request.toAmount) : double.parse(request.fromAmount),
|
||||
'address': request.toAddress,
|
||||
'refund_address': request.refundAddress,
|
||||
'additional_fee_percent': _additionalFeePercent,
|
||||
};
|
||||
|
||||
final response = await http.post(Uri.parse(_baseUrl + _exchangesPath),
|
||||
headers: headers, body: json.encode(body));
|
||||
|
||||
if (response.statusCode != 201) {
|
||||
throw Exception('StealthEx create trade failed: ${response.body}');
|
||||
}
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final deposit = responseJSON['deposit'] as Map<String, dynamic>;
|
||||
final withdrawal = responseJSON['withdrawal'] as Map<String, dynamic>;
|
||||
|
||||
final id = responseJSON['id'] as String;
|
||||
final from = deposit['symbol'] as String;
|
||||
final to = withdrawal['symbol'] as String;
|
||||
final payoutAddress = withdrawal['address'] as String;
|
||||
final depositAddress = deposit['address'] as String;
|
||||
final refundAddress = responseJSON['refund_address'] as String;
|
||||
final depositAmount = toDouble(deposit['amount']);
|
||||
final receiveAmount = toDouble(withdrawal['amount']);
|
||||
final status = responseJSON['status'] as String;
|
||||
final createdAtString = responseJSON['created_at'] as String;
|
||||
|
||||
final createdAt = DateTime.parse(createdAtString);
|
||||
final expiredAt = validUntil != null
|
||||
? DateTime.parse(validUntil)
|
||||
: DateTime.now().add(Duration(minutes: 5));
|
||||
|
||||
|
||||
CryptoCurrency fromCurrency;
|
||||
if (request.fromCurrency.tag != null && request.fromCurrency.title.toLowerCase() == from) {
|
||||
fromCurrency = request.fromCurrency;
|
||||
} else {
|
||||
fromCurrency = CryptoCurrency.fromString(from);
|
||||
}
|
||||
|
||||
CryptoCurrency toCurrency;
|
||||
if (request.toCurrency.tag != null && request.toCurrency.title.toLowerCase() == to) {
|
||||
toCurrency = request.toCurrency;
|
||||
} else {
|
||||
toCurrency = CryptoCurrency.fromString(to);
|
||||
}
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: fromCurrency,
|
||||
to: toCurrency,
|
||||
provider: description,
|
||||
inputAddress: depositAddress,
|
||||
payoutAddress: payoutAddress,
|
||||
refundAddress: refundAddress,
|
||||
amount: depositAmount.toString(),
|
||||
receiveAmount: receiveAmount.toString(),
|
||||
state: TradeState.deserialize(raw: status),
|
||||
createdAt: createdAt,
|
||||
expiredAt: expiredAt,
|
||||
);
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
throw TradeNotCreatedException(description);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> findTradeById({required String id}) async {
|
||||
final headers = {'Authorization': apiKey, 'Content-Type': 'application/json'};
|
||||
|
||||
final uri = Uri.parse('$_baseUrl$_exchangesPath/$id');
|
||||
final response = await http.get(uri, headers: headers);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('StealthEx fetch trade failed: ${response.body}');
|
||||
}
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final deposit = responseJSON['deposit'] as Map<String, dynamic>;
|
||||
final withdrawal = responseJSON['withdrawal'] as Map<String, dynamic>;
|
||||
|
||||
final respId = responseJSON['id'] as String;
|
||||
final from = deposit['symbol'] as String;
|
||||
final to = withdrawal['symbol'] as String;
|
||||
final payoutAddress = withdrawal['address'] as String;
|
||||
final depositAddress = deposit['address'] as String;
|
||||
final refundAddress = responseJSON['refund_address'] as String;
|
||||
final depositAmount = toDouble(deposit['amount']);
|
||||
final receiveAmount = toDouble(withdrawal['amount']);
|
||||
final status = responseJSON['status'] as String;
|
||||
final createdAtString = responseJSON['created_at'] as String;
|
||||
final createdAt = DateTime.parse(createdAtString);
|
||||
|
||||
return Trade(
|
||||
id: respId,
|
||||
from: CryptoCurrency.fromString(from),
|
||||
to: CryptoCurrency.fromString(to),
|
||||
provider: description,
|
||||
inputAddress: depositAddress,
|
||||
payoutAddress: payoutAddress,
|
||||
refundAddress: refundAddress,
|
||||
amount: depositAmount.toString(),
|
||||
receiveAmount: receiveAmount.toString(),
|
||||
state: TradeState.deserialize(raw: status),
|
||||
createdAt: createdAt,
|
||||
isRefund: status == 'refunded',
|
||||
);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> getEstimatedExchangeAmount(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode}) async {
|
||||
final headers = {'Authorization': apiKey, 'Content-Type': 'application/json'};
|
||||
|
||||
final body = {
|
||||
'route': {
|
||||
'from': {'symbol': _getName(from), 'network': _getNetwork(from)},
|
||||
'to': {'symbol': _getName(to), 'network': _getNetwork(to)}
|
||||
},
|
||||
'estimation': isFixedRateMode ? 'reversed' : 'direct',
|
||||
'rate': isFixedRateMode ? 'fixed' : 'floating',
|
||||
'amount': amount,
|
||||
'additional_fee_percent': _additionalFeePercent,
|
||||
};
|
||||
|
||||
try {
|
||||
final response = await http.post(Uri.parse(_baseUrl + _amountPath),
|
||||
headers: headers, body: json.encode(body));
|
||||
if (response.statusCode != 200) return {};
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final rate = responseJSON['rate'] as Map<String, dynamic>?;
|
||||
return {
|
||||
'estimated_amount': responseJSON['estimated_amount'] as double?,
|
||||
if (rate != null) 'valid_until': rate['valid_until'] as String?,
|
||||
if (rate != null) 'rate_id': rate['id'] as String?
|
||||
};
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
double toDouble(dynamic value) {
|
||||
if (value is int) {
|
||||
return value.toDouble();
|
||||
} else if (value is double) {
|
||||
return value;
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
String _getName(CryptoCurrency currency) {
|
||||
if (currency == CryptoCurrency.usdcEPoly) return 'usdce';
|
||||
return currency.title.toLowerCase();
|
||||
}
|
||||
|
||||
String _getNetwork(CryptoCurrency currency) {
|
||||
if (currency.tag == null) return 'mainnet';
|
||||
|
||||
if (currency == CryptoCurrency.maticpoly) return 'mainnet';
|
||||
|
||||
if (currency.tag == 'POLY') return 'matic';
|
||||
|
||||
return currency.tag!.toLowerCase();
|
||||
}
|
||||
}
|
|
@ -40,7 +40,6 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
|
|||
static const exchanging = TradeState(raw: 'exchanging', title: 'Exchanging');
|
||||
static const sending = TradeState(raw: 'sending', title: 'Sending');
|
||||
static const success = TradeState(raw: 'success', title: 'Success');
|
||||
|
||||
static TradeState deserialize({required String raw}) {
|
||||
|
||||
switch (raw) {
|
||||
|
@ -107,6 +106,7 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
|
|||
case 'waitingAuthorization':
|
||||
return waitingAuthorization;
|
||||
case 'failed':
|
||||
case 'error':
|
||||
return failed;
|
||||
case 'completed':
|
||||
return completed;
|
||||
|
@ -119,12 +119,14 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
|
|||
case 'refunded':
|
||||
return refunded;
|
||||
case 'confirmation':
|
||||
case 'verifying':
|
||||
return confirmation;
|
||||
case 'confirmed':
|
||||
return confirmed;
|
||||
case 'exchanging':
|
||||
return exchanging;
|
||||
case 'sending':
|
||||
case 'sending_confirmation':
|
||||
return sending;
|
||||
case 'success':
|
||||
case 'done':
|
||||
|
|
|
@ -48,10 +48,14 @@ final rootKey = GlobalKey<RootState>();
|
|||
final RouteObserver<PageRoute<dynamic>> routeObserver = RouteObserver<PageRoute<dynamic>>();
|
||||
|
||||
Future<void> main({Key? topLevelKey}) async {
|
||||
await runAppWithZone(topLevelKey: topLevelKey);
|
||||
}
|
||||
|
||||
Future<void> runAppWithZone({Key? topLevelKey}) async {
|
||||
bool isAppRunning = false;
|
||||
|
||||
await runZonedGuarded(() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
FlutterError.onError = ExceptionHandler.onError;
|
||||
|
||||
/// A callback that is invoked when an unhandled error occurs in the root
|
||||
|
@ -61,42 +65,14 @@ Future<void> main({Key? topLevelKey}) async {
|
|||
|
||||
return true;
|
||||
};
|
||||
await initializeAppAtRoot();
|
||||
|
||||
await setDefaultMinimumWindowSize();
|
||||
|
||||
await CakeHive.close();
|
||||
|
||||
await initializeAppConfigs();
|
||||
|
||||
runApp(App(key: topLevelKey));
|
||||
|
||||
runApp(App());
|
||||
isAppRunning = true;
|
||||
}, (error, stackTrace) async {
|
||||
if (!isAppRunning) {
|
||||
runApp(
|
||||
MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
scrollBehavior: AppScrollBehavior(),
|
||||
home: Scaffold(
|
||||
body: SingleChildScrollView(
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(top: 50, left: 20, right: 20, bottom: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'Error:\n${error.toString()}',
|
||||
style: TextStyle(fontSize: 22),
|
||||
),
|
||||
Text(
|
||||
'Stack trace:\n${stackTrace.toString()}',
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
TopLevelErrorWidget(error: error, stackTrace: stackTrace),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -104,6 +80,12 @@ Future<void> main({Key? topLevelKey}) async {
|
|||
});
|
||||
}
|
||||
|
||||
Future<void> initializeAppAtRoot({bool reInitializing = false}) async {
|
||||
if (!reInitializing) await setDefaultMinimumWindowSize();
|
||||
await CakeHive.close();
|
||||
await initializeAppConfigs();
|
||||
}
|
||||
|
||||
Future<void> initializeAppConfigs() async {
|
||||
setRootDirFromEnv();
|
||||
final appDir = await getAppDir();
|
||||
|
@ -340,3 +322,41 @@ class _HomeState extends State<_Home> {
|
|||
return const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
|
||||
class TopLevelErrorWidget extends StatelessWidget {
|
||||
const TopLevelErrorWidget({
|
||||
required this.error,
|
||||
required this.stackTrace,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final Object error;
|
||||
final StackTrace stackTrace;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
scrollBehavior: AppScrollBehavior(),
|
||||
home: Scaffold(
|
||||
body: SingleChildScrollView(
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(top: 50, left: 20, right: 20, bottom: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'Error:\n${error.toString()}',
|
||||
style: TextStyle(fontSize: 22),
|
||||
),
|
||||
Text(
|
||||
'Stack trace:\n${stackTrace.toString()}',
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,9 @@ void startCheckConnectionReaction(WalletBase wallet, SettingsStore settingsStore
|
|||
return;
|
||||
}
|
||||
|
||||
if (wallet.syncStatus is LostConnectionSyncStatus || wallet.syncStatus is FailedSyncStatus) {
|
||||
if (wallet.type != WalletType.bitcoin &&
|
||||
(wallet.syncStatus is LostConnectionSyncStatus ||
|
||||
wallet.syncStatus is FailedSyncStatus)) {
|
||||
final alive = await settingsStore.getCurrentNode(wallet.type).requestNode();
|
||||
|
||||
if (alive) {
|
||||
|
|
|
@ -17,6 +17,8 @@ import 'package:cake_wallet/src/screens/backup/edit_backup_password_page.dart';
|
|||
import 'package:cake_wallet/src/screens/buy/buy_options_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/buy_webview_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/webview_page.dart';
|
||||
import 'package:cake_wallet/src/screens/cake_pay/auth/cake_pay_account_page.dart';
|
||||
import 'package:cake_wallet/src/screens/cake_pay/cake_pay.dart';
|
||||
import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart';
|
||||
import 'package:cake_wallet/src/screens/connect_device/select_hardware_wallet_account_page.dart';
|
||||
import 'package:cake_wallet/src/screens/contact/contact_list_page.dart';
|
||||
|
@ -27,8 +29,8 @@ import 'package:cake_wallet/src/screens/dashboard/edit_token_page.dart';
|
|||
import 'package:cake_wallet/src/screens/dashboard/home_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/address_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/nft_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/sign_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/transactions_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/sign_page.dart';
|
||||
import 'package:cake_wallet/src/screens/disclaimer/disclaimer_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/exchange_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart';
|
||||
|
@ -43,10 +45,9 @@ import 'package:cake_wallet/src/screens/new_wallet/new_wallet_page.dart';
|
|||
import 'package:cake_wallet/src/screens/new_wallet/new_wallet_type_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/node_create_or_edit_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/pow_node_create_or_edit_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/address_list_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/sweeping_wallet_page.dart';
|
||||
import 'package:cake_wallet/src/screens/order_details/order_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/address_list_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart';
|
||||
|
@ -69,11 +70,9 @@ import 'package:cake_wallet/src/screens/settings/manage_nodes_page.dart';
|
|||
import 'package:cake_wallet/src/screens/settings/other_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/privacy_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/security_backup_page.dart';
|
||||
import 'package:cake_wallet/src/screens/cake_pay/auth/cake_pay_account_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/silent_payments_settings.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/tor_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/trocador_providers_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/tor_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart';
|
||||
|
@ -85,19 +84,18 @@ import 'package:cake_wallet/src/screens/support/support_page.dart';
|
|||
import 'package:cake_wallet/src/screens/support_chat/support_chat_page.dart';
|
||||
import 'package:cake_wallet/src/screens/support_other_links/support_other_links_page.dart';
|
||||
import 'package:cake_wallet/src/screens/trade_details/trade_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet/wallet_edit_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_page.dart';
|
||||
import 'package:cake_wallet/src/screens/welcome/create_welcome_page.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
|
@ -106,7 +104,7 @@ import 'package:cake_wallet/view_model/dashboard/sign_view_model.dart';
|
|||
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_hardware_restore_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
|
@ -120,7 +118,7 @@ import 'package:cw_core/wallet_type.dart';
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:cake_wallet/src/screens/cake_pay/cake_pay.dart';
|
||||
|
||||
import 'src/screens/dashboard/pages/nft_import_page.dart';
|
||||
|
||||
late RouteSettings currentRouteSettings;
|
||||
|
@ -135,7 +133,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
case Routes.newWalletFromWelcome:
|
||||
if (SettingsStoreBase.walletPasswordDirectInput) {
|
||||
if (availableWalletTypes.length == 1) {
|
||||
return createRoute(RouteSettings(name: Routes.newWallet, arguments: availableWalletTypes.first));
|
||||
return createRoute(
|
||||
RouteSettings(name: Routes.newWallet, arguments: availableWalletTypes.first));
|
||||
} else {
|
||||
return createRoute(RouteSettings(name: Routes.newWalletType));
|
||||
}
|
||||
|
@ -162,10 +161,10 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
case Routes.newWallet:
|
||||
final type = settings.arguments as WalletType;
|
||||
final walletNewVM = getIt.get<WalletNewVM>(param1: type);
|
||||
final seedTypeViewModel = getIt.get<SeedTypeViewModel>();
|
||||
final seedSettingsViewModel = getIt.get<SeedSettingsViewModel>();
|
||||
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => NewWalletPage(walletNewVM, seedTypeViewModel));
|
||||
builder: (_) => NewWalletPage(walletNewVM, seedSettingsViewModel));
|
||||
|
||||
case Routes.chooseHardwareWalletAccount:
|
||||
final arguments = settings.arguments as List<dynamic>;
|
||||
|
@ -348,16 +347,14 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
case Routes.auth:
|
||||
return MaterialPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_)
|
||||
=> SettingsStoreBase.walletPasswordDirectInput
|
||||
? getIt.get<WalletUnlockPage>(
|
||||
param1: WalletUnlockArguments(
|
||||
builder: (_) => SettingsStoreBase.walletPasswordDirectInput
|
||||
? getIt.get<WalletUnlockPage>(
|
||||
param1: WalletUnlockArguments(
|
||||
callback: settings.arguments as OnAuthenticationFinished),
|
||||
instanceName: 'wallet_unlock_verifiable',
|
||||
param2: true)
|
||||
: getIt.get<AuthPage>(
|
||||
param1: settings.arguments as OnAuthenticationFinished,
|
||||
param2: true));
|
||||
instanceName: 'wallet_unlock_verifiable',
|
||||
param2: true)
|
||||
: getIt.get<AuthPage>(
|
||||
param1: settings.arguments as OnAuthenticationFinished, param2: true));
|
||||
|
||||
case Routes.totpAuthCodePage:
|
||||
final args = settings.arguments as TotpAuthArgumentsModel;
|
||||
|
@ -371,28 +368,25 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
case Routes.walletUnlockLoadable:
|
||||
return MaterialPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_)
|
||||
=> getIt.get<WalletUnlockPage>(
|
||||
builder: (_) => getIt.get<WalletUnlockPage>(
|
||||
param1: settings.arguments as WalletUnlockArguments,
|
||||
instanceName: 'wallet_unlock_loadable',
|
||||
instanceName: 'wallet_unlock_loadable',
|
||||
param2: true));
|
||||
|
||||
case Routes.unlock:
|
||||
return MaterialPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_)
|
||||
=> SettingsStoreBase.walletPasswordDirectInput
|
||||
? WillPopScope(
|
||||
child: getIt.get<WalletUnlockPage>(
|
||||
builder: (_) => SettingsStoreBase.walletPasswordDirectInput
|
||||
? WillPopScope(
|
||||
child: getIt.get<WalletUnlockPage>(
|
||||
param1: WalletUnlockArguments(
|
||||
callback: settings.arguments as OnAuthenticationFinished),
|
||||
callback: settings.arguments as OnAuthenticationFinished),
|
||||
param2: false,
|
||||
instanceName: 'wallet_unlock_verifiable'),
|
||||
onWillPop: () async => false)
|
||||
: WillPopScope(
|
||||
child: getIt.get<AuthPage>(
|
||||
param1: settings.arguments as OnAuthenticationFinished,
|
||||
param2: false),
|
||||
onWillPop: () async => false)
|
||||
: WillPopScope(
|
||||
child: getIt.get<AuthPage>(
|
||||
param1: settings.arguments as OnAuthenticationFinished, param2: false),
|
||||
onWillPop: () async => false));
|
||||
|
||||
case Routes.silentPaymentsSettings:
|
||||
|
@ -437,11 +431,12 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
return CupertinoPageRoute<void>(
|
||||
builder: (context) => WillPopScope(
|
||||
child: SettingsStoreBase.walletPasswordDirectInput
|
||||
? getIt.get<WalletUnlockPage>(instanceName: 'wallet_password_login')
|
||||
: getIt.get<AuthPage>(instanceName: 'login'),
|
||||
? getIt.get<WalletUnlockPage>(instanceName: 'wallet_password_login')
|
||||
: getIt.get<AuthPage>(instanceName: 'login'),
|
||||
onWillPop: () async =>
|
||||
// FIX-ME: Additional check does it works correctly
|
||||
(await SystemChannels.platform.invokeMethod<bool>('SystemNavigator.pop') ?? false)),
|
||||
// FIX-ME: Additional check does it works correctly
|
||||
(await SystemChannels.platform.invokeMethod<bool>('SystemNavigator.pop') ??
|
||||
false)),
|
||||
fullscreenDialog: true);
|
||||
|
||||
case Routes.newPowNode:
|
||||
|
@ -537,8 +532,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
|
||||
case Routes.support:
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_) => getIt.get<SupportPage>());
|
||||
fullscreenDialog: true, builder: (_) => getIt.get<SupportPage>());
|
||||
|
||||
case Routes.supportLiveChat:
|
||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<SupportChatPage>());
|
||||
|
@ -567,8 +561,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
|
||||
case Routes.cakePayBuyCardPage:
|
||||
final args = settings.arguments as List;
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<CakePayBuyCardPage>(param1: args));
|
||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<CakePayBuyCardPage>(param1: args));
|
||||
|
||||
case Routes.cakePayBuyCardDetailPage:
|
||||
final args = settings.arguments as List;
|
||||
|
@ -582,7 +575,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
|
||||
case Routes.cakePayVerifyOtpPage:
|
||||
final args = settings.arguments as List;
|
||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<CakePayVerifyOtpPage>(param1: args));
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<CakePayVerifyOtpPage>(param1: args));
|
||||
|
||||
case Routes.cakePayAccountPage:
|
||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<CakePayAccountPage>());
|
||||
|
@ -597,16 +591,19 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
case Routes.advancedPrivacySettings:
|
||||
final args = settings.arguments as Map<String, dynamic>;
|
||||
final type = args['type'] as WalletType;
|
||||
final isFromRestore = args['isFromRestore'] as bool? ?? false;
|
||||
final useTestnet = args['useTestnet'] as bool;
|
||||
final toggleTestnet = args['toggleTestnet'] as Function(bool? val);
|
||||
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => AdvancedPrivacySettingsPage(
|
||||
useTestnet,
|
||||
toggleTestnet,
|
||||
getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
|
||||
getIt.get<NodeCreateOrEditViewModel>(param1: type, param2: false),
|
||||
getIt.get<SeedTypeViewModel>(),
|
||||
isFromRestore: isFromRestore,
|
||||
useTestnet: useTestnet,
|
||||
toggleUseTestnet: toggleTestnet,
|
||||
advancedPrivacySettingsViewModel:
|
||||
getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
|
||||
nodeViewModel: getIt.get<NodeCreateOrEditViewModel>(param1: type, param2: false),
|
||||
seedSettingsViewModel: getIt.get<SeedSettingsViewModel>(),
|
||||
));
|
||||
|
||||
case Routes.anonPayInvoicePage:
|
||||
|
@ -709,7 +706,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
getIt.get<SignViewModel>(),
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
case Routes.connectDevices:
|
||||
final params = settings.arguments as ConnectDevicePageParams;
|
||||
return MaterialPageRoute<void>(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/utils/image_utill.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
|
@ -36,7 +37,8 @@ class TradeRow extends StatelessWidget {
|
|||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
child: Image.asset(provider.image, width: 36, height: 36)),
|
||||
child: ImageUtil.getImageFromPath(
|
||||
imagePath: provider.image, height: 36, width: 36)),
|
||||
SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
|
|
|
@ -1,23 +1,7 @@
|
|||
import 'package:cake_wallet/core/wallet_name_validator.dart';
|
||||
import 'package:cake_wallet/entities/generate_name.dart';
|
||||
import 'package:cake_wallet/entities/seed_type.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/address_text_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/seed_language_picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/seed_widget.dart';
|
||||
import 'package:cake_wallet/themes/extensions/address_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:polyseed/polyseed.dart';
|
||||
|
||||
class VerifyForm extends StatefulWidget {
|
||||
VerifyForm({
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
|||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/store/dashboard/trades_store.dart';
|
||||
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||
import 'package:cake_wallet/utils/image_utill.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
@ -102,7 +103,8 @@ class ExchangeConfirmPage extends BasePage {
|
|||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
(trade.provider.image?.isNotEmpty ?? false)
|
||||
? Image.asset(trade.provider.image, height: 50)
|
||||
? ImageUtil.getImageFromPath(
|
||||
imagePath: trade.provider.image, width: 50)
|
||||
: const SizedBox(),
|
||||
if (!trade.provider.horizontalLogo)
|
||||
Padding(
|
||||
|
|
|
@ -40,13 +40,11 @@ class NanoChangeRepPage extends BasePage {
|
|||
(node) => node.account == currentRepAccount,
|
||||
orElse: () => N2Node(
|
||||
account: currentRepAccount,
|
||||
alias: currentRepAccount,
|
||||
score: 0,
|
||||
uptime: "???",
|
||||
weight: 0,
|
||||
),
|
||||
);
|
||||
|
||||
return currentNode;
|
||||
}
|
||||
|
||||
|
@ -57,9 +55,7 @@ class NanoChangeRepPage extends BasePage {
|
|||
child: FutureBuilder(
|
||||
future: nano!.getN2Reps(_wallet),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == null) {
|
||||
return SizedBox();
|
||||
}
|
||||
final reps = snapshot.data ?? [];
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
|
@ -101,29 +97,35 @@ class NanoChangeRepPage extends BasePage {
|
|||
),
|
||||
_buildSingleRepresentative(
|
||||
context,
|
||||
getCurrentRepNode(snapshot.data as List<N2Node>),
|
||||
getCurrentRepNode(reps),
|
||||
isList: false,
|
||||
divider: false,
|
||||
),
|
||||
Divider(height: 20),
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 12),
|
||||
child: Text(
|
||||
S.current.nano_pick_new_rep,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
if (reps.isNotEmpty) ...[
|
||||
Divider(height: 20),
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 12),
|
||||
child: Text(
|
||||
S.current.nano_pick_new_rep,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Divider(height: 20),
|
||||
],
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
contentPadding: EdgeInsets.only(bottom: 24),
|
||||
content: Container(
|
||||
child: Column(
|
||||
children: _getRepresentativeWidgets(context, snapshot.data as List<N2Node>),
|
||||
),
|
||||
child: reps.isNotEmpty
|
||||
? Column(
|
||||
children: _getRepresentativeWidgets(context, reps),
|
||||
)
|
||||
: SizedBox(),
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(bottom: 24),
|
||||
bottomSection: Observer(
|
||||
|
@ -207,19 +209,22 @@ class NanoChangeRepPage extends BasePage {
|
|||
final List<Widget> ret = [];
|
||||
for (final N2Node node in list) {
|
||||
if (node.alias != null && node.alias!.trim().isNotEmpty) {
|
||||
ret.add(_buildSingleRepresentative(context, node));
|
||||
bool divider = node != list.first;
|
||||
ret.add(_buildSingleRepresentative(context, node, divider: divider, isList: true));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Widget _buildSingleRepresentative(BuildContext context, N2Node rep, {bool isList = true}) {
|
||||
Widget _buildSingleRepresentative(
|
||||
BuildContext context,
|
||||
N2Node rep, {
|
||||
bool isList = true,
|
||||
bool divider = false,
|
||||
}) {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
if (isList)
|
||||
Divider(
|
||||
height: 2,
|
||||
),
|
||||
if (divider) Divider(height: 2),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
padding: EdgeInsets.zero,
|
||||
|
@ -244,11 +249,11 @@ class NanoChangeRepPage extends BasePage {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
_sanitizeAlias(rep.alias),
|
||||
rep.alias ?? rep.account!,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 18,
|
||||
fontSize: rep.alias == null ? 14 : 18,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
|
@ -337,11 +342,4 @@ class NanoChangeRepPage extends BasePage {
|
|||
],
|
||||
);
|
||||
}
|
||||
|
||||
String _sanitizeAlias(String? alias) {
|
||||
if (alias != null) {
|
||||
return alias.replaceAll(RegExp(r'[^a-zA-Z_.!?_;:-]'), '');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,52 +3,61 @@ import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
|||
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/seed_phrase_length.dart';
|
||||
import 'package:cake_wallet/entities/seed_type.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
|
||||
import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
|
||||
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class AdvancedPrivacySettingsPage extends BasePage {
|
||||
AdvancedPrivacySettingsPage(this.useTestnet, this.toggleUseTestnet,
|
||||
this.advancedPrivacySettingsViewModel, this.nodeViewModel, this.seedTypeViewModel);
|
||||
AdvancedPrivacySettingsPage({
|
||||
required this.isFromRestore,
|
||||
required this.useTestnet,
|
||||
required this.toggleUseTestnet,
|
||||
required this.advancedPrivacySettingsViewModel,
|
||||
required this.nodeViewModel,
|
||||
required this.seedSettingsViewModel,
|
||||
});
|
||||
|
||||
final AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel;
|
||||
final NodeCreateOrEditViewModel nodeViewModel;
|
||||
final SeedTypeViewModel seedTypeViewModel;
|
||||
final SeedSettingsViewModel seedSettingsViewModel;
|
||||
|
||||
@override
|
||||
String get title => S.current.privacy_settings;
|
||||
|
||||
final bool isFromRestore;
|
||||
final bool useTestnet;
|
||||
final Function(bool? val) toggleUseTestnet;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => AdvancedPrivacySettingsBody(useTestnet, toggleUseTestnet,
|
||||
advancedPrivacySettingsViewModel, nodeViewModel, seedTypeViewModel);
|
||||
Widget body(BuildContext context) => _AdvancedPrivacySettingsBody(isFromRestore, useTestnet,
|
||||
toggleUseTestnet, advancedPrivacySettingsViewModel, nodeViewModel, seedSettingsViewModel);
|
||||
}
|
||||
|
||||
class AdvancedPrivacySettingsBody extends StatefulWidget {
|
||||
const AdvancedPrivacySettingsBody(this.useTestnet, this.toggleUseTestnet,
|
||||
class _AdvancedPrivacySettingsBody extends StatefulWidget {
|
||||
const _AdvancedPrivacySettingsBody(this.isFromRestore, this.useTestnet, this.toggleUseTestnet,
|
||||
this.privacySettingsViewModel, this.nodeViewModel, this.seedTypeViewModel,
|
||||
{Key? key})
|
||||
: super(key: key);
|
||||
|
||||
final AdvancedPrivacySettingsViewModel privacySettingsViewModel;
|
||||
final NodeCreateOrEditViewModel nodeViewModel;
|
||||
final SeedTypeViewModel seedTypeViewModel;
|
||||
final SeedSettingsViewModel seedTypeViewModel;
|
||||
|
||||
final bool isFromRestore;
|
||||
final bool useTestnet;
|
||||
final Function(bool? val) toggleUseTestnet;
|
||||
|
||||
|
@ -56,15 +65,25 @@ class AdvancedPrivacySettingsBody extends StatefulWidget {
|
|||
_AdvancedPrivacySettingsBodyState createState() => _AdvancedPrivacySettingsBodyState();
|
||||
}
|
||||
|
||||
class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBody> {
|
||||
_AdvancedPrivacySettingsBodyState();
|
||||
|
||||
class _AdvancedPrivacySettingsBodyState extends State<_AdvancedPrivacySettingsBody> {
|
||||
final TextEditingController passphraseController = TextEditingController();
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
bool? testnetValue;
|
||||
|
||||
bool obscurePassphrase = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
passphraseController.text = widget.seedTypeViewModel.passphrase ?? '';
|
||||
|
||||
passphraseController
|
||||
.addListener(() => widget.seedTypeViewModel.setPassphrase(passphraseController.text));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (testnetValue == null && widget.useTestnet != null) {
|
||||
if (testnetValue == null && widget.useTestnet) {
|
||||
testnetValue = widget.useTestnet;
|
||||
}
|
||||
|
||||
|
@ -97,6 +116,61 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
|
|||
),
|
||||
);
|
||||
}),
|
||||
if (widget.privacySettingsViewModel.hasSeedTypeOption)
|
||||
Observer(builder: (_) {
|
||||
return SettingsChoicesCell(
|
||||
ChoicesListItem<MoneroSeedType>(
|
||||
title: S.current.seedtype,
|
||||
items: MoneroSeedType.all,
|
||||
selectedItem: widget.seedTypeViewModel.moneroSeedType,
|
||||
onItemSelected: widget.seedTypeViewModel.setMoneroSeedType,
|
||||
),
|
||||
);
|
||||
}),
|
||||
if ([WalletType.bitcoin, WalletType.litecoin]
|
||||
.contains(widget.privacySettingsViewModel.type))
|
||||
Observer(builder: (_) {
|
||||
return SettingsChoicesCell(
|
||||
ChoicesListItem<BitcoinSeedType>(
|
||||
title: S.current.seedtype,
|
||||
items: BitcoinSeedType.all,
|
||||
selectedItem: widget.seedTypeViewModel.bitcoinSeedType,
|
||||
onItemSelected: widget.seedTypeViewModel.setBitcoinSeedType,
|
||||
),
|
||||
);
|
||||
}),
|
||||
if (!widget.isFromRestore) ...[
|
||||
Observer(builder: (_) {
|
||||
if (widget.privacySettingsViewModel.hasSeedPhraseLengthOption)
|
||||
return SettingsPickerCell<SeedPhraseLength>(
|
||||
title: S.current.seed_phrase_length,
|
||||
items: SeedPhraseLength.values,
|
||||
selectedItem: widget.privacySettingsViewModel.seedPhraseLength,
|
||||
onItemSelected: (SeedPhraseLength length) {
|
||||
widget.privacySettingsViewModel.setSeedPhraseLength(length);
|
||||
},
|
||||
);
|
||||
return Container();
|
||||
}),
|
||||
if (widget.privacySettingsViewModel.hasPassphraseOption)
|
||||
Padding(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: BaseTextFormField(
|
||||
hintText: S.current.passphrase,
|
||||
controller: passphraseController,
|
||||
obscureText: obscurePassphrase,
|
||||
suffixIcon: GestureDetector(
|
||||
onTap: () => setState(() {
|
||||
obscurePassphrase = !obscurePassphrase;
|
||||
}),
|
||||
child: Icon(
|
||||
Icons.remove_red_eye,
|
||||
color: obscurePassphrase ? Colors.black54 : Colors.black26,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
Observer(builder: (_) {
|
||||
return Column(
|
||||
children: [
|
||||
|
@ -122,31 +196,9 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
|
|||
],
|
||||
);
|
||||
}),
|
||||
if (widget.privacySettingsViewModel.hasSeedPhraseLengthOption)
|
||||
Observer(builder: (_) {
|
||||
return SettingsPickerCell<SeedPhraseLength>(
|
||||
title: S.current.seed_phrase_length,
|
||||
items: SeedPhraseLength.values,
|
||||
selectedItem: widget.privacySettingsViewModel.seedPhraseLength,
|
||||
onItemSelected: (SeedPhraseLength length) {
|
||||
widget.privacySettingsViewModel.setSeedPhraseLength(length);
|
||||
},
|
||||
);
|
||||
}),
|
||||
if (widget.privacySettingsViewModel.hasSeedTypeOption)
|
||||
Observer(builder: (_) {
|
||||
return SettingsChoicesCell(
|
||||
ChoicesListItem<SeedType>(
|
||||
title: S.current.seedtype,
|
||||
items: SeedType.all,
|
||||
selectedItem: widget.seedTypeViewModel.moneroSeedType,
|
||||
onItemSelected: widget.seedTypeViewModel.setMoneroSeedType,
|
||||
),
|
||||
);
|
||||
}),
|
||||
if (widget.privacySettingsViewModel.type == WalletType.bitcoin)
|
||||
Builder(builder: (_) {
|
||||
final val = testnetValue!;
|
||||
final val = testnetValue ?? false;
|
||||
return SettingsSwitcherCell(
|
||||
title: S.current.use_testnet,
|
||||
value: val,
|
||||
|
@ -154,7 +206,7 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
|
|||
setState(() {
|
||||
testnetValue = !val;
|
||||
});
|
||||
widget.toggleUseTestnet!.call(testnetValue);
|
||||
widget.toggleUseTestnet.call(testnetValue);
|
||||
});
|
||||
}),
|
||||
],
|
||||
|
@ -203,4 +255,11 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
passphraseController
|
||||
.removeListener(() => widget.seedTypeViewModel.setPassphrase(passphraseController.text));
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +1,35 @@
|
|||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/core/wallet_name_validator.dart';
|
||||
import 'package:cake_wallet/entities/generate_name.dart';
|
||||
import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/entities/seed_type.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/main.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/core/wallet_name_validator.dart';
|
||||
import 'package:cake_wallet/src/widgets/seed_language_selector.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/src/widgets/seed_language_picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
|
||||
import 'package:cake_wallet/src/widgets/seed_language_selector.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||
import 'package:cake_wallet/entities/seed_type.dart';
|
||||
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
class NewWalletPage extends BasePage {
|
||||
NewWalletPage(this._walletNewVM, this._seedTypeViewModel);
|
||||
NewWalletPage(this._walletNewVM, this._seedSettingsViewModel);
|
||||
|
||||
final WalletNewVM _walletNewVM;
|
||||
final SeedTypeViewModel _seedTypeViewModel;
|
||||
final SeedSettingsViewModel _seedSettingsViewModel;
|
||||
|
||||
final walletNameImage = Image.asset('assets/images/wallet_name.png');
|
||||
|
||||
|
@ -51,15 +50,15 @@ class NewWalletPage extends BasePage {
|
|||
Widget body(BuildContext context) => WalletNameForm(
|
||||
_walletNewVM,
|
||||
currentTheme.type == ThemeType.dark ? walletNameImage : walletNameLightImage,
|
||||
_seedTypeViewModel);
|
||||
_seedSettingsViewModel);
|
||||
}
|
||||
|
||||
class WalletNameForm extends StatefulWidget {
|
||||
WalletNameForm(this._walletNewVM, this.walletImage, this._seedTypeViewModel);
|
||||
WalletNameForm(this._walletNewVM, this.walletImage, this._seedSettingsViewModel);
|
||||
|
||||
final WalletNewVM _walletNewVM;
|
||||
final Image walletImage;
|
||||
final SeedTypeViewModel _seedTypeViewModel;
|
||||
final SeedSettingsViewModel _seedSettingsViewModel;
|
||||
|
||||
@override
|
||||
_WalletNameFormState createState() => _WalletNameFormState(_walletNewVM);
|
||||
|
@ -113,7 +112,7 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
|||
}
|
||||
});
|
||||
|
||||
_setSeedType(SeedType.defaultSeedType);
|
||||
_setSeedType(MoneroSeedType.defaultSeedType);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
@ -291,12 +290,12 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
|||
padding: EdgeInsets.only(top: 24),
|
||||
child: SelectButton(
|
||||
key: ValueKey('new_wallet_page_monero_seed_type_button_key'),
|
||||
text: widget._seedTypeViewModel.moneroSeedType.title,
|
||||
text: widget._seedSettingsViewModel.moneroSeedType.title,
|
||||
onTap: () async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => Picker(
|
||||
items: SeedType.all,
|
||||
items: MoneroSeedType.all,
|
||||
selectedAtIndex: isPolyseed ? 1 : 0,
|
||||
onItemSelected: _setSeedType,
|
||||
isSeparated: false,
|
||||
|
@ -315,8 +314,8 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
|||
buttonKey: ValueKey('new_wallet_page_seed_language_selector_button_key'),
|
||||
initialSelected: defaultSeedLanguage,
|
||||
seedType: _walletNewVM.hasSeedType
|
||||
? widget._seedTypeViewModel.moneroSeedType
|
||||
: SeedType.legacy,
|
||||
? widget._seedSettingsViewModel.moneroSeedType
|
||||
: MoneroSeedType.legacy,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
@ -389,10 +388,10 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
|||
_formProcessing = false;
|
||||
}
|
||||
|
||||
bool get isPolyseed => widget._seedTypeViewModel.moneroSeedType == SeedType.polyseed;
|
||||
bool get isPolyseed => widget._seedSettingsViewModel.moneroSeedType == MoneroSeedType.polyseed;
|
||||
|
||||
void _setSeedType(SeedType item) {
|
||||
widget._seedTypeViewModel.setMoneroSeedType(item);
|
||||
void _setSeedType(MoneroSeedType item) {
|
||||
widget._seedSettingsViewModel.setMoneroSeedType(item);
|
||||
_languageSelectorKey.currentState?.selected = defaultSeedLanguage; // Reset Seed language
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,35 +9,34 @@ import 'package:cake_wallet/src/widgets/seed_language_picker.dart';
|
|||
import 'package:cake_wallet/src/widgets/seed_widget.dart';
|
||||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:polyseed/polyseed.dart';
|
||||
|
||||
class WalletRestoreFromSeedForm extends StatefulWidget {
|
||||
WalletRestoreFromSeedForm(
|
||||
{Key? key,
|
||||
required this.displayLanguageSelector,
|
||||
required this.displayBlockHeightSelector,
|
||||
required this.displayPassphrase,
|
||||
required this.type,
|
||||
required this.displayWalletPassword,
|
||||
required this.seedTypeViewModel,
|
||||
this.blockHeightFocusNode,
|
||||
this.onHeightOrDateEntered,
|
||||
this.onSeedChange,
|
||||
this.onLanguageChange,
|
||||
this.onPasswordChange,
|
||||
this.onRepeatedPasswordChange})
|
||||
: super(key: key);
|
||||
WalletRestoreFromSeedForm({Key? key,
|
||||
required this.displayLanguageSelector,
|
||||
required this.displayBlockHeightSelector,
|
||||
required this.displayPassphrase,
|
||||
required this.type,
|
||||
required this.displayWalletPassword,
|
||||
required this.seedSettingsViewModel,
|
||||
this.blockHeightFocusNode,
|
||||
this.onHeightOrDateEntered,
|
||||
this.onSeedChange,
|
||||
this.onLanguageChange,
|
||||
this.onPasswordChange,
|
||||
this.onRepeatedPasswordChange,
|
||||
}) : super(key: key);
|
||||
|
||||
final WalletType type;
|
||||
final bool displayLanguageSelector;
|
||||
final bool displayBlockHeightSelector;
|
||||
final bool displayWalletPassword;
|
||||
final bool displayPassphrase;
|
||||
final SeedTypeViewModel seedTypeViewModel;
|
||||
final SeedSettingsViewModel seedSettingsViewModel;
|
||||
final FocusNode? blockHeightFocusNode;
|
||||
final Function(bool)? onHeightOrDateEntered;
|
||||
final void Function(String)? onSeedChange;
|
||||
|
@ -58,7 +57,9 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
languageController = TextEditingController(),
|
||||
nameTextEditingController = TextEditingController(),
|
||||
passwordTextEditingController = displayWalletPassword ? TextEditingController() : null,
|
||||
repeatedPasswordTextEditingController = displayWalletPassword ? TextEditingController() : null,
|
||||
repeatedPasswordTextEditingController = displayWalletPassword
|
||||
? TextEditingController()
|
||||
: null,
|
||||
passphraseController = TextEditingController(),
|
||||
seedTypeController = TextEditingController();
|
||||
|
||||
|
@ -75,10 +76,11 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
String language;
|
||||
void Function()? passwordListener;
|
||||
void Function()? repeatedPasswordListener;
|
||||
void Function()? passphraseListener;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_setSeedType(widget.seedTypeViewModel.moneroSeedType);
|
||||
_setSeedType(widget.seedSettingsViewModel.moneroSeedType);
|
||||
_setLanguageLabel(language);
|
||||
|
||||
if (passwordTextEditingController != null) {
|
||||
|
@ -87,14 +89,19 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
}
|
||||
|
||||
if (repeatedPasswordTextEditingController != null) {
|
||||
repeatedPasswordListener = () => widget.onRepeatedPasswordChange?.call(repeatedPasswordTextEditingController!.text);
|
||||
repeatedPasswordListener =
|
||||
() => widget.onRepeatedPasswordChange?.call(repeatedPasswordTextEditingController!.text);
|
||||
repeatedPasswordTextEditingController?.addListener(repeatedPasswordListener!);
|
||||
}
|
||||
|
||||
passphraseListener = () => widget.seedSettingsViewModel.setPassphrase(passphraseController.text);
|
||||
passphraseController.addListener(passphraseListener!);
|
||||
|
||||
moneroSeedTypeReaction =
|
||||
reaction((_) => widget.seedTypeViewModel.moneroSeedType, (SeedType item) {
|
||||
_setSeedType(item);
|
||||
_changeLanguage('English');
|
||||
});
|
||||
reaction((_) => widget.seedSettingsViewModel.moneroSeedType, (MoneroSeedType item) {
|
||||
_setSeedType(item);
|
||||
_changeLanguage('English');
|
||||
});
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
@ -110,6 +117,9 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
if (repeatedPasswordListener != null) {
|
||||
repeatedPasswordTextEditingController?.removeListener(repeatedPasswordListener!);
|
||||
}
|
||||
|
||||
passphraseController.removeListener(passphraseListener!);
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
@ -118,11 +128,13 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
Polyseed.isValidSeed(seed)) {
|
||||
final lang = PolyseedLang.getByPhrase(seed);
|
||||
|
||||
_changeSeedType(SeedType.polyseed);
|
||||
_changeSeedType(MoneroSeedType.polyseed);
|
||||
_changeLanguage(lang.nameEnglish);
|
||||
}
|
||||
if (widget.type == WalletType.wownero && seed.split(" ").length == 14) {
|
||||
_changeSeedType(SeedType.wowneroSeed);
|
||||
if (widget.type == WalletType.wownero && seed
|
||||
.split(" ")
|
||||
.length == 14) {
|
||||
_changeSeedType(MoneroSeedType.wowneroSeed);
|
||||
_changeLanguage("English");
|
||||
}
|
||||
widget.onSeedChange?.call(seed);
|
||||
|
@ -141,7 +153,9 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
BaseTextFormField(
|
||||
key: ValueKey('wallet_restore_from_seed_wallet_name_textfield_key'),
|
||||
controller: nameTextEditingController,
|
||||
hintText: S.of(context).wallet_name,
|
||||
hintText: S
|
||||
.of(context)
|
||||
.wallet_name,
|
||||
suffixIcon: IconButton(
|
||||
key: ValueKey('wallet_restore_from_seed_wallet_name_refresh_button_key'),
|
||||
onPressed: () async {
|
||||
|
@ -158,7 +172,9 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6.0),
|
||||
color: Theme.of(context).hintColor,
|
||||
color: Theme
|
||||
.of(context)
|
||||
.hintColor,
|
||||
),
|
||||
width: 34,
|
||||
height: 34,
|
||||
|
@ -188,13 +204,14 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
onTap: () async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => Picker(
|
||||
builder: (_) =>
|
||||
Picker(
|
||||
items: _getItems(),
|
||||
selectedAtIndex: isPolyseed
|
||||
? 1
|
||||
: seedTypeController.value.text.contains("14")
|
||||
? 2
|
||||
: 0,
|
||||
? 2
|
||||
: 0,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
onItemSelected: _changeSeedType,
|
||||
isSeparated: false,
|
||||
|
@ -216,37 +233,43 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
if (widget.displayWalletPassword)
|
||||
...[BaseTextFormField(
|
||||
controller: passwordTextEditingController,
|
||||
hintText: S.of(context).password,
|
||||
hintText: S
|
||||
.of(context)
|
||||
.password,
|
||||
obscureText: true),
|
||||
BaseTextFormField(
|
||||
controller: repeatedPasswordTextEditingController,
|
||||
hintText: S.of(context).repeat_wallet_password,
|
||||
obscureText: true)],
|
||||
hintText: S
|
||||
.of(context)
|
||||
.repeat_wallet_password,
|
||||
obscureText: true)
|
||||
],
|
||||
if (widget.displayLanguageSelector)
|
||||
if (!seedTypeController.value.text.contains("14") && widget.displayLanguageSelector)
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => SeedLanguagePicker(
|
||||
selected: language,
|
||||
onItemSelected: _changeLanguage,
|
||||
seedType: isPolyseed ? SeedType.polyseed : SeedType.legacy,
|
||||
));
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: IgnorePointer(
|
||||
child: BaseTextFormField(
|
||||
controller: languageController,
|
||||
enableInteractiveSelection: false,
|
||||
readOnly: true,
|
||||
suffixIcon: expandIcon,
|
||||
if (!seedTypeController.value.text.contains("14") && widget.displayLanguageSelector)
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) =>
|
||||
SeedLanguagePicker(
|
||||
selected: language,
|
||||
onItemSelected: _changeLanguage,
|
||||
seedType: isPolyseed ? MoneroSeedType.polyseed : MoneroSeedType.legacy,
|
||||
));
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: IgnorePointer(
|
||||
child: BaseTextFormField(
|
||||
controller: languageController,
|
||||
enableInteractiveSelection: false,
|
||||
readOnly: true,
|
||||
suffixIcon: expandIcon,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if ((!isPolyseed) && widget.displayBlockHeightSelector)
|
||||
BlockchainHeightWidget(
|
||||
focusNode: widget.blockHeightFocusNode,
|
||||
|
@ -267,17 +290,20 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
}
|
||||
|
||||
bool get isPolyseed =>
|
||||
widget.seedTypeViewModel.moneroSeedType == SeedType.polyseed &&
|
||||
(widget.type == WalletType.monero || widget.type == WalletType.wownero);
|
||||
widget.seedSettingsViewModel.moneroSeedType == MoneroSeedType.polyseed &&
|
||||
(widget.type == WalletType.monero || widget.type == WalletType.wownero);
|
||||
|
||||
Widget get expandIcon => Container(
|
||||
Widget get expandIcon =>
|
||||
Container(
|
||||
padding: EdgeInsets.all(18),
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: Image.asset(
|
||||
'assets/images/arrow_bottom_purple_icon.png',
|
||||
height: 8,
|
||||
color: Theme.of(context).hintColor,
|
||||
color: Theme
|
||||
.of(context)
|
||||
.hintColor,
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -285,8 +311,8 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
final setLang = isPolyseed
|
||||
? "POLYSEED_$language"
|
||||
: seedTypeController.value.text.contains("14")
|
||||
? "WOWSEED_" + language
|
||||
: language;
|
||||
? "WOWSEED_" + language
|
||||
: language;
|
||||
setState(() {
|
||||
this.language = setLang;
|
||||
seedWidgetStateKey.currentState!.changeSeedLanguage(setLang);
|
||||
|
@ -298,24 +324,24 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
void _setLanguageLabel(String language) =>
|
||||
languageController.text = '${language.replaceAll("POLYSEED_", "")} (Seed language)';
|
||||
|
||||
void _changeSeedType(SeedType item) {
|
||||
void _changeSeedType(MoneroSeedType item) {
|
||||
_setSeedType(item);
|
||||
_changeLanguage('English');
|
||||
widget.seedTypeViewModel.setMoneroSeedType(item);
|
||||
widget.seedSettingsViewModel.setMoneroSeedType(item);
|
||||
}
|
||||
|
||||
void _setSeedType(SeedType item) {
|
||||
void _setSeedType(MoneroSeedType item) {
|
||||
seedTypeController.text = item.toString();
|
||||
}
|
||||
|
||||
List<SeedType> _getItems() {
|
||||
List<MoneroSeedType> _getItems() {
|
||||
switch (widget.type) {
|
||||
case WalletType.monero:
|
||||
return [SeedType.legacy, SeedType.polyseed];
|
||||
return [MoneroSeedType.legacy, MoneroSeedType.polyseed];
|
||||
case WalletType.wownero:
|
||||
return [SeedType.legacy, SeedType.polyseed, SeedType.wowneroSeed];
|
||||
return [MoneroSeedType.legacy, MoneroSeedType.polyseed, MoneroSeedType.wowneroSeed];
|
||||
default:
|
||||
return [SeedType.legacy];
|
||||
return [MoneroSeedType.legacy];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
|
|||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
|
||||
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
@ -23,7 +23,7 @@ import 'package:mobx/mobx.dart';
|
|||
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
||||
|
||||
class WalletRestorePage extends BasePage {
|
||||
WalletRestorePage(this.walletRestoreViewModel, this.seedTypeViewModel)
|
||||
WalletRestorePage(this.walletRestoreViewModel, this.seedSettingsViewModel)
|
||||
: walletRestoreFromSeedFormKey = GlobalKey<WalletRestoreFromSeedFormState>(),
|
||||
walletRestoreFromKeysFormKey = GlobalKey<WalletRestoreFromKeysFromState>(),
|
||||
_pages = [],
|
||||
|
@ -33,7 +33,7 @@ class WalletRestorePage extends BasePage {
|
|||
switch (mode) {
|
||||
case WalletRestoreMode.seed:
|
||||
_pages.add(WalletRestoreFromSeedForm(
|
||||
seedTypeViewModel: seedTypeViewModel,
|
||||
seedSettingsViewModel: seedSettingsViewModel,
|
||||
displayBlockHeightSelector:
|
||||
walletRestoreViewModel.hasBlockchainHeightLanguageSelector,
|
||||
displayLanguageSelector: walletRestoreViewModel.hasSeedLanguageSelector,
|
||||
|
@ -96,7 +96,7 @@ class WalletRestorePage extends BasePage {
|
|||
));
|
||||
|
||||
final WalletRestoreViewModel walletRestoreViewModel;
|
||||
final SeedTypeViewModel seedTypeViewModel;
|
||||
final SeedSettingsViewModel seedSettingsViewModel;
|
||||
final PageController _controller;
|
||||
final List<Widget> _pages;
|
||||
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
|
||||
|
@ -235,6 +235,7 @@ class WalletRestorePage extends BasePage {
|
|||
onTap: () {
|
||||
Navigator.of(context)
|
||||
.pushNamed(Routes.advancedPrivacySettings, arguments: {
|
||||
'isFromRestore': true,
|
||||
'type': walletRestoreViewModel.type,
|
||||
'useTestnet': walletRestoreViewModel.useTestnet,
|
||||
'toggleTestnet': walletRestoreViewModel.toggleUseTestnet
|
||||
|
@ -324,8 +325,7 @@ class WalletRestorePage extends BasePage {
|
|||
}
|
||||
|
||||
if (walletRestoreViewModel.hasPassphrase) {
|
||||
credentials['passphrase'] =
|
||||
walletRestoreFromSeedFormKey.currentState!.passphraseController.text;
|
||||
credentials['passphrase'] = seedSettingsViewModel.passphrase;
|
||||
}
|
||||
|
||||
credentials['name'] =
|
||||
|
@ -408,26 +408,19 @@ class WalletRestorePage extends BasePage {
|
|||
) as DerivationInfo?;
|
||||
} else if (derivationsWithHistory == 1) {
|
||||
dInfo = derivations[derivationWithHistoryIndex];
|
||||
}
|
||||
|
||||
// get the default derivation for this wallet type:
|
||||
if (dInfo == null) {
|
||||
} else if (derivations.length == 1) {
|
||||
// we only return 1 derivation if we're pretty sure we know which one to use:
|
||||
if (derivations.length == 1) {
|
||||
dInfo = derivations.first;
|
||||
} else {
|
||||
// if we have multiple possible derivations, and none have histories
|
||||
// we just default to the most common one:
|
||||
dInfo = walletRestoreViewModel.getCommonRestoreDerivation();
|
||||
}
|
||||
dInfo = derivations.first;
|
||||
} else {
|
||||
// if we have multiple possible derivations, and none (or multiple) have histories
|
||||
// we just default to the most common one:
|
||||
dInfo = walletRestoreViewModel.getCommonRestoreDerivation();
|
||||
}
|
||||
|
||||
this.derivationInfo = dInfo;
|
||||
if (this.derivationInfo == null) {
|
||||
this.derivationInfo = walletRestoreViewModel.getDefaultDerivation();
|
||||
}
|
||||
|
||||
await walletRestoreViewModel.create(options: _credentials());
|
||||
seedSettingsViewModel.setPassphrase(null);
|
||||
} catch (e) {
|
||||
_formProcessing = false;
|
||||
rethrow;
|
||||
|
|
|
@ -274,6 +274,7 @@ class SendPage extends BasePage {
|
|||
? template.cryptoCurrency
|
||||
: template.fiatCurrency,
|
||||
onTap: () async {
|
||||
sendViewModel.state = IsExecutingState();
|
||||
if (template.additionalRecipients?.isNotEmpty ?? false) {
|
||||
sendViewModel.clearOutputs();
|
||||
|
||||
|
@ -302,6 +303,7 @@ class SendPage extends BasePage {
|
|||
template: template,
|
||||
);
|
||||
}
|
||||
sendViewModel.state = InitialExecutionState();
|
||||
},
|
||||
onRemove: () {
|
||||
showPopUp<void>(
|
||||
|
@ -373,6 +375,7 @@ class SendPage extends BasePage {
|
|||
return LoadingPrimaryButton(
|
||||
key: ValueKey('send_page_send_button_key'),
|
||||
onPressed: () async {
|
||||
if (sendViewModel.state is IsExecutingState) return;
|
||||
if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
|
||||
if (sendViewModel.outputs.length > 1) {
|
||||
showErrorValidationAlert(context);
|
||||
|
|
|
@ -6,7 +6,9 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
|||
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -111,6 +113,33 @@ class PrivacyPage extends BasePage {
|
|||
_privacySettingsViewModel.setUseTronGrid(value);
|
||||
},
|
||||
),
|
||||
if (_privacySettingsViewModel.canUseMempoolFeeAPI)
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.live_fee_rates,
|
||||
value: _privacySettingsViewModel.useMempoolFeeAPI,
|
||||
onValueChange: (BuildContext _, bool isEnabled) async {
|
||||
if (!isEnabled) {
|
||||
final bool confirmation = await showPopUp<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).warning,
|
||||
alertContent: S.of(context).disable_fee_api_warning,
|
||||
rightButtonText: S.of(context).confirm,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () => Navigator.of(context).pop(true),
|
||||
actionLeftButton: () => Navigator.of(context).pop(false));
|
||||
}) ??
|
||||
false;
|
||||
if (confirmation) {
|
||||
_privacySettingsViewModel.setUseMempoolFeeAPI(isEnabled);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_privacySettingsViewModel.setUseMempoolFeeAPI(isEnabled);
|
||||
},
|
||||
),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.domain_looks_up,
|
||||
handler: (context) => Navigator.of(context).pushNamed(Routes.domainLookupsPage),
|
||||
|
|
|
@ -113,10 +113,6 @@ class CheckBoxPickerState extends State<CheckBoxPicker> {
|
|||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
if (item.isDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool newValue = !item.value;
|
||||
item.value = newValue;
|
||||
widget.onChanged(index, newValue);
|
||||
|
@ -134,7 +130,7 @@ class CheckBoxPickerState extends State<CheckBoxPicker> {
|
|||
borderColor: Theme.of(context).dividerColor,
|
||||
iconColor: Colors.white,
|
||||
onChanged: (bool? value) {
|
||||
if (value == null || item.isDisabled) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,36 +11,36 @@ class SeedLanguagePickerOption {
|
|||
final String name;
|
||||
final String nameLocalized;
|
||||
final Image image;
|
||||
final List<SeedType> supportedSeedTypes;
|
||||
final List<MoneroSeedType> supportedSeedTypes;
|
||||
}
|
||||
|
||||
final List<SeedLanguagePickerOption> seedLanguages = [
|
||||
SeedLanguagePickerOption('English', S.current.seed_language_english,
|
||||
Image.asset('assets/images/flags/usa.png'), [SeedType.legacy, SeedType.polyseed]),
|
||||
Image.asset('assets/images/flags/usa.png'), [MoneroSeedType.legacy, MoneroSeedType.polyseed]),
|
||||
SeedLanguagePickerOption('Chinese (Simplified)', S.current.seed_language_chinese,
|
||||
Image.asset('assets/images/flags/chn.png'), [SeedType.legacy, SeedType.polyseed]),
|
||||
Image.asset('assets/images/flags/chn.png'), [MoneroSeedType.legacy, MoneroSeedType.polyseed]),
|
||||
SeedLanguagePickerOption('Chinese (Traditional)', S.current.seed_language_chinese_traditional,
|
||||
Image.asset('assets/images/flags/chn.png'), [SeedType.polyseed]),
|
||||
Image.asset('assets/images/flags/chn.png'), [MoneroSeedType.polyseed]),
|
||||
SeedLanguagePickerOption('Dutch', S.current.seed_language_dutch,
|
||||
Image.asset('assets/images/flags/nld.png'), [SeedType.legacy]),
|
||||
Image.asset('assets/images/flags/nld.png'), [MoneroSeedType.legacy]),
|
||||
SeedLanguagePickerOption('German', S.current.seed_language_german,
|
||||
Image.asset('assets/images/flags/deu.png'), [SeedType.legacy]),
|
||||
Image.asset('assets/images/flags/deu.png'), [MoneroSeedType.legacy]),
|
||||
SeedLanguagePickerOption('Japanese', S.current.seed_language_japanese,
|
||||
Image.asset('assets/images/flags/jpn.png'), [SeedType.legacy, SeedType.polyseed]),
|
||||
Image.asset('assets/images/flags/jpn.png'), [MoneroSeedType.legacy, MoneroSeedType.polyseed]),
|
||||
SeedLanguagePickerOption('Korean', S.current.seed_language_korean,
|
||||
Image.asset('assets/images/flags/kor.png'), [SeedType.polyseed]),
|
||||
Image.asset('assets/images/flags/kor.png'), [MoneroSeedType.polyseed]),
|
||||
SeedLanguagePickerOption('Portuguese', S.current.seed_language_portuguese,
|
||||
Image.asset('assets/images/flags/prt.png'), [SeedType.legacy, SeedType.polyseed]),
|
||||
Image.asset('assets/images/flags/prt.png'), [MoneroSeedType.legacy, MoneroSeedType.polyseed]),
|
||||
SeedLanguagePickerOption('Russian', S.current.seed_language_russian,
|
||||
Image.asset('assets/images/flags/rus.png'), [SeedType.legacy]),
|
||||
Image.asset('assets/images/flags/rus.png'), [MoneroSeedType.legacy]),
|
||||
SeedLanguagePickerOption('Czech', S.current.seed_language_czech,
|
||||
Image.asset('assets/images/flags/czk.png'), [SeedType.polyseed]),
|
||||
Image.asset('assets/images/flags/czk.png'), [MoneroSeedType.polyseed]),
|
||||
SeedLanguagePickerOption('Spanish', S.current.seed_language_spanish,
|
||||
Image.asset('assets/images/flags/esp.png'), [SeedType.legacy, SeedType.polyseed]),
|
||||
Image.asset('assets/images/flags/esp.png'), [MoneroSeedType.legacy, MoneroSeedType.polyseed]),
|
||||
SeedLanguagePickerOption('French', S.current.seed_language_french,
|
||||
Image.asset('assets/images/flags/fra.png'), [SeedType.legacy, SeedType.polyseed]),
|
||||
Image.asset('assets/images/flags/fra.png'), [MoneroSeedType.legacy, MoneroSeedType.polyseed]),
|
||||
SeedLanguagePickerOption('Italian', S.current.seed_language_italian,
|
||||
Image.asset('assets/images/flags/ita.png'), [SeedType.legacy, SeedType.polyseed]),
|
||||
Image.asset('assets/images/flags/ita.png'), [MoneroSeedType.legacy, MoneroSeedType.polyseed]),
|
||||
];
|
||||
|
||||
const defaultSeedLanguage = 'English';
|
||||
|
@ -51,11 +51,11 @@ class SeedLanguagePicker extends StatefulWidget {
|
|||
SeedLanguagePicker(
|
||||
{Key? key,
|
||||
this.selected = defaultSeedLanguage,
|
||||
this.seedType = SeedType.defaultSeedType,
|
||||
this.seedType = MoneroSeedType.defaultSeedType,
|
||||
required this.onItemSelected})
|
||||
: super(key: key);
|
||||
|
||||
final SeedType seedType;
|
||||
final MoneroSeedType seedType;
|
||||
final String selected;
|
||||
final Function(String) onItemSelected;
|
||||
|
||||
|
@ -68,7 +68,7 @@ class SeedLanguagePickerState extends State<SeedLanguagePicker> {
|
|||
SeedLanguagePickerState(
|
||||
{required this.selected, required this.onItemSelected, required this.seedType});
|
||||
|
||||
final SeedType seedType;
|
||||
final MoneroSeedType seedType;
|
||||
final String selected;
|
||||
final Function(String) onItemSelected;
|
||||
|
||||
|
|
|
@ -8,13 +8,13 @@ import 'package:flutter/material.dart';
|
|||
class SeedLanguageSelector extends StatefulWidget {
|
||||
SeedLanguageSelector({
|
||||
required this.initialSelected,
|
||||
this.seedType = SeedType.defaultSeedType,
|
||||
this.seedType = MoneroSeedType.defaultSeedType,
|
||||
this.buttonKey,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
final String initialSelected;
|
||||
final SeedType seedType;
|
||||
final MoneroSeedType seedType;
|
||||
final Key? buttonKey;
|
||||
|
||||
@override
|
||||
|
|
|
@ -16,7 +16,9 @@ abstract class TradeFilterStoreBase with Store {
|
|||
displaySimpleSwap = true,
|
||||
displayTrocador = true,
|
||||
displayExolix = true,
|
||||
displayThorChain = true;
|
||||
displayThorChain = true,
|
||||
displayLetsExchange = true,
|
||||
displayStealthEx = true;
|
||||
|
||||
@observable
|
||||
bool displayXMRTO;
|
||||
|
@ -42,6 +44,12 @@ abstract class TradeFilterStoreBase with Store {
|
|||
@observable
|
||||
bool displayThorChain;
|
||||
|
||||
@observable
|
||||
bool displayLetsExchange;
|
||||
|
||||
@observable
|
||||
bool displayStealthEx;
|
||||
|
||||
@computed
|
||||
bool get displayAllTrades =>
|
||||
displayChangeNow &&
|
||||
|
@ -49,7 +57,9 @@ abstract class TradeFilterStoreBase with Store {
|
|||
displaySimpleSwap &&
|
||||
displayTrocador &&
|
||||
displayExolix &&
|
||||
displayThorChain;
|
||||
displayThorChain &&
|
||||
displayLetsExchange &&
|
||||
displayStealthEx;
|
||||
|
||||
@action
|
||||
void toggleDisplayExchange(ExchangeProviderDescription provider) {
|
||||
|
@ -78,6 +88,11 @@ abstract class TradeFilterStoreBase with Store {
|
|||
case ExchangeProviderDescription.thorChain:
|
||||
displayThorChain = !displayThorChain;
|
||||
break;
|
||||
case ExchangeProviderDescription.letsExchange:
|
||||
displayLetsExchange = !displayLetsExchange;
|
||||
case ExchangeProviderDescription.stealthEx:
|
||||
displayStealthEx = !displayStealthEx;
|
||||
break;
|
||||
case ExchangeProviderDescription.all:
|
||||
if (displayAllTrades) {
|
||||
displayChangeNow = false;
|
||||
|
@ -88,6 +103,8 @@ abstract class TradeFilterStoreBase with Store {
|
|||
displayTrocador = false;
|
||||
displayExolix = false;
|
||||
displayThorChain = false;
|
||||
displayLetsExchange = false;
|
||||
displayStealthEx = false;
|
||||
} else {
|
||||
displayChangeNow = true;
|
||||
displaySideShift = true;
|
||||
|
@ -97,6 +114,8 @@ abstract class TradeFilterStoreBase with Store {
|
|||
displayTrocador = true;
|
||||
displayExolix = true;
|
||||
displayThorChain = true;
|
||||
displayLetsExchange = true;
|
||||
displayStealthEx = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -112,13 +131,21 @@ abstract class TradeFilterStoreBase with Store {
|
|||
? _trades
|
||||
.where((item) =>
|
||||
(displayXMRTO && item.trade.provider == ExchangeProviderDescription.xmrto) ||
|
||||
(displaySideShift && item.trade.provider == ExchangeProviderDescription.sideShift) ||
|
||||
(displayChangeNow && item.trade.provider == ExchangeProviderDescription.changeNow) ||
|
||||
(displayMorphToken && item.trade.provider == ExchangeProviderDescription.morphToken) ||
|
||||
(displaySimpleSwap && item.trade.provider == ExchangeProviderDescription.simpleSwap) ||
|
||||
(displaySideShift &&
|
||||
item.trade.provider == ExchangeProviderDescription.sideShift) ||
|
||||
(displayChangeNow &&
|
||||
item.trade.provider == ExchangeProviderDescription.changeNow) ||
|
||||
(displayMorphToken &&
|
||||
item.trade.provider == ExchangeProviderDescription.morphToken) ||
|
||||
(displaySimpleSwap &&
|
||||
item.trade.provider == ExchangeProviderDescription.simpleSwap) ||
|
||||
(displayTrocador && item.trade.provider == ExchangeProviderDescription.trocador) ||
|
||||
(displayExolix && item.trade.provider == ExchangeProviderDescription.exolix) ||
|
||||
(displayThorChain && item.trade.provider == ExchangeProviderDescription.thorChain))
|
||||
(displayThorChain &&
|
||||
item.trade.provider == ExchangeProviderDescription.thorChain) ||
|
||||
(displayLetsExchange &&
|
||||
item.trade.provider == ExchangeProviderDescription.letsExchange) ||
|
||||
(displayStealthEx && item.trade.provider == ExchangeProviderDescription.stealthEx))
|
||||
.toList()
|
||||
: _trades;
|
||||
}
|
||||
|
|
11
lib/store/seed_settings_store.dart
Normal file
11
lib/store/seed_settings_store.dart
Normal file
|
@ -0,0 +1,11 @@
|
|||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'seed_settings_store.g.dart';
|
||||
|
||||
class SeedSettingsStore = SeedSettingsStoreBase with _$SeedSettingsStore;
|
||||
|
||||
abstract class SeedSettingsStoreBase with Store {
|
||||
|
||||
@observable
|
||||
String? passphrase;
|
||||
}
|
|
@ -1,45 +1,46 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||
import 'package:cake_wallet/core/secure_storage.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/entities/action_list_display_mode.dart';
|
||||
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
||||
import 'package:cake_wallet/entities/provider_types.dart';
|
||||
import 'package:cake_wallet/entities/cake_2fa_preset_options.dart';
|
||||
import 'package:cake_wallet/entities/background_tasks.dart';
|
||||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||
import 'package:cake_wallet/entities/cake_2fa_preset_options.dart';
|
||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/entities/language_service.dart';
|
||||
import 'package:cake_wallet/entities/pin_code_required_duration.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/entities/provider_types.dart';
|
||||
import 'package:cake_wallet/entities/secret_store_key.dart';
|
||||
import 'package:cake_wallet/entities/seed_phrase_length.dart';
|
||||
import 'package:cake_wallet/entities/seed_type.dart';
|
||||
import 'package:cake_wallet/entities/sort_balance_types.dart';
|
||||
import 'package:cake_wallet/entities/wallet_list_order_types.dart';
|
||||
import 'package:cake_wallet/polygon/polygon.dart';
|
||||
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
|
||||
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/polygon/polygon.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/themes/theme_list.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/package_info.dart';
|
||||
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/set_app_secure_native.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/utils/package_info.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:cake_wallet/entities/language_service.dart';
|
||||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/entities/action_list_display_mode.dart';
|
||||
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||
import 'package:cw_core/set_app_secure_native.dart';
|
||||
|
||||
part 'settings_store.g.dart';
|
||||
|
||||
|
@ -55,7 +56,8 @@ abstract class SettingsStoreBase with Store {
|
|||
required BalanceDisplayMode initialBalanceDisplayMode,
|
||||
required bool initialSaveRecipientAddress,
|
||||
required AutoGenerateSubaddressStatus initialAutoGenerateSubaddressStatus,
|
||||
required SeedType initialMoneroSeedType,
|
||||
required MoneroSeedType initialMoneroSeedType,
|
||||
required BitcoinSeedType initialBitcoinSeedType,
|
||||
required bool initialAppSecure,
|
||||
required bool initialDisableBuy,
|
||||
required bool initialDisableSell,
|
||||
|
@ -99,6 +101,7 @@ abstract class SettingsStoreBase with Store {
|
|||
required this.useEtherscan,
|
||||
required this.usePolygonScan,
|
||||
required this.useTronGrid,
|
||||
required this.useMempoolFeeAPI,
|
||||
required this.defaultNanoRep,
|
||||
required this.defaultBananoRep,
|
||||
required this.lookupsTwitter,
|
||||
|
@ -128,6 +131,7 @@ abstract class SettingsStoreBase with Store {
|
|||
shouldSaveRecipientAddress = initialSaveRecipientAddress,
|
||||
autoGenerateSubaddressStatus = initialAutoGenerateSubaddressStatus,
|
||||
moneroSeedType = initialMoneroSeedType,
|
||||
bitcoinSeedType = initialBitcoinSeedType,
|
||||
fiatApiMode = initialFiatMode,
|
||||
allowBiometricalAuthentication = initialAllowBiometricalAuthentication,
|
||||
selectedCake2FAPreset = initialCake2FAPresetOptions,
|
||||
|
@ -329,9 +333,14 @@ abstract class SettingsStoreBase with Store {
|
|||
|
||||
reaction(
|
||||
(_) => moneroSeedType,
|
||||
(SeedType moneroSeedType) =>
|
||||
(MoneroSeedType moneroSeedType) =>
|
||||
sharedPreferences.setInt(PreferencesKey.moneroSeedType, moneroSeedType.raw));
|
||||
|
||||
reaction(
|
||||
(_) => bitcoinSeedType,
|
||||
(BitcoinSeedType bitcoinSeedType) => sharedPreferences.setInt(
|
||||
PreferencesKey.bitcoinSeedType, bitcoinSeedType.raw));
|
||||
|
||||
reaction(
|
||||
(_) => fiatApiMode,
|
||||
(FiatApiMode mode) =>
|
||||
|
@ -408,6 +417,9 @@ abstract class SettingsStoreBase with Store {
|
|||
reaction((_) => useTronGrid,
|
||||
(bool useTronGrid) => _sharedPreferences.setBool(PreferencesKey.useTronGrid, useTronGrid));
|
||||
|
||||
reaction((_) => useMempoolFeeAPI,
|
||||
(bool useMempoolFeeAPI) => _sharedPreferences.setBool(PreferencesKey.useMempoolFeeAPI, useMempoolFeeAPI));
|
||||
|
||||
reaction((_) => defaultNanoRep,
|
||||
(String nanoRep) => _sharedPreferences.setString(PreferencesKey.defaultNanoRep, nanoRep));
|
||||
|
||||
|
@ -555,7 +567,8 @@ abstract class SettingsStoreBase with Store {
|
|||
static const defaultAutoGenerateSubaddressStatus = AutoGenerateSubaddressStatus.initialized;
|
||||
static final walletPasswordDirectInput = Platform.isLinux;
|
||||
static const defaultSeedPhraseLength = SeedPhraseLength.twelveWords;
|
||||
static const defaultMoneroSeedType = SeedType.defaultSeedType;
|
||||
static const defaultMoneroSeedType = MoneroSeedType.defaultSeedType;
|
||||
static const defaultBitcoinSeedType = BitcoinSeedType.defaultDerivationType;
|
||||
|
||||
@observable
|
||||
FiatCurrency fiatCurrency;
|
||||
|
@ -585,7 +598,10 @@ abstract class SettingsStoreBase with Store {
|
|||
AutoGenerateSubaddressStatus autoGenerateSubaddressStatus;
|
||||
|
||||
@observable
|
||||
SeedType moneroSeedType;
|
||||
MoneroSeedType moneroSeedType;
|
||||
|
||||
@observable
|
||||
BitcoinSeedType bitcoinSeedType;
|
||||
|
||||
@observable
|
||||
bool isAppSecure;
|
||||
|
@ -695,6 +711,9 @@ abstract class SettingsStoreBase with Store {
|
|||
@observable
|
||||
bool useTronGrid;
|
||||
|
||||
@observable
|
||||
bool useMempoolFeeAPI;
|
||||
|
||||
@observable
|
||||
String defaultNanoRep;
|
||||
|
||||
|
@ -880,6 +899,7 @@ abstract class SettingsStoreBase with Store {
|
|||
final useEtherscan = sharedPreferences.getBool(PreferencesKey.useEtherscan) ?? true;
|
||||
final usePolygonScan = sharedPreferences.getBool(PreferencesKey.usePolygonScan) ?? true;
|
||||
final useTronGrid = sharedPreferences.getBool(PreferencesKey.useTronGrid) ?? true;
|
||||
final useMempoolFeeAPI = sharedPreferences.getBool(PreferencesKey.useMempoolFeeAPI) ?? true;
|
||||
final defaultNanoRep = sharedPreferences.getString(PreferencesKey.defaultNanoRep) ?? "";
|
||||
final defaultBananoRep = sharedPreferences.getString(PreferencesKey.defaultBananoRep) ?? "";
|
||||
final lookupsTwitter = sharedPreferences.getBool(PreferencesKey.lookupsTwitter) ?? true;
|
||||
|
@ -945,9 +965,15 @@ abstract class SettingsStoreBase with Store {
|
|||
final _moneroSeedType = sharedPreferences.getInt(PreferencesKey.moneroSeedType);
|
||||
|
||||
final moneroSeedType = _moneroSeedType != null
|
||||
? SeedType.deserialize(raw: _moneroSeedType)
|
||||
? MoneroSeedType.deserialize(raw: _moneroSeedType)
|
||||
: defaultMoneroSeedType;
|
||||
|
||||
final _bitcoinSeedType = sharedPreferences.getInt(PreferencesKey.bitcoinSeedType);
|
||||
|
||||
final bitcoinSeedType = _bitcoinSeedType != null
|
||||
? BitcoinSeedType.deserialize(raw: _bitcoinSeedType)
|
||||
: defaultBitcoinSeedType;
|
||||
|
||||
final nodes = <WalletType, Node>{};
|
||||
final powNodes = <WalletType, Node>{};
|
||||
|
||||
|
@ -1111,6 +1137,7 @@ abstract class SettingsStoreBase with Store {
|
|||
initialSaveRecipientAddress: shouldSaveRecipientAddress,
|
||||
initialAutoGenerateSubaddressStatus: autoGenerateSubaddressStatus,
|
||||
initialMoneroSeedType: moneroSeedType,
|
||||
initialBitcoinSeedType: bitcoinSeedType,
|
||||
initialAppSecure: isAppSecure,
|
||||
initialDisableBuy: disableBuy,
|
||||
initialDisableSell: disableSell,
|
||||
|
@ -1135,6 +1162,7 @@ abstract class SettingsStoreBase with Store {
|
|||
useEtherscan: useEtherscan,
|
||||
usePolygonScan: usePolygonScan,
|
||||
useTronGrid: useTronGrid,
|
||||
useMempoolFeeAPI: useMempoolFeeAPI,
|
||||
defaultNanoRep: defaultNanoRep,
|
||||
defaultBananoRep: defaultBananoRep,
|
||||
lookupsTwitter: lookupsTwitter,
|
||||
|
@ -1233,9 +1261,15 @@ abstract class SettingsStoreBase with Store {
|
|||
final _moneroSeedType = sharedPreferences.getInt(PreferencesKey.moneroSeedType);
|
||||
|
||||
moneroSeedType = _moneroSeedType != null
|
||||
? SeedType.deserialize(raw: _moneroSeedType)
|
||||
? MoneroSeedType.deserialize(raw: _moneroSeedType)
|
||||
: defaultMoneroSeedType;
|
||||
|
||||
final _bitcoinSeedType = sharedPreferences.getInt(PreferencesKey.bitcoinSeedType);
|
||||
|
||||
bitcoinSeedType = _bitcoinSeedType != null
|
||||
? BitcoinSeedType.deserialize(raw: _bitcoinSeedType)
|
||||
: defaultBitcoinSeedType;
|
||||
|
||||
balanceDisplayMode = BalanceDisplayMode.deserialize(
|
||||
raw: sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey)!);
|
||||
shouldSaveRecipientAddress =
|
||||
|
@ -1282,6 +1316,7 @@ abstract class SettingsStoreBase with Store {
|
|||
useEtherscan = sharedPreferences.getBool(PreferencesKey.useEtherscan) ?? true;
|
||||
usePolygonScan = sharedPreferences.getBool(PreferencesKey.usePolygonScan) ?? true;
|
||||
useTronGrid = sharedPreferences.getBool(PreferencesKey.useTronGrid) ?? true;
|
||||
useMempoolFeeAPI = sharedPreferences.getBool(PreferencesKey.useMempoolFeeAPI) ?? true;
|
||||
defaultNanoRep = sharedPreferences.getString(PreferencesKey.defaultNanoRep) ?? "";
|
||||
defaultBananoRep = sharedPreferences.getString(PreferencesKey.defaultBananoRep) ?? "";
|
||||
lookupsTwitter = sharedPreferences.getBool(PreferencesKey.lookupsTwitter) ?? true;
|
||||
|
|
|
@ -172,8 +172,14 @@ class ExceptionHandler {
|
|||
"Error while launching http",
|
||||
"OS Error: Network is unreachable",
|
||||
"ClientException: Write failed, uri=http",
|
||||
"Connection terminated during handshake",
|
||||
"Corrupted wallets seeds",
|
||||
"bad_alloc",
|
||||
"does not correspond",
|
||||
"basic_string",
|
||||
"input_stream",
|
||||
"input stream error",
|
||||
"invalid signature",
|
||||
"invalid password",
|
||||
];
|
||||
|
||||
static Future<void> _addDeviceInfo(File file) async {
|
||||
|
|
60
lib/utils/image_utill.dart
Normal file
60
lib/utils/image_utill.dart
Normal file
|
@ -0,0 +1,60 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
class ImageUtil {
|
||||
static Widget getImageFromPath({required String imagePath, double? height, double? width}) {
|
||||
final bool isNetworkImage = imagePath.startsWith('http') || imagePath.startsWith('https');
|
||||
final bool isSvg = imagePath.endsWith('.svg');
|
||||
final double _height = height ?? 35;
|
||||
final double _width = width ?? 35;
|
||||
|
||||
if (isNetworkImage) {
|
||||
return isSvg
|
||||
? SvgPicture.network(
|
||||
imagePath,
|
||||
height: _height,
|
||||
width: _width,
|
||||
placeholderBuilder: (BuildContext context) => Container(
|
||||
height: _height,
|
||||
width: _width,
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Image.network(
|
||||
imagePath,
|
||||
height: _height,
|
||||
width: _width,
|
||||
loadingBuilder:
|
||||
(BuildContext context, Widget child, ImageChunkEvent? loadingProgress) {
|
||||
if (loadingProgress == null) {
|
||||
return child;
|
||||
}
|
||||
return Container(
|
||||
height: _height,
|
||||
width: _width,
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(
|
||||
value: loadingProgress.expectedTotalBytes != null
|
||||
? loadingProgress.cumulativeBytesLoaded /
|
||||
loadingProgress.expectedTotalBytes!
|
||||
: null,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) {
|
||||
return Container(
|
||||
height: _height,
|
||||
width: _width,
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return isSvg
|
||||
? SvgPicture.asset(imagePath, height: _height, width: _width)
|
||||
: Image.asset(imagePath, height: _height, width: _width);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,6 +30,7 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
|
|||
|
||||
final SettingsStore _settingsStore;
|
||||
|
||||
@computed
|
||||
bool get hasSeedPhraseLengthOption {
|
||||
// convert to switch case so that it give a syntax error when adding a new wallet type
|
||||
// thus we don't forget about it
|
||||
|
@ -40,11 +41,14 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
|
|||
case WalletType.solana:
|
||||
case WalletType.tron:
|
||||
return true;
|
||||
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
return _settingsStore.bitcoinSeedType == BitcoinSeedType.bip39;
|
||||
|
||||
case WalletType.monero:
|
||||
case WalletType.wownero:
|
||||
case WalletType.none:
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.haven:
|
||||
case WalletType.nano:
|
||||
case WalletType.banano:
|
||||
|
@ -52,7 +56,13 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
|
|||
}
|
||||
}
|
||||
|
||||
bool get hasSeedTypeOption => type == WalletType.monero || type == WalletType.wownero;
|
||||
bool get hasSeedTypeOption => [WalletType.monero, WalletType.wownero].contains(type);
|
||||
|
||||
bool get hasPassphraseOption => [
|
||||
WalletType.bitcoin,
|
||||
WalletType.litecoin,
|
||||
WalletType.bitcoinCash,
|
||||
].contains(type);
|
||||
|
||||
@computed
|
||||
bool get addCustomNode => _addCustomNode;
|
||||
|
@ -61,7 +71,7 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
|
|||
SeedPhraseLength get seedPhraseLength => _settingsStore.seedPhraseLength;
|
||||
|
||||
@computed
|
||||
bool get isPolySeed => _settingsStore.moneroSeedType == SeedType.polyseed;
|
||||
bool get isPolySeed => _settingsStore.moneroSeedType == MoneroSeedType.polyseed;
|
||||
|
||||
@action
|
||||
void setFiatApiMode(FiatApiMode fiatApiMode) => _settingsStore.fiatApiMode = fiatApiMode;
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
import 'package:cake_wallet/core/key_service.dart';
|
||||
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
||||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/entities/provider_types.dart';
|
||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/service_status.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
@ -45,11 +47,9 @@ import 'package:cw_core/wallet_info.dart';
|
|||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:eth_sig_util/util/utils.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
|
||||
part 'dashboard_view_model.g.dart';
|
||||
|
||||
|
@ -129,6 +129,16 @@ abstract class DashboardViewModelBase with Store {
|
|||
caption: ExchangeProviderDescription.thorChain.title,
|
||||
onChanged: () =>
|
||||
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.thorChain)),
|
||||
FilterItem(
|
||||
value: () => tradeFilterStore.displayLetsExchange,
|
||||
caption: ExchangeProviderDescription.letsExchange.title,
|
||||
onChanged: () =>
|
||||
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.letsExchange)),
|
||||
FilterItem(
|
||||
value: () => tradeFilterStore.displayStealthEx,
|
||||
caption: ExchangeProviderDescription.stealthEx.title,
|
||||
onChanged: () =>
|
||||
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.stealthEx)),
|
||||
]
|
||||
},
|
||||
subname = '',
|
||||
|
|
|
@ -69,12 +69,10 @@ class TransactionListItem extends ActionListItem with Keyable {
|
|||
}
|
||||
|
||||
String get formattedStatus {
|
||||
if (transaction.direction == TransactionDirection.incoming) {
|
||||
if (balanceViewModel.wallet.type == WalletType.monero ||
|
||||
balanceViewModel.wallet.type == WalletType.wownero ||
|
||||
balanceViewModel.wallet.type == WalletType.haven) {
|
||||
return formattedPendingStatus;
|
||||
}
|
||||
if (balanceViewModel.wallet.type == WalletType.monero ||
|
||||
balanceViewModel.wallet.type == WalletType.wownero ||
|
||||
balanceViewModel.wallet.type == WalletType.haven) {
|
||||
return formattedPendingStatus;
|
||||
}
|
||||
return transaction.isPending ? S.current.pending : '';
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:cake_wallet/exchange/provider/exolix_exchange_provider.dart';
|
|||
import 'package:cake_wallet/exchange/provider/quantex_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/sideshift_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/simpleswap_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/stealth_ex_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/thorchain_exchange.provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
|
@ -52,6 +53,8 @@ abstract class ExchangeTradeViewModelBase with Store {
|
|||
case ExchangeProviderDescription.quantex:
|
||||
_provider = QuantexExchangeProvider();
|
||||
break;
|
||||
case ExchangeProviderDescription.stealthEx:
|
||||
_provider = StealthExExchangeProvider();
|
||||
case ExchangeProviderDescription.thorChain:
|
||||
_provider = ThorChainExchangeProvider(tradesStore: trades);
|
||||
break;
|
||||
|
|
|
@ -4,6 +4,8 @@ import 'dart:convert';
|
|||
|
||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:cake_wallet/core/create_trade_result.dart';
|
||||
import 'package:cake_wallet/exchange/provider/letsexchange_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/stealth_ex_exchange_provider.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/sync_status.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
|
@ -160,15 +162,17 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
|||
final SharedPreferences sharedPreferences;
|
||||
|
||||
List<ExchangeProvider> get _allProviders => [
|
||||
ChangeNowExchangeProvider(settingsStore: _settingsStore),
|
||||
SideShiftExchangeProvider(),
|
||||
SimpleSwapExchangeProvider(),
|
||||
ThorChainExchangeProvider(tradesStore: trades),
|
||||
if (FeatureFlag.isExolixEnabled) ExolixExchangeProvider(),
|
||||
QuantexExchangeProvider(),
|
||||
TrocadorExchangeProvider(
|
||||
useTorOnly: _useTorOnly, providerStates: _settingsStore.trocadorProviderStates),
|
||||
];
|
||||
ChangeNowExchangeProvider(settingsStore: _settingsStore),
|
||||
SideShiftExchangeProvider(),
|
||||
SimpleSwapExchangeProvider(),
|
||||
ThorChainExchangeProvider(tradesStore: trades),
|
||||
if (FeatureFlag.isExolixEnabled) ExolixExchangeProvider(),
|
||||
QuantexExchangeProvider(),
|
||||
LetsExchangeExchangeProvider(),
|
||||
StealthExExchangeProvider(),
|
||||
TrocadorExchangeProvider(
|
||||
useTorOnly: _useTorOnly, providerStates: _settingsStore.trocadorProviderStates),
|
||||
];
|
||||
|
||||
@observable
|
||||
ExchangeProvider? provider;
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:cake_wallet/solana/solana.dart';
|
|||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
@ -26,13 +27,13 @@ class WalletRestorationFromQRVM = WalletRestorationFromQRVMBase with _$WalletRes
|
|||
|
||||
abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store {
|
||||
WalletRestorationFromQRVMBase(AppStore appStore, WalletCreationService walletCreationService,
|
||||
Box<WalletInfo> walletInfoSource, WalletType type)
|
||||
Box<WalletInfo> walletInfoSource, WalletType type, SeedSettingsViewModel seedSettingsViewModel)
|
||||
: height = 0,
|
||||
viewKey = '',
|
||||
spendKey = '',
|
||||
wif = '',
|
||||
address = '',
|
||||
super(appStore, walletInfoSource, walletCreationService, type: type, isRecovery: true);
|
||||
super(appStore, walletInfoSource, walletCreationService, seedSettingsViewModel, type: type, isRecovery: true);
|
||||
|
||||
@observable
|
||||
int height;
|
||||
|
@ -61,7 +62,7 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
|
|||
derivationInfo = options["derivationInfo"] as DerivationInfo?;
|
||||
passphrase = options["passphrase"] as String?;
|
||||
}
|
||||
derivationInfo ??= getDefaultDerivation();
|
||||
derivationInfo ??= getDefaultCreateDerivation();
|
||||
|
||||
switch (restoreWallet.restoreMode) {
|
||||
case WalletRestoreMode.keys:
|
||||
|
|
|
@ -46,7 +46,7 @@ abstract class RestoreFromBackupViewModelBase with Store {
|
|||
final data = await file.readAsBytes();
|
||||
|
||||
await backupService.importBackup(data, password);
|
||||
await main();
|
||||
await initializeAppAtRoot(reInitializing: true);
|
||||
|
||||
final store = getIt.get<AppStore>();
|
||||
ReactionDisposer? reaction;
|
||||
|
|
34
lib/view_model/seed_settings_view_model.dart
Normal file
34
lib/view_model/seed_settings_view_model.dart
Normal file
|
@ -0,0 +1,34 @@
|
|||
import 'package:cake_wallet/entities/seed_type.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/store/seed_settings_store.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'seed_settings_view_model.g.dart';
|
||||
|
||||
class SeedSettingsViewModel = SeedSettingsViewModelBase with _$SeedSettingsViewModel;
|
||||
|
||||
abstract class SeedSettingsViewModelBase with Store {
|
||||
SeedSettingsViewModelBase(this._appStore, this._seedSettingsStore);
|
||||
|
||||
@computed
|
||||
MoneroSeedType get moneroSeedType => _appStore.settingsStore.moneroSeedType;
|
||||
|
||||
@action
|
||||
void setMoneroSeedType(MoneroSeedType seedType) => _appStore.settingsStore.moneroSeedType = seedType;
|
||||
|
||||
@computed
|
||||
BitcoinSeedType get bitcoinSeedType => _appStore.settingsStore.bitcoinSeedType;
|
||||
|
||||
@action
|
||||
void setBitcoinSeedType(BitcoinSeedType derivationType) =>
|
||||
_appStore.settingsStore.bitcoinSeedType = derivationType;
|
||||
|
||||
@computed
|
||||
String? get passphrase => this._seedSettingsStore.passphrase;
|
||||
|
||||
@action
|
||||
void setPassphrase(String? passphrase) => this._seedSettingsStore.passphrase = passphrase;
|
||||
|
||||
final AppStore _appStore;
|
||||
final SeedSettingsStore _seedSettingsStore;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
import 'package:cake_wallet/entities/seed_type.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'seed_type_view_model.g.dart';
|
||||
|
||||
class SeedTypeViewModel = SeedTypeViewModelBase with _$SeedTypeViewModel;
|
||||
|
||||
abstract class SeedTypeViewModelBase with Store {
|
||||
SeedTypeViewModelBase(this._appStore);
|
||||
|
||||
@computed
|
||||
SeedType get moneroSeedType => _appStore.settingsStore.moneroSeedType;
|
||||
|
||||
@action
|
||||
void setMoneroSeedType(SeedType seedType) => _appStore.settingsStore.moneroSeedType = seedType;
|
||||
|
||||
final AppStore _appStore;
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
|
@ -75,6 +76,9 @@ abstract class PrivacySettingsViewModelBase with Store {
|
|||
@computed
|
||||
bool get useTronGrid => _settingsStore.useTronGrid;
|
||||
|
||||
@computed
|
||||
bool get useMempoolFeeAPI => _settingsStore.useMempoolFeeAPI;
|
||||
|
||||
@computed
|
||||
bool get lookupTwitter => _settingsStore.lookupsTwitter;
|
||||
|
||||
|
@ -99,6 +103,8 @@ abstract class PrivacySettingsViewModelBase with Store {
|
|||
|
||||
bool get canUseTronGrid => _wallet.type == WalletType.tron;
|
||||
|
||||
bool get canUseMempoolFeeAPI => _wallet.type == WalletType.bitcoin;
|
||||
|
||||
@action
|
||||
void setShouldSaveRecipientAddress(bool value) =>
|
||||
_settingsStore.shouldSaveRecipientAddress = value;
|
||||
|
@ -156,4 +162,9 @@ abstract class PrivacySettingsViewModelBase with Store {
|
|||
_settingsStore.useTronGrid = value;
|
||||
tron!.updateTronGridUsageState(_wallet, value);
|
||||
}
|
||||
|
||||
@action
|
||||
void setUseMempoolFeeAPI(bool value) {
|
||||
_settingsStore.useMempoolFeeAPI = value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,11 @@ import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
|||
import 'package:cake_wallet/exchange/provider/changenow_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/exolix_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/letsexchange_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/quantex_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/sideshift_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/simpleswap_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/stealth_ex_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/thorchain_exchange.provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
|
@ -59,6 +61,11 @@ abstract class TradeDetailsViewModelBase with Store {
|
|||
break;
|
||||
case ExchangeProviderDescription.quantex:
|
||||
_provider = QuantexExchangeProvider();
|
||||
case ExchangeProviderDescription.letsExchange:
|
||||
_provider = LetsExchangeExchangeProvider();
|
||||
break;
|
||||
case ExchangeProviderDescription.stealthEx:
|
||||
_provider = StealthExExchangeProvider();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -86,6 +93,10 @@ abstract class TradeDetailsViewModelBase with Store {
|
|||
return 'https://track.ninerealms.com/${trade.id}';
|
||||
case ExchangeProviderDescription.quantex:
|
||||
return 'https://myquantex.com/send/${trade.id}';
|
||||
case ExchangeProviderDescription.letsExchange:
|
||||
return 'https://letsexchange.io/?transactionId=${trade.id}';
|
||||
case ExchangeProviderDescription.stealthEx:
|
||||
return 'https://stealthex.io/exchange/?id=${trade.id}';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/entities/background_tasks.dart';
|
||||
import 'package:cake_wallet/entities/generate_name.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/entities/generate_name.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:polyseed/polyseed.dart';
|
||||
|
||||
part 'wallet_creation_vm.g.dart';
|
||||
|
@ -23,6 +24,7 @@ class WalletCreationVM = WalletCreationVMBase with _$WalletCreationVM;
|
|||
|
||||
abstract class WalletCreationVMBase with Store {
|
||||
WalletCreationVMBase(this._appStore, this._walletInfoSource, this.walletCreationService,
|
||||
this.seedSettingsViewModel,
|
||||
{required this.type, required this.isRecovery})
|
||||
: state = InitialExecutionState(),
|
||||
name = '';
|
||||
|
@ -44,7 +46,6 @@ abstract class WalletCreationVMBase with Store {
|
|||
|
||||
@observable
|
||||
String? repeatedWalletPassword;
|
||||
|
||||
bool get hasWalletPassword => SettingsStoreBase.walletPasswordDirectInput;
|
||||
|
||||
WalletType type;
|
||||
|
@ -52,6 +53,7 @@ abstract class WalletCreationVMBase with Store {
|
|||
final WalletCreationService walletCreationService;
|
||||
final Box<WalletInfo> _walletInfoSource;
|
||||
final AppStore _appStore;
|
||||
final SeedSettingsViewModel seedSettingsViewModel;
|
||||
|
||||
bool isPolyseed(String seed) =>
|
||||
(type == WalletType.monero || type == WalletType.wownero) &&
|
||||
|
@ -95,7 +97,7 @@ abstract class WalletCreationVMBase with Store {
|
|||
dirPath: dirPath,
|
||||
address: '',
|
||||
showIntroCakePayCard: (!walletCreationService.typeExists(type)) && type != WalletType.haven,
|
||||
derivationInfo: credentials.derivationInfo ?? getDefaultDerivation(),
|
||||
derivationInfo: credentials.derivationInfo ?? getDefaultCreateDerivation(),
|
||||
hardwareWalletType: credentials.hardwareWalletType,
|
||||
);
|
||||
|
||||
|
@ -109,17 +111,35 @@ abstract class WalletCreationVMBase with Store {
|
|||
getIt.get<BackgroundTasks>().registerSyncTask();
|
||||
_appStore.authenticationStore.allowed();
|
||||
state = ExecutedSuccessfullyState();
|
||||
} catch (e, s) {
|
||||
} catch (e, _) {
|
||||
state = FailureState(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
DerivationInfo? getDefaultDerivation() {
|
||||
switch (this.type) {
|
||||
DerivationInfo? getDefaultCreateDerivation() {
|
||||
final useBip39 = seedSettingsViewModel.bitcoinSeedType.type == DerivationType.bip39;
|
||||
switch (type) {
|
||||
case WalletType.nano:
|
||||
return DerivationInfo(derivationType: DerivationType.nano);
|
||||
case WalletType.bitcoin:
|
||||
if (useBip39) {
|
||||
return DerivationInfo(
|
||||
derivationType: DerivationType.bip39,
|
||||
derivationPath: "m/84'/0'/0'",
|
||||
description: "Standard BIP84 native segwit",
|
||||
scriptType: "p2wpkh",
|
||||
);
|
||||
}
|
||||
return bitcoin!.getElectrumDerivations()[DerivationType.electrum]!.first;
|
||||
case WalletType.litecoin:
|
||||
if (useBip39) {
|
||||
return DerivationInfo(
|
||||
derivationType: DerivationType.bip39,
|
||||
derivationPath: "m/84'/2'/0'",
|
||||
description: "Default Litecoin",
|
||||
scriptType: "p2wpkh",
|
||||
);
|
||||
}
|
||||
return bitcoin!.getElectrumDerivations()[DerivationType.electrum]!.first;
|
||||
default:
|
||||
return null;
|
||||
|
@ -127,10 +147,14 @@ abstract class WalletCreationVMBase with Store {
|
|||
}
|
||||
|
||||
DerivationInfo? getCommonRestoreDerivation() {
|
||||
final useElectrum = seedSettingsViewModel.bitcoinSeedType.type == DerivationType.electrum;
|
||||
switch (this.type) {
|
||||
case WalletType.nano:
|
||||
return DerivationInfo(derivationType: DerivationType.nano);
|
||||
case WalletType.bitcoin:
|
||||
if (useElectrum) {
|
||||
return bitcoin!.getElectrumDerivations()[DerivationType.electrum]!.first;
|
||||
}
|
||||
return DerivationInfo(
|
||||
derivationType: DerivationType.bip39,
|
||||
derivationPath: "m/84'/0'/0'/0",
|
||||
|
@ -138,6 +162,9 @@ abstract class WalletCreationVMBase with Store {
|
|||
scriptType: "p2wpkh",
|
||||
);
|
||||
case WalletType.litecoin:
|
||||
if (useElectrum) {
|
||||
return bitcoin!.getElectrumDerivations()[DerivationType.electrum]!.first;
|
||||
}
|
||||
return DerivationInfo(
|
||||
derivationType: DerivationType.bip39,
|
||||
derivationPath: "m/84'/2'/0'/0",
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:cake_wallet/generated/i18n.dart';
|
|||
import 'package:cake_wallet/polygon/polygon.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
|
||||
import 'package:cw_core/hardware/hardware_account_data.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
|
@ -25,10 +26,15 @@ abstract class WalletHardwareRestoreViewModelBase extends WalletCreationVM with
|
|||
|
||||
int _nextIndex = 0;
|
||||
|
||||
WalletHardwareRestoreViewModelBase(this.ledgerViewModel, AppStore appStore,
|
||||
WalletCreationService walletCreationService, Box<WalletInfo> walletInfoSource,
|
||||
WalletHardwareRestoreViewModelBase(
|
||||
this.ledgerViewModel,
|
||||
AppStore appStore,
|
||||
WalletCreationService walletCreationService,
|
||||
Box<WalletInfo> walletInfoSource,
|
||||
SeedSettingsViewModel seedSettingsViewModel,
|
||||
{required WalletType type})
|
||||
: super(appStore, walletInfoSource, walletCreationService, type: type, isRecovery: true);
|
||||
: super(appStore, walletInfoSource, walletCreationService, seedSettingsViewModel,
|
||||
type: type, isRecovery: true);
|
||||
|
||||
@observable
|
||||
String name = "";
|
||||
|
|
|
@ -342,7 +342,8 @@ abstract class WalletKeysViewModelBase with Store {
|
|||
'hexSeed': _appStore.wallet!.hexSeed!,
|
||||
if (_appStore.wallet!.seed == null && _appStore.wallet!.privateKey != null)
|
||||
'private_key': _appStore.wallet!.privateKey!,
|
||||
if (restoreHeightResult != null) ...{'height': restoreHeightResult}
|
||||
if (restoreHeightResult != null) ...{'height': restoreHeightResult},
|
||||
if (_appStore.wallet!.passphrase != null) 'passphrase': _appStore.wallet!.passphrase!
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,35 +1,42 @@
|
|||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||
import 'package:cake_wallet/solana/solana.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
||||
import 'package:cake_wallet/entities/seed_type.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cake_wallet/haven/haven.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/nano/nano.dart';
|
||||
import 'package:cake_wallet/solana/solana.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/haven/haven.dart';
|
||||
import 'advanced_privacy_settings_view_model.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
import '../polygon/polygon.dart';
|
||||
import 'advanced_privacy_settings_view_model.dart';
|
||||
|
||||
part 'wallet_new_vm.g.dart';
|
||||
|
||||
class WalletNewVM = WalletNewVMBase with _$WalletNewVM;
|
||||
|
||||
abstract class WalletNewVMBase extends WalletCreationVM with Store {
|
||||
WalletNewVMBase(AppStore appStore, WalletCreationService walletCreationService,
|
||||
Box<WalletInfo> walletInfoSource, this.advancedPrivacySettingsViewModel,
|
||||
WalletNewVMBase(
|
||||
AppStore appStore,
|
||||
WalletCreationService walletCreationService,
|
||||
Box<WalletInfo> walletInfoSource,
|
||||
this.advancedPrivacySettingsViewModel,
|
||||
SeedSettingsViewModel seedSettingsViewModel,
|
||||
{required WalletType type})
|
||||
: selectedMnemonicLanguage = '',
|
||||
super(appStore, walletInfoSource, walletCreationService, type: type, isRecovery: false);
|
||||
super(appStore, walletInfoSource, walletCreationService, seedSettingsViewModel,
|
||||
type: type, isRecovery: false);
|
||||
|
||||
final AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel;
|
||||
|
||||
|
@ -37,47 +44,58 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
|
|||
String selectedMnemonicLanguage;
|
||||
|
||||
bool get hasLanguageSelector =>
|
||||
type == WalletType.monero || type == WalletType.haven || type == WalletType.wownero;
|
||||
[WalletType.monero, WalletType.haven, WalletType.wownero].contains(type);
|
||||
|
||||
int get seedPhraseWordsLength {
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
case WalletType.wownero:
|
||||
if (advancedPrivacySettingsViewModel.isPolySeed) {
|
||||
return 16;
|
||||
}
|
||||
return 25;
|
||||
return advancedPrivacySettingsViewModel.isPolySeed ? 16 : 25;
|
||||
case WalletType.tron:
|
||||
case WalletType.solana:
|
||||
case WalletType.polygon:
|
||||
case WalletType.ethereum:
|
||||
case WalletType.bitcoinCash:
|
||||
return advancedPrivacySettingsViewModel.seedPhraseLength.value;
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
return seedSettingsViewModel.bitcoinSeedType == BitcoinSeedType.bip39
|
||||
? advancedPrivacySettingsViewModel.seedPhraseLength.value
|
||||
: 24;
|
||||
default:
|
||||
return 24;
|
||||
}
|
||||
}
|
||||
|
||||
bool get hasSeedType => type == WalletType.monero || type == WalletType.wownero;
|
||||
bool get hasSeedType => [WalletType.monero, WalletType.wownero].contains(type);
|
||||
|
||||
@override
|
||||
WalletCredentials getCredentials(dynamic _options) {
|
||||
final options = _options as List<dynamic>?;
|
||||
final passphrase = seedSettingsViewModel.passphrase;
|
||||
seedSettingsViewModel.setPassphrase(null);
|
||||
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
return monero!.createMoneroNewWalletCredentials(
|
||||
name: name, language: options!.first as String, password: walletPassword, isPolyseed: options.last as bool);
|
||||
name: name,
|
||||
language: options!.first as String,
|
||||
password: walletPassword,
|
||||
isPolyseed: options.last as bool);
|
||||
case WalletType.bitcoin:
|
||||
return bitcoin!.createBitcoinNewWalletCredentials(name: name, password: walletPassword);
|
||||
return bitcoin!.createBitcoinNewWalletCredentials(
|
||||
name: name, password: walletPassword, passphrase: passphrase);
|
||||
case WalletType.litecoin:
|
||||
return bitcoin!.createBitcoinNewWalletCredentials(name: name, password: walletPassword);
|
||||
return bitcoin!.createBitcoinNewWalletCredentials(
|
||||
name: name, password: walletPassword, passphrase: passphrase);
|
||||
case WalletType.haven:
|
||||
return haven!.createHavenNewWalletCredentials(
|
||||
name: name, language: options!.first as String, password: walletPassword);
|
||||
case WalletType.ethereum:
|
||||
return ethereum!.createEthereumNewWalletCredentials(name: name, password: walletPassword);
|
||||
case WalletType.bitcoinCash:
|
||||
return bitcoinCash!.createBitcoinCashNewWalletCredentials(name: name, password: walletPassword);
|
||||
return bitcoinCash!.createBitcoinCashNewWalletCredentials(
|
||||
name: name, password: walletPassword, passphrase: passphrase);
|
||||
case WalletType.nano:
|
||||
case WalletType.banano:
|
||||
return nano!.createNanoNewWalletCredentials(name: name);
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/nano/nano.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||
import 'package:cake_wallet/polygon/polygon.dart';
|
||||
import 'package:cake_wallet/solana/solana.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cake_wallet/core/generate_wallet_password.dart';
|
||||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cake_wallet/haven/haven.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/nano/nano.dart';
|
||||
import 'package:cake_wallet/polygon/polygon.dart';
|
||||
import 'package:cake_wallet/solana/solana.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'wallet_restore_view_model.g.dart';
|
||||
|
||||
|
@ -27,7 +28,7 @@ class WalletRestoreViewModel = WalletRestoreViewModelBase with _$WalletRestoreVi
|
|||
|
||||
abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||
WalletRestoreViewModelBase(AppStore appStore, WalletCreationService walletCreationService,
|
||||
Box<WalletInfo> walletInfoSource,
|
||||
Box<WalletInfo> walletInfoSource, SeedSettingsViewModel seedSettingsViewModel,
|
||||
{required WalletType type})
|
||||
: hasSeedLanguageSelector =
|
||||
type == WalletType.monero || type == WalletType.haven || type == WalletType.wownero,
|
||||
|
@ -41,7 +42,8 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
type == WalletType.tron,
|
||||
isButtonEnabled = false,
|
||||
mode = WalletRestoreMode.seed,
|
||||
super(appStore, walletInfoSource, walletCreationService, type: type, isRecovery: true) {
|
||||
super(appStore, walletInfoSource, walletCreationService, seedSettingsViewModel,
|
||||
type: type, isRecovery: true) {
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
availableModes = WalletRestoreMode.values;
|
||||
|
@ -76,7 +78,8 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
final bool hasBlockchainHeightLanguageSelector;
|
||||
final bool hasRestoreFromPrivateKey;
|
||||
|
||||
bool get hasPassphrase => [WalletType.bitcoin, WalletType.litecoin].contains(type);
|
||||
bool get hasPassphrase =>
|
||||
[WalletType.bitcoin, WalletType.litecoin, WalletType.bitcoinCash].contains(type);
|
||||
|
||||
@observable
|
||||
WalletRestoreMode mode;
|
||||
|
@ -192,10 +195,11 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
|
||||
case WalletType.nano:
|
||||
return nano!.createNanoRestoreWalletFromKeysCredentials(
|
||||
name: name,
|
||||
password: password,
|
||||
seedKey: options['private_key'] as String,
|
||||
derivationType: options["derivationType"] as DerivationType);
|
||||
name: name,
|
||||
password: password,
|
||||
seedKey: options['private_key'] as String,
|
||||
derivationType: derivationInfo!.derivationType!,
|
||||
);
|
||||
case WalletType.polygon:
|
||||
return polygon!.createPolygonRestoreWalletFromPrivateKey(
|
||||
name: name,
|
||||
|
|
|
@ -195,6 +195,7 @@
|
|||
"delete_wallet_confirm_message": "هل أنت متأكد أنك تريد حذف محفظة ${wallet_name}؟",
|
||||
"deleteConnectionConfirmationPrompt": "ـﺑ ﻝﺎﺼﺗﻻﺍ ﻑﺬﺣ ﺪﻳﺮﺗ ﻚﻧﺃ ﺪﻛﺄﺘﻣ ﺖﻧﺃ ﻞﻫ",
|
||||
"denominations": "الطوائف",
|
||||
"derivationpath": "مسار الاشتقاق",
|
||||
"descending": "النزول",
|
||||
"description": "ﻒﺻﻭ",
|
||||
"destination_tag": "علامة الوجهة:",
|
||||
|
@ -207,6 +208,7 @@
|
|||
"disable_buy": "تعطيل إجراء الشراء",
|
||||
"disable_cake_2fa": "تعطيل 2 عامل المصادقة",
|
||||
"disable_exchange": "تعطيل التبادل",
|
||||
"disable_fee_api_warning": "من خلال إيقاف تشغيل هذا ، قد تكون معدلات الرسوم غير دقيقة في بعض الحالات ، لذلك قد ينتهي بك الأمر إلى دفع مبالغ زائدة أو دفع رسوم المعاملات الخاصة بك",
|
||||
"disable_fiat": "تعطيل fiat",
|
||||
"disable_sell": "قم بتعطيل إجراء البيع",
|
||||
"disableBatteryOptimization": "تعطيل تحسين البطارية",
|
||||
|
@ -354,6 +356,7 @@
|
|||
"ledger_error_wrong_app": "يرجى التأكد",
|
||||
"ledger_please_enable_bluetooth": "يرجى تمكين البلوتوث للكشف عن دفتر الأستاذ الخاص بك",
|
||||
"light_theme": "فاتح",
|
||||
"live_fee_rates": "أسعار الرسوم المباشرة عبر API",
|
||||
"load_more": "تحميل المزيد",
|
||||
"loading_your_wallet": "يتم تحميل محفظتك",
|
||||
"login": "تسجيل الدخول",
|
||||
|
|
|
@ -195,6 +195,7 @@
|
|||
"delete_wallet_confirm_message": "Сигурни ли сте, че искате да изтриете протфейла ${wallet_name}?",
|
||||
"deleteConnectionConfirmationPrompt": "Сигурни ли сте, че искате да изтриете връзката към",
|
||||
"denominations": "Деноминации",
|
||||
"derivationpath": "Пътят на производно",
|
||||
"descending": "Низходящ",
|
||||
"description": "Описание",
|
||||
"destination_tag": "Destination tag:",
|
||||
|
@ -207,6 +208,7 @@
|
|||
"disable_buy": "Деактивирайте действието за покупка",
|
||||
"disable_cake_2fa": "Деактивирайте Cake 2FA",
|
||||
"disable_exchange": "Деактивиране на борса",
|
||||
"disable_fee_api_warning": "Като изключите това, таксите могат да бъдат неточни в някои случаи, така че може да се препланите или да не плащате таксите за вашите транзакции",
|
||||
"disable_fiat": "Деактивиране на fiat",
|
||||
"disable_sell": "Деактивирайте действието за продажба",
|
||||
"disableBatteryOptimization": "Деактивирайте оптимизацията на батерията",
|
||||
|
@ -354,6 +356,7 @@
|
|||
"ledger_error_wrong_app": "Моля, уверете се, че сте отворили правилното приложение на вашата книга",
|
||||
"ledger_please_enable_bluetooth": "Моля, активирайте Bluetooth да открие вашата книга",
|
||||
"light_theme": "Светло",
|
||||
"live_fee_rates": "Цени на таксите на живо чрез API",
|
||||
"load_more": "Зареди още",
|
||||
"loading_your_wallet": "Зареждане на портфейл",
|
||||
"login": "Влизане",
|
||||
|
|
|
@ -195,6 +195,7 @@
|
|||
"delete_wallet_confirm_message": "Opravdu chcete smazat ${wallet_name} peněženku?",
|
||||
"deleteConnectionConfirmationPrompt": "Jste si jisti, že chcete smazat připojení k?",
|
||||
"denominations": "Označení",
|
||||
"derivationpath": "Derivační cesta",
|
||||
"descending": "Klesající",
|
||||
"description": "Popis",
|
||||
"destination_tag": "Destination Tag:",
|
||||
|
@ -207,6 +208,7 @@
|
|||
"disable_buy": "Zakázat akci nákupu",
|
||||
"disable_cake_2fa": "Zakázat Cake 2FA",
|
||||
"disable_exchange": "Zakázat směnárny",
|
||||
"disable_fee_api_warning": "Tímto vypnutím by sazby poplatků mohly být v některých případech nepřesné, takže byste mohli skončit přepláváním nebo nedoplatkem poplatků za vaše transakce",
|
||||
"disable_fiat": "Zakázat fiat",
|
||||
"disable_sell": "Zakázat akci prodeje",
|
||||
"disableBatteryOptimization": "Zakázat optimalizaci baterie",
|
||||
|
@ -354,6 +356,7 @@
|
|||
"ledger_error_wrong_app": "Ujistěte se, že se na své knize otevřete správnou aplikaci",
|
||||
"ledger_please_enable_bluetooth": "Umožněte prosím Bluetooth detekovat vaši knihu",
|
||||
"light_theme": "Světlý",
|
||||
"live_fee_rates": "Živé sazby poplatků prostřednictvím API",
|
||||
"load_more": "Načíst další",
|
||||
"loading_your_wallet": "Načítám peněženku",
|
||||
"login": "Login",
|
||||
|
|
|
@ -195,6 +195,7 @@
|
|||
"delete_wallet_confirm_message": "Sind Sie sicher, dass Sie das ${wallet_name} Wallet löschen möchten?",
|
||||
"deleteConnectionConfirmationPrompt": "Sind Sie sicher, dass Sie die Verbindung zu löschen möchten?",
|
||||
"denominations": "Konfessionen",
|
||||
"derivationpath": "Ableitungspfad",
|
||||
"descending": "Absteigend",
|
||||
"description": "Beschreibung",
|
||||
"destination_tag": "Ziel-Tag:",
|
||||
|
@ -207,6 +208,7 @@
|
|||
"disable_buy": "Kaufaktion deaktivieren",
|
||||
"disable_cake_2fa": "Cake 2FA deaktivieren",
|
||||
"disable_exchange": "Exchange deaktivieren",
|
||||
"disable_fee_api_warning": "Wenn dies ausgeschaltet wird, sind die Gebührenquoten in einigen Fällen möglicherweise ungenau, sodass Sie die Gebühren für Ihre Transaktionen möglicherweise überbezahlt oder unterzahlt",
|
||||
"disable_fiat": "Fiat deaktivieren",
|
||||
"disable_sell": "Verkaufsaktion deaktivieren",
|
||||
"disableBatteryOptimization": "Batterieoptimierung deaktivieren",
|
||||
|
@ -354,6 +356,7 @@
|
|||
"ledger_error_wrong_app": "Bitte stellen Sie sicher, dass Sie die richtige App auf Ihrem Ledger geöffnet haben",
|
||||
"ledger_please_enable_bluetooth": "Bitte aktivieren Sie Bluetooth um sich mit Ihren Ledger zu verbinden.",
|
||||
"light_theme": "Hell",
|
||||
"live_fee_rates": "Live -Gebührenpreise über API",
|
||||
"load_more": "Mehr laden",
|
||||
"loading_your_wallet": "Wallet wird geladen",
|
||||
"login": "Einloggen",
|
||||
|
|
|
@ -195,6 +195,7 @@
|
|||
"delete_wallet_confirm_message": "Are you sure that you want to delete ${wallet_name} wallet?",
|
||||
"deleteConnectionConfirmationPrompt": "Are you sure that you want to delete the connection to",
|
||||
"denominations": "Denominations",
|
||||
"derivationpath": "Derivation Path",
|
||||
"descending": "Descending",
|
||||
"description": "Description",
|
||||
"destination_tag": "Destination tag:",
|
||||
|
@ -207,6 +208,7 @@
|
|||
"disable_buy": "Disable buy action",
|
||||
"disable_cake_2fa": "Disable Cake 2FA",
|
||||
"disable_exchange": "Disable exchange",
|
||||
"disable_fee_api_warning": "By turning this off, the fee rates might be inaccurate in some cases, so you might end up overpaying or underpaying the fees for your transactions",
|
||||
"disable_fiat": "Disable fiat",
|
||||
"disable_sell": "Disable sell action",
|
||||
"disableBatteryOptimization": "Disable Battery Optimization",
|
||||
|
@ -354,6 +356,7 @@
|
|||
"ledger_error_wrong_app": "Please make sure you opend the right app on your ledger",
|
||||
"ledger_please_enable_bluetooth": "Please enable Bluetooth to detect your Ledger",
|
||||
"light_theme": "Light",
|
||||
"live_fee_rates": "Live fee rates via API",
|
||||
"load_more": "Load more",
|
||||
"loading_your_wallet": "Loading your wallet",
|
||||
"login": "Login",
|
||||
|
|
|
@ -195,6 +195,7 @@
|
|||
"delete_wallet_confirm_message": "¿Está seguro de que desea eliminar la billetera ${wallet_name}?",
|
||||
"deleteConnectionConfirmationPrompt": "¿Está seguro de que desea eliminar la conexión a",
|
||||
"denominations": "Denominaciones",
|
||||
"derivationpath": "Ruta de derivación",
|
||||
"descending": "Descendente",
|
||||
"description": "Descripción",
|
||||
"destination_tag": "Etiqueta de destino:",
|
||||
|
@ -207,6 +208,7 @@
|
|||
"disable_buy": "Desactivar acción de compra",
|
||||
"disable_cake_2fa": "Desactivar pastel 2FA",
|
||||
"disable_exchange": "Deshabilitar intercambio",
|
||||
"disable_fee_api_warning": "Al apagar esto, las tasas de tarifas pueden ser inexactas en algunos casos, por lo que puede terminar pagando en exceso o pagando menos las tarifas por sus transacciones",
|
||||
"disable_fiat": "Deshabilitar fiat",
|
||||
"disable_sell": "Desactivar acción de venta",
|
||||
"disableBatteryOptimization": "Deshabilitar la optimización de la batería",
|
||||
|
@ -354,6 +356,7 @@
|
|||
"ledger_error_wrong_app": "Por favor, asegúrese de abrir la aplicación correcta en su libro mayor.",
|
||||
"ledger_please_enable_bluetooth": "Habilite Bluetooth para detectar su libro mayor",
|
||||
"light_theme": "Ligera",
|
||||
"live_fee_rates": "Tasas de tarifas en vivo a través de API",
|
||||
"load_more": "Carga más",
|
||||
"loading_your_wallet": "Cargando tu billetera",
|
||||
"login": "Iniciar sesión",
|
||||
|
@ -894,4 +897,4 @@
|
|||
"you_will_get": "Convertir a",
|
||||
"you_will_send": "Convertir de",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
|
@ -195,6 +195,7 @@
|
|||
"delete_wallet_confirm_message": "Êtes-vous sûr de vouloir supprimer le portefeuille (wallet) ${wallet_name}?",
|
||||
"deleteConnectionConfirmationPrompt": "Êtes-vous sûr de vouloir supprimer la connexion à",
|
||||
"denominations": "Dénominations",
|
||||
"derivationpath": "Chemin de dérivation",
|
||||
"descending": "Descendant",
|
||||
"description": "Description",
|
||||
"destination_tag": "Tag de destination :",
|
||||
|
@ -207,6 +208,7 @@
|
|||
"disable_buy": "Désactiver l'action d'achat",
|
||||
"disable_cake_2fa": "Désactiver Cake 2FA",
|
||||
"disable_exchange": "Désactiver l'échange",
|
||||
"disable_fee_api_warning": "En désactivant cela, les taux de frais peuvent être inexacts dans certains cas, vous pourriez donc finir par payer trop ou sous-paiement les frais pour vos transactions",
|
||||
"disable_fiat": "Désactiver les montants en fiat",
|
||||
"disable_sell": "Désactiver l'action de vente",
|
||||
"disableBatteryOptimization": "Désactiver l'optimisation de la batterie",
|
||||
|
@ -354,6 +356,7 @@
|
|||
"ledger_error_wrong_app": "Veuillez vous assurer d'ouvrir la bonne application sur votre grand livre",
|
||||
"ledger_please_enable_bluetooth": "Veuillez activer Bluetooth pour détecter votre grand livre",
|
||||
"light_theme": "Clair",
|
||||
"live_fee_rates": "Taux de frais en direct via l'API",
|
||||
"load_more": "Charger plus",
|
||||
"loading_your_wallet": "Chargement de votre portefeuille (wallet)",
|
||||
"login": "Utilisateur",
|
||||
|
|
|
@ -195,6 +195,7 @@
|
|||
"delete_wallet_confirm_message": "Shin kun tabbata cewa kuna son share jakar ${wallet_name}?",
|
||||
"deleteConnectionConfirmationPrompt": "Shin kun tabbata cewa kuna son share haɗin zuwa",
|
||||
"denominations": "Denominations",
|
||||
"derivationpath": "Hanyar Nasara",
|
||||
"descending": "Saukowa",
|
||||
"description": "Bayani",
|
||||
"destination_tag": "Tambarin makoma:",
|
||||
|
@ -207,6 +208,7 @@
|
|||
"disable_buy": "Kashe alama",
|
||||
"disable_cake_2fa": "Musaki Cake 2FA",
|
||||
"disable_exchange": "Kashe musanya",
|
||||
"disable_fee_api_warning": "Ta hanyar juya wannan kashe, kudaden da zai iya zama ba daidai ba a wasu halaye, saboda haka zaku iya ƙare da overpaying ko a ƙarƙashin kudaden don ma'amaloli",
|
||||
"disable_fiat": "Dakatar da fiat",
|
||||
"disable_sell": "Kashe karbuwa",
|
||||
"disableBatteryOptimization": "Kashe ingantawa baturi",
|
||||
|
@ -354,6 +356,7 @@
|
|||
"ledger_error_wrong_app": "Da fatan za a tabbata kun yi amfani da app ɗin dama akan dillalarku",
|
||||
"ledger_please_enable_bluetooth": "Da fatan za a kunna Bluetooth don gano Ledger ɗinku",
|
||||
"light_theme": "Haske",
|
||||
"live_fee_rates": "Kudin Kiɗa ta API",
|
||||
"load_more": "Like more",
|
||||
"loading_your_wallet": "Ana loda walat ɗin ku",
|
||||
"login": "Shiga",
|
||||
|
|
|
@ -195,6 +195,7 @@
|
|||
"delete_wallet_confirm_message": "क्या आप वाकई ${wallet_name} वॉलेट हटाना चाहते हैं?",
|
||||
"deleteConnectionConfirmationPrompt": "क्या आप वाकई कनेक्शन हटाना चाहते हैं?",
|
||||
"denominations": "मूल्यवर्ग",
|
||||
"derivationpath": "व्युत्पत्ति पथ",
|
||||
"descending": "अवरोही",
|
||||
"description": "विवरण",
|
||||
"destination_tag": "गंतव्य टैग:",
|
||||
|
@ -207,6 +208,7 @@
|
|||
"disable_buy": "खरीद कार्रवाई अक्षम करें",
|
||||
"disable_cake_2fa": "केक 2FA अक्षम करें",
|
||||
"disable_exchange": "एक्सचेंज अक्षम करें",
|
||||
"disable_fee_api_warning": "इसे बंद करने से, कुछ मामलों में शुल्क दरें गलत हो सकती हैं, इसलिए आप अपने लेनदेन के लिए फीस को कम कर सकते हैं या कम कर सकते हैं",
|
||||
"disable_fiat": "िएट को अक्षम करें",
|
||||
"disable_sell": "बेचने की कार्रवाई अक्षम करें",
|
||||
"disableBatteryOptimization": "बैटरी अनुकूलन अक्षम करें",
|
||||
|
@ -354,6 +356,7 @@
|
|||
"ledger_error_wrong_app": "कृपया सुनिश्चित करें कि आप अपने लेजर पर सही ऐप को खोलते हैं",
|
||||
"ledger_please_enable_bluetooth": "कृपया अपने बहीखाने का पता लगाने के लिए ब्लूटूथ को सक्षम करें",
|
||||
"light_theme": "रोशनी",
|
||||
"live_fee_rates": "एपीआई के माध्यम से लाइव शुल्क दरें",
|
||||
"load_more": "और लोड करें",
|
||||
"loading_your_wallet": "अपना बटुआ लोड कर रहा है",
|
||||
"login": "लॉग इन करें",
|
||||
|
|
|
@ -195,6 +195,7 @@
|
|||
"delete_wallet_confirm_message": "Jeste li sigurni da želite izbrisati ${wallet_name} novčanik?",
|
||||
"deleteConnectionConfirmationPrompt": "Jeste li sigurni da želite izbrisati vezu s",
|
||||
"denominations": "Denominacije",
|
||||
"derivationpath": "Put derivacije",
|
||||
"descending": "Silazni",
|
||||
"description": "Opis",
|
||||
"destination_tag": "Odredišna oznaka:",
|
||||
|
@ -207,6 +208,7 @@
|
|||
"disable_buy": "Onemogući kupnju",
|
||||
"disable_cake_2fa": "Onemogući Cake 2FA",
|
||||
"disable_exchange": "Onemogući exchange",
|
||||
"disable_fee_api_warning": "Isključivanjem ovoga, stope naknade u nekim bi slučajevima mogle biti netočne, tako da biste mogli preplatiti ili predati naknadu za vaše transakcije",
|
||||
"disable_fiat": "Isključi, fiat",
|
||||
"disable_sell": "Onemogući akciju prodaje",
|
||||
"disableBatteryOptimization": "Onemogući optimizaciju baterije",
|
||||
|
@ -354,6 +356,7 @@
|
|||
"ledger_error_wrong_app": "Obavezno obavezno otvorite pravu aplikaciju na knjizi",
|
||||
"ledger_please_enable_bluetooth": "Omogućite Bluetooth da otkrije svoju knjigu",
|
||||
"light_theme": "Svijetla",
|
||||
"live_fee_rates": "Stope naknada uživo putem API -ja",
|
||||
"load_more": "Učitaj više",
|
||||
"loading_your_wallet": "Novčanik se učitava",
|
||||
"login": "Prijava",
|
||||
|
|
|
@ -207,6 +207,7 @@
|
|||
"disable_buy": "Անջատել գնում գործողությունը",
|
||||
"disable_cake_2fa": "Անջատել Cake 2FA",
|
||||
"disable_exchange": "Անջատել փոխանակումը",
|
||||
"disable_fee_api_warning": "Դրանից անջատելով, վճարների տեմպերը որոշ դեպքերում կարող են անճիշտ լինել, այնպես որ դուք կարող եք վերջ տալ ձեր գործարքների համար վճարների գերավճարների կամ գերավճարների վրա",
|
||||
"disable_fiat": "Անջատել ֆիատ",
|
||||
"disable_sell": "Անջատել վաճառք գործողությունը",
|
||||
"disableBatteryOptimization": "Անջատել մարտկոցի օպտիմիզացիան",
|
||||
|
@ -354,6 +355,7 @@
|
|||
"ledger_error_wrong_app": "Խնդրում ենք համոզվել, որ դուք բացել եք ճիշտ ծրագիրը ձեր Ledger-ում",
|
||||
"ledger_please_enable_bluetooth": "Խնդրում ենք միացնել Bluetooth-ը ձեր Ledger-ը հայտնաբերելու համար",
|
||||
"light_theme": "Լուսավոր",
|
||||
"live_fee_rates": "Ապակի վարձավճարներ API- ի միջոցով",
|
||||
"load_more": "Բեռնել ավելին",
|
||||
"loading_your_wallet": "Ձեր հաշվեհամարը բեռնում է",
|
||||
"login": "Մուտք",
|
||||
|
|
|
@ -195,6 +195,7 @@
|
|||
"delete_wallet_confirm_message": "Apakah Anda yakin ingin menghapus dompet ${wallet_name}?",
|
||||
"deleteConnectionConfirmationPrompt": "Apakah Anda yakin ingin menghapus koneksi ke",
|
||||
"denominations": "Denominasi",
|
||||
"derivationpath": "Jalur derivasi",
|
||||
"descending": "Menurun",
|
||||
"description": "Keterangan",
|
||||
"destination_tag": "Tag tujuan:",
|
||||
|
@ -207,6 +208,7 @@
|
|||
"disable_buy": "Nonaktifkan tindakan beli",
|
||||
"disable_cake_2fa": "Nonaktifkan Kue 2FA",
|
||||
"disable_exchange": "Nonaktifkan pertukaran",
|
||||
"disable_fee_api_warning": "Dengan mematikan ini, tarif biaya mungkin tidak akurat dalam beberapa kasus, jadi Anda mungkin akan membayar lebih atau membayar biaya untuk transaksi Anda",
|
||||
"disable_fiat": "Nonaktifkan fiat",
|
||||
"disable_sell": "Nonaktifkan aksi jual",
|
||||
"disableBatteryOptimization": "Nonaktifkan optimasi baterai",
|
||||
|
@ -354,6 +356,7 @@
|
|||
"ledger_error_wrong_app": "Pastikan Anda membuka aplikasi yang tepat di buku besar Anda",
|
||||
"ledger_please_enable_bluetooth": "Harap aktifkan Bluetooth untuk mendeteksi buku besar Anda",
|
||||
"light_theme": "Terang",
|
||||
"live_fee_rates": "Tarif biaya langsung melalui API",
|
||||
"load_more": "Muat lebih banyak",
|
||||
"loading_your_wallet": "Memuat dompet Anda",
|
||||
"login": "Masuk",
|
||||
|
|
|
@ -196,6 +196,7 @@
|
|||
"delete_wallet_confirm_message": "Sei sicuro di voler eliminare il portafoglio ${wallet_name}?",
|
||||
"deleteConnectionConfirmationPrompt": "Sei sicuro di voler eliminare la connessione a",
|
||||
"denominations": "Denominazioni",
|
||||
"derivationpath": "Percorso di derivazione",
|
||||
"descending": "Discendente",
|
||||
"description": "Descrizione",
|
||||
"destination_tag": "Tag destinazione:",
|
||||
|
@ -208,6 +209,7 @@
|
|||
"disable_buy": "Disabilita l'azione di acquisto",
|
||||
"disable_cake_2fa": "Disabilita Cake 2FA",
|
||||
"disable_exchange": "Disabilita scambio",
|
||||
"disable_fee_api_warning": "Disattivando questo, i tassi delle commissioni potrebbero essere inaccurati in alcuni casi, quindi potresti finire in eccesso o sostenere le commissioni per le transazioni",
|
||||
"disable_fiat": "Disabilita fiat",
|
||||
"disable_sell": "Disabilita l'azione di vendita",
|
||||
"disableBatteryOptimization": "Disabilita l'ottimizzazione della batteria",
|
||||
|
@ -355,6 +357,7 @@
|
|||
"ledger_error_wrong_app": "Assicurati di aprire l'app giusta sul libro mastro",
|
||||
"ledger_please_enable_bluetooth": "Si prega di consentire al Bluetooth di rilevare il libro mastro",
|
||||
"light_theme": "Bianco",
|
||||
"live_fee_rates": "Tariffe delle commissioni dal vivo tramite API",
|
||||
"load_more": "Carica di più",
|
||||
"loading_your_wallet": "Caricamento portafoglio",
|
||||
"login": "Accedi",
|
||||
|
|
|
@ -195,6 +195,7 @@
|
|||
"delete_wallet_confirm_message": "${wallet_name} ウォレットを削除してもよろしいですか?",
|
||||
"deleteConnectionConfirmationPrompt": "への接続を削除してもよろしいですか?",
|
||||
"denominations": "宗派",
|
||||
"derivationpath": "派生パス",
|
||||
"descending": "下降",
|
||||
"description": "説明",
|
||||
"destination_tag": "宛先タグ:",
|
||||
|
@ -207,6 +208,7 @@
|
|||
"disable_buy": "購入アクションを無効にする",
|
||||
"disable_cake_2fa": "Cake 2FA を無効にする",
|
||||
"disable_exchange": "交換を無効にする",
|
||||
"disable_fee_api_warning": "これをオフにすることで、料金金利は場合によっては不正確になる可能性があるため、取引の費用が過払いまたは不足している可能性があります",
|
||||
"disable_fiat": "フィアットを無効にする",
|
||||
"disable_sell": "販売アクションを無効にする",
|
||||
"disableBatteryOptimization": "バッテリーの最適化を無効にします",
|
||||
|
@ -355,6 +357,7 @@
|
|||
"ledger_error_wrong_app": "元帳に適切なアプリを開始するようにしてください",
|
||||
"ledger_please_enable_bluetooth": "Bluetoothが元帳を検出できるようにしてください",
|
||||
"light_theme": "光",
|
||||
"live_fee_rates": "API経由のライブ料金",
|
||||
"load_more": "もっと読み込む",
|
||||
"loading_your_wallet": "ウォレットをロードしています",
|
||||
"login": "ログイン",
|
||||
|
|
|
@ -195,6 +195,7 @@
|
|||
"delete_wallet_confirm_message": "${wallet_name} 지갑을 삭제하시겠습니까?",
|
||||
"deleteConnectionConfirmationPrompt": "다음 연결을 삭제하시겠습니까?",
|
||||
"denominations": "교파",
|
||||
"derivationpath": "파생 경로",
|
||||
"descending": "내림차순",
|
||||
"description": "설명",
|
||||
"destination_tag": "목적지 태그:",
|
||||
|
@ -207,6 +208,7 @@
|
|||
"disable_buy": "구매 행동 비활성화",
|
||||
"disable_cake_2fa": "케이크 2FA 비활성화",
|
||||
"disable_exchange": "교환 비활성화",
|
||||
"disable_fee_api_warning": "이것을 끄면 경우에 따라 수수료가 부정확 할 수 있으므로 거래 수수료를 초과 지불하거나 지불 할 수 있습니다.",
|
||||
"disable_fiat": "법정화폐 비활성화",
|
||||
"disable_sell": "판매 조치 비활성화",
|
||||
"disableBatteryOptimization": "배터리 최적화를 비활성화합니다",
|
||||
|
@ -354,6 +356,7 @@
|
|||
"ledger_error_wrong_app": "원장에서 올바른 앱을 반대하는지 확인하십시오.",
|
||||
"ledger_please_enable_bluetooth": "Bluetooth가 원장을 감지 할 수 있도록하십시오",
|
||||
"light_theme": "빛",
|
||||
"live_fee_rates": "API를 통한 라이브 요금 요금",
|
||||
"load_more": "더로드하십시오",
|
||||
"loading_your_wallet": "지갑 넣기",
|
||||
"login": "로그인",
|
||||
|
|
|
@ -195,6 +195,7 @@
|
|||
"delete_wallet_confirm_message": "${wallet_name} ပိုက်ဆံအိတ်ကို ဖျက်လိုသည်မှာ သေချာပါသလား။",
|
||||
"deleteConnectionConfirmationPrompt": "ချိတ်ဆက်မှုကို ဖျက်လိုသည်မှာ သေချာပါသလား။",
|
||||
"denominations": "ဂိုဏ်းချုပ်ပစ္စည်းများ",
|
||||
"derivationpath": "derivation လမ်းကြောင်း",
|
||||
"descending": "ဆင်း",
|
||||
"description": "ဖော်ပြချက်",
|
||||
"destination_tag": "ခရီးဆုံးအမှတ်-",
|
||||
|
@ -207,6 +208,7 @@
|
|||
"disable_buy": "ဝယ်ယူမှု လုပ်ဆောင်ချက်ကို ပိတ်ပါ။",
|
||||
"disable_cake_2fa": "ကိတ်မုန့် 2FA ကို ပိတ်ပါ။",
|
||||
"disable_exchange": "လဲလှယ်မှုကို ပိတ်ပါ။",
|
||||
"disable_fee_api_warning": "ဤအရာကိုဖွင့်ခြင်းအားဖြင့်အချို့သောကိစ္စရပ်များတွင်အခကြေးငွေနှုန်းထားများသည်တိကျမှုရှိနိုင်သည်,",
|
||||
"disable_fiat": "Fiat ကိုပိတ်ပါ။",
|
||||
"disable_sell": "ရောင်းချခြင်းလုပ်ဆောင်ချက်ကို ပိတ်ပါ။",
|
||||
"disableBatteryOptimization": "ဘက်ထရီ optimization ကိုပိတ်ပါ",
|
||||
|
@ -354,6 +356,7 @@
|
|||
"ledger_error_wrong_app": "ကျေးဇူးပြု. သင့်လက်ျာအက်ပ်ကိုသင်၏ Ledger တွင်ဖွင့်ရန်သေချာစေပါ",
|
||||
"ledger_please_enable_bluetooth": "သင်၏ Ledger ကိုရှာဖွေရန် Bluetooth ကိုဖွင့်ပါ",
|
||||
"light_theme": "အလင်း",
|
||||
"live_fee_rates": "API မှတစ်ဆင့် Live အခကြေးငွေနှုန်းထားများ",
|
||||
"load_more": "ပိုပြီး load",
|
||||
"loading_your_wallet": "သင့်ပိုက်ဆံအိတ်ကို ဖွင့်နေသည်။",
|
||||
"login": "လော့ဂ်အင်",
|
||||
|
|
|
@ -195,6 +195,7 @@
|
|||
"delete_wallet_confirm_message": "Weet u zeker dat u de portemonnee van ${wallet_name} wilt verwijderen?",
|
||||
"deleteConnectionConfirmationPrompt": "Weet u zeker dat u de verbinding met",
|
||||
"denominations": "Denominaties",
|
||||
"derivationpath": "Afleidingspad",
|
||||
"descending": "Aflopend",
|
||||
"description": "Beschrijving",
|
||||
"destination_tag": "Bestemmingstag:",
|
||||
|
@ -207,6 +208,7 @@
|
|||
"disable_buy": "Koopactie uitschakelen",
|
||||
"disable_cake_2fa": "Taart 2FA uitschakelen",
|
||||
"disable_exchange": "Uitwisseling uitschakelen",
|
||||
"disable_fee_api_warning": "Door dit uit te schakelen, kunnen de tarieven in sommige gevallen onnauwkeurig zijn, dus u kunt de vergoedingen voor uw transacties te veel betalen of te weinig betalen",
|
||||
"disable_fiat": "Schakel Fiat uit",
|
||||
"disable_sell": "Verkoopactie uitschakelen",
|
||||
"disableBatteryOptimization": "Schakel de batterijoptimalisatie uit",
|
||||
|
@ -354,6 +356,7 @@
|
|||
"ledger_error_wrong_app": "Zorg ervoor dat u de juiste app op uw grootboek opent",
|
||||
"ledger_please_enable_bluetooth": "Schakel Bluetooth in staat om uw grootboek te detecteren",
|
||||
"light_theme": "Licht",
|
||||
"live_fee_rates": "Live -tarieven via API",
|
||||
"load_more": "Meer laden",
|
||||
"loading_your_wallet": "Uw portemonnee laden",
|
||||
"login": "Log in",
|
||||
|
|
|
@ -195,6 +195,7 @@
|
|||
"delete_wallet_confirm_message": "Czy na pewno chcesz usunąć portfel ${wallet_name}?",
|
||||
"deleteConnectionConfirmationPrompt": "Czy na pewno chcesz usunąć połączenie z",
|
||||
"denominations": "Wyznaczenia",
|
||||
"derivationpath": "Ścieżka pochodna",
|
||||
"descending": "Schodzenie",
|
||||
"description": "Opis",
|
||||
"destination_tag": "Tag docelowy:",
|
||||
|
@ -207,6 +208,7 @@
|
|||
"disable_buy": "Wyłącz akcję kupna",
|
||||
"disable_cake_2fa": "Wyłącz Cake 2FA",
|
||||
"disable_exchange": "Wyłącz wymianę",
|
||||
"disable_fee_api_warning": "Wyłączając to, stawki opłaty mogą być w niektórych przypadkach niedokładne, więc możesz skończyć się przepłaceniem lub wynagrodzeniem opłat za transakcje",
|
||||
"disable_fiat": "Wyłącz waluty FIAT",
|
||||
"disable_sell": "Wyłącz akcję sprzedaży",
|
||||
"disableBatteryOptimization": "Wyłącz optymalizację baterii",
|
||||
|
@ -354,6 +356,7 @@
|
|||
"ledger_error_wrong_app": "Upewnij się, że opisz odpowiednią aplikację na swojej księdze",
|
||||
"ledger_please_enable_bluetooth": "Włącz Bluetooth wykrywanie księgi",
|
||||
"light_theme": "Jasny",
|
||||
"live_fee_rates": "Stawki opłaty na żywo za pośrednictwem API",
|
||||
"load_more": "Załaduj więcej",
|
||||
"loading_your_wallet": "Ładowanie portfela",
|
||||
"login": "Login",
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue