mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-11-17 01:37:40 +00:00
Merge branch 'main' of https://github.com/cake-tech/cake_wallet into mweb
This commit is contained in:
commit
ac1fe6b221
122 changed files with 3920 additions and 1259 deletions
2
.github/workflows/pr_test_build.yml
vendored
2
.github/workflows/pr_test_build.yml
vendored
|
@ -42,7 +42,7 @@ jobs:
|
||||||
- name: Flutter action
|
- name: Flutter action
|
||||||
uses: subosito/flutter-action@v1
|
uses: subosito/flutter-action@v1
|
||||||
with:
|
with:
|
||||||
flutter-version: "3.19.5"
|
flutter-version: "3.19.6"
|
||||||
channel: stable
|
channel: stable
|
||||||
|
|
||||||
- name: Install package dependencies
|
- name: Install package dependencies
|
||||||
|
|
65
assets/images/cards.svg
Normal file
65
assets/images/cards.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 158 KiB |
BIN
assets/images/tbtc.png
Normal file
BIN
assets/images/tbtc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
|
@ -1,3 +1,2 @@
|
||||||
Add Tron wallet
|
Bitcoin Silent Payments
|
||||||
Hardware wallets enhancements
|
Bug fixes and generic enhancements
|
||||||
Bug fixes
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ import 'dart:convert';
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:cw_bitcoin/script_hash.dart' as sh;
|
import 'package:cw_bitcoin/script_hash.dart' as sh;
|
||||||
|
|
||||||
class BitcoinAddressRecord {
|
abstract class BaseBitcoinAddressRecord {
|
||||||
BitcoinAddressRecord(
|
BaseBitcoinAddressRecord(
|
||||||
this.address, {
|
this.address, {
|
||||||
required this.index,
|
required this.index,
|
||||||
this.isHidden = false,
|
this.isHidden = false,
|
||||||
|
@ -13,15 +13,62 @@ class BitcoinAddressRecord {
|
||||||
String name = '',
|
String name = '',
|
||||||
bool isUsed = false,
|
bool isUsed = false,
|
||||||
required this.type,
|
required this.type,
|
||||||
String? scriptHash,
|
|
||||||
required this.network,
|
required this.network,
|
||||||
}) : _txCount = txCount,
|
}) : _txCount = txCount,
|
||||||
_balance = balance,
|
_balance = balance,
|
||||||
_name = name,
|
_name = name,
|
||||||
_isUsed = isUsed,
|
_isUsed = isUsed;
|
||||||
scriptHash = scriptHash ?? sh.scriptHash(address, network: network);
|
|
||||||
|
|
||||||
factory BitcoinAddressRecord.fromJSON(String jsonSource, BasedUtxoNetwork network) {
|
@override
|
||||||
|
bool operator ==(Object o) => o is BaseBitcoinAddressRecord && address == o.address;
|
||||||
|
|
||||||
|
final String address;
|
||||||
|
bool isHidden;
|
||||||
|
final int index;
|
||||||
|
int _txCount;
|
||||||
|
int _balance;
|
||||||
|
String _name;
|
||||||
|
bool _isUsed;
|
||||||
|
BasedUtxoNetwork? network;
|
||||||
|
|
||||||
|
int get txCount => _txCount;
|
||||||
|
|
||||||
|
String get name => _name;
|
||||||
|
|
||||||
|
int get balance => _balance;
|
||||||
|
|
||||||
|
set txCount(int value) => _txCount = value;
|
||||||
|
|
||||||
|
set balance(int value) => _balance = value;
|
||||||
|
|
||||||
|
bool get isUsed => _isUsed;
|
||||||
|
|
||||||
|
void setAsUsed() => _isUsed = true;
|
||||||
|
void setNewName(String label) => _name = label;
|
||||||
|
|
||||||
|
int get hashCode => address.hashCode;
|
||||||
|
|
||||||
|
BitcoinAddressType type;
|
||||||
|
|
||||||
|
String toJSON();
|
||||||
|
}
|
||||||
|
|
||||||
|
class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
||||||
|
BitcoinAddressRecord(
|
||||||
|
super.address, {
|
||||||
|
required super.index,
|
||||||
|
super.isHidden = false,
|
||||||
|
super.txCount = 0,
|
||||||
|
super.balance = 0,
|
||||||
|
super.name = '',
|
||||||
|
super.isUsed = false,
|
||||||
|
required super.type,
|
||||||
|
String? scriptHash,
|
||||||
|
required super.network,
|
||||||
|
}) : scriptHash =
|
||||||
|
scriptHash ?? (network != null ? sh.scriptHash(address, network: network) : null);
|
||||||
|
|
||||||
|
factory BitcoinAddressRecord.fromJSON(String jsonSource, {BasedUtxoNetwork? network}) {
|
||||||
final decoded = json.decode(jsonSource) as Map;
|
final decoded = json.decode(jsonSource) as Map;
|
||||||
|
|
||||||
return BitcoinAddressRecord(
|
return BitcoinAddressRecord(
|
||||||
|
@ -41,44 +88,15 @@ class BitcoinAddressRecord {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object o) => o is BitcoinAddressRecord && address == o.address;
|
|
||||||
|
|
||||||
final String address;
|
|
||||||
bool isHidden;
|
|
||||||
final int index;
|
|
||||||
int _txCount;
|
|
||||||
int _balance;
|
|
||||||
String _name;
|
|
||||||
bool _isUsed;
|
|
||||||
String? scriptHash;
|
String? scriptHash;
|
||||||
BasedUtxoNetwork network;
|
|
||||||
|
|
||||||
int get txCount => _txCount;
|
String getScriptHash(BasedUtxoNetwork network) {
|
||||||
|
if (scriptHash != null) return scriptHash!;
|
||||||
String get name => _name;
|
|
||||||
|
|
||||||
int get balance => _balance;
|
|
||||||
|
|
||||||
set txCount(int value) => _txCount = value;
|
|
||||||
|
|
||||||
set balance(int value) => _balance = value;
|
|
||||||
|
|
||||||
bool get isUsed => _isUsed;
|
|
||||||
|
|
||||||
void setAsUsed() => _isUsed = true;
|
|
||||||
void setNewName(String label) => _name = label;
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => address.hashCode;
|
|
||||||
|
|
||||||
BitcoinAddressType type;
|
|
||||||
|
|
||||||
String updateScriptHash(BasedUtxoNetwork network) {
|
|
||||||
scriptHash = sh.scriptHash(address, network: network);
|
scriptHash = sh.scriptHash(address, network: network);
|
||||||
return scriptHash!;
|
return scriptHash!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
String toJSON() => json.encode({
|
String toJSON() => json.encode({
|
||||||
'address': address,
|
'address': address,
|
||||||
'index': index,
|
'index': index,
|
||||||
|
@ -91,3 +109,57 @@ class BitcoinAddressRecord {
|
||||||
'scriptHash': scriptHash,
|
'scriptHash': scriptHash,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord {
|
||||||
|
BitcoinSilentPaymentAddressRecord(
|
||||||
|
super.address, {
|
||||||
|
required super.index,
|
||||||
|
super.isHidden = false,
|
||||||
|
super.txCount = 0,
|
||||||
|
super.balance = 0,
|
||||||
|
super.name = '',
|
||||||
|
super.isUsed = false,
|
||||||
|
required this.silentPaymentTweak,
|
||||||
|
required super.network,
|
||||||
|
required super.type,
|
||||||
|
}) : super();
|
||||||
|
|
||||||
|
factory BitcoinSilentPaymentAddressRecord.fromJSON(String jsonSource,
|
||||||
|
{BasedUtxoNetwork? network}) {
|
||||||
|
final decoded = json.decode(jsonSource) as Map;
|
||||||
|
|
||||||
|
return BitcoinSilentPaymentAddressRecord(
|
||||||
|
decoded['address'] as String,
|
||||||
|
index: decoded['index'] as int,
|
||||||
|
isHidden: decoded['isHidden'] as bool? ?? false,
|
||||||
|
isUsed: decoded['isUsed'] as bool? ?? false,
|
||||||
|
txCount: decoded['txCount'] as int? ?? 0,
|
||||||
|
name: decoded['name'] as String? ?? '',
|
||||||
|
balance: decoded['balance'] as int? ?? 0,
|
||||||
|
network: (decoded['network'] as String?) == null
|
||||||
|
? network
|
||||||
|
: BasedUtxoNetwork.fromName(decoded['network'] as String),
|
||||||
|
silentPaymentTweak: decoded['silent_payment_tweak'] as String?,
|
||||||
|
type: decoded['type'] != null && decoded['type'] != ''
|
||||||
|
? BitcoinAddressType.values
|
||||||
|
.firstWhere((type) => type.toString() == decoded['type'] as String)
|
||||||
|
: SilentPaymentsAddresType.p2sp,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String? silentPaymentTweak;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toJSON() => json.encode({
|
||||||
|
'address': address,
|
||||||
|
'index': index,
|
||||||
|
'isHidden': isHidden,
|
||||||
|
'isUsed': isUsed,
|
||||||
|
'txCount': txCount,
|
||||||
|
'name': name,
|
||||||
|
'balance': balance,
|
||||||
|
'type': type.toString(),
|
||||||
|
'network': network?.value,
|
||||||
|
'silent_payment_tweak': silentPaymentTweak,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ class BitcoinReceivePageOption implements ReceivePageOption {
|
||||||
static const p2pkh = BitcoinReceivePageOption._('Legacy (P2PKH)');
|
static const p2pkh = BitcoinReceivePageOption._('Legacy (P2PKH)');
|
||||||
static const mweb = BitcoinReceivePageOption._('MWEB');
|
static const mweb = BitcoinReceivePageOption._('MWEB');
|
||||||
|
|
||||||
|
static const silent_payments = BitcoinReceivePageOption._('Silent Payments');
|
||||||
|
|
||||||
const BitcoinReceivePageOption._(this.value);
|
const BitcoinReceivePageOption._(this.value);
|
||||||
|
|
||||||
final String value;
|
final String value;
|
||||||
|
@ -18,6 +20,7 @@ class BitcoinReceivePageOption implements ReceivePageOption {
|
||||||
}
|
}
|
||||||
|
|
||||||
static const all = [
|
static const all = [
|
||||||
|
BitcoinReceivePageOption.silent_payments,
|
||||||
BitcoinReceivePageOption.p2wpkh,
|
BitcoinReceivePageOption.p2wpkh,
|
||||||
BitcoinReceivePageOption.p2tr,
|
BitcoinReceivePageOption.p2tr,
|
||||||
BitcoinReceivePageOption.p2wsh,
|
BitcoinReceivePageOption.p2wsh,
|
||||||
|
@ -29,6 +32,24 @@ class BitcoinReceivePageOption implements ReceivePageOption {
|
||||||
BitcoinReceivePageOption.p2wpkh,
|
BitcoinReceivePageOption.p2wpkh,
|
||||||
BitcoinReceivePageOption.mweb
|
BitcoinReceivePageOption.mweb
|
||||||
];
|
];
|
||||||
|
|
||||||
|
BitcoinAddressType toType() {
|
||||||
|
switch (this) {
|
||||||
|
case BitcoinReceivePageOption.p2tr:
|
||||||
|
return SegwitAddresType.p2tr;
|
||||||
|
case BitcoinReceivePageOption.p2wsh:
|
||||||
|
return SegwitAddresType.p2wsh;
|
||||||
|
case BitcoinReceivePageOption.p2pkh:
|
||||||
|
return P2pkhAddressType.p2pkh;
|
||||||
|
case BitcoinReceivePageOption.p2sh:
|
||||||
|
return P2shAddressType.p2wpkhInP2sh;
|
||||||
|
case BitcoinReceivePageOption.silent_payments:
|
||||||
|
return SilentPaymentsAddresType.p2sp;
|
||||||
|
case BitcoinReceivePageOption.p2wpkh:
|
||||||
|
default:
|
||||||
|
return SegwitAddresType.p2wpkh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
factory BitcoinReceivePageOption.fromType(BitcoinAddressType type) {
|
factory BitcoinReceivePageOption.fromType(BitcoinAddressType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -42,6 +63,8 @@ class BitcoinReceivePageOption implements ReceivePageOption {
|
||||||
return BitcoinReceivePageOption.p2pkh;
|
return BitcoinReceivePageOption.p2pkh;
|
||||||
case P2shAddressType.p2wpkhInP2sh:
|
case P2shAddressType.p2wpkhInP2sh:
|
||||||
return BitcoinReceivePageOption.p2sh;
|
return BitcoinReceivePageOption.p2sh;
|
||||||
|
case SilentPaymentsAddresType.p2sp:
|
||||||
|
return BitcoinReceivePageOption.silent_payments;
|
||||||
case SegwitAddresType.p2wpkh:
|
case SegwitAddresType.p2wpkh:
|
||||||
default:
|
default:
|
||||||
return BitcoinReceivePageOption.p2wpkh;
|
return BitcoinReceivePageOption.p2wpkh;
|
||||||
|
|
|
@ -2,13 +2,66 @@ import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_core/unspent_transaction_output.dart';
|
import 'package:cw_core/unspent_transaction_output.dart';
|
||||||
|
|
||||||
class BitcoinUnspent extends Unspent {
|
class BitcoinUnspent extends Unspent {
|
||||||
BitcoinUnspent(BitcoinAddressRecord addressRecord, String hash, int value, int vout)
|
BitcoinUnspent(BaseBitcoinAddressRecord addressRecord, String hash, int value, int vout)
|
||||||
: bitcoinAddressRecord = addressRecord,
|
: bitcoinAddressRecord = addressRecord,
|
||||||
super(addressRecord.address, hash, value, vout, null);
|
super(addressRecord.address, hash, value, vout, null);
|
||||||
|
|
||||||
factory BitcoinUnspent.fromJSON(BitcoinAddressRecord address, Map<String, dynamic> json) =>
|
factory BitcoinUnspent.fromJSON(BaseBitcoinAddressRecord? address, Map<String, dynamic> json) =>
|
||||||
BitcoinUnspent(
|
BitcoinUnspent(
|
||||||
address, json['tx_hash'] as String, json['value'] as int, json['tx_pos'] as int);
|
address ?? BitcoinAddressRecord.fromJSON(json['address_record'].toString()),
|
||||||
|
json['tx_hash'] as String,
|
||||||
|
json['value'] as int,
|
||||||
|
json['tx_pos'] as int,
|
||||||
|
);
|
||||||
|
|
||||||
final BitcoinAddressRecord bitcoinAddressRecord;
|
Map<String, dynamic> toJson() {
|
||||||
|
final json = <String, dynamic>{
|
||||||
|
'address_record': bitcoinAddressRecord.toJSON(),
|
||||||
|
'tx_hash': hash,
|
||||||
|
'value': value,
|
||||||
|
'tx_pos': vout,
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
final BaseBitcoinAddressRecord bitcoinAddressRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
class BitcoinSilentPaymentsUnspent extends BitcoinUnspent {
|
||||||
|
BitcoinSilentPaymentsUnspent(
|
||||||
|
BitcoinSilentPaymentAddressRecord addressRecord,
|
||||||
|
String hash,
|
||||||
|
int value,
|
||||||
|
int vout, {
|
||||||
|
required this.silentPaymentTweak,
|
||||||
|
required this.silentPaymentLabel,
|
||||||
|
}) : super(addressRecord, hash, value, vout);
|
||||||
|
|
||||||
|
@override
|
||||||
|
factory BitcoinSilentPaymentsUnspent.fromJSON(
|
||||||
|
BitcoinSilentPaymentAddressRecord? address, Map<String, dynamic> json) =>
|
||||||
|
BitcoinSilentPaymentsUnspent(
|
||||||
|
address ?? BitcoinSilentPaymentAddressRecord.fromJSON(json['address_record'].toString()),
|
||||||
|
json['tx_hash'] as String,
|
||||||
|
json['value'] as int,
|
||||||
|
json['tx_pos'] as int,
|
||||||
|
silentPaymentTweak: json['silent_payment_tweak'] as String?,
|
||||||
|
silentPaymentLabel: json['silent_payment_label'] as String?,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final json = <String, dynamic>{
|
||||||
|
'address_record': bitcoinAddressRecord.toJSON(),
|
||||||
|
'tx_hash': hash,
|
||||||
|
'value': value,
|
||||||
|
'tx_pos': vout,
|
||||||
|
'silent_payment_tweak': silentPaymentTweak,
|
||||||
|
'silent_payment_label': silentPaymentLabel,
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
String? silentPaymentTweak;
|
||||||
|
String? silentPaymentLabel;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,22 +39,28 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
Map<String, int>? initialRegularAddressIndex,
|
Map<String, int>? initialRegularAddressIndex,
|
||||||
Map<String, int>? initialChangeAddressIndex,
|
Map<String, int>? initialChangeAddressIndex,
|
||||||
String? passphrase,
|
String? passphrase,
|
||||||
|
List<BitcoinSilentPaymentAddressRecord>? initialSilentAddresses,
|
||||||
|
int initialSilentAddressIndex = 0,
|
||||||
|
bool? alwaysScan,
|
||||||
}) : super(
|
}) : super(
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
passphrase: passphrase,
|
passphrase: passphrase,
|
||||||
xpub: xpub,
|
xpub: xpub,
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
networkType: networkParam == null
|
networkType: networkParam == null
|
||||||
? bitcoin.bitcoin
|
|
||||||
: networkParam == BitcoinNetwork.mainnet
|
|
||||||
? bitcoin.bitcoin
|
? bitcoin.bitcoin
|
||||||
: bitcoin.testnet,
|
: networkParam == BitcoinNetwork.mainnet
|
||||||
initialAddresses: initialAddresses,
|
? bitcoin.bitcoin
|
||||||
initialBalance: initialBalance,
|
: bitcoin.testnet,
|
||||||
seedBytes: seedBytes,
|
initialAddresses: initialAddresses,
|
||||||
currency: CryptoCurrency.btc) {
|
initialBalance: initialBalance,
|
||||||
|
seedBytes: seedBytes,
|
||||||
|
currency:
|
||||||
|
networkParam == BitcoinNetwork.testnet ? CryptoCurrency.tbtc : CryptoCurrency.btc,
|
||||||
|
alwaysScan: alwaysScan,
|
||||||
|
) {
|
||||||
// in a standard BIP44 wallet, mainHd derivation path = m/84'/0'/0'/0 (account 0, index unspecified here)
|
// in a standard BIP44 wallet, mainHd derivation path = m/84'/0'/0'/0 (account 0, index unspecified here)
|
||||||
// the sideHd derivation path = m/84'/0'/0'/1 (account 1, index unspecified here)
|
// the sideHd derivation path = m/84'/0'/0'/1 (account 1, index unspecified here)
|
||||||
// String derivationPath = walletInfo.derivationInfo!.derivationPath!;
|
// String derivationPath = walletInfo.derivationInfo!.derivationPath!;
|
||||||
|
@ -62,14 +68,18 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
// final hd = bitcoin.HDWallet.fromSeed(seedBytes, network: networkType);
|
// final hd = bitcoin.HDWallet.fromSeed(seedBytes, network: networkType);
|
||||||
walletAddresses = BitcoinWalletAddresses(
|
walletAddresses = BitcoinWalletAddresses(
|
||||||
walletInfo,
|
walletInfo,
|
||||||
electrumClient: electrumClient,
|
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
|
initialSilentAddresses: initialSilentAddresses,
|
||||||
|
initialSilentAddressIndex: initialSilentAddressIndex,
|
||||||
mainHd: hd,
|
mainHd: hd,
|
||||||
sideHd: accountHD.derive(1),
|
sideHd: accountHD.derive(1),
|
||||||
network: networkParam ?? network,
|
network: networkParam ?? network,
|
||||||
|
masterHd:
|
||||||
|
seedBytes != null ? bitcoin.HDWallet.fromSeed(seedBytes, network: networkType) : null,
|
||||||
);
|
);
|
||||||
|
|
||||||
autorun((_) {
|
autorun((_) {
|
||||||
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
|
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
|
||||||
});
|
});
|
||||||
|
@ -84,9 +94,11 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
String? addressPageType,
|
String? addressPageType,
|
||||||
BasedUtxoNetwork? network,
|
BasedUtxoNetwork? network,
|
||||||
List<BitcoinAddressRecord>? initialAddresses,
|
List<BitcoinAddressRecord>? initialAddresses,
|
||||||
|
List<BitcoinSilentPaymentAddressRecord>? initialSilentAddresses,
|
||||||
ElectrumBalance? initialBalance,
|
ElectrumBalance? initialBalance,
|
||||||
Map<String, int>? initialRegularAddressIndex,
|
Map<String, int>? initialRegularAddressIndex,
|
||||||
Map<String, int>? initialChangeAddressIndex,
|
Map<String, int>? initialChangeAddressIndex,
|
||||||
|
int initialSilentAddressIndex = 0,
|
||||||
}) async {
|
}) async {
|
||||||
late Uint8List seedBytes;
|
late Uint8List seedBytes;
|
||||||
|
|
||||||
|
@ -109,6 +121,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
|
initialSilentAddresses: initialSilentAddresses,
|
||||||
|
initialSilentAddressIndex: initialSilentAddressIndex,
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
seedBytes: seedBytes,
|
seedBytes: seedBytes,
|
||||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
|
@ -123,6 +137,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
required String password,
|
required String password,
|
||||||
|
required bool alwaysScan,
|
||||||
}) async {
|
}) async {
|
||||||
final network = walletInfo.network != null
|
final network = walletInfo.network != null
|
||||||
? BasedUtxoNetwork.fromName(walletInfo.network!)
|
? BasedUtxoNetwork.fromName(walletInfo.network!)
|
||||||
|
@ -163,12 +178,15 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
initialAddresses: snp.addresses,
|
initialAddresses: snp.addresses,
|
||||||
|
initialSilentAddresses: snp.silentAddresses,
|
||||||
|
initialSilentAddressIndex: snp.silentAddressIndex,
|
||||||
initialBalance: snp.balance,
|
initialBalance: snp.balance,
|
||||||
seedBytes: seedBytes,
|
seedBytes: seedBytes,
|
||||||
initialRegularAddressIndex: snp.regularAddressIndex,
|
initialRegularAddressIndex: snp.regularAddressIndex,
|
||||||
initialChangeAddressIndex: snp.changeAddressIndex,
|
initialChangeAddressIndex: snp.changeAddressIndex,
|
||||||
addressPageType: snp.addressPageType,
|
addressPageType: snp.addressPageType,
|
||||||
networkParam: network,
|
networkParam: network,
|
||||||
|
alwaysScan: alwaysScan,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +197,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
void setLedger(Ledger setLedger, LedgerDevice setLedgerDevice) {
|
void setLedger(Ledger setLedger, LedgerDevice setLedgerDevice) {
|
||||||
_ledger = setLedger;
|
_ledger = setLedger;
|
||||||
_ledgerDevice = setLedgerDevice;
|
_ledgerDevice = setLedgerDevice;
|
||||||
_bitcoinLedgerApp = BitcoinLedgerApp(_ledger!, derivationPath: walletInfo.derivationInfo!.derivationPath!);
|
_bitcoinLedgerApp =
|
||||||
|
BitcoinLedgerApp(_ledger!, derivationPath: walletInfo.derivationInfo!.derivationPath!);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -202,16 +221,17 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
final publicKeyAndDerivationPath = publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;
|
final publicKeyAndDerivationPath = publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;
|
||||||
|
|
||||||
psbtReadyInputs.add(PSBTReadyUtxoWithAddress(
|
psbtReadyInputs.add(PSBTReadyUtxoWithAddress(
|
||||||
utxo: utxo.utxo,
|
utxo: utxo.utxo,
|
||||||
rawTx: rawTx,
|
rawTx: rawTx,
|
||||||
ownerDetails: utxo.ownerDetails,
|
ownerDetails: utxo.ownerDetails,
|
||||||
ownerDerivationPath: publicKeyAndDerivationPath.derivationPath,
|
ownerDerivationPath: publicKeyAndDerivationPath.derivationPath,
|
||||||
ownerMasterFingerprint: masterFingerprint,
|
ownerMasterFingerprint: masterFingerprint,
|
||||||
ownerPublicKey: publicKeyAndDerivationPath.publicKey,
|
ownerPublicKey: publicKeyAndDerivationPath.publicKey,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
final psbt = PSBTTransactionBuild(inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF);
|
final psbt =
|
||||||
|
PSBTTransactionBuild(inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF);
|
||||||
|
|
||||||
final rawHex = await _bitcoinLedgerApp!.signPsbt(_ledgerDevice!, psbt: psbt.psbt);
|
final rawHex = await _bitcoinLedgerApp!.signPsbt(_ledgerDevice!, psbt: psbt.psbt);
|
||||||
return BtcTransaction.fromRaw(hex.encode(rawHex));
|
return BtcTransaction.fromRaw(hex.encode(rawHex));
|
||||||
|
|
|
@ -15,10 +15,12 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
||||||
required super.mainHd,
|
required super.mainHd,
|
||||||
required super.sideHd,
|
required super.sideHd,
|
||||||
required super.network,
|
required super.network,
|
||||||
required super.electrumClient,
|
|
||||||
super.initialAddresses,
|
super.initialAddresses,
|
||||||
super.initialRegularAddressIndex,
|
super.initialRegularAddressIndex,
|
||||||
super.initialChangeAddressIndex,
|
super.initialChangeAddressIndex,
|
||||||
|
super.initialSilentAddresses,
|
||||||
|
super.initialSilentAddressIndex = 0,
|
||||||
|
super.masterHd,
|
||||||
}) : super(walletInfo);
|
}) : super(walletInfo);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -19,10 +19,11 @@ class BitcoinWalletService extends WalletService<
|
||||||
BitcoinRestoreWalletFromSeedCredentials,
|
BitcoinRestoreWalletFromSeedCredentials,
|
||||||
BitcoinRestoreWalletFromWIFCredentials,
|
BitcoinRestoreWalletFromWIFCredentials,
|
||||||
BitcoinRestoreWalletFromHardware> {
|
BitcoinRestoreWalletFromHardware> {
|
||||||
BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
|
BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.alwaysScan);
|
||||||
|
|
||||||
final Box<WalletInfo> walletInfoSource;
|
final Box<WalletInfo> walletInfoSource;
|
||||||
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
|
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
|
||||||
|
final bool alwaysScan;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WalletType getType() => WalletType.bitcoin;
|
WalletType getType() => WalletType.bitcoin;
|
||||||
|
@ -55,20 +56,24 @@ class BitcoinWalletService extends WalletService<
|
||||||
.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
|
.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
|
||||||
try {
|
try {
|
||||||
final wallet = await BitcoinWalletBase.open(
|
final wallet = await BitcoinWalletBase.open(
|
||||||
password: password,
|
password: password,
|
||||||
name: name,
|
name: name,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
alwaysScan: alwaysScan,
|
||||||
|
);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
saveBackup(name);
|
saveBackup(name);
|
||||||
return wallet;
|
return wallet;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
await restoreWalletFilesFromBackup(name);
|
await restoreWalletFilesFromBackup(name);
|
||||||
final wallet = await BitcoinWalletBase.open(
|
final wallet = await BitcoinWalletBase.open(
|
||||||
password: password,
|
password: password,
|
||||||
name: name,
|
name: name,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
alwaysScan: alwaysScan,
|
||||||
|
);
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
@ -87,10 +92,12 @@ class BitcoinWalletService extends WalletService<
|
||||||
final currentWalletInfo = walletInfoSource.values
|
final currentWalletInfo = walletInfoSource.values
|
||||||
.firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
|
.firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
|
||||||
final currentWallet = await BitcoinWalletBase.open(
|
final currentWallet = await BitcoinWalletBase.open(
|
||||||
password: password,
|
password: password,
|
||||||
name: currentName,
|
name: currentName,
|
||||||
walletInfo: currentWalletInfo,
|
walletInfo: currentWalletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
alwaysScan: alwaysScan,
|
||||||
|
);
|
||||||
|
|
||||||
await currentWallet.renameWalletFiles(newName);
|
await currentWallet.renameWalletFiles(newName);
|
||||||
await saveBackup(newName);
|
await saveBackup(newName);
|
||||||
|
@ -105,12 +112,13 @@ class BitcoinWalletService extends WalletService<
|
||||||
@override
|
@override
|
||||||
Future<BitcoinWallet> restoreFromHardwareWallet(BitcoinRestoreWalletFromHardware credentials,
|
Future<BitcoinWallet> restoreFromHardwareWallet(BitcoinRestoreWalletFromHardware credentials,
|
||||||
{bool? isTestnet}) async {
|
{bool? isTestnet}) async {
|
||||||
|
|
||||||
final network = isTestnet == true ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet;
|
final network = isTestnet == true ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet;
|
||||||
credentials.walletInfo?.network = network.value;
|
credentials.walletInfo?.network = network.value;
|
||||||
credentials.walletInfo?.derivationInfo?.derivationPath = credentials.hwAccountData.derivationPath;
|
credentials.walletInfo?.derivationInfo?.derivationPath =
|
||||||
|
credentials.hwAccountData.derivationPath;
|
||||||
|
|
||||||
final wallet = await BitcoinWallet(password: credentials.password!,
|
final wallet = await BitcoinWallet(
|
||||||
|
password: credentials.password!,
|
||||||
xpub: credentials.hwAccountData.xpub,
|
xpub: credentials.hwAccountData.xpub,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
@ -123,7 +131,7 @@ class BitcoinWalletService extends WalletService<
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<BitcoinWallet> restoreFromKeys(BitcoinRestoreWalletFromWIFCredentials credentials,
|
Future<BitcoinWallet> restoreFromKeys(BitcoinRestoreWalletFromWIFCredentials credentials,
|
||||||
{bool? isTestnet}) async =>
|
{bool? isTestnet}) async =>
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -41,23 +41,35 @@ class ElectrumClient {
|
||||||
|
|
||||||
bool get isConnected => _isConnected;
|
bool get isConnected => _isConnected;
|
||||||
Socket? socket;
|
Socket? socket;
|
||||||
void Function(bool)? onConnectionStatusChange;
|
void Function(bool?)? onConnectionStatusChange;
|
||||||
int _id;
|
int _id;
|
||||||
final Map<String, SocketTask> _tasks;
|
final Map<String, SocketTask> _tasks;
|
||||||
|
Map<String, SocketTask> get tasks => _tasks;
|
||||||
final Map<String, String> _errors;
|
final Map<String, String> _errors;
|
||||||
bool _isConnected;
|
bool _isConnected;
|
||||||
Timer? _aliveTimer;
|
Timer? _aliveTimer;
|
||||||
String unterminatedString;
|
String unterminatedString;
|
||||||
|
|
||||||
Future<void> connectToUri(Uri uri) async => await connect(host: uri.host, port: uri.port);
|
Uri? uri;
|
||||||
|
bool? useSSL;
|
||||||
|
|
||||||
Future<void> connect({required String host, required int port}) async {
|
Future<void> connectToUri(Uri uri, {bool? useSSL}) async {
|
||||||
|
this.uri = uri;
|
||||||
|
this.useSSL = useSSL;
|
||||||
|
await connect(host: uri.host, port: uri.port, useSSL: useSSL);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> connect({required String host, required int port, bool? useSSL}) async {
|
||||||
try {
|
try {
|
||||||
await socket?.close();
|
await socket?.close();
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
socket = await SecureSocket.connect(host, port,
|
if (useSSL == false) {
|
||||||
timeout: connectionTimeout, onBadCertificate: (_) => true);
|
socket = await Socket.connect(host, port, timeout: connectionTimeout);
|
||||||
|
} else {
|
||||||
|
socket = await SecureSocket.connect(host, port,
|
||||||
|
timeout: connectionTimeout, onBadCertificate: (_) => true);
|
||||||
|
}
|
||||||
_setIsConnected(true);
|
_setIsConnected(true);
|
||||||
|
|
||||||
socket!.listen((Uint8List event) {
|
socket!.listen((Uint8List event) {
|
||||||
|
@ -79,7 +91,7 @@ class ElectrumClient {
|
||||||
_setIsConnected(false);
|
_setIsConnected(false);
|
||||||
}, onDone: () {
|
}, onDone: () {
|
||||||
unterminatedString = '';
|
unterminatedString = '';
|
||||||
_setIsConnected(false);
|
_setIsConnected(null);
|
||||||
});
|
});
|
||||||
keepAlive();
|
keepAlive();
|
||||||
}
|
}
|
||||||
|
@ -134,11 +146,12 @@ class ElectrumClient {
|
||||||
await callWithTimeout(method: 'server.ping');
|
await callWithTimeout(method: 'server.ping');
|
||||||
_setIsConnected(true);
|
_setIsConnected(true);
|
||||||
} on RequestFailedTimeoutException catch (_) {
|
} on RequestFailedTimeoutException catch (_) {
|
||||||
_setIsConnected(false);
|
_setIsConnected(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<String>> version() => call(method: 'server.version').then((dynamic result) {
|
Future<List<String>> version() =>
|
||||||
|
call(method: 'server.version', params: ["", "1.4"]).then((dynamic result) {
|
||||||
if (result is List) {
|
if (result is List) {
|
||||||
return result.map((dynamic val) => val.toString()).toList();
|
return result.map((dynamic val) => val.toString()).toList();
|
||||||
}
|
}
|
||||||
|
@ -266,6 +279,18 @@ class ElectrumClient {
|
||||||
Future<Map<String, dynamic>> getHeader({required int height}) async =>
|
Future<Map<String, dynamic>> getHeader({required int height}) async =>
|
||||||
await call(method: 'blockchain.block.get_header', params: [height]) as Map<String, dynamic>;
|
await call(method: 'blockchain.block.get_header', params: [height]) as Map<String, dynamic>;
|
||||||
|
|
||||||
|
BehaviorSubject<Object>? tweaksSubscribe({required int height, required int count}) {
|
||||||
|
_id += 1;
|
||||||
|
return subscribe<Object>(
|
||||||
|
id: 'blockchain.tweaks.subscribe:${height + count}',
|
||||||
|
method: 'blockchain.tweaks.subscribe',
|
||||||
|
params: [height, count, false],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<dynamic> getTweaks({required int height}) async =>
|
||||||
|
await callWithTimeout(method: 'blockchain.tweaks.subscribe', params: [height, 1, false]);
|
||||||
|
|
||||||
Future<double> estimatefee({required int p}) =>
|
Future<double> estimatefee({required int p}) =>
|
||||||
call(method: 'blockchain.estimatefee', params: [p]).then((dynamic result) {
|
call(method: 'blockchain.estimatefee', params: [p]).then((dynamic result) {
|
||||||
if (result is double) {
|
if (result is double) {
|
||||||
|
@ -308,9 +333,6 @@ class ElectrumClient {
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<List<int>> feeRates({BasedUtxoNetwork? network}) async {
|
Future<List<int>> feeRates({BasedUtxoNetwork? network}) async {
|
||||||
if (network == BitcoinNetwork.testnet) {
|
|
||||||
return [1, 1, 1];
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
final topDoubleString = await estimatefee(p: 1);
|
final topDoubleString = await estimatefee(p: 1);
|
||||||
final middleDoubleString = await estimatefee(p: 5);
|
final middleDoubleString = await estimatefee(p: 5);
|
||||||
|
@ -333,6 +355,11 @@ class ElectrumClient {
|
||||||
// }
|
// }
|
||||||
BehaviorSubject<Map<String, dynamic>>? tipListener;
|
BehaviorSubject<Map<String, dynamic>>? tipListener;
|
||||||
int? currentTip;
|
int? currentTip;
|
||||||
|
Future<int?> getCurrentBlockChainTip() =>
|
||||||
|
callWithTimeout(method: 'blockchain.headers.subscribe').then((result) {
|
||||||
|
if (result is Map<String, dynamic>) {
|
||||||
|
return result["height"] as int;
|
||||||
|
}
|
||||||
|
|
||||||
Future<int?> getCurrentBlockChainTip() async {
|
Future<int?> getCurrentBlockChainTip() async {
|
||||||
final method = 'blockchain.headers.subscribe';
|
final method = 'blockchain.headers.subscribe';
|
||||||
|
@ -345,6 +372,12 @@ class ElectrumClient {
|
||||||
return currentTip;
|
return currentTip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BehaviorSubject<Object>? chainTipSubscribe() {
|
||||||
|
_id += 1;
|
||||||
|
return subscribe<Object>(
|
||||||
|
id: 'blockchain.headers.subscribe', method: 'blockchain.headers.subscribe');
|
||||||
|
}
|
||||||
|
|
||||||
BehaviorSubject<Object>? scripthashUpdate(String scripthash) {
|
BehaviorSubject<Object>? scripthashUpdate(String scripthash) {
|
||||||
_id += 1;
|
_id += 1;
|
||||||
return subscribe<Object>(
|
return subscribe<Object>(
|
||||||
|
@ -401,7 +434,9 @@ class ElectrumClient {
|
||||||
|
|
||||||
Future<void> close() async {
|
Future<void> close() async {
|
||||||
_aliveTimer?.cancel();
|
_aliveTimer?.cancel();
|
||||||
await socket?.close();
|
try {
|
||||||
|
await socket?.close();
|
||||||
|
} catch (_) {}
|
||||||
onConnectionStatusChange = null;
|
onConnectionStatusChange = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,17 +477,25 @@ class ElectrumClient {
|
||||||
|
|
||||||
_tasks[id]?.subject?.add(params.last);
|
_tasks[id]?.subject?.add(params.last);
|
||||||
break;
|
break;
|
||||||
|
case 'blockchain.headers.subscribe':
|
||||||
|
final params = request['params'] as List<dynamic>;
|
||||||
|
_tasks[method]?.subject?.add(params.last);
|
||||||
|
break;
|
||||||
|
case 'blockchain.tweaks.subscribe':
|
||||||
|
final params = request['params'] as List<dynamic>;
|
||||||
|
_tasks[_tasks.keys.first]?.subject?.add(params.last);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setIsConnected(bool isConnected) {
|
void _setIsConnected(bool? isConnected) {
|
||||||
if (_isConnected != isConnected) {
|
if (_isConnected != isConnected) {
|
||||||
onConnectionStatusChange?.call(isConnected);
|
onConnectionStatusChange?.call(isConnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
_isConnected = isConnected;
|
_isConnected = isConnected ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleResponse(Map<String, dynamic> response) {
|
void _handleResponse(Map<String, dynamic> response) {
|
||||||
|
|
|
@ -3,8 +3,11 @@ import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
||||||
import 'package:cw_core/balance.dart';
|
import 'package:cw_core/balance.dart';
|
||||||
|
|
||||||
class ElectrumBalance extends Balance {
|
class ElectrumBalance extends Balance {
|
||||||
const ElectrumBalance({required this.confirmed, required this.unconfirmed, required this.frozen})
|
ElectrumBalance({
|
||||||
: super(confirmed, unconfirmed);
|
required this.confirmed,
|
||||||
|
required this.unconfirmed,
|
||||||
|
required this.frozen,
|
||||||
|
}) : super(confirmed, unconfirmed);
|
||||||
|
|
||||||
static ElectrumBalance? fromJSON(String? jsonSource) {
|
static ElectrumBalance? fromJSON(String? jsonSource) {
|
||||||
if (jsonSource == null) {
|
if (jsonSource == null) {
|
||||||
|
@ -19,8 +22,8 @@ class ElectrumBalance extends Balance {
|
||||||
frozen: decoded['frozen'] as int? ?? 0);
|
frozen: decoded['frozen'] as int? ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
final int confirmed;
|
int confirmed;
|
||||||
final int unconfirmed;
|
int unconfirmed;
|
||||||
final int frozen;
|
final int frozen;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -11,13 +11,11 @@ part 'electrum_transaction_history.g.dart';
|
||||||
|
|
||||||
const transactionsHistoryFileName = 'transactions.json';
|
const transactionsHistoryFileName = 'transactions.json';
|
||||||
|
|
||||||
class ElectrumTransactionHistory = ElectrumTransactionHistoryBase
|
class ElectrumTransactionHistory = ElectrumTransactionHistoryBase with _$ElectrumTransactionHistory;
|
||||||
with _$ElectrumTransactionHistory;
|
|
||||||
|
|
||||||
abstract class ElectrumTransactionHistoryBase
|
abstract class ElectrumTransactionHistoryBase
|
||||||
extends TransactionHistoryBase<ElectrumTransactionInfo> with Store {
|
extends TransactionHistoryBase<ElectrumTransactionInfo> with Store {
|
||||||
ElectrumTransactionHistoryBase(
|
ElectrumTransactionHistoryBase({required this.walletInfo, required String password})
|
||||||
{required this.walletInfo, required String password})
|
|
||||||
: _password = password,
|
: _password = password,
|
||||||
_height = 0 {
|
_height = 0 {
|
||||||
transactions = ObservableMap<String, ElectrumTransactionInfo>();
|
transactions = ObservableMap<String, ElectrumTransactionInfo>();
|
||||||
|
@ -30,8 +28,7 @@ abstract class ElectrumTransactionHistoryBase
|
||||||
Future<void> init() async => await _load();
|
Future<void> init() async => await _load();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void addOne(ElectrumTransactionInfo transaction) =>
|
void addOne(ElectrumTransactionInfo transaction) => transactions[transaction.id] = transaction;
|
||||||
transactions[transaction.id] = transaction;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void addMany(Map<String, ElectrumTransactionInfo> transactions) =>
|
void addMany(Map<String, ElectrumTransactionInfo> transactions) =>
|
||||||
|
@ -40,11 +37,13 @@ abstract class ElectrumTransactionHistoryBase
|
||||||
@override
|
@override
|
||||||
Future<void> save() async {
|
Future<void> save() async {
|
||||||
try {
|
try {
|
||||||
final dirPath =
|
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||||
await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
|
||||||
final path = '$dirPath/$transactionsHistoryFileName';
|
final path = '$dirPath/$transactionsHistoryFileName';
|
||||||
final data =
|
final txjson = {};
|
||||||
json.encode({'height': _height, 'transactions': transactions});
|
for (final tx in transactions.entries) {
|
||||||
|
txjson[tx.key] = tx.value.toJson();
|
||||||
|
}
|
||||||
|
final data = json.encode({'height': _height, 'transactions': txjson});
|
||||||
await writeData(path: path, password: _password, data: data);
|
await writeData(path: path, password: _password, data: data);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error while save bitcoin transaction history: ${e.toString()}');
|
print('Error while save bitcoin transaction history: ${e.toString()}');
|
||||||
|
@ -57,8 +56,7 @@ abstract class ElectrumTransactionHistoryBase
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> _read() async {
|
Future<Map<String, dynamic>> _read() async {
|
||||||
final dirPath =
|
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||||
await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
|
||||||
final path = '$dirPath/$transactionsHistoryFileName';
|
final path = '$dirPath/$transactionsHistoryFileName';
|
||||||
final content = await read(path: path, password: _password);
|
final content = await read(path: path, password: _password);
|
||||||
return json.decode(content) as Map<String, dynamic>;
|
return json.decode(content) as Map<String, dynamic>;
|
||||||
|
@ -84,7 +82,5 @@ abstract class ElectrumTransactionHistoryBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _update(ElectrumTransactionInfo transaction) =>
|
void _update(ElectrumTransactionInfo transaction) => transactions[transaction.id] = transaction;
|
||||||
transactions[transaction.id] = transaction;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
|
||||||
import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
|
|
||||||
import 'package:cw_bitcoin/address_from_output.dart';
|
import 'package:cw_bitcoin/address_from_output.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_unspent.dart';
|
||||||
import 'package:cw_core/transaction_direction.dart';
|
import 'package:cw_core/transaction_direction.dart';
|
||||||
import 'package:cw_core/transaction_info.dart';
|
import 'package:cw_core/transaction_info.dart';
|
||||||
import 'package:cw_core/format_amount.dart';
|
import 'package:cw_core/format_amount.dart';
|
||||||
|
@ -19,6 +18,8 @@ class ElectrumTransactionBundle {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ElectrumTransactionInfo extends TransactionInfo {
|
class ElectrumTransactionInfo extends TransactionInfo {
|
||||||
|
List<BitcoinSilentPaymentsUnspent>? unspents;
|
||||||
|
|
||||||
ElectrumTransactionInfo(this.type,
|
ElectrumTransactionInfo(this.type,
|
||||||
{required String id,
|
{required String id,
|
||||||
required int height,
|
required int height,
|
||||||
|
@ -29,7 +30,9 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
||||||
required TransactionDirection direction,
|
required TransactionDirection direction,
|
||||||
required bool isPending,
|
required bool isPending,
|
||||||
required DateTime date,
|
required DateTime date,
|
||||||
required int confirmations}) {
|
required int confirmations,
|
||||||
|
String? to,
|
||||||
|
this.unspents}) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
|
@ -40,6 +43,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
||||||
this.date = date;
|
this.date = date;
|
||||||
this.isPending = isPending;
|
this.isPending = isPending;
|
||||||
this.confirmations = confirmations;
|
this.confirmations = confirmations;
|
||||||
|
this.to = to;
|
||||||
}
|
}
|
||||||
|
|
||||||
factory ElectrumTransactionInfo.fromElectrumVerbose(Map<String, Object> obj, WalletType type,
|
factory ElectrumTransactionInfo.fromElectrumVerbose(Map<String, Object> obj, WalletType type,
|
||||||
|
@ -153,52 +157,31 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
||||||
confirmations: bundle.confirmations);
|
confirmations: bundle.confirmations);
|
||||||
}
|
}
|
||||||
|
|
||||||
factory ElectrumTransactionInfo.fromHexAndHeader(WalletType type, String hex,
|
|
||||||
{List<String>? addresses, required int height, int? timestamp, required int confirmations}) {
|
|
||||||
final tx = bitcoin.Transaction.fromHex(hex);
|
|
||||||
var exist = false;
|
|
||||||
var amount = 0;
|
|
||||||
|
|
||||||
if (addresses != null) {
|
|
||||||
tx.outs.forEach((out) {
|
|
||||||
try {
|
|
||||||
final p2pkh =
|
|
||||||
bitcoin.P2PKH(data: PaymentData(output: out.script), network: bitcoin.bitcoin);
|
|
||||||
exist = addresses.contains(p2pkh.data.address);
|
|
||||||
|
|
||||||
if (exist) {
|
|
||||||
amount += out.value!;
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
final date =
|
|
||||||
timestamp != null ? DateTime.fromMillisecondsSinceEpoch(timestamp * 1000) : DateTime.now();
|
|
||||||
|
|
||||||
return ElectrumTransactionInfo(type,
|
|
||||||
id: tx.getId(),
|
|
||||||
height: height,
|
|
||||||
isPending: false,
|
|
||||||
fee: null,
|
|
||||||
direction: TransactionDirection.incoming,
|
|
||||||
amount: amount,
|
|
||||||
date: date,
|
|
||||||
confirmations: confirmations);
|
|
||||||
}
|
|
||||||
|
|
||||||
factory ElectrumTransactionInfo.fromJson(Map<String, dynamic> data, WalletType type) {
|
factory ElectrumTransactionInfo.fromJson(Map<String, dynamic> data, WalletType type) {
|
||||||
return ElectrumTransactionInfo(type,
|
final inputAddresses = data['inputAddresses'] as List<dynamic>? ?? [];
|
||||||
id: data['id'] as String,
|
final outputAddresses = data['outputAddresses'] as List<dynamic>? ?? [];
|
||||||
height: data['height'] as int,
|
final unspents = data['unspents'] as List<dynamic>? ?? [];
|
||||||
amount: data['amount'] as int,
|
|
||||||
fee: data['fee'] as int,
|
return ElectrumTransactionInfo(
|
||||||
direction: parseTransactionDirectionFromInt(data['direction'] as int),
|
type,
|
||||||
date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int),
|
id: data['id'] as String,
|
||||||
isPending: data['isPending'] as bool,
|
height: data['height'] as int,
|
||||||
inputAddresses: List<String>.from(data['inputAddresses'] as List),
|
amount: data['amount'] as int,
|
||||||
outputAddresses: List<String>.from(data['outputAddresses'] as List),
|
fee: data['fee'] as int,
|
||||||
confirmations: data['confirmations'] as int);
|
direction: parseTransactionDirectionFromInt(data['direction'] as int),
|
||||||
|
date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int),
|
||||||
|
isPending: data['isPending'] as bool,
|
||||||
|
confirmations: data['confirmations'] as int,
|
||||||
|
inputAddresses:
|
||||||
|
inputAddresses.isEmpty ? [] : inputAddresses.map((e) => e.toString()).toList(),
|
||||||
|
outputAddresses:
|
||||||
|
outputAddresses.isEmpty ? [] : outputAddresses.map((e) => e.toString()).toList(),
|
||||||
|
to: data['to'] as String?,
|
||||||
|
unspents: unspents
|
||||||
|
.map((unspent) =>
|
||||||
|
BitcoinSilentPaymentsUnspent.fromJSON(null, unspent as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final WalletType type;
|
final WalletType type;
|
||||||
|
@ -244,8 +227,14 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
||||||
m['isPending'] = isPending;
|
m['isPending'] = isPending;
|
||||||
m['confirmations'] = confirmations;
|
m['confirmations'] = confirmations;
|
||||||
m['fee'] = fee;
|
m['fee'] = fee;
|
||||||
|
m['to'] = to;
|
||||||
|
m['unspents'] = unspents?.map((e) => e.toJson()).toList() ?? [];
|
||||||
m['inputAddresses'] = inputAddresses;
|
m['inputAddresses'] = inputAddresses;
|
||||||
m['outputAddresses'] = outputAddresses;
|
m['outputAddresses'] = outputAddresses;
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String toString() {
|
||||||
|
return 'ElectrumTransactionInfo(id: $id, height: $height, amount: $amount, fee: $fee, direction: $direction, date: $date, isPending: $isPending, confirmations: $confirmations, to: $to, unspent: $unspents)';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,7 @@
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||||
|
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/electrum.dart';
|
|
||||||
import 'package:cw_core/wallet_addresses.dart';
|
import 'package:cw_core/wallet_addresses.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
@ -25,15 +25,17 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
WalletInfo walletInfo, {
|
WalletInfo walletInfo, {
|
||||||
required this.mainHd,
|
required this.mainHd,
|
||||||
required this.sideHd,
|
required this.sideHd,
|
||||||
required this.electrumClient,
|
|
||||||
required this.network,
|
required this.network,
|
||||||
List<BitcoinAddressRecord>? initialAddresses,
|
List<BitcoinAddressRecord>? initialAddresses,
|
||||||
Map<String, int>? initialRegularAddressIndex,
|
Map<String, int>? initialRegularAddressIndex,
|
||||||
Map<String, int>? initialChangeAddressIndex,
|
Map<String, int>? initialChangeAddressIndex,
|
||||||
|
List<BitcoinSilentPaymentAddressRecord>? initialSilentAddresses,
|
||||||
|
int initialSilentAddressIndex = 0,
|
||||||
|
bitcoin.HDWallet? masterHd,
|
||||||
BitcoinAddressType? initialAddressPageType,
|
BitcoinAddressType? initialAddressPageType,
|
||||||
}) : _addresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? []).toSet()),
|
}) : _addresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? []).toSet()),
|
||||||
addressesByReceiveType =
|
addressesByReceiveType =
|
||||||
ObservableList<BitcoinAddressRecord>.of((<BitcoinAddressRecord>[]).toSet()),
|
ObservableList<BaseBitcoinAddressRecord>.of((<BitcoinAddressRecord>[]).toSet()),
|
||||||
receiveAddresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? [])
|
receiveAddresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? [])
|
||||||
.where((addressRecord) => !addressRecord.isHidden && !addressRecord.isUsed)
|
.where((addressRecord) => !addressRecord.isHidden && !addressRecord.isUsed)
|
||||||
.toSet()),
|
.toSet()),
|
||||||
|
@ -46,7 +48,38 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
(walletInfo.addressPageType != null
|
(walletInfo.addressPageType != null
|
||||||
? BitcoinAddressType.fromValue(walletInfo.addressPageType!)
|
? BitcoinAddressType.fromValue(walletInfo.addressPageType!)
|
||||||
: SegwitAddresType.p2wpkh),
|
: SegwitAddresType.p2wpkh),
|
||||||
|
silentAddresses = ObservableList<BitcoinSilentPaymentAddressRecord>.of(
|
||||||
|
(initialSilentAddresses ?? []).toSet()),
|
||||||
|
currentSilentAddressIndex = initialSilentAddressIndex,
|
||||||
super(walletInfo) {
|
super(walletInfo) {
|
||||||
|
if (masterHd != null) {
|
||||||
|
silentAddress = SilentPaymentOwner.fromPrivateKeys(
|
||||||
|
b_scan: ECPrivate.fromHex(masterHd.derivePath(SCAN_PATH).privKey!),
|
||||||
|
b_spend: ECPrivate.fromHex(masterHd.derivePath(SPEND_PATH).privKey!),
|
||||||
|
hrp: network == BitcoinNetwork.testnet ? 'tsp' : 'sp');
|
||||||
|
|
||||||
|
if (silentAddresses.length == 0) {
|
||||||
|
silentAddresses.add(BitcoinSilentPaymentAddressRecord(
|
||||||
|
silentAddress.toString(),
|
||||||
|
index: 0,
|
||||||
|
isHidden: false,
|
||||||
|
name: "",
|
||||||
|
silentPaymentTweak: null,
|
||||||
|
network: network,
|
||||||
|
type: SilentPaymentsAddresType.p2sp,
|
||||||
|
));
|
||||||
|
silentAddresses.add(BitcoinSilentPaymentAddressRecord(
|
||||||
|
silentAddress!.toLabeledSilentPaymentAddress(0).toString(),
|
||||||
|
index: 0,
|
||||||
|
isHidden: true,
|
||||||
|
name: "",
|
||||||
|
silentPaymentTweak: BytesUtils.toHexString(silentAddress!.generateLabel(0)),
|
||||||
|
network: network,
|
||||||
|
type: SilentPaymentsAddresType.p2sp,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateAddressesByMatch();
|
updateAddressesByMatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,27 +88,40 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
static const gap = 20;
|
static const gap = 20;
|
||||||
|
|
||||||
final ObservableList<BitcoinAddressRecord> _addresses;
|
final ObservableList<BitcoinAddressRecord> _addresses;
|
||||||
// Matched by addressPageType
|
late ObservableList<BaseBitcoinAddressRecord> addressesByReceiveType;
|
||||||
late ObservableList<BitcoinAddressRecord> addressesByReceiveType;
|
|
||||||
final ObservableList<BitcoinAddressRecord> receiveAddresses;
|
final ObservableList<BitcoinAddressRecord> receiveAddresses;
|
||||||
final ObservableList<BitcoinAddressRecord> changeAddresses;
|
final ObservableList<BitcoinAddressRecord> changeAddresses;
|
||||||
final ElectrumClient electrumClient;
|
final ObservableList<BitcoinSilentPaymentAddressRecord> silentAddresses;
|
||||||
final BasedUtxoNetwork network;
|
final BasedUtxoNetwork network;
|
||||||
final bitcoin.HDWallet mainHd;
|
final bitcoin.HDWallet mainHd;
|
||||||
final bitcoin.HDWallet sideHd;
|
final bitcoin.HDWallet sideHd;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
SilentPaymentOwner? silentAddress;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
late BitcoinAddressType _addressPageType;
|
late BitcoinAddressType _addressPageType;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
BitcoinAddressType get addressPageType => _addressPageType;
|
BitcoinAddressType get addressPageType => _addressPageType;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
String? activeSilentAddress;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
List<BitcoinAddressRecord> get allAddresses => _addresses;
|
List<BitcoinAddressRecord> get allAddresses => _addresses;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@computed
|
@computed
|
||||||
String get address {
|
String get address {
|
||||||
|
if (addressPageType == SilentPaymentsAddresType.p2sp) {
|
||||||
|
if (activeSilentAddress != null) {
|
||||||
|
return activeSilentAddress!;
|
||||||
|
}
|
||||||
|
|
||||||
|
return silentAddress.toString();
|
||||||
|
}
|
||||||
|
|
||||||
String receiveAddress;
|
String receiveAddress;
|
||||||
|
|
||||||
final typeMatchingReceiveAddresses =
|
final typeMatchingReceiveAddresses =
|
||||||
|
@ -104,6 +150,18 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
set address(String addr) {
|
set address(String addr) {
|
||||||
|
if (addressPageType == SilentPaymentsAddresType.p2sp) {
|
||||||
|
final selected = silentAddresses.firstWhere((addressRecord) => addressRecord.address == addr);
|
||||||
|
|
||||||
|
if (selected.silentPaymentTweak != null && silentAddress != null) {
|
||||||
|
activeSilentAddress =
|
||||||
|
silentAddress!.toLabeledSilentPaymentAddress(selected.index).toString();
|
||||||
|
} else {
|
||||||
|
activeSilentAddress = silentAddress!.toString();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final addressRecord = _addresses.firstWhere((addressRecord) => addressRecord.address == addr);
|
final addressRecord = _addresses.firstWhere((addressRecord) => addressRecord.address == addr);
|
||||||
|
|
||||||
previousAddressRecord = addressRecord;
|
previousAddressRecord = addressRecord;
|
||||||
|
@ -130,6 +188,8 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
void set currentChangeAddressIndex(int index) =>
|
void set currentChangeAddressIndex(int index) =>
|
||||||
currentChangeAddressIndexByType[_addressPageType.toString()] = index;
|
currentChangeAddressIndexByType[_addressPageType.toString()] = index;
|
||||||
|
|
||||||
|
int currentSilentAddressIndex;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
BitcoinAddressRecord? previousAddressRecord;
|
BitcoinAddressRecord? previousAddressRecord;
|
||||||
|
|
||||||
|
@ -198,7 +258,50 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
BitcoinAddressRecord generateNewAddress({String label = ''}) {
|
Map<String, String> get labels {
|
||||||
|
final G = ECPublic.fromBytes(BigintUtils.toBytes(Curves.generatorSecp256k1.x, length: 32));
|
||||||
|
final labels = <String, String>{};
|
||||||
|
for (int i = 0; i < silentAddresses.length; i++) {
|
||||||
|
final silentAddressRecord = silentAddresses[i];
|
||||||
|
final silentPaymentTweak = silentAddressRecord.silentPaymentTweak;
|
||||||
|
|
||||||
|
if (silentPaymentTweak != null &&
|
||||||
|
SilentPaymentAddress.regex.hasMatch(silentAddressRecord.address)) {
|
||||||
|
labels[G
|
||||||
|
.tweakMul(BigintUtils.fromBytes(BytesUtils.fromHexString(silentPaymentTweak)))
|
||||||
|
.toHex()] = silentPaymentTweak;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
BaseBitcoinAddressRecord generateNewAddress({String label = ''}) {
|
||||||
|
if (addressPageType == SilentPaymentsAddresType.p2sp && silentAddress != null) {
|
||||||
|
final currentSilentAddressIndex = silentAddresses
|
||||||
|
.where((addressRecord) => addressRecord.type != SegwitAddresType.p2tr)
|
||||||
|
.length -
|
||||||
|
1;
|
||||||
|
|
||||||
|
this.currentSilentAddressIndex = currentSilentAddressIndex;
|
||||||
|
|
||||||
|
final address = BitcoinSilentPaymentAddressRecord(
|
||||||
|
silentAddress!.toLabeledSilentPaymentAddress(currentSilentAddressIndex).toString(),
|
||||||
|
index: currentSilentAddressIndex,
|
||||||
|
isHidden: false,
|
||||||
|
name: label,
|
||||||
|
silentPaymentTweak:
|
||||||
|
BytesUtils.toHexString(silentAddress!.generateLabel(currentSilentAddressIndex)),
|
||||||
|
network: network,
|
||||||
|
type: SilentPaymentsAddresType.p2sp,
|
||||||
|
);
|
||||||
|
|
||||||
|
silentAddresses.add(address);
|
||||||
|
updateAddressesByMatch();
|
||||||
|
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
final newAddressIndex = addressesByReceiveType.fold(
|
final newAddressIndex = addressesByReceiveType.fold(
|
||||||
0, (int acc, addressRecord) => addressRecord.isHidden == false ? acc + 1 : acc);
|
0, (int acc, addressRecord) => addressRecord.isHidden == false ? acc + 1 : acc);
|
||||||
|
|
||||||
|
@ -227,12 +330,70 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
Future<void> updateAddressesInBox() async {
|
Future<void> updateAddressesInBox() async {
|
||||||
try {
|
try {
|
||||||
addressesMap.clear();
|
addressesMap.clear();
|
||||||
addressesMap[address] = '';
|
addressesMap[address] = 'Active';
|
||||||
|
|
||||||
allAddressesMap.clear();
|
allAddressesMap.clear();
|
||||||
_addresses.forEach((addressRecord) {
|
_addresses.forEach((addressRecord) {
|
||||||
allAddressesMap[addressRecord.address] = addressRecord.name;
|
allAddressesMap[addressRecord.address] = addressRecord.name;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final lastP2wpkh = _addresses
|
||||||
|
.where((addressRecord) =>
|
||||||
|
_isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2wpkh))
|
||||||
|
.toList()
|
||||||
|
.last;
|
||||||
|
if (lastP2wpkh.address != address) {
|
||||||
|
addressesMap[lastP2wpkh.address] = 'P2WPKH';
|
||||||
|
} else {
|
||||||
|
addressesMap[address] = 'Active - P2WPKH';
|
||||||
|
}
|
||||||
|
|
||||||
|
final lastP2pkh = _addresses.firstWhere(
|
||||||
|
(addressRecord) => _isUnusedReceiveAddressByType(addressRecord, P2pkhAddressType.p2pkh));
|
||||||
|
if (lastP2pkh.address != address) {
|
||||||
|
addressesMap[lastP2pkh.address] = 'P2PKH';
|
||||||
|
} else {
|
||||||
|
addressesMap[address] = 'Active - P2PKH';
|
||||||
|
}
|
||||||
|
|
||||||
|
final lastP2sh = _addresses.firstWhere((addressRecord) =>
|
||||||
|
_isUnusedReceiveAddressByType(addressRecord, P2shAddressType.p2wpkhInP2sh));
|
||||||
|
if (lastP2sh.address != address) {
|
||||||
|
addressesMap[lastP2sh.address] = 'P2SH';
|
||||||
|
} else {
|
||||||
|
addressesMap[address] = 'Active - P2SH';
|
||||||
|
}
|
||||||
|
|
||||||
|
final lastP2tr = _addresses.firstWhere(
|
||||||
|
(addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2tr));
|
||||||
|
if (lastP2tr.address != address) {
|
||||||
|
addressesMap[lastP2tr.address] = 'P2TR';
|
||||||
|
} else {
|
||||||
|
addressesMap[address] = 'Active - P2TR';
|
||||||
|
}
|
||||||
|
|
||||||
|
final lastP2wsh = _addresses.firstWhere(
|
||||||
|
(addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2wsh));
|
||||||
|
if (lastP2wsh.address != address) {
|
||||||
|
addressesMap[lastP2wsh.address] = 'P2WSH';
|
||||||
|
} else {
|
||||||
|
addressesMap[address] = 'Active - P2WSH';
|
||||||
|
}
|
||||||
|
|
||||||
|
silentAddresses.forEach((addressRecord) {
|
||||||
|
if (addressRecord.type != SilentPaymentsAddresType.p2sp || addressRecord.isHidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addressRecord.address != address) {
|
||||||
|
addressesMap[addressRecord.address] = addressRecord.name.isEmpty
|
||||||
|
? "Silent Payments"
|
||||||
|
: "Silent Payments - " + addressRecord.name;
|
||||||
|
} else {
|
||||||
|
addressesMap[address] = 'Active - Silent Payments';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
await saveAddressesInBox();
|
await saveAddressesInBox();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e.toString());
|
print(e.toString());
|
||||||
|
@ -241,18 +402,41 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void updateAddress(String address, String label) {
|
void updateAddress(String address, String label) {
|
||||||
final addressRecord =
|
BaseBitcoinAddressRecord? foundAddress;
|
||||||
_addresses.firstWhere((addressRecord) => addressRecord.address == address);
|
_addresses.forEach((addressRecord) {
|
||||||
addressRecord.setNewName(label);
|
if (addressRecord.address == address) {
|
||||||
final index = _addresses.indexOf(addressRecord);
|
foundAddress = addressRecord;
|
||||||
_addresses.remove(addressRecord);
|
}
|
||||||
_addresses.insert(index, addressRecord);
|
});
|
||||||
|
silentAddresses.forEach((addressRecord) {
|
||||||
|
if (addressRecord.address == address) {
|
||||||
|
foundAddress = addressRecord;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
updateAddressesByMatch();
|
if (foundAddress != null) {
|
||||||
|
foundAddress!.setNewName(label);
|
||||||
|
|
||||||
|
if (foundAddress is BitcoinAddressRecord) {
|
||||||
|
final index = _addresses.indexOf(foundAddress);
|
||||||
|
_addresses.remove(foundAddress);
|
||||||
|
_addresses.insert(index, foundAddress as BitcoinAddressRecord);
|
||||||
|
} else {
|
||||||
|
final index = silentAddresses.indexOf(foundAddress as BitcoinSilentPaymentAddressRecord);
|
||||||
|
silentAddresses.remove(foundAddress);
|
||||||
|
silentAddresses.insert(index, foundAddress as BitcoinSilentPaymentAddressRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void updateAddressesByMatch() {
|
void updateAddressesByMatch() {
|
||||||
|
if (addressPageType == SilentPaymentsAddresType.p2sp) {
|
||||||
|
addressesByReceiveType.clear();
|
||||||
|
addressesByReceiveType.addAll(silentAddresses);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
addressesByReceiveType.clear();
|
addressesByReceiveType.clear();
|
||||||
addressesByReceiveType.addAll(_addresses.where(_isAddressPageTypeMatch).toList());
|
addressesByReceiveType.addAll(_addresses.where(_isAddressPageTypeMatch).toList());
|
||||||
}
|
}
|
||||||
|
@ -278,7 +462,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> discoverAddresses(List<BitcoinAddressRecord> addressList, bool isHidden,
|
Future<void> discoverAddresses(List<BitcoinAddressRecord> addressList, bool isHidden,
|
||||||
Future<String?> Function(BitcoinAddressRecord, Set<String>) getAddressHistory,
|
Future<String?> Function(BitcoinAddressRecord) getAddressHistory,
|
||||||
{BitcoinAddressType type = SegwitAddresType.p2wpkh}) async {
|
{BitcoinAddressType type = SegwitAddresType.p2wpkh}) async {
|
||||||
if (!isHidden) {
|
if (!isHidden) {
|
||||||
_validateSideHdAddresses(addressList.toList());
|
_validateSideHdAddresses(addressList.toList());
|
||||||
|
@ -288,8 +472,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
startIndex: addressList.length, isHidden: isHidden, type: type);
|
startIndex: addressList.length, isHidden: isHidden, type: type);
|
||||||
addAddresses(newAddresses);
|
addAddresses(newAddresses);
|
||||||
|
|
||||||
final addressesWithHistory = await Future.wait(newAddresses
|
final addressesWithHistory = await Future.wait(newAddresses.map(getAddressHistory));
|
||||||
.map((addr) => getAddressHistory(addr, _addresses.map((e) => e.address).toSet())));
|
|
||||||
final isLastAddressUsed = addressesWithHistory.last == addressList.last.address;
|
final isLastAddressUsed = addressesWithHistory.last == addressList.last.address;
|
||||||
|
|
||||||
if (isLastAddressUsed) {
|
if (isLastAddressUsed) {
|
||||||
|
@ -355,6 +538,15 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
updateAddressesByMatch();
|
updateAddressesByMatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
void addSilentAddresses(Iterable<BitcoinSilentPaymentAddressRecord> addresses) {
|
||||||
|
final addressesSet = this.silentAddresses.toSet();
|
||||||
|
addressesSet.addAll(addresses);
|
||||||
|
this.silentAddresses.clear();
|
||||||
|
this.silentAddresses.addAll(addressesSet);
|
||||||
|
updateAddressesByMatch();
|
||||||
|
}
|
||||||
|
|
||||||
void _validateSideHdAddresses(List<BitcoinAddressRecord> addrWithTransactions) {
|
void _validateSideHdAddresses(List<BitcoinAddressRecord> addrWithTransactions) {
|
||||||
addrWithTransactions.forEach((element) {
|
addrWithTransactions.forEach((element) {
|
||||||
if (element.address !=
|
if (element.address !=
|
||||||
|
@ -377,4 +569,15 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
|
|
||||||
bitcoin.HDWallet _getHd(bool isHidden) => isHidden ? sideHd : mainHd;
|
bitcoin.HDWallet _getHd(bool isHidden) => isHidden ? sideHd : mainHd;
|
||||||
bool _isAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) => addr.type == type;
|
bool _isAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) => addr.type == type;
|
||||||
|
bool _isUnusedReceiveAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) =>
|
||||||
|
!addr.isHidden && !addr.isUsed && addr.type == type;
|
||||||
|
|
||||||
|
@action
|
||||||
|
void deleteSilentPaymentAddress(String address) {
|
||||||
|
final addressRecord = silentAddresses.firstWhere((addressRecord) =>
|
||||||
|
addressRecord.type == SilentPaymentsAddresType.p2sp && addressRecord.address == address);
|
||||||
|
|
||||||
|
silentAddresses.remove(addressRecord);
|
||||||
|
updateAddressesByMatch();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@ class ElectrumWalletSnapshot {
|
||||||
required this.regularAddressIndex,
|
required this.regularAddressIndex,
|
||||||
required this.changeAddressIndex,
|
required this.changeAddressIndex,
|
||||||
required this.addressPageType,
|
required this.addressPageType,
|
||||||
|
required this.silentAddresses,
|
||||||
|
required this.silentAddressIndex,
|
||||||
this.passphrase,
|
this.passphrase,
|
||||||
this.derivationType,
|
this.derivationType,
|
||||||
this.derivationPath,
|
this.derivationPath,
|
||||||
|
@ -32,9 +34,11 @@ class ElectrumWalletSnapshot {
|
||||||
String? mnemonic;
|
String? mnemonic;
|
||||||
String? xpub;
|
String? xpub;
|
||||||
List<BitcoinAddressRecord> addresses;
|
List<BitcoinAddressRecord> addresses;
|
||||||
|
List<BitcoinSilentPaymentAddressRecord> silentAddresses;
|
||||||
ElectrumBalance balance;
|
ElectrumBalance balance;
|
||||||
Map<String, int> regularAddressIndex;
|
Map<String, int> regularAddressIndex;
|
||||||
Map<String, int> changeAddressIndex;
|
Map<String, int> changeAddressIndex;
|
||||||
|
int silentAddressIndex;
|
||||||
String? passphrase;
|
String? passphrase;
|
||||||
DerivationType? derivationType;
|
DerivationType? derivationType;
|
||||||
String? derivationPath;
|
String? derivationPath;
|
||||||
|
@ -50,15 +54,23 @@ class ElectrumWalletSnapshot {
|
||||||
final passphrase = data['passphrase'] as String? ?? '';
|
final passphrase = data['passphrase'] as String? ?? '';
|
||||||
final addresses = addressesTmp
|
final addresses = addressesTmp
|
||||||
.whereType<String>()
|
.whereType<String>()
|
||||||
.map((addr) => BitcoinAddressRecord.fromJSON(addr, network))
|
.map((addr) => BitcoinAddressRecord.fromJSON(addr, network: network))
|
||||||
.toList();
|
.toList();
|
||||||
final balance = ElectrumBalance.fromJSON(data['balance'] as String) ??
|
|
||||||
|
final silentAddressesTmp = data['silent_addresses'] as List? ?? <Object>[];
|
||||||
|
final silentAddresses = silentAddressesTmp
|
||||||
|
.whereType<String>()
|
||||||
|
.map((addr) => BitcoinSilentPaymentAddressRecord.fromJSON(addr, network: network))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
final balance = ElectrumBalance.fromJSON(data['balance'] as String?) ??
|
||||||
ElectrumBalance(confirmed: 0, unconfirmed: 0, frozen: 0);
|
ElectrumBalance(confirmed: 0, unconfirmed: 0, frozen: 0);
|
||||||
var regularAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0};
|
var regularAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0};
|
||||||
var changeAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0};
|
var changeAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0};
|
||||||
|
var silentAddressIndex = 0;
|
||||||
|
|
||||||
final derivationType =
|
final derivationType = DerivationType
|
||||||
DerivationType.values[(data['derivationTypeIndex'] as int?) ?? DerivationType.electrum.index];
|
.values[(data['derivationTypeIndex'] as int?) ?? DerivationType.electrum.index];
|
||||||
final derivationPath = data['derivationPath'] as String? ?? "m/0'/0";
|
final derivationPath = data['derivationPath'] as String? ?? "m/0'/0";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -69,6 +81,7 @@ class ElectrumWalletSnapshot {
|
||||||
SegwitAddresType.p2wpkh.toString():
|
SegwitAddresType.p2wpkh.toString():
|
||||||
int.parse(data['change_address_index'] as String? ?? '0')
|
int.parse(data['change_address_index'] as String? ?? '0')
|
||||||
};
|
};
|
||||||
|
silentAddressIndex = int.parse(data['silent_address_index'] as String? ?? '0');
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
try {
|
try {
|
||||||
regularAddressIndexByType = data["account_index"] as Map<String, int>? ?? {};
|
regularAddressIndexByType = data["account_index"] as Map<String, int>? ?? {};
|
||||||
|
@ -90,6 +103,8 @@ class ElectrumWalletSnapshot {
|
||||||
addressPageType: data['address_page_type'] as String?,
|
addressPageType: data['address_page_type'] as String?,
|
||||||
derivationType: derivationType,
|
derivationType: derivationType,
|
||||||
derivationPath: derivationPath,
|
derivationPath: derivationPath,
|
||||||
|
silentAddresses: silentAddresses,
|
||||||
|
silentAddressIndex: silentAddressIndex,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/exceptions.dart';
|
import 'package:cw_core/exceptions.dart';
|
||||||
|
|
||||||
class BitcoinTransactionWrongBalanceException extends TransactionWrongBalanceException {
|
class BitcoinTransactionWrongBalanceException extends TransactionWrongBalanceException {
|
||||||
BitcoinTransactionWrongBalanceException() : super(CryptoCurrency.btc);
|
BitcoinTransactionWrongBalanceException({super.amount}) : super(CryptoCurrency.btc);
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitcoinTransactionNoInputsException extends TransactionNoInputsException {}
|
class BitcoinTransactionNoInputsException extends TransactionNoInputsException {}
|
||||||
|
@ -27,3 +27,7 @@ class BitcoinTransactionCommitFailedDustOutputSendAll
|
||||||
extends TransactionCommitFailedDustOutputSendAll {}
|
extends TransactionCommitFailedDustOutputSendAll {}
|
||||||
|
|
||||||
class BitcoinTransactionCommitFailedVoutNegative extends TransactionCommitFailedVoutNegative {}
|
class BitcoinTransactionCommitFailedVoutNegative extends TransactionCommitFailedVoutNegative {}
|
||||||
|
|
||||||
|
class BitcoinTransactionCommitFailedBIP68Final extends TransactionCommitFailedBIP68Final {}
|
||||||
|
|
||||||
|
class BitcoinTransactionSilentPaymentsNotSupported extends TransactionInputNotSupported {}
|
||||||
|
|
|
@ -63,7 +63,6 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
currency: CryptoCurrency.ltc) {
|
currency: CryptoCurrency.ltc) {
|
||||||
walletAddresses = LitecoinWalletAddresses(
|
walletAddresses = LitecoinWalletAddresses(
|
||||||
walletInfo,
|
walletInfo,
|
||||||
electrumClient: electrumClient,
|
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
|
|
|
@ -19,7 +19,6 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
||||||
required super.sideHd,
|
required super.sideHd,
|
||||||
required this.mwebHd,
|
required this.mwebHd,
|
||||||
required super.network,
|
required super.network,
|
||||||
required super.electrumClient,
|
|
||||||
super.initialAddresses,
|
super.initialAddresses,
|
||||||
super.initialRegularAddressIndex,
|
super.initialRegularAddressIndex,
|
||||||
super.initialChangeAddressIndex,
|
super.initialChangeAddressIndex,
|
||||||
|
|
|
@ -79,6 +79,11 @@ class PendingBitcoinTransaction with PendingTransaction {
|
||||||
if (error.contains("bad-txns-vout-negative")) {
|
if (error.contains("bad-txns-vout-negative")) {
|
||||||
throw BitcoinTransactionCommitFailedVoutNegative();
|
throw BitcoinTransactionCommitFailedVoutNegative();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error.contains("non-BIP68-final")) {
|
||||||
|
throw BitcoinTransactionCommitFailedBIP68Final();
|
||||||
|
}
|
||||||
|
|
||||||
throw BitcoinTransactionCommitFailed(errorMessage: error);
|
throw BitcoinTransactionCommitFailed(errorMessage: error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,10 +37,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: asn1lib
|
name: asn1lib
|
||||||
sha256: c9c85fedbe2188b95133cbe960e16f5f448860f7133330e272edbbca5893ddc6
|
sha256: "58082b3f0dca697204dbab0ef9ff208bfaea7767ea771076af9a343488428dda"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.2"
|
version: "1.5.3"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -87,11 +87,11 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: cake-mweb
|
ref: cake-update-v3
|
||||||
resolved-ref: "9389210f4c0376ac6f5dfe5aeabc042adc76449c"
|
resolved-ref: cc99eedb1d28ee9376dda0465ef72aa627ac6149
|
||||||
url: "https://github.com/cake-tech/bitcoin_base.git"
|
url: "https://github.com/cake-tech/bitcoin_base"
|
||||||
source: git
|
source: git
|
||||||
version: "4.2.0"
|
version: "4.2.1"
|
||||||
bitcoin_flutter:
|
bitcoin_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -104,11 +104,12 @@ packages:
|
||||||
blockchain_utils:
|
blockchain_utils:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: blockchain_utils
|
path: "."
|
||||||
sha256: "38ef5f4a22441ac4370aed9071dc71c460acffc37c79b344533f67d15f24c13c"
|
ref: cake-update-v1
|
||||||
url: "https://pub.dev"
|
resolved-ref: cabd7e0e16c4da9920338c76eff3aeb8af0211f3
|
||||||
source: hosted
|
url: "https://github.com/cake-tech/blockchain_utils"
|
||||||
version: "2.1.1"
|
source: git
|
||||||
|
version: "2.1.2"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -205,6 +206,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.3"
|
version: "2.0.3"
|
||||||
|
cli_util:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cli_util
|
||||||
|
sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.4.1"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -249,10 +258,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: cryptography
|
name: cryptography
|
||||||
sha256: df156c5109286340817d21fa7b62f9140f17915077127dd70f8bd7a2a0997a35
|
sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.0"
|
version: "2.7.0"
|
||||||
cw_core:
|
cw_core:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -303,10 +312,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: ffi
|
name: ffi
|
||||||
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
|
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.2"
|
||||||
|
ffigen:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: ffigen
|
||||||
|
sha256: d3e76c2ad48a4e7f93a29a162006f00eba46ce7c08194a77bb5c5e97d1b5ff0a
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.0.2"
|
||||||
file:
|
file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -361,10 +378,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: functional_data
|
name: functional_data
|
||||||
sha256: aefdec4365452283b2a7cf420a3169654d51d3e9553069a22d76680d7a9d7c3d
|
sha256: "76d17dc707c40e552014f5a49c0afcc3f1e3f05e800cd6b7872940bfe41a5039"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.2.0"
|
||||||
glob:
|
glob:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -425,18 +442,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.2.1"
|
||||||
http2:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: http2
|
|
||||||
sha256: "9ced024a160b77aba8fb8674e38f70875e321d319e6f303ec18e87bd5a4b0c1d"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.3.0"
|
|
||||||
http_multi_server:
|
http_multi_server:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -481,10 +490,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: json_annotation
|
name: json_annotation
|
||||||
sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
|
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.8.1"
|
version: "4.9.0"
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -570,10 +579,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: mime
|
name: mime
|
||||||
sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
|
sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.5"
|
||||||
mobx:
|
mobx:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -618,26 +627,26 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path_provider
|
name: path_provider
|
||||||
sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b
|
sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.3"
|
||||||
path_provider_android:
|
path_provider_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_android
|
name: path_provider_android
|
||||||
sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668"
|
sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.2"
|
version: "2.2.4"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_foundation
|
name: path_provider_foundation
|
||||||
sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
|
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.2"
|
version: "2.4.0"
|
||||||
path_provider_linux:
|
path_provider_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -682,10 +691,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pointycastle
|
name: pointycastle
|
||||||
sha256: "70fe966348fe08c34bf929582f1d8247d9d9408130723206472b4687227e4333"
|
sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.8.0"
|
version: "3.9.1"
|
||||||
pool:
|
pool:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -726,6 +735,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.3"
|
version: "1.2.3"
|
||||||
|
quiver:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: quiver
|
||||||
|
sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.1"
|
||||||
reactive_ble_mobile:
|
reactive_ble_mobile:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -775,10 +792,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: socks5_proxy
|
name: socks5_proxy
|
||||||
sha256: "1d21b5606169654bbf4cfb904e8e6ed897e9f763358709f87310c757096d909a"
|
sha256: "045cbba84f6e2b01c1c77634a63e926352bf110ef5f07fc462c6d43bbd4b6a83"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.5+dev.2"
|
||||||
source_gen:
|
source_gen:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -803,6 +820,15 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.0"
|
version: "1.10.0"
|
||||||
|
sp_scanner:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: "sp_v1.0.0"
|
||||||
|
resolved-ref: a9a4c6d051f37a15a3a52cc2a0094f24c68b62c5
|
||||||
|
url: "https://github.com/cake-tech/sp_scanner"
|
||||||
|
source: git
|
||||||
|
version: "0.0.1"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -899,22 +925,30 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.0"
|
||||||
|
web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web
|
||||||
|
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.5.1"
|
||||||
web_socket_channel:
|
web_socket_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web_socket_channel
|
name: web_socket_channel
|
||||||
sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
|
sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.0"
|
version: "2.4.5"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3"
|
sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.9"
|
version: "5.5.0"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -931,6 +965,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
|
yaml_edit:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: yaml_edit
|
||||||
|
sha256: e9c1a3543d2da0db3e90270dbb1e4eebc985ee5e3ffe468d83224472b2194a5f
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.2.0-0 <4.0.0"
|
dart: ">=3.3.0 <4.0.0"
|
||||||
flutter: ">=3.10.0"
|
flutter: ">=3.16.6"
|
||||||
|
|
|
@ -32,9 +32,12 @@ dependencies:
|
||||||
cryptography: ^2.0.5
|
cryptography: ^2.0.5
|
||||||
bitcoin_base:
|
bitcoin_base:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitcoin_base.git
|
url: https://github.com/cake-tech/bitcoin_base
|
||||||
ref: cake-mweb
|
ref: cake-mweb
|
||||||
blockchain_utils: ^2.1.1
|
blockchain_utils:
|
||||||
|
git:
|
||||||
|
url: https://github.com/cake-tech/blockchain_utils
|
||||||
|
ref: cake-update-v1
|
||||||
ledger_flutter: ^1.0.1
|
ledger_flutter: ^1.0.1
|
||||||
ledger_bitcoin:
|
ledger_bitcoin:
|
||||||
git:
|
git:
|
||||||
|
@ -42,6 +45,10 @@ dependencies:
|
||||||
cw_mweb:
|
cw_mweb:
|
||||||
path: ../cw_mweb
|
path: ../cw_mweb
|
||||||
grpc: ^3.2.4
|
grpc: ^3.2.4
|
||||||
|
sp_scanner:
|
||||||
|
git:
|
||||||
|
url: https://github.com/cake-tech/sp_scanner
|
||||||
|
ref: sp_v2.0.0
|
||||||
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
|
|
@ -46,7 +46,6 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
currency: CryptoCurrency.bch) {
|
currency: CryptoCurrency.bch) {
|
||||||
walletAddresses = BitcoinCashWalletAddresses(
|
walletAddresses = BitcoinCashWalletAddresses(
|
||||||
walletInfo,
|
walletInfo,
|
||||||
electrumClient: electrumClient,
|
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
|
|
|
@ -15,7 +15,6 @@ abstract class BitcoinCashWalletAddressesBase extends ElectrumWalletAddresses wi
|
||||||
required super.mainHd,
|
required super.mainHd,
|
||||||
required super.sideHd,
|
required super.sideHd,
|
||||||
required super.network,
|
required super.network,
|
||||||
required super.electrumClient,
|
|
||||||
super.initialAddresses,
|
super.initialAddresses,
|
||||||
super.initialRegularAddressIndex,
|
super.initialRegularAddressIndex,
|
||||||
super.initialChangeAddressIndex,
|
super.initialChangeAddressIndex,
|
||||||
|
|
|
@ -31,10 +31,12 @@ dependencies:
|
||||||
ref: Add-Support-For-OP-Return-data
|
ref: Add-Support-For-OP-Return-data
|
||||||
bitcoin_base:
|
bitcoin_base:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitcoin_base.git
|
url: https://github.com/cake-tech/bitcoin_base
|
||||||
ref: cake-mweb
|
ref: cake-mweb
|
||||||
|
blockchain_utils:
|
||||||
|
git:
|
||||||
|
url: https://github.com/cake-tech/blockchain_utils
|
||||||
|
ref: cake-update-v1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
@ -104,6 +104,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
||||||
CryptoCurrency.digibyte,
|
CryptoCurrency.digibyte,
|
||||||
CryptoCurrency.usdtSol,
|
CryptoCurrency.usdtSol,
|
||||||
CryptoCurrency.usdcTrc20,
|
CryptoCurrency.usdcTrc20,
|
||||||
|
CryptoCurrency.tbtc,
|
||||||
];
|
];
|
||||||
|
|
||||||
static const havenCurrencies = [
|
static const havenCurrencies = [
|
||||||
|
@ -218,7 +219,8 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
||||||
static const kaspa = CryptoCurrency(title: 'KAS', fullName: 'Kaspa', raw: 89, name: 'kas', iconPath: 'assets/images/kaspa_icon.png', decimals: 8);
|
static const kaspa = CryptoCurrency(title: 'KAS', fullName: 'Kaspa', raw: 89, name: 'kas', iconPath: 'assets/images/kaspa_icon.png', decimals: 8);
|
||||||
static const digibyte = CryptoCurrency(title: 'DGB', fullName: 'DigiByte', raw: 90, name: 'dgb', iconPath: 'assets/images/digibyte.png', decimals: 8);
|
static const digibyte = CryptoCurrency(title: 'DGB', fullName: 'DigiByte', raw: 90, name: 'dgb', iconPath: 'assets/images/digibyte.png', decimals: 8);
|
||||||
static const usdtSol = CryptoCurrency(title: 'USDT', tag: 'SOL', fullName: 'USDT Tether', raw: 91, name: 'usdtsol', iconPath: 'assets/images/usdt_icon.png', decimals: 6);
|
static const usdtSol = CryptoCurrency(title: 'USDT', tag: 'SOL', fullName: 'USDT Tether', raw: 91, name: 'usdtsol', iconPath: 'assets/images/usdt_icon.png', decimals: 6);
|
||||||
static const usdcTrc20 = CryptoCurrency(title: 'USDC', tag: 'TRX', fullName: 'USDC Coin', raw: 92, name: 'usdctrc20', iconPath: 'assets/images/usdc_icon.png', decimals: 6);
|
static const usdcTrc20 = CryptoCurrency(title: 'USDC', tag: 'TRX', fullName: 'USDC Coin', raw: 92, name: 'usdctrc20', iconPath: 'assets/images/usdc_icon.png', decimals: 6);
|
||||||
|
static const tbtc = CryptoCurrency(title: 'tBTC', fullName: 'Testnet Bitcoin', raw: 93, name: 'tbtc', iconPath: 'assets/images/tbtc.png', decimals: 8);
|
||||||
|
|
||||||
|
|
||||||
static final Map<int, CryptoCurrency> _rawCurrencyMap =
|
static final Map<int, CryptoCurrency> _rawCurrencyMap =
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
|
||||||
CryptoCurrency currencyForWalletType(WalletType type) {
|
CryptoCurrency currencyForWalletType(WalletType type, {bool? isTestnet}) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
|
if (isTestnet == true) {
|
||||||
|
return CryptoCurrency.tbtc;
|
||||||
|
}
|
||||||
return CryptoCurrency.btc;
|
return CryptoCurrency.btc;
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
return CryptoCurrency.xmr;
|
return CryptoCurrency.xmr;
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
|
||||||
class TransactionWrongBalanceException implements Exception {
|
class TransactionWrongBalanceException implements Exception {
|
||||||
TransactionWrongBalanceException(this.currency);
|
TransactionWrongBalanceException(this.currency, {this.amount});
|
||||||
|
|
||||||
final CryptoCurrency currency;
|
final CryptoCurrency currency;
|
||||||
|
final int? amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
class TransactionNoInputsException implements Exception {}
|
class TransactionNoInputsException implements Exception {}
|
||||||
|
@ -32,3 +33,7 @@ class TransactionCommitFailedDustOutput implements Exception {}
|
||||||
class TransactionCommitFailedDustOutputSendAll implements Exception {}
|
class TransactionCommitFailedDustOutputSendAll implements Exception {}
|
||||||
|
|
||||||
class TransactionCommitFailedVoutNegative implements Exception {}
|
class TransactionCommitFailedVoutNegative implements Exception {}
|
||||||
|
|
||||||
|
class TransactionCommitFailedBIP68Final implements Exception {}
|
||||||
|
|
||||||
|
class TransactionInputNotSupported implements Exception {}
|
||||||
|
|
|
@ -242,3 +242,57 @@ Future<int> getHavenCurrentHeight() async {
|
||||||
throw Exception('Failed to load current blockchain height');
|
throw Exception('Failed to load current blockchain height');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Data taken from https://timechaincalendar.com/
|
||||||
|
const bitcoinDates = {
|
||||||
|
"2024-05": 841590,
|
||||||
|
"2024-04": 837182,
|
||||||
|
"2024-03": 832623,
|
||||||
|
"2024-02": 828319,
|
||||||
|
"2024-01": 823807,
|
||||||
|
"2023-12": 819206,
|
||||||
|
"2023-11": 814765,
|
||||||
|
"2023-10": 810098,
|
||||||
|
"2023-09": 805675,
|
||||||
|
"2023-08": 801140,
|
||||||
|
"2023-07": 796640,
|
||||||
|
"2023-06": 792330,
|
||||||
|
"2023-05": 787733,
|
||||||
|
"2023-04": 783403,
|
||||||
|
"2023-03": 778740,
|
||||||
|
"2023-02": 774525,
|
||||||
|
"2023-01": 769810,
|
||||||
|
};
|
||||||
|
|
||||||
|
int getBitcoinHeightByDate({required DateTime date}) {
|
||||||
|
String dateKey = '${date.year}-${date.month.toString().padLeft(2, '0')}';
|
||||||
|
final closestKey = bitcoinDates.keys
|
||||||
|
.firstWhere((key) => formatMapKey(key).isBefore(date), orElse: () => bitcoinDates.keys.last);
|
||||||
|
final beginningBlock = bitcoinDates[dateKey] ?? bitcoinDates[closestKey]!;
|
||||||
|
|
||||||
|
final startOfMonth = DateTime(date.year, date.month);
|
||||||
|
final daysDifference = date.difference(startOfMonth).inDays;
|
||||||
|
|
||||||
|
// approximately 6 blocks per hour, 24 hours per day
|
||||||
|
int estimatedBlocksSinceStartOfMonth = (daysDifference * 24 * 6);
|
||||||
|
|
||||||
|
return beginningBlock + estimatedBlocksSinceStartOfMonth;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime getDateByBitcoinHeight(int height) {
|
||||||
|
final closestEntry = bitcoinDates.entries
|
||||||
|
.lastWhere((entry) => entry.value >= height, orElse: () => bitcoinDates.entries.first);
|
||||||
|
final beginningBlock = closestEntry.value;
|
||||||
|
|
||||||
|
final startOfMonth = formatMapKey(closestEntry.key);
|
||||||
|
final blocksDifference = height - beginningBlock;
|
||||||
|
final hoursDifference = blocksDifference / 5.5;
|
||||||
|
|
||||||
|
final estimatedDate = startOfMonth.add(Duration(hours: hoursDifference.ceil()));
|
||||||
|
|
||||||
|
if (estimatedDate.isAfter(DateTime.now())) {
|
||||||
|
return DateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
return estimatedDate;
|
||||||
|
}
|
||||||
|
|
|
@ -244,8 +244,12 @@ class Node extends HiveObject with Keyable {
|
||||||
|
|
||||||
Future<bool> requestElectrumServer() async {
|
Future<bool> requestElectrumServer() async {
|
||||||
try {
|
try {
|
||||||
await SecureSocket.connect(uri.host, uri.port,
|
if (useSSL == true) {
|
||||||
timeout: Duration(seconds: 5), onBadCertificate: (_) => true);
|
await SecureSocket.connect(uri.host, uri.port,
|
||||||
|
timeout: Duration(seconds: 5), onBadCertificate: (_) => true);
|
||||||
|
} else {
|
||||||
|
await Socket.connect(uri.host, uri.port, timeout: Duration(seconds: 5));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -14,6 +14,16 @@ class SyncingSyncStatus extends SyncStatus {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => '$blocksLeft';
|
String toString() => '$blocksLeft';
|
||||||
|
|
||||||
|
factory SyncingSyncStatus.fromHeightValues(int chainTip, int initialSyncHeight, int syncHeight) {
|
||||||
|
final track = chainTip - initialSyncHeight;
|
||||||
|
final diff = track - (chainTip - syncHeight);
|
||||||
|
final ptc = diff <= 0 ? 0.0 : diff / track;
|
||||||
|
final left = chainTip - syncHeight;
|
||||||
|
|
||||||
|
// sum 1 because if at the chain tip, will say "0 blocks left"
|
||||||
|
return SyncingSyncStatus(left + 1, ptc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SyncedSyncStatus extends SyncStatus {
|
class SyncedSyncStatus extends SyncStatus {
|
||||||
|
@ -21,6 +31,17 @@ class SyncedSyncStatus extends SyncStatus {
|
||||||
double progress() => 1.0;
|
double progress() => 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SyncedTipSyncStatus extends SyncedSyncStatus {
|
||||||
|
SyncedTipSyncStatus(this.tip);
|
||||||
|
|
||||||
|
final int tip;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SyncronizingSyncStatus extends SyncStatus {
|
||||||
|
@override
|
||||||
|
double progress() => 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
class NotConnectedSyncStatus extends SyncStatus {
|
class NotConnectedSyncStatus extends SyncStatus {
|
||||||
const NotConnectedSyncStatus();
|
const NotConnectedSyncStatus();
|
||||||
|
|
||||||
|
@ -33,10 +54,7 @@ class AttemptingSyncStatus extends SyncStatus {
|
||||||
double progress() => 0.0;
|
double progress() => 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
class FailedSyncStatus extends SyncStatus {
|
class FailedSyncStatus extends NotConnectedSyncStatus {}
|
||||||
@override
|
|
||||||
double progress() => 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConnectingSyncStatus extends SyncStatus {
|
class ConnectingSyncStatus extends SyncStatus {
|
||||||
@override
|
@override
|
||||||
|
@ -48,7 +66,14 @@ class ConnectedSyncStatus extends SyncStatus {
|
||||||
double progress() => 0.0;
|
double progress() => 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
class LostConnectionSyncStatus extends SyncStatus {
|
class UnsupportedSyncStatus extends NotConnectedSyncStatus {}
|
||||||
|
|
||||||
|
class TimedOutSyncStatus extends NotConnectedSyncStatus {
|
||||||
@override
|
@override
|
||||||
double progress() => 1.0;
|
String toString() => 'Timed out';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LostConnectionSyncStatus extends NotConnectedSyncStatus {
|
||||||
|
@override
|
||||||
|
String toString() => 'Reconnecting';
|
||||||
|
}
|
||||||
|
|
|
@ -16,7 +16,8 @@ class UnspentCoinsInfo extends HiveObject {
|
||||||
required this.value,
|
required this.value,
|
||||||
this.keyImage = null,
|
this.keyImage = null,
|
||||||
this.isChange = false,
|
this.isChange = false,
|
||||||
this.accountIndex = 0
|
this.accountIndex = 0,
|
||||||
|
this.isSilentPayment = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
static const typeId = UNSPENT_COINS_INFO_TYPE_ID;
|
static const typeId = UNSPENT_COINS_INFO_TYPE_ID;
|
||||||
|
@ -49,13 +50,16 @@ class UnspentCoinsInfo extends HiveObject {
|
||||||
|
|
||||||
@HiveField(8, defaultValue: null)
|
@HiveField(8, defaultValue: null)
|
||||||
String? keyImage;
|
String? keyImage;
|
||||||
|
|
||||||
@HiveField(9, defaultValue: false)
|
@HiveField(9, defaultValue: false)
|
||||||
bool isChange;
|
bool isChange;
|
||||||
|
|
||||||
@HiveField(10, defaultValue: 0)
|
@HiveField(10, defaultValue: 0)
|
||||||
int accountIndex;
|
int accountIndex;
|
||||||
|
|
||||||
|
@HiveField(11, defaultValue: false)
|
||||||
|
bool? isSilentPayment;
|
||||||
|
|
||||||
String get note => noteRaw ?? '';
|
String get note => noteRaw ?? '';
|
||||||
|
|
||||||
set note(String value) => noteRaw = value;
|
set note(String value) => noteRaw = value;
|
||||||
|
|
|
@ -17,5 +17,6 @@ class Unspent {
|
||||||
int? confirmations;
|
int? confirmations;
|
||||||
String note;
|
String note;
|
||||||
|
|
||||||
bool get isP2wpkh => address.startsWith('bc') || address.startsWith('ltc');
|
bool get isP2wpkh =>
|
||||||
|
address.startsWith('bc') || address.startsWith('tb') || address.startsWith('ltc');
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
|
||||||
|
|
||||||
WalletType get type => walletInfo.type;
|
WalletType get type => walletInfo.type;
|
||||||
|
|
||||||
CryptoCurrency get currency => currencyForWalletType(type);
|
CryptoCurrency get currency => currencyForWalletType(type, isTestnet: isTestnet);
|
||||||
|
|
||||||
String get id => walletInfo.id;
|
String get id => walletInfo.id;
|
||||||
|
|
||||||
|
|
|
@ -66,21 +66,21 @@ class DerivationInfo extends HiveObject {
|
||||||
@HiveType(typeId: WalletInfo.typeId)
|
@HiveType(typeId: WalletInfo.typeId)
|
||||||
class WalletInfo extends HiveObject {
|
class WalletInfo extends HiveObject {
|
||||||
WalletInfo(
|
WalletInfo(
|
||||||
this.id,
|
this.id,
|
||||||
this.name,
|
this.name,
|
||||||
this.type,
|
this.type,
|
||||||
this.isRecovery,
|
this.isRecovery,
|
||||||
this.restoreHeight,
|
this.restoreHeight,
|
||||||
this.timestamp,
|
this.timestamp,
|
||||||
this.dirPath,
|
this.dirPath,
|
||||||
this.path,
|
this.path,
|
||||||
this.address,
|
this.address,
|
||||||
this.yatEid,
|
this.yatEid,
|
||||||
this.yatLastUsedAddressRaw,
|
this.yatLastUsedAddressRaw,
|
||||||
this.showIntroCakePayCard,
|
this.showIntroCakePayCard,
|
||||||
this.derivationInfo,
|
this.derivationInfo,
|
||||||
this.hardwareWalletType,
|
this.hardwareWalletType,
|
||||||
): _yatLastUsedAddressController = StreamController<String>.broadcast();
|
) : _yatLastUsedAddressController = StreamController<String>.broadcast();
|
||||||
|
|
||||||
factory WalletInfo.external({
|
factory WalletInfo.external({
|
||||||
required String id,
|
required String id,
|
||||||
|
@ -207,4 +207,9 @@ class WalletInfo extends HiveObject {
|
||||||
Stream<String> get yatLastUsedAddressStream => _yatLastUsedAddressController.stream;
|
Stream<String> get yatLastUsedAddressStream => _yatLastUsedAddressController.stream;
|
||||||
|
|
||||||
StreamController<String> _yatLastUsedAddressController;
|
StreamController<String> _yatLastUsedAddressController;
|
||||||
|
|
||||||
|
Future<void> updateRestoreHeight(int height) async {
|
||||||
|
restoreHeight = height;
|
||||||
|
await save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,11 +173,14 @@ String walletTypeToDisplayName(WalletType type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CryptoCurrency walletTypeToCryptoCurrency(WalletType type) {
|
CryptoCurrency walletTypeToCryptoCurrency(WalletType type, {bool isTestnet = false}) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
return CryptoCurrency.xmr;
|
return CryptoCurrency.xmr;
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
|
if (isTestnet) {
|
||||||
|
return CryptoCurrency.tbtc;
|
||||||
|
}
|
||||||
return CryptoCurrency.btc;
|
return CryptoCurrency.btc;
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
return CryptoCurrency.ltc;
|
return CryptoCurrency.ltc;
|
||||||
|
|
|
@ -1,147 +0,0 @@
|
||||||
# Generated by pub
|
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
|
||||||
packages:
|
|
||||||
async:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: async
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.5.0"
|
|
||||||
boolean_selector:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: boolean_selector
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.0"
|
|
||||||
characters:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: characters
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.0"
|
|
||||||
charcode:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: charcode
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.0"
|
|
||||||
clock:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: clock
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.0"
|
|
||||||
collection:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: collection
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.15.0"
|
|
||||||
fake_async:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: fake_async
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.0"
|
|
||||||
flutter:
|
|
||||||
dependency: "direct main"
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.0"
|
|
||||||
flutter_test:
|
|
||||||
dependency: "direct dev"
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.0"
|
|
||||||
matcher:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: matcher
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.12.10"
|
|
||||||
meta:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: meta
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.3.0"
|
|
||||||
path:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.8.0"
|
|
||||||
sky_engine:
|
|
||||||
dependency: transitive
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.99"
|
|
||||||
source_span:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: source_span
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.8.0"
|
|
||||||
stack_trace:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: stack_trace
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.10.0"
|
|
||||||
stream_channel:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: stream_channel
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.0"
|
|
||||||
string_scanner:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: string_scanner
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.0"
|
|
||||||
term_glyph:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: term_glyph
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.0"
|
|
||||||
test_api:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: test_api
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.2.19"
|
|
||||||
typed_data:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: typed_data
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.3.0"
|
|
||||||
vector_math:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: vector_math
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.0"
|
|
||||||
sdks:
|
|
||||||
dart: ">=2.12.0-0.0 <3.0.0"
|
|
||||||
flutter: ">=1.20.0"
|
|
|
@ -15,8 +15,14 @@ dependencies:
|
||||||
path: ../cw_core
|
path: ../cw_core
|
||||||
cw_evm:
|
cw_evm:
|
||||||
path: ../cw_evm
|
path: ../cw_evm
|
||||||
on_chain: ^3.0.1
|
on_chain:
|
||||||
blockchain_utils: ^2.1.1
|
git:
|
||||||
|
url: https://github.com/cake-tech/On_chain
|
||||||
|
ref: cake-update-v1
|
||||||
|
blockchain_utils:
|
||||||
|
git:
|
||||||
|
url: https://github.com/cake-tech/blockchain_utils
|
||||||
|
ref: cake-update-v1
|
||||||
mobx: ^2.3.0+1
|
mobx: ^2.3.0+1
|
||||||
bip39: ^1.0.6
|
bip39: ^1.0.6
|
||||||
hive: ^2.2.3
|
hive: ^2.2.3
|
||||||
|
|
|
@ -142,27 +142,9 @@ Then we need to generate localization files.
|
||||||
|
|
||||||
`$ flutter packages pub run tool/generate_localization.dart`
|
`$ flutter packages pub run tool/generate_localization.dart`
|
||||||
|
|
||||||
Lastly, we will generate mobx models for the project.
|
|
||||||
|
|
||||||
Generate mobx models for `cw_core`:
|
|
||||||
|
|
||||||
`cd cw_core && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..`
|
|
||||||
|
|
||||||
Generate mobx models for `cw_monero`:
|
|
||||||
|
|
||||||
`cd cw_monero && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..`
|
|
||||||
|
|
||||||
Generate mobx models for `cw_bitcoin`:
|
|
||||||
|
|
||||||
`cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..`
|
|
||||||
|
|
||||||
Generate mobx models for `cw_haven`:
|
|
||||||
|
|
||||||
`cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..`
|
|
||||||
|
|
||||||
Finally build mobx models for the app:
|
Finally build mobx models for the app:
|
||||||
|
|
||||||
`$ flutter packages pub run build_runner build --delete-conflicting-outputs`
|
`$ ./model_generator.sh`
|
||||||
|
|
||||||
### 9. Build!
|
### 9. Build!
|
||||||
|
|
||||||
|
|
|
@ -147,6 +147,8 @@ PODS:
|
||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- sp_scanner (0.0.1):
|
||||||
|
- Flutter
|
||||||
- SwiftProtobuf (1.25.2)
|
- SwiftProtobuf (1.25.2)
|
||||||
- SwiftyGif (5.4.4)
|
- SwiftyGif (5.4.4)
|
||||||
- Toast (4.1.0)
|
- Toast (4.1.0)
|
||||||
|
@ -188,6 +190,7 @@ DEPENDENCIES:
|
||||||
- sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`)
|
- sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`)
|
||||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
|
- sp_scanner (from `.symlinks/plugins/sp_scanner/ios`)
|
||||||
- uni_links (from `.symlinks/plugins/uni_links/ios`)
|
- uni_links (from `.symlinks/plugins/uni_links/ios`)
|
||||||
- UnstoppableDomainsResolution (~> 4.0.0)
|
- UnstoppableDomainsResolution (~> 4.0.0)
|
||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
|
@ -259,6 +262,8 @@ EXTERNAL SOURCES:
|
||||||
:path: ".symlinks/plugins/share_plus/ios"
|
:path: ".symlinks/plugins/share_plus/ios"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||||
|
sp_scanner:
|
||||||
|
:path: ".symlinks/plugins/sp_scanner/ios"
|
||||||
uni_links:
|
uni_links:
|
||||||
:path: ".symlinks/plugins/uni_links/ios"
|
:path: ".symlinks/plugins/uni_links/ios"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
|
@ -302,6 +307,7 @@ SPEC CHECKSUMS:
|
||||||
sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
|
sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
|
||||||
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
|
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
|
||||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||||
|
sp_scanner: eaa617fa827396b967116b7f1f43549ca62e9a12
|
||||||
SwiftProtobuf: 407a385e97fd206c4fbe880cc84123989167e0d1
|
SwiftProtobuf: 407a385e97fd206c4fbe880cc84123989167e0d1
|
||||||
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
|
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
|
||||||
Toast: ec33c32b8688982cecc6348adeae667c1b9938da
|
Toast: ec33c32b8688982cecc6348adeae667c1b9938da
|
||||||
|
|
|
@ -121,20 +121,12 @@ class CWBitcoin extends Bitcoin {
|
||||||
priority: priority != null ? priority as BitcoinTransactionPriority : null,
|
priority: priority != null ? priority as BitcoinTransactionPriority : null,
|
||||||
feeRate: feeRate);
|
feeRate: feeRate);
|
||||||
|
|
||||||
@override
|
|
||||||
List<String> getAddresses(Object wallet) {
|
|
||||||
final bitcoinWallet = wallet as ElectrumWallet;
|
|
||||||
return bitcoinWallet.walletAddresses.addressesByReceiveType
|
|
||||||
.map((BitcoinAddressRecord addr) => addr.address)
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@computed
|
@computed
|
||||||
List<ElectrumSubAddress> getSubAddresses(Object wallet) {
|
List<ElectrumSubAddress> getSubAddresses(Object wallet) {
|
||||||
final electrumWallet = wallet as ElectrumWallet;
|
final electrumWallet = wallet as ElectrumWallet;
|
||||||
return electrumWallet.walletAddresses.addressesByReceiveType
|
return electrumWallet.walletAddresses.addressesByReceiveType
|
||||||
.map((BitcoinAddressRecord addr) => ElectrumSubAddress(
|
.map((BaseBitcoinAddressRecord addr) => ElectrumSubAddress(
|
||||||
id: addr.index,
|
id: addr.index,
|
||||||
name: addr.name,
|
name: addr.name,
|
||||||
address: addr.address,
|
address: addr.address,
|
||||||
|
@ -207,12 +199,12 @@ class CWBitcoin extends Bitcoin {
|
||||||
|
|
||||||
Future<void> updateUnspents(Object wallet) async {
|
Future<void> updateUnspents(Object wallet) async {
|
||||||
final bitcoinWallet = wallet as ElectrumWallet;
|
final bitcoinWallet = wallet as ElectrumWallet;
|
||||||
await bitcoinWallet.updateUnspent();
|
await bitcoinWallet.updateAllUnspents();
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletService createBitcoinWalletService(
|
WalletService createBitcoinWalletService(
|
||||||
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
|
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool alwaysScan) {
|
||||||
return BitcoinWalletService(walletInfoSource, unspentCoinSource);
|
return BitcoinWalletService(walletInfoSource, unspentCoinSource, alwaysScan);
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletService createLitecoinWalletService(
|
WalletService createLitecoinWalletService(
|
||||||
|
@ -247,6 +239,12 @@ class CWBitcoin extends Bitcoin {
|
||||||
return BitcoinReceivePageOption.fromType(bitcoinWallet.walletAddresses.addressPageType);
|
return BitcoinReceivePageOption.fromType(bitcoinWallet.walletAddresses.addressPageType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool hasSelectedSilentPayments(Object wallet) {
|
||||||
|
final bitcoinWallet = wallet as ElectrumWallet;
|
||||||
|
return bitcoinWallet.walletAddresses.addressPageType == SilentPaymentsAddresType.p2sp;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<ReceivePageOption> getBitcoinReceivePageOptions() => BitcoinReceivePageOption.all;
|
List<ReceivePageOption> getBitcoinReceivePageOptions() => BitcoinReceivePageOption.all;
|
||||||
|
|
||||||
|
@ -467,4 +465,137 @@ class CWBitcoin extends Bitcoin {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<ElectrumSubAddress> getSilentPaymentAddresses(Object wallet) {
|
||||||
|
final bitcoinWallet = wallet as ElectrumWallet;
|
||||||
|
return bitcoinWallet.walletAddresses.silentAddresses
|
||||||
|
.where((addr) => addr.type != SegwitAddresType.p2tr)
|
||||||
|
.map((addr) => ElectrumSubAddress(
|
||||||
|
id: addr.index,
|
||||||
|
name: addr.name,
|
||||||
|
address: addr.address,
|
||||||
|
txCount: addr.txCount,
|
||||||
|
balance: addr.balance,
|
||||||
|
isChange: addr.isHidden))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<ElectrumSubAddress> getSilentPaymentReceivedAddresses(Object wallet) {
|
||||||
|
final bitcoinWallet = wallet as ElectrumWallet;
|
||||||
|
return bitcoinWallet.walletAddresses.silentAddresses
|
||||||
|
.where((addr) => addr.type == SegwitAddresType.p2tr)
|
||||||
|
.map((addr) => ElectrumSubAddress(
|
||||||
|
id: addr.index,
|
||||||
|
name: addr.name,
|
||||||
|
address: addr.address,
|
||||||
|
txCount: addr.txCount,
|
||||||
|
balance: addr.balance,
|
||||||
|
isChange: addr.isHidden))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool isBitcoinReceivePageOption(ReceivePageOption option) {
|
||||||
|
return option is BitcoinReceivePageOption;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
BitcoinAddressType getOptionToType(ReceivePageOption option) {
|
||||||
|
return (option as BitcoinReceivePageOption).toType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@computed
|
||||||
|
bool getScanningActive(Object wallet) {
|
||||||
|
final bitcoinWallet = wallet as ElectrumWallet;
|
||||||
|
return bitcoinWallet.silentPaymentsScanningActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> setScanningActive(Object wallet, bool active) async {
|
||||||
|
final bitcoinWallet = wallet as ElectrumWallet;
|
||||||
|
|
||||||
|
if (active && !(await getNodeIsElectrsSPEnabled(wallet))) {
|
||||||
|
final node = Node(
|
||||||
|
useSSL: false,
|
||||||
|
uri: 'electrs.cakewallet.com:${(wallet.network == BitcoinNetwork.testnet ? 50002 : 50001)}',
|
||||||
|
);
|
||||||
|
node.type = WalletType.bitcoin;
|
||||||
|
|
||||||
|
await bitcoinWallet.connectToNode(node: node);
|
||||||
|
}
|
||||||
|
|
||||||
|
bitcoinWallet.setSilentPaymentsScanning(active);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool isTestnet(Object wallet) {
|
||||||
|
final bitcoinWallet = wallet as ElectrumWallet;
|
||||||
|
return bitcoinWallet.isTestnet ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int getHeightByDate({required DateTime date}) => getBitcoinHeightByDate(date: date);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> rescan(Object wallet, {required int height, bool? doSingleScan}) async {
|
||||||
|
final bitcoinWallet = wallet as ElectrumWallet;
|
||||||
|
if (!(await getNodeIsElectrsSPEnabled(wallet))) {
|
||||||
|
final node = Node(
|
||||||
|
useSSL: false,
|
||||||
|
uri: 'electrs.cakewallet.com:${(wallet.network == BitcoinNetwork.testnet ? 50002 : 50001)}',
|
||||||
|
);
|
||||||
|
node.type = WalletType.bitcoin;
|
||||||
|
await bitcoinWallet.connectToNode(node: node);
|
||||||
|
}
|
||||||
|
bitcoinWallet.rescan(height: height, doSingleScan: doSingleScan);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> getNodeIsElectrs(Object wallet) async {
|
||||||
|
final bitcoinWallet = wallet as ElectrumWallet;
|
||||||
|
|
||||||
|
final version = await bitcoinWallet.electrumClient.version();
|
||||||
|
|
||||||
|
if (version.isEmpty) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final server = version[0];
|
||||||
|
|
||||||
|
if (server.toLowerCase().contains('electrs')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> getNodeIsElectrsSPEnabled(Object wallet) async {
|
||||||
|
if (!(await getNodeIsElectrs(wallet))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final bitcoinWallet = wallet as ElectrumWallet;
|
||||||
|
final tweaksResponse = await bitcoinWallet.electrumClient.getTweaks(height: 0);
|
||||||
|
|
||||||
|
if (tweaksResponse != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void deleteSilentPaymentAddress(Object wallet, String address) {
|
||||||
|
final bitcoinWallet = wallet as ElectrumWallet;
|
||||||
|
bitcoinWallet.walletAddresses.deleteSilentPaymentAddress(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> updateFeeRates(Object wallet) async {
|
||||||
|
final bitcoinWallet = wallet as ElectrumWallet;
|
||||||
|
await bitcoinWallet.updateFeeRates();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ class AddressValidator extends TextValidator {
|
||||||
return '^[0-9a-zA-Z]{59}\$|^[0-9a-zA-Z]{92}\$|^[0-9a-zA-Z]{104}\$'
|
return '^[0-9a-zA-Z]{59}\$|^[0-9a-zA-Z]{92}\$|^[0-9a-zA-Z]{104}\$'
|
||||||
'|^[0-9a-zA-Z]{105}\$|^addr1[0-9a-zA-Z]{98}\$';
|
'|^[0-9a-zA-Z]{105}\$|^addr1[0-9a-zA-Z]{98}\$';
|
||||||
case CryptoCurrency.btc:
|
case CryptoCurrency.btc:
|
||||||
return '^${P2pkhAddress.regex.pattern}\$|^${P2shAddress.regex.pattern}\$|^${P2wpkhAddress.regex.pattern}\$|${P2trAddress.regex.pattern}\$|^${P2wshAddress.regex.pattern}\$';
|
return '^${P2pkhAddress.regex.pattern}\$|^${P2shAddress.regex.pattern}\$|^${P2wpkhAddress.regex.pattern}\$|${P2trAddress.regex.pattern}\$|^${P2wshAddress.regex.pattern}\$|^${SilentPaymentAddress.regex.pattern}\$';
|
||||||
case CryptoCurrency.ltc:
|
case CryptoCurrency.ltc:
|
||||||
return '^${P2pkhAddress.regex.pattern}\$|^${P2shAddress.regex.pattern}\$|^${P2wpkhAddress.regex.pattern}\$|${P2trAddress.regex.pattern}\$|^${P2wshAddress.regex.pattern}\$|^${MwebAddress.regex.pattern}\$';
|
return '^${P2pkhAddress.regex.pattern}\$|^${P2shAddress.regex.pattern}\$|^${P2wpkhAddress.regex.pattern}\$|${P2trAddress.regex.pattern}\$|^${P2wshAddress.regex.pattern}\$|^${MwebAddress.regex.pattern}\$';
|
||||||
case CryptoCurrency.nano:
|
case CryptoCurrency.nano:
|
||||||
|
@ -275,7 +275,9 @@ class AddressValidator extends TextValidator {
|
||||||
'|([^0-9a-zA-Z]|^)([23][a-km-zA-HJ-NP-Z1-9]{25,34})([^0-9a-zA-Z]|\$)' //P2shAddress type
|
'|([^0-9a-zA-Z]|^)([23][a-km-zA-HJ-NP-Z1-9]{25,34})([^0-9a-zA-Z]|\$)' //P2shAddress type
|
||||||
'|([^0-9a-zA-Z]|^)((bc|tb)1q[ac-hj-np-z02-9]{25,39})([^0-9a-zA-Z]|\$)' //P2wpkhAddress type
|
'|([^0-9a-zA-Z]|^)((bc|tb)1q[ac-hj-np-z02-9]{25,39})([^0-9a-zA-Z]|\$)' //P2wpkhAddress type
|
||||||
'|([^0-9a-zA-Z]|^)((bc|tb)1q[ac-hj-np-z02-9]{40,80})([^0-9a-zA-Z]|\$)' //P2wshAddress type
|
'|([^0-9a-zA-Z]|^)((bc|tb)1q[ac-hj-np-z02-9]{40,80})([^0-9a-zA-Z]|\$)' //P2wshAddress type
|
||||||
'|([^0-9a-zA-Z]|^)((bc|tb)1p([ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59}|[ac-hj-np-z02-9]{8,89}))([^0-9a-zA-Z]|\$)'; //P2trAddress type
|
'|([^0-9a-zA-Z]|^)((bc|tb)1p([ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59}|[ac-hj-np-z02-9]{8,89}))([^0-9a-zA-Z]|\$)' //P2trAddress type
|
||||||
|
'|${SilentPaymentAddress.regex.pattern}\$';
|
||||||
|
|
||||||
case CryptoCurrency.ltc:
|
case CryptoCurrency.ltc:
|
||||||
return '([^0-9a-zA-Z]|^)^L[a-zA-Z0-9]{26,33}([^0-9a-zA-Z]|\$)'
|
return '([^0-9a-zA-Z]|^)^L[a-zA-Z0-9]{26,33}([^0-9a-zA-Z]|\$)'
|
||||||
'|([^0-9a-zA-Z]|^)[LM][a-km-zA-HJ-NP-Z1-9]{26,33}([^0-9a-zA-Z]|\$)'
|
'|([^0-9a-zA-Z]|^)[LM][a-km-zA-HJ-NP-Z1-9]{26,33}([^0-9a-zA-Z]|\$)'
|
||||||
|
|
|
@ -3,7 +3,13 @@ import 'package:cw_core/sync_status.dart';
|
||||||
|
|
||||||
String syncStatusTitle(SyncStatus syncStatus) {
|
String syncStatusTitle(SyncStatus syncStatus) {
|
||||||
if (syncStatus is SyncingSyncStatus) {
|
if (syncStatus is SyncingSyncStatus) {
|
||||||
return S.current.Blocks_remaining('${syncStatus.blocksLeft}');
|
return syncStatus.blocksLeft == 1
|
||||||
|
? S.current.block_remaining
|
||||||
|
: S.current.Blocks_remaining('${syncStatus.blocksLeft}');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (syncStatus is SyncedTipSyncStatus) {
|
||||||
|
return S.current.silent_payments_scanned_tip(syncStatus.tip.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (syncStatus is SyncedSyncStatus) {
|
if (syncStatus is SyncedSyncStatus) {
|
||||||
|
@ -34,5 +40,17 @@ String syncStatusTitle(SyncStatus syncStatus) {
|
||||||
return S.current.sync_status_failed_connect;
|
return S.current.sync_status_failed_connect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (syncStatus is UnsupportedSyncStatus) {
|
||||||
|
return S.current.sync_status_unsupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (syncStatus is TimedOutSyncStatus) {
|
||||||
|
return S.current.sync_status_timed_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (syncStatus is SyncronizingSyncStatus) {
|
||||||
|
return S.current.sync_status_syncronizing;
|
||||||
|
}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
25
lib/di.dart
25
lib/di.dart
|
@ -6,6 +6,7 @@ import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
|
||||||
import 'package:cake_wallet/anypay/anypay_api.dart';
|
import 'package:cake_wallet/anypay/anypay_api.dart';
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||||
|
import 'package:cake_wallet/buy/dfx/dfx_buy_provider.dart';
|
||||||
import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
|
import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
|
||||||
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
||||||
import 'package:cake_wallet/buy/order.dart';
|
import 'package:cake_wallet/buy/order.dart';
|
||||||
|
@ -15,6 +16,7 @@ import 'package:cake_wallet/core/auth_service.dart';
|
||||||
import 'package:cake_wallet/core/backup_service.dart';
|
import 'package:cake_wallet/core/backup_service.dart';
|
||||||
import 'package:cake_wallet/core/key_service.dart';
|
import 'package:cake_wallet/core/key_service.dart';
|
||||||
import 'package:cake_wallet/core/secure_storage.dart';
|
import 'package:cake_wallet/core/secure_storage.dart';
|
||||||
|
import 'package:cake_wallet/core/totp_request_details.dart';
|
||||||
import 'package:cake_wallet/core/wallet_connect/wallet_connect_key_service.dart';
|
import 'package:cake_wallet/core/wallet_connect/wallet_connect_key_service.dart';
|
||||||
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
|
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
|
||||||
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
|
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
|
||||||
|
@ -102,12 +104,14 @@ import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/send/send_page.dart';
|
import 'package:cake_wallet/src/screens/send/send_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/send/send_template_page.dart';
|
import 'package:cake_wallet/src/screens/send/send_template_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart';
|
import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/settings/desktop_settings/desktop_settings_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
|
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/domain_lookups_page.dart';
|
import 'package:cake_wallet/src/screens/settings/domain_lookups_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/manage_nodes_page.dart';
|
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/other_settings_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/privacy_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/settings/security_backup_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/tor_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/trocador_providers_page.dart';
|
import 'package:cake_wallet/src/screens/settings/trocador_providers_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart';
|
import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart';
|
||||||
|
@ -159,10 +163,10 @@ import 'package:cake_wallet/view_model/buy/buy_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
|
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/contact_list/contact_view_model.dart';
|
import 'package:cake_wallet/view_model/contact_list/contact_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/desktop_sidebar_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/desktop_sidebar_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
|
|
||||||
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/edit_backup_password_view_model.dart';
|
import 'package:cake_wallet/view_model/edit_backup_password_view_model.dart';
|
||||||
|
@ -199,6 +203,7 @@ import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart
|
||||||
import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
|
import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
|
import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
|
import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/settings/silent_payments_settings_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/trocador_providers_view_model.dart';
|
import 'package:cake_wallet/view_model/settings/trocador_providers_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/setup_pin_code_view_model.dart';
|
import 'package:cake_wallet/view_model/setup_pin_code_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/support_view_model.dart';
|
import 'package:cake_wallet/view_model/support_view_model.dart';
|
||||||
|
@ -235,10 +240,6 @@ import 'package:hive/hive.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
import 'buy/dfx/dfx_buy_provider.dart';
|
|
||||||
import 'core/totp_request_details.dart';
|
|
||||||
import 'src/screens/settings/desktop_settings/desktop_settings_page.dart';
|
|
||||||
|
|
||||||
final getIt = GetIt.instance;
|
final getIt = GetIt.instance;
|
||||||
|
|
||||||
var _isSetupFinished = false;
|
var _isSetupFinished = false;
|
||||||
|
@ -745,6 +746,9 @@ Future<void> setup({
|
||||||
return DisplaySettingsViewModel(getIt.get<SettingsStore>());
|
return DisplaySettingsViewModel(getIt.get<SettingsStore>());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
getIt.registerFactory(() =>
|
||||||
|
SilentPaymentsSettingsViewModel(getIt.get<SettingsStore>(), getIt.get<AppStore>().wallet!));
|
||||||
|
|
||||||
getIt.registerFactory(() {
|
getIt.registerFactory(() {
|
||||||
return PrivacySettingsViewModel(getIt.get<SettingsStore>(), getIt.get<AppStore>().wallet!);
|
return PrivacySettingsViewModel(getIt.get<SettingsStore>(), getIt.get<AppStore>().wallet!);
|
||||||
});
|
});
|
||||||
|
@ -806,6 +810,9 @@ Future<void> setup({
|
||||||
|
|
||||||
getIt.registerFactory(() => DisplaySettingsPage(getIt.get<DisplaySettingsViewModel>()));
|
getIt.registerFactory(() => DisplaySettingsPage(getIt.get<DisplaySettingsViewModel>()));
|
||||||
|
|
||||||
|
getIt.registerFactory(
|
||||||
|
() => SilentPaymentsSettingsPage(getIt.get<SilentPaymentsSettingsViewModel>()));
|
||||||
|
|
||||||
getIt.registerFactory(() => OtherSettingsPage(getIt.get<OtherSettingsViewModel>()));
|
getIt.registerFactory(() => OtherSettingsPage(getIt.get<OtherSettingsViewModel>()));
|
||||||
|
|
||||||
getIt.registerFactory(() => NanoChangeRepPage(
|
getIt.registerFactory(() => NanoChangeRepPage(
|
||||||
|
@ -893,7 +900,11 @@ Future<void> setup({
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
return monero!.createMoneroWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
return monero!.createMoneroWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
return bitcoin!.createBitcoinWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
return bitcoin!.createBitcoinWalletService(
|
||||||
|
_walletInfoSource,
|
||||||
|
_unspentCoinsInfoSource,
|
||||||
|
getIt.get<SettingsStore>().silentPaymentsAlwaysScan,
|
||||||
|
);
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
return bitcoin!.createLitecoinWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
return bitcoin!.createLitecoinWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
|
@ -1089,7 +1100,7 @@ Future<void> setup({
|
||||||
|
|
||||||
getIt.registerFactory(() => IoniaGiftCardsListViewModel(ioniaService: getIt.get<IoniaService>()));
|
getIt.registerFactory(() => IoniaGiftCardsListViewModel(ioniaService: getIt.get<IoniaService>()));
|
||||||
|
|
||||||
getIt.registerFactory(() => MarketPlaceViewModel(getIt.get<IoniaService>()));
|
getIt.registerFactory(() => CakeFeaturesViewModel(getIt.get<IoniaService>()));
|
||||||
|
|
||||||
getIt.registerFactory(() => IoniaAuthViewModel(ioniaService: getIt.get<IoniaService>()));
|
getIt.registerFactory(() => IoniaAuthViewModel(ioniaService: getIt.get<IoniaService>()));
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,9 @@ import 'package:collection/collection.dart';
|
||||||
|
|
||||||
const newCakeWalletMoneroUri = 'xmr-node.cakewallet.com:18081';
|
const newCakeWalletMoneroUri = 'xmr-node.cakewallet.com:18081';
|
||||||
const cakeWalletBitcoinElectrumUri = 'electrum.cakewallet.com:50002';
|
const cakeWalletBitcoinElectrumUri = 'electrum.cakewallet.com:50002';
|
||||||
const publicBitcoinTestnetElectrumAddress = 'electrum.blockstream.info';
|
const cakeWalletSilentPaymentsElectrsUri = 'electrs.cakewallet.com:50001';
|
||||||
const publicBitcoinTestnetElectrumPort = '60002';
|
const publicBitcoinTestnetElectrumAddress = 'electrs.cakewallet.com';
|
||||||
|
const publicBitcoinTestnetElectrumPort = '50002';
|
||||||
const publicBitcoinTestnetElectrumUri =
|
const publicBitcoinTestnetElectrumUri =
|
||||||
'$publicBitcoinTestnetElectrumAddress:$publicBitcoinTestnetElectrumPort';
|
'$publicBitcoinTestnetElectrumAddress:$publicBitcoinTestnetElectrumPort';
|
||||||
const cakeWalletLitecoinElectrumUri = 'ltc-electrum.cakewallet.com:50002';
|
const cakeWalletLitecoinElectrumUri = 'ltc-electrum.cakewallet.com:50002';
|
||||||
|
@ -224,6 +225,9 @@ Future<void> defaultSettingsMigration(
|
||||||
await addTronNodeList(nodes: nodes);
|
await addTronNodeList(nodes: nodes);
|
||||||
await changeTronCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
|
await changeTronCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
|
||||||
break;
|
break;
|
||||||
|
case 34:
|
||||||
|
await _addElectRsNode(nodes, sharedPreferences);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -790,7 +794,8 @@ Future<void> changeDefaultBitcoinNode(
|
||||||
final needToReplaceCurrentBitcoinNode =
|
final needToReplaceCurrentBitcoinNode =
|
||||||
currentBitcoinNode.uri.toString().contains(cakeWalletBitcoinNodeUriPattern);
|
currentBitcoinNode.uri.toString().contains(cakeWalletBitcoinNodeUriPattern);
|
||||||
|
|
||||||
final newCakeWalletBitcoinNode = Node(uri: newCakeWalletBitcoinUri, type: WalletType.bitcoin);
|
final newCakeWalletBitcoinNode =
|
||||||
|
Node(uri: newCakeWalletBitcoinUri, type: WalletType.bitcoin, useSSL: false);
|
||||||
|
|
||||||
await nodeSource.add(newCakeWalletBitcoinNode);
|
await nodeSource.add(newCakeWalletBitcoinNode);
|
||||||
|
|
||||||
|
@ -800,6 +805,26 @@ Future<void> changeDefaultBitcoinNode(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _addElectRsNode(Box<Node> nodeSource, SharedPreferences sharedPreferences) async {
|
||||||
|
const cakeWalletBitcoinNodeUriPattern = '.cakewallet.com';
|
||||||
|
final currentBitcoinNodeId =
|
||||||
|
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
|
||||||
|
final currentBitcoinNode =
|
||||||
|
nodeSource.values.firstWhere((node) => node.key == currentBitcoinNodeId);
|
||||||
|
final needToReplaceCurrentBitcoinNode =
|
||||||
|
currentBitcoinNode.uri.toString().contains(cakeWalletBitcoinNodeUriPattern);
|
||||||
|
|
||||||
|
final newElectRsBitcoinNode =
|
||||||
|
Node(uri: cakeWalletSilentPaymentsElectrsUri, type: WalletType.bitcoin, useSSL: false);
|
||||||
|
|
||||||
|
await nodeSource.add(newElectRsBitcoinNode);
|
||||||
|
|
||||||
|
if (needToReplaceCurrentBitcoinNode) {
|
||||||
|
await sharedPreferences.setInt(
|
||||||
|
PreferencesKey.currentBitcoinElectrumSererIdKey, newElectRsBitcoinNode.key as int);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> checkCurrentNodes(
|
Future<void> checkCurrentNodes(
|
||||||
Box<Node> nodeSource, Box<Node> powNodeSource, SharedPreferences sharedPreferences) async {
|
Box<Node> nodeSource, Box<Node> powNodeSource, SharedPreferences sharedPreferences) async {
|
||||||
final currentMoneroNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
|
final currentMoneroNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
|
||||||
|
@ -845,14 +870,19 @@ Future<void> checkCurrentNodes(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentBitcoinElectrumServer == null) {
|
if (currentBitcoinElectrumServer == null) {
|
||||||
final cakeWalletElectrum = Node(uri: cakeWalletBitcoinElectrumUri, type: WalletType.bitcoin);
|
final cakeWalletElectrum =
|
||||||
|
Node(uri: cakeWalletBitcoinElectrumUri, type: WalletType.bitcoin, useSSL: false);
|
||||||
await nodeSource.add(cakeWalletElectrum);
|
await nodeSource.add(cakeWalletElectrum);
|
||||||
|
final cakeWalletElectrumTestnet =
|
||||||
|
Node(uri: publicBitcoinTestnetElectrumUri, type: WalletType.bitcoin, useSSL: false);
|
||||||
|
await nodeSource.add(cakeWalletElectrumTestnet);
|
||||||
await sharedPreferences.setInt(
|
await sharedPreferences.setInt(
|
||||||
PreferencesKey.currentBitcoinElectrumSererIdKey, cakeWalletElectrum.key as int);
|
PreferencesKey.currentBitcoinElectrumSererIdKey, cakeWalletElectrum.key as int);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentLitecoinElectrumServer == null) {
|
if (currentLitecoinElectrumServer == null) {
|
||||||
final cakeWalletElectrum = Node(uri: cakeWalletLitecoinElectrumUri, type: WalletType.litecoin);
|
final cakeWalletElectrum =
|
||||||
|
Node(uri: cakeWalletLitecoinElectrumUri, type: WalletType.litecoin, useSSL: false);
|
||||||
await nodeSource.add(cakeWalletElectrum);
|
await nodeSource.add(cakeWalletElectrum);
|
||||||
await sharedPreferences.setInt(
|
await sharedPreferences.setInt(
|
||||||
PreferencesKey.currentLitecoinElectrumSererIdKey, cakeWalletElectrum.key as int);
|
PreferencesKey.currentLitecoinElectrumSererIdKey, cakeWalletElectrum.key as int);
|
||||||
|
@ -887,7 +917,8 @@ Future<void> checkCurrentNodes(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentBitcoinCashNodeServer == null) {
|
if (currentBitcoinCashNodeServer == null) {
|
||||||
final node = Node(uri: cakeWalletBitcoinCashDefaultNodeUri, type: WalletType.bitcoinCash);
|
final node =
|
||||||
|
Node(uri: cakeWalletBitcoinCashDefaultNodeUri, type: WalletType.bitcoinCash, useSSL: false);
|
||||||
await nodeSource.add(node);
|
await nodeSource.add(node);
|
||||||
await sharedPreferences.setInt(PreferencesKey.currentBitcoinCashNodeIdKey, node.key as int);
|
await sharedPreferences.setInt(PreferencesKey.currentBitcoinCashNodeIdKey, node.key as int);
|
||||||
}
|
}
|
||||||
|
@ -921,7 +952,11 @@ Future<void> resetBitcoinElectrumServer(
|
||||||
.firstWhereOrNull((node) => node.uriRaw.toString() == cakeWalletBitcoinElectrumUri);
|
.firstWhereOrNull((node) => node.uriRaw.toString() == cakeWalletBitcoinElectrumUri);
|
||||||
|
|
||||||
if (cakeWalletNode == null) {
|
if (cakeWalletNode == null) {
|
||||||
cakeWalletNode = Node(uri: cakeWalletBitcoinElectrumUri, type: WalletType.bitcoin);
|
cakeWalletNode =
|
||||||
|
Node(uri: cakeWalletBitcoinElectrumUri, type: WalletType.bitcoin, useSSL: false);
|
||||||
|
// final cakeWalletElectrumTestnet =
|
||||||
|
// Node(uri: publicBitcoinTestnetElectrumUri, type: WalletType.bitcoin, useSSL: false);
|
||||||
|
// await nodeSource.add(cakeWalletElectrumTestnet);
|
||||||
await nodeSource.add(cakeWalletNode);
|
await nodeSource.add(cakeWalletNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,8 @@ class PreferencesKey {
|
||||||
static const polygonTransactionPriority = 'current_fee_priority_polygon';
|
static const polygonTransactionPriority = 'current_fee_priority_polygon';
|
||||||
static const bitcoinCashTransactionPriority = 'current_fee_priority_bitcoin_cash';
|
static const bitcoinCashTransactionPriority = 'current_fee_priority_bitcoin_cash';
|
||||||
static const customBitcoinFeeRate = 'custom_electrum_fee_rate';
|
static const customBitcoinFeeRate = 'custom_electrum_fee_rate';
|
||||||
|
static const silentPaymentsCardDisplay = 'silentPaymentsCardDisplay';
|
||||||
|
static const silentPaymentsAlwaysScan = 'silentPaymentsAlwaysScan';
|
||||||
static const shouldShowReceiveWarning = 'should_show_receive_warning';
|
static const shouldShowReceiveWarning = 'should_show_receive_warning';
|
||||||
static const shouldShowYatPopup = 'should_show_yat_popup';
|
static const shouldShowYatPopup = 'should_show_yat_popup';
|
||||||
static const shouldShowRepWarning = 'should_show_rep_warning';
|
static const shouldShowRepWarning = 'should_show_rep_warning';
|
||||||
|
|
|
@ -202,7 +202,7 @@ Future<void> initializeAppConfigs() async {
|
||||||
transactionDescriptions: transactionDescriptions,
|
transactionDescriptions: transactionDescriptions,
|
||||||
secureStorage: secureStorage,
|
secureStorage: secureStorage,
|
||||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||||
initialMigrationVersion: 33,
|
initialMigrationVersion: 34,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,19 @@ import 'dart:async';
|
||||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/sync_status.dart';
|
import 'package:cw_core/sync_status.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
|
|
||||||
Timer? _checkConnectionTimer;
|
Timer? _checkConnectionTimer;
|
||||||
|
|
||||||
void startCheckConnectionReaction(
|
void startCheckConnectionReaction(WalletBase wallet, SettingsStore settingsStore,
|
||||||
WalletBase wallet, SettingsStore settingsStore,
|
|
||||||
{int timeInterval = 5}) {
|
{int timeInterval = 5}) {
|
||||||
_checkConnectionTimer?.cancel();
|
_checkConnectionTimer?.cancel();
|
||||||
_checkConnectionTimer =
|
_checkConnectionTimer = Timer.periodic(Duration(seconds: timeInterval), (_) async {
|
||||||
Timer.periodic(Duration(seconds: timeInterval), (_) async {
|
if (wallet.type == WalletType.bitcoin && wallet.syncStatus is SyncingSyncStatus) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final connectivityResult = await (Connectivity().checkConnectivity());
|
final connectivityResult = await (Connectivity().checkConnectivity());
|
||||||
|
|
||||||
|
@ -20,14 +24,11 @@ void startCheckConnectionReaction(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wallet.syncStatus is LostConnectionSyncStatus ||
|
if (wallet.syncStatus is LostConnectionSyncStatus || wallet.syncStatus is FailedSyncStatus) {
|
||||||
wallet.syncStatus is FailedSyncStatus) {
|
final alive = await settingsStore.getCurrentNode(wallet.type).requestNode();
|
||||||
final alive =
|
|
||||||
await settingsStore.getCurrentNode(wallet.type).requestNode();
|
|
||||||
|
|
||||||
if (alive) {
|
if (alive) {
|
||||||
await wallet.connectToNode(
|
await wallet.connectToNode(node: settingsStore.getCurrentNode(wallet.type));
|
||||||
node: settingsStore.getCurrentNode(wallet.type));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -12,12 +12,10 @@ import 'package:wakelock_plus/wakelock_plus.dart';
|
||||||
ReactionDisposer? _onWalletSyncStatusChangeReaction;
|
ReactionDisposer? _onWalletSyncStatusChangeReaction;
|
||||||
|
|
||||||
void startWalletSyncStatusChangeReaction(
|
void startWalletSyncStatusChangeReaction(
|
||||||
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
|
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet,
|
||||||
TransactionInfo> wallet,
|
|
||||||
FiatConversionStore fiatConversionStore) {
|
FiatConversionStore fiatConversionStore) {
|
||||||
_onWalletSyncStatusChangeReaction?.reaction.dispose();
|
_onWalletSyncStatusChangeReaction?.reaction.dispose();
|
||||||
_onWalletSyncStatusChangeReaction =
|
_onWalletSyncStatusChangeReaction = reaction((_) => wallet.syncStatus, (SyncStatus status) async {
|
||||||
reaction((_) => wallet.syncStatus, (SyncStatus status) async {
|
|
||||||
try {
|
try {
|
||||||
if (status is ConnectedSyncStatus) {
|
if (status is ConnectedSyncStatus) {
|
||||||
await wallet.startSync();
|
await wallet.startSync();
|
||||||
|
@ -32,7 +30,7 @@ void startWalletSyncStatusChangeReaction(
|
||||||
if (status is SyncedSyncStatus || status is FailedSyncStatus) {
|
if (status is SyncedSyncStatus || status is FailedSyncStatus) {
|
||||||
await WakelockPlus.disable();
|
await WakelockPlus.disable();
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
print(e.toString());
|
print(e.toString());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -76,6 +76,7 @@ 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/other_settings_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/privacy_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/settings/security_backup_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/tor_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/trocador_providers_page.dart';
|
import 'package:cake_wallet/src/screens/settings/trocador_providers_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart';
|
import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart';
|
||||||
|
@ -366,6 +367,10 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
param1: settings.arguments as OnAuthenticationFinished, param2: false),
|
param1: settings.arguments as OnAuthenticationFinished, param2: false),
|
||||||
onWillPop: () async => false));
|
onWillPop: () async => false));
|
||||||
|
|
||||||
|
case Routes.silentPaymentsSettings:
|
||||||
|
return CupertinoPageRoute<void>(
|
||||||
|
fullscreenDialog: true, builder: (_) => getIt.get<SilentPaymentsSettingsPage>());
|
||||||
|
|
||||||
case Routes.connectionSync:
|
case Routes.connectionSync:
|
||||||
return CupertinoPageRoute<void>(
|
return CupertinoPageRoute<void>(
|
||||||
fullscreenDialog: true, builder: (_) => getIt.get<ConnectionSyncPage>());
|
fullscreenDialog: true, builder: (_) => getIt.get<ConnectionSyncPage>());
|
||||||
|
|
|
@ -81,6 +81,7 @@ class Routes {
|
||||||
static const ioniaMoreOptionsPage = '/ionia_more_options_page';
|
static const ioniaMoreOptionsPage = '/ionia_more_options_page';
|
||||||
static const ioniaCustomRedeemPage = '/ionia_custom_redeem_page';
|
static const ioniaCustomRedeemPage = '/ionia_custom_redeem_page';
|
||||||
static const webViewPage = '/web_view_page';
|
static const webViewPage = '/web_view_page';
|
||||||
|
static const silentPaymentsSettings = '/silent_payments_settings';
|
||||||
static const connectionSync = '/connection_sync_page';
|
static const connectionSync = '/connection_sync_page';
|
||||||
static const securityBackupPage = '/security_and_backup_page';
|
static const securityBackupPage = '/security_and_backup_page';
|
||||||
static const privacyPage = '/privacy_page';
|
static const privacyPage = '/privacy_page';
|
||||||
|
|
|
@ -4,7 +4,7 @@ import 'package:cake_wallet/entities/preferences_key.dart';
|
||||||
import 'package:cake_wallet/di.dart';
|
import 'package:cake_wallet/di.dart';
|
||||||
import 'package:cake_wallet/entities/main_actions.dart';
|
import 'package:cake_wallet/entities/main_actions.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart';
|
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart';
|
import 'package:cake_wallet/src/screens/dashboard/pages/cake_features_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart';
|
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart';
|
||||||
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
||||||
import 'package:cake_wallet/src/widgets/services_updates_widget.dart';
|
import 'package:cake_wallet/src/widgets/services_updates_widget.dart';
|
||||||
|
@ -12,7 +12,7 @@ import 'package:cake_wallet/src/widgets/vulnerable_seeds_popup.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||||
import 'package:cake_wallet/utils/device_info.dart';
|
import 'package:cake_wallet/utils/device_info.dart';
|
||||||
import 'package:cake_wallet/utils/version_comparator.dart';
|
import 'package:cake_wallet/utils/version_comparator.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
|
import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
|
||||||
|
@ -330,10 +330,10 @@ class _DashboardPageView extends BasePage {
|
||||||
if (dashboardViewModel.shouldShowMarketPlaceInDashboard) {
|
if (dashboardViewModel.shouldShowMarketPlaceInDashboard) {
|
||||||
pages.add(
|
pages.add(
|
||||||
Semantics(
|
Semantics(
|
||||||
label: S.of(context).market_place,
|
label: 'Cake ${S.of(context).features}',
|
||||||
child: MarketPlacePage(
|
child: CakeFeaturesPage(
|
||||||
dashboardViewModel: dashboardViewModel,
|
dashboardViewModel: dashboardViewModel,
|
||||||
marketPlaceViewModel: getIt.get<MarketPlaceViewModel>(),
|
cakeFeaturesViewModel: getIt.get<CakeFeaturesViewModel>(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import 'package:cake_wallet/di.dart';
|
import 'package:cake_wallet/di.dart';
|
||||||
import 'package:cake_wallet/entities/main_actions.dart';
|
import 'package:cake_wallet/entities/main_actions.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_action_button.dart';
|
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_action_button.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart';
|
import 'package:cake_wallet/src/screens/dashboard/pages/cake_features_page.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
|
||||||
|
@ -74,9 +74,9 @@ class DesktopDashboardActions extends StatelessWidget {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MarketPlacePage(
|
child: CakeFeaturesPage(
|
||||||
dashboardViewModel: dashboardViewModel,
|
dashboardViewModel: dashboardViewModel,
|
||||||
marketPlaceViewModel: getIt.get<MarketPlaceViewModel>(),
|
cakeFeaturesViewModel: getIt.get<CakeFeaturesViewModel>(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -30,6 +30,7 @@ class DesktopWalletSelectionDropDown extends StatefulWidget {
|
||||||
class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionDropDown> {
|
class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionDropDown> {
|
||||||
final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
|
final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
|
||||||
final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
||||||
|
final tBitcoinIcon = Image.asset('assets/images/tbtc.png', height: 24, width: 24);
|
||||||
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
|
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
|
||||||
final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
|
final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
|
||||||
final ethereumIcon = Image.asset('assets/images/eth_icon.png', height: 24, width: 24);
|
final ethereumIcon = Image.asset('assets/images/eth_icon.png', height: 24, width: 24);
|
||||||
|
@ -68,8 +69,11 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: BoxConstraints(maxWidth: 500),
|
constraints: BoxConstraints(maxWidth: 500),
|
||||||
child: DropDownItemWidget(
|
child: DropDownItemWidget(
|
||||||
title: wallet.name,
|
title: wallet.name,
|
||||||
image: wallet.isEnabled ? _imageFor(type: wallet.type) : nonWalletTypeIcon),
|
image: wallet.isEnabled
|
||||||
|
? _imageFor(type: wallet.type, isTestnet: wallet.isTestnet)
|
||||||
|
: nonWalletTypeIcon,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
onSelected: () => _onSelectedWallet(wallet),
|
onSelected: () => _onSelectedWallet(wallet),
|
||||||
))
|
))
|
||||||
|
@ -120,16 +124,16 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
final confirmed = await showPopUp<bool>(
|
final confirmed = await showPopUp<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (dialogContext) {
|
builder: (dialogContext) {
|
||||||
return AlertWithTwoActions(
|
return AlertWithTwoActions(
|
||||||
alertTitle: S.of(context).change_wallet_alert_title,
|
alertTitle: S.of(context).change_wallet_alert_title,
|
||||||
alertContent: S.of(context).change_wallet_alert_content(selectedWallet.name),
|
alertContent: S.of(context).change_wallet_alert_content(selectedWallet.name),
|
||||||
leftButtonText: S.of(context).cancel,
|
leftButtonText: S.of(context).cancel,
|
||||||
rightButtonText: S.of(context).change,
|
rightButtonText: S.of(context).change,
|
||||||
actionLeftButton: () => Navigator.of(dialogContext).pop(false),
|
actionLeftButton: () => Navigator.of(dialogContext).pop(false),
|
||||||
actionRightButton: () => Navigator.of(dialogContext).pop(true));
|
actionRightButton: () => Navigator.of(dialogContext).pop(true));
|
||||||
}) ??
|
}) ??
|
||||||
false;
|
false;
|
||||||
|
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
|
@ -138,9 +142,12 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Image _imageFor({required WalletType type}) {
|
Image _imageFor({required WalletType type, bool? isTestnet}) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
|
if (isTestnet == true) {
|
||||||
|
return tBitcoinIcon;
|
||||||
|
}
|
||||||
return bitcoinIcon;
|
return bitcoinIcon;
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
return moneroIcon;
|
return moneroIcon;
|
||||||
|
@ -160,7 +167,7 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||||
return polygonIcon;
|
return polygonIcon;
|
||||||
case WalletType.solana:
|
case WalletType.solana:
|
||||||
return solanaIcon;
|
return solanaIcon;
|
||||||
case WalletType.tron:
|
case WalletType.tron:
|
||||||
return tronIcon;
|
return tronIcon;
|
||||||
default:
|
default:
|
||||||
return nonWalletTypeIcon;
|
return nonWalletTypeIcon;
|
||||||
|
@ -168,24 +175,25 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _loadWallet(WalletListItem wallet) async {
|
Future<void> _loadWallet(WalletListItem wallet) async {
|
||||||
widget._authService.authenticateAction(context,
|
widget._authService.authenticateAction(
|
||||||
onAuthSuccess: (isAuthenticatedSuccessfully) async {
|
context,
|
||||||
if (!isAuthenticatedSuccessfully) {
|
onAuthSuccess: (isAuthenticatedSuccessfully) async {
|
||||||
return;
|
if (!isAuthenticatedSuccessfully) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name));
|
changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name));
|
||||||
|
}
|
||||||
|
await widget.walletListViewModel.loadWallet(wallet);
|
||||||
|
hideProgressText();
|
||||||
|
setState(() {});
|
||||||
|
} catch (e) {
|
||||||
|
if (context.mounted) {
|
||||||
|
changeProcessText(S.of(context).wallet_list_failed_to_load(wallet.name, e.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
await widget.walletListViewModel.loadWallet(wallet);
|
|
||||||
hideProgressText();
|
|
||||||
setState(() {});
|
|
||||||
} catch (e) {
|
|
||||||
if (context.mounted) {
|
|
||||||
changeProcessText(S.of(context).wallet_list_failed_to_load(wallet.name, e.toString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
conditionToDetermineIfToUse2FA:
|
conditionToDetermineIfToUse2FA:
|
||||||
widget.walletListViewModel.shouldRequireTOTP2FAForAccessingWallet,
|
widget.walletListViewModel.shouldRequireTOTP2FAForAccessingWallet,
|
||||||
|
@ -198,17 +206,16 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||||
context,
|
context,
|
||||||
route: Routes.newWallet,
|
route: Routes.newWallet,
|
||||||
arguments: widget.walletListViewModel.currentWalletType,
|
arguments: widget.walletListViewModel.currentWalletType,
|
||||||
conditionToDetermineIfToUse2FA: widget
|
conditionToDetermineIfToUse2FA:
|
||||||
.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets,
|
widget.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
widget._authService.authenticateAction(
|
widget._authService.authenticateAction(
|
||||||
context,
|
context,
|
||||||
route: Routes.newWalletType,
|
route: Routes.newWalletType,
|
||||||
conditionToDetermineIfToUse2FA: widget
|
conditionToDetermineIfToUse2FA:
|
||||||
.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets,
|
widget.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets,
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -187,6 +187,11 @@ class AddressPage extends BasePage {
|
||||||
}
|
}
|
||||||
|
|
||||||
reaction((_) => receiveOptionViewModel.selectedReceiveOption, (ReceivePageOption option) {
|
reaction((_) => receiveOptionViewModel.selectedReceiveOption, (ReceivePageOption option) {
|
||||||
|
if (bitcoin!.isBitcoinReceivePageOption(option)) {
|
||||||
|
addressListViewModel.setAddressType(bitcoin!.getOptionToType(option));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case ReceivePageOption.anonPayInvoice:
|
case ReceivePageOption.anonPayInvoice:
|
||||||
Navigator.pushNamed(
|
Navigator.pushNamed(
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:auto_size_text/auto_size_text.dart';
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/pages/nft_listing_page.dart';
|
import 'package:cake_wallet/src/screens/dashboard/pages/nft_listing_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/widgets/home_screen_account_widget.dart';
|
import 'package:cake_wallet/src/screens/dashboard/widgets/home_screen_account_widget.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||||
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
|
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
|
||||||
import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
|
import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
|
||||||
import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart';
|
import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart';
|
||||||
import 'package:cake_wallet/src/widgets/introducing_card.dart';
|
import 'package:cake_wallet/src/widgets/introducing_card.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/standard_switch.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||||
|
@ -21,6 +24,7 @@ import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
class BalancePage extends StatelessWidget {
|
class BalancePage extends StatelessWidget {
|
||||||
BalancePage({
|
BalancePage({
|
||||||
|
@ -221,30 +225,136 @@ class CryptoBalanceWidget extends StatelessWidget {
|
||||||
itemBuilder: (__, index) {
|
itemBuilder: (__, index) {
|
||||||
final balance =
|
final balance =
|
||||||
dashboardViewModel.balanceViewModel.formattedBalances.elementAt(index);
|
dashboardViewModel.balanceViewModel.formattedBalances.elementAt(index);
|
||||||
return BalanceRowWidget(
|
return Observer(builder: (_) {
|
||||||
availableBalanceLabel:
|
return BalanceRowWidget(
|
||||||
'${dashboardViewModel.balanceViewModel.availableBalanceLabel}',
|
availableBalanceLabel:
|
||||||
availableBalance: balance.availableBalance,
|
'${dashboardViewModel.balanceViewModel.availableBalanceLabel}',
|
||||||
availableFiatBalance: balance.fiatAvailableBalance,
|
availableBalance: balance.availableBalance,
|
||||||
additionalBalanceLabel:
|
availableFiatBalance: balance.fiatAvailableBalance,
|
||||||
'${dashboardViewModel.balanceViewModel.additionalBalanceLabel}',
|
additionalBalanceLabel:
|
||||||
additionalBalance: balance.additionalBalance,
|
'${dashboardViewModel.balanceViewModel.additionalBalanceLabel}',
|
||||||
additionalFiatBalance: balance.fiatAdditionalBalance,
|
additionalBalance: balance.additionalBalance,
|
||||||
frozenBalance: balance.frozenBalance,
|
additionalFiatBalance: balance.fiatAdditionalBalance,
|
||||||
frozenFiatBalance: balance.fiatFrozenBalance,
|
frozenBalance: balance.frozenBalance,
|
||||||
currency: balance.asset,
|
frozenFiatBalance: balance.fiatFrozenBalance,
|
||||||
hasAdditionalBalance:
|
currency: balance.asset,
|
||||||
dashboardViewModel.balanceViewModel.hasAdditionalBalance,
|
hasAdditionalBalance:
|
||||||
);
|
dashboardViewModel.balanceViewModel.hasAdditionalBalance,
|
||||||
|
isTestnet: dashboardViewModel.isTestnet,
|
||||||
|
);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
|
Observer(builder: (context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
if (dashboardViewModel.showSilentPaymentsCard) ...[
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
||||||
|
child: DashBoardRoundedCardWidget(
|
||||||
|
customBorder: 30,
|
||||||
|
title: S.of(context).silent_payments,
|
||||||
|
subTitle: S.of(context).enable_silent_payments_scanning,
|
||||||
|
hint: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
|
onTap: () => launchUrl(
|
||||||
|
Uri.parse(
|
||||||
|
"https://guides.cakewallet.com/docs/cryptos/bitcoin/#silent-payments"),
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
S.of(context).what_is_silent_payments,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontFamily: 'Lato',
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<BalancePageTheme>()!
|
||||||
|
.labelTextColor,
|
||||||
|
height: 1,
|
||||||
|
),
|
||||||
|
softWrap: true,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
|
child: Icon(Icons.help_outline,
|
||||||
|
size: 16,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<BalancePageTheme>()!
|
||||||
|
.labelTextColor),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Observer(
|
||||||
|
builder: (_) => StandardSwitch(
|
||||||
|
value: dashboardViewModel.silentPaymentsScanningActive,
|
||||||
|
onTaped: () => _toggleSilentPaymentsScanning(context),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: () => _toggleSilentPaymentsScanning(context),
|
||||||
|
icon: Icon(
|
||||||
|
Icons.lock,
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||||
|
size: 50,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _toggleSilentPaymentsScanning(BuildContext context) async {
|
||||||
|
final isSilentPaymentsScanningActive = dashboardViewModel.silentPaymentsScanningActive;
|
||||||
|
final newValue = !isSilentPaymentsScanningActive;
|
||||||
|
|
||||||
|
dashboardViewModel.silentPaymentsScanningActive = newValue;
|
||||||
|
|
||||||
|
final needsToSwitch = !isSilentPaymentsScanningActive &&
|
||||||
|
await bitcoin!.getNodeIsElectrsSPEnabled(dashboardViewModel.wallet) == false;
|
||||||
|
|
||||||
|
if (needsToSwitch) {
|
||||||
|
return showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) => AlertWithTwoActions(
|
||||||
|
alertTitle: S.of(context).change_current_node_title,
|
||||||
|
alertContent: S.of(context).confirm_silent_payments_switch_node,
|
||||||
|
rightButtonText: S.of(context).ok,
|
||||||
|
leftButtonText: S.of(context).cancel,
|
||||||
|
actionRightButton: () {
|
||||||
|
dashboardViewModel.setSilentPaymentsScanning(newValue);
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
actionLeftButton: () {
|
||||||
|
dashboardViewModel.silentPaymentsScanningActive = isSilentPaymentsScanningActive;
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return dashboardViewModel.setSilentPaymentsScanning(newValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BalanceRowWidget extends StatelessWidget {
|
class BalanceRowWidget extends StatelessWidget {
|
||||||
|
@ -259,6 +369,7 @@ class BalanceRowWidget extends StatelessWidget {
|
||||||
required this.frozenFiatBalance,
|
required this.frozenFiatBalance,
|
||||||
required this.currency,
|
required this.currency,
|
||||||
required this.hasAdditionalBalance,
|
required this.hasAdditionalBalance,
|
||||||
|
required this.isTestnet,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -272,6 +383,7 @@ class BalanceRowWidget extends StatelessWidget {
|
||||||
final String frozenFiatBalance;
|
final String frozenFiatBalance;
|
||||||
final CryptoCurrency currency;
|
final CryptoCurrency currency;
|
||||||
final bool hasAdditionalBalance;
|
final bool hasAdditionalBalance;
|
||||||
|
final bool isTestnet;
|
||||||
|
|
||||||
// void _showBalanceDescription(BuildContext context) {
|
// void _showBalanceDescription(BuildContext context) {
|
||||||
// showPopUp<void>(
|
// showPopUp<void>(
|
||||||
|
@ -346,14 +458,24 @@ class BalanceRowWidget extends StatelessWidget {
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
textAlign: TextAlign.start),
|
textAlign: TextAlign.start),
|
||||||
SizedBox(height: 6),
|
SizedBox(height: 6),
|
||||||
Text('${availableFiatBalance}',
|
if (isTestnet)
|
||||||
textAlign: TextAlign.center,
|
Text(S.current.testnet_coins_no_value,
|
||||||
style: TextStyle(
|
textAlign: TextAlign.center,
|
||||||
fontSize: 16,
|
style: TextStyle(
|
||||||
fontFamily: 'Lato',
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w500,
|
fontFamily: 'Lato',
|
||||||
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
fontWeight: FontWeight.w400,
|
||||||
height: 1)),
|
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||||
|
height: 1)),
|
||||||
|
if (!isTestnet)
|
||||||
|
Text('${availableFiatBalance}',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Lato',
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||||
|
height: 1)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -362,27 +484,23 @@ class BalanceRowWidget extends StatelessWidget {
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
CakeImageWidget(
|
||||||
clipBehavior: Clip.antiAlias,
|
imageUrl: currency.iconPath,
|
||||||
decoration: BoxDecoration(shape: BoxShape.circle),
|
height: 40,
|
||||||
child: CakeImageWidget(
|
width: 40,
|
||||||
imageUrl: currency.iconPath,
|
displayOnError: Container(
|
||||||
height: 40,
|
height: 30.0,
|
||||||
width: 40,
|
width: 30.0,
|
||||||
displayOnError: Container(
|
child: Center(
|
||||||
height: 30.0,
|
child: Text(
|
||||||
width: 30.0,
|
currency.title.substring(0, min(currency.title.length, 2)),
|
||||||
child: Center(
|
style: TextStyle(fontSize: 11),
|
||||||
child: Text(
|
|
||||||
currency.title.substring(0, min(currency.title.length, 2)),
|
|
||||||
style: TextStyle(fontSize: 11),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
color: Colors.grey.shade400,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: Colors.grey.shade400,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
|
@ -449,17 +567,18 @@ class BalanceRowWidget extends StatelessWidget {
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
SizedBox(height: 4),
|
SizedBox(height: 4),
|
||||||
Text(
|
if (!isTestnet)
|
||||||
frozenFiatBalance,
|
Text(
|
||||||
textAlign: TextAlign.center,
|
frozenFiatBalance,
|
||||||
style: TextStyle(
|
textAlign: TextAlign.center,
|
||||||
fontSize: 12,
|
style: TextStyle(
|
||||||
fontFamily: 'Lato',
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w400,
|
fontFamily: 'Lato',
|
||||||
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
fontWeight: FontWeight.w400,
|
||||||
height: 1,
|
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||||
|
height: 1,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -493,17 +612,18 @@ class BalanceRowWidget extends StatelessWidget {
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
SizedBox(height: 4),
|
SizedBox(height: 4),
|
||||||
Text(
|
if (!isTestnet)
|
||||||
'${additionalFiatBalance}',
|
Text(
|
||||||
textAlign: TextAlign.center,
|
'${additionalFiatBalance}',
|
||||||
style: TextStyle(
|
textAlign: TextAlign.center,
|
||||||
fontSize: 12,
|
style: TextStyle(
|
||||||
fontFamily: 'Lato',
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w400,
|
fontFamily: 'Lato',
|
||||||
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
fontWeight: FontWeight.w400,
|
||||||
height: 1,
|
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||||
|
height: 1,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,23 +1,20 @@
|
||||||
import 'package:cake_wallet/routes.dart';
|
|
||||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
|
||||||
import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart';
|
import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart';
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
|
||||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
|
||||||
class MarketPlacePage extends StatelessWidget {
|
class CakeFeaturesPage extends StatelessWidget {
|
||||||
MarketPlacePage({
|
CakeFeaturesPage({
|
||||||
required this.dashboardViewModel,
|
required this.dashboardViewModel,
|
||||||
required this.marketPlaceViewModel,
|
required this.cakeFeaturesViewModel,
|
||||||
});
|
});
|
||||||
|
|
||||||
final DashboardViewModel dashboardViewModel;
|
final DashboardViewModel dashboardViewModel;
|
||||||
final MarketPlaceViewModel marketPlaceViewModel;
|
final CakeFeaturesViewModel cakeFeaturesViewModel;
|
||||||
final _scrollController = ScrollController();
|
final _scrollController = ScrollController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -37,7 +34,7 @@ class MarketPlacePage extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 50),
|
SizedBox(height: 50),
|
||||||
Text(
|
Text(
|
||||||
S.of(context).market_place,
|
'Cake ${S.of(context).features}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
|
@ -59,15 +56,21 @@ class MarketPlacePage extends StatelessWidget {
|
||||||
// ),
|
// ),
|
||||||
SizedBox(height: 20),
|
SizedBox(height: 20),
|
||||||
DashBoardRoundedCardWidget(
|
DashBoardRoundedCardWidget(
|
||||||
|
onTap: () => _launchUrl("buy.cakepay.com"),
|
||||||
title: S.of(context).cake_pay_web_cards_title,
|
title: S.of(context).cake_pay_web_cards_title,
|
||||||
subTitle: S.of(context).cake_pay_web_cards_subtitle,
|
subTitle: S.of(context).cake_pay_web_cards_subtitle,
|
||||||
onTap: () => _launchMarketPlaceUrl("buy.cakepay.com"),
|
svgPicture: SvgPicture.asset(
|
||||||
|
'assets/images/cards.svg',
|
||||||
|
height: 125,
|
||||||
|
width: 125,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
SizedBox(height: 10),
|
||||||
DashBoardRoundedCardWidget(
|
DashBoardRoundedCardWidget(
|
||||||
title: "NanoGPT",
|
title: "NanoGPT",
|
||||||
subTitle: S.of(context).nanogpt_subtitle,
|
subTitle: S.of(context).nanogpt_subtitle,
|
||||||
onTap: () => _launchMarketPlaceUrl("cake.nano-gpt.com"),
|
onTap: () => _launchUrl("cake.nano-gpt.com"),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -79,41 +82,12 @@ class MarketPlacePage extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _launchMarketPlaceUrl(String url) async {
|
void _launchUrl(String url) {
|
||||||
try {
|
try {
|
||||||
launchUrl(
|
launchUrl(
|
||||||
Uri.https(url),
|
Uri.https(url),
|
||||||
mode: LaunchMode.externalApplication,
|
mode: LaunchMode.externalApplication,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (_) {}
|
||||||
print(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Remove ionia flow/files if we will discard it
|
|
||||||
void _navigatorToGiftCardsPage(BuildContext context) {
|
|
||||||
final walletType = dashboardViewModel.type;
|
|
||||||
|
|
||||||
switch (walletType) {
|
|
||||||
case WalletType.haven:
|
|
||||||
showPopUp<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return AlertWithOneAction(
|
|
||||||
alertTitle: S.of(context).error,
|
|
||||||
alertContent: S.of(context).gift_cards_unavailable,
|
|
||||||
buttonText: S.of(context).ok,
|
|
||||||
buttonAction: () => Navigator.of(context).pop());
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
marketPlaceViewModel.isIoniaUserAuthenticated().then((value) {
|
|
||||||
if (value) {
|
|
||||||
Navigator.pushNamed(context, Routes.ioniaManageCardsPage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Navigator.of(context).pushNamed(Routes.ioniaWelcomePage);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/src/widgets/setting_action_button.dart';
|
import 'package:cake_wallet/src/widgets/setting_action_button.dart';
|
||||||
import 'package:cake_wallet/src/widgets/setting_actions.dart';
|
import 'package:cake_wallet/src/widgets/setting_actions.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
||||||
|
@ -180,6 +181,11 @@ class MenuWidgetState extends State<MenuWidget> {
|
||||||
|
|
||||||
final item = SettingActions.all[index];
|
final item = SettingActions.all[index];
|
||||||
|
|
||||||
|
if (!widget.dashboardViewModel.hasSilentPayments &&
|
||||||
|
item.name(context) == S.of(context).silent_payments_settings) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
|
||||||
final isLastTile = index == itemCount - 1;
|
final isLastTile = index == itemCount - 1;
|
||||||
|
|
||||||
return SettingActionButton(
|
return SettingActionButton(
|
||||||
|
|
|
@ -10,8 +10,7 @@ import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
|
||||||
class PresentReceiveOptionPicker extends StatelessWidget {
|
class PresentReceiveOptionPicker extends StatelessWidget {
|
||||||
PresentReceiveOptionPicker(
|
PresentReceiveOptionPicker({required this.receiveOptionViewModel, required this.color});
|
||||||
{required this.receiveOptionViewModel, required this.color});
|
|
||||||
|
|
||||||
final ReceiveOptionViewModel receiveOptionViewModel;
|
final ReceiveOptionViewModel receiveOptionViewModel;
|
||||||
final Color color;
|
final Color color;
|
||||||
|
@ -43,17 +42,17 @@ class PresentReceiveOptionPicker extends StatelessWidget {
|
||||||
Text(
|
Text(
|
||||||
S.current.receive,
|
S.current.receive,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18.0,
|
fontSize: 18.0, fontWeight: FontWeight.bold, fontFamily: 'Lato', color: color),
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontFamily: 'Lato',
|
|
||||||
color: color),
|
|
||||||
),
|
),
|
||||||
Observer(
|
Observer(
|
||||||
builder: (_) => Text(receiveOptionViewModel.selectedReceiveOption.toString(),
|
builder: (_) => Text(
|
||||||
style: TextStyle(
|
receiveOptionViewModel.selectedReceiveOption
|
||||||
fontSize: 10.0,
|
.toString()
|
||||||
fontWeight: FontWeight.w500,
|
.replaceAll(RegExp(r'silent payments', caseSensitive: false),
|
||||||
color: color)))
|
S.current.silent_payments)
|
||||||
|
.replaceAll(
|
||||||
|
RegExp(r'default', caseSensitive: false), S.current.string_default),
|
||||||
|
style: TextStyle(fontSize: 10.0, fontWeight: FontWeight.w500, color: color)))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(width: 5),
|
SizedBox(width: 5),
|
||||||
|
@ -73,65 +72,75 @@ class PresentReceiveOptionPicker extends StatelessWidget {
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
body: Stack(
|
body: Stack(
|
||||||
alignment: AlignmentDirectional.center,
|
alignment: AlignmentDirectional.center,
|
||||||
children:[ AlertBackground(
|
children: [
|
||||||
child: Column(
|
AlertBackground(
|
||||||
mainAxisSize: MainAxisSize.min,
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
Spacer(),
|
children: [
|
||||||
Container(
|
Spacer(),
|
||||||
margin: EdgeInsets.symmetric(horizontal: 24),
|
Container(
|
||||||
decoration: BoxDecoration(
|
margin: EdgeInsets.symmetric(horizontal: 24),
|
||||||
borderRadius: BorderRadius.circular(30),
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.background,
|
borderRadius: BorderRadius.circular(30),
|
||||||
),
|
color: Theme.of(context).colorScheme.background,
|
||||||
child: Padding(
|
),
|
||||||
padding: const EdgeInsets.only(top: 24, bottom: 24),
|
child: Padding(
|
||||||
child: (ListView.separated(
|
padding: const EdgeInsets.only(top: 24, bottom: 24),
|
||||||
padding: EdgeInsets.zero,
|
child: (ListView.separated(
|
||||||
shrinkWrap: true,
|
padding: EdgeInsets.zero,
|
||||||
itemCount: receiveOptionViewModel.options.length,
|
shrinkWrap: true,
|
||||||
itemBuilder: (_, index) {
|
itemCount: receiveOptionViewModel.options.length,
|
||||||
final option = receiveOptionViewModel.options[index];
|
itemBuilder: (_, index) {
|
||||||
return InkWell(
|
final option = receiveOptionViewModel.options[index];
|
||||||
onTap: () {
|
return InkWell(
|
||||||
Navigator.pop(popUpContext);
|
onTap: () {
|
||||||
|
Navigator.pop(popUpContext);
|
||||||
|
|
||||||
receiveOptionViewModel.selectReceiveOption(option);
|
receiveOptionViewModel.selectReceiveOption(option);
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(left: 24, right: 24),
|
padding: const EdgeInsets.only(left: 24, right: 24),
|
||||||
child: Observer(builder: (_) {
|
child: Observer(builder: (_) {
|
||||||
final value = receiveOptionViewModel.selectedReceiveOption;
|
final value = receiveOptionViewModel.selectedReceiveOption;
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(option.toString(),
|
Text(
|
||||||
textAlign: TextAlign.left,
|
option
|
||||||
style: textSmall(
|
.toString()
|
||||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
.replaceAll(
|
||||||
).copyWith(
|
RegExp(r'silent payments', caseSensitive: false),
|
||||||
fontWeight:
|
S.current.silent_payments)
|
||||||
value == option ? FontWeight.w800 : FontWeight.w500,
|
.replaceAll(RegExp(r'default', caseSensitive: false),
|
||||||
)),
|
S.current.string_default),
|
||||||
RoundedCheckbox(
|
textAlign: TextAlign.left,
|
||||||
value: value == option,
|
style: textSmall(
|
||||||
)
|
color: Theme.of(context)
|
||||||
],
|
.extension<CakeTextTheme>()!
|
||||||
);
|
.titleColor,
|
||||||
}),
|
).copyWith(
|
||||||
),
|
fontWeight:
|
||||||
);
|
value == option ? FontWeight.w800 : FontWeight.w500,
|
||||||
},
|
)),
|
||||||
separatorBuilder: (_, index) => SizedBox(height: 30),
|
RoundedCheckbox(
|
||||||
)),
|
value: value == option,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorBuilder: (_, index) => SizedBox(height: 30),
|
||||||
|
)),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
Spacer()
|
||||||
Spacer()
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
AlertCloseButton(onTap: () => Navigator.of(popUpContext).pop(), bottom: 40)
|
AlertCloseButton(onTap: () => Navigator.of(popUpContext).pop(), bottom: 40)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -67,8 +67,7 @@ class ReceivePage extends BasePage {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget Function(BuildContext, Widget) get rootWrapper =>
|
Widget Function(BuildContext, Widget) get rootWrapper =>
|
||||||
(BuildContext context, Widget scaffold) =>
|
(BuildContext context, Widget scaffold) => GradientBackground(scaffold: scaffold);
|
||||||
GradientBackground(scaffold: scaffold);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget trailing(BuildContext context) {
|
Widget trailing(BuildContext context) {
|
||||||
|
@ -99,115 +98,144 @@ class ReceivePage extends BasePage {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
return KeyboardActions(
|
return KeyboardActions(
|
||||||
config: KeyboardActionsConfig(
|
config: KeyboardActionsConfig(
|
||||||
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||||
keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
|
keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
|
||||||
nextFocus: false,
|
nextFocus: false,
|
||||||
actions: [
|
actions: [
|
||||||
KeyboardActionsItem(
|
KeyboardActionsItem(
|
||||||
focusNode: _cryptoAmountFocus,
|
focusNode: _cryptoAmountFocus,
|
||||||
toolbarButtons: [(_) => KeyboardDoneButton()],
|
toolbarButtons: [(_) => KeyboardDoneButton()],
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.fromLTRB(24, 50, 24, 24),
|
padding: EdgeInsets.fromLTRB(24, 50, 24, 24),
|
||||||
child: QRWidget(
|
child: QRWidget(
|
||||||
addressListViewModel: addressListViewModel,
|
addressListViewModel: addressListViewModel,
|
||||||
formKey: _formKey,
|
formKey: _formKey,
|
||||||
heroTag: _heroTag,
|
heroTag: _heroTag,
|
||||||
amountTextFieldFocusNode: _cryptoAmountFocus,
|
amountTextFieldFocusNode: _cryptoAmountFocus,
|
||||||
amountController: _amountController,
|
amountController: _amountController,
|
||||||
isLight: currentTheme.type == ThemeType.light),
|
isLight: currentTheme.type == ThemeType.light),
|
||||||
),
|
|
||||||
Observer(
|
|
||||||
builder: (_) => ListView.separated(
|
|
||||||
padding: EdgeInsets.all(0),
|
|
||||||
separatorBuilder: (context, _) => const HorizontalSectionDivider(),
|
|
||||||
shrinkWrap: true,
|
|
||||||
physics: NeverScrollableScrollPhysics(),
|
|
||||||
itemCount: addressListViewModel.items.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final item = addressListViewModel.items[index];
|
|
||||||
Widget cell = Container();
|
|
||||||
|
|
||||||
if (item is WalletAccountListHeader) {
|
|
||||||
cell = HeaderTile(
|
|
||||||
showTrailingButton: true,
|
|
||||||
walletAddressListViewModel: addressListViewModel,
|
|
||||||
trailingButtonTap: () async {
|
|
||||||
if (addressListViewModel.type == WalletType.monero ||
|
|
||||||
addressListViewModel.type == WalletType.haven) {
|
|
||||||
await showPopUp<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => getIt.get<MoneroAccountListPage>());
|
|
||||||
} else {
|
|
||||||
await showPopUp<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => getIt.get<NanoAccountListPage>());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
title: S.of(context).accounts,
|
|
||||||
trailingIcon: Icon(
|
|
||||||
Icons.arrow_forward_ios,
|
|
||||||
size: 14,
|
|
||||||
color: Theme.of(context).extension<ReceivePageTheme>()!.iconsColor,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item is WalletAddressListHeader) {
|
|
||||||
cell = HeaderTile(
|
|
||||||
title: S.of(context).addresses,
|
|
||||||
walletAddressListViewModel: addressListViewModel,
|
|
||||||
showTrailingButton: !addressListViewModel.isAutoGenerateSubaddressEnabled,
|
|
||||||
showSearchButton: true,
|
|
||||||
trailingButtonTap: () =>
|
|
||||||
Navigator.of(context).pushNamed(Routes.newSubaddress),
|
|
||||||
trailingIcon: Icon(
|
|
||||||
Icons.add,
|
|
||||||
size: 20,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.extension<ReceivePageTheme>()!
|
|
||||||
.iconsColor,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item is WalletAddressListItem) {
|
|
||||||
cell = Observer(builder: (_) {
|
|
||||||
final isCurrent =
|
|
||||||
item.address == addressListViewModel.address.address;
|
|
||||||
final backgroundColor = isCurrent
|
|
||||||
? Theme.of(context).extension<ReceivePageTheme>()!.currentTileBackgroundColor
|
|
||||||
: Theme.of(context).extension<ReceivePageTheme>()!.tilesBackgroundColor;
|
|
||||||
final textColor = isCurrent
|
|
||||||
? Theme.of(context).extension<ReceivePageTheme>()!.currentTileTextColor
|
|
||||||
: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor;
|
|
||||||
|
|
||||||
return AddressCell.fromItem(item,
|
|
||||||
isCurrent: isCurrent,
|
|
||||||
hasBalance: addressListViewModel.isElectrumWallet,
|
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
textColor: textColor,
|
|
||||||
onTap: (_) => addressListViewModel.setAddress(item),
|
|
||||||
onEdit: () => Navigator.of(context)
|
|
||||||
.pushNamed(Routes.newSubaddress, arguments: item));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return index != 0
|
|
||||||
? cell
|
|
||||||
: ClipRRect(
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(30),
|
|
||||||
topRight: Radius.circular(30)),
|
|
||||||
child: cell,
|
|
||||||
);
|
|
||||||
})),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
));
|
Observer(
|
||||||
|
builder: (_) => ListView.separated(
|
||||||
|
padding: EdgeInsets.all(0),
|
||||||
|
separatorBuilder: (context, _) => const HorizontalSectionDivider(),
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: addressListViewModel.items.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final item = addressListViewModel.items[index];
|
||||||
|
Widget cell = Container();
|
||||||
|
|
||||||
|
if (item is WalletAccountListHeader) {
|
||||||
|
cell = HeaderTile(
|
||||||
|
showTrailingButton: true,
|
||||||
|
walletAddressListViewModel: addressListViewModel,
|
||||||
|
trailingButtonTap: () async {
|
||||||
|
if (addressListViewModel.type == WalletType.monero ||
|
||||||
|
addressListViewModel.type == WalletType.haven) {
|
||||||
|
await showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => getIt.get<MoneroAccountListPage>());
|
||||||
|
} else {
|
||||||
|
await showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => getIt.get<NanoAccountListPage>());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: S.of(context).accounts,
|
||||||
|
trailingIcon: Icon(
|
||||||
|
Icons.arrow_forward_ios,
|
||||||
|
size: 14,
|
||||||
|
color: Theme.of(context).extension<ReceivePageTheme>()!.iconsColor,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item is WalletAddressListHeader) {
|
||||||
|
final hasTitle = item.title != null;
|
||||||
|
|
||||||
|
cell = HeaderTile(
|
||||||
|
title: hasTitle ? item.title! : S.of(context).addresses,
|
||||||
|
walletAddressListViewModel: addressListViewModel,
|
||||||
|
showTrailingButton:
|
||||||
|
!addressListViewModel.isAutoGenerateSubaddressEnabled && !hasTitle,
|
||||||
|
showSearchButton: true,
|
||||||
|
trailingButtonTap: () =>
|
||||||
|
Navigator.of(context).pushNamed(Routes.newSubaddress),
|
||||||
|
trailingIcon: hasTitle
|
||||||
|
? null
|
||||||
|
: Icon(
|
||||||
|
Icons.add,
|
||||||
|
size: 20,
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<ReceivePageTheme>()!.iconsColor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item is WalletAddressListItem) {
|
||||||
|
cell = Observer(builder: (_) {
|
||||||
|
final isCurrent = item.address == addressListViewModel.address.address;
|
||||||
|
final backgroundColor = isCurrent
|
||||||
|
? Theme.of(context)
|
||||||
|
.extension<ReceivePageTheme>()!
|
||||||
|
.currentTileBackgroundColor
|
||||||
|
: Theme.of(context)
|
||||||
|
.extension<ReceivePageTheme>()!
|
||||||
|
.tilesBackgroundColor;
|
||||||
|
final textColor = isCurrent
|
||||||
|
? Theme.of(context)
|
||||||
|
.extension<ReceivePageTheme>()!
|
||||||
|
.currentTileTextColor
|
||||||
|
: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor;
|
||||||
|
|
||||||
|
return AddressCell.fromItem(
|
||||||
|
item,
|
||||||
|
isCurrent: isCurrent,
|
||||||
|
hasBalance: addressListViewModel.isElectrumWallet,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
textColor: textColor,
|
||||||
|
onTap: item.isOneTimeReceiveAddress == true
|
||||||
|
? null
|
||||||
|
: (_) => addressListViewModel.setAddress(item),
|
||||||
|
onEdit: item.isOneTimeReceiveAddress == true || item.isPrimary
|
||||||
|
? null
|
||||||
|
: () => Navigator.of(context)
|
||||||
|
.pushNamed(Routes.newSubaddress, arguments: item),
|
||||||
|
onDelete: !addressListViewModel.isSilentPayments || item.isPrimary
|
||||||
|
? null
|
||||||
|
: () => addressListViewModel.deleteAddress(item),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return index != 0
|
||||||
|
? cell
|
||||||
|
: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(30), topRight: Radius.circular(30)),
|
||||||
|
child: cell,
|
||||||
|
);
|
||||||
|
})),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
|
||||||
|
child: Text(
|
||||||
|
addressListViewModel.isSilentPayments
|
||||||
|
? S.of(context).silent_payments_disclaimer
|
||||||
|
: S.of(context).electrum_address_disclaimer,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: Theme.of(context).extension<BalancePageTheme>()!.labelTextColor)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,18 +15,22 @@ class AddressCell extends StatelessWidget {
|
||||||
required this.textColor,
|
required this.textColor,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
this.onEdit,
|
this.onEdit,
|
||||||
|
this.onDelete,
|
||||||
this.txCount,
|
this.txCount,
|
||||||
this.balance,
|
this.balance,
|
||||||
this.isChange = false,
|
this.isChange = false,
|
||||||
this.hasBalance = false});
|
this.hasBalance = false});
|
||||||
|
|
||||||
factory AddressCell.fromItem(WalletAddressListItem item,
|
factory AddressCell.fromItem(
|
||||||
{required bool isCurrent,
|
WalletAddressListItem item, {
|
||||||
required Color backgroundColor,
|
required bool isCurrent,
|
||||||
required Color textColor,
|
required Color backgroundColor,
|
||||||
Function(String)? onTap,
|
required Color textColor,
|
||||||
bool hasBalance = false,
|
Function(String)? onTap,
|
||||||
Function()? onEdit}) =>
|
bool hasBalance = false,
|
||||||
|
Function()? onEdit,
|
||||||
|
Function()? onDelete,
|
||||||
|
}) =>
|
||||||
AddressCell(
|
AddressCell(
|
||||||
address: item.address,
|
address: item.address,
|
||||||
name: item.name ?? '',
|
name: item.name ?? '',
|
||||||
|
@ -36,6 +40,7 @@ class AddressCell extends StatelessWidget {
|
||||||
textColor: textColor,
|
textColor: textColor,
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
onEdit: onEdit,
|
onEdit: onEdit,
|
||||||
|
onDelete: onDelete,
|
||||||
txCount: item.txCount,
|
txCount: item.txCount,
|
||||||
balance: item.balance,
|
balance: item.balance,
|
||||||
isChange: item.isChange,
|
isChange: item.isChange,
|
||||||
|
@ -49,6 +54,7 @@ class AddressCell extends StatelessWidget {
|
||||||
final Color textColor;
|
final Color textColor;
|
||||||
final Function(String)? onTap;
|
final Function(String)? onTap;
|
||||||
final Function()? onEdit;
|
final Function()? onEdit;
|
||||||
|
final Function()? onDelete;
|
||||||
final int? txCount;
|
final int? txCount;
|
||||||
final String? balance;
|
final String? balance;
|
||||||
final bool isChange;
|
final bool isChange;
|
||||||
|
@ -64,7 +70,8 @@ class AddressCell extends StatelessWidget {
|
||||||
} else {
|
} else {
|
||||||
return formatIfCashAddr.substring(0, addressPreviewLength) +
|
return formatIfCashAddr.substring(0, addressPreviewLength) +
|
||||||
'...' +
|
'...' +
|
||||||
formatIfCashAddr.substring(formatIfCashAddr.length - addressPreviewLength, formatIfCashAddr.length);
|
formatIfCashAddr.substring(
|
||||||
|
formatIfCashAddr.length - addressPreviewLength, formatIfCashAddr.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +146,7 @@ class AddressCell extends StatelessWidget {
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Balance: $balance',
|
'${S.of(context).balance}: $balance',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
@ -180,7 +187,7 @@ class AddressCell extends StatelessWidget {
|
||||||
|
|
||||||
ActionPane _actionPane(BuildContext context) => ActionPane(
|
ActionPane _actionPane(BuildContext context) => ActionPane(
|
||||||
motion: const ScrollMotion(),
|
motion: const ScrollMotion(),
|
||||||
extentRatio: 0.3,
|
extentRatio: onDelete != null ? 0.4 : 0.3,
|
||||||
children: [
|
children: [
|
||||||
SlidableAction(
|
SlidableAction(
|
||||||
onPressed: (_) => onEdit?.call(),
|
onPressed: (_) => onEdit?.call(),
|
||||||
|
@ -189,6 +196,14 @@ class AddressCell extends StatelessWidget {
|
||||||
icon: Icons.edit,
|
icon: Icons.edit,
|
||||||
label: S.of(context).edit,
|
label: S.of(context).edit,
|
||||||
),
|
),
|
||||||
|
if (onDelete != null)
|
||||||
|
SlidableAction(
|
||||||
|
onPressed: (_) => onDelete!.call(),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
icon: Icons.delete,
|
||||||
|
label: S.of(context).delete,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
|
import 'package:cake_wallet/main.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||||
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
import 'package:cake_wallet/view_model/rescan_view_model.dart';
|
import 'package:cake_wallet/view_model/rescan_view_model.dart';
|
||||||
|
@ -11,7 +15,8 @@ class RescanPage extends BasePage {
|
||||||
: _blockchainHeightWidgetKey = GlobalKey<BlockchainHeightState>();
|
: _blockchainHeightWidgetKey = GlobalKey<BlockchainHeightState>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get title => S.current.rescan;
|
String get title =>
|
||||||
|
_rescanViewModel.isSilentPaymentsScan ? S.current.silent_payments_scanning : S.current.rescan;
|
||||||
final GlobalKey<BlockchainHeightState> _blockchainHeightWidgetKey;
|
final GlobalKey<BlockchainHeightState> _blockchainHeightWidgetKey;
|
||||||
final RescanViewModel _rescanViewModel;
|
final RescanViewModel _rescanViewModel;
|
||||||
|
|
||||||
|
@ -19,20 +24,28 @@ class RescanPage extends BasePage {
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
padding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||||
child:
|
child: Column(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||||
Column(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
Observer(
|
||||||
BlockchainHeightWidget(key: _blockchainHeightWidgetKey,
|
builder: (_) => BlockchainHeightWidget(
|
||||||
onHeightOrDateEntered: (value) =>
|
key: _blockchainHeightWidgetKey,
|
||||||
_rescanViewModel.isButtonEnabled = value),
|
onHeightOrDateEntered: (value) => _rescanViewModel.isButtonEnabled = value,
|
||||||
|
isSilentPaymentsScan: _rescanViewModel.isSilentPaymentsScan,
|
||||||
|
doSingleScan: _rescanViewModel.doSingleScan,
|
||||||
|
toggleSingleScan: () =>
|
||||||
|
_rescanViewModel.doSingleScan = !_rescanViewModel.doSingleScan,
|
||||||
|
)),
|
||||||
Observer(
|
Observer(
|
||||||
builder: (_) => LoadingPrimaryButton(
|
builder: (_) => LoadingPrimaryButton(
|
||||||
isLoading:
|
isLoading: _rescanViewModel.state == RescanWalletState.rescaning,
|
||||||
_rescanViewModel.state == RescanWalletState.rescaning,
|
|
||||||
text: S.of(context).rescan,
|
text: S.of(context).rescan,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await _rescanViewModel.rescanCurrentWallet(
|
if (_rescanViewModel.isSilentPaymentsScan) {
|
||||||
restoreHeight:
|
return _toggleSilentPaymentsScanning(context);
|
||||||
_blockchainHeightWidgetKey.currentState!.height);
|
}
|
||||||
|
|
||||||
|
_rescanViewModel.rescanCurrentWallet(
|
||||||
|
restoreHeight: _blockchainHeightWidgetKey.currentState!.height);
|
||||||
|
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
color: Theme.of(context).primaryColor,
|
color: Theme.of(context).primaryColor,
|
||||||
|
@ -42,4 +55,32 @@ class RescanPage extends BasePage {
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _toggleSilentPaymentsScanning(BuildContext context) async {
|
||||||
|
final height = _blockchainHeightWidgetKey.currentState!.height;
|
||||||
|
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
|
final needsToSwitch =
|
||||||
|
await bitcoin!.getNodeIsElectrsSPEnabled(_rescanViewModel.wallet) == false;
|
||||||
|
|
||||||
|
if (needsToSwitch) {
|
||||||
|
return showPopUp<void>(
|
||||||
|
context: navigatorKey.currentState!.context,
|
||||||
|
builder: (BuildContext _dialogContext) => AlertWithTwoActions(
|
||||||
|
alertTitle: S.of(_dialogContext).change_current_node_title,
|
||||||
|
alertContent: S.of(_dialogContext).confirm_silent_payments_switch_node,
|
||||||
|
rightButtonText: S.of(_dialogContext).ok,
|
||||||
|
leftButtonText: S.of(_dialogContext).cancel,
|
||||||
|
actionRightButton: () async {
|
||||||
|
Navigator.of(_dialogContext).pop();
|
||||||
|
|
||||||
|
_rescanViewModel.rescanCurrentWallet(restoreHeight: height);
|
||||||
|
},
|
||||||
|
actionLeftButton: () => Navigator.of(_dialogContext).pop(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
_rescanViewModel.rescanCurrentWallet(restoreHeight: height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:cake_wallet/core/auth_service.dart';
|
import 'package:cake_wallet/core/auth_service.dart';
|
||||||
import 'package:cake_wallet/entities/contact_record.dart';
|
import 'package:cake_wallet/entities/contact_record.dart';
|
||||||
import 'package:cake_wallet/core/execution_state.dart';
|
import 'package:cake_wallet/core/execution_state.dart';
|
||||||
|
@ -420,6 +421,10 @@ class SendPage extends BasePage {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sendViewModel.isElectrumWallet) {
|
||||||
|
bitcoin!.updateFeeRates(sendViewModel.wallet);
|
||||||
|
}
|
||||||
|
|
||||||
reaction((_) => sendViewModel.state, (ExecutionState state) {
|
reaction((_) => sendViewModel.state, (ExecutionState state) {
|
||||||
if (dialogContext != null && dialogContext?.mounted == true) {
|
if (dialogContext != null && dialogContext?.mounted == true) {
|
||||||
Navigator.of(dialogContext!).pop();
|
Navigator.of(dialogContext!).pop();
|
||||||
|
|
|
@ -39,7 +39,9 @@ class ConnectionSyncPage extends BasePage {
|
||||||
),
|
),
|
||||||
if (dashboardViewModel.hasRescan) ...[
|
if (dashboardViewModel.hasRescan) ...[
|
||||||
SettingsCellWithArrow(
|
SettingsCellWithArrow(
|
||||||
title: S.current.rescan,
|
title: dashboardViewModel.hasSilentPayments
|
||||||
|
? S.current.silent_payments_scanning
|
||||||
|
: S.current.rescan,
|
||||||
handler: (context) => Navigator.of(context).pushNamed(Routes.rescan),
|
handler: (context) => Navigator.of(context).pushNamed(Routes.rescan),
|
||||||
),
|
),
|
||||||
if (DeviceInfo.instance.isMobile && FeatureFlag.isBackgroundSyncEnabled) ...[
|
if (DeviceInfo.instance.isMobile && FeatureFlag.isBackgroundSyncEnabled) ...[
|
||||||
|
|
50
lib/src/screens/settings/silent_payments_settings.dart
Normal file
50
lib/src/screens/settings/silent_payments_settings.dart
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/routes.dart';
|
||||||
|
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_switcher_cell.dart';
|
||||||
|
import 'package:cake_wallet/view_model/settings/silent_payments_settings_view_model.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
|
||||||
|
class SilentPaymentsSettingsPage extends BasePage {
|
||||||
|
SilentPaymentsSettingsPage(this._silentPaymentsSettingsViewModel);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => S.current.silent_payments_settings;
|
||||||
|
|
||||||
|
final SilentPaymentsSettingsViewModel _silentPaymentsSettingsViewModel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget body(BuildContext context) {
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Observer(builder: (_) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.only(top: 10),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SettingsSwitcherCell(
|
||||||
|
title: S.current.silent_payments_display_card,
|
||||||
|
value: _silentPaymentsSettingsViewModel.silentPaymentsCardDisplay,
|
||||||
|
onValueChange: (_, bool value) {
|
||||||
|
_silentPaymentsSettingsViewModel.setSilentPaymentsCardDisplay(value);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SettingsSwitcherCell(
|
||||||
|
title: S.current.silent_payments_always_scan,
|
||||||
|
value: _silentPaymentsSettingsViewModel.silentPaymentsAlwaysScan,
|
||||||
|
onValueChange: (_, bool value) {
|
||||||
|
_silentPaymentsSettingsViewModel.setSilentPaymentsAlwaysScan(value);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SettingsCellWithArrow(
|
||||||
|
title: S.current.silent_payments_scanning,
|
||||||
|
handler: (BuildContext context) => Navigator.of(context).pushNamed(Routes.rescan),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,6 +57,7 @@ class UnspentCoinsListFormState extends State<UnspentCoinsListForm> {
|
||||||
isSending: item.isSending,
|
isSending: item.isSending,
|
||||||
isFrozen: item.isFrozen,
|
isFrozen: item.isFrozen,
|
||||||
isChange: item.isChange,
|
isChange: item.isChange,
|
||||||
|
isSilentPayment: item.isSilentPayment,
|
||||||
onCheckBoxTap: item.isFrozen
|
onCheckBoxTap: item.isFrozen
|
||||||
? null
|
? null
|
||||||
: () async {
|
: () async {
|
||||||
|
|
|
@ -12,6 +12,7 @@ class UnspentCoinsListItem extends StatelessWidget {
|
||||||
required this.isSending,
|
required this.isSending,
|
||||||
required this.isFrozen,
|
required this.isFrozen,
|
||||||
required this.isChange,
|
required this.isChange,
|
||||||
|
required this.isSilentPayment,
|
||||||
this.onCheckBoxTap,
|
this.onCheckBoxTap,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -21,18 +22,16 @@ class UnspentCoinsListItem extends StatelessWidget {
|
||||||
final bool isSending;
|
final bool isSending;
|
||||||
final bool isFrozen;
|
final bool isFrozen;
|
||||||
final bool isChange;
|
final bool isChange;
|
||||||
|
final bool isSilentPayment;
|
||||||
final Function()? onCheckBoxTap;
|
final Function()? onCheckBoxTap;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final unselectedItemColor = Theme.of(context).cardColor;
|
final unselectedItemColor = Theme.of(context).cardColor;
|
||||||
final selectedItemColor = Theme.of(context).primaryColor;
|
final selectedItemColor = Theme.of(context).primaryColor;
|
||||||
final itemColor = isSending
|
final itemColor = isSending ? selectedItemColor : unselectedItemColor;
|
||||||
? selectedItemColor
|
final amountColor =
|
||||||
: unselectedItemColor;
|
isSending ? Colors.white : Theme.of(context).extension<CakeTextTheme>()!.buttonTextColor;
|
||||||
final amountColor = isSending
|
|
||||||
? Colors.white
|
|
||||||
: Theme.of(context).extension<CakeTextTheme>()!.buttonTextColor;
|
|
||||||
final addressColor = isSending
|
final addressColor = isSending
|
||||||
? Colors.white.withOpacity(0.5)
|
? Colors.white.withOpacity(0.5)
|
||||||
: Theme.of(context).extension<CakeTextTheme>()!.buttonSecondaryTextColor;
|
: Theme.of(context).extension<CakeTextTheme>()!.buttonSecondaryTextColor;
|
||||||
|
@ -121,6 +120,23 @@ class UnspentCoinsListItem extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (isSilentPayment)
|
||||||
|
Container(
|
||||||
|
height: 17,
|
||||||
|
padding: EdgeInsets.only(left: 6, right: 6),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(8.5)),
|
||||||
|
color: Colors.white),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Text(
|
||||||
|
S.of(context).silent_payments,
|
||||||
|
style: TextStyle(
|
||||||
|
color: itemColor,
|
||||||
|
fontSize: 7,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -96,6 +96,7 @@ class WalletListBody extends StatefulWidget {
|
||||||
class WalletListBodyState extends State<WalletListBody> {
|
class WalletListBodyState extends State<WalletListBody> {
|
||||||
final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
|
final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
|
||||||
final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
||||||
|
final tBitcoinIcon = Image.asset('assets/images/tbtc.png', height: 24, width: 24);
|
||||||
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
|
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
|
||||||
final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
|
final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
|
||||||
final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
|
final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
|
||||||
|
@ -162,7 +163,10 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
wallet.isEnabled
|
wallet.isEnabled
|
||||||
? _imageFor(type: wallet.type)
|
? _imageFor(
|
||||||
|
type: wallet.type,
|
||||||
|
isTestnet: wallet.isTestnet,
|
||||||
|
)
|
||||||
: nonWalletTypeIcon,
|
: nonWalletTypeIcon,
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
Flexible(
|
Flexible(
|
||||||
|
@ -297,9 +301,12 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Image _imageFor({required WalletType type}) {
|
Image _imageFor({required WalletType type, bool? isTestnet}) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
|
if (isTestnet == true) {
|
||||||
|
return tBitcoinIcon;
|
||||||
|
}
|
||||||
return bitcoinIcon;
|
return bitcoinIcon;
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
return moneroIcon;
|
return moneroIcon;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/standard_switch.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||||
import 'package:cake_wallet/utils/date_picker.dart';
|
import 'package:cake_wallet/utils/date_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -12,13 +14,19 @@ class BlockchainHeightWidget extends StatefulWidget {
|
||||||
this.onHeightChange,
|
this.onHeightChange,
|
||||||
this.focusNode,
|
this.focusNode,
|
||||||
this.onHeightOrDateEntered,
|
this.onHeightOrDateEntered,
|
||||||
this.hasDatePicker = true})
|
this.hasDatePicker = true,
|
||||||
: super(key: key);
|
this.isSilentPaymentsScan = false,
|
||||||
|
this.toggleSingleScan,
|
||||||
|
this.doSingleScan = false,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
final Function(int)? onHeightChange;
|
final Function(int)? onHeightChange;
|
||||||
final Function(bool)? onHeightOrDateEntered;
|
final Function(bool)? onHeightOrDateEntered;
|
||||||
final FocusNode? focusNode;
|
final FocusNode? focusNode;
|
||||||
final bool hasDatePicker;
|
final bool hasDatePicker;
|
||||||
|
final bool isSilentPaymentsScan;
|
||||||
|
final bool doSingleScan;
|
||||||
|
final Function()? toggleSingleScan;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() => BlockchainHeightState();
|
State<StatefulWidget> createState() => BlockchainHeightState();
|
||||||
|
@ -64,9 +72,10 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
|
||||||
child: BaseTextFormField(
|
child: BaseTextFormField(
|
||||||
focusNode: widget.focusNode,
|
focusNode: widget.focusNode,
|
||||||
controller: restoreHeightController,
|
controller: restoreHeightController,
|
||||||
keyboardType: TextInputType.numberWithOptions(
|
keyboardType: TextInputType.numberWithOptions(signed: false, decimal: false),
|
||||||
signed: false, decimal: false),
|
hintText: widget.isSilentPaymentsScan
|
||||||
hintText: S.of(context).widgets_restore_from_blockheight,
|
? S.of(context).silent_payments_scan_from_height
|
||||||
|
: S.of(context).widgets_restore_from_blockheight,
|
||||||
)))
|
)))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -78,8 +87,7 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16.0,
|
fontSize: 16.0,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color:
|
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
|
||||||
Theme.of(context).extension<CakeTextTheme>()!.titleColor),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
|
@ -91,22 +99,47 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
|
||||||
child: IgnorePointer(
|
child: IgnorePointer(
|
||||||
child: BaseTextFormField(
|
child: BaseTextFormField(
|
||||||
controller: dateController,
|
controller: dateController,
|
||||||
hintText: S.of(context).widgets_restore_from_date,
|
hintText: widget.isSilentPaymentsScan
|
||||||
|
? S.of(context).silent_payments_scan_from_date
|
||||||
|
: S.of(context).widgets_restore_from_date,
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
if (widget.isSilentPaymentsScan)
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: 24),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
S.of(context).scan_one_block,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 8),
|
||||||
|
child: StandardSwitch(
|
||||||
|
value: widget.doSingleScan,
|
||||||
|
onTaped: () => widget.toggleSingleScan?.call(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(left: 40, right: 40, top: 24),
|
padding: EdgeInsets.only(left: 40, right: 40, top: 24),
|
||||||
child: Text(
|
child: Text(
|
||||||
S.of(context).restore_from_date_or_blockheight,
|
widget.isSilentPaymentsScan
|
||||||
|
? S.of(context).silent_payments_scan_from_date_or_blockheight
|
||||||
|
: S.of(context).restore_from_date_or_blockheight,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12, fontWeight: FontWeight.normal, color: Theme.of(context).hintColor),
|
||||||
fontWeight: FontWeight.normal,
|
|
||||||
color: Theme.of(context).hintColor
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
@ -123,7 +156,12 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
|
||||||
lastDate: now);
|
lastDate: now);
|
||||||
|
|
||||||
if (date != null) {
|
if (date != null) {
|
||||||
final height = monero!.getHeightByDate(date: date);
|
int height;
|
||||||
|
if (widget.isSilentPaymentsScan) {
|
||||||
|
height = bitcoin!.getHeightByDate(date: date);
|
||||||
|
} else {
|
||||||
|
height = monero!.getHeightByDate(date: date);
|
||||||
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
dateController.text = DateFormat('yyyy-MM-dd').format(date);
|
dateController.text = DateFormat('yyyy-MM-dd').format(date);
|
||||||
restoreHeightController.text = '$height';
|
restoreHeightController.text = '$height';
|
||||||
|
|
|
@ -2,19 +2,28 @@ import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
|
||||||
class DashBoardRoundedCardWidget extends StatelessWidget {
|
class DashBoardRoundedCardWidget extends StatelessWidget {
|
||||||
DashBoardRoundedCardWidget({
|
DashBoardRoundedCardWidget({
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.subTitle,
|
required this.subTitle,
|
||||||
|
this.hint,
|
||||||
|
this.svgPicture,
|
||||||
|
this.icon,
|
||||||
this.onClose,
|
this.onClose,
|
||||||
|
this.customBorder,
|
||||||
});
|
});
|
||||||
|
|
||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
final VoidCallback? onClose;
|
final VoidCallback? onClose;
|
||||||
final String title;
|
final String title;
|
||||||
final String subTitle;
|
final String subTitle;
|
||||||
|
final Widget? hint;
|
||||||
|
final SvgPicture? svgPicture;
|
||||||
|
final Icon? icon;
|
||||||
|
final double? customBorder;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -26,34 +35,56 @@ class DashBoardRoundedCardWidget extends StatelessWidget {
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.fromLTRB(20, 20, 40, 20),
|
padding: EdgeInsets.all(20),
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
|
color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(customBorder ?? 20),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
|
color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Row(
|
||||||
title,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
style: TextStyle(
|
children: [
|
||||||
color: Theme.of(context).extension<DashboardPageTheme>()!.cardTextColor,
|
Expanded(
|
||||||
fontSize: 24,
|
child: Column(
|
||||||
fontWeight: FontWeight.w900,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
),
|
children: [
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<DashboardPageTheme>()!.cardTextColor,
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.w900,
|
||||||
|
),
|
||||||
|
softWrap: true,
|
||||||
|
),
|
||||||
|
SizedBox(height: 5),
|
||||||
|
Text(
|
||||||
|
subTitle,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<DashboardPageTheme>()!
|
||||||
|
.cardTextColor,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
fontFamily: 'Lato'),
|
||||||
|
softWrap: true,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (svgPicture != null) svgPicture!,
|
||||||
|
if (icon != null) icon!
|
||||||
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
if (hint != null) ...[
|
||||||
Text(
|
SizedBox(height: 10),
|
||||||
subTitle,
|
hint!,
|
||||||
style: TextStyle(
|
]
|
||||||
color: Theme.of(context).extension<DashboardPageTheme>()!.cardTextColor,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
fontFamily: 'Lato'),
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -17,6 +17,7 @@ class SettingActions {
|
||||||
connectionSettingAction,
|
connectionSettingAction,
|
||||||
walletSettingAction,
|
walletSettingAction,
|
||||||
addressBookSettingAction,
|
addressBookSettingAction,
|
||||||
|
silentPaymentsSettingAction,
|
||||||
securityBackupSettingAction,
|
securityBackupSettingAction,
|
||||||
privacySettingAction,
|
privacySettingAction,
|
||||||
displaySettingAction,
|
displaySettingAction,
|
||||||
|
@ -35,6 +36,15 @@ class SettingActions {
|
||||||
supportSettingAction,
|
supportSettingAction,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
static SettingActions silentPaymentsSettingAction = SettingActions._(
|
||||||
|
name: (context) => S.of(context).silent_payments_settings,
|
||||||
|
image: 'assets/images/bitcoin_menu.png',
|
||||||
|
onTap: (BuildContext context) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
Navigator.of(context).pushNamed(Routes.silentPaymentsSettings);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
static SettingActions connectionSettingAction = SettingActions._(
|
static SettingActions connectionSettingAction = SettingActions._(
|
||||||
name: (context) => S.of(context).connection_sync,
|
name: (context) => S.of(context).connection_sync,
|
||||||
image: 'assets/images/nodes_menu.png',
|
image: 'assets/images/nodes_menu.png',
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||||
import 'package:cake_wallet/core/secure_storage.dart';
|
import 'package:cake_wallet/core/secure_storage.dart';
|
||||||
|
@ -108,6 +107,8 @@ abstract class SettingsStoreBase with Store {
|
||||||
required this.lookupsOpenAlias,
|
required this.lookupsOpenAlias,
|
||||||
required this.lookupsENS,
|
required this.lookupsENS,
|
||||||
required this.customBitcoinFeeRate,
|
required this.customBitcoinFeeRate,
|
||||||
|
required this.silentPaymentsCardDisplay,
|
||||||
|
required this.silentPaymentsAlwaysScan,
|
||||||
TransactionPriority? initialBitcoinTransactionPriority,
|
TransactionPriority? initialBitcoinTransactionPriority,
|
||||||
TransactionPriority? initialMoneroTransactionPriority,
|
TransactionPriority? initialMoneroTransactionPriority,
|
||||||
TransactionPriority? initialHavenTransactionPriority,
|
TransactionPriority? initialHavenTransactionPriority,
|
||||||
|
@ -518,6 +519,16 @@ abstract class SettingsStoreBase with Store {
|
||||||
(int customBitcoinFeeRate) =>
|
(int customBitcoinFeeRate) =>
|
||||||
_sharedPreferences.setInt(PreferencesKey.customBitcoinFeeRate, customBitcoinFeeRate));
|
_sharedPreferences.setInt(PreferencesKey.customBitcoinFeeRate, customBitcoinFeeRate));
|
||||||
|
|
||||||
|
reaction((_) => silentPaymentsCardDisplay, (bool silentPaymentsCardDisplay) {
|
||||||
|
_sharedPreferences.setBool(
|
||||||
|
PreferencesKey.silentPaymentsCardDisplay, silentPaymentsCardDisplay);
|
||||||
|
});
|
||||||
|
|
||||||
|
reaction(
|
||||||
|
(_) => silentPaymentsAlwaysScan,
|
||||||
|
(bool silentPaymentsAlwaysScan) => _sharedPreferences.setBool(
|
||||||
|
PreferencesKey.silentPaymentsAlwaysScan, silentPaymentsAlwaysScan));
|
||||||
|
|
||||||
this.nodes.observe((change) {
|
this.nodes.observe((change) {
|
||||||
if (change.newValue != null && change.key != null) {
|
if (change.newValue != null && change.key != null) {
|
||||||
_saveCurrentNode(change.newValue!, change.key!);
|
_saveCurrentNode(change.newValue!, change.key!);
|
||||||
|
@ -713,6 +724,12 @@ abstract class SettingsStoreBase with Store {
|
||||||
@observable
|
@observable
|
||||||
int customBitcoinFeeRate;
|
int customBitcoinFeeRate;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
bool silentPaymentsCardDisplay;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
bool silentPaymentsAlwaysScan;
|
||||||
|
|
||||||
final SecureStorage _secureStorage;
|
final SecureStorage _secureStorage;
|
||||||
final SharedPreferences _sharedPreferences;
|
final SharedPreferences _sharedPreferences;
|
||||||
final BackgroundTasks _backgroundTasks;
|
final BackgroundTasks _backgroundTasks;
|
||||||
|
@ -859,6 +876,10 @@ abstract class SettingsStoreBase with Store {
|
||||||
final lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true;
|
final lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true;
|
||||||
final lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true;
|
final lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true;
|
||||||
final customBitcoinFeeRate = sharedPreferences.getInt(PreferencesKey.customBitcoinFeeRate) ?? 1;
|
final customBitcoinFeeRate = sharedPreferences.getInt(PreferencesKey.customBitcoinFeeRate) ?? 1;
|
||||||
|
final silentPaymentsCardDisplay =
|
||||||
|
sharedPreferences.getBool(PreferencesKey.silentPaymentsCardDisplay) ?? true;
|
||||||
|
final silentPaymentsAlwaysScan =
|
||||||
|
sharedPreferences.getBool(PreferencesKey.silentPaymentsAlwaysScan) ?? false;
|
||||||
|
|
||||||
// If no value
|
// If no value
|
||||||
if (pinLength == null || pinLength == 0) {
|
if (pinLength == null || pinLength == 0) {
|
||||||
|
@ -1103,6 +1124,8 @@ abstract class SettingsStoreBase with Store {
|
||||||
lookupsOpenAlias: lookupsOpenAlias,
|
lookupsOpenAlias: lookupsOpenAlias,
|
||||||
lookupsENS: lookupsENS,
|
lookupsENS: lookupsENS,
|
||||||
customBitcoinFeeRate: customBitcoinFeeRate,
|
customBitcoinFeeRate: customBitcoinFeeRate,
|
||||||
|
silentPaymentsCardDisplay: silentPaymentsCardDisplay,
|
||||||
|
silentPaymentsAlwaysScan: silentPaymentsAlwaysScan,
|
||||||
initialMoneroTransactionPriority: moneroTransactionPriority,
|
initialMoneroTransactionPriority: moneroTransactionPriority,
|
||||||
initialBitcoinTransactionPriority: bitcoinTransactionPriority,
|
initialBitcoinTransactionPriority: bitcoinTransactionPriority,
|
||||||
initialHavenTransactionPriority: havenTransactionPriority,
|
initialHavenTransactionPriority: havenTransactionPriority,
|
||||||
|
@ -1242,6 +1265,10 @@ abstract class SettingsStoreBase with Store {
|
||||||
lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true;
|
lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true;
|
||||||
lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true;
|
lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true;
|
||||||
customBitcoinFeeRate = sharedPreferences.getInt(PreferencesKey.customBitcoinFeeRate) ?? 1;
|
customBitcoinFeeRate = sharedPreferences.getInt(PreferencesKey.customBitcoinFeeRate) ?? 1;
|
||||||
|
silentPaymentsCardDisplay =
|
||||||
|
sharedPreferences.getBool(PreferencesKey.silentPaymentsCardDisplay) ?? true;
|
||||||
|
silentPaymentsAlwaysScan =
|
||||||
|
sharedPreferences.getBool(PreferencesKey.silentPaymentsAlwaysScan) ?? false;
|
||||||
final nodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
|
final nodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
|
||||||
final bitcoinElectrumServerId =
|
final bitcoinElectrumServerId =
|
||||||
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
|
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
||||||
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
||||||
import 'package:cake_wallet/entities/contact_base.dart';
|
import 'package:cake_wallet/entities/contact_base.dart';
|
||||||
import 'package:cake_wallet/entities/wallet_contact.dart';
|
import 'package:cake_wallet/entities/wallet_contact.dart';
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
@ -40,16 +41,19 @@ abstract class ContactListViewModelBase with Store {
|
||||||
});
|
});
|
||||||
} else if (info.addresses?.isNotEmpty == true) {
|
} else if (info.addresses?.isNotEmpty == true) {
|
||||||
info.addresses!.forEach((address, label) {
|
info.addresses!.forEach((address, label) {
|
||||||
|
if (label.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
final name = _createName(info.name, label);
|
final name = _createName(info.name, label);
|
||||||
walletContacts.add(WalletContact(
|
walletContacts.add(WalletContact(
|
||||||
address,
|
address,
|
||||||
name,
|
name,
|
||||||
walletTypeToCryptoCurrency(info.type),
|
walletTypeToCryptoCurrency(info.type,
|
||||||
|
isTestnet:
|
||||||
|
info.network == null ? false : info.network!.toLowerCase().contains("testnet")),
|
||||||
));
|
));
|
||||||
// Only one contact address per wallet
|
|
||||||
return;
|
|
||||||
});
|
});
|
||||||
} else if (info.address != null) {
|
} else {
|
||||||
walletContacts.add(WalletContact(
|
walletContacts.add(WalletContact(
|
||||||
info.address,
|
info.address,
|
||||||
info.name,
|
info.name,
|
||||||
|
@ -64,7 +68,9 @@ abstract class ContactListViewModelBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
String _createName(String walletName, String label) {
|
String _createName(String walletName, String label) {
|
||||||
return label.isNotEmpty ? '$walletName ($label)' : walletName;
|
return label.isNotEmpty
|
||||||
|
? '$walletName (${label.replaceAll(RegExp(r'active', caseSensitive: false), S.current.active).replaceAll(RegExp(r'silent payments', caseSensitive: false), S.current.silent_payments)})'
|
||||||
|
: walletName;
|
||||||
}
|
}
|
||||||
|
|
||||||
final bool isAutoGenerateEnabled;
|
final bool isAutoGenerateEnabled;
|
||||||
|
|
|
@ -60,6 +60,9 @@ abstract class BalanceViewModelBase with Store {
|
||||||
@observable
|
@observable
|
||||||
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet;
|
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
bool get hasSilentPayments => wallet.type == WalletType.bitcoin;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
double get price {
|
double get price {
|
||||||
final price = fiatConvertationStore.prices[appStore.wallet!.currency];
|
final price = fiatConvertationStore.prices[appStore.wallet!.currency];
|
||||||
|
|
16
lib/view_model/dashboard/cake_features_view_model.dart
Normal file
16
lib/view_model/dashboard/cake_features_view_model.dart
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import 'package:cake_wallet/ionia/ionia_service.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
part 'cake_features_view_model.g.dart';
|
||||||
|
|
||||||
|
class CakeFeaturesViewModel = CakeFeaturesViewModelBase with _$CakeFeaturesViewModel;
|
||||||
|
|
||||||
|
abstract class CakeFeaturesViewModelBase with Store {
|
||||||
|
final IoniaService _ioniaService;
|
||||||
|
|
||||||
|
CakeFeaturesViewModelBase(this._ioniaService);
|
||||||
|
|
||||||
|
Future<bool> isIoniaUserAuthenticated() async {
|
||||||
|
return await _ioniaService.isLogined();
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,6 +45,7 @@ import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:eth_sig_util/util/utils.dart';
|
import 'package:eth_sig_util/util/utils.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
@ -201,6 +202,14 @@ abstract class DashboardViewModelBase with Store {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (hasSilentPayments) {
|
||||||
|
silentPaymentsScanningActive = bitcoin!.getScanningActive(wallet);
|
||||||
|
|
||||||
|
reaction((_) => wallet.syncStatus, (SyncStatus syncStatus) {
|
||||||
|
silentPaymentsScanningActive = bitcoin!.getScanningActive(wallet);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
|
@ -287,11 +296,36 @@ abstract class DashboardViewModelBase with Store {
|
||||||
@observable
|
@observable
|
||||||
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet;
|
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet;
|
||||||
|
|
||||||
bool get hasRescan => wallet.type == WalletType.monero || wallet.type == WalletType.haven;
|
@computed
|
||||||
|
bool get isTestnet => wallet.type == WalletType.bitcoin && bitcoin!.isTestnet(wallet);
|
||||||
|
|
||||||
|
@computed
|
||||||
|
bool get hasRescan =>
|
||||||
|
wallet.type == WalletType.bitcoin ||
|
||||||
|
wallet.type == WalletType.monero ||
|
||||||
|
wallet.type == WalletType.haven;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
bool get hasSilentPayments => wallet.type == WalletType.bitcoin;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
bool get showSilentPaymentsCard => hasSilentPayments && settingsStore.silentPaymentsCardDisplay;
|
||||||
|
|
||||||
final KeyService keyService;
|
final KeyService keyService;
|
||||||
final SharedPreferences sharedPreferences;
|
final SharedPreferences sharedPreferences;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
bool silentPaymentsScanningActive = false;
|
||||||
|
|
||||||
|
@action
|
||||||
|
void setSilentPaymentsScanning(bool active) {
|
||||||
|
silentPaymentsScanningActive = active;
|
||||||
|
|
||||||
|
if (hasSilentPayments) {
|
||||||
|
bitcoin!.setScanningActive(wallet, active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BalanceViewModel balanceViewModel;
|
BalanceViewModel balanceViewModel;
|
||||||
|
|
||||||
AppStore appStore;
|
AppStore appStore;
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
import 'package:cake_wallet/ionia/ionia_service.dart';
|
|
||||||
import 'package:mobx/mobx.dart';
|
|
||||||
|
|
||||||
part 'market_place_view_model.g.dart';
|
|
||||||
|
|
||||||
class MarketPlaceViewModel = MarketPlaceViewModelBase with _$MarketPlaceViewModel;
|
|
||||||
|
|
||||||
abstract class MarketPlaceViewModelBase with Store {
|
|
||||||
final IoniaService _ioniaService;
|
|
||||||
|
|
||||||
MarketPlaceViewModelBase(this._ioniaService);
|
|
||||||
|
|
||||||
|
|
||||||
Future<bool> isIoniaUserAuthenticated() async {
|
|
||||||
return await _ioniaService.isLogined();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
part 'rescan_view_model.g.dart';
|
part 'rescan_view_model.g.dart';
|
||||||
|
@ -8,11 +10,12 @@ class RescanViewModel = RescanViewModelBase with _$RescanViewModel;
|
||||||
enum RescanWalletState { rescaning, none }
|
enum RescanWalletState { rescaning, none }
|
||||||
|
|
||||||
abstract class RescanViewModelBase with Store {
|
abstract class RescanViewModelBase with Store {
|
||||||
RescanViewModelBase(this._wallet)
|
RescanViewModelBase(this.wallet)
|
||||||
: state = RescanWalletState.none,
|
: state = RescanWalletState.none,
|
||||||
isButtonEnabled = false;
|
isButtonEnabled = false,
|
||||||
|
doSingleScan = false;
|
||||||
|
|
||||||
final WalletBase _wallet;
|
final WalletBase wallet;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
RescanWalletState state;
|
RescanWalletState state;
|
||||||
|
@ -20,11 +23,21 @@ abstract class RescanViewModelBase with Store {
|
||||||
@observable
|
@observable
|
||||||
bool isButtonEnabled;
|
bool isButtonEnabled;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
bool doSingleScan;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
bool get isSilentPaymentsScan => wallet.type == WalletType.bitcoin;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> rescanCurrentWallet({required int restoreHeight}) async {
|
Future<void> rescanCurrentWallet({required int restoreHeight}) async {
|
||||||
state = RescanWalletState.rescaning;
|
state = RescanWalletState.rescaning;
|
||||||
await _wallet.rescan(height: restoreHeight);
|
if (wallet.type != WalletType.bitcoin) {
|
||||||
_wallet.transactionHistory.clear();
|
wallet.rescan(height: restoreHeight);
|
||||||
|
wallet.transactionHistory.clear();
|
||||||
|
} else {
|
||||||
|
bitcoin!.rescan(wallet, height: restoreHeight, doSingleScan: doSingleScan);
|
||||||
|
}
|
||||||
state = RescanWalletState.none;
|
state = RescanWalletState.none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,7 +229,10 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
isFiatDisabled ? '' : pendingTransactionFeeFiatAmount + ' ' + fiat.title;
|
isFiatDisabled ? '' : pendingTransactionFeeFiatAmount + ' ' + fiat.title;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get isReadyForSend => wallet.syncStatus is SyncedSyncStatus;
|
bool get isReadyForSend =>
|
||||||
|
wallet.syncStatus is SyncedSyncStatus ||
|
||||||
|
// If silent payments scanning, can still send payments
|
||||||
|
(wallet.type == WalletType.bitcoin && wallet.syncStatus is SyncingSyncStatus);
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
List<Template> get templates => sendTemplateViewModel.templates
|
List<Template> get templates => sendTemplateViewModel.templates
|
||||||
|
@ -599,6 +602,10 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
walletType == WalletType.litecoin ||
|
walletType == WalletType.litecoin ||
|
||||||
walletType == WalletType.bitcoinCash) {
|
walletType == WalletType.bitcoinCash) {
|
||||||
if (error is TransactionWrongBalanceException) {
|
if (error is TransactionWrongBalanceException) {
|
||||||
|
if (error.amount != null)
|
||||||
|
return S.current
|
||||||
|
.tx_wrong_balance_with_amount_exception(currency.toString(), error.amount.toString());
|
||||||
|
|
||||||
return S.current.tx_wrong_balance_exception(currency.toString());
|
return S.current.tx_wrong_balance_exception(currency.toString());
|
||||||
}
|
}
|
||||||
if (error is TransactionNoInputsException) {
|
if (error is TransactionNoInputsException) {
|
||||||
|
@ -625,9 +632,15 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
if (error is TransactionCommitFailedVoutNegative) {
|
if (error is TransactionCommitFailedVoutNegative) {
|
||||||
return S.current.tx_rejected_vout_negative;
|
return S.current.tx_rejected_vout_negative;
|
||||||
}
|
}
|
||||||
|
if (error is TransactionCommitFailedBIP68Final) {
|
||||||
|
return S.current.tx_rejected_bip68_final;
|
||||||
|
}
|
||||||
if (error is TransactionNoDustOnChangeException) {
|
if (error is TransactionNoDustOnChangeException) {
|
||||||
return S.current.tx_commit_exception_no_dust_on_change(error.min, error.max);
|
return S.current.tx_commit_exception_no_dust_on_change(error.min, error.max);
|
||||||
}
|
}
|
||||||
|
if (error is TransactionInputNotSupported) {
|
||||||
|
return S.current.tx_invalid_input;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return errorMessage;
|
return errorMessage;
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
part 'silent_payments_settings_view_model.g.dart';
|
||||||
|
|
||||||
|
class SilentPaymentsSettingsViewModel = SilentPaymentsSettingsViewModelBase
|
||||||
|
with _$SilentPaymentsSettingsViewModel;
|
||||||
|
|
||||||
|
abstract class SilentPaymentsSettingsViewModelBase with Store {
|
||||||
|
SilentPaymentsSettingsViewModelBase(this._settingsStore, this._wallet);
|
||||||
|
|
||||||
|
final SettingsStore _settingsStore;
|
||||||
|
final WalletBase _wallet;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
bool get silentPaymentsCardDisplay => _settingsStore.silentPaymentsCardDisplay;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
bool get silentPaymentsAlwaysScan => _settingsStore.silentPaymentsAlwaysScan;
|
||||||
|
|
||||||
|
@action
|
||||||
|
void setSilentPaymentsCardDisplay(bool value) {
|
||||||
|
_settingsStore.silentPaymentsCardDisplay = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
void setSilentPaymentsAlwaysScan(bool value) {
|
||||||
|
_settingsStore.silentPaymentsAlwaysScan = value;
|
||||||
|
if (value) bitcoin!.setScanningActive(_wallet, true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,8 @@ abstract class UnspentCoinsItemBase with Store {
|
||||||
required this.isChange,
|
required this.isChange,
|
||||||
required this.amountRaw,
|
required this.amountRaw,
|
||||||
required this.vout,
|
required this.vout,
|
||||||
required this.keyImage
|
required this.keyImage,
|
||||||
|
required this.isSilentPayment,
|
||||||
});
|
});
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
|
@ -47,4 +48,7 @@ abstract class UnspentCoinsItemBase with Store {
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
String? keyImage;
|
String? keyImage;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
bool isSilentPayment;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:cake_wallet/monero/monero.dart';
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
|
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||||
import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_item.dart';
|
import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_item.dart';
|
||||||
import 'package:cw_core/unspent_coins_info.dart';
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
import 'package:cw_core/unspent_transaction_output.dart';
|
import 'package:cw_core/unspent_transaction_output.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
@ -86,22 +88,33 @@ abstract class UnspentCoinsListViewModelBase with Store {
|
||||||
@action
|
@action
|
||||||
void _updateUnspentCoinsInfo() {
|
void _updateUnspentCoinsInfo() {
|
||||||
_items.clear();
|
_items.clear();
|
||||||
_items.addAll(_getUnspents().map((elem) {
|
|
||||||
final info =
|
|
||||||
getUnspentCoinInfo(elem.hash, elem.address, elem.value, elem.vout, elem.keyImage);
|
|
||||||
|
|
||||||
return UnspentCoinsItem(
|
List<UnspentCoinsItem> unspents = [];
|
||||||
address: elem.address,
|
_getUnspents().forEach((elem) {
|
||||||
amount: '${formatAmountToString(elem.value)} ${wallet.currency.title}',
|
try {
|
||||||
hash: elem.hash,
|
final info =
|
||||||
isFrozen: info.isFrozen,
|
getUnspentCoinInfo(elem.hash, elem.address, elem.value, elem.vout, elem.keyImage);
|
||||||
note: info.note,
|
|
||||||
isSending: info.isSending,
|
unspents.add(UnspentCoinsItem(
|
||||||
amountRaw: elem.value,
|
address: elem.address,
|
||||||
vout: elem.vout,
|
amount: '${formatAmountToString(elem.value)} ${wallet.currency.title}',
|
||||||
keyImage: elem.keyImage,
|
hash: elem.hash,
|
||||||
isChange: elem.isChange,
|
isFrozen: info.isFrozen,
|
||||||
);
|
note: info.note,
|
||||||
}));
|
isSending: info.isSending,
|
||||||
|
amountRaw: elem.value,
|
||||||
|
vout: elem.vout,
|
||||||
|
keyImage: elem.keyImage,
|
||||||
|
isChange: elem.isChange,
|
||||||
|
isSilentPayment: info.isSilentPayment ?? false,
|
||||||
|
));
|
||||||
|
} catch (e, s) {
|
||||||
|
print(s);
|
||||||
|
print(e.toString());
|
||||||
|
ExceptionHandler.onError(FlutterErrorDetails(exception: e, stack: s));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_items.addAll(unspents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
import 'package:cake_wallet/utils/list_item.dart';
|
import 'package:cake_wallet/utils/list_item.dart';
|
||||||
|
|
||||||
class WalletAddressListHeader extends ListItem {}
|
class WalletAddressListHeader extends ListItem {
|
||||||
|
final String? title;
|
||||||
|
WalletAddressListHeader({this.title});
|
||||||
|
}
|
||||||
|
|
|
@ -8,8 +8,10 @@ class WalletAddressListItem extends ListItem {
|
||||||
this.name,
|
this.name,
|
||||||
this.txCount,
|
this.txCount,
|
||||||
this.balance,
|
this.balance,
|
||||||
this.isChange = false})
|
this.isChange = false,
|
||||||
: super();
|
// Address that is only ever used once, shouldn't be used to receive funds, copy and paste, share etc
|
||||||
|
this.isOneTimeReceiveAddress = false,
|
||||||
|
}) : super();
|
||||||
|
|
||||||
final int? id;
|
final int? id;
|
||||||
final bool isPrimary;
|
final bool isPrimary;
|
||||||
|
@ -18,7 +20,8 @@ class WalletAddressListItem extends ListItem {
|
||||||
final int? txCount;
|
final int? txCount;
|
||||||
final String? balance;
|
final String? balance;
|
||||||
final bool isChange;
|
final bool isChange;
|
||||||
|
final bool? isOneTimeReceiveAddress;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => name ?? address;
|
String toString() => name ?? address;
|
||||||
}
|
}
|
||||||
|
|
|
@ -334,20 +334,55 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isElectrumWallet) {
|
if (isElectrumWallet) {
|
||||||
final addressItems = bitcoin!.getSubAddresses(wallet).map((subaddress) {
|
if (bitcoin!.hasSelectedSilentPayments(wallet)) {
|
||||||
final isPrimary = subaddress.id == 0;
|
final addressItems = bitcoin!.getSilentPaymentAddresses(wallet).map((address) {
|
||||||
|
final isPrimary = address.id == 0;
|
||||||
|
|
||||||
return WalletAddressListItem(
|
return WalletAddressListItem(
|
||||||
id: subaddress.id,
|
id: address.id,
|
||||||
isPrimary: isPrimary,
|
isPrimary: isPrimary,
|
||||||
name: subaddress.name,
|
name: address.name,
|
||||||
address: subaddress.address,
|
address: address.address,
|
||||||
txCount: subaddress.txCount,
|
txCount: address.txCount,
|
||||||
balance: AmountConverter.amountIntToString(
|
balance: AmountConverter.amountIntToString(
|
||||||
walletTypeToCryptoCurrency(type), subaddress.balance),
|
walletTypeToCryptoCurrency(type), address.balance),
|
||||||
isChange: subaddress.isChange);
|
isChange: address.isChange,
|
||||||
});
|
);
|
||||||
addressList.addAll(addressItems);
|
});
|
||||||
|
addressList.addAll(addressItems);
|
||||||
|
addressList.add(WalletAddressListHeader(title: S.current.received));
|
||||||
|
|
||||||
|
final receivedAddressItems =
|
||||||
|
bitcoin!.getSilentPaymentReceivedAddresses(wallet).map((address) {
|
||||||
|
return WalletAddressListItem(
|
||||||
|
id: address.id,
|
||||||
|
isPrimary: false,
|
||||||
|
name: address.name,
|
||||||
|
address: address.address,
|
||||||
|
txCount: address.txCount,
|
||||||
|
balance: AmountConverter.amountIntToString(
|
||||||
|
walletTypeToCryptoCurrency(type), address.balance),
|
||||||
|
isChange: address.isChange,
|
||||||
|
isOneTimeReceiveAddress: true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
addressList.addAll(receivedAddressItems);
|
||||||
|
} else {
|
||||||
|
final addressItems = bitcoin!.getSubAddresses(wallet).map((subaddress) {
|
||||||
|
final isPrimary = subaddress.id == 0;
|
||||||
|
|
||||||
|
return WalletAddressListItem(
|
||||||
|
id: subaddress.id,
|
||||||
|
isPrimary: isPrimary,
|
||||||
|
name: subaddress.name,
|
||||||
|
address: subaddress.address,
|
||||||
|
txCount: subaddress.txCount,
|
||||||
|
balance: AmountConverter.amountIntToString(
|
||||||
|
walletTypeToCryptoCurrency(type), subaddress.balance),
|
||||||
|
isChange: subaddress.isChange);
|
||||||
|
});
|
||||||
|
addressList.addAll(addressItems);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wallet.type == WalletType.ethereum) {
|
if (wallet.type == WalletType.ethereum) {
|
||||||
|
@ -416,9 +451,14 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
|
||||||
wallet.type == WalletType.litecoin ||
|
wallet.type == WalletType.litecoin ||
|
||||||
wallet.type == WalletType.bitcoinCash;
|
wallet.type == WalletType.bitcoinCash;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
bool get isSilentPayments =>
|
||||||
|
wallet.type == WalletType.bitcoin && bitcoin!.hasSelectedSilentPayments(wallet);
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get isAutoGenerateSubaddressEnabled =>
|
bool get isAutoGenerateSubaddressEnabled =>
|
||||||
_settingsStore.autoGenerateSubaddressStatus != AutoGenerateSubaddressStatus.disabled;
|
_settingsStore.autoGenerateSubaddressStatus != AutoGenerateSubaddressStatus.disabled &&
|
||||||
|
!isSilentPayments;
|
||||||
|
|
||||||
List<ListItem> _baseItems;
|
List<ListItem> _baseItems;
|
||||||
|
|
||||||
|
@ -479,4 +519,11 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
|
||||||
amount = '';
|
amount = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
void deleteAddress(ListItem item) {
|
||||||
|
if (wallet.type == WalletType.bitcoin && item is WalletAddressListItem) {
|
||||||
|
bitcoin!.deleteSilentPaymentAddress(wallet, item.address);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ class WalletListItem {
|
||||||
required this.key,
|
required this.key,
|
||||||
this.isCurrent = false,
|
this.isCurrent = false,
|
||||||
this.isEnabled = true,
|
this.isEnabled = true,
|
||||||
|
this.isTestnet = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String name;
|
final String name;
|
||||||
|
@ -14,4 +15,5 @@ class WalletListItem {
|
||||||
final bool isCurrent;
|
final bool isCurrent;
|
||||||
final dynamic key;
|
final dynamic key;
|
||||||
final bool isEnabled;
|
final bool isEnabled;
|
||||||
|
final bool isTestnet;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,7 @@ abstract class WalletListViewModelBase with Store {
|
||||||
key: info.key,
|
key: info.key,
|
||||||
isCurrent: info.name == _appStore.wallet?.name && info.type == _appStore.wallet?.type,
|
isCurrent: info.name == _appStore.wallet?.name && info.type == _appStore.wallet?.type,
|
||||||
isEnabled: availableWalletTypes.contains(info.type),
|
isEnabled: availableWalletTypes.contains(info.type),
|
||||||
|
isTestnet: info.network?.toLowerCase().contains('testnet') ?? false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -47,6 +47,8 @@ PODS:
|
||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- sp_scanner (0.0.1):
|
||||||
|
- FlutterMacOS
|
||||||
- url_launcher_macos (0.0.1):
|
- url_launcher_macos (0.0.1):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- wakelock_plus (0.0.1):
|
- wakelock_plus (0.0.1):
|
||||||
|
@ -67,6 +69,7 @@ DEPENDENCIES:
|
||||||
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- share_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos`)
|
- share_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos`)
|
||||||
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
|
- sp_scanner (from `Flutter/ephemeral/.symlinks/plugins/sp_scanner/macos`)
|
||||||
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
||||||
- wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`)
|
- wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`)
|
||||||
|
|
||||||
|
@ -104,6 +107,8 @@ EXTERNAL SOURCES:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
||||||
|
sp_scanner:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/sp_scanner/macos
|
||||||
url_launcher_macos:
|
url_launcher_macos:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
|
||||||
wakelock_plus:
|
wakelock_plus:
|
||||||
|
@ -126,7 +131,8 @@ SPEC CHECKSUMS:
|
||||||
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
||||||
share_plus_macos: 853ee48e7dce06b633998ca0735d482dd671ade4
|
share_plus_macos: 853ee48e7dce06b633998ca0735d482dd671ade4
|
||||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||||
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
|
sp_scanner: 269d96e0ec3173e69156be7239b95182be3b8303
|
||||||
|
url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399
|
||||||
wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269
|
wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269
|
||||||
|
|
||||||
PODFILE CHECKSUM: 65ec1541137fb5b35d00490dec1bb48d4d9586bb
|
PODFILE CHECKSUM: 65ec1541137fb5b35d00490dec1bb48d4d9586bb
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
cd cw_core && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_core; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||||
cd cw_evm && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_evm; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||||
cd cw_monero && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_monero; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||||
cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_bitcoin; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||||
cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_haven; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||||
cd cw_nano && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_nano; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||||
cd cw_bitcoin_cash && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_bitcoin_cash; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||||
cd cw_solana && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_solana; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||||
cd cw_tron && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_tron; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||||
cd cw_mweb && flutter pub get && cd ..
|
cd cw_mweb && flutter pub get && cd ..
|
||||||
cd cw_ethereum && flutter pub get && cd ..
|
cd cw_polygon; flutter pub get; cd ..
|
||||||
cd cw_polygon && flutter pub get && cd ..
|
cd cw_ethereum; flutter pub get; cd ..
|
||||||
flutter packages pub run build_runner build --delete-conflicting-outputs
|
flutter packages pub run build_runner build --delete-conflicting-outputs
|
||||||
|
|
|
@ -105,7 +105,7 @@ dependencies:
|
||||||
solana: ^0.30.1
|
solana: ^0.30.1
|
||||||
bitcoin_base:
|
bitcoin_base:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitcoin_base.git
|
url: https://github.com/cake-tech/bitcoin_base
|
||||||
ref: cake-mweb
|
ref: cake-mweb
|
||||||
ledger_flutter: ^1.0.1
|
ledger_flutter: ^1.0.1
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ dev_dependencies:
|
||||||
mobx_codegen: ^2.1.1
|
mobx_codegen: ^2.1.1
|
||||||
build_resolvers: ^2.0.9
|
build_resolvers: ^2.0.9
|
||||||
hive_generator: ^1.1.3
|
hive_generator: ^1.1.3
|
||||||
flutter_launcher_icons: ^0.11.0
|
# flutter_launcher_icons: ^0.11.0
|
||||||
# check flutter_launcher_icons for usage
|
# check flutter_launcher_icons for usage
|
||||||
pedantic: ^1.8.0
|
pedantic: ^1.8.0
|
||||||
# replace https://github.com/dart-lang/lints#migrating-from-packagepedantic
|
# replace https://github.com/dart-lang/lints#migrating-from-packagepedantic
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
"backup": "نسخ الاحتياطي",
|
"backup": "نسخ الاحتياطي",
|
||||||
"backup_file": "ملف النسخ الاحتياطي",
|
"backup_file": "ملف النسخ الاحتياطي",
|
||||||
"backup_password": "كلمة مرور النسخ الاحتياطي",
|
"backup_password": "كلمة مرور النسخ الاحتياطي",
|
||||||
|
"balance": "توازن",
|
||||||
"balance_page": "صفحة التوازن",
|
"balance_page": "صفحة التوازن",
|
||||||
"bill_amount": "مبلغ الفاتورة",
|
"bill_amount": "مبلغ الفاتورة",
|
||||||
"billing_address_info": "إذا طُلب منك عنوان إرسال فواتير ، فأدخل عنوان الشحن الخاص بك",
|
"billing_address_info": "إذا طُلب منك عنوان إرسال فواتير ، فأدخل عنوان الشحن الخاص بك",
|
||||||
|
@ -78,6 +79,7 @@
|
||||||
"bitcoin_dark_theme": "موضوع البيتكوين الظلام",
|
"bitcoin_dark_theme": "موضوع البيتكوين الظلام",
|
||||||
"bitcoin_light_theme": "موضوع البيتكوين الخفيفة",
|
"bitcoin_light_theme": "موضوع البيتكوين الخفيفة",
|
||||||
"bitcoin_payments_require_1_confirmation": "تتطلب مدفوعات Bitcoin تأكيدًا واحدًا ، والذي قد يستغرق 20 دقيقة أو أكثر. شكرا لصبرك! سيتم إرسال بريد إلكتروني إليك عند تأكيد الدفع.",
|
"bitcoin_payments_require_1_confirmation": "تتطلب مدفوعات Bitcoin تأكيدًا واحدًا ، والذي قد يستغرق 20 دقيقة أو أكثر. شكرا لصبرك! سيتم إرسال بريد إلكتروني إليك عند تأكيد الدفع.",
|
||||||
|
"block_remaining": "1 كتلة متبقية",
|
||||||
"Blocks_remaining": "بلوك متبقي ${status}",
|
"Blocks_remaining": "بلوك متبقي ${status}",
|
||||||
"bluetooth": "بلوتوث",
|
"bluetooth": "بلوتوث",
|
||||||
"bright_theme": "مشرق",
|
"bright_theme": "مشرق",
|
||||||
|
@ -139,6 +141,7 @@
|
||||||
"confirm_fee_deduction": "تأكيد خصم الرسوم",
|
"confirm_fee_deduction": "تأكيد خصم الرسوم",
|
||||||
"confirm_fee_deduction_content": "هل توافق على خصم الرسوم من الإخراج؟",
|
"confirm_fee_deduction_content": "هل توافق على خصم الرسوم من الإخراج؟",
|
||||||
"confirm_sending": "تأكيد الإرسال",
|
"confirm_sending": "تأكيد الإرسال",
|
||||||
|
"confirm_silent_payments_switch_node": "حاليا مطلوب لتبديل العقد لمسح المدفوعات الصامتة",
|
||||||
"confirmations": "التأكيدات",
|
"confirmations": "التأكيدات",
|
||||||
"confirmed": "رصيد مؤكد",
|
"confirmed": "رصيد مؤكد",
|
||||||
"confirmed_tx": "مؤكد",
|
"confirmed_tx": "مؤكد",
|
||||||
|
@ -221,6 +224,7 @@
|
||||||
"electrum_address_disclaimer": "نقوم بإنشاء عناوين جديدة في كل مرة تستخدم فيها عنوانًا ، لكن العناوين السابقة تستمر في العمل",
|
"electrum_address_disclaimer": "نقوم بإنشاء عناوين جديدة في كل مرة تستخدم فيها عنوانًا ، لكن العناوين السابقة تستمر في العمل",
|
||||||
"email_address": "عنوان البريد الالكترونى",
|
"email_address": "عنوان البريد الالكترونى",
|
||||||
"enable_replace_by_fee": "تمكين الاستبدال",
|
"enable_replace_by_fee": "تمكين الاستبدال",
|
||||||
|
"enable_silent_payments_scanning": "تمكين المسح الضوئي للمدفوعات الصامتة",
|
||||||
"enabled": "ممكنة",
|
"enabled": "ممكنة",
|
||||||
"enter_amount": "أدخل المبلغ",
|
"enter_amount": "أدخل المبلغ",
|
||||||
"enter_backup_password": "أدخل كلمة المرور الاحتياطية هنا",
|
"enter_backup_password": "أدخل كلمة المرور الاحتياطية هنا",
|
||||||
|
@ -278,6 +282,7 @@
|
||||||
"extracted_address_content": "سوف ترسل الأموال إلى\n${recipient_name}",
|
"extracted_address_content": "سوف ترسل الأموال إلى\n${recipient_name}",
|
||||||
"failed_authentication": "${state_error} فشل المصادقة.",
|
"failed_authentication": "${state_error} فشل المصادقة.",
|
||||||
"faq": "الأسئلة الشائعة",
|
"faq": "الأسئلة الشائعة",
|
||||||
|
"features": "سمات",
|
||||||
"fetching": "جار الجلب",
|
"fetching": "جار الجلب",
|
||||||
"fiat_api": "Fiat API",
|
"fiat_api": "Fiat API",
|
||||||
"fiat_balance": "الرصيد فيات",
|
"fiat_balance": "الرصيد فيات",
|
||||||
|
@ -531,6 +536,7 @@
|
||||||
"save_backup_password_alert": "حفظ كلمة المرور الاحتياطية",
|
"save_backup_password_alert": "حفظ كلمة المرور الاحتياطية",
|
||||||
"save_to_downloads": "ﺕﻼﻳﺰﻨﺘﻟﺍ ﻲﻓ ﻆﻔﺣ",
|
"save_to_downloads": "ﺕﻼﻳﺰﻨﺘﻟﺍ ﻲﻓ ﻆﻔﺣ",
|
||||||
"saved_the_trade_id": "لقد تم حفظ معرف العملية",
|
"saved_the_trade_id": "لقد تم حفظ معرف العملية",
|
||||||
|
"scan_one_block": "مسح كتلة واحدة",
|
||||||
"scan_qr_code": "امسح رمز QR ضوئيًا",
|
"scan_qr_code": "امسح رمز QR ضوئيًا",
|
||||||
"scan_qr_code_to_get_address": "امسح ال QR للحصول على العنوان",
|
"scan_qr_code_to_get_address": "امسح ال QR للحصول على العنوان",
|
||||||
"scan_qr_on_device": " ﺮﺧﺁ ﺯﺎﻬﺟ ﻰﻠﻋ ﺎﻴًﺋﻮﺿ ﺍﺬﻫ ﺔﻌﻳﺮﺴﻟﺍ ﺔﺑﺎﺠﺘﺳﻻﺍ ﺰﻣﺭ ﺢﺴﻤﺑ ﻢﻗ",
|
"scan_qr_on_device": " ﺮﺧﺁ ﺯﺎﻬﺟ ﻰﻠﻋ ﺎﻴًﺋﻮﺿ ﺍﺬﻫ ﺔﻌﻳﺮﺴﻟﺍ ﺔﺑﺎﺠﺘﺳﻻﺍ ﺰﻣﺭ ﺢﺴﻤﺑ ﻢﻗ",
|
||||||
|
@ -641,11 +647,22 @@
|
||||||
"sign_up": "اشتراك",
|
"sign_up": "اشتراك",
|
||||||
"signTransaction": " ﺔﻠﻣﺎﻌﻤﻟﺍ ﻊﻴﻗﻮﺗ",
|
"signTransaction": " ﺔﻠﻣﺎﻌﻤﻟﺍ ﻊﻴﻗﻮﺗ",
|
||||||
"signup_for_card_accept_terms": "قم بالتسجيل للحصول على البطاقة وقبول الشروط.",
|
"signup_for_card_accept_terms": "قم بالتسجيل للحصول على البطاقة وقبول الشروط.",
|
||||||
|
"silent_payments": "مدفوعات صامتة",
|
||||||
|
"silent_payments_always_scan": "حدد المدفوعات الصامتة دائمًا المسح الضوئي",
|
||||||
|
"silent_payments_disclaimer": "العناوين الجديدة ليست هويات جديدة. إنها إعادة استخدام هوية موجودة مع ملصق مختلف.",
|
||||||
|
"silent_payments_display_card": "عرض بطاقة المدفوعات الصامتة",
|
||||||
|
"silent_payments_scan_from_date": "فحص من التاريخ",
|
||||||
|
"silent_payments_scan_from_date_or_blockheight": "يرجى إدخال ارتفاع الكتلة الذي تريد بدء المسح الضوئي للمدفوعات الصامتة الواردة ، أو استخدام التاريخ بدلاً من ذلك. يمكنك اختيار ما إذا كانت المحفظة تواصل مسح كل كتلة ، أو تتحقق فقط من الارتفاع المحدد.",
|
||||||
|
"silent_payments_scan_from_height": "فحص من ارتفاع الكتلة",
|
||||||
|
"silent_payments_scanned_tip": "ممسوح ليفحص! (${tip})",
|
||||||
|
"silent_payments_scanning": "المدفوعات الصامتة المسح الضوئي",
|
||||||
|
"silent_payments_settings": "إعدادات المدفوعات الصامتة",
|
||||||
"slidable": "قابل للانزلاق",
|
"slidable": "قابل للانزلاق",
|
||||||
"sort_by": "ترتيب حسب",
|
"sort_by": "ترتيب حسب",
|
||||||
"spend_key_private": "مفتاح الإنفاق (خاص)",
|
"spend_key_private": "مفتاح الإنفاق (خاص)",
|
||||||
"spend_key_public": "مفتاح الإنفاق (عام)",
|
"spend_key_public": "مفتاح الإنفاق (عام)",
|
||||||
"status": "الحالة:",
|
"status": "الحالة:",
|
||||||
|
"string_default": "تقصير",
|
||||||
"subaddress_title": "قائمة العناوين الفرعية",
|
"subaddress_title": "قائمة العناوين الفرعية",
|
||||||
"subaddresses": "العناوين الفرعية",
|
"subaddresses": "العناوين الفرعية",
|
||||||
"submit_request": "تقديم طلب",
|
"submit_request": "تقديم طلب",
|
||||||
|
@ -670,10 +687,13 @@
|
||||||
"sync_status_starting_sync": "بدء المزامنة",
|
"sync_status_starting_sync": "بدء المزامنة",
|
||||||
"sync_status_syncronized": "متزامن",
|
"sync_status_syncronized": "متزامن",
|
||||||
"sync_status_syncronizing": "يتم المزامنة",
|
"sync_status_syncronizing": "يتم المزامنة",
|
||||||
|
"sync_status_timed_out": "نفد وقته",
|
||||||
|
"sync_status_unsupported": "عقدة غير مدعومة",
|
||||||
"syncing_wallet_alert_content": "قد لا يكتمل رصيدك وقائمة المعاملات الخاصة بك حتى تظهر عبارة “SYNCHRONIZED“ في الأعلى. انقر / اضغط لمعرفة المزيد.",
|
"syncing_wallet_alert_content": "قد لا يكتمل رصيدك وقائمة المعاملات الخاصة بك حتى تظهر عبارة “SYNCHRONIZED“ في الأعلى. انقر / اضغط لمعرفة المزيد.",
|
||||||
"syncing_wallet_alert_title": "محفظتك تتم مزامنتها",
|
"syncing_wallet_alert_title": "محفظتك تتم مزامنتها",
|
||||||
"template": "قالب",
|
"template": "قالب",
|
||||||
"template_name": "اسم القالب",
|
"template_name": "اسم القالب",
|
||||||
|
"testnet_coins_no_value": "عملات TestNet ليس لها قيمة",
|
||||||
"third_intro_content": "يعيش Yats خارج Cake Wallet أيضًا. يمكن استبدال أي عنوان محفظة على وجه الأرض بـ Yat!",
|
"third_intro_content": "يعيش Yats خارج Cake Wallet أيضًا. يمكن استبدال أي عنوان محفظة على وجه الأرض بـ Yat!",
|
||||||
"third_intro_title": "يتماشي Yat بلطف مع الآخرين",
|
"third_intro_title": "يتماشي Yat بلطف مع الآخرين",
|
||||||
"thorchain_contract_address_not_supported": "لا يدعم Thorchain الإرسال إلى عنوان العقد",
|
"thorchain_contract_address_not_supported": "لا يدعم Thorchain الإرسال إلى عنوان العقد",
|
||||||
|
@ -749,13 +769,16 @@
|
||||||
"trusted": "موثوق به",
|
"trusted": "موثوق به",
|
||||||
"tx_commit_exception_no_dust_on_change": "يتم رفض المعاملة مع هذا المبلغ. باستخدام هذه العملات المعدنية ، يمكنك إرسال ${min} دون تغيير أو ${max} الذي يعيد التغيير.",
|
"tx_commit_exception_no_dust_on_change": "يتم رفض المعاملة مع هذا المبلغ. باستخدام هذه العملات المعدنية ، يمكنك إرسال ${min} دون تغيير أو ${max} الذي يعيد التغيير.",
|
||||||
"tx_commit_failed": "فشل ارتكاب المعاملة. يرجى الاتصال بالدعم.",
|
"tx_commit_failed": "فشل ارتكاب المعاملة. يرجى الاتصال بالدعم.",
|
||||||
|
"tx_invalid_input": "أنت تستخدم نوع الإدخال الخاطئ لهذا النوع من الدفع",
|
||||||
"tx_no_dust_exception": "يتم رفض المعاملة عن طريق إرسال مبلغ صغير جدًا. يرجى محاولة زيادة المبلغ.",
|
"tx_no_dust_exception": "يتم رفض المعاملة عن طريق إرسال مبلغ صغير جدًا. يرجى محاولة زيادة المبلغ.",
|
||||||
"tx_not_enough_inputs_exception": "لا يكفي المدخلات المتاحة. الرجاء تحديد المزيد تحت التحكم في العملة",
|
"tx_not_enough_inputs_exception": "لا يكفي المدخلات المتاحة. الرجاء تحديد المزيد تحت التحكم في العملة",
|
||||||
|
"tx_rejected_bip68_final": "تحتوي المعاملة على مدخلات غير مؤكدة وفشلت في استبدال الرسوم.",
|
||||||
"tx_rejected_dust_change": "المعاملة التي يتم رفضها بموجب قواعد الشبكة ، ومبلغ التغيير المنخفض (الغبار). حاول إرسال كل أو تقليل المبلغ.",
|
"tx_rejected_dust_change": "المعاملة التي يتم رفضها بموجب قواعد الشبكة ، ومبلغ التغيير المنخفض (الغبار). حاول إرسال كل أو تقليل المبلغ.",
|
||||||
"tx_rejected_dust_output": "المعاملة التي يتم رفضها بموجب قواعد الشبكة ، وكمية الإخراج المنخفض (الغبار). يرجى زيادة المبلغ.",
|
"tx_rejected_dust_output": "المعاملة التي يتم رفضها بموجب قواعد الشبكة ، وكمية الإخراج المنخفض (الغبار). يرجى زيادة المبلغ.",
|
||||||
"tx_rejected_dust_output_send_all": "المعاملة التي يتم رفضها بموجب قواعد الشبكة ، وكمية الإخراج المنخفض (الغبار). يرجى التحقق من رصيد العملات المعدنية المحددة تحت التحكم في العملة.",
|
"tx_rejected_dust_output_send_all": "المعاملة التي يتم رفضها بموجب قواعد الشبكة ، وكمية الإخراج المنخفض (الغبار). يرجى التحقق من رصيد العملات المعدنية المحددة تحت التحكم في العملة.",
|
||||||
"tx_rejected_vout_negative": "لا يوجد ما يكفي من الرصيد لدفع رسوم هذه الصفقة. يرجى التحقق من رصيد العملات المعدنية تحت السيطرة على العملة.",
|
"tx_rejected_vout_negative": "لا يوجد ما يكفي من الرصيد لدفع رسوم هذه الصفقة. يرجى التحقق من رصيد العملات المعدنية تحت السيطرة على العملة.",
|
||||||
"tx_wrong_balance_exception": "ليس لديك ما يكفي من ${currency} لإرسال هذا المبلغ.",
|
"tx_wrong_balance_exception": "ليس لديك ما يكفي من ${currency} لإرسال هذا المبلغ.",
|
||||||
|
"tx_wrong_balance_with_amount_exception": "ليس لديك ما يكفي ${currency} لإرسال المبلغ الإجمالي ${amount}",
|
||||||
"tx_zero_fee_exception": "لا يمكن إرسال معاملة مع 0 رسوم. حاول زيادة المعدل أو التحقق من اتصالك للحصول على أحدث التقديرات.",
|
"tx_zero_fee_exception": "لا يمكن إرسال معاملة مع 0 رسوم. حاول زيادة المعدل أو التحقق من اتصالك للحصول على أحدث التقديرات.",
|
||||||
"unavailable_balance": "ﺮﻓﻮﺘﻣ ﺮﻴﻏ ﺪﻴﺻﺭ",
|
"unavailable_balance": "ﺮﻓﻮﺘﻣ ﺮﻴﻏ ﺪﻴﺻﺭ",
|
||||||
"unavailable_balance_description": ".ﺎﻫﺪﻴﻤﺠﺗ ءﺎﻐﻟﺇ ﺭﺮﻘﺗ ﻰﺘﺣ ﺕﻼﻣﺎﻌﻤﻠﻟ ﻝﻮﺻﻮﻠﻟ ﺔﻠﺑﺎﻗ ﺮﻴﻏ ﺓﺪﻤﺠﻤﻟﺍ ﺓﺪﺻﺭﻷﺍ ﻞﻈﺗ ﺎﻤﻨﻴﺑ ،ﺎﻬﺑ ﺔﺻﺎﺨﻟﺍ ﺕﻼﻣﺎﻌﻤﻟﺍ ﻝﺎﻤﺘﻛﺍ ﺩﺮﺠﻤﺑ ﺔﺣﺎﺘﻣ ﺔﻠﻔﻘﻤﻟﺍ ﺓﺪﺻﺭﻷﺍ ﺢﺒﺼﺘﺳ .ﻚﺑ ﺔﺻﺎﺨﻟﺍ ﺕﻼﻤﻌﻟﺍ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺕﺍﺩﺍﺪﻋﺇ ﻲﻓ ﻂﺸﻧ ﻞﻜﺸﺑ ﺎﻫﺪﻴﻤﺠﺘﺑ ﺖﻤﻗ",
|
"unavailable_balance_description": ".ﺎﻫﺪﻴﻤﺠﺗ ءﺎﻐﻟﺇ ﺭﺮﻘﺗ ﻰﺘﺣ ﺕﻼﻣﺎﻌﻤﻠﻟ ﻝﻮﺻﻮﻠﻟ ﺔﻠﺑﺎﻗ ﺮﻴﻏ ﺓﺪﻤﺠﻤﻟﺍ ﺓﺪﺻﺭﻷﺍ ﻞﻈﺗ ﺎﻤﻨﻴﺑ ،ﺎﻬﺑ ﺔﺻﺎﺨﻟﺍ ﺕﻼﻣﺎﻌﻤﻟﺍ ﻝﺎﻤﺘﻛﺍ ﺩﺮﺠﻤﺑ ﺔﺣﺎﺘﻣ ﺔﻠﻔﻘﻤﻟﺍ ﺓﺪﺻﺭﻷﺍ ﺢﺒﺼﺘﺳ .ﻚﺑ ﺔﺻﺎﺨﻟﺍ ﺕﻼﻤﻌﻟﺍ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺕﺍﺩﺍﺪﻋﺇ ﻲﻓ ﻂﺸﻧ ﻞﻜﺸﺑ ﺎﻫﺪﻴﻤﺠﺘﺑ ﺖﻤﻗ",
|
||||||
|
@ -809,6 +832,7 @@
|
||||||
"warning": "تحذير",
|
"warning": "تحذير",
|
||||||
"welcome": "مرحبا بك في",
|
"welcome": "مرحبا بك في",
|
||||||
"welcome_to_cakepay": "مرحبا بكم في Cake Pay!",
|
"welcome_to_cakepay": "مرحبا بكم في Cake Pay!",
|
||||||
|
"what_is_silent_payments": "ما هي المدفوعات الصامتة؟",
|
||||||
"widgets_address": "عنوان",
|
"widgets_address": "عنوان",
|
||||||
"widgets_or": "أو",
|
"widgets_or": "أو",
|
||||||
"widgets_restore_from_blockheight": "استعادة من ارتفاع البلوك",
|
"widgets_restore_from_blockheight": "استعادة من ارتفاع البلوك",
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
"backup": "Резервно копие",
|
"backup": "Резервно копие",
|
||||||
"backup_file": "Резервно копие",
|
"backup_file": "Резервно копие",
|
||||||
"backup_password": "Парола за възстановяване",
|
"backup_password": "Парола за възстановяване",
|
||||||
|
"balance": "Баланс",
|
||||||
"balance_page": "Страница за баланс",
|
"balance_page": "Страница за баланс",
|
||||||
"bill_amount": "Искана сума",
|
"bill_amount": "Искана сума",
|
||||||
"billing_address_info": "Ако Ви попитат за билинг адрес, въведето своя адрес за доставка",
|
"billing_address_info": "Ако Ви попитат за билинг адрес, въведето своя адрес за доставка",
|
||||||
|
@ -78,6 +79,7 @@
|
||||||
"bitcoin_dark_theme": "Тъмна тема за биткойн",
|
"bitcoin_dark_theme": "Тъмна тема за биткойн",
|
||||||
"bitcoin_light_theme": "Лека биткойн тема",
|
"bitcoin_light_theme": "Лека биткойн тема",
|
||||||
"bitcoin_payments_require_1_confirmation": "Плащанията с Bitcoin изискват потвърждение, което може да отнеме 20 минути или повече. Благодарим за търпението! Ще получите имейл, когато плащането е потвърдено.",
|
"bitcoin_payments_require_1_confirmation": "Плащанията с Bitcoin изискват потвърждение, което може да отнеме 20 минути или повече. Благодарим за търпението! Ще получите имейл, когато плащането е потвърдено.",
|
||||||
|
"block_remaining": "1 блок останал",
|
||||||
"Blocks_remaining": "${status} оставащи блока",
|
"Blocks_remaining": "${status} оставащи блока",
|
||||||
"bluetooth": "Bluetooth",
|
"bluetooth": "Bluetooth",
|
||||||
"bright_theme": "Ярко",
|
"bright_theme": "Ярко",
|
||||||
|
@ -139,6 +141,7 @@
|
||||||
"confirm_fee_deduction": "Потвърдете приспадането на таксите",
|
"confirm_fee_deduction": "Потвърдете приспадането на таксите",
|
||||||
"confirm_fee_deduction_content": "Съгласни ли сте да приспадате таксата от продукцията?",
|
"confirm_fee_deduction_content": "Съгласни ли сте да приспадате таксата от продукцията?",
|
||||||
"confirm_sending": "Потвърждаване на изпращането",
|
"confirm_sending": "Потвърждаване на изпращането",
|
||||||
|
"confirm_silent_payments_switch_node": "Понастоящем се изисква да превключвате възлите за сканиране на мълчаливи плащания",
|
||||||
"confirmations": "потвърждения",
|
"confirmations": "потвърждения",
|
||||||
"confirmed": "Потвърден баланс",
|
"confirmed": "Потвърден баланс",
|
||||||
"confirmed_tx": "Потвърдено",
|
"confirmed_tx": "Потвърдено",
|
||||||
|
@ -221,6 +224,7 @@
|
||||||
"electrum_address_disclaimer": "Нови адреси се генерират всеки път, когато използвате този, но и предишните продължават да работят",
|
"electrum_address_disclaimer": "Нови адреси се генерират всеки път, когато използвате този, но и предишните продължават да работят",
|
||||||
"email_address": "Имейл адрес",
|
"email_address": "Имейл адрес",
|
||||||
"enable_replace_by_fee": "Активиране на замяна по забрана",
|
"enable_replace_by_fee": "Активиране на замяна по забрана",
|
||||||
|
"enable_silent_payments_scanning": "Активирайте безшумните плащания за сканиране",
|
||||||
"enabled": "Активирано",
|
"enabled": "Активирано",
|
||||||
"enter_amount": "Въведете сума",
|
"enter_amount": "Въведете сума",
|
||||||
"enter_backup_password": "Въведете парола за възстановяване",
|
"enter_backup_password": "Въведете парола за възстановяване",
|
||||||
|
@ -278,6 +282,7 @@
|
||||||
"extracted_address_content": "Ще изпратите средства на \n${recipient_name}",
|
"extracted_address_content": "Ще изпратите средства на \n${recipient_name}",
|
||||||
"failed_authentication": "Неуспешно удостоверяване. ${state_error}",
|
"failed_authentication": "Неуспешно удостоверяване. ${state_error}",
|
||||||
"faq": "FAQ",
|
"faq": "FAQ",
|
||||||
|
"features": "Характеристика",
|
||||||
"fetching": "Обработване",
|
"fetching": "Обработване",
|
||||||
"fiat_api": "Fiat API",
|
"fiat_api": "Fiat API",
|
||||||
"fiat_balance": "Фиат Баланс",
|
"fiat_balance": "Фиат Баланс",
|
||||||
|
@ -531,6 +536,7 @@
|
||||||
"save_backup_password_alert": "Запазване на паролата за възстановяване",
|
"save_backup_password_alert": "Запазване на паролата за възстановяване",
|
||||||
"save_to_downloads": "Запазване в Изтегляния",
|
"save_to_downloads": "Запазване в Изтегляния",
|
||||||
"saved_the_trade_id": "Запазих trade ID-то",
|
"saved_the_trade_id": "Запазих trade ID-то",
|
||||||
|
"scan_one_block": "Сканирайте един блок",
|
||||||
"scan_qr_code": "Сканирайте QR кода, за да получите адреса",
|
"scan_qr_code": "Сканирайте QR кода, за да получите адреса",
|
||||||
"scan_qr_code_to_get_address": "Сканирайте QR кода, за да получите адреса",
|
"scan_qr_code_to_get_address": "Сканирайте QR кода, за да получите адреса",
|
||||||
"scan_qr_on_device": "Сканирайте този QR код на друго устройство",
|
"scan_qr_on_device": "Сканирайте този QR код на друго устройство",
|
||||||
|
@ -641,11 +647,22 @@
|
||||||
"sign_up": "Регистрация",
|
"sign_up": "Регистрация",
|
||||||
"signTransaction": "Подпишете транзакция",
|
"signTransaction": "Подпишете транзакция",
|
||||||
"signup_for_card_accept_terms": "Регистрайте се за картата и приемете условията.",
|
"signup_for_card_accept_terms": "Регистрайте се за картата и приемете условията.",
|
||||||
|
"silent_payments": "Мълчаливи плащания",
|
||||||
|
"silent_payments_always_scan": "Задайте мълчаливи плащания винаги сканиране",
|
||||||
|
"silent_payments_disclaimer": "Новите адреси не са нови идентичности. Това е повторна употреба на съществуваща идентичност с различен етикет.",
|
||||||
|
"silent_payments_display_card": "Показване на безшумни плащания карта",
|
||||||
|
"silent_payments_scan_from_date": "Сканиране от дата",
|
||||||
|
"silent_payments_scan_from_date_or_blockheight": "Моля, въведете височината на блока, която искате да започнете да сканирате за входящи безшумни плащания, или вместо това използвайте датата. Можете да изберете дали портфейлът продължава да сканира всеки блок или проверява само определената височина.",
|
||||||
|
"silent_payments_scan_from_height": "Сканиране от височината на блока",
|
||||||
|
"silent_payments_scanned_tip": "Сканиран за съвет! (${tip})",
|
||||||
|
"silent_payments_scanning": "Безшумни плащания за сканиране",
|
||||||
|
"silent_payments_settings": "Настройки за безшумни плащания",
|
||||||
"slidable": "Плъзгащ се",
|
"slidable": "Плъзгащ се",
|
||||||
"sort_by": "Сортирай по",
|
"sort_by": "Сортирай по",
|
||||||
"spend_key_private": "Spend key (таен)",
|
"spend_key_private": "Spend key (таен)",
|
||||||
"spend_key_public": "Spend key (публичен)",
|
"spend_key_public": "Spend key (публичен)",
|
||||||
"status": "Статус: ",
|
"status": "Статус: ",
|
||||||
|
"string_default": "По подразбиране",
|
||||||
"subaddress_title": "Лист от подадреси",
|
"subaddress_title": "Лист от подадреси",
|
||||||
"subaddresses": "Подадреси",
|
"subaddresses": "Подадреси",
|
||||||
"submit_request": "изпращане на заявка",
|
"submit_request": "изпращане на заявка",
|
||||||
|
@ -670,10 +687,13 @@
|
||||||
"sync_status_starting_sync": "ЗАПОЧВАНЕ НА СИНХРОНИЗАЦИЯ",
|
"sync_status_starting_sync": "ЗАПОЧВАНЕ НА СИНХРОНИЗАЦИЯ",
|
||||||
"sync_status_syncronized": "СИНХРОНИЗИРАНО",
|
"sync_status_syncronized": "СИНХРОНИЗИРАНО",
|
||||||
"sync_status_syncronizing": "СИНХРОНИЗИРАНЕ",
|
"sync_status_syncronizing": "СИНХРОНИЗИРАНЕ",
|
||||||
|
"sync_status_timed_out": "ВРЕМЕТО ИЗТЕЧЕ",
|
||||||
|
"sync_status_unsupported": "Неподдържан възел",
|
||||||
"syncing_wallet_alert_content": "Списъкът ви с баланс и транзакции може да не е пълен, докато в горната част не пише „СИНХРОНИЗИРАН“. Кликнете/докоснете, за да научите повече.",
|
"syncing_wallet_alert_content": "Списъкът ви с баланс и транзакции може да не е пълен, докато в горната част не пише „СИНХРОНИЗИРАН“. Кликнете/докоснете, за да научите повече.",
|
||||||
"syncing_wallet_alert_title": "Вашият портфейл се синхронизира",
|
"syncing_wallet_alert_title": "Вашият портфейл се синхронизира",
|
||||||
"template": "Шаблон",
|
"template": "Шаблон",
|
||||||
"template_name": "Име на шаблон",
|
"template_name": "Име на шаблон",
|
||||||
|
"testnet_coins_no_value": "Тестовите монети нямат стойност",
|
||||||
"third_intro_content": "Yats също живее извън Cake Wallet. Всеки адрес на портфейл може да бъде заменен с Yat!",
|
"third_intro_content": "Yats също живее извън Cake Wallet. Всеки адрес на портфейл може да бъде заменен с Yat!",
|
||||||
"third_intro_title": "Yat добре се сработва с други",
|
"third_intro_title": "Yat добре се сработва с други",
|
||||||
"thorchain_contract_address_not_supported": "Thorchain не подкрепя изпращането до адрес на договор",
|
"thorchain_contract_address_not_supported": "Thorchain не подкрепя изпращането до адрес на договор",
|
||||||
|
@ -749,13 +769,16 @@
|
||||||
"trusted": "Надежден",
|
"trusted": "Надежден",
|
||||||
"tx_commit_exception_no_dust_on_change": "Сделката се отхвърля с тази сума. С тези монети можете да изпратите ${min} без промяна или ${max}, която връща промяна.",
|
"tx_commit_exception_no_dust_on_change": "Сделката се отхвърля с тази сума. С тези монети можете да изпратите ${min} без промяна или ${max}, която връща промяна.",
|
||||||
"tx_commit_failed": "Компетацията на транзакцията не успя. Моля, свържете се с поддръжката.",
|
"tx_commit_failed": "Компетацията на транзакцията не успя. Моля, свържете се с поддръжката.",
|
||||||
|
"tx_invalid_input": "Използвате грешен тип вход за този тип плащане",
|
||||||
"tx_no_dust_exception": "Сделката се отхвърля чрез изпращане на сума твърде малка. Моля, опитайте да увеличите сумата.",
|
"tx_no_dust_exception": "Сделката се отхвърля чрез изпращане на сума твърде малка. Моля, опитайте да увеличите сумата.",
|
||||||
"tx_not_enough_inputs_exception": "Няма достатъчно налични входове. Моля, изберете повече под контрол на монети",
|
"tx_not_enough_inputs_exception": "Няма достатъчно налични входове. Моля, изберете повече под контрол на монети",
|
||||||
|
"tx_rejected_bip68_final": "Сделката има непотвърдени входове и не успя да се замени с такса.",
|
||||||
"tx_rejected_dust_change": "Транзакция, отхвърлена от мрежови правила, ниска сума на промяна (прах). Опитайте да изпратите всички или да намалите сумата.",
|
"tx_rejected_dust_change": "Транзакция, отхвърлена от мрежови правила, ниска сума на промяна (прах). Опитайте да изпратите всички или да намалите сумата.",
|
||||||
"tx_rejected_dust_output": "Транзакция, отхвърлена от мрежови правила, ниска стойност на изхода (прах). Моля, увеличете сумата.",
|
"tx_rejected_dust_output": "Транзакция, отхвърлена от мрежови правила, ниска стойност на изхода (прах). Моля, увеличете сумата.",
|
||||||
"tx_rejected_dust_output_send_all": "Транзакция, отхвърлена от мрежови правила, ниска стойност на изхода (прах). Моля, проверете баланса на монетите, избрани под контрол на монети.",
|
"tx_rejected_dust_output_send_all": "Транзакция, отхвърлена от мрежови правила, ниска стойност на изхода (прах). Моля, проверете баланса на монетите, избрани под контрол на монети.",
|
||||||
"tx_rejected_vout_negative": "Няма достатъчно баланс, за да платите за таксите на тази транзакция. Моля, проверете баланса на монетите под контрол на монетите.",
|
"tx_rejected_vout_negative": "Няма достатъчно баланс, за да платите за таксите на тази транзакция. Моля, проверете баланса на монетите под контрол на монетите.",
|
||||||
"tx_wrong_balance_exception": "Нямате достатъчно ${currency}, за да изпратите тази сума.",
|
"tx_wrong_balance_exception": "Нямате достатъчно ${currency}, за да изпратите тази сума.",
|
||||||
|
"tx_wrong_balance_with_amount_exception": "Нямате достатъчно ${currency} За да изпратите общата сума на ${amount}",
|
||||||
"tx_zero_fee_exception": "Не може да изпраща транзакция с 0 такса. Опитайте да увеличите скоростта или да проверите връзката си за най -новите оценки.",
|
"tx_zero_fee_exception": "Не може да изпраща транзакция с 0 такса. Опитайте да увеличите скоростта или да проверите връзката си за най -новите оценки.",
|
||||||
"unavailable_balance": "Неналично салдо",
|
"unavailable_balance": "Неналично салдо",
|
||||||
"unavailable_balance_description": "Неналично салдо: Тази обща сума включва средства, които са заключени в чакащи транзакции и тези, които сте замразили активно в настройките за контрол на монетите. Заключените баланси ще станат достъпни, след като съответните им транзакции бъдат завършени, докато замразените баланси остават недостъпни за транзакции, докато не решите да ги размразите.",
|
"unavailable_balance_description": "Неналично салдо: Тази обща сума включва средства, които са заключени в чакащи транзакции и тези, които сте замразили активно в настройките за контрол на монетите. Заключените баланси ще станат достъпни, след като съответните им транзакции бъдат завършени, докато замразените баланси остават недостъпни за транзакции, докато не решите да ги размразите.",
|
||||||
|
@ -809,6 +832,7 @@
|
||||||
"warning": "Внимание",
|
"warning": "Внимание",
|
||||||
"welcome": "Добре дошли в",
|
"welcome": "Добре дошли в",
|
||||||
"welcome_to_cakepay": "Добре дошли в Cake Pay!",
|
"welcome_to_cakepay": "Добре дошли в Cake Pay!",
|
||||||
|
"what_is_silent_payments": "Какво са мълчаливи плащания?",
|
||||||
"widgets_address": "Адрес",
|
"widgets_address": "Адрес",
|
||||||
"widgets_or": "или",
|
"widgets_or": "или",
|
||||||
"widgets_restore_from_blockheight": "Възстановяване от blockheight",
|
"widgets_restore_from_blockheight": "Възстановяване от blockheight",
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
"backup": "Záloha",
|
"backup": "Záloha",
|
||||||
"backup_file": "Soubor se zálohou",
|
"backup_file": "Soubor se zálohou",
|
||||||
"backup_password": "Heslo pro zálohy",
|
"backup_password": "Heslo pro zálohy",
|
||||||
|
"balance": "Zůstatek",
|
||||||
"balance_page": "Stránka zůstatku",
|
"balance_page": "Stránka zůstatku",
|
||||||
"bill_amount": "Účtovaná částka",
|
"bill_amount": "Účtovaná částka",
|
||||||
"billing_address_info": "Při dotazu na fakturační adresu, zadejte svou doručovací adresu",
|
"billing_address_info": "Při dotazu na fakturační adresu, zadejte svou doručovací adresu",
|
||||||
|
@ -78,6 +79,7 @@
|
||||||
"bitcoin_dark_theme": "Tmavé téma bitcoinů",
|
"bitcoin_dark_theme": "Tmavé téma bitcoinů",
|
||||||
"bitcoin_light_theme": "Světlé téma bitcoinů",
|
"bitcoin_light_theme": "Světlé téma bitcoinů",
|
||||||
"bitcoin_payments_require_1_confirmation": "U plateb Bitcoinem je vyžadováno alespoň 1 potvrzení, což může trvat 20 minut i déle. Děkujeme za vaši trpělivost! Až bude platba potvrzena, budete informováni e-mailem.",
|
"bitcoin_payments_require_1_confirmation": "U plateb Bitcoinem je vyžadováno alespoň 1 potvrzení, což může trvat 20 minut i déle. Děkujeme za vaši trpělivost! Až bude platba potvrzena, budete informováni e-mailem.",
|
||||||
|
"block_remaining": "1 blok zbývající",
|
||||||
"Blocks_remaining": "Zbývá ${status} bloků",
|
"Blocks_remaining": "Zbývá ${status} bloků",
|
||||||
"bluetooth": "Bluetooth",
|
"bluetooth": "Bluetooth",
|
||||||
"bright_theme": "Jasný",
|
"bright_theme": "Jasný",
|
||||||
|
@ -139,6 +141,7 @@
|
||||||
"confirm_fee_deduction": "Potvrďte odpočet poplatků",
|
"confirm_fee_deduction": "Potvrďte odpočet poplatků",
|
||||||
"confirm_fee_deduction_content": "Souhlasíte s odečtením poplatku z výstupu?",
|
"confirm_fee_deduction_content": "Souhlasíte s odečtením poplatku z výstupu?",
|
||||||
"confirm_sending": "Potvrdit odeslání",
|
"confirm_sending": "Potvrdit odeslání",
|
||||||
|
"confirm_silent_payments_switch_node": "V současné době je nutné přepínat uzly pro skenování tichých plateb",
|
||||||
"confirmations": "Potvrzení",
|
"confirmations": "Potvrzení",
|
||||||
"confirmed": "Potvrzený zůstatek",
|
"confirmed": "Potvrzený zůstatek",
|
||||||
"confirmed_tx": "Potvrzeno",
|
"confirmed_tx": "Potvrzeno",
|
||||||
|
@ -221,6 +224,7 @@
|
||||||
"electrum_address_disclaimer": "Po každém použití je generována nová adresa, ale předchozí adresy také stále fungují",
|
"electrum_address_disclaimer": "Po každém použití je generována nová adresa, ale předchozí adresy také stále fungují",
|
||||||
"email_address": "E-mailová adresa",
|
"email_address": "E-mailová adresa",
|
||||||
"enable_replace_by_fee": "Povolit výměnu podle poplatku",
|
"enable_replace_by_fee": "Povolit výměnu podle poplatku",
|
||||||
|
"enable_silent_payments_scanning": "Povolte skenování tichých plateb",
|
||||||
"enabled": "Povoleno",
|
"enabled": "Povoleno",
|
||||||
"enter_amount": "Zadejte částku",
|
"enter_amount": "Zadejte částku",
|
||||||
"enter_backup_password": "Zde zadejte své heslo pro zálohy",
|
"enter_backup_password": "Zde zadejte své heslo pro zálohy",
|
||||||
|
@ -278,6 +282,7 @@
|
||||||
"extracted_address_content": "Prostředky budete posílat na\n${recipient_name}",
|
"extracted_address_content": "Prostředky budete posílat na\n${recipient_name}",
|
||||||
"failed_authentication": "Ověřování selhalo. ${state_error}",
|
"failed_authentication": "Ověřování selhalo. ${state_error}",
|
||||||
"faq": "FAQ",
|
"faq": "FAQ",
|
||||||
|
"features": "Funkce",
|
||||||
"fetching": "Načítá se",
|
"fetching": "Načítá se",
|
||||||
"fiat_api": "Fiat API",
|
"fiat_api": "Fiat API",
|
||||||
"fiat_balance": "Fiat Balance",
|
"fiat_balance": "Fiat Balance",
|
||||||
|
@ -531,6 +536,7 @@
|
||||||
"save_backup_password_alert": "Uložit heslo pro zálohy",
|
"save_backup_password_alert": "Uložit heslo pro zálohy",
|
||||||
"save_to_downloads": "Uložit do Stažených souborů",
|
"save_to_downloads": "Uložit do Stažených souborů",
|
||||||
"saved_the_trade_id": "Uložil jsem si ID transakce (trade ID)",
|
"saved_the_trade_id": "Uložil jsem si ID transakce (trade ID)",
|
||||||
|
"scan_one_block": "Prohledejte jeden blok",
|
||||||
"scan_qr_code": "Naskenujte QR kód pro získání adresy",
|
"scan_qr_code": "Naskenujte QR kód pro získání adresy",
|
||||||
"scan_qr_code_to_get_address": "Prohledejte QR kód a získejte adresu",
|
"scan_qr_code_to_get_address": "Prohledejte QR kód a získejte adresu",
|
||||||
"scan_qr_on_device": "Naskenujte tento QR kód na jiném zařízení",
|
"scan_qr_on_device": "Naskenujte tento QR kód na jiném zařízení",
|
||||||
|
@ -641,11 +647,22 @@
|
||||||
"sign_up": "Registrovat se",
|
"sign_up": "Registrovat se",
|
||||||
"signTransaction": "Podepsat transakci",
|
"signTransaction": "Podepsat transakci",
|
||||||
"signup_for_card_accept_terms": "Zaregistrujte se pro kartu a souhlaste s podmínkami.",
|
"signup_for_card_accept_terms": "Zaregistrujte se pro kartu a souhlaste s podmínkami.",
|
||||||
|
"silent_payments": "Tiché platby",
|
||||||
|
"silent_payments_always_scan": "Nastavit tiché platby vždy skenování",
|
||||||
|
"silent_payments_disclaimer": "Nové adresy nejsou nové identity. Je to opětovné použití existující identity s jiným štítkem.",
|
||||||
|
"silent_payments_display_card": "Zobrazit kartu Silent Payments",
|
||||||
|
"silent_payments_scan_from_date": "Skenovat od data",
|
||||||
|
"silent_payments_scan_from_date_or_blockheight": "Zadejte výšku bloku, kterou chcete začít skenovat, zda jsou přicházející tiché platby, nebo místo toho použijte datum. Můžete si vybrat, zda peněženka pokračuje v skenování každého bloku nebo zkontroluje pouze zadanou výšku.",
|
||||||
|
"silent_payments_scan_from_height": "Skenování z výšky bloku",
|
||||||
|
"silent_payments_scanned_tip": "Naskenované na tip! (${tip})",
|
||||||
|
"silent_payments_scanning": "Skenování tichých plateb",
|
||||||
|
"silent_payments_settings": "Nastavení tichých plateb",
|
||||||
"slidable": "Posuvné",
|
"slidable": "Posuvné",
|
||||||
"sort_by": "Seřazeno podle",
|
"sort_by": "Seřazeno podle",
|
||||||
"spend_key_private": "Klíč pro platby (soukromý)",
|
"spend_key_private": "Klíč pro platby (soukromý)",
|
||||||
"spend_key_public": "Klíč pro platby (veřejný)",
|
"spend_key_public": "Klíč pro platby (veřejný)",
|
||||||
"status": "Status: ",
|
"status": "Status: ",
|
||||||
|
"string_default": "Výchozí",
|
||||||
"subaddress_title": "Seznam subadres",
|
"subaddress_title": "Seznam subadres",
|
||||||
"subaddresses": "Subadresy",
|
"subaddresses": "Subadresy",
|
||||||
"submit_request": "odeslat požadavek",
|
"submit_request": "odeslat požadavek",
|
||||||
|
@ -670,10 +687,13 @@
|
||||||
"sync_status_starting_sync": "SPOUŠTĚNÍ SYNCHRONIZACE",
|
"sync_status_starting_sync": "SPOUŠTĚNÍ SYNCHRONIZACE",
|
||||||
"sync_status_syncronized": "SYNCHRONIZOVÁNO",
|
"sync_status_syncronized": "SYNCHRONIZOVÁNO",
|
||||||
"sync_status_syncronizing": "SYNCHRONIZUJI",
|
"sync_status_syncronizing": "SYNCHRONIZUJI",
|
||||||
|
"sync_status_timed_out": "ČAS VYPRŠEL",
|
||||||
|
"sync_status_unsupported": "Nepodporovaný uzel",
|
||||||
"syncing_wallet_alert_content": "Váš seznam zůstatků a transakcí nemusí být úplný, dokud nebude nahoře uvedeno „SYNCHRONIZOVANÉ“. Kliknutím/klepnutím se dozvíte více.",
|
"syncing_wallet_alert_content": "Váš seznam zůstatků a transakcí nemusí být úplný, dokud nebude nahoře uvedeno „SYNCHRONIZOVANÉ“. Kliknutím/klepnutím se dozvíte více.",
|
||||||
"syncing_wallet_alert_title": "Vaše peněženka se synchronizuje",
|
"syncing_wallet_alert_title": "Vaše peněženka se synchronizuje",
|
||||||
"template": "Šablona",
|
"template": "Šablona",
|
||||||
"template_name": "Název šablony",
|
"template_name": "Název šablony",
|
||||||
|
"testnet_coins_no_value": "Mince TestNet nemají žádnou hodnotu",
|
||||||
"third_intro_content": "Yat existuje i mimo Cake Wallet. Jakákoliv adresa peněženky na světě může být nahrazena Yatem!",
|
"third_intro_content": "Yat existuje i mimo Cake Wallet. Jakákoliv adresa peněženky na světě může být nahrazena Yatem!",
|
||||||
"third_intro_title": "Yat dobře spolupracuje s ostatními",
|
"third_intro_title": "Yat dobře spolupracuje s ostatními",
|
||||||
"thorchain_contract_address_not_supported": "Thorchain nepodporuje odeslání na adresu smlouvy",
|
"thorchain_contract_address_not_supported": "Thorchain nepodporuje odeslání na adresu smlouvy",
|
||||||
|
@ -749,13 +769,16 @@
|
||||||
"trusted": "Důvěřovat",
|
"trusted": "Důvěřovat",
|
||||||
"tx_commit_exception_no_dust_on_change": "Transakce je zamítnuta s touto částkou. S těmito mincemi můžete odeslat ${min} bez změny nebo ${max}, které se vrátí změna.",
|
"tx_commit_exception_no_dust_on_change": "Transakce je zamítnuta s touto částkou. S těmito mincemi můžete odeslat ${min} bez změny nebo ${max}, které se vrátí změna.",
|
||||||
"tx_commit_failed": "Transakce COMPORT selhala. Kontaktujte prosím podporu.",
|
"tx_commit_failed": "Transakce COMPORT selhala. Kontaktujte prosím podporu.",
|
||||||
|
"tx_invalid_input": "Pro tento typ platby používáte nesprávný typ vstupu",
|
||||||
"tx_no_dust_exception": "Transakce je zamítnuta odesláním příliš malé. Zkuste prosím zvýšit částku.",
|
"tx_no_dust_exception": "Transakce je zamítnuta odesláním příliš malé. Zkuste prosím zvýšit částku.",
|
||||||
"tx_not_enough_inputs_exception": "Není k dispozici dostatek vstupů. Vyberte prosím více pod kontrolou mincí",
|
"tx_not_enough_inputs_exception": "Není k dispozici dostatek vstupů. Vyberte prosím více pod kontrolou mincí",
|
||||||
|
"tx_rejected_bip68_final": "Transakce má nepotvrzené vstupy a nepodařilo se nahradit poplatkem.",
|
||||||
"tx_rejected_dust_change": "Transakce zamítnuta podle síťových pravidel, množství nízké změny (prach). Zkuste odeslat vše nebo snížit částku.",
|
"tx_rejected_dust_change": "Transakce zamítnuta podle síťových pravidel, množství nízké změny (prach). Zkuste odeslat vše nebo snížit částku.",
|
||||||
"tx_rejected_dust_output": "Transakce zamítnuta síťovými pravidly, nízkým množstvím výstupu (prach). Zvyšte prosím částku.",
|
"tx_rejected_dust_output": "Transakce zamítnuta síťovými pravidly, nízkým množstvím výstupu (prach). Zvyšte prosím částku.",
|
||||||
"tx_rejected_dust_output_send_all": "Transakce zamítnuta síťovými pravidly, nízkým množstvím výstupu (prach). Zkontrolujte prosím zůstatek mincí vybraných pod kontrolou mincí.",
|
"tx_rejected_dust_output_send_all": "Transakce zamítnuta síťovými pravidly, nízkým množstvím výstupu (prach). Zkontrolujte prosím zůstatek mincí vybraných pod kontrolou mincí.",
|
||||||
"tx_rejected_vout_negative": "Nedostatek zůstatek na zaplacení poplatků za tuto transakci. Zkontrolujte prosím zůstatek mincí pod kontrolou mincí.",
|
"tx_rejected_vout_negative": "Nedostatek zůstatek na zaplacení poplatků za tuto transakci. Zkontrolujte prosím zůstatek mincí pod kontrolou mincí.",
|
||||||
"tx_wrong_balance_exception": "Nemáte dost ${currency} pro odeslání této částky.",
|
"tx_wrong_balance_exception": "Nemáte dost ${currency} pro odeslání této částky.",
|
||||||
|
"tx_wrong_balance_with_amount_exception": "Nemáte dost ${currency} na odeslání celkové částky ${amount}",
|
||||||
"tx_zero_fee_exception": "Nelze odeslat transakci s 0 poplatkem. Zkuste zvýšit sazbu nebo zkontrolovat připojení pro nejnovější odhady.",
|
"tx_zero_fee_exception": "Nelze odeslat transakci s 0 poplatkem. Zkuste zvýšit sazbu nebo zkontrolovat připojení pro nejnovější odhady.",
|
||||||
"unavailable_balance": "Nedostupný zůstatek",
|
"unavailable_balance": "Nedostupný zůstatek",
|
||||||
"unavailable_balance_description": "Nedostupný zůstatek: Tento součet zahrnuje prostředky, které jsou uzamčeny v nevyřízených transakcích a ty, které jste aktivně zmrazili v nastavení kontroly mincí. Uzamčené zůstatky budou k dispozici po dokončení příslušných transakcí, zatímco zmrazené zůstatky zůstanou pro transakce nepřístupné, dokud se nerozhodnete je uvolnit.",
|
"unavailable_balance_description": "Nedostupný zůstatek: Tento součet zahrnuje prostředky, které jsou uzamčeny v nevyřízených transakcích a ty, které jste aktivně zmrazili v nastavení kontroly mincí. Uzamčené zůstatky budou k dispozici po dokončení příslušných transakcí, zatímco zmrazené zůstatky zůstanou pro transakce nepřístupné, dokud se nerozhodnete je uvolnit.",
|
||||||
|
@ -809,6 +832,7 @@
|
||||||
"warning": "Varování",
|
"warning": "Varování",
|
||||||
"welcome": "Vítejte v",
|
"welcome": "Vítejte v",
|
||||||
"welcome_to_cakepay": "Vítejte v Cake Pay!",
|
"welcome_to_cakepay": "Vítejte v Cake Pay!",
|
||||||
|
"what_is_silent_payments": "Co jsou tiché platby?",
|
||||||
"widgets_address": "Adresa",
|
"widgets_address": "Adresa",
|
||||||
"widgets_or": "nebo",
|
"widgets_or": "nebo",
|
||||||
"widgets_restore_from_blockheight": "Obnovit z výšky bloku",
|
"widgets_restore_from_blockheight": "Obnovit z výšky bloku",
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
"backup": "Sicherung",
|
"backup": "Sicherung",
|
||||||
"backup_file": "Sicherungsdatei",
|
"backup_file": "Sicherungsdatei",
|
||||||
"backup_password": "Passwort sichern",
|
"backup_password": "Passwort sichern",
|
||||||
|
"balance": "Gleichgewicht",
|
||||||
"balance_page": "Balance-Seite",
|
"balance_page": "Balance-Seite",
|
||||||
"bill_amount": "Rechnungsbetrag",
|
"bill_amount": "Rechnungsbetrag",
|
||||||
"billing_address_info": "Wenn Sie nach einer Rechnungsadresse gefragt werden, geben Sie bitte Ihre Lieferadresse an",
|
"billing_address_info": "Wenn Sie nach einer Rechnungsadresse gefragt werden, geben Sie bitte Ihre Lieferadresse an",
|
||||||
|
@ -78,6 +79,7 @@
|
||||||
"bitcoin_dark_theme": "Dunkles Bitcoin-Thema",
|
"bitcoin_dark_theme": "Dunkles Bitcoin-Thema",
|
||||||
"bitcoin_light_theme": "Bitcoin Light-Thema",
|
"bitcoin_light_theme": "Bitcoin Light-Thema",
|
||||||
"bitcoin_payments_require_1_confirmation": "Bitcoin-Zahlungen erfordern 1 Bestätigung, was 20 Minuten oder länger dauern kann. Danke für Ihre Geduld! Sie erhalten eine E-Mail, wenn die Zahlung bestätigt ist.",
|
"bitcoin_payments_require_1_confirmation": "Bitcoin-Zahlungen erfordern 1 Bestätigung, was 20 Minuten oder länger dauern kann. Danke für Ihre Geduld! Sie erhalten eine E-Mail, wenn die Zahlung bestätigt ist.",
|
||||||
|
"block_remaining": "1 Block verbleibend",
|
||||||
"Blocks_remaining": "${status} verbleibende Blöcke",
|
"Blocks_remaining": "${status} verbleibende Blöcke",
|
||||||
"bluetooth": "Bluetooth",
|
"bluetooth": "Bluetooth",
|
||||||
"bright_theme": "Strahlend hell",
|
"bright_theme": "Strahlend hell",
|
||||||
|
@ -139,6 +141,7 @@
|
||||||
"confirm_fee_deduction": "Gebührenabzug bestätigen",
|
"confirm_fee_deduction": "Gebührenabzug bestätigen",
|
||||||
"confirm_fee_deduction_content": "Stimmen Sie zu, die Gebühr von der Ausgabe abzuziehen?",
|
"confirm_fee_deduction_content": "Stimmen Sie zu, die Gebühr von der Ausgabe abzuziehen?",
|
||||||
"confirm_sending": "Senden bestätigen",
|
"confirm_sending": "Senden bestätigen",
|
||||||
|
"confirm_silent_payments_switch_node": "Derzeit ist es erforderlich, Knoten zu wechseln, um stille Zahlungen zu scannen",
|
||||||
"confirmations": "Bestätigungen",
|
"confirmations": "Bestätigungen",
|
||||||
"confirmed": "Bestätigter Saldo",
|
"confirmed": "Bestätigter Saldo",
|
||||||
"confirmed_tx": "Bestätigt",
|
"confirmed_tx": "Bestätigt",
|
||||||
|
@ -221,6 +224,7 @@
|
||||||
"electrum_address_disclaimer": "Wir generieren jedes Mal neue Adressen, wenn Sie eine verwenden, aber vorherige Adressen funktionieren weiterhin",
|
"electrum_address_disclaimer": "Wir generieren jedes Mal neue Adressen, wenn Sie eine verwenden, aber vorherige Adressen funktionieren weiterhin",
|
||||||
"email_address": "E-Mail-Adresse",
|
"email_address": "E-Mail-Adresse",
|
||||||
"enable_replace_by_fee": "Aktivieren Sie Ersatz für Fee",
|
"enable_replace_by_fee": "Aktivieren Sie Ersatz für Fee",
|
||||||
|
"enable_silent_payments_scanning": "Aktivieren Sie stille Zahlungen Scannen",
|
||||||
"enabled": "Ermöglicht",
|
"enabled": "Ermöglicht",
|
||||||
"enter_amount": "Betrag eingeben",
|
"enter_amount": "Betrag eingeben",
|
||||||
"enter_backup_password": "Sicherungskennwort hier eingeben",
|
"enter_backup_password": "Sicherungskennwort hier eingeben",
|
||||||
|
@ -278,6 +282,7 @@
|
||||||
"extracted_address_content": "Sie senden Geld an\n${recipient_name}",
|
"extracted_address_content": "Sie senden Geld an\n${recipient_name}",
|
||||||
"failed_authentication": "Authentifizierung fehlgeschlagen. ${state_error}",
|
"failed_authentication": "Authentifizierung fehlgeschlagen. ${state_error}",
|
||||||
"faq": "Häufig gestellte Fragen",
|
"faq": "Häufig gestellte Fragen",
|
||||||
|
"features": "Merkmale",
|
||||||
"fetching": "Frage ab",
|
"fetching": "Frage ab",
|
||||||
"fiat_api": "Fiat API",
|
"fiat_api": "Fiat API",
|
||||||
"fiat_balance": "Fiat Balance",
|
"fiat_balance": "Fiat Balance",
|
||||||
|
@ -532,6 +537,7 @@
|
||||||
"save_backup_password_alert": "Sicherungskennwort speichern",
|
"save_backup_password_alert": "Sicherungskennwort speichern",
|
||||||
"save_to_downloads": "Unter „Downloads“ speichern",
|
"save_to_downloads": "Unter „Downloads“ speichern",
|
||||||
"saved_the_trade_id": "Ich habe die Handels-ID gespeichert",
|
"saved_the_trade_id": "Ich habe die Handels-ID gespeichert",
|
||||||
|
"scan_one_block": "Einen Block scannen",
|
||||||
"scan_qr_code": "QR-Code scannen",
|
"scan_qr_code": "QR-Code scannen",
|
||||||
"scan_qr_code_to_get_address": "Scannen Sie den QR-Code, um die Adresse zu erhalten",
|
"scan_qr_code_to_get_address": "Scannen Sie den QR-Code, um die Adresse zu erhalten",
|
||||||
"scan_qr_on_device": "Scannen Sie diesen QR-Code auf einem anderen Gerät",
|
"scan_qr_on_device": "Scannen Sie diesen QR-Code auf einem anderen Gerät",
|
||||||
|
@ -642,11 +648,22 @@
|
||||||
"sign_up": "Anmelden",
|
"sign_up": "Anmelden",
|
||||||
"signTransaction": "Transaktion unterzeichnen",
|
"signTransaction": "Transaktion unterzeichnen",
|
||||||
"signup_for_card_accept_terms": "Melden Sie sich für die Karte an und akzeptieren Sie die Bedingungen.",
|
"signup_for_card_accept_terms": "Melden Sie sich für die Karte an und akzeptieren Sie die Bedingungen.",
|
||||||
|
"silent_payments": "Stille Zahlungen",
|
||||||
|
"silent_payments_always_scan": "Setzen Sie stille Zahlungen immer scannen",
|
||||||
|
"silent_payments_disclaimer": "Neue Adressen sind keine neuen Identitäten. Es ist eine Wiederverwendung einer bestehenden Identität mit einem anderen Etikett.",
|
||||||
|
"silent_payments_display_card": "Zeigen Sie stille Zahlungskarte",
|
||||||
|
"silent_payments_scan_from_date": "Scan ab Datum",
|
||||||
|
"silent_payments_scan_from_date_or_blockheight": "Bitte geben Sie die Blockhöhe ein, die Sie für eingehende stille Zahlungen scannen möchten, oder verwenden Sie stattdessen das Datum. Sie können wählen, ob die Brieftasche jeden Block scannt oder nur die angegebene Höhe überprüft.",
|
||||||
|
"silent_payments_scan_from_height": "Scan aus der Blockhöhe scannen",
|
||||||
|
"silent_payments_scanned_tip": "Gescannt zum Trinkgeld! (${tip})",
|
||||||
|
"silent_payments_scanning": "Stille Zahlungen scannen",
|
||||||
|
"silent_payments_settings": "Einstellungen für stille Zahlungen",
|
||||||
"slidable": "Verschiebbar",
|
"slidable": "Verschiebbar",
|
||||||
"sort_by": "Sortiere nach",
|
"sort_by": "Sortiere nach",
|
||||||
"spend_key_private": "Spend Key (geheim)",
|
"spend_key_private": "Spend Key (geheim)",
|
||||||
"spend_key_public": "Spend Key (öffentlich)",
|
"spend_key_public": "Spend Key (öffentlich)",
|
||||||
"status": "Status: ",
|
"status": "Status: ",
|
||||||
|
"string_default": "Standard",
|
||||||
"subaddress_title": "Unteradressenliste",
|
"subaddress_title": "Unteradressenliste",
|
||||||
"subaddresses": "Unteradressen",
|
"subaddresses": "Unteradressen",
|
||||||
"submit_request": "Eine Anfrage stellen",
|
"submit_request": "Eine Anfrage stellen",
|
||||||
|
@ -671,10 +688,13 @@
|
||||||
"sync_status_starting_sync": "STARTE SYNCHRONISIERUNG",
|
"sync_status_starting_sync": "STARTE SYNCHRONISIERUNG",
|
||||||
"sync_status_syncronized": "SYNCHRONISIERT",
|
"sync_status_syncronized": "SYNCHRONISIERT",
|
||||||
"sync_status_syncronizing": "SYNCHRONISIERE",
|
"sync_status_syncronizing": "SYNCHRONISIERE",
|
||||||
|
"sync_status_timed_out": "Zeitlich abgestimmt",
|
||||||
|
"sync_status_unsupported": "Nicht unterstützter Knoten",
|
||||||
"syncing_wallet_alert_content": "Ihr Kontostand und Ihre Transaktionsliste sind möglicherweise erst vollständig, wenn oben „SYNCHRONISIERT“ steht. Klicken/tippen Sie, um mehr zu erfahren.",
|
"syncing_wallet_alert_content": "Ihr Kontostand und Ihre Transaktionsliste sind möglicherweise erst vollständig, wenn oben „SYNCHRONISIERT“ steht. Klicken/tippen Sie, um mehr zu erfahren.",
|
||||||
"syncing_wallet_alert_title": "Ihr Wallet wird synchronisiert",
|
"syncing_wallet_alert_title": "Ihr Wallet wird synchronisiert",
|
||||||
"template": "Vorlage",
|
"template": "Vorlage",
|
||||||
"template_name": "Vorlagenname",
|
"template_name": "Vorlagenname",
|
||||||
|
"testnet_coins_no_value": "Testnet -Münzen haben keinen Wert",
|
||||||
"third_intro_content": "Yats leben auch außerhalb von Cake Wallet. Jede Wallet-Adresse auf der Welt kann durch ein Yat ersetzt werden!",
|
"third_intro_content": "Yats leben auch außerhalb von Cake Wallet. Jede Wallet-Adresse auf der Welt kann durch ein Yat ersetzt werden!",
|
||||||
"third_intro_title": "Yat spielt gut mit anderen",
|
"third_intro_title": "Yat spielt gut mit anderen",
|
||||||
"thorchain_contract_address_not_supported": "Thorchain unterstützt das Senden an eine Vertragsadresse nicht",
|
"thorchain_contract_address_not_supported": "Thorchain unterstützt das Senden an eine Vertragsadresse nicht",
|
||||||
|
@ -750,13 +770,16 @@
|
||||||
"trusted": "Vertrauenswürdige",
|
"trusted": "Vertrauenswürdige",
|
||||||
"tx_commit_exception_no_dust_on_change": "Die Transaktion wird diesen Betrag abgelehnt. Mit diesen Münzen können Sie ${min} ohne Veränderung oder ${max} senden, die Änderungen zurückgeben.",
|
"tx_commit_exception_no_dust_on_change": "Die Transaktion wird diesen Betrag abgelehnt. Mit diesen Münzen können Sie ${min} ohne Veränderung oder ${max} senden, die Änderungen zurückgeben.",
|
||||||
"tx_commit_failed": "Transaktionsausschüsse ist fehlgeschlagen. Bitte wenden Sie sich an Support.",
|
"tx_commit_failed": "Transaktionsausschüsse ist fehlgeschlagen. Bitte wenden Sie sich an Support.",
|
||||||
|
"tx_invalid_input": "Sie verwenden den falschen Eingangstyp für diese Art von Zahlung",
|
||||||
"tx_no_dust_exception": "Die Transaktion wird abgelehnt, indem eine Menge zu klein gesendet wird. Bitte versuchen Sie, die Menge zu erhöhen.",
|
"tx_no_dust_exception": "Die Transaktion wird abgelehnt, indem eine Menge zu klein gesendet wird. Bitte versuchen Sie, die Menge zu erhöhen.",
|
||||||
"tx_not_enough_inputs_exception": "Nicht genügend Eingänge verfügbar. Bitte wählen Sie mehr unter Münzkontrolle aus",
|
"tx_not_enough_inputs_exception": "Nicht genügend Eingänge verfügbar. Bitte wählen Sie mehr unter Münzkontrolle aus",
|
||||||
|
"tx_rejected_bip68_final": "Die Transaktion hat unbestätigte Inputs und konnte nicht durch Gebühr ersetzt werden.",
|
||||||
"tx_rejected_dust_change": "Transaktion abgelehnt durch Netzwerkregeln, niedriger Änderungsbetrag (Staub). Versuchen Sie, alle zu senden oder die Menge zu reduzieren.",
|
"tx_rejected_dust_change": "Transaktion abgelehnt durch Netzwerkregeln, niedriger Änderungsbetrag (Staub). Versuchen Sie, alle zu senden oder die Menge zu reduzieren.",
|
||||||
"tx_rejected_dust_output": "Transaktion durch Netzwerkregeln, niedriger Ausgangsmenge (Staub) abgelehnt. Bitte erhöhen Sie den Betrag.",
|
"tx_rejected_dust_output": "Transaktion durch Netzwerkregeln, niedriger Ausgangsmenge (Staub) abgelehnt. Bitte erhöhen Sie den Betrag.",
|
||||||
"tx_rejected_dust_output_send_all": "Transaktion durch Netzwerkregeln, niedriger Ausgangsmenge (Staub) abgelehnt. Bitte überprüfen Sie den Gleichgewicht der unter Münzkontrolle ausgewählten Münzen.",
|
"tx_rejected_dust_output_send_all": "Transaktion durch Netzwerkregeln, niedriger Ausgangsmenge (Staub) abgelehnt. Bitte überprüfen Sie den Gleichgewicht der unter Münzkontrolle ausgewählten Münzen.",
|
||||||
"tx_rejected_vout_negative": "Nicht genug Guthaben, um die Gebühren dieser Transaktion zu bezahlen. Bitte überprüfen Sie den Restbetrag der Münzen unter Münzkontrolle.",
|
"tx_rejected_vout_negative": "Nicht genug Guthaben, um die Gebühren dieser Transaktion zu bezahlen. Bitte überprüfen Sie den Restbetrag der Münzen unter Münzkontrolle.",
|
||||||
"tx_wrong_balance_exception": "Sie haben nicht genug ${currency}, um diesen Betrag zu senden.",
|
"tx_wrong_balance_exception": "Sie haben nicht genug ${currency}, um diesen Betrag zu senden.",
|
||||||
|
"tx_wrong_balance_with_amount_exception": "Sie haben nicht genug ${currency}, um die Gesamtmenge von ${amount} zu senden",
|
||||||
"tx_zero_fee_exception": "Transaktion kann nicht mit 0 Gebühren gesendet werden. Versuchen Sie, die Rate zu erhöhen oder Ihre Verbindung auf die neuesten Schätzungen zu überprüfen.",
|
"tx_zero_fee_exception": "Transaktion kann nicht mit 0 Gebühren gesendet werden. Versuchen Sie, die Rate zu erhöhen oder Ihre Verbindung auf die neuesten Schätzungen zu überprüfen.",
|
||||||
"unavailable_balance": "Nicht verfügbares Guthaben",
|
"unavailable_balance": "Nicht verfügbares Guthaben",
|
||||||
"unavailable_balance_description": "Nicht verfügbares Guthaben: Diese Summe umfasst Gelder, die in ausstehenden Transaktionen gesperrt sind, und solche, die Sie in Ihren Münzkontrolleinstellungen aktiv eingefroren haben. Gesperrte Guthaben werden verfügbar, sobald die entsprechenden Transaktionen abgeschlossen sind, während eingefrorene Guthaben für Transaktionen nicht zugänglich bleiben, bis Sie sich dazu entschließen, sie wieder freizugeben.",
|
"unavailable_balance_description": "Nicht verfügbares Guthaben: Diese Summe umfasst Gelder, die in ausstehenden Transaktionen gesperrt sind, und solche, die Sie in Ihren Münzkontrolleinstellungen aktiv eingefroren haben. Gesperrte Guthaben werden verfügbar, sobald die entsprechenden Transaktionen abgeschlossen sind, während eingefrorene Guthaben für Transaktionen nicht zugänglich bleiben, bis Sie sich dazu entschließen, sie wieder freizugeben.",
|
||||||
|
@ -812,6 +835,7 @@
|
||||||
"warning": "Warnung",
|
"warning": "Warnung",
|
||||||
"welcome": "Willkommen bei",
|
"welcome": "Willkommen bei",
|
||||||
"welcome_to_cakepay": "Willkommen bei Cake Pay!",
|
"welcome_to_cakepay": "Willkommen bei Cake Pay!",
|
||||||
|
"what_is_silent_payments": "Was sind stille Zahlungen?",
|
||||||
"widgets_address": "Adresse",
|
"widgets_address": "Adresse",
|
||||||
"widgets_or": "oder",
|
"widgets_or": "oder",
|
||||||
"widgets_restore_from_blockheight": "Ab Blockhöhe wiederherstellen",
|
"widgets_restore_from_blockheight": "Ab Blockhöhe wiederherstellen",
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
"backup": "Backup",
|
"backup": "Backup",
|
||||||
"backup_file": "Backup file",
|
"backup_file": "Backup file",
|
||||||
"backup_password": "Backup password",
|
"backup_password": "Backup password",
|
||||||
|
"balance": "Balance",
|
||||||
"balance_page": "Balance Page",
|
"balance_page": "Balance Page",
|
||||||
"bill_amount": "Bill Amount",
|
"bill_amount": "Bill Amount",
|
||||||
"billing_address_info": "If asked for a billing address, provide your shipping address",
|
"billing_address_info": "If asked for a billing address, provide your shipping address",
|
||||||
|
@ -78,6 +79,7 @@
|
||||||
"bitcoin_dark_theme": "Bitcoin Dark Theme",
|
"bitcoin_dark_theme": "Bitcoin Dark Theme",
|
||||||
"bitcoin_light_theme": "Bitcoin Light Theme",
|
"bitcoin_light_theme": "Bitcoin Light Theme",
|
||||||
"bitcoin_payments_require_1_confirmation": "Bitcoin payments require 1 confirmation, which can take 20 minutes or longer. Thanks for your patience! You will be emailed when the payment is confirmed.",
|
"bitcoin_payments_require_1_confirmation": "Bitcoin payments require 1 confirmation, which can take 20 minutes or longer. Thanks for your patience! You will be emailed when the payment is confirmed.",
|
||||||
|
"block_remaining": "1 Block Remaining",
|
||||||
"Blocks_remaining": "${status} Blocks Remaining",
|
"Blocks_remaining": "${status} Blocks Remaining",
|
||||||
"bluetooth": "Bluetooth",
|
"bluetooth": "Bluetooth",
|
||||||
"bright_theme": "Bright",
|
"bright_theme": "Bright",
|
||||||
|
@ -139,6 +141,7 @@
|
||||||
"confirm_fee_deduction": "Confirm Fee Deduction",
|
"confirm_fee_deduction": "Confirm Fee Deduction",
|
||||||
"confirm_fee_deduction_content": "Do you agree to deduct the fee from the output?",
|
"confirm_fee_deduction_content": "Do you agree to deduct the fee from the output?",
|
||||||
"confirm_sending": "Confirm sending",
|
"confirm_sending": "Confirm sending",
|
||||||
|
"confirm_silent_payments_switch_node": "Currently it is required to switch nodes to scan silent payments",
|
||||||
"confirmations": "Confirmations",
|
"confirmations": "Confirmations",
|
||||||
"confirmed": "Confirmed Balance",
|
"confirmed": "Confirmed Balance",
|
||||||
"confirmed_tx": "Confirmed",
|
"confirmed_tx": "Confirmed",
|
||||||
|
@ -221,6 +224,7 @@
|
||||||
"electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work",
|
"electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work",
|
||||||
"email_address": "Email Address",
|
"email_address": "Email Address",
|
||||||
"enable_replace_by_fee": "Enable Replace-By-Fee",
|
"enable_replace_by_fee": "Enable Replace-By-Fee",
|
||||||
|
"enable_silent_payments_scanning": "Enable silent payments scanning",
|
||||||
"enabled": "Enabled",
|
"enabled": "Enabled",
|
||||||
"enter_amount": "Enter Amount",
|
"enter_amount": "Enter Amount",
|
||||||
"enter_backup_password": "Enter backup password here",
|
"enter_backup_password": "Enter backup password here",
|
||||||
|
@ -278,6 +282,7 @@
|
||||||
"extracted_address_content": "You will be sending funds to\n${recipient_name}",
|
"extracted_address_content": "You will be sending funds to\n${recipient_name}",
|
||||||
"failed_authentication": "Failed authentication. ${state_error}",
|
"failed_authentication": "Failed authentication. ${state_error}",
|
||||||
"faq": "FAQ",
|
"faq": "FAQ",
|
||||||
|
"features": "Features",
|
||||||
"fetching": "Fetching",
|
"fetching": "Fetching",
|
||||||
"fiat_api": "Fiat API",
|
"fiat_api": "Fiat API",
|
||||||
"fiat_balance": "Fiat Balance",
|
"fiat_balance": "Fiat Balance",
|
||||||
|
@ -531,6 +536,7 @@
|
||||||
"save_backup_password_alert": "Save backup password",
|
"save_backup_password_alert": "Save backup password",
|
||||||
"save_to_downloads": "Save to Downloads",
|
"save_to_downloads": "Save to Downloads",
|
||||||
"saved_the_trade_id": "I've saved the trade ID",
|
"saved_the_trade_id": "I've saved the trade ID",
|
||||||
|
"scan_one_block": "Scan one block",
|
||||||
"scan_qr_code": "Scan QR code",
|
"scan_qr_code": "Scan QR code",
|
||||||
"scan_qr_code_to_get_address": "Scan the QR code to get the address",
|
"scan_qr_code_to_get_address": "Scan the QR code to get the address",
|
||||||
"scan_qr_on_device": "Scan this QR code on another device",
|
"scan_qr_on_device": "Scan this QR code on another device",
|
||||||
|
@ -641,11 +647,22 @@
|
||||||
"sign_up": "Sign Up",
|
"sign_up": "Sign Up",
|
||||||
"signTransaction": "Sign Transaction",
|
"signTransaction": "Sign Transaction",
|
||||||
"signup_for_card_accept_terms": "Sign up for the card and accept the terms.",
|
"signup_for_card_accept_terms": "Sign up for the card and accept the terms.",
|
||||||
|
"silent_payments": "Silent Payments",
|
||||||
|
"silent_payments_always_scan": "Set Silent Payments always scanning",
|
||||||
|
"silent_payments_disclaimer": "New addresses are not new identities. It is a re-use of an existing identity with a different label.",
|
||||||
|
"silent_payments_display_card": "Show Silent Payments card",
|
||||||
|
"silent_payments_scan_from_date": "Scan from date",
|
||||||
|
"silent_payments_scan_from_date_or_blockheight": "Please enter the block height you want to start scanning for incoming silent payments, or, use the date instead. You can choose if the wallet continues scanning every block, or checks only the specified height.",
|
||||||
|
"silent_payments_scan_from_height": "Scan from block height",
|
||||||
|
"silent_payments_scanned_tip": "SCANNED TO TIP! (${tip})",
|
||||||
|
"silent_payments_scanning": "Silent Payments Scanning",
|
||||||
|
"silent_payments_settings": "Silent Payments settings",
|
||||||
"slidable": "Slidable",
|
"slidable": "Slidable",
|
||||||
"sort_by": "Sort by",
|
"sort_by": "Sort by",
|
||||||
"spend_key_private": "Spend key (private)",
|
"spend_key_private": "Spend key (private)",
|
||||||
"spend_key_public": "Spend key (public)",
|
"spend_key_public": "Spend key (public)",
|
||||||
"status": "Status: ",
|
"status": "Status: ",
|
||||||
|
"string_default": "Default",
|
||||||
"subaddress_title": "Subaddress list",
|
"subaddress_title": "Subaddress list",
|
||||||
"subaddresses": "Subaddresses",
|
"subaddresses": "Subaddresses",
|
||||||
"submit_request": "submit a request",
|
"submit_request": "submit a request",
|
||||||
|
@ -670,10 +687,13 @@
|
||||||
"sync_status_starting_sync": "STARTING SYNC",
|
"sync_status_starting_sync": "STARTING SYNC",
|
||||||
"sync_status_syncronized": "SYNCHRONIZED",
|
"sync_status_syncronized": "SYNCHRONIZED",
|
||||||
"sync_status_syncronizing": "SYNCHRONIZING",
|
"sync_status_syncronizing": "SYNCHRONIZING",
|
||||||
|
"sync_status_timed_out": "TIMED OUT",
|
||||||
|
"sync_status_unsupported": "UNSUPPORTED NODE",
|
||||||
"syncing_wallet_alert_content": "Your balance and transaction list may not be complete until it says “SYNCHRONIZED” at the top. Click/tap to learn more.",
|
"syncing_wallet_alert_content": "Your balance and transaction list may not be complete until it says “SYNCHRONIZED” at the top. Click/tap to learn more.",
|
||||||
"syncing_wallet_alert_title": "Your wallet is syncing",
|
"syncing_wallet_alert_title": "Your wallet is syncing",
|
||||||
"template": "Template",
|
"template": "Template",
|
||||||
"template_name": "Template Name",
|
"template_name": "Template Name",
|
||||||
|
"testnet_coins_no_value": "Testnet coins have no value",
|
||||||
"third_intro_content": "Yats live outside of Cake Wallet, too. Any wallet address on earth can be replaced with a Yat!",
|
"third_intro_content": "Yats live outside of Cake Wallet, too. Any wallet address on earth can be replaced with a Yat!",
|
||||||
"third_intro_title": "Yat plays nicely with others",
|
"third_intro_title": "Yat plays nicely with others",
|
||||||
"thorchain_contract_address_not_supported": "THORChain does not support sending to a contract address",
|
"thorchain_contract_address_not_supported": "THORChain does not support sending to a contract address",
|
||||||
|
@ -749,13 +769,16 @@
|
||||||
"trusted": "Trusted",
|
"trusted": "Trusted",
|
||||||
"tx_commit_exception_no_dust_on_change": "The transaction is rejected with this amount. With these coins you can send ${min} without change or ${max} that returns change.",
|
"tx_commit_exception_no_dust_on_change": "The transaction is rejected with this amount. With these coins you can send ${min} without change or ${max} that returns change.",
|
||||||
"tx_commit_failed": "Transaction commit failed. Please contact support.",
|
"tx_commit_failed": "Transaction commit failed. Please contact support.",
|
||||||
|
"tx_invalid_input": "You are using the wrong input type for this type of payment",
|
||||||
"tx_no_dust_exception": "The transaction is rejected by sending an amount too small. Please try increasing the amount.",
|
"tx_no_dust_exception": "The transaction is rejected by sending an amount too small. Please try increasing the amount.",
|
||||||
"tx_not_enough_inputs_exception": "Not enough inputs available. Please select more under Coin Control",
|
"tx_not_enough_inputs_exception": "Not enough inputs available. Please select more under Coin Control",
|
||||||
|
"tx_rejected_bip68_final": "Transaction has unconfirmed inputs and failed to replace by fee.",
|
||||||
"tx_rejected_dust_change": "Transaction rejected by network rules, low change amount (dust). Try sending ALL or reducing the amount.",
|
"tx_rejected_dust_change": "Transaction rejected by network rules, low change amount (dust). Try sending ALL or reducing the amount.",
|
||||||
"tx_rejected_dust_output": "Transaction rejected by network rules, low output amount (dust). Please increase the amount.",
|
"tx_rejected_dust_output": "Transaction rejected by network rules, low output amount (dust). Please increase the amount.",
|
||||||
"tx_rejected_dust_output_send_all": "Transaction rejected by network rules, low output amount (dust). Please check the balance of coins selected under Coin Control.",
|
"tx_rejected_dust_output_send_all": "Transaction rejected by network rules, low output amount (dust). Please check the balance of coins selected under Coin Control.",
|
||||||
"tx_rejected_vout_negative": "Not enough balance to pay for this transaction's fees. Please check the balance of coins under Coin Control.",
|
"tx_rejected_vout_negative": "Not enough balance to pay for this transaction's fees. Please check the balance of coins under Coin Control.",
|
||||||
"tx_wrong_balance_exception": "You do not have enough ${currency} to send this amount.",
|
"tx_wrong_balance_exception": "You do not have enough ${currency} to send this amount.",
|
||||||
|
"tx_wrong_balance_with_amount_exception": "You do not have enough ${currency} to send the total amount of ${amount}",
|
||||||
"tx_zero_fee_exception": "Cannot send transaction with 0 fee. Try increasing the rate or checking your connection for latest estimates.",
|
"tx_zero_fee_exception": "Cannot send transaction with 0 fee. Try increasing the rate or checking your connection for latest estimates.",
|
||||||
"unavailable_balance": "Unavailable balance",
|
"unavailable_balance": "Unavailable balance",
|
||||||
"unavailable_balance_description": "Unavailable Balance: This total includes funds that are locked in pending transactions and those you have actively frozen in your coin control settings. Locked balances will become available once their respective transactions are completed, while frozen balances remain inaccessible for transactions until you decide to unfreeze them.",
|
"unavailable_balance_description": "Unavailable Balance: This total includes funds that are locked in pending transactions and those you have actively frozen in your coin control settings. Locked balances will become available once their respective transactions are completed, while frozen balances remain inaccessible for transactions until you decide to unfreeze them.",
|
||||||
|
@ -809,6 +832,7 @@
|
||||||
"warning": "Warning",
|
"warning": "Warning",
|
||||||
"welcome": "Welcome to",
|
"welcome": "Welcome to",
|
||||||
"welcome_to_cakepay": "Welcome to Cake Pay!",
|
"welcome_to_cakepay": "Welcome to Cake Pay!",
|
||||||
|
"what_is_silent_payments": "What is silent payments?",
|
||||||
"widgets_address": "Address",
|
"widgets_address": "Address",
|
||||||
"widgets_or": "or",
|
"widgets_or": "or",
|
||||||
"widgets_restore_from_blockheight": "Restore from blockheight",
|
"widgets_restore_from_blockheight": "Restore from blockheight",
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
"backup": "Apoyo",
|
"backup": "Apoyo",
|
||||||
"backup_file": "Archivo de respaldo",
|
"backup_file": "Archivo de respaldo",
|
||||||
"backup_password": "Contraseña de respaldo",
|
"backup_password": "Contraseña de respaldo",
|
||||||
|
"balance": "Balance",
|
||||||
"balance_page": "Página de saldo",
|
"balance_page": "Página de saldo",
|
||||||
"bill_amount": "Importe de la factura",
|
"bill_amount": "Importe de la factura",
|
||||||
"billing_address_info": "Si se le solicita una dirección de facturación, proporcione su dirección de envío",
|
"billing_address_info": "Si se le solicita una dirección de facturación, proporcione su dirección de envío",
|
||||||
|
@ -78,6 +79,7 @@
|
||||||
"bitcoin_dark_theme": "Tema oscuro de Bitcoin",
|
"bitcoin_dark_theme": "Tema oscuro de Bitcoin",
|
||||||
"bitcoin_light_theme": "Tema de la luz de Bitcoin",
|
"bitcoin_light_theme": "Tema de la luz de Bitcoin",
|
||||||
"bitcoin_payments_require_1_confirmation": "Los pagos de Bitcoin requieren 1 confirmación, que puede demorar 20 minutos o más. ¡Gracias por su paciencia! Se le enviará un correo electrónico cuando se confirme el pago.",
|
"bitcoin_payments_require_1_confirmation": "Los pagos de Bitcoin requieren 1 confirmación, que puede demorar 20 minutos o más. ¡Gracias por su paciencia! Se le enviará un correo electrónico cuando se confirme el pago.",
|
||||||
|
"block_remaining": "1 bloqueo restante",
|
||||||
"Blocks_remaining": "${status} Bloques restantes",
|
"Blocks_remaining": "${status} Bloques restantes",
|
||||||
"bluetooth": "Bluetooth",
|
"bluetooth": "Bluetooth",
|
||||||
"bright_theme": "Brillante",
|
"bright_theme": "Brillante",
|
||||||
|
@ -139,6 +141,7 @@
|
||||||
"confirm_fee_deduction": "Confirmar la deducción de la tarifa",
|
"confirm_fee_deduction": "Confirmar la deducción de la tarifa",
|
||||||
"confirm_fee_deduction_content": "¿Acepta deducir la tarifa de la producción?",
|
"confirm_fee_deduction_content": "¿Acepta deducir la tarifa de la producción?",
|
||||||
"confirm_sending": "Confirmar envío",
|
"confirm_sending": "Confirmar envío",
|
||||||
|
"confirm_silent_payments_switch_node": "Actualmente se requiere cambiar los nodos para escanear pagos silenciosos",
|
||||||
"confirmations": "Confirmaciones",
|
"confirmations": "Confirmaciones",
|
||||||
"confirmed": "Saldo confirmado",
|
"confirmed": "Saldo confirmado",
|
||||||
"confirmed_tx": "Confirmado",
|
"confirmed_tx": "Confirmado",
|
||||||
|
@ -221,6 +224,7 @@
|
||||||
"electrum_address_disclaimer": "Generamos nuevas direcciones cada vez que usa una, pero las direcciones anteriores siguen funcionando",
|
"electrum_address_disclaimer": "Generamos nuevas direcciones cada vez que usa una, pero las direcciones anteriores siguen funcionando",
|
||||||
"email_address": "Dirección de correo electrónico",
|
"email_address": "Dirección de correo electrónico",
|
||||||
"enable_replace_by_fee": "Habilitar reemplazar por tarea",
|
"enable_replace_by_fee": "Habilitar reemplazar por tarea",
|
||||||
|
"enable_silent_payments_scanning": "Habilitar escaneo de pagos silenciosos",
|
||||||
"enabled": "Activado",
|
"enabled": "Activado",
|
||||||
"enter_amount": "Ingrese la cantidad",
|
"enter_amount": "Ingrese la cantidad",
|
||||||
"enter_backup_password": "Ingrese la contraseña de respaldo aquí",
|
"enter_backup_password": "Ingrese la contraseña de respaldo aquí",
|
||||||
|
@ -278,6 +282,7 @@
|
||||||
"extracted_address_content": "Enviará fondos a\n${recipient_name}",
|
"extracted_address_content": "Enviará fondos a\n${recipient_name}",
|
||||||
"failed_authentication": "Autenticación fallida. ${state_error}",
|
"failed_authentication": "Autenticación fallida. ${state_error}",
|
||||||
"faq": "FAQ",
|
"faq": "FAQ",
|
||||||
|
"features": "Características",
|
||||||
"fetching": "Cargando",
|
"fetching": "Cargando",
|
||||||
"fiat_api": "Fiat API",
|
"fiat_api": "Fiat API",
|
||||||
"fiat_balance": "Equilibrio Fiat",
|
"fiat_balance": "Equilibrio Fiat",
|
||||||
|
@ -532,6 +537,7 @@
|
||||||
"save_backup_password_alert": "Guardar contraseña de respaldo",
|
"save_backup_password_alert": "Guardar contraseña de respaldo",
|
||||||
"save_to_downloads": "Guardar en Descargas",
|
"save_to_downloads": "Guardar en Descargas",
|
||||||
"saved_the_trade_id": "He salvado comercial ID",
|
"saved_the_trade_id": "He salvado comercial ID",
|
||||||
|
"scan_one_block": "Escanear un bloque",
|
||||||
"scan_qr_code": "Escanear código QR",
|
"scan_qr_code": "Escanear código QR",
|
||||||
"scan_qr_code_to_get_address": "Escanee el código QR para obtener la dirección",
|
"scan_qr_code_to_get_address": "Escanee el código QR para obtener la dirección",
|
||||||
"scan_qr_on_device": "Escanea este código QR en otro dispositivo",
|
"scan_qr_on_device": "Escanea este código QR en otro dispositivo",
|
||||||
|
@ -642,11 +648,22 @@
|
||||||
"sign_up": "Registrarse",
|
"sign_up": "Registrarse",
|
||||||
"signTransaction": "Firmar transacción",
|
"signTransaction": "Firmar transacción",
|
||||||
"signup_for_card_accept_terms": "Regístrese para obtener la tarjeta y acepte los términos.",
|
"signup_for_card_accept_terms": "Regístrese para obtener la tarjeta y acepte los términos.",
|
||||||
|
"silent_payments": "Pagos silenciosos",
|
||||||
|
"silent_payments_always_scan": "Establecer pagos silenciosos siempre escaneando",
|
||||||
|
"silent_payments_disclaimer": "Las nuevas direcciones no son nuevas identidades. Es una reutilización de una identidad existente con una etiqueta diferente.",
|
||||||
|
"silent_payments_display_card": "Mostrar tarjeta de pagos silenciosos",
|
||||||
|
"silent_payments_scan_from_date": "Escanear desde la fecha",
|
||||||
|
"silent_payments_scan_from_date_or_blockheight": "Ingrese la altura del bloque que desea comenzar a escanear para pagos silenciosos entrantes, o use la fecha en su lugar. Puede elegir si la billetera continúa escaneando cada bloque, o verifica solo la altura especificada.",
|
||||||
|
"silent_payments_scan_from_height": "Escanear desde la altura del bloque",
|
||||||
|
"silent_payments_scanned_tip": "Escaneado hasta la punta! (${tip})",
|
||||||
|
"silent_payments_scanning": "Escaneo de pagos silenciosos",
|
||||||
|
"silent_payments_settings": "Configuración de pagos silenciosos",
|
||||||
"slidable": "deslizable",
|
"slidable": "deslizable",
|
||||||
"sort_by": "Ordenar por",
|
"sort_by": "Ordenar por",
|
||||||
"spend_key_private": "Spend clave (privado)",
|
"spend_key_private": "Spend clave (privado)",
|
||||||
"spend_key_public": "Spend clave (público)",
|
"spend_key_public": "Spend clave (público)",
|
||||||
"status": "Estado: ",
|
"status": "Estado: ",
|
||||||
|
"string_default": "Por defecto",
|
||||||
"subaddress_title": "Lista de subdirecciones",
|
"subaddress_title": "Lista de subdirecciones",
|
||||||
"subaddresses": "Subdirecciones",
|
"subaddresses": "Subdirecciones",
|
||||||
"submit_request": "presentar una solicitud",
|
"submit_request": "presentar una solicitud",
|
||||||
|
@ -671,10 +688,13 @@
|
||||||
"sync_status_starting_sync": "EMPEZANDO A SINCRONIZAR",
|
"sync_status_starting_sync": "EMPEZANDO A SINCRONIZAR",
|
||||||
"sync_status_syncronized": "SINCRONIZADO",
|
"sync_status_syncronized": "SINCRONIZADO",
|
||||||
"sync_status_syncronizing": "SINCRONIZANDO",
|
"sync_status_syncronizing": "SINCRONIZANDO",
|
||||||
|
"sync_status_timed_out": "CADUCADO",
|
||||||
|
"sync_status_unsupported": "Nodo no compatible",
|
||||||
"syncing_wallet_alert_content": "Es posible que su lista de saldo y transacciones no esté completa hasta que diga \"SINCRONIZADO\" en la parte superior. Haga clic/toque para obtener más información.",
|
"syncing_wallet_alert_content": "Es posible que su lista de saldo y transacciones no esté completa hasta que diga \"SINCRONIZADO\" en la parte superior. Haga clic/toque para obtener más información.",
|
||||||
"syncing_wallet_alert_title": "Tu billetera se está sincronizando",
|
"syncing_wallet_alert_title": "Tu billetera se está sincronizando",
|
||||||
"template": "Plantilla",
|
"template": "Plantilla",
|
||||||
"template_name": "Nombre de la plantilla",
|
"template_name": "Nombre de la plantilla",
|
||||||
|
"testnet_coins_no_value": "Las monedas de prueba no tienen valor",
|
||||||
"third_intro_content": "Los Yats también viven fuera de Cake Wallet. Cualquier dirección de billetera en la tierra se puede reemplazar con un Yat!",
|
"third_intro_content": "Los Yats también viven fuera de Cake Wallet. Cualquier dirección de billetera en la tierra se puede reemplazar con un Yat!",
|
||||||
"third_intro_title": "Yat juega muy bien con otras",
|
"third_intro_title": "Yat juega muy bien con otras",
|
||||||
"thorchain_contract_address_not_supported": "Thorchain no admite enviar a una dirección de contrato",
|
"thorchain_contract_address_not_supported": "Thorchain no admite enviar a una dirección de contrato",
|
||||||
|
@ -750,13 +770,16 @@
|
||||||
"trusted": "de confianza",
|
"trusted": "de confianza",
|
||||||
"tx_commit_exception_no_dust_on_change": "La transacción se rechaza con esta cantidad. Con estas monedas puede enviar ${min} sin cambios o ${max} que devuelve el cambio.",
|
"tx_commit_exception_no_dust_on_change": "La transacción se rechaza con esta cantidad. Con estas monedas puede enviar ${min} sin cambios o ${max} que devuelve el cambio.",
|
||||||
"tx_commit_failed": "La confirmación de transacción falló. Póngase en contacto con el soporte.",
|
"tx_commit_failed": "La confirmación de transacción falló. Póngase en contacto con el soporte.",
|
||||||
|
"tx_invalid_input": "Está utilizando el tipo de entrada incorrecto para este tipo de pago",
|
||||||
"tx_no_dust_exception": "La transacción se rechaza enviando una cantidad demasiado pequeña. Intente aumentar la cantidad.",
|
"tx_no_dust_exception": "La transacción se rechaza enviando una cantidad demasiado pequeña. Intente aumentar la cantidad.",
|
||||||
"tx_not_enough_inputs_exception": "No hay suficientes entradas disponibles. Seleccione más bajo control de monedas",
|
"tx_not_enough_inputs_exception": "No hay suficientes entradas disponibles. Seleccione más bajo control de monedas",
|
||||||
|
"tx_rejected_bip68_final": "La transacción tiene entradas no confirmadas y no ha podido reemplazar por tarifa.",
|
||||||
"tx_rejected_dust_change": "Transacción rechazada por reglas de red, bajo cambio de cambio (polvo). Intente enviar todo o reducir la cantidad.",
|
"tx_rejected_dust_change": "Transacción rechazada por reglas de red, bajo cambio de cambio (polvo). Intente enviar todo o reducir la cantidad.",
|
||||||
"tx_rejected_dust_output": "Transacción rechazada por reglas de red, baja cantidad de salida (polvo). Aumente la cantidad.",
|
"tx_rejected_dust_output": "Transacción rechazada por reglas de red, baja cantidad de salida (polvo). Aumente la cantidad.",
|
||||||
"tx_rejected_dust_output_send_all": "Transacción rechazada por reglas de red, baja cantidad de salida (polvo). Verifique el saldo de monedas seleccionadas bajo control de monedas.",
|
"tx_rejected_dust_output_send_all": "Transacción rechazada por reglas de red, baja cantidad de salida (polvo). Verifique el saldo de monedas seleccionadas bajo control de monedas.",
|
||||||
"tx_rejected_vout_negative": "No es suficiente saldo para pagar las tarifas de esta transacción. Verifique el saldo de monedas bajo control de monedas.",
|
"tx_rejected_vout_negative": "No es suficiente saldo para pagar las tarifas de esta transacción. Verifique el saldo de monedas bajo control de monedas.",
|
||||||
"tx_wrong_balance_exception": "No tiene suficiente ${currency} para enviar esta cantidad.",
|
"tx_wrong_balance_exception": "No tiene suficiente ${currency} para enviar esta cantidad.",
|
||||||
|
"tx_wrong_balance_with_amount_exception": "No tiene suficiente ${currency} para enviar la cantidad total de ${amount}",
|
||||||
"tx_zero_fee_exception": "No se puede enviar transacciones con 0 tarifa. Intente aumentar la tasa o verificar su conexión para las últimas estimaciones.",
|
"tx_zero_fee_exception": "No se puede enviar transacciones con 0 tarifa. Intente aumentar la tasa o verificar su conexión para las últimas estimaciones.",
|
||||||
"unavailable_balance": "Saldo no disponible",
|
"unavailable_balance": "Saldo no disponible",
|
||||||
"unavailable_balance_description": "Saldo no disponible: este total incluye fondos que están bloqueados en transacciones pendientes y aquellos que usted ha congelado activamente en su configuración de control de monedas. Los saldos bloqueados estarán disponibles una vez que se completen sus respectivas transacciones, mientras que los saldos congelados permanecerán inaccesibles para las transacciones hasta que usted decida descongelarlos.",
|
"unavailable_balance_description": "Saldo no disponible: este total incluye fondos que están bloqueados en transacciones pendientes y aquellos que usted ha congelado activamente en su configuración de control de monedas. Los saldos bloqueados estarán disponibles una vez que se completen sus respectivas transacciones, mientras que los saldos congelados permanecerán inaccesibles para las transacciones hasta que usted decida descongelarlos.",
|
||||||
|
@ -810,6 +833,7 @@
|
||||||
"warning": "Advertencia",
|
"warning": "Advertencia",
|
||||||
"welcome": "Bienvenido",
|
"welcome": "Bienvenido",
|
||||||
"welcome_to_cakepay": "¡Bienvenido a Cake Pay!",
|
"welcome_to_cakepay": "¡Bienvenido a Cake Pay!",
|
||||||
|
"what_is_silent_payments": "¿Qué son los pagos silenciosos?",
|
||||||
"widgets_address": "Dirección",
|
"widgets_address": "Dirección",
|
||||||
"widgets_or": "o",
|
"widgets_or": "o",
|
||||||
"widgets_restore_from_blockheight": "Restaurar desde blockheight",
|
"widgets_restore_from_blockheight": "Restaurar desde blockheight",
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
"backup": "Sauvegarde",
|
"backup": "Sauvegarde",
|
||||||
"backup_file": "Fichier de sauvegarde",
|
"backup_file": "Fichier de sauvegarde",
|
||||||
"backup_password": "Mot de passe de sauvegarde",
|
"backup_password": "Mot de passe de sauvegarde",
|
||||||
|
"balance": "Équilibre",
|
||||||
"balance_page": "Page Solde",
|
"balance_page": "Page Solde",
|
||||||
"bill_amount": "Montant de la facture",
|
"bill_amount": "Montant de la facture",
|
||||||
"billing_address_info": "Si une adresse de facturation vous est demandée, indiquez votre adresse de livraison",
|
"billing_address_info": "Si une adresse de facturation vous est demandée, indiquez votre adresse de livraison",
|
||||||
|
@ -78,6 +79,7 @@
|
||||||
"bitcoin_dark_theme": "Thème sombre Bitcoin",
|
"bitcoin_dark_theme": "Thème sombre Bitcoin",
|
||||||
"bitcoin_light_theme": "Thème léger Bitcoin",
|
"bitcoin_light_theme": "Thème léger Bitcoin",
|
||||||
"bitcoin_payments_require_1_confirmation": "Les paiements Bitcoin nécessitent 1 confirmation, ce qui peut prendre 20 minutes ou plus. Merci pour votre patience ! Vous serez averti par e-mail lorsque le paiement sera confirmé.",
|
"bitcoin_payments_require_1_confirmation": "Les paiements Bitcoin nécessitent 1 confirmation, ce qui peut prendre 20 minutes ou plus. Merci pour votre patience ! Vous serez averti par e-mail lorsque le paiement sera confirmé.",
|
||||||
|
"block_remaining": "1 bloc restant",
|
||||||
"Blocks_remaining": "Blocs Restants : ${status}",
|
"Blocks_remaining": "Blocs Restants : ${status}",
|
||||||
"bluetooth": "Bluetooth",
|
"bluetooth": "Bluetooth",
|
||||||
"bright_theme": "Vif",
|
"bright_theme": "Vif",
|
||||||
|
@ -139,6 +141,7 @@
|
||||||
"confirm_fee_deduction": "Confirmer la déduction des frais",
|
"confirm_fee_deduction": "Confirmer la déduction des frais",
|
||||||
"confirm_fee_deduction_content": "Acceptez-vous de déduire les frais de la production?",
|
"confirm_fee_deduction_content": "Acceptez-vous de déduire les frais de la production?",
|
||||||
"confirm_sending": "Confirmer l'envoi",
|
"confirm_sending": "Confirmer l'envoi",
|
||||||
|
"confirm_silent_payments_switch_node": "Actuellement, il est nécessaire de changer de nœuds pour scanner les paiements silencieux",
|
||||||
"confirmations": "Confirmations",
|
"confirmations": "Confirmations",
|
||||||
"confirmed": "Solde confirmé",
|
"confirmed": "Solde confirmé",
|
||||||
"confirmed_tx": "Confirmé",
|
"confirmed_tx": "Confirmé",
|
||||||
|
@ -221,6 +224,7 @@
|
||||||
"electrum_address_disclaimer": "Nous générons de nouvelles adresses à chaque fois que vous en utilisez une, mais les adresses précédentes continuent à fonctionner",
|
"electrum_address_disclaimer": "Nous générons de nouvelles adresses à chaque fois que vous en utilisez une, mais les adresses précédentes continuent à fonctionner",
|
||||||
"email_address": "Adresse e-mail",
|
"email_address": "Adresse e-mail",
|
||||||
"enable_replace_by_fee": "Activer Remplace-by-Fee",
|
"enable_replace_by_fee": "Activer Remplace-by-Fee",
|
||||||
|
"enable_silent_payments_scanning": "Activer la numérisation des paiements silencieux",
|
||||||
"enabled": "Activé",
|
"enabled": "Activé",
|
||||||
"enter_amount": "Entrez le montant",
|
"enter_amount": "Entrez le montant",
|
||||||
"enter_backup_password": "Entrez le mot de passe de sauvegarde ici",
|
"enter_backup_password": "Entrez le mot de passe de sauvegarde ici",
|
||||||
|
@ -278,6 +282,7 @@
|
||||||
"extracted_address_content": "Vous allez envoyer des fonds à\n${recipient_name}",
|
"extracted_address_content": "Vous allez envoyer des fonds à\n${recipient_name}",
|
||||||
"failed_authentication": "Échec d'authentification. ${state_error}",
|
"failed_authentication": "Échec d'authentification. ${state_error}",
|
||||||
"faq": "FAQ",
|
"faq": "FAQ",
|
||||||
|
"features": "Caractéristiques",
|
||||||
"fetching": "Récupération",
|
"fetching": "Récupération",
|
||||||
"fiat_api": "Fiat API",
|
"fiat_api": "Fiat API",
|
||||||
"fiat_balance": "Solde fiat",
|
"fiat_balance": "Solde fiat",
|
||||||
|
@ -531,6 +536,7 @@
|
||||||
"save_backup_password_alert": "Enregistrer le mot de passe de sauvegarde",
|
"save_backup_password_alert": "Enregistrer le mot de passe de sauvegarde",
|
||||||
"save_to_downloads": "Enregistrer dans les téléchargements",
|
"save_to_downloads": "Enregistrer dans les téléchargements",
|
||||||
"saved_the_trade_id": "J'ai sauvegardé l'ID d'échange",
|
"saved_the_trade_id": "J'ai sauvegardé l'ID d'échange",
|
||||||
|
"scan_one_block": "Scanner un bloc",
|
||||||
"scan_qr_code": "Scannez le QR code",
|
"scan_qr_code": "Scannez le QR code",
|
||||||
"scan_qr_code_to_get_address": "Scannez le QR code pour obtenir l'adresse",
|
"scan_qr_code_to_get_address": "Scannez le QR code pour obtenir l'adresse",
|
||||||
"scan_qr_on_device": "Scannez ce code QR sur un autre appareil",
|
"scan_qr_on_device": "Scannez ce code QR sur un autre appareil",
|
||||||
|
@ -641,11 +647,22 @@
|
||||||
"sign_up": "S'inscrire",
|
"sign_up": "S'inscrire",
|
||||||
"signTransaction": "Signer une transaction",
|
"signTransaction": "Signer une transaction",
|
||||||
"signup_for_card_accept_terms": "Inscrivez-vous pour la carte et acceptez les conditions.",
|
"signup_for_card_accept_terms": "Inscrivez-vous pour la carte et acceptez les conditions.",
|
||||||
|
"silent_payments": "Paiements silencieux",
|
||||||
|
"silent_payments_always_scan": "Définir les paiements silencieux toujours à la scanne",
|
||||||
|
"silent_payments_disclaimer": "Les nouvelles adresses ne sont pas de nouvelles identités. Il s'agit d'une réutilisation d'une identité existante avec une étiquette différente.",
|
||||||
|
"silent_payments_display_card": "Afficher la carte de paiement silencieuse",
|
||||||
|
"silent_payments_scan_from_date": "Analyser à partir de la date",
|
||||||
|
"silent_payments_scan_from_date_or_blockheight": "Veuillez saisir la hauteur du bloc que vous souhaitez commencer à scanner pour les paiements silencieux entrants, ou utilisez la date à la place. Vous pouvez choisir si le portefeuille continue de numériser chaque bloc ou ne vérifie que la hauteur spécifiée.",
|
||||||
|
"silent_payments_scan_from_height": "Scan à partir de la hauteur du bloc",
|
||||||
|
"silent_payments_scanned_tip": "Scanné à la pointe! (${tip})",
|
||||||
|
"silent_payments_scanning": "Payments silencieux SCANNING",
|
||||||
|
"silent_payments_settings": "Paramètres de paiement silencieux",
|
||||||
"slidable": "Glissable",
|
"slidable": "Glissable",
|
||||||
"sort_by": "Trier par",
|
"sort_by": "Trier par",
|
||||||
"spend_key_private": "Clef de dépense (spend key) (privée)",
|
"spend_key_private": "Clef de dépense (spend key) (privée)",
|
||||||
"spend_key_public": "Clef de dépense (spend key) (publique)",
|
"spend_key_public": "Clef de dépense (spend key) (publique)",
|
||||||
"status": "Statut : ",
|
"status": "Statut : ",
|
||||||
|
"string_default": "Défaut",
|
||||||
"subaddress_title": "Liste des sous-adresses",
|
"subaddress_title": "Liste des sous-adresses",
|
||||||
"subaddresses": "Sous-adresses",
|
"subaddresses": "Sous-adresses",
|
||||||
"submit_request": "soumettre une requête",
|
"submit_request": "soumettre une requête",
|
||||||
|
@ -670,10 +687,13 @@
|
||||||
"sync_status_starting_sync": "DÉBUT DE SYNCHRO",
|
"sync_status_starting_sync": "DÉBUT DE SYNCHRO",
|
||||||
"sync_status_syncronized": "SYNCHRONISÉ",
|
"sync_status_syncronized": "SYNCHRONISÉ",
|
||||||
"sync_status_syncronizing": "SYNCHRONISATION EN COURS",
|
"sync_status_syncronizing": "SYNCHRONISATION EN COURS",
|
||||||
|
"sync_status_timed_out": "FIN DU TEMPS",
|
||||||
|
"sync_status_unsupported": "Nœud non pris en charge",
|
||||||
"syncing_wallet_alert_content": "Votre solde et votre liste de transactions peuvent ne pas être à jour tant que la mention « SYNCHRONISÉ » n'apparaît en haut de l'écran. Cliquez/appuyez pour en savoir plus.",
|
"syncing_wallet_alert_content": "Votre solde et votre liste de transactions peuvent ne pas être à jour tant que la mention « SYNCHRONISÉ » n'apparaît en haut de l'écran. Cliquez/appuyez pour en savoir plus.",
|
||||||
"syncing_wallet_alert_title": "Votre portefeuille (wallet) est en cours de synchronisation",
|
"syncing_wallet_alert_title": "Votre portefeuille (wallet) est en cours de synchronisation",
|
||||||
"template": "Modèle",
|
"template": "Modèle",
|
||||||
"template_name": "Nom du modèle",
|
"template_name": "Nom du modèle",
|
||||||
|
"testnet_coins_no_value": "Les pièces TestNet n'ont aucune valeur",
|
||||||
"third_intro_content": "Les Yats existent aussi en dehors de Cake Wallet. Toute adresse sur terre peut être remplacée par un Yat !",
|
"third_intro_content": "Les Yats existent aussi en dehors de Cake Wallet. Toute adresse sur terre peut être remplacée par un Yat !",
|
||||||
"third_intro_title": "Yat est universel",
|
"third_intro_title": "Yat est universel",
|
||||||
"thorchain_contract_address_not_supported": "Thorchain ne prend pas en charge l'envoi à une adresse de contrat",
|
"thorchain_contract_address_not_supported": "Thorchain ne prend pas en charge l'envoi à une adresse de contrat",
|
||||||
|
@ -749,13 +769,16 @@
|
||||||
"trusted": "de confiance",
|
"trusted": "de confiance",
|
||||||
"tx_commit_exception_no_dust_on_change": "La transaction est rejetée avec ce montant. Avec ces pièces, vous pouvez envoyer ${min} sans changement ou ${max} qui renvoie le changement.",
|
"tx_commit_exception_no_dust_on_change": "La transaction est rejetée avec ce montant. Avec ces pièces, vous pouvez envoyer ${min} sans changement ou ${max} qui renvoie le changement.",
|
||||||
"tx_commit_failed": "La validation de la transaction a échoué. Veuillez contacter l'assistance.",
|
"tx_commit_failed": "La validation de la transaction a échoué. Veuillez contacter l'assistance.",
|
||||||
|
"tx_invalid_input": "Vous utilisez le mauvais type d'entrée pour ce type de paiement",
|
||||||
"tx_no_dust_exception": "La transaction est rejetée en envoyant un montant trop faible. Veuillez essayer d'augmenter le montant.",
|
"tx_no_dust_exception": "La transaction est rejetée en envoyant un montant trop faible. Veuillez essayer d'augmenter le montant.",
|
||||||
"tx_not_enough_inputs_exception": "Pas assez d'entrées disponibles. Veuillez sélectionner plus sous Control Control",
|
"tx_not_enough_inputs_exception": "Pas assez d'entrées disponibles. Veuillez sélectionner plus sous Control Control",
|
||||||
|
"tx_rejected_bip68_final": "La transaction a des entrées non confirmées et n'a pas réussi à remplacer par les frais.",
|
||||||
"tx_rejected_dust_change": "Transaction rejetée par les règles du réseau, montant de faible variation (poussière). Essayez d'envoyer tout ou de réduire le montant.",
|
"tx_rejected_dust_change": "Transaction rejetée par les règles du réseau, montant de faible variation (poussière). Essayez d'envoyer tout ou de réduire le montant.",
|
||||||
"tx_rejected_dust_output": "Transaction rejetée par les règles du réseau, faible quantité de sortie (poussière). Veuillez augmenter le montant.",
|
"tx_rejected_dust_output": "Transaction rejetée par les règles du réseau, faible quantité de sortie (poussière). Veuillez augmenter le montant.",
|
||||||
"tx_rejected_dust_output_send_all": "Transaction rejetée par les règles du réseau, faible quantité de sortie (poussière). Veuillez vérifier le solde des pièces sélectionnées sous le contrôle des pièces de monnaie.",
|
"tx_rejected_dust_output_send_all": "Transaction rejetée par les règles du réseau, faible quantité de sortie (poussière). Veuillez vérifier le solde des pièces sélectionnées sous le contrôle des pièces de monnaie.",
|
||||||
"tx_rejected_vout_negative": "Pas assez de solde pour payer les frais de cette transaction. Veuillez vérifier le solde des pièces sous le contrôle des pièces.",
|
"tx_rejected_vout_negative": "Pas assez de solde pour payer les frais de cette transaction. Veuillez vérifier le solde des pièces sous le contrôle des pièces.",
|
||||||
"tx_wrong_balance_exception": "Vous n'avez pas assez ${currency} pour envoyer ce montant.",
|
"tx_wrong_balance_exception": "Vous n'avez pas assez ${currency} pour envoyer ce montant.",
|
||||||
|
"tx_wrong_balance_with_amount_exception": "Vous n'avez pas assez ${currency} pour envoyer le montant total de ${amount}",
|
||||||
"tx_zero_fee_exception": "Impossible d'envoyer une transaction avec 0 frais. Essayez d'augmenter le taux ou de vérifier votre connexion pour les dernières estimations.",
|
"tx_zero_fee_exception": "Impossible d'envoyer une transaction avec 0 frais. Essayez d'augmenter le taux ou de vérifier votre connexion pour les dernières estimations.",
|
||||||
"unavailable_balance": "Solde indisponible",
|
"unavailable_balance": "Solde indisponible",
|
||||||
"unavailable_balance_description": "Solde indisponible : ce total comprend les fonds bloqués dans les transactions en attente et ceux que vous avez activement gelés dans vos paramètres de contrôle des pièces. Les soldes bloqués deviendront disponibles une fois leurs transactions respectives terminées, tandis que les soldes gelés resteront inaccessibles aux transactions jusqu'à ce que vous décidiez de les débloquer.",
|
"unavailable_balance_description": "Solde indisponible : ce total comprend les fonds bloqués dans les transactions en attente et ceux que vous avez activement gelés dans vos paramètres de contrôle des pièces. Les soldes bloqués deviendront disponibles une fois leurs transactions respectives terminées, tandis que les soldes gelés resteront inaccessibles aux transactions jusqu'à ce que vous décidiez de les débloquer.",
|
||||||
|
@ -809,6 +832,7 @@
|
||||||
"warning": "Avertissement",
|
"warning": "Avertissement",
|
||||||
"welcome": "Bienvenue sur",
|
"welcome": "Bienvenue sur",
|
||||||
"welcome_to_cakepay": "Bienvenue sur Cake Pay !",
|
"welcome_to_cakepay": "Bienvenue sur Cake Pay !",
|
||||||
|
"what_is_silent_payments": "Qu'est-ce que les paiements silencieux?",
|
||||||
"widgets_address": "Adresse",
|
"widgets_address": "Adresse",
|
||||||
"widgets_or": "ou",
|
"widgets_or": "ou",
|
||||||
"widgets_restore_from_blockheight": "Restaurer depuis une hauteur de bloc",
|
"widgets_restore_from_blockheight": "Restaurer depuis une hauteur de bloc",
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
"backup": "Ajiyayyen",
|
"backup": "Ajiyayyen",
|
||||||
"backup_file": "Ajiyayyen fayil",
|
"backup_file": "Ajiyayyen fayil",
|
||||||
"backup_password": "Ajiyayyen kalmar sirri",
|
"backup_password": "Ajiyayyen kalmar sirri",
|
||||||
|
"balance": "Ma'auni",
|
||||||
"balance_page": "Ma'auni Page",
|
"balance_page": "Ma'auni Page",
|
||||||
"bill_amount": "Adadin Bill",
|
"bill_amount": "Adadin Bill",
|
||||||
"billing_address_info": "Idan an nemi adireshin biyan kuɗi, samar da adireshin jigilar kaya",
|
"billing_address_info": "Idan an nemi adireshin biyan kuɗi, samar da adireshin jigilar kaya",
|
||||||
|
@ -78,6 +79,7 @@
|
||||||
"bitcoin_dark_theme": "Bitcoin Dark Jigo",
|
"bitcoin_dark_theme": "Bitcoin Dark Jigo",
|
||||||
"bitcoin_light_theme": "Jigon Hasken Bitcoin",
|
"bitcoin_light_theme": "Jigon Hasken Bitcoin",
|
||||||
"bitcoin_payments_require_1_confirmation": "Akwatin Bitcoin na buɗe 1 sambumbu, da yake za ta samu mintuna 20 ko yawa. Ina kira ga sabuwar lafiya! Zaka sanarwa ta email lokacin da aka samu akwatin samun lambar waya.",
|
"bitcoin_payments_require_1_confirmation": "Akwatin Bitcoin na buɗe 1 sambumbu, da yake za ta samu mintuna 20 ko yawa. Ina kira ga sabuwar lafiya! Zaka sanarwa ta email lokacin da aka samu akwatin samun lambar waya.",
|
||||||
|
"block_remaining": "1 toshe ragowar",
|
||||||
"Blocks_remaining": "${status} Katanga ya rage",
|
"Blocks_remaining": "${status} Katanga ya rage",
|
||||||
"bluetooth": "Bluetooth",
|
"bluetooth": "Bluetooth",
|
||||||
"bright_theme": "Mai haske",
|
"bright_theme": "Mai haske",
|
||||||
|
@ -139,6 +141,7 @@
|
||||||
"confirm_fee_deduction": "Tabbatar da cire kudade",
|
"confirm_fee_deduction": "Tabbatar da cire kudade",
|
||||||
"confirm_fee_deduction_content": "Shin kun yarda ku cire kuɗin daga fitarwa?",
|
"confirm_fee_deduction_content": "Shin kun yarda ku cire kuɗin daga fitarwa?",
|
||||||
"confirm_sending": "Tabbatar da aikawa",
|
"confirm_sending": "Tabbatar da aikawa",
|
||||||
|
"confirm_silent_payments_switch_node": "A halin yanzu ana buƙatar sauya nodes don bincika biyan siliki",
|
||||||
"confirmations": "Tabbatar",
|
"confirmations": "Tabbatar",
|
||||||
"confirmed": "An tabbatar",
|
"confirmed": "An tabbatar",
|
||||||
"confirmed_tx": "Tabbatar",
|
"confirmed_tx": "Tabbatar",
|
||||||
|
@ -221,6 +224,7 @@
|
||||||
"electrum_address_disclaimer": "Muna samar da sababbin adireshi duk lokacin da kuka yi amfani da ɗaya, amma adiresoshin da suka gabata suna ci gaba da aiki",
|
"electrum_address_disclaimer": "Muna samar da sababbin adireshi duk lokacin da kuka yi amfani da ɗaya, amma adiresoshin da suka gabata suna ci gaba da aiki",
|
||||||
"email_address": "Adireshin i-mel",
|
"email_address": "Adireshin i-mel",
|
||||||
"enable_replace_by_fee": "Ba da damar maye gurbin-by-kudin",
|
"enable_replace_by_fee": "Ba da damar maye gurbin-by-kudin",
|
||||||
|
"enable_silent_payments_scanning": "Kunna biya biya",
|
||||||
"enabled": "An kunna",
|
"enabled": "An kunna",
|
||||||
"enter_amount": "Shigar da Adadi",
|
"enter_amount": "Shigar da Adadi",
|
||||||
"enter_backup_password": "Shigar da kalmar wucewa ta madadin nan",
|
"enter_backup_password": "Shigar da kalmar wucewa ta madadin nan",
|
||||||
|
@ -278,6 +282,7 @@
|
||||||
"extracted_address_content": "Za ku aika da kudade zuwa\n${recipient_name}",
|
"extracted_address_content": "Za ku aika da kudade zuwa\n${recipient_name}",
|
||||||
"failed_authentication": "Binne wajen shiga. ${state_error}",
|
"failed_authentication": "Binne wajen shiga. ${state_error}",
|
||||||
"faq": "FAQ",
|
"faq": "FAQ",
|
||||||
|
"features": "Fasas",
|
||||||
"fetching": "Daukewa",
|
"fetching": "Daukewa",
|
||||||
"fiat_api": "API ɗin Fiat",
|
"fiat_api": "API ɗin Fiat",
|
||||||
"fiat_balance": "Fiat Balance",
|
"fiat_balance": "Fiat Balance",
|
||||||
|
@ -533,6 +538,7 @@
|
||||||
"save_backup_password_alert": "Ajiye kalmar sirri ta ajiya",
|
"save_backup_password_alert": "Ajiye kalmar sirri ta ajiya",
|
||||||
"save_to_downloads": "Ajiye zuwa Zazzagewa",
|
"save_to_downloads": "Ajiye zuwa Zazzagewa",
|
||||||
"saved_the_trade_id": "Na ajiye ID na ciniki",
|
"saved_the_trade_id": "Na ajiye ID na ciniki",
|
||||||
|
"scan_one_block": "Duba toshe daya",
|
||||||
"scan_qr_code": "Gani QR kodin",
|
"scan_qr_code": "Gani QR kodin",
|
||||||
"scan_qr_code_to_get_address": "Duba lambar QR don samun adireshin",
|
"scan_qr_code_to_get_address": "Duba lambar QR don samun adireshin",
|
||||||
"scan_qr_on_device": "Duba wannan lambar QR akan wata na'ura",
|
"scan_qr_on_device": "Duba wannan lambar QR akan wata na'ura",
|
||||||
|
@ -643,11 +649,22 @@
|
||||||
"sign_up": "Shiga",
|
"sign_up": "Shiga",
|
||||||
"signTransaction": "Sa hannu Ma'amala",
|
"signTransaction": "Sa hannu Ma'amala",
|
||||||
"signup_for_card_accept_terms": "Yi rajista don katin kuma karɓi sharuɗɗan.",
|
"signup_for_card_accept_terms": "Yi rajista don katin kuma karɓi sharuɗɗan.",
|
||||||
|
"silent_payments": "Biya silent",
|
||||||
|
"silent_payments_always_scan": "Saita biya na shiru koyaushe",
|
||||||
|
"silent_payments_disclaimer": "Sabbin adiresoshin ba sabon tsari bane. Wannan shine sake amfani da asalin asalin tare da wata alama daban.",
|
||||||
|
"silent_payments_display_card": "Nuna katin silent",
|
||||||
|
"silent_payments_scan_from_date": "Scan daga kwanan wata",
|
||||||
|
"silent_payments_scan_from_date_or_blockheight": "Da fatan za a shigar da toshe wurin da kake son fara bincika don biyan silins mai shigowa, ko, yi amfani da kwanan wata. Zaka iya zabar idan walat ɗin ya ci gaba da bincika kowane toshe, ko duba tsinkaye da aka ƙayyade.",
|
||||||
|
"silent_payments_scan_from_height": "Scan daga tsayin daka",
|
||||||
|
"silent_payments_scanned_tip": "Bincika don tip! (${tip})",
|
||||||
|
"silent_payments_scanning": "Silent biya scanning",
|
||||||
|
"silent_payments_settings": "Saitunan Silent",
|
||||||
"slidable": "Mai iya zamewa",
|
"slidable": "Mai iya zamewa",
|
||||||
"sort_by": "Kasa",
|
"sort_by": "Kasa",
|
||||||
"spend_key_private": "makullin biya (maɓallin kalmar sirri)",
|
"spend_key_private": "makullin biya (maɓallin kalmar sirri)",
|
||||||
"spend_key_public": "makullin biya (maɓallin jama'a)",
|
"spend_key_public": "makullin biya (maɓallin jama'a)",
|
||||||
"status": "Matsayi:",
|
"status": "Matsayi:",
|
||||||
|
"string_default": "Ƙin cika alƙawari",
|
||||||
"subaddress_title": "Jagorar subaddress",
|
"subaddress_title": "Jagorar subaddress",
|
||||||
"subaddresses": "Subaddresses",
|
"subaddresses": "Subaddresses",
|
||||||
"submit_request": "gabatar da bukata",
|
"submit_request": "gabatar da bukata",
|
||||||
|
@ -672,10 +689,13 @@
|
||||||
"sync_status_starting_sync": "KWAFI",
|
"sync_status_starting_sync": "KWAFI",
|
||||||
"sync_status_syncronized": "KYAU",
|
"sync_status_syncronized": "KYAU",
|
||||||
"sync_status_syncronizing": "KWAFI",
|
"sync_status_syncronizing": "KWAFI",
|
||||||
|
"sync_status_timed_out": "ATED Out",
|
||||||
|
"sync_status_unsupported": "Ba a Taimako ba",
|
||||||
"syncing_wallet_alert_content": "Ma'aunin ku da lissafin ma'amala bazai cika ba har sai an ce \"SYNCHRONIZED\" a saman. Danna/matsa don ƙarin koyo.",
|
"syncing_wallet_alert_content": "Ma'aunin ku da lissafin ma'amala bazai cika ba har sai an ce \"SYNCHRONIZED\" a saman. Danna/matsa don ƙarin koyo.",
|
||||||
"syncing_wallet_alert_title": "Walat ɗin ku yana aiki tare",
|
"syncing_wallet_alert_title": "Walat ɗin ku yana aiki tare",
|
||||||
"template": "Samfura",
|
"template": "Samfura",
|
||||||
"template_name": "Sunan Samfura",
|
"template_name": "Sunan Samfura",
|
||||||
|
"testnet_coins_no_value": "TalkNet tsabar kudi ba su da darajar",
|
||||||
"third_intro_content": "Yats suna zaune a wajen Kek Wallet, kuma. Ana iya maye gurbin kowane adireshin walat a duniya da Yat!",
|
"third_intro_content": "Yats suna zaune a wajen Kek Wallet, kuma. Ana iya maye gurbin kowane adireshin walat a duniya da Yat!",
|
||||||
"third_intro_title": "Yat yana wasa da kyau tare da wasu",
|
"third_intro_title": "Yat yana wasa da kyau tare da wasu",
|
||||||
"thorchain_contract_address_not_supported": "Thorchain baya goyon bayan aika zuwa adireshin kwangila",
|
"thorchain_contract_address_not_supported": "Thorchain baya goyon bayan aika zuwa adireshin kwangila",
|
||||||
|
@ -751,13 +771,16 @@
|
||||||
"trusted": "Amintacce",
|
"trusted": "Amintacce",
|
||||||
"tx_commit_exception_no_dust_on_change": "An ƙi ma'amala da wannan adadin. Tare da waɗannan tsabar kudi Zaka iya aika ${min}, ba tare da canji ba ko ${max} wanda ya dawo canzawa.",
|
"tx_commit_exception_no_dust_on_change": "An ƙi ma'amala da wannan adadin. Tare da waɗannan tsabar kudi Zaka iya aika ${min}, ba tare da canji ba ko ${max} wanda ya dawo canzawa.",
|
||||||
"tx_commit_failed": "Ma'amala ya kasa. Da fatan za a tuntuɓi goyan baya.",
|
"tx_commit_failed": "Ma'amala ya kasa. Da fatan za a tuntuɓi goyan baya.",
|
||||||
|
"tx_invalid_input": "Kuna amfani da nau'in shigar da ba daidai ba don wannan nau'in biyan kuɗi",
|
||||||
"tx_no_dust_exception": "An ƙi ma'amala ta hanyar aika adadin ƙarami. Da fatan za a gwada ƙara adadin.",
|
"tx_no_dust_exception": "An ƙi ma'amala ta hanyar aika adadin ƙarami. Da fatan za a gwada ƙara adadin.",
|
||||||
"tx_not_enough_inputs_exception": "Bai isa ba hanyoyin da ake samu. Da fatan za selectiari a karkashin Kwarewar Coin",
|
"tx_not_enough_inputs_exception": "Bai isa ba hanyoyin da ake samu. Da fatan za selectiari a karkashin Kwarewar Coin",
|
||||||
|
"tx_rejected_bip68_final": "Ma'amala tana da abubuwan da basu dace ba kuma sun kasa maye gurbin ta.",
|
||||||
"tx_rejected_dust_change": "Ma'amala ta ƙi ta dokokin cibiyar sadarwa, ƙarancin canji (ƙura). Gwada aikawa da duka ko rage adadin.",
|
"tx_rejected_dust_change": "Ma'amala ta ƙi ta dokokin cibiyar sadarwa, ƙarancin canji (ƙura). Gwada aikawa da duka ko rage adadin.",
|
||||||
"tx_rejected_dust_output": "Ma'adar da aka ƙi ta dokokin cibiyar sadarwa, ƙananan fitarwa (ƙura). Da fatan za a ƙara adadin.",
|
"tx_rejected_dust_output": "Ma'adar da aka ƙi ta dokokin cibiyar sadarwa, ƙananan fitarwa (ƙura). Da fatan za a ƙara adadin.",
|
||||||
"tx_rejected_dust_output_send_all": "Ma'adar da aka ƙi ta dokokin cibiyar sadarwa, ƙananan fitarwa (ƙura). Da fatan za a duba daidaiton tsabar kudi a ƙarƙashin ikon tsabar kudin.",
|
"tx_rejected_dust_output_send_all": "Ma'adar da aka ƙi ta dokokin cibiyar sadarwa, ƙananan fitarwa (ƙura). Da fatan za a duba daidaiton tsabar kudi a ƙarƙashin ikon tsabar kudin.",
|
||||||
"tx_rejected_vout_negative": "Bai isa daidai ba don biyan wannan kudin ma'amala. Da fatan za a duba daidaiton tsabar kudi a ƙarƙashin ikon tsabar kudin.",
|
"tx_rejected_vout_negative": "Bai isa daidai ba don biyan wannan kudin ma'amala. Da fatan za a duba daidaiton tsabar kudi a ƙarƙashin ikon tsabar kudin.",
|
||||||
"tx_wrong_balance_exception": "Ba ku da isasshen ${currency} don aika wannan adadin.",
|
"tx_wrong_balance_exception": "Ba ku da isasshen ${currency} don aika wannan adadin.",
|
||||||
|
"tx_wrong_balance_with_amount_exception": "Ba ku da isasshen ${currency} don aika jimlar adadin ${amount}",
|
||||||
"tx_zero_fee_exception": "Ba zai iya aika ma'amala da kuɗi 0 ba. Gwada ƙara ƙimar ko bincika haɗin ku don mahimmin ƙididdiga.",
|
"tx_zero_fee_exception": "Ba zai iya aika ma'amala da kuɗi 0 ba. Gwada ƙara ƙimar ko bincika haɗin ku don mahimmin ƙididdiga.",
|
||||||
"unavailable_balance": "Ma'aunin da ba ya samuwa",
|
"unavailable_balance": "Ma'aunin da ba ya samuwa",
|
||||||
"unavailable_balance_description": "Ma'auni Babu: Wannan jimlar ya haɗa da kuɗi waɗanda ke kulle a cikin ma'amaloli da ke jiran aiki da waɗanda kuka daskare sosai a cikin saitunan sarrafa kuɗin ku. Ma'auni da aka kulle za su kasance da zarar an kammala ma'amalolinsu, yayin da daskararrun ma'auni ba za su iya samun damar yin ciniki ba har sai kun yanke shawarar cire su.",
|
"unavailable_balance_description": "Ma'auni Babu: Wannan jimlar ya haɗa da kuɗi waɗanda ke kulle a cikin ma'amaloli da ke jiran aiki da waɗanda kuka daskare sosai a cikin saitunan sarrafa kuɗin ku. Ma'auni da aka kulle za su kasance da zarar an kammala ma'amalolinsu, yayin da daskararrun ma'auni ba za su iya samun damar yin ciniki ba har sai kun yanke shawarar cire su.",
|
||||||
|
@ -811,6 +834,7 @@
|
||||||
"warning": "Gargadi",
|
"warning": "Gargadi",
|
||||||
"welcome": "Barka da zuwa",
|
"welcome": "Barka da zuwa",
|
||||||
"welcome_to_cakepay": "Barka da zuwa Cake Pay!",
|
"welcome_to_cakepay": "Barka da zuwa Cake Pay!",
|
||||||
|
"what_is_silent_payments": "Menene biyan shiru?",
|
||||||
"widgets_address": "Adireshin",
|
"widgets_address": "Adireshin",
|
||||||
"widgets_or": "ko",
|
"widgets_or": "ko",
|
||||||
"widgets_restore_from_blockheight": "Sake dawo da daga blockheight",
|
"widgets_restore_from_blockheight": "Sake dawo da daga blockheight",
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
"backup": "बैकअप",
|
"backup": "बैकअप",
|
||||||
"backup_file": "बैकअपफ़ाइल",
|
"backup_file": "बैकअपफ़ाइल",
|
||||||
"backup_password": "बैकअप पासवर्ड",
|
"backup_password": "बैकअप पासवर्ड",
|
||||||
|
"balance": "संतुलन",
|
||||||
"balance_page": "बैलेंस पेज",
|
"balance_page": "बैलेंस पेज",
|
||||||
"bill_amount": "बिल राशि",
|
"bill_amount": "बिल राशि",
|
||||||
"billing_address_info": "यदि बिलिंग पता मांगा जाए, तो अपना शिपिंग पता प्रदान करें",
|
"billing_address_info": "यदि बिलिंग पता मांगा जाए, तो अपना शिपिंग पता प्रदान करें",
|
||||||
|
@ -78,6 +79,7 @@
|
||||||
"bitcoin_dark_theme": "बिटकॉइन डार्क थीम",
|
"bitcoin_dark_theme": "बिटकॉइन डार्क थीम",
|
||||||
"bitcoin_light_theme": "बिटकॉइन लाइट थीम",
|
"bitcoin_light_theme": "बिटकॉइन लाइट थीम",
|
||||||
"bitcoin_payments_require_1_confirmation": "बिटकॉइन भुगतान के लिए 1 पुष्टिकरण की आवश्यकता होती है, जिसमें 20 मिनट या अधिक समय लग सकता है। आपके धैर्य के लिए धन्यवाद! भुगतान की पुष्टि होने पर आपको ईमेल किया जाएगा।",
|
"bitcoin_payments_require_1_confirmation": "बिटकॉइन भुगतान के लिए 1 पुष्टिकरण की आवश्यकता होती है, जिसमें 20 मिनट या अधिक समय लग सकता है। आपके धैर्य के लिए धन्यवाद! भुगतान की पुष्टि होने पर आपको ईमेल किया जाएगा।",
|
||||||
|
"block_remaining": "1 ब्लॉक शेष",
|
||||||
"Blocks_remaining": "${status} शेष रहते हैं",
|
"Blocks_remaining": "${status} शेष रहते हैं",
|
||||||
"bluetooth": "ब्लूटूथ",
|
"bluetooth": "ब्लूटूथ",
|
||||||
"bright_theme": "उज्ज्वल",
|
"bright_theme": "उज्ज्वल",
|
||||||
|
@ -139,6 +141,7 @@
|
||||||
"confirm_fee_deduction": "शुल्क कटौती की पुष्टि करें",
|
"confirm_fee_deduction": "शुल्क कटौती की पुष्टि करें",
|
||||||
"confirm_fee_deduction_content": "क्या आप आउटपुट से शुल्क में कटौती करने के लिए सहमत हैं?",
|
"confirm_fee_deduction_content": "क्या आप आउटपुट से शुल्क में कटौती करने के लिए सहमत हैं?",
|
||||||
"confirm_sending": "भेजने की पुष्टि करें",
|
"confirm_sending": "भेजने की पुष्टि करें",
|
||||||
|
"confirm_silent_payments_switch_node": "वर्तमान में मूक भुगतान को स्कैन करने के लिए नोड्स को स्विच करना आवश्यक है",
|
||||||
"confirmations": "पुष्टिकरण",
|
"confirmations": "पुष्टिकरण",
|
||||||
"confirmed": "पुष्टि की गई शेष राशिी",
|
"confirmed": "पुष्टि की गई शेष राशिी",
|
||||||
"confirmed_tx": "की पुष्टि",
|
"confirmed_tx": "की पुष्टि",
|
||||||
|
@ -221,6 +224,7 @@
|
||||||
"electrum_address_disclaimer": "हर बार जब आप एक का उपयोग करते हैं तो हम नए पते उत्पन्न करते हैं, लेकिन पिछले पते काम करना जारी रखते हैं",
|
"electrum_address_disclaimer": "हर बार जब आप एक का उपयोग करते हैं तो हम नए पते उत्पन्न करते हैं, लेकिन पिछले पते काम करना जारी रखते हैं",
|
||||||
"email_address": "ईमेल पता",
|
"email_address": "ईमेल पता",
|
||||||
"enable_replace_by_fee": "प्रतिस्थापित-दर-शुल्क सक्षम करें",
|
"enable_replace_by_fee": "प्रतिस्थापित-दर-शुल्क सक्षम करें",
|
||||||
|
"enable_silent_payments_scanning": "मूक भुगतान स्कैनिंग सक्षम करें",
|
||||||
"enabled": "सक्रिय",
|
"enabled": "सक्रिय",
|
||||||
"enter_amount": "राशि दर्ज करें",
|
"enter_amount": "राशि दर्ज करें",
|
||||||
"enter_backup_password": "यहां बैकअप पासवर्ड डालें",
|
"enter_backup_password": "यहां बैकअप पासवर्ड डालें",
|
||||||
|
@ -278,6 +282,7 @@
|
||||||
"extracted_address_content": "आपको धनराशि भेजी जाएगी\n${recipient_name}",
|
"extracted_address_content": "आपको धनराशि भेजी जाएगी\n${recipient_name}",
|
||||||
"failed_authentication": "प्रमाणीकरण विफल. ${state_error}",
|
"failed_authentication": "प्रमाणीकरण विफल. ${state_error}",
|
||||||
"faq": "FAQ",
|
"faq": "FAQ",
|
||||||
|
"features": "विशेषताएँ",
|
||||||
"fetching": "ला रहा है",
|
"fetching": "ला रहा है",
|
||||||
"fiat_api": "फिएट पैसे API",
|
"fiat_api": "फिएट पैसे API",
|
||||||
"fiat_balance": "फिएट बैलेंस",
|
"fiat_balance": "फिएट बैलेंस",
|
||||||
|
@ -533,6 +538,7 @@
|
||||||
"save_backup_password_alert": "बैकअप पासवर्ड सेव करें",
|
"save_backup_password_alert": "बैकअप पासवर्ड सेव करें",
|
||||||
"save_to_downloads": "डाउनलोड में सहेजें",
|
"save_to_downloads": "डाउनलोड में सहेजें",
|
||||||
"saved_the_trade_id": "मैंने व्यापार बचा लिया है ID",
|
"saved_the_trade_id": "मैंने व्यापार बचा लिया है ID",
|
||||||
|
"scan_one_block": "एक ब्लॉक को स्कैन करना",
|
||||||
"scan_qr_code": "स्कैन क्यू आर कोड",
|
"scan_qr_code": "स्कैन क्यू आर कोड",
|
||||||
"scan_qr_code_to_get_address": "पता प्राप्त करने के लिए QR कोड स्कैन करें",
|
"scan_qr_code_to_get_address": "पता प्राप्त करने के लिए QR कोड स्कैन करें",
|
||||||
"scan_qr_on_device": "इस QR कोड को किसी अन्य डिवाइस पर स्कैन करें",
|
"scan_qr_on_device": "इस QR कोड को किसी अन्य डिवाइस पर स्कैन करें",
|
||||||
|
@ -643,11 +649,22 @@
|
||||||
"sign_up": "साइन अप करें",
|
"sign_up": "साइन अप करें",
|
||||||
"signTransaction": "लेन-देन पर हस्ताक्षर करें",
|
"signTransaction": "लेन-देन पर हस्ताक्षर करें",
|
||||||
"signup_for_card_accept_terms": "कार्ड के लिए साइन अप करें और शर्तें स्वीकार करें।",
|
"signup_for_card_accept_terms": "कार्ड के लिए साइन अप करें और शर्तें स्वीकार करें।",
|
||||||
|
"silent_payments": "मूक भुगतान",
|
||||||
|
"silent_payments_always_scan": "मूक भुगतान हमेशा स्कैनिंग सेट करें",
|
||||||
|
"silent_payments_disclaimer": "नए पते नई पहचान नहीं हैं। यह एक अलग लेबल के साथ एक मौजूदा पहचान का पुन: उपयोग है।",
|
||||||
|
"silent_payments_display_card": "मूक भुगतान कार्ड दिखाएं",
|
||||||
|
"silent_payments_scan_from_date": "तिथि से स्कैन करना",
|
||||||
|
"silent_payments_scan_from_date_or_blockheight": "कृपया उस ब्लॉक ऊंचाई दर्ज करें जिसे आप आने वाले मूक भुगतान के लिए स्कैन करना शुरू करना चाहते हैं, या, इसके बजाय तारीख का उपयोग करें। आप चुन सकते हैं कि क्या वॉलेट हर ब्लॉक को स्कैन करना जारी रखता है, या केवल निर्दिष्ट ऊंचाई की जांच करता है।",
|
||||||
|
"silent_payments_scan_from_height": "ब्लॉक ऊंचाई से स्कैन करें",
|
||||||
|
"silent_payments_scanned_tip": "टिप करने के लिए स्कैन किया! (${tip})",
|
||||||
|
"silent_payments_scanning": "मूक भुगतान स्कैनिंग",
|
||||||
|
"silent_payments_settings": "मूक भुगतान सेटिंग्स",
|
||||||
"slidable": "फिसलने लायक",
|
"slidable": "फिसलने लायक",
|
||||||
"sort_by": "इसके अनुसार क्रमबद्ध करें",
|
"sort_by": "इसके अनुसार क्रमबद्ध करें",
|
||||||
"spend_key_private": "खर्च करना (निजी)",
|
"spend_key_private": "खर्च करना (निजी)",
|
||||||
"spend_key_public": "खर्च करना (जनता)",
|
"spend_key_public": "खर्च करना (जनता)",
|
||||||
"status": "स्थिति: ",
|
"status": "स्थिति: ",
|
||||||
|
"string_default": "गलती करना",
|
||||||
"subaddress_title": "उपखंड सूची",
|
"subaddress_title": "उपखंड सूची",
|
||||||
"subaddresses": "उप पते",
|
"subaddresses": "उप पते",
|
||||||
"submit_request": "एक अनुरोध सबमिट करें",
|
"submit_request": "एक अनुरोध सबमिट करें",
|
||||||
|
@ -672,10 +689,13 @@
|
||||||
"sync_status_starting_sync": "सिताज़ा करना",
|
"sync_status_starting_sync": "सिताज़ा करना",
|
||||||
"sync_status_syncronized": "सिंक्रनाइज़",
|
"sync_status_syncronized": "सिंक्रनाइज़",
|
||||||
"sync_status_syncronizing": "सिंक्रनाइज़ करने",
|
"sync_status_syncronizing": "सिंक्रनाइज़ करने",
|
||||||
|
"sync_status_timed_out": "समय समााप्त",
|
||||||
|
"sync_status_unsupported": "असमर्थित नोड",
|
||||||
"syncing_wallet_alert_content": "आपकी शेष राशि और लेनदेन सूची तब तक पूरी नहीं हो सकती जब तक कि शीर्ष पर \"सिंक्रनाइज़्ड\" न लिखा हो। अधिक जानने के लिए क्लिक/टैप करें।",
|
"syncing_wallet_alert_content": "आपकी शेष राशि और लेनदेन सूची तब तक पूरी नहीं हो सकती जब तक कि शीर्ष पर \"सिंक्रनाइज़्ड\" न लिखा हो। अधिक जानने के लिए क्लिक/टैप करें।",
|
||||||
"syncing_wallet_alert_title": "आपका वॉलेट सिंक हो रहा है",
|
"syncing_wallet_alert_title": "आपका वॉलेट सिंक हो रहा है",
|
||||||
"template": "खाका",
|
"template": "खाका",
|
||||||
"template_name": "टेम्पलेट नाम",
|
"template_name": "टेम्पलेट नाम",
|
||||||
|
"testnet_coins_no_value": "टेस्टनेट सिक्कों का कोई मूल्य नहीं है",
|
||||||
"third_intro_content": "Yats Cake Wallet के बाहर भी रहता है। धरती पर किसी भी वॉलेट पते को Yat से बदला जा सकता है!",
|
"third_intro_content": "Yats Cake Wallet के बाहर भी रहता है। धरती पर किसी भी वॉलेट पते को Yat से बदला जा सकता है!",
|
||||||
"third_intro_title": "Yat दूसरों के साथ अच्छा खेलता है",
|
"third_intro_title": "Yat दूसरों के साथ अच्छा खेलता है",
|
||||||
"thorchain_contract_address_not_supported": "थोरचेन एक अनुबंध पते पर भेजने का समर्थन नहीं करता है",
|
"thorchain_contract_address_not_supported": "थोरचेन एक अनुबंध पते पर भेजने का समर्थन नहीं करता है",
|
||||||
|
@ -751,13 +771,16 @@
|
||||||
"trusted": "भरोसा",
|
"trusted": "भरोसा",
|
||||||
"tx_commit_exception_no_dust_on_change": "लेनदेन को इस राशि से खारिज कर दिया जाता है। इन सिक्कों के साथ आप चेंज या ${min} के बिना ${max} को भेज सकते हैं जो परिवर्तन लौटाता है।",
|
"tx_commit_exception_no_dust_on_change": "लेनदेन को इस राशि से खारिज कर दिया जाता है। इन सिक्कों के साथ आप चेंज या ${min} के बिना ${max} को भेज सकते हैं जो परिवर्तन लौटाता है।",
|
||||||
"tx_commit_failed": "लेन -देन प्रतिबद्ध विफल। कृपया संपर्क समर्थन करें।",
|
"tx_commit_failed": "लेन -देन प्रतिबद्ध विफल। कृपया संपर्क समर्थन करें।",
|
||||||
|
"tx_invalid_input": "आप इस प्रकार के भुगतान के लिए गलत इनपुट प्रकार का उपयोग कर रहे हैं",
|
||||||
"tx_no_dust_exception": "लेनदेन को बहुत छोटी राशि भेजकर अस्वीकार कर दिया जाता है। कृपया राशि बढ़ाने का प्रयास करें।",
|
"tx_no_dust_exception": "लेनदेन को बहुत छोटी राशि भेजकर अस्वीकार कर दिया जाता है। कृपया राशि बढ़ाने का प्रयास करें।",
|
||||||
"tx_not_enough_inputs_exception": "पर्याप्त इनपुट उपलब्ध नहीं है। कृपया सिक्का नियंत्रण के तहत अधिक चुनें",
|
"tx_not_enough_inputs_exception": "पर्याप्त इनपुट उपलब्ध नहीं है। कृपया सिक्का नियंत्रण के तहत अधिक चुनें",
|
||||||
|
"tx_rejected_bip68_final": "लेन -देन में अपुष्ट इनपुट हैं और शुल्क द्वारा प्रतिस्थापित करने में विफल रहे हैं।",
|
||||||
"tx_rejected_dust_change": "नेटवर्क नियमों, कम परिवर्तन राशि (धूल) द्वारा खारिज किए गए लेनदेन। सभी भेजने या राशि को कम करने का प्रयास करें।",
|
"tx_rejected_dust_change": "नेटवर्क नियमों, कम परिवर्तन राशि (धूल) द्वारा खारिज किए गए लेनदेन। सभी भेजने या राशि को कम करने का प्रयास करें।",
|
||||||
"tx_rejected_dust_output": "नेटवर्क नियमों, कम आउटपुट राशि (धूल) द्वारा खारिज किए गए लेनदेन। कृपया राशि बढ़ाएं।",
|
"tx_rejected_dust_output": "नेटवर्क नियमों, कम आउटपुट राशि (धूल) द्वारा खारिज किए गए लेनदेन। कृपया राशि बढ़ाएं।",
|
||||||
"tx_rejected_dust_output_send_all": "नेटवर्क नियमों, कम आउटपुट राशि (धूल) द्वारा खारिज किए गए लेनदेन। कृपया सिक्का नियंत्रण के तहत चुने गए सिक्कों के संतुलन की जाँच करें।",
|
"tx_rejected_dust_output_send_all": "नेटवर्क नियमों, कम आउटपुट राशि (धूल) द्वारा खारिज किए गए लेनदेन। कृपया सिक्का नियंत्रण के तहत चुने गए सिक्कों के संतुलन की जाँच करें।",
|
||||||
"tx_rejected_vout_negative": "इस लेनदेन की फीस के लिए भुगतान करने के लिए पर्याप्त शेष राशि नहीं है। कृपया सिक्के नियंत्रण के तहत सिक्कों के संतुलन की जाँच करें।",
|
"tx_rejected_vout_negative": "इस लेनदेन की फीस के लिए भुगतान करने के लिए पर्याप्त शेष राशि नहीं है। कृपया सिक्के नियंत्रण के तहत सिक्कों के संतुलन की जाँच करें।",
|
||||||
"tx_wrong_balance_exception": "इस राशि को भेजने के लिए आपके पास पर्याप्त ${currency} नहीं है।",
|
"tx_wrong_balance_exception": "इस राशि को भेजने के लिए आपके पास पर्याप्त ${currency} नहीं है।",
|
||||||
|
"tx_wrong_balance_with_amount_exception": "आपके पास पर्याप्त नहीं है${currency} ${amount} की कुल राशि भेजने के लिए",
|
||||||
"tx_zero_fee_exception": "0 शुल्क के साथ लेनदेन नहीं भेज सकते। नवीनतम अनुमानों के लिए दर बढ़ाने या अपने कनेक्शन की जांच करने का प्रयास करें।",
|
"tx_zero_fee_exception": "0 शुल्क के साथ लेनदेन नहीं भेज सकते। नवीनतम अनुमानों के लिए दर बढ़ाने या अपने कनेक्शन की जांच करने का प्रयास करें।",
|
||||||
"unavailable_balance": "अनुपलब्ध शेष",
|
"unavailable_balance": "अनुपलब्ध शेष",
|
||||||
"unavailable_balance_description": "अनुपलब्ध शेष राशि: इस कुल में वे धनराशि शामिल हैं जो लंबित लेनदेन में बंद हैं और जिन्हें आपने अपनी सिक्का नियंत्रण सेटिंग्स में सक्रिय रूप से जमा कर रखा है। लॉक किए गए शेष उनके संबंधित लेन-देन पूरे होने के बाद उपलब्ध हो जाएंगे, जबकि जमे हुए शेष लेन-देन के लिए अप्राप्य रहेंगे जब तक कि आप उन्हें अनफ्रीज करने का निर्णय नहीं लेते।",
|
"unavailable_balance_description": "अनुपलब्ध शेष राशि: इस कुल में वे धनराशि शामिल हैं जो लंबित लेनदेन में बंद हैं और जिन्हें आपने अपनी सिक्का नियंत्रण सेटिंग्स में सक्रिय रूप से जमा कर रखा है। लॉक किए गए शेष उनके संबंधित लेन-देन पूरे होने के बाद उपलब्ध हो जाएंगे, जबकि जमे हुए शेष लेन-देन के लिए अप्राप्य रहेंगे जब तक कि आप उन्हें अनफ्रीज करने का निर्णय नहीं लेते।",
|
||||||
|
@ -811,6 +834,7 @@
|
||||||
"warning": "चेतावनी",
|
"warning": "चेतावनी",
|
||||||
"welcome": "स्वागत हे सेवा मेरे",
|
"welcome": "स्वागत हे सेवा मेरे",
|
||||||
"welcome_to_cakepay": "केकपे में आपका स्वागत है!",
|
"welcome_to_cakepay": "केकपे में आपका स्वागत है!",
|
||||||
|
"what_is_silent_payments": "मूक भुगतान क्या है?",
|
||||||
"widgets_address": "पता",
|
"widgets_address": "पता",
|
||||||
"widgets_or": "या",
|
"widgets_or": "या",
|
||||||
"widgets_restore_from_blockheight": "ब्लॉकचेन से पुनर्स्थापित करें",
|
"widgets_restore_from_blockheight": "ब्लॉकचेन से पुनर्स्थापित करें",
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue